Updated Nero Digital address.
[LameXP.git] / src / Global_Win32.cpp
blob09a95d51c8768d9ca20d8263a11794105e2022af
1 ///////////////////////////////////////////////////////////////////////////////
2 // LameXP - Audio Encoder Front-End
3 // Copyright (C) 2004-2014 LoRd_MuldeR <MuldeR2@GMX.de>
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 2 of the License, or
8 // (at your option) any later version, but always including the *additional*
9 // restrictions defined in the "License.txt" file.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License along
17 // with this program; if not, write to the Free Software Foundation, Inc.,
18 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 // http://www.gnu.org/licenses/gpl-2.0.txt
21 ///////////////////////////////////////////////////////////////////////////////
23 #include "Global.h"
25 //Target version
26 #include "Targetver.h"
28 //Visual Leaks Detector
29 #include <vld.h>
31 //Windows includes
32 #define NOMINMAX
33 #define WIN32_LEAN_AND_MEAN
34 #include <Windows.h>
35 #include <MMSystem.h>
36 #include <ShellAPI.h>
37 #include <SensAPI.h>
38 #include <Objbase.h>
39 #include <PowrProf.h>
40 #include <Psapi.h>
41 #include <dwmapi.h>
43 //Qt includes
44 #include <QApplication>
45 #include <QDate>
46 #include <QDir>
47 #include <QEvent>
48 #include <QIcon>
49 #include <QImageReader>
50 #include <QLibrary>
51 #include <QLibraryInfo>
52 #include <QMap>
53 #include <QMessageBox>
54 #include <QPlastiqueStyle>
55 #include <QProcess>
56 #include <QReadWriteLock>
57 #include <QRegExp>
58 #include <QSysInfo>
59 #include <QTextCodec>
60 #include <QTimer>
61 #include <QTranslator>
62 #include <QUuid>
63 #include <QResource>
65 //LameXP includes
66 #define LAMEXP_INC_CONFIG
67 #include "Resource.h"
68 #include "Config.h"
70 //CRT includes
71 #include <cstdio>
72 #include <iostream>
73 #include <fstream>
74 #include <io.h>
75 #include <fcntl.h>
76 #include <intrin.h>
77 #include <cmath>
78 #include <ctime>
79 #include <process.h>
80 #include <csignal>
82 //Initialize static Qt plugins
83 #ifdef QT_NODLL
84 #if QT_VERSION < QT_VERSION_CHECK(5,0,0)
85 Q_IMPORT_PLUGIN(qico)
86 Q_IMPORT_PLUGIN(qsvg)
87 #else
88 Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin)
89 Q_IMPORT_PLUGIN(QICOPlugin)
90 #endif
91 #endif
93 ///////////////////////////////////////////////////////////////////////////////
94 // HELPER MACROS
95 ///////////////////////////////////////////////////////////////////////////////
97 #define _LAMEXP_MAKE_STR(STR) #STR
98 #define LAMEXP_MAKE_STR(STR) _LAMEXP_MAKE_STR(STR)
100 //String helper
101 #define CLEAN_OUTPUT_STRING(STR) do \
103 const char CTRL_CHARS[3] = { '\r', '\n', '\t' }; \
104 for(size_t i = 0; i < 3; i++) \
106 while(char *pos = strchr((STR), CTRL_CHARS[i])) *pos = char(0x20); \
109 while(0)
111 //String helper
112 #define TRIM_LEFT(STR) do \
114 const char WHITE_SPACE[4] = { char(0x20), '\r', '\n', '\t' }; \
115 for(size_t i = 0; i < 4; i++) \
117 while(*(STR) == WHITE_SPACE[i]) (STR)++; \
120 while(0)
122 ///////////////////////////////////////////////////////////////////////////////
123 // GLOBAL TYPES
124 ///////////////////////////////////////////////////////////////////////////////
126 typedef HRESULT (WINAPI *SHGetKnownFolderPath_t)(const GUID &rfid, DWORD dwFlags, HANDLE hToken, PWSTR *ppszPath);
127 typedef HRESULT (WINAPI *SHGetFolderPath_t)(HWND hwndOwner, int nFolder, HANDLE hToken, DWORD dwFlags, LPWSTR pszPath);
129 ///////////////////////////////////////////////////////////////////////////////
130 // CRITICAL SECTION
131 ///////////////////////////////////////////////////////////////////////////////
134 * wrapper for native Win32 critical sections
136 class CriticalSection
138 public:
139 inline CriticalSection(void)
141 InitializeCriticalSection(&m_win32criticalSection);
144 inline ~CriticalSection(void)
146 DeleteCriticalSection(&m_win32criticalSection);
149 inline void enter(void)
151 EnterCriticalSection(&m_win32criticalSection);
154 inline bool tryEnter(void)
156 return TryEnterCriticalSection(&m_win32criticalSection);
159 inline void leave(void)
161 LeaveCriticalSection(&m_win32criticalSection);
164 protected:
165 CRITICAL_SECTION m_win32criticalSection;
169 * RAII-style critical section locker
171 class CSLocker
173 public:
174 inline CSLocker(CriticalSection &criticalSection)
176 m_locked(false),
177 m_criticalSection(criticalSection)
179 m_criticalSection.enter();
180 m_locked = true;
183 inline ~CSLocker(void)
185 forceUnlock();
188 inline void forceUnlock(void)
190 if(m_locked)
192 m_criticalSection.leave();
193 m_locked = false;
196 protected:
197 volatile bool m_locked;
198 CriticalSection &m_criticalSection;
201 ///////////////////////////////////////////////////////////////////////////////
202 // GLOBAL VARS
203 ///////////////////////////////////////////////////////////////////////////////
205 //Console attached flag
206 static bool g_lamexp_console_attached = false;
208 //Fatal exit flags
209 static volatile bool g_lamexp_fatal_flag = true;
210 static CriticalSection g_lamexp_fatal_lock;
212 //Global locks
213 static CriticalSection g_lamexp_message_lock;
215 //Special folders
216 static struct
218 QMap<size_t, QString> *knownFolders;
219 SHGetKnownFolderPath_t getKnownFolderPath;
220 SHGetFolderPath_t getFolderPath;
221 QReadWriteLock lock;
223 g_lamexp_known_folder;
225 //CLI Arguments
226 static struct
228 QStringList *list;
229 QReadWriteLock lock;
231 g_lamexp_argv;
233 //OS Version
234 static struct
236 bool bInitialized;
237 lamexp_os_version_t version;
238 QReadWriteLock lock;
240 g_lamexp_os_version;
242 //Wine detection
243 static struct
245 bool bInitialized;
246 bool bIsWine;
247 QReadWriteLock lock;
249 g_lamexp_wine;
251 //Win32 Theme support
252 static struct
254 bool bInitialized;
255 bool bThemesEnabled;
256 QReadWriteLock lock;
258 g_lamexp_themes_enabled;
260 //Win32 DWM API functions
261 static struct
263 bool bInitialized;
264 HRESULT (__stdcall *dwmIsCompositionEnabled)(BOOL *bEnabled);
265 HRESULT (__stdcall *dwmExtendFrameIntoClientArea)(HWND hWnd, const MARGINS* pMarInset);
266 HRESULT (__stdcall *dwmEnableBlurBehindWindow)(HWND hWnd, const DWM_BLURBEHIND* pBlurBehind);
267 QLibrary *dwmapi_dll;
268 QReadWriteLock lock;
270 g_lamexp_dwmapi;
272 //Sound file cache
273 static struct
275 QHash<const QString, const unsigned char*> *sound_db;
276 QReadWriteLock lock;
278 g_lamexp_sounds;
280 //Image formats
281 static const char *g_lamexp_imageformats[] = {"bmp", "png", "jpg", "gif", "ico", "xpm", NULL}; //"svg"
283 //Main thread ID
284 static const DWORD g_main_thread_id = GetCurrentThreadId();
286 //Log file
287 static FILE *g_lamexp_log_file = NULL;
289 //Localization
290 const char* LAMEXP_DEFAULT_LANGID = "en";
291 const char* LAMEXP_DEFAULT_TRANSLATION = "LameXP_EN.qm";
293 //Known Windows versions - maps marketing names to the actual Windows NT versions
294 const lamexp_os_version_t lamexp_winver_win2k = {5,0};
295 const lamexp_os_version_t lamexp_winver_winxp = {5,1};
296 const lamexp_os_version_t lamexp_winver_xpx64 = {5,2};
297 const lamexp_os_version_t lamexp_winver_vista = {6,0};
298 const lamexp_os_version_t lamexp_winver_win70 = {6,1};
299 const lamexp_os_version_t lamexp_winver_win80 = {6,2};
300 const lamexp_os_version_t lamexp_winver_win81 = {6,3};
302 //GURU MEDITATION
303 static const char *GURU_MEDITATION = "\n\nGURU MEDITATION !!!\n\n";
305 ///////////////////////////////////////////////////////////////////////////////
306 // GLOBAL FUNCTIONS
307 ///////////////////////////////////////////////////////////////////////////////
310 * Verify a specific Windows version
312 static bool lamexp_verify_os_version(const DWORD major, const DWORD minor)
314 OSVERSIONINFOEXW osvi;
315 DWORDLONG dwlConditionMask = 0;
317 //Initialize the OSVERSIONINFOEX structure
318 memset(&osvi, 0, sizeof(OSVERSIONINFOEXW));
319 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW);
320 osvi.dwMajorVersion = major;
321 osvi.dwMinorVersion = minor;
322 osvi.dwPlatformId = VER_PLATFORM_WIN32_NT;
324 //Initialize the condition mask
325 VER_SET_CONDITION(dwlConditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL);
326 VER_SET_CONDITION(dwlConditionMask, VER_MINORVERSION, VER_GREATER_EQUAL);
327 VER_SET_CONDITION(dwlConditionMask, VER_PLATFORMID, VER_EQUAL);
329 // Perform the test
330 const BOOL ret = VerifyVersionInfoW(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_PLATFORMID, dwlConditionMask);
332 //Error checking
333 if(!ret)
335 if(GetLastError() != ERROR_OLD_WIN_VERSION)
337 qWarning("VerifyVersionInfo() system call has failed!");
341 return (ret != FALSE);
345 * Determine the *real* Windows version
347 static bool lamexp_get_real_os_version(unsigned int *major, unsigned int *minor, bool *pbOverride)
349 *major = *minor = 0;
350 *pbOverride = false;
352 //Initialize local variables
353 OSVERSIONINFOEXW osvi;
354 memset(&osvi, 0, sizeof(OSVERSIONINFOEXW));
355 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW);
357 //Try GetVersionEx() first
358 if(GetVersionExW((LPOSVERSIONINFOW)&osvi) == FALSE)
360 qWarning("GetVersionEx() has failed, cannot detect Windows version!");
361 return false;
364 //Make sure we are running on NT
365 if(osvi.dwPlatformId == VER_PLATFORM_WIN32_NT)
367 *major = osvi.dwMajorVersion;
368 *minor = osvi.dwMinorVersion;
370 else
372 qWarning("Not running on Windows NT, unsupported operating system!");
373 return false;
376 //Determine the real *major* version first
377 forever
379 const DWORD nextMajor = (*major) + 1;
380 if(lamexp_verify_os_version(nextMajor, 0))
382 *pbOverride = true;
383 *major = nextMajor;
384 *minor = 0;
385 continue;
387 break;
390 //Now also determine the real *minor* version
391 forever
393 const DWORD nextMinor = (*minor) + 1;
394 if(lamexp_verify_os_version((*major), nextMinor))
396 *pbOverride = true;
397 *minor = nextMinor;
398 continue;
400 break;
403 return true;
407 * Get the native operating system version
409 const lamexp_os_version_t &lamexp_get_os_version(void)
411 QReadLocker readLock(&g_lamexp_os_version.lock);
413 //Already initialized?
414 if(g_lamexp_os_version.bInitialized)
416 return g_lamexp_os_version.version;
419 readLock.unlock();
420 QWriteLocker writeLock(&g_lamexp_os_version.lock);
422 //Detect OS version
423 if(!g_lamexp_os_version.bInitialized)
425 unsigned int major, minor; bool oflag;
426 if(lamexp_get_real_os_version(&major, &minor, &oflag))
428 g_lamexp_os_version.version.versionMajor = major;
429 g_lamexp_os_version.version.versionMinor = minor;
430 g_lamexp_os_version.version.overrideFlag = oflag;
431 g_lamexp_os_version.bInitialized = true;
433 else
435 qWarning("Failed to determin the operating system version!");
439 return g_lamexp_os_version.version;
443 * Check if we are running under wine
445 bool lamexp_detect_wine(void)
447 QReadLocker readLock(&g_lamexp_wine.lock);
449 //Already initialized?
450 if(g_lamexp_wine.bInitialized)
452 return g_lamexp_wine.bIsWine;
455 readLock.unlock();
456 QWriteLocker writeLock(&g_lamexp_wine.lock);
458 if(!g_lamexp_wine.bInitialized)
460 g_lamexp_wine.bIsWine = false;
461 QLibrary ntdll("ntdll.dll");
462 if(ntdll.load())
464 if(ntdll.resolve("wine_nt_to_unix_file_name") != NULL) g_lamexp_wine.bIsWine = true;
465 if(ntdll.resolve("wine_get_version") != NULL) g_lamexp_wine.bIsWine = true;
466 ntdll.unload();
468 g_lamexp_wine.bInitialized = true;
471 return g_lamexp_wine.bIsWine;
475 * Change console text color
477 static void lamexp_console_color(FILE* file, WORD attributes)
479 const HANDLE hConsole = (HANDLE)(_get_osfhandle(_fileno(file)));
480 if((hConsole != NULL) && (hConsole != INVALID_HANDLE_VALUE))
482 SetConsoleTextAttribute(hConsole, attributes);
487 * Output logging message to console
489 static void lamexp_write_console(const int type, const char *msg)
491 __try
493 if(_isatty(_fileno(stderr)))
495 UINT oldOutputCP = GetConsoleOutputCP();
496 if(oldOutputCP != CP_UTF8) SetConsoleOutputCP(CP_UTF8);
498 switch(type)
500 case QtCriticalMsg:
501 case QtFatalMsg:
502 lamexp_console_color(stderr, FOREGROUND_RED | FOREGROUND_INTENSITY);
503 fprintf(stderr, GURU_MEDITATION);
504 fprintf(stderr, "%s\n", msg);
505 fflush(stderr);
506 break;
507 case QtWarningMsg:
508 lamexp_console_color(stderr, FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY);
509 fprintf(stderr, "%s\n", msg);
510 fflush(stderr);
511 break;
512 default:
513 lamexp_console_color(stderr, FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY);
514 fprintf(stderr, "%s\n", msg);
515 fflush(stderr);
516 break;
519 lamexp_console_color(stderr, FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED);
520 if(oldOutputCP != CP_UTF8) SetConsoleOutputCP(oldOutputCP);
523 __except(1)
525 /*ignore any exception that might occur here!*/
530 * Output logging message to debugger
532 static void lamexp_write_dbg_out(const int type, const char *msg)
534 const char *FORMAT = "[LameXP][%c] %s\n";
536 __try
538 char buffer[512];
539 const char* input = msg;
540 TRIM_LEFT(input);
542 switch(type)
544 case QtCriticalMsg:
545 case QtFatalMsg:
546 _snprintf_s(buffer, 512, _TRUNCATE, FORMAT, 'C', input);
547 break;
548 case QtWarningMsg:
549 _snprintf_s(buffer, 512, _TRUNCATE, FORMAT, 'W', input);
550 break;
551 default:
552 _snprintf_s(buffer, 512, _TRUNCATE, FORMAT, 'I', input);
553 break;
556 char *temp = &buffer[0];
557 CLEAN_OUTPUT_STRING(temp);
558 OutputDebugStringA(temp);
560 __except(1)
562 /*ignore any exception that might occur here!*/
567 * Output logging message to logfile
569 static void lamexp_write_logfile(const int type, const char *msg)
571 const char *FORMAT = "[%c][%04u] %s\r\n";
573 __try
575 if(g_lamexp_log_file)
577 char buffer[512];
578 strncpy_s(buffer, 512, msg, _TRUNCATE);
580 char *temp = &buffer[0];
581 TRIM_LEFT(temp);
582 CLEAN_OUTPUT_STRING(temp);
584 const unsigned int timestamp = static_cast<unsigned int>(_time64(NULL) % 3600I64);
586 switch(type)
588 case QtCriticalMsg:
589 case QtFatalMsg:
590 fprintf(g_lamexp_log_file, FORMAT, 'C', timestamp, temp);
591 break;
592 case QtWarningMsg:
593 fprintf(g_lamexp_log_file, FORMAT, 'W', timestamp, temp);
594 break;
595 default:
596 fprintf(g_lamexp_log_file, FORMAT, 'I', timestamp, temp);
597 break;
600 fflush(g_lamexp_log_file);
603 __except(1)
605 /*ignore any exception that might occur here!*/
610 * Qt message handler
612 void lamexp_message_handler(QtMsgType type, const char *msg)
614 if((!msg) || (!(msg[0])))
616 return;
619 CSLocker lock(g_lamexp_message_lock);
621 if(g_lamexp_log_file)
623 lamexp_write_logfile(type, msg);
626 if(g_lamexp_console_attached)
628 lamexp_write_console(type, msg);
630 else
632 lamexp_write_dbg_out(type, msg);
635 if((type == QtCriticalMsg) || (type == QtFatalMsg))
637 lock.forceUnlock();
638 lamexp_fatal_exit(msg);
643 * Invalid parameters handler
645 static void lamexp_invalid_param_handler(const wchar_t* exp, const wchar_t* fun, const wchar_t* fil, unsigned int, uintptr_t)
647 lamexp_fatal_exit("Invalid parameter handler invoked, application will exit!");
651 * Signal handler
653 static void lamexp_signal_handler(int signal_num)
655 signal(signal_num, lamexp_signal_handler);
656 lamexp_fatal_exit("Signal handler invoked, application will exit!");
660 * Global exception handler
662 static LONG WINAPI lamexp_exception_handler(struct _EXCEPTION_POINTERS *ExceptionInfo)
664 lamexp_fatal_exit("Unhandeled exception handler invoked, application will exit!");
665 return LONG_MAX;
669 * Initialize error handlers
671 void lamexp_init_error_handlers(void)
673 SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
674 SetUnhandledExceptionFilter(lamexp_exception_handler);
675 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
676 _set_invalid_parameter_handler(lamexp_invalid_param_handler);
678 static const int signal_num[6] = { SIGABRT, SIGFPE, SIGILL, SIGINT, SIGSEGV, SIGTERM };
680 for(size_t i = 0; i < 6; i++)
682 signal(signal_num[i], lamexp_signal_handler);
687 * Initialize the console
689 void lamexp_init_console(const QStringList &argv)
691 bool enableConsole = (LAMEXP_DEBUG) || ((VER_LAMEXP_CONSOLE_ENABLED) && lamexp_version_demo());
693 if(_environ)
695 wchar_t *logfile = NULL;
696 size_t logfile_len = 0;
697 if(!_wdupenv_s(&logfile, &logfile_len, L"LAMEXP_LOGFILE"))
699 if(logfile && (logfile_len > 0))
701 FILE *temp = NULL;
702 if(!_wfopen_s(&temp, logfile, L"wb"))
704 fprintf(temp, "%c%c%c", char(0xEF), char(0xBB), char(0xBF));
705 g_lamexp_log_file = temp;
707 free(logfile);
712 if(!LAMEXP_DEBUG)
714 for(int i = 0; i < argv.count(); i++)
716 if(!argv.at(i).compare("--console", Qt::CaseInsensitive))
718 enableConsole = true;
720 else if(!argv.at(i).compare("--no-console", Qt::CaseInsensitive))
722 enableConsole = false;
727 if(enableConsole)
729 if(!g_lamexp_console_attached)
731 if(AllocConsole() != FALSE)
733 SetConsoleCtrlHandler(NULL, TRUE);
734 SetConsoleTitle(L"LameXP - Audio Encoder Front-End | Debug Console");
735 SetConsoleOutputCP(CP_UTF8);
736 g_lamexp_console_attached = true;
740 if(g_lamexp_console_attached)
742 //-------------------------------------------------------------------
743 //See: http://support.microsoft.com/default.aspx?scid=kb;en-us;105305
744 //-------------------------------------------------------------------
745 const int flags = _O_WRONLY | _O_U8TEXT;
746 int hCrtStdOut = _open_osfhandle((intptr_t) GetStdHandle(STD_OUTPUT_HANDLE), flags);
747 int hCrtStdErr = _open_osfhandle((intptr_t) GetStdHandle(STD_ERROR_HANDLE), flags);
748 FILE *hfStdOut = (hCrtStdOut >= 0) ? _fdopen(hCrtStdOut, "wb") : NULL;
749 FILE *hfStdErr = (hCrtStdErr >= 0) ? _fdopen(hCrtStdErr, "wb") : NULL;
750 if(hfStdOut) { *stdout = *hfStdOut; std::cout.rdbuf(new std::filebuf(hfStdOut)); }
751 if(hfStdErr) { *stderr = *hfStdErr; std::cerr.rdbuf(new std::filebuf(hfStdErr)); }
754 HWND hwndConsole = GetConsoleWindow();
756 if((hwndConsole != NULL) && (hwndConsole != INVALID_HANDLE_VALUE))
758 HMENU hMenu = GetSystemMenu(hwndConsole, 0);
759 EnableMenuItem(hMenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);
760 RemoveMenu(hMenu, SC_CLOSE, MF_BYCOMMAND);
762 SetWindowPos(hwndConsole, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_FRAMECHANGED);
763 SetWindowLong(hwndConsole, GWL_STYLE, GetWindowLong(hwndConsole, GWL_STYLE) & (~WS_MAXIMIZEBOX) & (~WS_MINIMIZEBOX));
764 SetWindowPos(hwndConsole, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_FRAMECHANGED);
770 * Detect CPU features
772 lamexp_cpu_t lamexp_detect_cpu_features(const QStringList &argv)
774 typedef BOOL (WINAPI *IsWow64ProcessFun)(__in HANDLE hProcess, __out PBOOL Wow64Process);
776 lamexp_cpu_t features;
777 SYSTEM_INFO systemInfo;
778 int CPUInfo[4] = {-1};
779 char CPUIdentificationString[0x40];
780 char CPUBrandString[0x40];
782 memset(&features, 0, sizeof(lamexp_cpu_t));
783 memset(&systemInfo, 0, sizeof(SYSTEM_INFO));
784 memset(CPUIdentificationString, 0, sizeof(CPUIdentificationString));
785 memset(CPUBrandString, 0, sizeof(CPUBrandString));
787 __cpuid(CPUInfo, 0);
788 memcpy(CPUIdentificationString, &CPUInfo[1], sizeof(int));
789 memcpy(CPUIdentificationString + 4, &CPUInfo[3], sizeof(int));
790 memcpy(CPUIdentificationString + 8, &CPUInfo[2], sizeof(int));
791 features.intel = (_stricmp(CPUIdentificationString, "GenuineIntel") == 0);
792 strncpy_s(features.vendor, 0x40, CPUIdentificationString, _TRUNCATE);
794 if(CPUInfo[0] >= 1)
796 __cpuid(CPUInfo, 1);
797 features.mmx = (CPUInfo[3] & 0x800000) || false;
798 features.sse = (CPUInfo[3] & 0x2000000) || false;
799 features.sse2 = (CPUInfo[3] & 0x4000000) || false;
800 features.ssse3 = (CPUInfo[2] & 0x200) || false;
801 features.sse3 = (CPUInfo[2] & 0x1) || false;
802 features.ssse3 = (CPUInfo[2] & 0x200) || false;
803 features.stepping = CPUInfo[0] & 0xf;
804 features.model = ((CPUInfo[0] >> 4) & 0xf) + (((CPUInfo[0] >> 16) & 0xf) << 4);
805 features.family = ((CPUInfo[0] >> 8) & 0xf) + ((CPUInfo[0] >> 20) & 0xff);
808 __cpuid(CPUInfo, 0x80000000);
809 int nExIds = qMax<int>(qMin<int>(CPUInfo[0], 0x80000004), 0x80000000);
811 for(int i = 0x80000002; i <= nExIds; ++i)
813 __cpuid(CPUInfo, i);
814 switch(i)
816 case 0x80000002:
817 memcpy(CPUBrandString, CPUInfo, sizeof(CPUInfo));
818 break;
819 case 0x80000003:
820 memcpy(CPUBrandString + 16, CPUInfo, sizeof(CPUInfo));
821 break;
822 case 0x80000004:
823 memcpy(CPUBrandString + 32, CPUInfo, sizeof(CPUInfo));
824 break;
828 strncpy_s(features.brand, 0x40, CPUBrandString, _TRUNCATE);
830 if(strlen(features.brand) < 1) strncpy_s(features.brand, 0x40, "Unknown", _TRUNCATE);
831 if(strlen(features.vendor) < 1) strncpy_s(features.vendor, 0x40, "Unknown", _TRUNCATE);
833 #if (!(defined(_M_X64) || defined(_M_IA64)))
834 QLibrary Kernel32Lib("kernel32.dll");
835 if(IsWow64ProcessFun IsWow64ProcessPtr = (IsWow64ProcessFun) Kernel32Lib.resolve("IsWow64Process"))
837 BOOL x64flag = FALSE;
838 if(IsWow64ProcessPtr(GetCurrentProcess(), &x64flag))
840 features.x64 = (x64flag == TRUE);
843 #else
844 features.x64 = true;
845 #endif
847 DWORD_PTR procAffinity, sysAffinity;
848 if(GetProcessAffinityMask(GetCurrentProcess(), &procAffinity, &sysAffinity))
850 for(DWORD_PTR mask = 1; mask; mask <<= 1)
852 features.count += ((sysAffinity & mask) ? (1) : (0));
855 if(features.count < 1)
857 GetNativeSystemInfo(&systemInfo);
858 features.count = qBound(1UL, systemInfo.dwNumberOfProcessors, 64UL);
861 if(argv.count() > 0)
863 bool flag = false;
864 for(int i = 0; i < argv.count(); i++)
866 if(!argv[i].compare("--force-cpu-no-64bit", Qt::CaseInsensitive)) { flag = true; features.x64 = false; }
867 if(!argv[i].compare("--force-cpu-no-sse", Qt::CaseInsensitive)) { flag = true; features.sse = features.sse2 = features.sse3 = features.ssse3 = false; }
868 if(!argv[i].compare("--force-cpu-no-intel", Qt::CaseInsensitive)) { flag = true; features.intel = false; }
870 if(flag) qWarning("CPU flags overwritten by user-defined parameters. Take care!\n");
873 return features;
877 * Check for debugger (detect routine)
879 static __forceinline bool lamexp_check_for_debugger(void)
881 __try
883 CloseHandle((HANDLE)((DWORD_PTR)-3));
885 __except(1)
887 return true;
890 BOOL bHaveDebugger = FALSE;
891 if(CheckRemoteDebuggerPresent(GetCurrentProcess(), &bHaveDebugger))
893 if(bHaveDebugger) return true;
896 return IsDebuggerPresent();
900 * Check for debugger (thread proc)
902 static unsigned int __stdcall lamexp_debug_thread_proc(LPVOID lpParameter)
904 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_LOWEST);
905 forever
907 if(lamexp_check_for_debugger())
909 lamexp_fatal_exit("Not a debug build. Please unload debugger and try again!");
910 return 666;
912 lamexp_sleep(100);
917 * Check for debugger (startup routine)
919 static HANDLE lamexp_debug_thread_init()
921 if(lamexp_check_for_debugger())
923 lamexp_fatal_exit("Not a debug build. Please unload debugger and try again!");
925 const uintptr_t h = _beginthreadex(NULL, 0, lamexp_debug_thread_proc, NULL, 0, NULL);
926 return (HANDLE)(h^0xdeadbeef);
930 * Qt event filter
932 static bool lamexp_event_filter(void *message, long *result)
934 if((!(LAMEXP_DEBUG)) && lamexp_check_for_debugger())
936 lamexp_fatal_exit("Not a debug build. Please unload debugger and try again!");
939 switch(reinterpret_cast<MSG*>(message)->message)
941 case WM_QUERYENDSESSION:
942 qWarning("WM_QUERYENDSESSION message received!");
943 *result = lamexp_broadcast(lamexp_event_queryendsession, false) ? TRUE : FALSE;
944 return true;
945 case WM_ENDSESSION:
946 qWarning("WM_ENDSESSION message received!");
947 if(reinterpret_cast<MSG*>(message)->wParam == TRUE)
949 lamexp_broadcast(lamexp_event_endsession, false);
950 if(QApplication *app = reinterpret_cast<QApplication*>(QApplication::instance()))
952 app->closeAllWindows();
953 app->quit();
955 lamexp_finalization();
956 exit(1);
958 *result = 0;
959 return true;
960 default:
961 /*ignore this message and let Qt handle it*/
962 return false;
967 * Check for process elevation
969 static bool lamexp_process_is_elevated(bool *bIsUacEnabled = NULL)
971 bool bIsProcessElevated = false;
972 if(bIsUacEnabled) *bIsUacEnabled = false;
973 HANDLE hToken = NULL;
975 if(OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
977 TOKEN_ELEVATION_TYPE tokenElevationType;
978 DWORD returnLength;
979 if(GetTokenInformation(hToken, TokenElevationType, &tokenElevationType, sizeof(TOKEN_ELEVATION_TYPE), &returnLength))
981 if(returnLength == sizeof(TOKEN_ELEVATION_TYPE))
983 switch(tokenElevationType)
985 case TokenElevationTypeDefault:
986 qDebug("Process token elevation type: Default -> UAC is disabled.\n");
987 break;
988 case TokenElevationTypeFull:
989 qWarning("Process token elevation type: Full -> potential security risk!\n");
990 bIsProcessElevated = true;
991 if(bIsUacEnabled) *bIsUacEnabled = true;
992 break;
993 case TokenElevationTypeLimited:
994 qDebug("Process token elevation type: Limited -> not elevated.\n");
995 if(bIsUacEnabled) *bIsUacEnabled = true;
996 break;
997 default:
998 qWarning("Unknown tokenElevationType value: %d", tokenElevationType);
999 break;
1002 else
1004 qWarning("GetTokenInformation() return an unexpected size!");
1007 CloseHandle(hToken);
1009 else
1011 qWarning("Failed to open process token!");
1014 return bIsProcessElevated;
1018 * Convert QIcon to HICON -> caller is responsible for destroying the HICON!
1020 static HICON lamexp_qicon2hicon(const QIcon &icon, const int w, const int h)
1022 if(!icon.isNull())
1024 QPixmap pixmap = icon.pixmap(w, h);
1025 if(!pixmap.isNull())
1027 return pixmap.toWinHICON();
1030 return NULL;
1034 * Initialize Qt framework
1036 bool lamexp_init_qt(int argc, char* argv[])
1038 static bool qt_initialized = false;
1039 typedef BOOL (WINAPI *SetDllDirectoryProc)(WCHAR *lpPathName);
1040 const QStringList &arguments = lamexp_arguments();
1042 //Don't initialized again, if done already
1043 if(qt_initialized)
1045 return true;
1048 //Secure DLL loading
1049 QLibrary kernel32("kernel32.dll");
1050 if(kernel32.load())
1052 SetDllDirectoryProc pSetDllDirectory = (SetDllDirectoryProc) kernel32.resolve("SetDllDirectoryW");
1053 if(pSetDllDirectory != NULL) pSetDllDirectory(L"");
1056 //Extract executable name from argv[] array
1057 QString executableName = QLatin1String("LameXP.exe");
1058 if(arguments.count() > 0)
1060 static const char *delimiters = "\\/:?";
1061 executableName = arguments[0].trimmed();
1062 for(int i = 0; delimiters[i]; i++)
1064 int temp = executableName.lastIndexOf(QChar(delimiters[i]));
1065 if(temp >= 0) executableName = executableName.mid(temp + 1);
1067 executableName = executableName.trimmed();
1068 if(executableName.isEmpty())
1070 executableName = QLatin1String("LameXP.exe");
1074 //Check Qt version
1075 #ifdef QT_BUILD_KEY
1076 qDebug("Using Qt v%s [%s], %s, %s", qVersion(), QLibraryInfo::buildDate().toString(Qt::ISODate).toLatin1().constData(), (qSharedBuild() ? "DLL" : "Static"), QLibraryInfo::buildKey().toLatin1().constData());
1077 qDebug("Compiled with Qt v%s [%s], %s\n", QT_VERSION_STR, QT_PACKAGEDATE_STR, QT_BUILD_KEY);
1078 if(_stricmp(qVersion(), QT_VERSION_STR))
1080 qFatal("%s", QApplication::tr("Executable '%1' requires Qt v%2, but found Qt v%3.").arg(executableName, QString::fromLatin1(QT_VERSION_STR), QString::fromLatin1(qVersion())).toLatin1().constData());
1081 return false;
1083 if(QLibraryInfo::buildKey().compare(QString::fromLatin1(QT_BUILD_KEY), Qt::CaseInsensitive))
1085 qFatal("%s", QApplication::tr("Executable '%1' was built for Qt '%2', but found Qt '%3'.").arg(executableName, QString::fromLatin1(QT_BUILD_KEY), QLibraryInfo::buildKey()).toLatin1().constData());
1086 return false;
1088 #else
1089 qDebug("Using Qt v%s [%s], %s", qVersion(), QLibraryInfo::buildDate().toString(Qt::ISODate).toLatin1().constData(), (qSharedBuild() ? "DLL" : "Static"));
1090 qDebug("Compiled with Qt v%s [%s]\n", QT_VERSION_STR, QT_PACKAGEDATE_STR);
1091 #endif
1093 //Check the Windows version
1094 const lamexp_os_version_t &osVersionNo = lamexp_get_os_version();
1095 if(osVersionNo < lamexp_winver_winxp)
1097 qFatal("%s", QApplication::tr("Executable '%1' requires Windows XP or later.").arg(executableName).toLatin1().constData());
1100 //Supported Windows version?
1101 if(osVersionNo == lamexp_winver_winxp)
1103 qDebug("Running on Windows XP or Windows XP Media Center Edition.\n"); //lamexp_check_compatibility_mode("GetLargePageMinimum", executableName);
1105 else if(osVersionNo == lamexp_winver_xpx64)
1107 qDebug("Running on Windows Server 2003, Windows Server 2003 R2 or Windows XP x64.\n"); //lamexp_check_compatibility_mode("GetLocaleInfoEx", executableName);
1109 else if(osVersionNo == lamexp_winver_vista)
1111 qDebug("Running on Windows Vista or Windows Server 2008.\n"); //lamexp_check_compatibility_mode("CreateRemoteThreadEx", executableName*/);
1113 else if(osVersionNo == lamexp_winver_win70)
1115 qDebug("Running on Windows 7 or Windows Server 2008 R2.\n"); //lamexp_check_compatibility_mode("CreateFile2", executableName);
1117 else if(osVersionNo == lamexp_winver_win80)
1119 qDebug("Running on Windows 8 or Windows Server 2012.\n"); //lamexp_check_compatibility_mode("FindPackagesByPackageFamily", executableName);
1121 else if(osVersionNo == lamexp_winver_win81)
1123 qDebug("Running on Windows 8.1 or Windows Server 2012 R2.\n"); //lamexp_check_compatibility_mode(NULL, executableName);
1125 else
1127 const QString message = QString().sprintf("Running on an unknown WindowsNT-based system (v%u.%u).", osVersionNo.versionMajor, osVersionNo.versionMinor);
1128 qWarning("%s\n", QUTF8(message));
1129 MessageBoxW(NULL, QWCHAR(message), L"LameXP", MB_OK | MB_TOPMOST | MB_ICONWARNING);
1132 //Check for compat mode
1133 if(osVersionNo.overrideFlag && (osVersionNo <= lamexp_winver_win81))
1135 qWarning("Windows compatibility mode detected!");
1136 if(!arguments.contains("--ignore-compat-mode", Qt::CaseInsensitive))
1138 qFatal("%s", QApplication::tr("Executable '%1' doesn't support Windows compatibility mode.").arg(executableName).toLatin1().constData());
1139 return false;
1143 //Check for Wine
1144 if(lamexp_detect_wine())
1146 qWarning("It appears we are running under Wine, unexpected things might happen!\n");
1149 //Set text Codec for locale
1150 QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"));
1152 //Create Qt application instance
1153 QApplication *application = new QApplication(argc, argv);
1155 //Load plugins from application directory
1156 QCoreApplication::setLibraryPaths(QStringList() << QApplication::applicationDirPath());
1157 qDebug("Library Path:\n%s\n", QUTF8(QApplication::libraryPaths().first()));
1159 //Set application properties
1160 application->setApplicationName("LameXP - Audio Encoder Front-End");
1161 application->setApplicationVersion(QString().sprintf("%d.%02d.%04d", lamexp_version_major(), lamexp_version_minor(), lamexp_version_build()));
1162 application->setOrganizationName("LoRd_MuldeR");
1163 application->setOrganizationDomain("mulder.at.gg");
1164 application->setWindowIcon(lamexp_app_icon());
1165 application->setEventFilter(lamexp_event_filter);
1167 //Check for supported image formats
1168 QList<QByteArray> supportedFormats = QImageReader::supportedImageFormats();
1169 for(int i = 0; g_lamexp_imageformats[i]; i++)
1171 if(!supportedFormats.contains(g_lamexp_imageformats[i]))
1173 qFatal("Qt initialization error: QImageIOHandler for '%s' missing!", g_lamexp_imageformats[i]);
1174 return false;
1178 //Enable larger/smaller font size
1179 double fontScaleFactor = 1.0;
1180 if(arguments.contains("--huge-font", Qt::CaseInsensitive)) fontScaleFactor = 1.500;
1181 if(arguments.contains("--big-font", Qt::CaseInsensitive)) fontScaleFactor = 1.250;
1182 if(arguments.contains("--small-font", Qt::CaseInsensitive)) fontScaleFactor = 0.875;
1183 if(arguments.contains("--tiny-font", Qt::CaseInsensitive)) fontScaleFactor = 0.750;
1184 if(!qFuzzyCompare(fontScaleFactor, 1.0))
1186 qWarning("Application font scale factor set to: %.3f\n", fontScaleFactor);
1187 QFont appFont = application->font();
1188 appFont.setPointSizeF(appFont.pointSizeF() * fontScaleFactor);
1189 application->setFont(appFont);
1192 //Add the default translations
1193 lamexp_translation_init();
1195 //Check for process elevation
1196 if(lamexp_process_is_elevated() && (!lamexp_detect_wine()))
1198 QMessageBox messageBox(QMessageBox::Warning, "LameXP", "<nobr>LameXP was started with 'elevated' rights, altough LameXP does not need these rights.<br>Running an applications with unnecessary rights is a potential security risk!</nobr>", QMessageBox::NoButton, NULL, Qt::Dialog | Qt::MSWindowsFixedSizeDialogHint | Qt::WindowStaysOnTopHint);
1199 messageBox.addButton("Quit Program (Recommended)", QMessageBox::NoRole);
1200 messageBox.addButton("Ignore", QMessageBox::NoRole);
1201 if(messageBox.exec() == 0)
1203 return false;
1207 //Update console icon, if a console is attached
1208 #if QT_VERSION < QT_VERSION_CHECK(5,0,0)
1209 if(g_lamexp_console_attached && (!lamexp_detect_wine()))
1211 QLibrary kernel32("kernel32.dll");
1212 if(kernel32.load())
1214 typedef DWORD (__stdcall *SetConsoleIconFun)(HICON);
1215 if(SetConsoleIconFun SetConsoleIconPtr = (SetConsoleIconFun) kernel32.resolve("SetConsoleIcon"))
1217 if(HICON hIcon = lamexp_qicon2hicon(QIcon(":/icons/sound.png"), 16, 16))
1219 SetConsoleIconPtr(hIcon);
1220 DestroyIcon(hIcon);
1225 #endif
1227 //Done
1228 qt_initialized = true;
1229 return true;
1232 const QStringList &lamexp_arguments(void)
1234 QReadLocker readLock(&g_lamexp_argv.lock);
1236 if(!g_lamexp_argv.list)
1238 readLock.unlock();
1239 QWriteLocker writeLock(&g_lamexp_argv.lock);
1241 g_lamexp_argv.list = new QStringList;
1243 int nArgs = 0;
1244 LPWSTR *szArglist = CommandLineToArgvW(GetCommandLineW(), &nArgs);
1246 if(NULL != szArglist)
1248 for(int i = 0; i < nArgs; i++)
1250 (*g_lamexp_argv.list) << WCHAR2QSTR(szArglist[i]);
1252 LocalFree(szArglist);
1254 else
1256 qWarning("CommandLineToArgvW() has failed !!!");
1260 return (*g_lamexp_argv.list);
1264 * Locate known folder on local system
1266 const QString &lamexp_known_folder(lamexp_known_folder_t folder_id)
1268 static const int CSIDL_FLAG_CREATE = 0x8000;
1269 typedef enum { KF_FLAG_CREATE = 0x00008000 } kf_flags_t;
1271 struct
1273 const int csidl;
1274 const GUID guid;
1276 static s_folders[] =
1278 { 0x001c, {0xF1B32785,0x6FBA,0x4FCF,{0x9D,0x55,0x7B,0x8E,0x7F,0x15,0x70,0x91}} }, //CSIDL_LOCAL_APPDATA
1279 { 0x0026, {0x905e63b6,0xc1bf,0x494e,{0xb2,0x9c,0x65,0xb7,0x32,0xd3,0xd2,0x1a}} }, //CSIDL_PROGRAM_FILES
1280 { 0x0024, {0xF38BF404,0x1D43,0x42F2,{0x93,0x05,0x67,0xDE,0x0B,0x28,0xFC,0x23}} }, //CSIDL_WINDOWS_FOLDER
1281 { 0x0025, {0x1AC14E77,0x02E7,0x4E5D,{0xB7,0x44,0x2E,0xB1,0xAE,0x51,0x98,0xB7}} }, //CSIDL_SYSTEM_FOLDER
1284 size_t folderId = size_t(-1);
1286 switch(folder_id)
1288 case lamexp_folder_localappdata: folderId = 0; break;
1289 case lamexp_folder_programfiles: folderId = 1; break;
1290 case lamexp_folder_systroot_dir: folderId = 2; break;
1291 case lamexp_folder_systemfolder: folderId = 3; break;
1294 if(folderId == size_t(-1))
1296 qWarning("Invalid 'known' folder was requested!");
1297 return *reinterpret_cast<QString*>(NULL);
1300 QReadLocker readLock(&g_lamexp_known_folder.lock);
1302 //Already in cache?
1303 if(g_lamexp_known_folder.knownFolders)
1305 if(g_lamexp_known_folder.knownFolders->contains(folderId))
1307 return (*g_lamexp_known_folder.knownFolders)[folderId];
1311 //Obtain write lock to initialize
1312 readLock.unlock();
1313 QWriteLocker writeLock(&g_lamexp_known_folder.lock);
1315 //Still not in cache?
1316 if(g_lamexp_known_folder.knownFolders)
1318 if(g_lamexp_known_folder.knownFolders->contains(folderId))
1320 return (*g_lamexp_known_folder.knownFolders)[folderId];
1324 //Initialize on first call
1325 if(!g_lamexp_known_folder.knownFolders)
1327 QLibrary shell32("shell32.dll");
1328 if(shell32.load())
1330 g_lamexp_known_folder.getFolderPath = (SHGetFolderPath_t) shell32.resolve("SHGetFolderPathW");
1331 g_lamexp_known_folder.getKnownFolderPath = (SHGetKnownFolderPath_t) shell32.resolve("SHGetKnownFolderPath");
1333 g_lamexp_known_folder.knownFolders = new QMap<size_t, QString>();
1336 QString folderPath;
1338 //Now try to get the folder path!
1339 if(g_lamexp_known_folder.getKnownFolderPath)
1341 WCHAR *path = NULL;
1342 if(g_lamexp_known_folder.getKnownFolderPath(s_folders[folderId].guid, KF_FLAG_CREATE, NULL, &path) == S_OK)
1344 //MessageBoxW(0, path, L"SHGetKnownFolderPath", MB_TOPMOST);
1345 QDir folderTemp = QDir(QDir::fromNativeSeparators(QString::fromUtf16(reinterpret_cast<const unsigned short*>(path))));
1346 if(folderTemp.exists())
1348 folderPath = folderTemp.canonicalPath();
1350 CoTaskMemFree(path);
1353 else if(g_lamexp_known_folder.getFolderPath)
1355 WCHAR *path = new WCHAR[4096];
1356 if(g_lamexp_known_folder.getFolderPath(NULL, s_folders[folderId].csidl | CSIDL_FLAG_CREATE, NULL, NULL, path) == S_OK)
1358 //MessageBoxW(0, path, L"SHGetFolderPathW", MB_TOPMOST);
1359 QDir folderTemp = QDir(QDir::fromNativeSeparators(QString::fromUtf16(reinterpret_cast<const unsigned short*>(path))));
1360 if(folderTemp.exists())
1362 folderPath = folderTemp.canonicalPath();
1365 LAMEXP_DELETE_ARRAY(path);
1368 //Update cache
1369 g_lamexp_known_folder.knownFolders->insert(folderId, folderPath);
1370 return (*g_lamexp_known_folder.knownFolders)[folderId];
1374 * Safely remove a file
1376 bool lamexp_remove_file(const QString &filename)
1378 if(!QFileInfo(filename).exists() || !QFileInfo(filename).isFile())
1380 return true;
1382 else
1384 if(!QFile::remove(filename))
1386 static const DWORD attrMask = FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM;
1387 const DWORD attributes = GetFileAttributesW(QWCHAR(filename));
1388 if(attributes & attrMask)
1390 SetFileAttributesW(QWCHAR(filename), FILE_ATTRIBUTE_NORMAL);
1392 if(!QFile::remove(filename))
1394 qWarning("Could not delete \"%s\"", filename.toLatin1().constData());
1395 return false;
1397 else
1399 return true;
1402 else
1404 return true;
1410 * Check if visual themes are enabled (WinXP and later)
1412 bool lamexp_themes_enabled(void)
1414 typedef int (WINAPI *IsAppThemedFun)(void);
1416 QReadLocker readLock(&g_lamexp_themes_enabled.lock);
1417 if(g_lamexp_themes_enabled.bInitialized)
1419 return g_lamexp_themes_enabled.bThemesEnabled;
1422 readLock.unlock();
1423 QWriteLocker writeLock(&g_lamexp_themes_enabled.lock);
1425 if(!g_lamexp_themes_enabled.bInitialized)
1427 g_lamexp_themes_enabled.bThemesEnabled = false;
1428 const lamexp_os_version_t &osVersion = lamexp_get_os_version();
1429 if(osVersion >= lamexp_winver_winxp)
1431 IsAppThemedFun IsAppThemedPtr = NULL;
1432 QLibrary uxTheme(QString("%1/UxTheme.dll").arg(lamexp_known_folder(lamexp_folder_systemfolder)));
1433 if(uxTheme.load())
1435 IsAppThemedPtr = (IsAppThemedFun) uxTheme.resolve("IsAppThemed");
1437 if(IsAppThemedPtr)
1439 g_lamexp_themes_enabled.bThemesEnabled = IsAppThemedPtr();
1440 if(!g_lamexp_themes_enabled.bThemesEnabled)
1442 qWarning("Theme support is disabled for this process!");
1446 g_lamexp_themes_enabled.bInitialized = true;
1449 return g_lamexp_themes_enabled.bThemesEnabled;
1453 * Get number of free bytes on disk
1455 unsigned __int64 lamexp_free_diskspace(const QString &path, bool *ok)
1457 ULARGE_INTEGER freeBytesAvailable, totalNumberOfBytes, totalNumberOfFreeBytes;
1458 if(GetDiskFreeSpaceExW(reinterpret_cast<const wchar_t*>(QDir::toNativeSeparators(path).utf16()), &freeBytesAvailable, &totalNumberOfBytes, &totalNumberOfFreeBytes))
1460 if(ok) *ok = true;
1461 return freeBytesAvailable.QuadPart;
1463 else
1465 if(ok) *ok = false;
1466 return 0;
1471 * Check if computer does support hibernation
1473 bool lamexp_is_hibernation_supported(void)
1475 bool hibernationSupported = false;
1477 SYSTEM_POWER_CAPABILITIES pwrCaps;
1478 SecureZeroMemory(&pwrCaps, sizeof(SYSTEM_POWER_CAPABILITIES));
1480 if(GetPwrCapabilities(&pwrCaps))
1482 hibernationSupported = pwrCaps.SystemS4 && pwrCaps.HiberFilePresent;
1485 return hibernationSupported;
1489 * Shutdown the computer
1491 bool lamexp_shutdown_computer(const QString &message, const unsigned long timeout, const bool forceShutdown, const bool hibernate)
1493 HANDLE hToken = NULL;
1495 if(OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
1497 TOKEN_PRIVILEGES privileges;
1498 memset(&privileges, 0, sizeof(TOKEN_PRIVILEGES));
1499 privileges.PrivilegeCount = 1;
1500 privileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
1502 if(LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &privileges.Privileges[0].Luid))
1504 if(AdjustTokenPrivileges(hToken, FALSE, &privileges, NULL, NULL, NULL))
1506 if(hibernate)
1508 if(SetSuspendState(TRUE, TRUE, TRUE))
1510 return true;
1513 const DWORD reason = SHTDN_REASON_MAJOR_APPLICATION | SHTDN_REASON_FLAG_PLANNED;
1514 return InitiateSystemShutdownEx(NULL, const_cast<wchar_t*>(QWCHAR(message)), timeout, forceShutdown ? TRUE : FALSE, FALSE, reason);
1519 return false;
1523 * Determines the current date, resistant against certain manipulations
1525 QDate lamexp_current_date_safe(void)
1527 const DWORD MAX_PROC = 1024;
1528 DWORD *processes = new DWORD[MAX_PROC];
1529 DWORD bytesReturned = 0;
1531 if(!EnumProcesses(processes, sizeof(DWORD) * MAX_PROC, &bytesReturned))
1533 LAMEXP_DELETE_ARRAY(processes);
1534 return QDate::currentDate();
1537 const DWORD procCount = bytesReturned / sizeof(DWORD);
1538 ULARGE_INTEGER lastStartTime;
1539 memset(&lastStartTime, 0, sizeof(ULARGE_INTEGER));
1541 for(DWORD i = 0; i < procCount; i++)
1543 HANDLE hProc = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, processes[i]);
1544 if(hProc)
1546 FILETIME processTime[4];
1547 if(GetProcessTimes(hProc, &processTime[0], &processTime[1], &processTime[2], &processTime[3]))
1549 ULARGE_INTEGER timeCreation;
1550 timeCreation.LowPart = processTime[0].dwLowDateTime;
1551 timeCreation.HighPart = processTime[0].dwHighDateTime;
1552 if(timeCreation.QuadPart > lastStartTime.QuadPart)
1554 lastStartTime.QuadPart = timeCreation.QuadPart;
1557 CloseHandle(hProc);
1561 LAMEXP_DELETE_ARRAY(processes);
1563 FILETIME lastStartTime_fileTime;
1564 lastStartTime_fileTime.dwHighDateTime = lastStartTime.HighPart;
1565 lastStartTime_fileTime.dwLowDateTime = lastStartTime.LowPart;
1567 FILETIME lastStartTime_localTime;
1568 if(!FileTimeToLocalFileTime(&lastStartTime_fileTime, &lastStartTime_localTime))
1570 memcpy(&lastStartTime_localTime, &lastStartTime_fileTime, sizeof(FILETIME));
1573 SYSTEMTIME lastStartTime_system;
1574 if(!FileTimeToSystemTime(&lastStartTime_localTime, &lastStartTime_system))
1576 memset(&lastStartTime_system, 0, sizeof(SYSTEMTIME));
1577 lastStartTime_system.wYear = 1970; lastStartTime_system.wMonth = lastStartTime_system.wDay = 1;
1580 const QDate currentDate = QDate::currentDate();
1581 const QDate processDate = QDate(lastStartTime_system.wYear, lastStartTime_system.wMonth, lastStartTime_system.wDay);
1582 return (currentDate >= processDate) ? currentDate : processDate;
1586 * Show system message box
1588 int lamexp_system_message(const wchar_t *text, int beepType)
1590 UINT flags = MB_OK | MB_TOPMOST;
1592 switch(beepType)
1594 case lamexp_beep_info: flags = flags | MB_ICONASTERISK;
1595 case lamexp_beep_warning: flags = flags | MB_ICONEXCLAMATION;
1596 case lamexp_beep_error: flags = flags | MB_ICONHAND;
1599 return MessageBoxW(NULL, text, L"LameXP", flags);
1603 * Block window "move" message
1605 bool lamexp_block_window_move(void *message)
1607 if(message)
1609 MSG *msg = reinterpret_cast<MSG*>(message);
1610 if((msg->message == WM_SYSCOMMAND) && (msg->wParam == SC_MOVE))
1612 return true;
1614 if((msg->message == WM_NCLBUTTONDOWN) && (msg->wParam == HTCAPTION))
1616 return true;
1619 return false;
1623 * Suspend calling thread for N milliseconds
1625 inline void lamexp_sleep(const unsigned int delay)
1627 Sleep(delay);
1630 bool lamexp_beep(int beepType)
1632 switch(beepType)
1634 case lamexp_beep_info: return MessageBeep(MB_ICONASTERISK) == TRUE; break;
1635 case lamexp_beep_warning: return MessageBeep(MB_ICONEXCLAMATION) == TRUE; break;
1636 case lamexp_beep_error: return MessageBeep(MB_ICONHAND) == TRUE; break;
1637 default: return false;
1642 * Play a sound (from resources)
1644 bool lamexp_play_sound(const QString &name, const bool bAsync)
1646 const unsigned char *data = NULL;
1648 //Try to look-up the sound in the cache first
1649 if(!name.isEmpty())
1651 QReadLocker readLock(&g_lamexp_sounds.lock);
1652 if(g_lamexp_sounds.sound_db && g_lamexp_sounds.sound_db->contains(name))
1654 data = g_lamexp_sounds.sound_db->value(name);
1658 //If data not found in cache, try to load from resource!
1659 if((!data) && (!name.isEmpty()))
1661 QResource resource(QString(":/sounds/%1.wav").arg(name));
1662 if(resource.isValid() && (data = resource.data()))
1664 QWriteLocker writeLock(&g_lamexp_sounds.lock);
1665 if(!g_lamexp_sounds.sound_db)
1667 g_lamexp_sounds.sound_db = new QHash<const QString, const unsigned char*>();
1669 g_lamexp_sounds.sound_db->insert(name, data);
1671 else
1673 qWarning("Sound effect \"%s\" not found!", QUTF8(name));
1677 //Play the sound, if availbale
1678 if(data)
1680 return PlaySound(LPCWSTR(data), NULL, (SND_MEMORY | (bAsync ? SND_ASYNC : SND_SYNC))) != FALSE;
1683 return false;
1687 * Play a sound (system alias)
1689 bool lamexp_play_sound_alias(const QString &alias, const bool bAsync)
1691 return PlaySound(QWCHAR(alias), GetModuleHandle(NULL), (SND_ALIAS | (bAsync ? SND_ASYNC : SND_SYNC))) != FALSE;
1695 * Play a sound (from external DLL)
1697 bool lamexp_play_sound_file(const QString &library, const unsigned short uiSoundIdx, const bool bAsync)
1699 bool result = false;
1701 QFileInfo libraryFile(library);
1702 if(!libraryFile.isAbsolute())
1704 const QString &systemDir = lamexp_known_folder(lamexp_folder_systemfolder);
1705 if(!systemDir.isEmpty())
1707 libraryFile.setFile(QDir(systemDir), libraryFile.fileName());
1711 if(libraryFile.exists() && libraryFile.isFile())
1713 if(HMODULE module = LoadLibraryW(QWCHAR(QDir::toNativeSeparators(libraryFile.canonicalFilePath()))))
1715 result = (PlaySound(MAKEINTRESOURCE(uiSoundIdx), module, (SND_RESOURCE | (bAsync ? SND_ASYNC : SND_SYNC))) != FALSE);
1716 FreeLibrary(module);
1719 else
1721 qWarning("PlaySound: File \"%s\" could not be found!", QUTF8(libraryFile.absoluteFilePath()));
1724 return result;
1728 * Open file using the shell
1730 bool lamexp_exec_shell(const QWidget *win, const QString &url, const bool explore)
1732 return lamexp_exec_shell(win, url, QString(), QString(), explore);
1736 * Open file using the shell (with parameters)
1738 bool lamexp_exec_shell(const QWidget *win, const QString &url, const QString &parameters, const QString &directory, const bool explore)
1740 return ((int) ShellExecuteW(((win) ? win->winId() : NULL), (explore ? L"explore" : L"open"), QWCHAR(url), ((!parameters.isEmpty()) ? QWCHAR(parameters) : NULL), ((!directory.isEmpty()) ? QWCHAR(directory) : NULL), SW_SHOW)) > 32;
1744 * Query value of the performance counter
1746 __int64 lamexp_perfcounter_value(void)
1748 LARGE_INTEGER counter;
1749 if(QueryPerformanceCounter(&counter) == TRUE)
1751 return counter.QuadPart;
1753 return -1;
1757 * Query frequency of the performance counter
1759 __int64 lamexp_perfcounter_frequ(void)
1761 LARGE_INTEGER frequency;
1762 if(QueryPerformanceFrequency(&frequency) == TRUE)
1764 return frequency.QuadPart;
1766 return -1;
1770 * Insert entry to the window's system menu
1772 bool lamexp_append_sysmenu(const QWidget *win, const unsigned int identifier, const QString &text)
1774 bool ok = false;
1776 if(HMENU hMenu = GetSystemMenu(win->winId(), FALSE))
1778 ok = (AppendMenuW(hMenu, MF_SEPARATOR, 0, 0) == TRUE);
1779 ok = (AppendMenuW(hMenu, MF_STRING, identifier, QWCHAR(text)) == TRUE);
1782 return ok;
1786 * Insert entry to the window's system menu
1788 bool lamexp_check_sysmenu_msg(void *message, const unsigned int identifier)
1790 return (((MSG*)message)->message == WM_SYSCOMMAND) && ((((MSG*)message)->wParam & 0xFFF0) == identifier);
1794 * Update system menu entry
1796 bool lamexp_update_sysmenu(const QWidget *win, const unsigned int identifier, const QString &text)
1798 bool ok = false;
1800 if(HMENU hMenu = ::GetSystemMenu(win->winId(), FALSE))
1802 ok = (ModifyMenu(hMenu, identifier, MF_STRING | MF_BYCOMMAND, identifier, QWCHAR(text)) == TRUE);
1804 return ok;
1808 * Display the window's close button
1810 bool lamexp_enable_close_button(const QWidget *win, const bool bEnable)
1812 bool ok = false;
1814 if(HMENU hMenu = GetSystemMenu(win->winId(), FALSE))
1816 ok = (EnableMenuItem(hMenu, SC_CLOSE, MF_BYCOMMAND | (bEnable ? MF_ENABLED : MF_GRAYED)) == TRUE);
1819 return ok;
1823 * Check whether ESC key has been pressed since the previous call to this function
1825 bool lamexp_check_escape_state(void)
1827 return (GetAsyncKeyState(VK_ESCAPE) & 0x0001) != 0;
1831 * Set the process priority class for current process
1833 bool lamexp_change_process_priority(const int priority)
1835 return lamexp_change_process_priority(GetCurrentProcess(), priority);
1839 * Set the process priority class for specified process
1841 bool lamexp_change_process_priority(const QProcess *proc, const int priority)
1843 if(Q_PID qPid = proc->pid())
1845 return lamexp_change_process_priority(qPid->hProcess, priority);
1847 else
1849 return false;
1854 * Set the process priority class for specified process
1856 bool lamexp_change_process_priority(void *hProcess, const int priority)
1858 bool ok = false;
1860 switch(qBound(-2, priority, 2))
1862 case 2:
1863 ok = (SetPriorityClass(hProcess, HIGH_PRIORITY_CLASS) == TRUE);
1864 break;
1865 case 1:
1866 if(!(ok = (SetPriorityClass(hProcess, ABOVE_NORMAL_PRIORITY_CLASS) == TRUE)))
1868 ok = (SetPriorityClass(hProcess, HIGH_PRIORITY_CLASS) == TRUE);
1870 break;
1871 case 0:
1872 ok = (SetPriorityClass(hProcess, NORMAL_PRIORITY_CLASS) == TRUE);
1873 break;
1874 case -1:
1875 if(!(ok = (SetPriorityClass(hProcess, BELOW_NORMAL_PRIORITY_CLASS) == TRUE)))
1877 ok = (SetPriorityClass(hProcess, IDLE_PRIORITY_CLASS) == TRUE);
1879 break;
1880 case -2:
1881 ok = (SetPriorityClass(hProcess, IDLE_PRIORITY_CLASS) == TRUE);
1882 break;
1885 return ok;
1889 * Returns the current file time
1891 unsigned __int64 lamexp_current_file_time(void)
1893 FILETIME fileTime;
1894 GetSystemTimeAsFileTime(&fileTime);
1896 ULARGE_INTEGER temp;
1897 temp.HighPart = fileTime.dwHighDateTime;
1898 temp.LowPart = fileTime.dwLowDateTime;
1900 return temp.QuadPart;
1904 * Bring the specifed window to the front
1906 bool lamexp_bring_to_front(const QWidget *window)
1908 bool ret = false;
1910 if(window)
1912 for(int i = 0; (i < 5) && (!ret); i++)
1914 ret = (SetForegroundWindow(window->winId()) != FALSE);
1915 SwitchToThisWindow(window->winId(), TRUE);
1917 LockSetForegroundWindow(LSFW_LOCK);
1920 return ret;
1924 * Bring window of the specifed process to the front (callback)
1926 static BOOL CALLBACK lamexp_bring_process_to_front_helper(HWND hwnd, LPARAM lParam)
1928 DWORD processId = *reinterpret_cast<WORD*>(lParam);
1929 DWORD windowProcessId = NULL;
1930 GetWindowThreadProcessId(hwnd, &windowProcessId);
1931 if(windowProcessId == processId)
1933 SwitchToThisWindow(hwnd, TRUE);
1934 SetForegroundWindow(hwnd);
1935 return FALSE;
1938 return TRUE;
1942 * Bring window of the specifed process to the front
1944 bool lamexp_bring_process_to_front(const unsigned long pid)
1946 return EnumWindows(lamexp_bring_process_to_front_helper, reinterpret_cast<LPARAM>(&pid)) == TRUE;
1950 * Check the network connectivity status
1952 int lamexp_network_status(void)
1954 DWORD dwFlags;
1955 const BOOL ret = IsNetworkAlive(&dwFlags);
1956 if(GetLastError() == 0)
1958 return (ret != FALSE) ? lamexp_network_yes : lamexp_network_non;
1960 return lamexp_network_err;
1964 * Retrun the process ID of the given QProcess
1966 unsigned long lamexp_process_id(const QProcess *proc)
1968 PROCESS_INFORMATION *procInf = proc->pid();
1969 return (procInf) ? procInf->dwProcessId : NULL;
1973 * Convert long path to short path
1975 QString lamexp_path_to_short(const QString &longPath)
1977 QString shortPath;
1978 DWORD buffSize = GetShortPathNameW(reinterpret_cast<const wchar_t*>(longPath.utf16()), NULL, NULL);
1980 if(buffSize > 0)
1982 wchar_t *buffer = new wchar_t[buffSize];
1983 DWORD result = GetShortPathNameW(reinterpret_cast<const wchar_t*>(longPath.utf16()), buffer, buffSize);
1985 if(result > 0 && result < buffSize)
1987 shortPath = QString::fromUtf16(reinterpret_cast<const unsigned short*>(buffer));
1990 delete[] buffer;
1993 return (shortPath.isEmpty() ? longPath : shortPath);
1997 * Open media file in external player
1999 bool lamexp_open_media_file(const QString &mediaFilePath)
2001 const static wchar_t *registryPrefix[2] = { L"SOFTWARE\\", L"SOFTWARE\\Wow6432Node\\" };
2002 const static wchar_t *registryKeys[3] =
2004 L"Microsoft\\Windows\\CurrentVersion\\Uninstall\\{97D341C8-B0D1-4E4A-A49A-C30B52F168E9}",
2005 L"Microsoft\\Windows\\CurrentVersion\\Uninstall\\{DB9E4EAB-2717-499F-8D56-4CC8A644AB60}",
2006 L"foobar2000"
2008 const static wchar_t *appNames[4] = { L"smplayer_portable.exe", L"smplayer.exe", L"MPUI.exe", L"foobar2000.exe" };
2009 const static wchar_t *valueNames[2] = { L"InstallLocation", L"InstallDir" };
2011 for(size_t i = 0; i < 3; i++)
2013 for(size_t j = 0; j < 2; j++)
2015 QString mplayerPath;
2016 HKEY registryKeyHandle = NULL;
2018 const QString currentKey = WCHAR2QSTR(registryPrefix[j]).append(WCHAR2QSTR(registryKeys[i]));
2019 if(RegOpenKeyExW(HKEY_LOCAL_MACHINE, QWCHAR(currentKey), 0, KEY_READ, &registryKeyHandle) == ERROR_SUCCESS)
2021 for(size_t k = 0; k < 2; k++)
2023 wchar_t Buffer[4096];
2024 DWORD BuffSize = sizeof(wchar_t*) * 4096;
2025 DWORD DataType = REG_NONE;
2026 if(RegQueryValueExW(registryKeyHandle, valueNames[k], 0, &DataType, reinterpret_cast<BYTE*>(Buffer), &BuffSize) == ERROR_SUCCESS)
2028 if((DataType == REG_SZ) || (DataType == REG_EXPAND_SZ) || (DataType == REG_LINK))
2030 mplayerPath = WCHAR2QSTR(Buffer);
2031 break;
2035 RegCloseKey(registryKeyHandle);
2038 if(!mplayerPath.isEmpty())
2040 QDir mplayerDir(mplayerPath);
2041 if(mplayerDir.exists())
2043 for(size_t k = 0; k < 4; k++)
2045 if(mplayerDir.exists(WCHAR2QSTR(appNames[k])))
2047 qDebug("Player found at:\n%s\n", QUTF8(mplayerDir.absoluteFilePath(WCHAR2QSTR(appNames[k]))));
2048 QProcess::startDetached(mplayerDir.absoluteFilePath(WCHAR2QSTR(appNames[k])), QStringList() << QDir::toNativeSeparators(mediaFilePath));
2049 return true;
2056 return false;
2059 static void lamexp_init_dwmapi(void)
2061 QReadLocker writeLock(&g_lamexp_dwmapi.lock);
2063 //Not initialized yet?
2064 if(g_lamexp_dwmapi.bInitialized)
2066 return;
2069 //Reset function pointers
2070 g_lamexp_dwmapi.dwmIsCompositionEnabled = NULL;
2071 g_lamexp_dwmapi.dwmExtendFrameIntoClientArea = NULL;
2072 g_lamexp_dwmapi.dwmEnableBlurBehindWindow = NULL;
2074 //Does OS support DWM?
2075 if(lamexp_get_os_version() >= lamexp_winver_vista)
2077 //Load DWMAPI.DLL
2078 g_lamexp_dwmapi.dwmapi_dll = new QLibrary("dwmapi.dll");
2079 if(g_lamexp_dwmapi.dwmapi_dll->load())
2081 //Initialize function pointers
2082 g_lamexp_dwmapi.dwmIsCompositionEnabled = (HRESULT (__stdcall*)(BOOL*)) g_lamexp_dwmapi.dwmapi_dll->resolve("DwmIsCompositionEnabled");
2083 g_lamexp_dwmapi.dwmExtendFrameIntoClientArea = (HRESULT (__stdcall*)(HWND, const MARGINS*)) g_lamexp_dwmapi.dwmapi_dll->resolve("DwmExtendFrameIntoClientArea");
2084 g_lamexp_dwmapi.dwmEnableBlurBehindWindow = (HRESULT (__stdcall*)(HWND, const DWM_BLURBEHIND*)) g_lamexp_dwmapi.dwmapi_dll->resolve("DwmEnableBlurBehindWindow");
2086 else
2088 LAMEXP_DELETE(g_lamexp_dwmapi.dwmapi_dll);
2089 qWarning("Failed to load DWMAPI.DLL on a DWM-enabled system!");
2093 g_lamexp_dwmapi.bInitialized = true;
2097 * Enable "sheet of glass" effect on the given Window
2099 bool lamexp_sheet_of_glass(QWidget *window)
2101 QReadLocker readLock(&g_lamexp_dwmapi.lock);
2103 //Initialize the DWM API
2104 while(!g_lamexp_dwmapi.bInitialized)
2106 readLock.unlock();
2107 lamexp_init_dwmapi();
2108 readLock.relock();
2111 BOOL bCompositionEnabled = FALSE;
2113 //Required functions available?
2114 if((g_lamexp_dwmapi.dwmIsCompositionEnabled != NULL) && (g_lamexp_dwmapi.dwmExtendFrameIntoClientArea != NULL) && (g_lamexp_dwmapi.dwmEnableBlurBehindWindow != NULL))
2116 //Check if composition is currently enabled
2117 if(HRESULT hr = g_lamexp_dwmapi.dwmIsCompositionEnabled(&bCompositionEnabled))
2119 qWarning("DwmIsCompositionEnabled function has failed! (error %d)", hr);
2120 return false;
2124 //All functions available *and* composition enabled?
2125 if(!bCompositionEnabled)
2127 return false;
2130 //Enable the "sheet of glass" effect on this window
2131 MARGINS margins = {-1, -1, -1, -1};
2132 if(HRESULT hr = g_lamexp_dwmapi.dwmExtendFrameIntoClientArea(window->winId(), &margins))
2134 qWarning("DwmExtendFrameIntoClientArea function has failed! (error %d)", hr);
2135 return false;
2138 //Create and populate the Blur Behind structure
2139 DWM_BLURBEHIND bb;
2140 memset(&bb, 0, sizeof(DWM_BLURBEHIND));
2141 bb.fEnable = TRUE;
2142 bb.dwFlags = DWM_BB_ENABLE;
2143 if(HRESULT hr = g_lamexp_dwmapi.dwmEnableBlurBehindWindow(window->winId(), &bb))
2145 qWarning("DwmEnableBlurBehindWindow function has failed! (error %d)", hr);
2146 return false;
2149 //Required for Qt
2150 window->setAutoFillBackground(false);
2151 window->setAttribute(Qt::WA_TranslucentBackground);
2152 window->setAttribute(Qt::WA_NoSystemBackground);
2154 return true;
2158 * Update "sheet of glass" effect on the given Window
2160 bool lamexp_sheet_of_glass_update(QWidget *window)
2162 QReadLocker readLock(&g_lamexp_dwmapi.lock);
2164 //Initialize the DWM API
2165 while(!g_lamexp_dwmapi.bInitialized)
2167 readLock.unlock();
2168 lamexp_init_dwmapi();
2169 readLock.relock();
2172 BOOL bCompositionEnabled = FALSE;
2174 //Required functions available?
2175 if((g_lamexp_dwmapi.dwmIsCompositionEnabled != NULL) && (g_lamexp_dwmapi.dwmEnableBlurBehindWindow != NULL))
2177 //Check if composition is currently enabled
2178 if(HRESULT hr = g_lamexp_dwmapi.dwmIsCompositionEnabled(&bCompositionEnabled))
2180 qWarning("DwmIsCompositionEnabled function has failed! (error %d)", hr);
2181 return false;
2185 //All functions available *and* composition enabled?
2186 if(!bCompositionEnabled)
2188 return false;
2191 //Create and populate the Blur Behind structure
2192 DWM_BLURBEHIND bb;
2193 memset(&bb, 0, sizeof(DWM_BLURBEHIND));
2194 bb.fEnable = TRUE;
2195 bb.dwFlags = DWM_BB_ENABLE;
2196 if(HRESULT hr = g_lamexp_dwmapi.dwmEnableBlurBehindWindow(window->winId(), &bb))
2198 qWarning("DwmEnableBlurBehindWindow function has failed! (error %d)", hr);
2199 return false;
2202 return true;
2206 * Update the window icon
2208 lamexp_icon_t *lamexp_set_window_icon(QWidget *window, const QIcon &icon, const bool bIsBigIcon)
2210 if(!icon.isNull())
2212 const int extend = (bIsBigIcon ? 32 : 16);
2213 if(HICON hIcon = lamexp_qicon2hicon(icon, extend, extend))
2215 SendMessage(window->winId(), WM_SETICON, (bIsBigIcon ? ICON_BIG : ICON_SMALL), LPARAM(hIcon));
2216 return reinterpret_cast<lamexp_icon_t*>(hIcon);
2219 return NULL;
2223 * Free window icon
2225 void lamexp_free_window_icon(lamexp_icon_t *icon)
2227 if(HICON hIcon = reinterpret_cast<HICON>(icon))
2229 DestroyIcon(hIcon);
2234 * Get system color info
2236 QColor lamexp_system_color(const int color_id)
2238 int nIndex = -1;
2240 switch(color_id)
2242 case lamexp_syscolor_text:
2243 nIndex = COLOR_WINDOWTEXT; /*Text in windows*/
2244 break;
2245 case lamexp_syscolor_background:
2246 nIndex = COLOR_WINDOW; /*Window background*/
2247 break;
2248 case lamexp_syscolor_caption:
2249 nIndex = COLOR_CAPTIONTEXT; /*Text in caption, size box, and scroll bar arrow box*/
2250 break;
2251 default:
2252 qWarning("Unknown system color id (%d) specified!", color_id);
2253 nIndex = COLOR_WINDOWTEXT;
2256 const DWORD rgb = GetSysColor(nIndex);
2257 QColor color(GetRValue(rgb), GetGValue(rgb), GetBValue(rgb));
2258 return color;
2262 * Check if the current user is an administartor (helper function)
2264 static bool lamexp_user_is_admin_helper(void)
2266 HANDLE hToken = NULL;
2267 if(!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
2269 return false;
2272 DWORD dwSize = 0;
2273 if(!GetTokenInformation(hToken, TokenGroups, NULL, 0, &dwSize))
2275 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
2277 CloseHandle(hToken);
2278 return false;
2282 PTOKEN_GROUPS lpGroups = (PTOKEN_GROUPS) malloc(dwSize);
2283 if(!lpGroups)
2285 CloseHandle(hToken);
2286 return false;
2289 if(!GetTokenInformation(hToken, TokenGroups, lpGroups, dwSize, &dwSize))
2291 free(lpGroups);
2292 CloseHandle(hToken);
2293 return false;
2296 PSID lpSid = NULL; SID_IDENTIFIER_AUTHORITY Authority = {SECURITY_NT_AUTHORITY};
2297 if(!AllocateAndInitializeSid(&Authority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &lpSid))
2299 free(lpGroups);
2300 CloseHandle(hToken);
2301 return false;
2304 bool bResult = false;
2305 for(DWORD i = 0; i < lpGroups->GroupCount; i++)
2307 if(EqualSid(lpSid, lpGroups->Groups[i].Sid))
2309 bResult = true;
2310 break;
2314 FreeSid(lpSid);
2315 free(lpGroups);
2316 CloseHandle(hToken);
2317 return bResult;
2321 * Check if the current user is an administartor
2323 bool lamexp_user_is_admin(void)
2325 bool isAdmin = false;
2327 //Check for process elevation and UAC support first!
2328 if(lamexp_process_is_elevated(&isAdmin))
2330 qWarning("Process is elevated -> user is admin!");
2331 return true;
2334 //If not elevated and UAC is not available -> user must be in admin group!
2335 if(!isAdmin)
2337 qDebug("UAC is disabled/unavailable -> checking for Administrators group");
2338 isAdmin = lamexp_user_is_admin_helper();
2341 return isAdmin;
2345 * Check if file is a valid Win32/Win64 executable
2347 bool lamexp_is_executable(const QString &path)
2349 bool bIsExecutable = false;
2350 DWORD binaryType;
2351 if(GetBinaryType(QWCHAR(QDir::toNativeSeparators(path)), &binaryType))
2353 bIsExecutable = (binaryType == SCS_32BIT_BINARY || binaryType == SCS_64BIT_BINARY);
2355 return bIsExecutable;
2359 * Fatal application exit - helper
2361 static DWORD WINAPI lamexp_fatal_exit_helper(LPVOID lpParameter)
2363 MessageBoxA(NULL, ((LPCSTR) lpParameter), "LameXP - Guru Meditation", MB_OK | MB_ICONERROR | MB_TASKMODAL | MB_TOPMOST | MB_SETFOREGROUND);
2364 return 0;
2368 * Fatal application exit
2370 void lamexp_fatal_exit(const char* const errorMessage)
2372 g_lamexp_fatal_lock.enter();
2374 if(!g_lamexp_fatal_flag)
2376 return; /*prevent recursive invocation*/
2379 g_lamexp_fatal_flag = false;
2381 if(g_main_thread_id != GetCurrentThreadId())
2383 if(HANDLE hThreadMain = OpenThread(THREAD_SUSPEND_RESUME, FALSE, g_main_thread_id))
2385 SuspendThread(hThreadMain); /*stop main thread*/
2389 if(HANDLE hThread = CreateThread(NULL, 0, lamexp_fatal_exit_helper, (LPVOID) errorMessage, 0, NULL))
2391 WaitForSingleObject(hThread, INFINITE);
2394 for(;;)
2396 TerminateProcess(GetCurrentProcess(), 666);
2401 * Initialize debug thread
2403 static const HANDLE g_debug_thread1 = LAMEXP_DEBUG ? NULL : lamexp_debug_thread_init();
2406 * Get number private bytes [debug only]
2408 unsigned long lamexp_dbg_private_bytes(void)
2410 #if LAMEXP_DEBUG
2411 for(int i = 0; i < 8; i++) _heapmin();
2412 PROCESS_MEMORY_COUNTERS_EX memoryCounters;
2413 memoryCounters.cb = sizeof(PROCESS_MEMORY_COUNTERS_EX);
2414 GetProcessMemoryInfo(GetCurrentProcess(), (PPROCESS_MEMORY_COUNTERS) &memoryCounters, sizeof(PROCESS_MEMORY_COUNTERS_EX));
2415 return memoryCounters.PrivateUsage;
2416 #else
2417 THROW("Cannot call this function in a non-debug build!");
2418 #endif //LAMEXP_DEBUG
2422 * Output string to debugger [debug only]
2424 void lamexp_dbg_dbg_output_string(const char* format, ...)
2426 #if LAMEXP_DEBUG
2427 char buffer[256];
2428 va_list args;
2429 va_start (args, format);
2430 vsnprintf_s(buffer, 256, _TRUNCATE, format, args);
2431 OutputDebugStringA(buffer);
2432 va_end(args);
2433 #else
2434 THROW("Cannot call this function in a non-debug build!");
2435 #endif //LAMEXP_DEBUG
2438 ///////////////////////////////////////////////////////////////////////////////
2439 // INITIALIZATION
2440 ///////////////////////////////////////////////////////////////////////////////
2442 extern "C" void _lamexp_global_init_win32(void)
2444 if((!LAMEXP_DEBUG) && lamexp_check_for_debugger())
2446 lamexp_fatal_exit("Not a debug build. Please unload debugger and try again!");
2449 //Zero *before* constructors are called
2450 LAMEXP_ZERO_MEMORY(g_lamexp_argv);
2451 LAMEXP_ZERO_MEMORY(g_lamexp_known_folder);
2452 LAMEXP_ZERO_MEMORY(g_lamexp_os_version);
2453 LAMEXP_ZERO_MEMORY(g_lamexp_wine);
2454 LAMEXP_ZERO_MEMORY(g_lamexp_themes_enabled);
2455 LAMEXP_ZERO_MEMORY(g_lamexp_dwmapi);
2456 LAMEXP_ZERO_MEMORY(g_lamexp_sounds);
2459 ///////////////////////////////////////////////////////////////////////////////
2460 // FINALIZATION
2461 ///////////////////////////////////////////////////////////////////////////////
2463 extern "C" void _lamexp_global_free_win32(void)
2465 //Clear folder cache
2466 LAMEXP_DELETE(g_lamexp_known_folder.knownFolders);
2468 //Destroy Qt application object
2469 QApplication *application = dynamic_cast<QApplication*>(QApplication::instance());
2470 LAMEXP_DELETE(application);
2472 //Release DWM API
2473 g_lamexp_dwmapi.dwmIsCompositionEnabled = NULL;
2474 g_lamexp_dwmapi.dwmExtendFrameIntoClientArea = NULL;
2475 g_lamexp_dwmapi.dwmEnableBlurBehindWindow = NULL;
2476 LAMEXP_DELETE(g_lamexp_dwmapi.dwmapi_dll);
2478 //Free STDOUT and STDERR buffers
2479 if(g_lamexp_console_attached)
2481 if(std::filebuf *tmp = dynamic_cast<std::filebuf*>(std::cout.rdbuf()))
2483 std::cout.rdbuf(NULL);
2484 LAMEXP_DELETE(tmp);
2486 if(std::filebuf *tmp = dynamic_cast<std::filebuf*>(std::cerr.rdbuf()))
2488 std::cerr.rdbuf(NULL);
2489 LAMEXP_DELETE(tmp);
2493 //Close log file
2494 if(g_lamexp_log_file)
2496 fclose(g_lamexp_log_file);
2497 g_lamexp_log_file = NULL;
2500 //Clear sound cache
2501 LAMEXP_DELETE(g_lamexp_sounds.sound_db);
2503 //Free CLI Arguments
2504 LAMEXP_DELETE(g_lamexp_argv.list);