1 ///////////////////////////////////////////////////////////////////////////////
2 // MuldeR's Utilities for Qt
3 // Copyright (C) 2004-2014 LoRd_MuldeR <MuldeR2@GMX.de>
5 // This library is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU Lesser General Public
7 // License as published by the Free Software Foundation; either
8 // version 2.1 of the License, or (at your option) any later version.
10 // This library is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // Lesser General Public License for more details.
15 // You should have received a copy of the GNU Lesser General Public
16 // License along with this library; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 // http://www.gnu.org/licenses/lgpl-2.1.txt
20 //////////////////////////////////////////////////////////////////////////////////
25 #define WIN32_LEAN_AND_MEAN 1
34 #include <MUtils/Global.h>
35 #include <MUtils/OSSupport.h>
36 #include <MUtils/GUI.h>
37 #include "CriticalSection_Win32.h"
41 #include <QReadWriteLock>
48 static const DWORD g_main_thread_id = GetCurrentThreadId();
50 ///////////////////////////////////////////////////////////////////////////////
52 ///////////////////////////////////////////////////////////////////////////////
54 static const UINT g_msgBoxFlags = MB_TOPMOST | MB_TASKMODAL | MB_SETFOREGROUND;
56 void MUtils::OS::system_message_nfo(const wchar_t *const title, const wchar_t *const text)
58 MessageBoxW(NULL, text, title, g_msgBoxFlags | MB_ICONINFORMATION);
61 void MUtils::OS::system_message_wrn(const wchar_t *const title, const wchar_t *const text)
63 MessageBoxW(NULL, text, title, g_msgBoxFlags | MB_ICONWARNING);
66 void MUtils::OS::system_message_err(const wchar_t *const title, const wchar_t *const text)
68 MessageBoxW(NULL, text, title, g_msgBoxFlags | MB_ICONERROR);
71 ///////////////////////////////////////////////////////////////////////////////
72 // FETCH CLI ARGUMENTS
73 ///////////////////////////////////////////////////////////////////////////////
75 static QReadWriteLock g_arguments_lock;
76 static QScopedPointer<QStringList> g_arguments_list;
78 const QStringList &MUtils::OS::arguments(void)
80 QReadLocker readLock(&g_arguments_lock);
82 //Already initialized?
83 if(!g_arguments_list.isNull())
85 return (*(g_arguments_list.data()));
89 QWriteLocker writeLock(&g_arguments_lock);
91 //Still not initialized?
92 if(!g_arguments_list.isNull())
94 return (*(g_arguments_list.data()));
97 g_arguments_list.reset(new QStringList);
99 LPWSTR *szArglist = CommandLineToArgvW(GetCommandLineW(), &nArgs);
101 if(NULL != szArglist)
103 for(int i = 0; i < nArgs; i++)
105 *(g_arguments_list.data()) << MUTILS_QSTR(szArglist[i]);
107 LocalFree(szArglist);
111 qWarning("CommandLineToArgvW() has failed !!!");
114 return (*(g_arguments_list.data()));
117 ///////////////////////////////////////////////////////////////////////////////
118 // OS VERSION DETECTION
119 ///////////////////////////////////////////////////////////////////////////////
121 static bool g_os_version_initialized = false;
122 static MUtils::OS::Version::os_version_t g_os_version_info = MUtils::OS::Version::UNKNOWN_OPSYS;
123 static QReadWriteLock g_os_version_lock;
125 //Maps marketing names to the actual Windows NT versions
128 MUtils::OS::Version::os_version_t version;
129 const char friendlyName[64];
133 { MUtils::OS::Version::WINDOWS_WIN2K, "Windows 2000" }, //2000
134 { MUtils::OS::Version::WINDOWS_WINXP, "Windows XP or Windows XP Media Center Edition" }, //XP
135 { MUtils::OS::Version::WINDOWS_XPX64, "Windows Server 2003 or Windows XP x64" }, //XP_x64
136 { MUtils::OS::Version::WINDOWS_VISTA, "Windows Vista or Windows Server 2008" }, //Vista
137 { MUtils::OS::Version::WINDOWS_WIN70, "Windows 7 or Windows Server 2008 R2" }, //7
138 { MUtils::OS::Version::WINDOWS_WIN80, "Windows 8 or Windows Server 2012" }, //8
139 { MUtils::OS::Version::WINDOWS_WIN81, "Windows 8.1 or Windows Server 2012 R2" }, //8.1
140 { MUtils::OS::Version::WINDOWS_WN100, "Windows 10 or Windows Server 2014 (Preview)" }, //10
141 { MUtils::OS::Version::UNKNOWN_OPSYS, "N/A" }
144 static bool verify_os_version(const DWORD major, const DWORD minor)
146 OSVERSIONINFOEXW osvi;
147 DWORDLONG dwlConditionMask = 0;
149 //Initialize the OSVERSIONINFOEX structure
150 memset(&osvi, 0, sizeof(OSVERSIONINFOEXW));
151 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW);
152 osvi.dwMajorVersion = major;
153 osvi.dwMinorVersion = minor;
154 osvi.dwPlatformId = VER_PLATFORM_WIN32_NT;
156 //Initialize the condition mask
157 VER_SET_CONDITION(dwlConditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL);
158 VER_SET_CONDITION(dwlConditionMask, VER_MINORVERSION, VER_GREATER_EQUAL);
159 VER_SET_CONDITION(dwlConditionMask, VER_PLATFORMID, VER_EQUAL);
162 const BOOL ret = VerifyVersionInfoW(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_PLATFORMID, dwlConditionMask);
167 if(GetLastError() != ERROR_OLD_WIN_VERSION)
169 qWarning("VerifyVersionInfo() system call has failed!");
173 return (ret != FALSE);
176 static bool get_real_os_version(unsigned int *major, unsigned int *minor, bool *pbOverride)
181 //Initialize local variables
182 OSVERSIONINFOEXW osvi;
183 memset(&osvi, 0, sizeof(OSVERSIONINFOEXW));
184 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW);
186 //Try GetVersionEx() first
187 if(GetVersionExW((LPOSVERSIONINFOW)&osvi) == FALSE)
189 qWarning("GetVersionEx() has failed, cannot detect Windows version!");
193 //Make sure we are running on NT
194 if(osvi.dwPlatformId == VER_PLATFORM_WIN32_NT)
196 *major = osvi.dwMajorVersion;
197 *minor = osvi.dwMinorVersion;
201 qWarning("Not running on Windows NT, unsupported operating system!");
205 //Determine the real *major* version first
208 const DWORD nextMajor = (*major) + 1;
209 if(verify_os_version(nextMajor, 0))
219 //Now also determine the real *minor* version
222 const DWORD nextMinor = (*minor) + 1;
223 if(verify_os_version((*major), nextMinor))
235 const MUtils::OS::Version::os_version_t &MUtils::OS::os_version(void)
237 QReadLocker readLock(&g_os_version_lock);
239 //Already initialized?
240 if(g_os_version_initialized)
242 return g_os_version_info;
246 QWriteLocker writeLock(&g_os_version_lock);
249 if(g_os_version_initialized)
251 return g_os_version_info;
255 unsigned int major, minor; bool overrideFlg;
256 if(get_real_os_version(&major, &minor, &overrideFlg))
258 g_os_version_info.type = Version::OS_WINDOWS;
259 g_os_version_info.versionMajor = major;
260 g_os_version_info.versionMinor = minor;
261 g_os_version_info.overrideFlag = overrideFlg;
265 qWarning("Failed to determin the operating system version!");
269 g_os_version_initialized = true;
270 return g_os_version_info;
273 const char *MUtils::OS::os_friendly_name(const MUtils::OS::Version::os_version_t &os_version)
275 for(size_t i = 0; g_os_version_lut[i].version != MUtils::OS::Version::UNKNOWN_OPSYS; i++)
277 if(os_version == g_os_version_lut[i].version)
279 return g_os_version_lut[i].friendlyName;
286 ///////////////////////////////////////////////////////////////////////////////
288 ///////////////////////////////////////////////////////////////////////////////
290 static bool g_wine_deteced = false;
291 static bool g_wine_initialized = false;
292 static QReadWriteLock g_wine_lock;
294 static const bool detect_wine(void)
296 bool is_wine = false;
298 QLibrary ntdll("ntdll.dll");
301 if(ntdll.resolve("wine_nt_to_unix_file_name") != NULL) is_wine = true;
302 if(ntdll.resolve("wine_get_version") != NULL) is_wine = true;
309 const bool &MUtils::OS::running_on_wine(void)
311 QReadLocker readLock(&g_wine_lock);
313 //Already initialized?
314 if(g_wine_initialized)
316 return g_wine_deteced;
320 QWriteLocker writeLock(&g_wine_lock);
323 if(g_wine_initialized)
325 return g_wine_deteced;
329 g_wine_deteced = detect_wine();
330 g_wine_initialized = true;
332 return g_wine_deteced;
335 ///////////////////////////////////////////////////////////////////////////////
337 ///////////////////////////////////////////////////////////////////////////////
339 typedef QMap<size_t, QString> KFMap;
340 typedef HRESULT (WINAPI *SHGetKnownFolderPath_t)(const GUID &rfid, DWORD dwFlags, HANDLE hToken, PWSTR *ppszPath);
341 typedef HRESULT (WINAPI *SHGetFolderPath_t)(HWND hwndOwner, int nFolder, HANDLE hToken, DWORD dwFlags, LPWSTR pszPath);
343 static QScopedPointer<KFMap> g_known_folders_map;
344 static SHGetKnownFolderPath_t g_known_folders_fpGetKnownFolderPath;
345 static SHGetFolderPath_t g_known_folders_fpGetFolderPath;
346 static QReadWriteLock g_known_folders_lock;
348 const QString &MUtils::OS::known_folder(known_folder_t folder_id)
350 static const int CSIDL_FLAG_CREATE = 0x8000;
351 typedef enum { KF_FLAG_CREATE = 0x00008000 } kf_flags_t;
360 { 0x001c, {0xF1B32785,0x6FBA,0x4FCF,{0x9D,0x55,0x7B,0x8E,0x7F,0x15,0x70,0x91}} }, //CSIDL_LOCAL_APPDATA
361 { 0x0026, {0x905e63b6,0xc1bf,0x494e,{0xb2,0x9c,0x65,0xb7,0x32,0xd3,0xd2,0x1a}} }, //CSIDL_PROGRAM_FILES
362 { 0x0024, {0xF38BF404,0x1D43,0x42F2,{0x93,0x05,0x67,0xDE,0x0B,0x28,0xFC,0x23}} }, //CSIDL_WINDOWS_FOLDER
363 { 0x0025, {0x1AC14E77,0x02E7,0x4E5D,{0xB7,0x44,0x2E,0xB1,0xAE,0x51,0x98,0xB7}} }, //CSIDL_SYSTEM_FOLDER
366 size_t folderId = size_t(-1);
370 case FOLDER_LOCALAPPDATA: folderId = 0; break;
371 case FOLDER_PROGRAMFILES: folderId = 1; break;
372 case FOLDER_SYSTROOT_DIR: folderId = 2; break;
373 case FOLDER_SYSTEMFOLDER: folderId = 3; break;
376 if(folderId == size_t(-1))
378 qWarning("Invalid 'known' folder was requested!");
379 return *reinterpret_cast<QString*>(NULL);
382 QReadLocker readLock(&g_known_folders_lock);
385 if(!g_known_folders_map.isNull())
387 if(g_known_folders_map->contains(folderId))
389 return g_known_folders_map->operator[](folderId);
393 //Obtain write lock to initialize
395 QWriteLocker writeLock(&g_known_folders_lock);
397 //Still not in cache?
398 if(!g_known_folders_map.isNull())
400 if(g_known_folders_map->contains(folderId))
402 return g_known_folders_map->operator[](folderId);
406 //Initialize on first call
407 if(g_known_folders_map.isNull())
409 QLibrary shell32("shell32.dll");
412 g_known_folders_fpGetFolderPath = (SHGetFolderPath_t) shell32.resolve("SHGetFolderPathW");
413 g_known_folders_fpGetKnownFolderPath = (SHGetKnownFolderPath_t) shell32.resolve("SHGetKnownFolderPath");
415 g_known_folders_map.reset(new QMap<size_t, QString>());
420 //Now try to get the folder path!
421 if(g_known_folders_fpGetKnownFolderPath)
424 if(g_known_folders_fpGetKnownFolderPath(s_folders[folderId].guid, KF_FLAG_CREATE, NULL, &path) == S_OK)
426 //MessageBoxW(0, path, L"SHGetKnownFolderPath", MB_TOPMOST);
427 QDir folderTemp = QDir(QDir::fromNativeSeparators(MUTILS_QSTR(path)));
428 if(folderTemp.exists())
430 folderPath = folderTemp.canonicalPath();
435 else if(g_known_folders_fpGetFolderPath)
437 QScopedArrayPointer<WCHAR> path(new WCHAR[4096]);
438 if(g_known_folders_fpGetFolderPath(NULL, s_folders[folderId].csidl | CSIDL_FLAG_CREATE, NULL, NULL, path.data()) == S_OK)
440 //MessageBoxW(0, path, L"SHGetFolderPathW", MB_TOPMOST);
441 QDir folderTemp = QDir(QDir::fromNativeSeparators(MUTILS_QSTR(path.data())));
442 if(folderTemp.exists())
444 folderPath = folderTemp.canonicalPath();
450 g_known_folders_map->insert(folderId, folderPath);
451 return g_known_folders_map->operator[](folderId);
454 ///////////////////////////////////////////////////////////////////////////////
455 // CURRENT DATA & TIME
456 ///////////////////////////////////////////////////////////////////////////////
458 QDate MUtils::OS::current_date(void)
460 const DWORD MAX_PROC = 1024;
461 QScopedArrayPointer<DWORD> processes(new DWORD[MAX_PROC]);
462 DWORD bytesReturned = 0;
464 if(!EnumProcesses(processes.data(), sizeof(DWORD) * MAX_PROC, &bytesReturned))
466 return QDate::currentDate();
469 const DWORD procCount = bytesReturned / sizeof(DWORD);
470 ULARGE_INTEGER lastStartTime;
471 memset(&lastStartTime, 0, sizeof(ULARGE_INTEGER));
473 for(DWORD i = 0; i < procCount; i++)
475 if(HANDLE hProc = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, processes[i]))
477 FILETIME processTime[4];
478 if(GetProcessTimes(hProc, &processTime[0], &processTime[1], &processTime[2], &processTime[3]))
480 ULARGE_INTEGER timeCreation;
481 timeCreation.LowPart = processTime[0].dwLowDateTime;
482 timeCreation.HighPart = processTime[0].dwHighDateTime;
483 if(timeCreation.QuadPart > lastStartTime.QuadPart)
485 lastStartTime.QuadPart = timeCreation.QuadPart;
492 FILETIME lastStartTime_fileTime;
493 lastStartTime_fileTime.dwHighDateTime = lastStartTime.HighPart;
494 lastStartTime_fileTime.dwLowDateTime = lastStartTime.LowPart;
496 FILETIME lastStartTime_localTime;
497 if(!FileTimeToLocalFileTime(&lastStartTime_fileTime, &lastStartTime_localTime))
499 memcpy(&lastStartTime_localTime, &lastStartTime_fileTime, sizeof(FILETIME));
502 SYSTEMTIME lastStartTime_system;
503 if(!FileTimeToSystemTime(&lastStartTime_localTime, &lastStartTime_system))
505 memset(&lastStartTime_system, 0, sizeof(SYSTEMTIME));
506 lastStartTime_system.wYear = 1970; lastStartTime_system.wMonth = lastStartTime_system.wDay = 1;
509 const QDate currentDate = QDate::currentDate();
510 const QDate processDate = QDate(lastStartTime_system.wYear, lastStartTime_system.wMonth, lastStartTime_system.wDay);
511 return (currentDate >= processDate) ? currentDate : processDate;
514 quint64 MUtils::OS::current_file_time(void)
517 GetSystemTimeAsFileTime(&fileTime);
520 temp.HighPart = fileTime.dwHighDateTime;
521 temp.LowPart = fileTime.dwLowDateTime;
523 return temp.QuadPart;
526 ///////////////////////////////////////////////////////////////////////////////
528 ///////////////////////////////////////////////////////////////////////////////
530 static bool user_is_admin_helper(void)
532 HANDLE hToken = NULL;
533 if(!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
539 if(!GetTokenInformation(hToken, TokenGroups, NULL, 0, &dwSize))
541 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
548 PTOKEN_GROUPS lpGroups = (PTOKEN_GROUPS) malloc(dwSize);
555 if(!GetTokenInformation(hToken, TokenGroups, lpGroups, dwSize, &dwSize))
562 PSID lpSid = NULL; SID_IDENTIFIER_AUTHORITY Authority = {SECURITY_NT_AUTHORITY};
563 if(!AllocateAndInitializeSid(&Authority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &lpSid))
570 bool bResult = false;
571 for(DWORD i = 0; i < lpGroups->GroupCount; i++)
573 if(EqualSid(lpSid, lpGroups->Groups[i].Sid))
586 bool MUtils::OS::is_elevated(bool *bIsUacEnabled)
590 *bIsUacEnabled = false;
593 bool bIsProcessElevated = false;
594 HANDLE hToken = NULL;
596 if(OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
598 TOKEN_ELEVATION_TYPE tokenElevationType;
600 if(GetTokenInformation(hToken, TokenElevationType, &tokenElevationType, sizeof(TOKEN_ELEVATION_TYPE), &returnLength))
602 if(returnLength == sizeof(TOKEN_ELEVATION_TYPE))
604 switch(tokenElevationType)
606 case TokenElevationTypeDefault:
607 qDebug("Process token elevation type: Default -> UAC is disabled.\n");
609 case TokenElevationTypeFull:
610 qWarning("Process token elevation type: Full -> potential security risk!\n");
611 bIsProcessElevated = true;
612 if(bIsUacEnabled) *bIsUacEnabled = true;
614 case TokenElevationTypeLimited:
615 qDebug("Process token elevation type: Limited -> not elevated.\n");
616 if(bIsUacEnabled) *bIsUacEnabled = true;
619 qWarning("Unknown tokenElevationType value: %d", tokenElevationType);
625 qWarning("GetTokenInformation() return an unexpected size!");
632 qWarning("Failed to open process token!");
635 return bIsProcessElevated;
638 bool MUtils::OS::user_is_admin(void)
640 bool isAdmin = false;
642 //Check for process elevation and UAC support first!
643 if(MUtils::OS::is_elevated(&isAdmin))
645 qWarning("Process is elevated -> user is admin!");
649 //If not elevated and UAC is not available -> user must be in admin group!
652 qDebug("UAC is disabled/unavailable -> checking for Administrators group");
653 isAdmin = user_is_admin_helper();
659 ///////////////////////////////////////////////////////////////////////////////
661 ///////////////////////////////////////////////////////////////////////////////
663 int MUtils::OS::network_status(void)
666 const BOOL ret = IsNetworkAlive(&dwFlags);
667 if(GetLastError() == 0)
669 return (ret != FALSE) ? NETWORK_TYPE_YES : NETWORK_TYPE_NON;
671 return NETWORK_TYPE_ERR;
674 ///////////////////////////////////////////////////////////////////////////////
676 ///////////////////////////////////////////////////////////////////////////////
678 bool MUtils::OS::handle_os_message(const void *const message, long *result)
680 const MSG *const msg = reinterpret_cast<const MSG*>(message);
684 case WM_QUERYENDSESSION:
685 qWarning("WM_QUERYENDSESSION message received!");
686 *result = MUtils::GUI::broadcast(MUtils::GUI::USER_EVENT_QUERYENDSESSION, false) ? TRUE : FALSE;
689 qWarning("WM_ENDSESSION message received!");
690 if(msg->wParam == TRUE)
692 MUtils::GUI::broadcast(MUtils::GUI::USER_EVENT_ENDSESSION, false);
693 MUtils::GUI::force_quit();
699 /*ignore this message and let Qt handle it*/
704 ///////////////////////////////////////////////////////////////////////////////
706 ///////////////////////////////////////////////////////////////////////////////
708 void MUtils::OS::sleep_ms(const size_t &duration)
710 Sleep((DWORD) duration);
713 ///////////////////////////////////////////////////////////////////////////////
715 ///////////////////////////////////////////////////////////////////////////////
717 bool MUtils::OS::is_executable_file(const QString &path)
719 bool bIsExecutable = false;
721 if(GetBinaryType(MUTILS_WCHR(QDir::toNativeSeparators(path)), &binaryType))
723 bIsExecutable = (binaryType == SCS_32BIT_BINARY || binaryType == SCS_64BIT_BINARY);
725 return bIsExecutable;
728 ///////////////////////////////////////////////////////////////////////////////
729 // HIBERNATION / SHUTDOWN
730 ///////////////////////////////////////////////////////////////////////////////
732 bool MUtils::OS::is_hibernation_supported(void)
734 bool hibernationSupported = false;
736 SYSTEM_POWER_CAPABILITIES pwrCaps;
737 SecureZeroMemory(&pwrCaps, sizeof(SYSTEM_POWER_CAPABILITIES));
739 if(GetPwrCapabilities(&pwrCaps))
741 hibernationSupported = pwrCaps.SystemS4 && pwrCaps.HiberFilePresent;
744 return hibernationSupported;
747 bool MUtils::OS::shutdown_computer(const QString &message, const unsigned long timeout, const bool forceShutdown, const bool hibernate)
749 HANDLE hToken = NULL;
751 if(OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
753 TOKEN_PRIVILEGES privileges;
754 memset(&privileges, 0, sizeof(TOKEN_PRIVILEGES));
755 privileges.PrivilegeCount = 1;
756 privileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
758 if(LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &privileges.Privileges[0].Luid))
760 if(AdjustTokenPrivileges(hToken, FALSE, &privileges, NULL, NULL, NULL))
764 if(SetSuspendState(TRUE, TRUE, TRUE))
769 const DWORD reason = SHTDN_REASON_MAJOR_APPLICATION | SHTDN_REASON_FLAG_PLANNED;
770 return InitiateSystemShutdownEx(NULL, const_cast<wchar_t*>(MUTILS_WCHR(message)), timeout, forceShutdown ? TRUE : FALSE, FALSE, reason);
778 ///////////////////////////////////////////////////////////////////////////////
780 ///////////////////////////////////////////////////////////////////////////////
782 bool MUtils::OS::free_diskspace(const QString &path, quint64 &freeSpace)
784 ULARGE_INTEGER freeBytesAvailable, totalNumberOfBytes, totalNumberOfFreeBytes;
785 if(GetDiskFreeSpaceExW(reinterpret_cast<const wchar_t*>(QDir::toNativeSeparators(path).utf16()), &freeBytesAvailable, &totalNumberOfBytes, &totalNumberOfFreeBytes))
787 freeSpace = freeBytesAvailable.QuadPart;
795 ///////////////////////////////////////////////////////////////////////////////
797 ///////////////////////////////////////////////////////////////////////////////
799 bool MUtils::OS::shell_open(const QWidget *parent, const QString &url, const QString ¶meters, const QString &directory, const bool explore)
801 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;
804 bool MUtils::OS::shell_open(const QWidget *parent, const QString &url, const bool explore)
806 return shell_open(parent, url, QString(), QString(), explore);
809 ///////////////////////////////////////////////////////////////////////////////
811 ///////////////////////////////////////////////////////////////////////////////
813 bool MUtils::OS::open_media_file(const QString &mediaFilePath)
815 const static wchar_t *registryPrefix[2] = { L"SOFTWARE\\", L"SOFTWARE\\Wow6432Node\\" };
816 const static wchar_t *registryKeys[3] =
818 L"Microsoft\\Windows\\CurrentVersion\\Uninstall\\{97D341C8-B0D1-4E4A-A49A-C30B52F168E9}",
819 L"Microsoft\\Windows\\CurrentVersion\\Uninstall\\{DB9E4EAB-2717-499F-8D56-4CC8A644AB60}",
822 const static wchar_t *appNames[4] = { L"smplayer_portable.exe", L"smplayer.exe", L"MPUI.exe", L"foobar2000.exe" };
823 const static wchar_t *valueNames[2] = { L"InstallLocation", L"InstallDir" };
825 for(size_t i = 0; i < 3; i++)
827 for(size_t j = 0; j < 2; j++)
830 HKEY registryKeyHandle = NULL;
832 const QString currentKey = MUTILS_QSTR(registryPrefix[j]).append(MUTILS_QSTR(registryKeys[i]));
833 if(RegOpenKeyExW(HKEY_LOCAL_MACHINE, MUTILS_WCHR(currentKey), 0, KEY_READ, ®istryKeyHandle) == ERROR_SUCCESS)
835 for(size_t k = 0; k < 2; k++)
837 wchar_t Buffer[4096];
838 DWORD BuffSize = sizeof(wchar_t*) * 4096;
839 DWORD DataType = REG_NONE;
840 if(RegQueryValueExW(registryKeyHandle, valueNames[k], 0, &DataType, reinterpret_cast<BYTE*>(Buffer), &BuffSize) == ERROR_SUCCESS)
842 if((DataType == REG_SZ) || (DataType == REG_EXPAND_SZ) || (DataType == REG_LINK))
844 mplayerPath = MUTILS_QSTR(Buffer);
849 RegCloseKey(registryKeyHandle);
852 if(!mplayerPath.isEmpty())
854 QDir mplayerDir(mplayerPath);
855 if(mplayerDir.exists())
857 for(size_t k = 0; k < 4; k++)
859 if(mplayerDir.exists(MUTILS_QSTR(appNames[k])))
861 qDebug("Player found at:\n%s\n", MUTILS_UTF8(mplayerDir.absoluteFilePath(MUTILS_QSTR(appNames[k]))));
862 QProcess::startDetached(mplayerDir.absoluteFilePath(MUTILS_QSTR(appNames[k])), QStringList() << QDir::toNativeSeparators(mediaFilePath));
873 ///////////////////////////////////////////////////////////////////////////////
875 ///////////////////////////////////////////////////////////////////////////////
877 static bool change_process_priority_helper(const HANDLE hProcess, const int priority)
881 switch(qBound(-2, priority, 2))
884 ok = (SetPriorityClass(hProcess, HIGH_PRIORITY_CLASS) == TRUE);
887 if(!(ok = (SetPriorityClass(hProcess, ABOVE_NORMAL_PRIORITY_CLASS) == TRUE)))
889 ok = (SetPriorityClass(hProcess, HIGH_PRIORITY_CLASS) == TRUE);
893 ok = (SetPriorityClass(hProcess, NORMAL_PRIORITY_CLASS) == TRUE);
896 if(!(ok = (SetPriorityClass(hProcess, BELOW_NORMAL_PRIORITY_CLASS) == TRUE)))
898 ok = (SetPriorityClass(hProcess, IDLE_PRIORITY_CLASS) == TRUE);
902 ok = (SetPriorityClass(hProcess, IDLE_PRIORITY_CLASS) == TRUE);
909 bool MUtils::OS::change_process_priority(const int priority)
911 return change_process_priority_helper(GetCurrentProcess(), priority);
914 bool MUtils::OS::change_process_priority(const QProcess *proc, const int priority)
916 if(Q_PID qPid = proc->pid())
918 return change_process_priority_helper(qPid->hProcess, priority);
926 ///////////////////////////////////////////////////////////////////////////////
928 ///////////////////////////////////////////////////////////////////////////////
930 quint32 MUtils::OS::process_id(const QProcess *proc)
932 PROCESS_INFORMATION *procInf = proc->pid();
933 return (procInf) ? procInf->dwProcessId : NULL;
936 ///////////////////////////////////////////////////////////////////////////////
938 ///////////////////////////////////////////////////////////////////////////////
940 #if (!(MUTILS_DEBUG))
941 static __forceinline bool is_debugger_present(void)
945 CloseHandle((HANDLE)((DWORD_PTR)-3));
952 BOOL bHaveDebugger = FALSE;
953 if(CheckRemoteDebuggerPresent(GetCurrentProcess(), &bHaveDebugger))
955 if(bHaveDebugger) return true;
958 return IsDebuggerPresent();
960 static __forceinline bool check_debugger_helper(void)
962 if(is_debugger_present())
964 MUtils::OS::fatal_exit(L"Not a debug build. Please unload debugger and try again!");
970 #define check_debugger_helper() (false)
973 void MUtils::OS::check_debugger(void)
975 check_debugger_helper();
978 static volatile bool g_debug_check = check_debugger_helper();
980 ///////////////////////////////////////////////////////////////////////////////
982 ///////////////////////////////////////////////////////////////////////////////
984 static MUtils::Internal::CriticalSection g_fatal_exit_lock;
985 static volatile bool g_fatal_exit_flag = true;
987 static DWORD WINAPI fatal_exit_helper(LPVOID lpParameter)
989 MUtils::OS::system_message_err(L"GURU MEDITATION", (LPWSTR) lpParameter);
993 void MUtils::OS::fatal_exit(const wchar_t* const errorMessage)
995 g_fatal_exit_lock.enter();
997 if(!g_fatal_exit_flag)
999 return; /*prevent recursive invocation*/
1002 g_fatal_exit_flag = false;
1004 if(g_main_thread_id != GetCurrentThreadId())
1006 if(HANDLE hThreadMain = OpenThread(THREAD_SUSPEND_RESUME, FALSE, g_main_thread_id))
1008 SuspendThread(hThreadMain); /*stop main thread*/
1012 if(HANDLE hThread = CreateThread(NULL, 0, fatal_exit_helper, (LPVOID) errorMessage, 0, NULL))
1014 WaitForSingleObject(hThread, INFINITE);
1019 TerminateProcess(GetCurrentProcess(), 666);
1023 ///////////////////////////////////////////////////////////////////////////////