X-Git-Url: http://git.osdn.net/view?a=blobdiff_plain;f=src%2FOSSupport_Win32.cpp;h=f47590d19caef5de83bafcdf8c75bc79dbc8e04b;hb=bc3701305df979cb462492945bc35cddd8c21ef7;hp=ee9e2ba4420630e0ea30fb81082abf4a7faf858a;hpb=7ecdb2f57e87e00c6789a3d82d9e468e4ad11c5e;p=mutilities%2FMUtilities.git diff --git a/src/OSSupport_Win32.cpp b/src/OSSupport_Win32.cpp index ee9e2ba..f47590d 100644 --- a/src/OSSupport_Win32.cpp +++ b/src/OSSupport_Win32.cpp @@ -19,31 +19,327 @@ // http://www.gnu.org/licenses/lgpl-2.1.txt ////////////////////////////////////////////////////////////////////////////////// -#pragma once - -//Internal -#include -#include - //Win32 API #define WIN32_LEAN_AND_MEAN 1 #include #include +#include +#include +#include +#include +#include + +//Internal +#include +#include +#include +#include "CriticalSection_Win32.h" //Qt #include #include #include #include +#include +#include + +//Main thread ID +static const DWORD g_main_thread_id = GetCurrentThreadId(); + +/////////////////////////////////////////////////////////////////////////////// +// SYSTEM MESSAGE +/////////////////////////////////////////////////////////////////////////////// + +static const UINT g_msgBoxFlags = MB_TOPMOST | MB_TASKMODAL | MB_SETFOREGROUND; + +void MUtils::OS::system_message_nfo(const wchar_t *const title, const wchar_t *const text) +{ + MessageBoxW(NULL, text, title, g_msgBoxFlags | MB_ICONINFORMATION); +} + +void MUtils::OS::system_message_wrn(const wchar_t *const title, const wchar_t *const text) +{ + MessageBoxW(NULL, text, title, g_msgBoxFlags | MB_ICONWARNING); +} + +void MUtils::OS::system_message_err(const wchar_t *const title, const wchar_t *const text) +{ + MessageBoxW(NULL, text, title, g_msgBoxFlags | MB_ICONERROR); +} + +/////////////////////////////////////////////////////////////////////////////// +// FETCH CLI ARGUMENTS +/////////////////////////////////////////////////////////////////////////////// + +static QReadWriteLock g_arguments_lock; +static QScopedPointer g_arguments_list; + +const QStringList &MUtils::OS::arguments(void) +{ + QReadLocker readLock(&g_arguments_lock); + + //Already initialized? + if(!g_arguments_list.isNull()) + { + return (*(g_arguments_list.data())); + } + + readLock.unlock(); + QWriteLocker writeLock(&g_arguments_lock); + + //Still not initialized? + if(!g_arguments_list.isNull()) + { + return (*(g_arguments_list.data())); + } + + g_arguments_list.reset(new QStringList); + int nArgs = 0; + LPWSTR *szArglist = CommandLineToArgvW(GetCommandLineW(), &nArgs); + + if(NULL != szArglist) + { + for(int i = 0; i < nArgs; i++) + { + *(g_arguments_list.data()) << MUTILS_QSTR(szArglist[i]); + } + LocalFree(szArglist); + } + else + { + qWarning("CommandLineToArgvW() has failed !!!"); + } + + return (*(g_arguments_list.data())); +} + +/////////////////////////////////////////////////////////////////////////////// +// OS VERSION DETECTION +/////////////////////////////////////////////////////////////////////////////// + +static bool g_os_version_initialized = false; +static MUtils::OS::Version::os_version_t g_os_version_info = MUtils::OS::Version::UNKNOWN_OPSYS; +static QReadWriteLock g_os_version_lock; + +//Maps marketing names to the actual Windows NT versions +static const struct +{ + MUtils::OS::Version::os_version_t version; + const char friendlyName[64]; +} +g_os_version_lut[] = +{ + { MUtils::OS::Version::WINDOWS_WIN2K, "Windows 2000" }, //2000 + { MUtils::OS::Version::WINDOWS_WINXP, "Windows XP or Windows XP Media Center Edition" }, //XP + { MUtils::OS::Version::WINDOWS_XPX64, "Windows Server 2003 or Windows XP x64" }, //XP_x64 + { MUtils::OS::Version::WINDOWS_VISTA, "Windows Vista or Windows Server 2008" }, //Vista + { MUtils::OS::Version::WINDOWS_WIN70, "Windows 7 or Windows Server 2008 R2" }, //7 + { MUtils::OS::Version::WINDOWS_WIN80, "Windows 8 or Windows Server 2012" }, //8 + { MUtils::OS::Version::WINDOWS_WIN81, "Windows 8.1 or Windows Server 2012 R2" }, //8.1 + { MUtils::OS::Version::WINDOWS_WN100, "Windows 10 or Windows Server 2014 (Preview)" }, //10 + { MUtils::OS::Version::UNKNOWN_OPSYS, "N/A" } +}; + +static bool verify_os_version(const DWORD major, const DWORD minor) +{ + OSVERSIONINFOEXW osvi; + DWORDLONG dwlConditionMask = 0; + + //Initialize the OSVERSIONINFOEX structure + memset(&osvi, 0, sizeof(OSVERSIONINFOEXW)); + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW); + osvi.dwMajorVersion = major; + osvi.dwMinorVersion = minor; + osvi.dwPlatformId = VER_PLATFORM_WIN32_NT; + + //Initialize the condition mask + VER_SET_CONDITION(dwlConditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL); + VER_SET_CONDITION(dwlConditionMask, VER_MINORVERSION, VER_GREATER_EQUAL); + VER_SET_CONDITION(dwlConditionMask, VER_PLATFORMID, VER_EQUAL); + + // Perform the test + const BOOL ret = VerifyVersionInfoW(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_PLATFORMID, dwlConditionMask); + + //Error checking + if(!ret) + { + if(GetLastError() != ERROR_OLD_WIN_VERSION) + { + qWarning("VerifyVersionInfo() system call has failed!"); + } + } + + return (ret != FALSE); +} + +static bool get_real_os_version(unsigned int *major, unsigned int *minor, bool *pbOverride) +{ + *major = *minor = 0; + *pbOverride = false; + + //Initialize local variables + OSVERSIONINFOEXW osvi; + memset(&osvi, 0, sizeof(OSVERSIONINFOEXW)); + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW); + + //Try GetVersionEx() first + if(GetVersionExW((LPOSVERSIONINFOW)&osvi) == FALSE) + { + qWarning("GetVersionEx() has failed, cannot detect Windows version!"); + return false; + } + + //Make sure we are running on NT + if(osvi.dwPlatformId == VER_PLATFORM_WIN32_NT) + { + *major = osvi.dwMajorVersion; + *minor = osvi.dwMinorVersion; + } + else + { + qWarning("Not running on Windows NT, unsupported operating system!"); + return false; + } + + //Determine the real *major* version first + forever + { + const DWORD nextMajor = (*major) + 1; + if(verify_os_version(nextMajor, 0)) + { + *pbOverride = true; + *major = nextMajor; + *minor = 0; + continue; + } + break; + } + + //Now also determine the real *minor* version + forever + { + const DWORD nextMinor = (*minor) + 1; + if(verify_os_version((*major), nextMinor)) + { + *pbOverride = true; + *minor = nextMinor; + continue; + } + break; + } + + return true; +} + +const MUtils::OS::Version::os_version_t &MUtils::OS::os_version(void) +{ + QReadLocker readLock(&g_os_version_lock); + + //Already initialized? + if(g_os_version_initialized) + { + return g_os_version_info; + } + + readLock.unlock(); + QWriteLocker writeLock(&g_os_version_lock); + + //Initialized now? + if(g_os_version_initialized) + { + return g_os_version_info; + } + + //Detect OS version + unsigned int major, minor; bool overrideFlg; + if(get_real_os_version(&major, &minor, &overrideFlg)) + { + g_os_version_info.type = Version::OS_WINDOWS; + g_os_version_info.versionMajor = major; + g_os_version_info.versionMinor = minor; + g_os_version_info.overrideFlag = overrideFlg; + } + else + { + qWarning("Failed to determin the operating system version!"); + } + + //Completed + g_os_version_initialized = true; + return g_os_version_info; +} + +const char *MUtils::OS::os_friendly_name(const MUtils::OS::Version::os_version_t &os_version) +{ + for(size_t i = 0; g_os_version_lut[i].version != MUtils::OS::Version::UNKNOWN_OPSYS; i++) + { + if(os_version == g_os_version_lut[i].version) + { + return g_os_version_lut[i].friendlyName; + } + } + + return NULL; +} + +/////////////////////////////////////////////////////////////////////////////// +// WINE DETECTION +/////////////////////////////////////////////////////////////////////////////// + +static bool g_wine_deteced = false; +static bool g_wine_initialized = false; +static QReadWriteLock g_wine_lock; + +static const bool detect_wine(void) +{ + bool is_wine = false; + + QLibrary ntdll("ntdll.dll"); + if(ntdll.load()) + { + if(ntdll.resolve("wine_nt_to_unix_file_name") != NULL) is_wine = true; + if(ntdll.resolve("wine_get_version") != NULL) is_wine = true; + ntdll.unload(); + } + + return is_wine; +} + +const bool &MUtils::OS::running_on_wine(void) +{ + QReadLocker readLock(&g_wine_lock); + + //Already initialized? + if(g_wine_initialized) + { + return g_wine_deteced; + } + + readLock.unlock(); + QWriteLocker writeLock(&g_wine_lock); + + //Initialized now? + if(g_wine_initialized) + { + return g_wine_deteced; + } + + //Try to detect Wine + g_wine_deteced = detect_wine(); + g_wine_initialized = true; + + return g_wine_deteced; +} /////////////////////////////////////////////////////////////////////////////// // KNWON FOLDERS /////////////////////////////////////////////////////////////////////////////// +typedef QMap KFMap; typedef HRESULT (WINAPI *SHGetKnownFolderPath_t)(const GUID &rfid, DWORD dwFlags, HANDLE hToken, PWSTR *ppszPath); typedef HRESULT (WINAPI *SHGetFolderPath_t)(HWND hwndOwner, int nFolder, HANDLE hToken, DWORD dwFlags, LPWSTR pszPath); -static QMap* g_known_folders_map; +static QScopedPointer g_known_folders_map; static SHGetKnownFolderPath_t g_known_folders_fpGetKnownFolderPath; static SHGetFolderPath_t g_known_folders_fpGetFolderPath; static QReadWriteLock g_known_folders_lock; @@ -85,7 +381,7 @@ const QString &MUtils::OS::known_folder(known_folder_t folder_id) QReadLocker readLock(&g_known_folders_lock); //Already in cache? - if(g_known_folders_map) + if(!g_known_folders_map.isNull()) { if(g_known_folders_map->contains(folderId)) { @@ -98,7 +394,7 @@ const QString &MUtils::OS::known_folder(known_folder_t folder_id) QWriteLocker writeLock(&g_known_folders_lock); //Still not in cache? - if(g_known_folders_map) + if(!g_known_folders_map.isNull()) { if(g_known_folders_map->contains(folderId)) { @@ -107,7 +403,7 @@ const QString &MUtils::OS::known_folder(known_folder_t folder_id) } //Initialize on first call - if(!g_known_folders_map) + if(g_known_folders_map.isNull()) { QLibrary shell32("shell32.dll"); if(shell32.load()) @@ -115,7 +411,7 @@ const QString &MUtils::OS::known_folder(known_folder_t folder_id) g_known_folders_fpGetFolderPath = (SHGetFolderPath_t) shell32.resolve("SHGetFolderPathW"); g_known_folders_fpGetKnownFolderPath = (SHGetKnownFolderPath_t) shell32.resolve("SHGetKnownFolderPath"); } - g_known_folders_map = new QMap(); + g_known_folders_map.reset(new QMap()); } QString folderPath; @@ -127,7 +423,7 @@ const QString &MUtils::OS::known_folder(known_folder_t folder_id) if(g_known_folders_fpGetKnownFolderPath(s_folders[folderId].guid, KF_FLAG_CREATE, NULL, &path) == S_OK) { //MessageBoxW(0, path, L"SHGetKnownFolderPath", MB_TOPMOST); - QDir folderTemp = QDir(QDir::fromNativeSeparators(MUTILS_WCHAR2QSTR(path))); + QDir folderTemp = QDir(QDir::fromNativeSeparators(MUTILS_QSTR(path))); if(folderTemp.exists()) { folderPath = folderTemp.canonicalPath(); @@ -141,7 +437,7 @@ const QString &MUtils::OS::known_folder(known_folder_t folder_id) if(g_known_folders_fpGetFolderPath(NULL, s_folders[folderId].csidl | CSIDL_FLAG_CREATE, NULL, NULL, path.data()) == S_OK) { //MessageBoxW(0, path, L"SHGetFolderPathW", MB_TOPMOST); - QDir folderTemp = QDir(QDir::fromNativeSeparators(MUTILS_WCHAR2QSTR(path.data()))); + QDir folderTemp = QDir(QDir::fromNativeSeparators(MUTILS_QSTR(path.data()))); if(folderTemp.exists()) { folderPath = folderTemp.canonicalPath(); @@ -155,3 +451,595 @@ const QString &MUtils::OS::known_folder(known_folder_t folder_id) } /////////////////////////////////////////////////////////////////////////////// +// CURRENT DATA & TIME +/////////////////////////////////////////////////////////////////////////////// + +QDate MUtils::OS::current_date(void) +{ + const DWORD MAX_PROC = 1024; + QScopedArrayPointer processes(new DWORD[MAX_PROC]); + DWORD bytesReturned = 0; + + if(!EnumProcesses(processes.data(), sizeof(DWORD) * MAX_PROC, &bytesReturned)) + { + return QDate::currentDate(); + } + + const DWORD procCount = bytesReturned / sizeof(DWORD); + ULARGE_INTEGER lastStartTime; + memset(&lastStartTime, 0, sizeof(ULARGE_INTEGER)); + + for(DWORD i = 0; i < procCount; i++) + { + if(HANDLE hProc = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, processes[i])) + { + FILETIME processTime[4]; + if(GetProcessTimes(hProc, &processTime[0], &processTime[1], &processTime[2], &processTime[3])) + { + ULARGE_INTEGER timeCreation; + timeCreation.LowPart = processTime[0].dwLowDateTime; + timeCreation.HighPart = processTime[0].dwHighDateTime; + if(timeCreation.QuadPart > lastStartTime.QuadPart) + { + lastStartTime.QuadPart = timeCreation.QuadPart; + } + } + CloseHandle(hProc); + } + } + + FILETIME lastStartTime_fileTime; + lastStartTime_fileTime.dwHighDateTime = lastStartTime.HighPart; + lastStartTime_fileTime.dwLowDateTime = lastStartTime.LowPart; + + FILETIME lastStartTime_localTime; + if(!FileTimeToLocalFileTime(&lastStartTime_fileTime, &lastStartTime_localTime)) + { + memcpy(&lastStartTime_localTime, &lastStartTime_fileTime, sizeof(FILETIME)); + } + + SYSTEMTIME lastStartTime_system; + if(!FileTimeToSystemTime(&lastStartTime_localTime, &lastStartTime_system)) + { + memset(&lastStartTime_system, 0, sizeof(SYSTEMTIME)); + lastStartTime_system.wYear = 1970; lastStartTime_system.wMonth = lastStartTime_system.wDay = 1; + } + + const QDate currentDate = QDate::currentDate(); + const QDate processDate = QDate(lastStartTime_system.wYear, lastStartTime_system.wMonth, lastStartTime_system.wDay); + 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) + { + *bIsUacEnabled = false; + } + + bool bIsProcessElevated = false; + HANDLE hToken = NULL; + + if(OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) + { + TOKEN_ELEVATION_TYPE tokenElevationType; + DWORD returnLength; + if(GetTokenInformation(hToken, TokenElevationType, &tokenElevationType, sizeof(TOKEN_ELEVATION_TYPE), &returnLength)) + { + if(returnLength == sizeof(TOKEN_ELEVATION_TYPE)) + { + switch(tokenElevationType) + { + case TokenElevationTypeDefault: + qDebug("Process token elevation type: Default -> UAC is disabled.\n"); + break; + case TokenElevationTypeFull: + qWarning("Process token elevation type: Full -> potential security risk!\n"); + bIsProcessElevated = true; + if(bIsUacEnabled) *bIsUacEnabled = true; + break; + case TokenElevationTypeLimited: + qDebug("Process token elevation type: Limited -> not elevated.\n"); + if(bIsUacEnabled) *bIsUacEnabled = true; + break; + default: + qWarning("Unknown tokenElevationType value: %d", tokenElevationType); + break; + } + } + else + { + qWarning("GetTokenInformation() return an unexpected size!"); + } + } + CloseHandle(hToken); + } + else + { + qWarning("Failed to open process token!"); + } + + 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 +/////////////////////////////////////////////////////////////////////////////// + +int MUtils::OS::network_status(void) +{ + DWORD dwFlags; + const BOOL ret = IsNetworkAlive(&dwFlags); + if(GetLastError() == 0) + { + return (ret != FALSE) ? NETWORK_TYPE_YES : NETWORK_TYPE_NON; + } + return NETWORK_TYPE_ERR; +} + +/////////////////////////////////////////////////////////////////////////////// +// MESSAGE HANDLER +/////////////////////////////////////////////////////////////////////////////// + +bool MUtils::OS::handle_os_message(const void *const message, long *result) +{ + const MSG *const msg = reinterpret_cast(message); + + switch(msg->message) + { + case WM_QUERYENDSESSION: + qWarning("WM_QUERYENDSESSION message received!"); + *result = MUtils::GUI::broadcast(MUtils::GUI::USER_EVENT_QUERYENDSESSION, false) ? TRUE : FALSE; + return true; + case WM_ENDSESSION: + qWarning("WM_ENDSESSION message received!"); + if(msg->wParam == TRUE) + { + MUtils::GUI::broadcast(MUtils::GUI::USER_EVENT_ENDSESSION, false); + MUtils::GUI::force_quit(); + exit(1); + } + *result = 0; + return true; + default: + /*ignore this message and let Qt handle it*/ + return false; + } +} + +/////////////////////////////////////////////////////////////////////////////// +// SLEEP +/////////////////////////////////////////////////////////////////////////////// + +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; +} + +/////////////////////////////////////////////////////////////////////////////// +// 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; +} + +/////////////////////////////////////////////////////////////////////////////// +// SYSTEM TIMER +/////////////////////////////////////////////////////////////////////////////// + +bool MUtils::OS::setup_timer_resolution(const quint32 &interval) +{ + return timeBeginPeriod(interval) == TIMERR_NOERROR; +} + +bool MUtils::OS::reset_timer_resolution(const quint32 &interval) +{ + return timeEndPeriod(interval) == TIMERR_NOERROR; +} + +/////////////////////////////////////////////////////////////////////////////// +// CHECK KEY STATE +/////////////////////////////////////////////////////////////////////////////// + +bool MUtils::OS::check_key_state_esc(void) +{ + return (GetAsyncKeyState(VK_ESCAPE) & 0x0001) != 0; +} + +/////////////////////////////////////////////////////////////////////////////// +// DEBUGGER CHECK +/////////////////////////////////////////////////////////////////////////////// + +#if (!(MUTILS_DEBUG)) +static __forceinline bool is_debugger_present(void) +{ + __try + { + CloseHandle((HANDLE)((DWORD_PTR)-3)); + } + __except(1) + { + return true; + } + + BOOL bHaveDebugger = FALSE; + if(CheckRemoteDebuggerPresent(GetCurrentProcess(), &bHaveDebugger)) + { + if(bHaveDebugger) return true; + } + + return IsDebuggerPresent(); +} +static __forceinline bool check_debugger_helper(void) +{ + if(is_debugger_present()) + { + MUtils::OS::fatal_exit(L"Not a debug build. Please unload debugger and try again!"); + return true; + } + return false; +} +#else +#define check_debugger_helper() (false) +#endif + +void MUtils::OS::check_debugger(void) +{ + check_debugger_helper(); +} + +static volatile bool g_debug_check = check_debugger_helper(); + +/////////////////////////////////////////////////////////////////////////////// +// FATAL EXIT +/////////////////////////////////////////////////////////////////////////////// + +static MUtils::Internal::CriticalSection g_fatal_exit_lock; +static volatile bool g_fatal_exit_flag = true; + +static DWORD WINAPI fatal_exit_helper(LPVOID lpParameter) +{ + MUtils::OS::system_message_err(L"GURU MEDITATION", (LPWSTR) lpParameter); + return 0; +} + +void MUtils::OS::fatal_exit(const wchar_t* const errorMessage) +{ + g_fatal_exit_lock.enter(); + + if(!g_fatal_exit_flag) + { + return; /*prevent recursive invocation*/ + } + + g_fatal_exit_flag = false; + + if(g_main_thread_id != GetCurrentThreadId()) + { + if(HANDLE hThreadMain = OpenThread(THREAD_SUSPEND_RESUME, FALSE, g_main_thread_id)) + { + SuspendThread(hThreadMain); /*stop main thread*/ + } + } + + if(HANDLE hThread = CreateThread(NULL, 0, fatal_exit_helper, (LPVOID) errorMessage, 0, NULL)) + { + WaitForSingleObject(hThread, INFINITE); + } + + for(;;) + { + TerminateProcess(GetCurrentProcess(), 666); + } +} + +///////////////////////////////////////////////////////////////////////////////