diff --git a/MUtilities_VS2013.vcxproj b/MUtilities_VS2013.vcxproj index 8ae0cf5..4c86384 100644 --- a/MUtilities_VS2013.vcxproj +++ b/MUtilities_VS2013.vcxproj @@ -143,7 +143,7 @@ Windows true $(QTDIR)\lib;$(SolutionDir)\..\Prerequisites\VisualLeakDetector\lib\Win32 - QtCored4.lib;QtGuid4.lib;Psapi.lib;Sensapi.lib;%(AdditionalDependencies) + QtCored4.lib;QtGuid4.lib;Psapi.lib;Sensapi.lib;PowrProf.lib;%(AdditionalDependencies) @@ -172,7 +172,7 @@ true true $(QTDIR)\lib;$(SolutionDir)\..\Prerequisites\VisualLeakDetector\lib\Win32 - QtCore4.lib;QtGui4.lib;Psapi.lib;Sensapi.lib;%(AdditionalDependencies) + QtCore4.lib;QtGui4.lib;Psapi.lib;Sensapi.lib;PowrProf.lib;%(AdditionalDependencies) false diff --git a/include/MUtils/OSSupport.h b/include/MUtils/OSSupport.h index f6c8a8c..139edac 100644 --- a/include/MUtils/OSSupport.h +++ b/include/MUtils/OSSupport.h @@ -111,11 +111,13 @@ namespace MUtils //Get known Folder MUTILS_API const QString &known_folder(known_folder_t folder_id); - //Current Date + //Current Date & Time MUTILS_API QDate current_date(void); + MUTILS_API quint64 current_file_time(void); //Check for process elevation MUTILS_API bool is_elevated(bool *bIsUacEnabled = NULL); + MUTILS_API bool user_is_admin(void); //Network Status MUTILS_API int network_status(void); @@ -126,6 +128,34 @@ namespace MUtils //Sleep MUTILS_API void sleep_ms(const size_t &duration); + //Is executable file? + MUTILS_API bool is_executable_file(const QString &path); + + //Shutdown & Hibernation + MUTILS_API bool is_hibernation_supported(void); + MUTILS_API bool shutdown_computer(const QString &message, const unsigned long timeout, const bool forceShutdown, const bool hibernate); + + //Free diskspace + MUTILS_API bool free_diskspace(const QString &path, quint64 &freeSpace); + + //Shell open + MUTILS_API bool shell_open(const QWidget *parent, const QString &url, const bool explore = false); + MUTILS_API bool shell_open(const QWidget *parent, const QString &url, const QString ¶meters, const QString &directory, const bool explore = false); + + //Open media file + MUTILS_API bool open_media_file(const QString &mediaFilePath); + + //Performance counter + MUTILS_API qint64 perfcounter_read(void); + MUTILS_API qint64 perfcounter_freq(void); + + //Process priority + MUTILS_API bool change_process_priority(const int priority); + MUTILS_API bool change_process_priority(const QProcess *proc, const int priority); + + //Process ID + MUTILS_API quint32 process_id(const QProcess *proc); + //Check if debugger is present MUTILS_API void check_debugger(void); diff --git a/src/OSSupport_Win32.cpp b/src/OSSupport_Win32.cpp index b31adda..0051d10 100644 --- a/src/OSSupport_Win32.cpp +++ b/src/OSSupport_Win32.cpp @@ -28,6 +28,7 @@ #include #include #include +#include //Internal #include @@ -40,6 +41,8 @@ #include #include #include +#include +#include //Main thread ID static const DWORD g_main_thread_id = GetCurrentThreadId(); @@ -449,7 +452,7 @@ const QString &MUtils::OS::known_folder(known_folder_t folder_id) } /////////////////////////////////////////////////////////////////////////////// -// CURRENT DATA (SAFE) +// CURRENT DATA & TIME /////////////////////////////////////////////////////////////////////////////// QDate MUtils::OS::current_date(void) @@ -508,10 +511,78 @@ QDate MUtils::OS::current_date(void) return (currentDate >= processDate) ? currentDate : processDate; } +quint64 MUtils::OS::current_file_time(void) +{ + FILETIME fileTime; + GetSystemTimeAsFileTime(&fileTime); + + ULARGE_INTEGER temp; + temp.HighPart = fileTime.dwHighDateTime; + temp.LowPart = fileTime.dwLowDateTime; + + return temp.QuadPart; +} + /////////////////////////////////////////////////////////////////////////////// // PROCESS ELEVATION /////////////////////////////////////////////////////////////////////////////// +static bool user_is_admin_helper(void) +{ + HANDLE hToken = NULL; + if(!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) + { + return false; + } + + DWORD dwSize = 0; + if(!GetTokenInformation(hToken, TokenGroups, NULL, 0, &dwSize)) + { + if(GetLastError() != ERROR_INSUFFICIENT_BUFFER) + { + CloseHandle(hToken); + return false; + } + } + + PTOKEN_GROUPS lpGroups = (PTOKEN_GROUPS) malloc(dwSize); + if(!lpGroups) + { + CloseHandle(hToken); + return false; + } + + if(!GetTokenInformation(hToken, TokenGroups, lpGroups, dwSize, &dwSize)) + { + free(lpGroups); + CloseHandle(hToken); + return false; + } + + PSID lpSid = NULL; SID_IDENTIFIER_AUTHORITY Authority = {SECURITY_NT_AUTHORITY}; + if(!AllocateAndInitializeSid(&Authority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &lpSid)) + { + free(lpGroups); + CloseHandle(hToken); + return false; + } + + bool bResult = false; + for(DWORD i = 0; i < lpGroups->GroupCount; i++) + { + if(EqualSid(lpSid, lpGroups->Groups[i].Sid)) + { + bResult = true; + break; + } + } + + FreeSid(lpSid); + free(lpGroups); + CloseHandle(hToken); + return bResult; +} + bool MUtils::OS::is_elevated(bool *bIsUacEnabled) { if(bIsUacEnabled) @@ -564,6 +635,27 @@ bool MUtils::OS::is_elevated(bool *bIsUacEnabled) return bIsProcessElevated; } +bool MUtils::OS::user_is_admin(void) +{ + bool isAdmin = false; + + //Check for process elevation and UAC support first! + if(MUtils::OS::is_elevated(&isAdmin)) + { + qWarning("Process is elevated -> user is admin!"); + return true; + } + + //If not elevated and UAC is not available -> user must be in admin group! + if(!isAdmin) + { + qDebug("UAC is disabled/unavailable -> checking for Administrators group"); + isAdmin = user_is_admin_helper(); + } + + return isAdmin; +} + /////////////////////////////////////////////////////////////////////////////// // NETWORK STATE /////////////////////////////////////////////////////////////////////////////// @@ -618,6 +710,253 @@ void MUtils::OS::sleep_ms(const size_t &duration) Sleep((DWORD) duration); } +/////////////////////////////////////////////////////////////////////////////// +// EXECUTABLE CHECK +/////////////////////////////////////////////////////////////////////////////// + +bool MUtils::OS::is_executable_file(const QString &path) +{ + bool bIsExecutable = false; + DWORD binaryType; + if(GetBinaryType(MUTILS_WCHR(QDir::toNativeSeparators(path)), &binaryType)) + { + bIsExecutable = (binaryType == SCS_32BIT_BINARY || binaryType == SCS_64BIT_BINARY); + } + return bIsExecutable; +} + +/////////////////////////////////////////////////////////////////////////////// +// HIBERNATION / SHUTDOWN +/////////////////////////////////////////////////////////////////////////////// + +bool MUtils::OS::is_hibernation_supported(void) +{ + bool hibernationSupported = false; + + SYSTEM_POWER_CAPABILITIES pwrCaps; + SecureZeroMemory(&pwrCaps, sizeof(SYSTEM_POWER_CAPABILITIES)); + + if(GetPwrCapabilities(&pwrCaps)) + { + hibernationSupported = pwrCaps.SystemS4 && pwrCaps.HiberFilePresent; + } + + return hibernationSupported; +} + +bool MUtils::OS::shutdown_computer(const QString &message, const unsigned long timeout, const bool forceShutdown, const bool hibernate) +{ + HANDLE hToken = NULL; + + if(OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) + { + TOKEN_PRIVILEGES privileges; + memset(&privileges, 0, sizeof(TOKEN_PRIVILEGES)); + privileges.PrivilegeCount = 1; + privileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + + if(LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &privileges.Privileges[0].Luid)) + { + if(AdjustTokenPrivileges(hToken, FALSE, &privileges, NULL, NULL, NULL)) + { + if(hibernate) + { + if(SetSuspendState(TRUE, TRUE, TRUE)) + { + return true; + } + } + const DWORD reason = SHTDN_REASON_MAJOR_APPLICATION | SHTDN_REASON_FLAG_PLANNED; + return InitiateSystemShutdownEx(NULL, const_cast(MUTILS_WCHR(message)), timeout, forceShutdown ? TRUE : FALSE, FALSE, reason); + } + } + } + + return false; +} + +/////////////////////////////////////////////////////////////////////////////// +// FREE DISKSPACE +/////////////////////////////////////////////////////////////////////////////// + +bool MUtils::OS::free_diskspace(const QString &path, quint64 &freeSpace) +{ + ULARGE_INTEGER freeBytesAvailable, totalNumberOfBytes, totalNumberOfFreeBytes; + if(GetDiskFreeSpaceExW(reinterpret_cast(QDir::toNativeSeparators(path).utf16()), &freeBytesAvailable, &totalNumberOfBytes, &totalNumberOfFreeBytes)) + { + freeSpace = freeBytesAvailable.QuadPart; + return true;; + } + + freeSpace = -1; + return false; +} + +/////////////////////////////////////////////////////////////////////////////// +// SHELL OPEN +/////////////////////////////////////////////////////////////////////////////// + +bool MUtils::OS::shell_open(const QWidget *parent, const QString &url, const QString ¶meters, const QString &directory, const bool explore) +{ + return ((int) ShellExecuteW((parent ? parent->winId() : NULL), (explore ? L"explore" : L"open"), MUTILS_WCHR(url), ((!parameters.isEmpty()) ? MUTILS_WCHR(parameters) : NULL), ((!directory.isEmpty()) ? MUTILS_WCHR(directory) : NULL), SW_SHOW)) > 32; +} + +bool MUtils::OS::shell_open(const QWidget *parent, const QString &url, const bool explore) +{ + return shell_open(parent, url, QString(), QString(), explore); +} + +/////////////////////////////////////////////////////////////////////////////// +// OPEN MEDIA FILE +/////////////////////////////////////////////////////////////////////////////// + +bool MUtils::OS::open_media_file(const QString &mediaFilePath) +{ + const static wchar_t *registryPrefix[2] = { L"SOFTWARE\\", L"SOFTWARE\\Wow6432Node\\" }; + const static wchar_t *registryKeys[3] = + { + L"Microsoft\\Windows\\CurrentVersion\\Uninstall\\{97D341C8-B0D1-4E4A-A49A-C30B52F168E9}", + L"Microsoft\\Windows\\CurrentVersion\\Uninstall\\{DB9E4EAB-2717-499F-8D56-4CC8A644AB60}", + L"foobar2000" + }; + const static wchar_t *appNames[4] = { L"smplayer_portable.exe", L"smplayer.exe", L"MPUI.exe", L"foobar2000.exe" }; + const static wchar_t *valueNames[2] = { L"InstallLocation", L"InstallDir" }; + + for(size_t i = 0; i < 3; i++) + { + for(size_t j = 0; j < 2; j++) + { + QString mplayerPath; + HKEY registryKeyHandle = NULL; + + const QString currentKey = MUTILS_QSTR(registryPrefix[j]).append(MUTILS_QSTR(registryKeys[i])); + if(RegOpenKeyExW(HKEY_LOCAL_MACHINE, MUTILS_WCHR(currentKey), 0, KEY_READ, ®istryKeyHandle) == ERROR_SUCCESS) + { + for(size_t k = 0; k < 2; k++) + { + wchar_t Buffer[4096]; + DWORD BuffSize = sizeof(wchar_t*) * 4096; + DWORD DataType = REG_NONE; + if(RegQueryValueExW(registryKeyHandle, valueNames[k], 0, &DataType, reinterpret_cast(Buffer), &BuffSize) == ERROR_SUCCESS) + { + if((DataType == REG_SZ) || (DataType == REG_EXPAND_SZ) || (DataType == REG_LINK)) + { + mplayerPath = MUTILS_QSTR(Buffer); + break; + } + } + } + RegCloseKey(registryKeyHandle); + } + + if(!mplayerPath.isEmpty()) + { + QDir mplayerDir(mplayerPath); + if(mplayerDir.exists()) + { + for(size_t k = 0; k < 4; k++) + { + if(mplayerDir.exists(MUTILS_QSTR(appNames[k]))) + { + qDebug("Player found at:\n%s\n", MUTILS_UTF8(mplayerDir.absoluteFilePath(MUTILS_QSTR(appNames[k])))); + QProcess::startDetached(mplayerDir.absoluteFilePath(MUTILS_QSTR(appNames[k])), QStringList() << QDir::toNativeSeparators(mediaFilePath)); + return true; + } + } + } + } + } + } + return false; +} + +/////////////////////////////////////////////////////////////////////////////// +// PERFORMANCE COUNTER +/////////////////////////////////////////////////////////////////////////////// + +qint64 MUtils::OS::perfcounter_read(void) +{ + LARGE_INTEGER counter; + if(QueryPerformanceCounter(&counter) == TRUE) + { + return counter.QuadPart; + } + return -1; +} + +qint64 MUtils::OS::perfcounter_freq(void) +{ + LARGE_INTEGER frequency; + if(QueryPerformanceFrequency(&frequency) == TRUE) + { + return frequency.QuadPart; + } + return -1; +} + +/////////////////////////////////////////////////////////////////////////////// +// DEBUGGER CHECK +/////////////////////////////////////////////////////////////////////////////// + +static bool change_process_priority_helper(const HANDLE hProcess, const int priority) +{ + bool ok = false; + + switch(qBound(-2, priority, 2)) + { + case 2: + ok = (SetPriorityClass(hProcess, HIGH_PRIORITY_CLASS) == TRUE); + break; + case 1: + if(!(ok = (SetPriorityClass(hProcess, ABOVE_NORMAL_PRIORITY_CLASS) == TRUE))) + { + ok = (SetPriorityClass(hProcess, HIGH_PRIORITY_CLASS) == TRUE); + } + break; + case 0: + ok = (SetPriorityClass(hProcess, NORMAL_PRIORITY_CLASS) == TRUE); + break; + case -1: + if(!(ok = (SetPriorityClass(hProcess, BELOW_NORMAL_PRIORITY_CLASS) == TRUE))) + { + ok = (SetPriorityClass(hProcess, IDLE_PRIORITY_CLASS) == TRUE); + } + break; + case -2: + ok = (SetPriorityClass(hProcess, IDLE_PRIORITY_CLASS) == TRUE); + break; + } + + return ok; +} + +bool MUtils::OS::change_process_priority(const int priority) +{ + return change_process_priority_helper(GetCurrentProcess(), priority); +} + +bool MUtils::OS::change_process_priority(const QProcess *proc, const int priority) +{ + if(Q_PID qPid = proc->pid()) + { + return change_process_priority_helper(qPid->hProcess, priority); + } + else + { + return false; + } +} + +/////////////////////////////////////////////////////////////////////////////// +// PROCESS ID +/////////////////////////////////////////////////////////////////////////////// + +quint32 MUtils::OS::process_id(const QProcess *proc) +{ + PROCESS_INFORMATION *procInf = proc->pid(); + return (procInf) ? procInf->dwProcessId : NULL; +} + /////////////////////////////////////////////////////////////////////////////// // DEBUGGER CHECK ///////////////////////////////////////////////////////////////////////////////