Reorganized global functions: The file "Global.h" was split into multiple file in...
[LameXP.git] / src / Global_Win32.cpp
blobcfd6c25000d888a1a87888b4c573f78007a6b0f9
1 ///////////////////////////////////////////////////////////////////////////////
2 // LameXP - Audio Encoder Front-End
3 // Copyright (C) 2004-2013 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>
42 //Qt includes
43 #include <QApplication>
44 #include <QDate>
45 #include <QDir>
46 #include <QEvent>
47 #include <QIcon>
48 #include <QImageReader>
49 #include <QLibrary>
50 #include <QLibraryInfo>
51 #include <QMap>
52 #include <QMessageBox>
53 #include <QMutex>
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>
64 //LameXP includes
65 #define LAMEXP_INC_CONFIG
66 #include "Resource.h"
67 #include "Config.h"
69 //CRT includes
70 #include <cstdio>
71 #include <iostream>
72 #include <fstream>
73 #include <io.h>
74 #include <fcntl.h>
75 #include <intrin.h>
76 #include <cmath>
77 #include <ctime>
78 #include <process.h>
80 //Initialize static Qt plugins
81 #ifdef QT_NODLL
82 #if QT_VERSION < QT_VERSION_CHECK(5,0,0)
83 Q_IMPORT_PLUGIN(qico)
84 Q_IMPORT_PLUGIN(qsvg)
85 #else
86 Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin)
87 Q_IMPORT_PLUGIN(QICOPlugin)
88 #endif
89 #endif
91 ///////////////////////////////////////////////////////////////////////////////
92 // HELPER MACROS
93 ///////////////////////////////////////////////////////////////////////////////
95 #define _LAMEXP_MAKE_STR(STR) #STR
96 #define LAMEXP_MAKE_STR(STR) _LAMEXP_MAKE_STR(STR)
98 //String helper
99 #define CLEAN_OUTPUT_STRING(STR) do \
101 const char CTRL_CHARS[3] = { '\r', '\n', '\t' }; \
102 for(size_t i = 0; i < 3; i++) \
104 while(char *pos = strchr((STR), CTRL_CHARS[i])) *pos = char(0x20); \
107 while(0)
109 //String helper
110 #define TRIM_LEFT(STR) do \
112 const char WHITE_SPACE[4] = { char(0x20), '\r', '\n', '\t' }; \
113 for(size_t i = 0; i < 4; i++) \
115 while(*(STR) == WHITE_SPACE[i]) (STR)++; \
118 while(0)
120 ///////////////////////////////////////////////////////////////////////////////
121 // GLOBAL VARS
122 ///////////////////////////////////////////////////////////////////////////////
124 //Console attached flag
125 static bool g_lamexp_console_attached = false;
127 //Special folders
128 static struct
130 QMap<size_t, QString> *knownFolders;
131 QReadWriteLock lock;
133 g_lamexp_known_folder;
135 //CLI Arguments
136 static struct
138 QStringList *list;
139 QReadWriteLock lock;
141 g_lamexp_argv;
143 //OS Version
144 static struct
146 bool bInitialized;
147 lamexp_os_version_t version;
148 QReadWriteLock lock;
150 g_lamexp_os_version;
152 //Wine detection
153 static struct
155 bool bInitialized;
156 bool bIsWine;
157 QReadWriteLock lock;
159 g_lamexp_wine;
161 //Win32 Theme support
162 static struct
164 bool bInitialized;
165 bool bThemesEnabled;
166 QReadWriteLock lock;
168 g_lamexp_themes_enabled;
170 //Image formats
171 static const char *g_lamexp_imageformats[] = {"bmp", "png", "jpg", "gif", "ico", "xpm", NULL}; //"svg"
173 //Global locks
174 static QMutex g_lamexp_message_mutex;
176 //Main thread ID
177 static const DWORD g_main_thread_id = GetCurrentThreadId();
179 //Log file
180 static FILE *g_lamexp_log_file = NULL;
182 //Localization
183 const char* LAMEXP_DEFAULT_LANGID = "en";
184 const char* LAMEXP_DEFAULT_TRANSLATION = "LameXP_EN.qm";
186 //Known Windows versions - maps marketing names to the actual Windows NT versions
187 const lamexp_os_version_t lamexp_winver_win2k = {5,0};
188 const lamexp_os_version_t lamexp_winver_winxp = {5,1};
189 const lamexp_os_version_t lamexp_winver_xpx64 = {5,2};
190 const lamexp_os_version_t lamexp_winver_vista = {6,0};
191 const lamexp_os_version_t lamexp_winver_win70 = {6,1};
192 const lamexp_os_version_t lamexp_winver_win80 = {6,2};
193 const lamexp_os_version_t lamexp_winver_win81 = {6,3};
195 //GURU MEDITATION
196 static const char *GURU_MEDITATION = "\n\nGURU MEDITATION !!!\n\n";
198 ///////////////////////////////////////////////////////////////////////////////
199 // GLOBAL FUNCTIONS
200 ///////////////////////////////////////////////////////////////////////////////
203 * Verify a specific Windows version
205 static bool lamexp_verify_os_version(const DWORD major, const DWORD minor)
207 OSVERSIONINFOEXW osvi;
208 DWORDLONG dwlConditionMask = 0;
210 //Initialize the OSVERSIONINFOEX structure
211 memset(&osvi, 0, sizeof(OSVERSIONINFOEXW));
212 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW);
213 osvi.dwMajorVersion = major;
214 osvi.dwMinorVersion = minor;
215 osvi.dwPlatformId = VER_PLATFORM_WIN32_NT;
217 //Initialize the condition mask
218 VER_SET_CONDITION(dwlConditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL);
219 VER_SET_CONDITION(dwlConditionMask, VER_MINORVERSION, VER_GREATER_EQUAL);
220 VER_SET_CONDITION(dwlConditionMask, VER_PLATFORMID, VER_EQUAL);
222 // Perform the test
223 const BOOL ret = VerifyVersionInfoW(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_PLATFORMID, dwlConditionMask);
225 //Error checking
226 if(!ret)
228 if(GetLastError() != ERROR_OLD_WIN_VERSION)
230 qWarning("VerifyVersionInfo() system call has failed!");
234 return (ret != FALSE);
238 * Determine the *real* Windows version
240 static bool lamexp_get_real_os_version(unsigned int *major, unsigned int *minor, bool *pbOverride)
242 *major = *minor = 0;
243 *pbOverride = false;
245 //Initialize local variables
246 OSVERSIONINFOEXW osvi;
247 memset(&osvi, 0, sizeof(OSVERSIONINFOEXW));
248 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW);
250 //Try GetVersionEx() first
251 if(GetVersionExW((LPOSVERSIONINFOW)&osvi) == FALSE)
253 qWarning("GetVersionEx() has failed, cannot detect Windows version!");
254 return false;
257 //Make sure we are running on NT
258 if(osvi.dwPlatformId == VER_PLATFORM_WIN32_NT)
260 *major = osvi.dwMajorVersion;
261 *minor = osvi.dwMinorVersion;
263 else
265 qWarning("Not running on Windows NT, unsupported operating system!");
266 return false;
269 //Determine the real *major* version first
270 forever
272 const DWORD nextMajor = (*major) + 1;
273 if(lamexp_verify_os_version(nextMajor, 0))
275 *pbOverride = true;
276 *major = nextMajor;
277 *minor = 0;
278 continue;
280 break;
283 //Now also determine the real *minor* version
284 forever
286 const DWORD nextMinor = (*minor) + 1;
287 if(lamexp_verify_os_version((*major), nextMinor))
289 *pbOverride = true;
290 *minor = nextMinor;
291 continue;
293 break;
296 return true;
300 * Get the native operating system version
302 const lamexp_os_version_t &lamexp_get_os_version(void)
304 QReadLocker readLock(&g_lamexp_os_version.lock);
306 //Already initialized?
307 if(g_lamexp_os_version.bInitialized)
309 return g_lamexp_os_version.version;
312 readLock.unlock();
313 QWriteLocker writeLock(&g_lamexp_os_version.lock);
315 //Detect OS version
316 if(!g_lamexp_os_version.bInitialized)
318 unsigned int major, minor; bool oflag;
319 if(lamexp_get_real_os_version(&major, &minor, &oflag))
321 g_lamexp_os_version.version.versionMajor = major;
322 g_lamexp_os_version.version.versionMinor = minor;
323 g_lamexp_os_version.version.overrideFlag = oflag;
324 g_lamexp_os_version.bInitialized = true;
326 else
328 qWarning("Failed to determin the operating system version!");
332 return g_lamexp_os_version.version;
336 * Check if we are running under wine
338 bool lamexp_detect_wine(void)
340 QReadLocker readLock(&g_lamexp_wine.lock);
342 //Already initialized?
343 if(g_lamexp_wine.bInitialized)
345 return g_lamexp_wine.bIsWine;
348 readLock.unlock();
349 QWriteLocker writeLock(&g_lamexp_wine.lock);
351 if(!g_lamexp_wine.bInitialized)
353 g_lamexp_wine.bIsWine = false;
354 QLibrary ntdll("ntdll.dll");
355 if(ntdll.load())
357 if(ntdll.resolve("wine_nt_to_unix_file_name") != NULL) g_lamexp_wine.bIsWine = true;
358 if(ntdll.resolve("wine_get_version") != NULL) g_lamexp_wine.bIsWine = true;
359 ntdll.unload();
361 g_lamexp_wine.bInitialized = true;
364 return g_lamexp_wine.bIsWine;
368 * Invalid parameters handler
370 void lamexp_invalid_param_handler(const wchar_t* exp, const wchar_t* fun, const wchar_t* fil, unsigned int, uintptr_t)
372 lamexp_fatal_exit(L"Invalid parameter handler invoked, application will exit!");
376 * Change console text color
378 static void lamexp_console_color(FILE* file, WORD attributes)
380 const HANDLE hConsole = (HANDLE)(_get_osfhandle(_fileno(file)));
381 if((hConsole != NULL) && (hConsole != INVALID_HANDLE_VALUE))
383 SetConsoleTextAttribute(hConsole, attributes);
388 * Output logging message to console
390 static void lamexp_write_console(const int type, const char *msg)
392 __try
394 if(_isatty(_fileno(stderr)))
396 UINT oldOutputCP = GetConsoleOutputCP();
397 if(oldOutputCP != CP_UTF8) SetConsoleOutputCP(CP_UTF8);
399 switch(type)
401 case QtCriticalMsg:
402 case QtFatalMsg:
403 lamexp_console_color(stderr, FOREGROUND_RED | FOREGROUND_INTENSITY);
404 fprintf(stderr, GURU_MEDITATION);
405 fprintf(stderr, "%s\n", msg);
406 fflush(stderr);
407 break;
408 case QtWarningMsg:
409 lamexp_console_color(stderr, FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY);
410 fprintf(stderr, "%s\n", msg);
411 fflush(stderr);
412 break;
413 default:
414 lamexp_console_color(stderr, FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY);
415 fprintf(stderr, "%s\n", msg);
416 fflush(stderr);
417 break;
420 lamexp_console_color(stderr, FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED);
421 if(oldOutputCP != CP_UTF8) SetConsoleOutputCP(oldOutputCP);
424 __except(1)
426 /*ignore any exception that might occur here!*/
431 * Output logging message to debugger
433 static void lamexp_write_dbg_out(const int type, const char *msg)
435 const char *FORMAT = "[LameXP][%c] %s\n";
437 __try
439 char buffer[512];
440 const char* input = msg;
441 TRIM_LEFT(input);
443 switch(type)
445 case QtCriticalMsg:
446 case QtFatalMsg:
447 _snprintf_s(buffer, 512, _TRUNCATE, FORMAT, 'C', input);
448 break;
449 case QtWarningMsg:
450 _snprintf_s(buffer, 512, _TRUNCATE, FORMAT, 'W', input);
451 break;
452 default:
453 _snprintf_s(buffer, 512, _TRUNCATE, FORMAT, 'I', input);
454 break;
457 char *temp = &buffer[0];
458 CLEAN_OUTPUT_STRING(temp);
459 OutputDebugStringA(temp);
461 __except(1)
463 /*ignore any exception that might occur here!*/
468 * Output logging message to logfile
470 static void lamexp_write_logfile(const int type, const char *msg)
472 const char *FORMAT = "[%c][%04u] %s\r\n";
474 __try
476 if(g_lamexp_log_file)
478 char buffer[512];
479 strncpy_s(buffer, 512, msg, _TRUNCATE);
481 char *temp = &buffer[0];
482 TRIM_LEFT(temp);
483 CLEAN_OUTPUT_STRING(temp);
485 const unsigned int timestamp = static_cast<unsigned int>(_time64(NULL) % 3600I64);
487 switch(type)
489 case QtCriticalMsg:
490 case QtFatalMsg:
491 fprintf(g_lamexp_log_file, FORMAT, 'C', timestamp, temp);
492 break;
493 case QtWarningMsg:
494 fprintf(g_lamexp_log_file, FORMAT, 'W', timestamp, temp);
495 break;
496 default:
497 fprintf(g_lamexp_log_file, FORMAT, 'I', timestamp, temp);
498 break;
501 fflush(g_lamexp_log_file);
504 __except(1)
506 /*ignore any exception that might occur here!*/
511 * Qt message handler
513 void lamexp_message_handler(QtMsgType type, const char *msg)
515 if((!msg) || (!(msg[0])))
517 return;
520 QMutexLocker lock(&g_lamexp_message_mutex);
522 if(g_lamexp_log_file)
524 lamexp_write_logfile(type, msg);
527 if(g_lamexp_console_attached)
529 lamexp_write_console(type, msg);
531 else
533 lamexp_write_dbg_out(type, msg);
536 if((type == QtCriticalMsg) || (type == QtFatalMsg))
538 lock.unlock();
539 lamexp_fatal_exit(L"The application has encountered a critical error and will exit now!", QWCHAR(QString::fromUtf8(msg)));
545 * Global exception handler
547 static LONG WINAPI lamexp_exception_handler(__in struct _EXCEPTION_POINTERS *ExceptionInfo)
549 lamexp_fatal_exit(L"Unhandeled exception handler invoked, application will exit!");
550 return LONG_MAX;
554 * Initialize error handlers
556 void lamexp_init_error_handlers(void)
558 SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
559 SetUnhandledExceptionFilter(lamexp_exception_handler);
560 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
561 _set_invalid_parameter_handler(lamexp_invalid_param_handler);
565 * Initialize the console
567 void lamexp_init_console(const QStringList &argv)
569 bool enableConsole = (LAMEXP_DEBUG) || ((VER_LAMEXP_CONSOLE_ENABLED) && lamexp_version_demo());
571 if(_environ)
573 wchar_t *logfile = NULL;
574 size_t logfile_len = 0;
575 if(!_wdupenv_s(&logfile, &logfile_len, L"LAMEXP_LOGFILE"))
577 if(logfile && (logfile_len > 0))
579 FILE *temp = NULL;
580 if(!_wfopen_s(&temp, logfile, L"wb"))
582 fprintf(temp, "%c%c%c", char(0xEF), char(0xBB), char(0xBF));
583 g_lamexp_log_file = temp;
585 free(logfile);
590 if(!LAMEXP_DEBUG)
592 for(int i = 0; i < argv.count(); i++)
594 if(!argv.at(i).compare("--console", Qt::CaseInsensitive))
596 enableConsole = true;
598 else if(!argv.at(i).compare("--no-console", Qt::CaseInsensitive))
600 enableConsole = false;
605 if(enableConsole)
607 if(!g_lamexp_console_attached)
609 if(AllocConsole() != FALSE)
611 SetConsoleCtrlHandler(NULL, TRUE);
612 SetConsoleTitle(L"LameXP - Audio Encoder Front-End | Debug Console");
613 SetConsoleOutputCP(CP_UTF8);
614 g_lamexp_console_attached = true;
618 if(g_lamexp_console_attached)
620 //-------------------------------------------------------------------
621 //See: http://support.microsoft.com/default.aspx?scid=kb;en-us;105305
622 //-------------------------------------------------------------------
623 const int flags = _O_WRONLY | _O_U8TEXT;
624 int hCrtStdOut = _open_osfhandle((intptr_t) GetStdHandle(STD_OUTPUT_HANDLE), flags);
625 int hCrtStdErr = _open_osfhandle((intptr_t) GetStdHandle(STD_ERROR_HANDLE), flags);
626 FILE *hfStdOut = (hCrtStdOut >= 0) ? _fdopen(hCrtStdOut, "wb") : NULL;
627 FILE *hfStdErr = (hCrtStdErr >= 0) ? _fdopen(hCrtStdErr, "wb") : NULL;
628 if(hfStdOut) { *stdout = *hfStdOut; std::cout.rdbuf(new std::filebuf(hfStdOut)); }
629 if(hfStdErr) { *stderr = *hfStdErr; std::cerr.rdbuf(new std::filebuf(hfStdErr)); }
632 HWND hwndConsole = GetConsoleWindow();
634 if((hwndConsole != NULL) && (hwndConsole != INVALID_HANDLE_VALUE))
636 HMENU hMenu = GetSystemMenu(hwndConsole, 0);
637 EnableMenuItem(hMenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);
638 RemoveMenu(hMenu, SC_CLOSE, MF_BYCOMMAND);
640 SetWindowPos(hwndConsole, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_FRAMECHANGED);
641 SetWindowLong(hwndConsole, GWL_STYLE, GetWindowLong(hwndConsole, GWL_STYLE) & (~WS_MAXIMIZEBOX) & (~WS_MINIMIZEBOX));
642 SetWindowPos(hwndConsole, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_FRAMECHANGED);
648 * Detect CPU features
650 lamexp_cpu_t lamexp_detect_cpu_features(const QStringList &argv)
652 typedef BOOL (WINAPI *IsWow64ProcessFun)(__in HANDLE hProcess, __out PBOOL Wow64Process);
654 lamexp_cpu_t features;
655 SYSTEM_INFO systemInfo;
656 int CPUInfo[4] = {-1};
657 char CPUIdentificationString[0x40];
658 char CPUBrandString[0x40];
660 memset(&features, 0, sizeof(lamexp_cpu_t));
661 memset(&systemInfo, 0, sizeof(SYSTEM_INFO));
662 memset(CPUIdentificationString, 0, sizeof(CPUIdentificationString));
663 memset(CPUBrandString, 0, sizeof(CPUBrandString));
665 __cpuid(CPUInfo, 0);
666 memcpy(CPUIdentificationString, &CPUInfo[1], sizeof(int));
667 memcpy(CPUIdentificationString + 4, &CPUInfo[3], sizeof(int));
668 memcpy(CPUIdentificationString + 8, &CPUInfo[2], sizeof(int));
669 features.intel = (_stricmp(CPUIdentificationString, "GenuineIntel") == 0);
670 strncpy_s(features.vendor, 0x40, CPUIdentificationString, _TRUNCATE);
672 if(CPUInfo[0] >= 1)
674 __cpuid(CPUInfo, 1);
675 features.mmx = (CPUInfo[3] & 0x800000) || false;
676 features.sse = (CPUInfo[3] & 0x2000000) || false;
677 features.sse2 = (CPUInfo[3] & 0x4000000) || false;
678 features.ssse3 = (CPUInfo[2] & 0x200) || false;
679 features.sse3 = (CPUInfo[2] & 0x1) || false;
680 features.ssse3 = (CPUInfo[2] & 0x200) || false;
681 features.stepping = CPUInfo[0] & 0xf;
682 features.model = ((CPUInfo[0] >> 4) & 0xf) + (((CPUInfo[0] >> 16) & 0xf) << 4);
683 features.family = ((CPUInfo[0] >> 8) & 0xf) + ((CPUInfo[0] >> 20) & 0xff);
686 __cpuid(CPUInfo, 0x80000000);
687 int nExIds = qMax<int>(qMin<int>(CPUInfo[0], 0x80000004), 0x80000000);
689 for(int i = 0x80000002; i <= nExIds; ++i)
691 __cpuid(CPUInfo, i);
692 switch(i)
694 case 0x80000002:
695 memcpy(CPUBrandString, CPUInfo, sizeof(CPUInfo));
696 break;
697 case 0x80000003:
698 memcpy(CPUBrandString + 16, CPUInfo, sizeof(CPUInfo));
699 break;
700 case 0x80000004:
701 memcpy(CPUBrandString + 32, CPUInfo, sizeof(CPUInfo));
702 break;
706 strncpy_s(features.brand, 0x40, CPUBrandString, _TRUNCATE);
708 if(strlen(features.brand) < 1) strncpy_s(features.brand, 0x40, "Unknown", _TRUNCATE);
709 if(strlen(features.vendor) < 1) strncpy_s(features.vendor, 0x40, "Unknown", _TRUNCATE);
711 #if (!(defined(_M_X64) || defined(_M_IA64)))
712 QLibrary Kernel32Lib("kernel32.dll");
713 if(IsWow64ProcessFun IsWow64ProcessPtr = (IsWow64ProcessFun) Kernel32Lib.resolve("IsWow64Process"))
715 BOOL x64flag = FALSE;
716 if(IsWow64ProcessPtr(GetCurrentProcess(), &x64flag))
718 features.x64 = (x64flag == TRUE);
721 #else
722 features.x64 = true;
723 #endif
725 DWORD_PTR procAffinity, sysAffinity;
726 if(GetProcessAffinityMask(GetCurrentProcess(), &procAffinity, &sysAffinity))
728 for(DWORD_PTR mask = 1; mask; mask <<= 1)
730 features.count += ((sysAffinity & mask) ? (1) : (0));
733 if(features.count < 1)
735 GetNativeSystemInfo(&systemInfo);
736 features.count = qBound(1UL, systemInfo.dwNumberOfProcessors, 64UL);
739 if(argv.count() > 0)
741 bool flag = false;
742 for(int i = 0; i < argv.count(); i++)
744 if(!argv[i].compare("--force-cpu-no-64bit", Qt::CaseInsensitive)) { flag = true; features.x64 = false; }
745 if(!argv[i].compare("--force-cpu-no-sse", Qt::CaseInsensitive)) { flag = true; features.sse = features.sse2 = features.sse3 = features.ssse3 = false; }
746 if(!argv[i].compare("--force-cpu-no-intel", Qt::CaseInsensitive)) { flag = true; features.intel = false; }
748 if(flag) qWarning("CPU flags overwritten by user-defined parameters. Take care!\n");
751 return features;
755 * Check for debugger (detect routine)
757 static __forceinline bool lamexp_check_for_debugger(void)
759 __try
761 CloseHandle((HANDLE)((DWORD_PTR)-3));
763 __except(1)
765 return true;
767 __try
769 __debugbreak();
771 __except(1)
773 return IsDebuggerPresent();
775 return true;
779 * Check for debugger (thread proc)
781 static unsigned int __stdcall lamexp_debug_thread_proc(LPVOID lpParameter)
783 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_LOWEST);
784 forever
786 if(lamexp_check_for_debugger())
788 lamexp_fatal_exit(L"Not a debug build. Please unload debugger and try again!");
789 return 666;
791 lamexp_sleep(100);
796 * Check for debugger (startup routine)
798 static HANDLE lamexp_debug_thread_init()
800 if(lamexp_check_for_debugger())
802 lamexp_fatal_exit(L"Not a debug build. Please unload debugger and try again!");
804 const uintptr_t h = _beginthreadex(NULL, 0, lamexp_debug_thread_proc, NULL, 0, NULL);
805 return (HANDLE)(h^0xdeadbeef);
809 * Qt event filter
811 static bool lamexp_event_filter(void *message, long *result)
813 if((!(LAMEXP_DEBUG)) && lamexp_check_for_debugger())
815 lamexp_fatal_exit(L"Not a debug build. Please unload debugger and try again!");
818 switch(reinterpret_cast<MSG*>(message)->message)
820 case WM_QUERYENDSESSION:
821 qWarning("WM_QUERYENDSESSION message received!");
822 *result = lamexp_broadcast(lamexp_event_queryendsession, false) ? TRUE : FALSE;
823 return true;
824 case WM_ENDSESSION:
825 qWarning("WM_ENDSESSION message received!");
826 if(reinterpret_cast<MSG*>(message)->wParam == TRUE)
828 lamexp_broadcast(lamexp_event_endsession, false);
829 if(QApplication *app = reinterpret_cast<QApplication*>(QApplication::instance()))
831 app->closeAllWindows();
832 app->quit();
834 lamexp_finalization();
835 exit(1);
837 *result = 0;
838 return true;
839 default:
840 /*ignore this message and let Qt handle it*/
841 return false;
846 * Check for process elevation
848 static bool lamexp_check_elevation(void)
850 typedef enum { lamexp_token_elevationType_class = 18, lamexp_token_elevation_class = 20 } LAMEXP_TOKEN_INFORMATION_CLASS;
851 typedef enum { lamexp_elevationType_default = 1, lamexp_elevationType_full, lamexp_elevationType_limited } LAMEXP_TOKEN_ELEVATION_TYPE;
853 HANDLE hToken = NULL;
854 bool bIsProcessElevated = false;
856 if(OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
858 LAMEXP_TOKEN_ELEVATION_TYPE tokenElevationType;
859 DWORD returnLength;
860 if(GetTokenInformation(hToken, (TOKEN_INFORMATION_CLASS) lamexp_token_elevationType_class, &tokenElevationType, sizeof(LAMEXP_TOKEN_ELEVATION_TYPE), &returnLength))
862 if(returnLength == sizeof(LAMEXP_TOKEN_ELEVATION_TYPE))
864 switch(tokenElevationType)
866 case lamexp_elevationType_default:
867 qDebug("Process token elevation type: Default -> UAC is disabled.\n");
868 break;
869 case lamexp_elevationType_full:
870 qWarning("Process token elevation type: Full -> potential security risk!\n");
871 bIsProcessElevated = true;
872 break;
873 case lamexp_elevationType_limited:
874 qDebug("Process token elevation type: Limited -> not elevated.\n");
875 break;
879 CloseHandle(hToken);
881 else
883 qWarning("Failed to open process token!");
886 return !bIsProcessElevated;
890 * Initialize Qt framework
892 bool lamexp_init_qt(int argc, char* argv[])
894 static bool qt_initialized = false;
895 typedef BOOL (WINAPI *SetDllDirectoryProc)(WCHAR *lpPathName);
896 const QStringList &arguments = lamexp_arguments();
898 //Don't initialized again, if done already
899 if(qt_initialized)
901 return true;
904 //Secure DLL loading
905 QLibrary kernel32("kernel32.dll");
906 if(kernel32.load())
908 SetDllDirectoryProc pSetDllDirectory = (SetDllDirectoryProc) kernel32.resolve("SetDllDirectoryW");
909 if(pSetDllDirectory != NULL) pSetDllDirectory(L"");
912 //Extract executable name from argv[] array
913 QString executableName = QLatin1String("LameXP.exe");
914 if(arguments.count() > 0)
916 static const char *delimiters = "\\/:?";
917 executableName = arguments[0].trimmed();
918 for(int i = 0; delimiters[i]; i++)
920 int temp = executableName.lastIndexOf(QChar(delimiters[i]));
921 if(temp >= 0) executableName = executableName.mid(temp + 1);
923 executableName = executableName.trimmed();
924 if(executableName.isEmpty())
926 executableName = QLatin1String("LameXP.exe");
930 //Check Qt version
931 #ifdef QT_BUILD_KEY
932 qDebug("Using Qt v%s [%s], %s, %s", qVersion(), QLibraryInfo::buildDate().toString(Qt::ISODate).toLatin1().constData(), (qSharedBuild() ? "DLL" : "Static"), QLibraryInfo::buildKey().toLatin1().constData());
933 qDebug("Compiled with Qt v%s [%s], %s\n", QT_VERSION_STR, QT_PACKAGEDATE_STR, QT_BUILD_KEY);
934 if(_stricmp(qVersion(), QT_VERSION_STR))
936 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());
937 return false;
939 if(QLibraryInfo::buildKey().compare(QString::fromLatin1(QT_BUILD_KEY), Qt::CaseInsensitive))
941 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());
942 return false;
944 #else
945 qDebug("Using Qt v%s [%s], %s", qVersion(), QLibraryInfo::buildDate().toString(Qt::ISODate).toLatin1().constData(), (qSharedBuild() ? "DLL" : "Static"));
946 qDebug("Compiled with Qt v%s [%s]\n", QT_VERSION_STR, QT_PACKAGEDATE_STR);
947 #endif
949 //Check the Windows version
950 const lamexp_os_version_t &osVersionNo = lamexp_get_os_version();
951 if(osVersionNo < lamexp_winver_winxp)
953 qFatal("%s", QApplication::tr("Executable '%1' requires Windows XP or later.").arg(executableName).toLatin1().constData());
956 //Supported Windows version?
957 if(osVersionNo == lamexp_winver_winxp)
959 qDebug("Running on Windows XP or Windows XP Media Center Edition.\n"); //lamexp_check_compatibility_mode("GetLargePageMinimum", executableName);
961 else if(osVersionNo == lamexp_winver_xpx64)
963 qDebug("Running on Windows Server 2003, Windows Server 2003 R2 or Windows XP x64.\n"); //lamexp_check_compatibility_mode("GetLocaleInfoEx", executableName);
965 else if(osVersionNo == lamexp_winver_vista)
967 qDebug("Running on Windows Vista or Windows Server 2008.\n"); //lamexp_check_compatibility_mode("CreateRemoteThreadEx", executableName*/);
969 else if(osVersionNo == lamexp_winver_win70)
971 qDebug("Running on Windows 7 or Windows Server 2008 R2.\n"); //lamexp_check_compatibility_mode("CreateFile2", executableName);
973 else if(osVersionNo == lamexp_winver_win80)
975 qDebug("Running on Windows 8 or Windows Server 2012.\n"); //lamexp_check_compatibility_mode("FindPackagesByPackageFamily", executableName);
977 else if(osVersionNo == lamexp_winver_win81)
979 qDebug("Running on Windows 8.1 or Windows Server 2012 R2.\n"); //lamexp_check_compatibility_mode(NULL, executableName);
981 else
983 const QString message = QString().sprintf("Running on an unknown WindowsNT-based system (v%u.%u).", osVersionNo.versionMajor, osVersionNo.versionMinor);
984 qWarning("%s\n", QUTF8(message));
985 MessageBoxW(NULL, QWCHAR(message), L"LameXP", MB_OK | MB_TOPMOST | MB_ICONWARNING);
988 //Check for compat mode
989 if(osVersionNo.overrideFlag && (osVersionNo <= lamexp_winver_win81))
991 qWarning("Windows compatibility mode detected!");
992 if(!arguments.contains("--ignore-compat-mode", Qt::CaseInsensitive))
994 qFatal("%s", QApplication::tr("Executable '%1' doesn't support Windows compatibility mode.").arg(executableName).toLatin1().constData());
995 return false;
999 //Check for Wine
1000 if(lamexp_detect_wine())
1002 qWarning("It appears we are running under Wine, unexpected things might happen!\n");
1005 //Set text Codec for locale
1006 QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"));
1008 //Create Qt application instance
1009 QApplication *application = new QApplication(argc, argv);
1011 //Load plugins from application directory
1012 QCoreApplication::setLibraryPaths(QStringList() << QApplication::applicationDirPath());
1013 qDebug("Library Path:\n%s\n", QUTF8(QApplication::libraryPaths().first()));
1015 //Set application properties
1016 application->setApplicationName("LameXP - Audio Encoder Front-End");
1017 application->setApplicationVersion(QString().sprintf("%d.%02d.%04d", lamexp_version_major(), lamexp_version_minor(), lamexp_version_build()));
1018 application->setOrganizationName("LoRd_MuldeR");
1019 application->setOrganizationDomain("mulder.at.gg");
1020 application->setWindowIcon(lamexp_app_icon());
1021 application->setEventFilter(lamexp_event_filter);
1023 //Check for supported image formats
1024 QList<QByteArray> supportedFormats = QImageReader::supportedImageFormats();
1025 for(int i = 0; g_lamexp_imageformats[i]; i++)
1027 if(!supportedFormats.contains(g_lamexp_imageformats[i]))
1029 qFatal("Qt initialization error: QImageIOHandler for '%s' missing!", g_lamexp_imageformats[i]);
1030 return false;
1034 //Add the default translations
1035 lamexp_translation_init();
1037 //Check for process elevation
1038 if((!lamexp_check_elevation()) && (!lamexp_detect_wine()))
1040 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);
1041 messageBox.addButton("Quit Program (Recommended)", QMessageBox::NoRole);
1042 messageBox.addButton("Ignore", QMessageBox::NoRole);
1043 if(messageBox.exec() == 0)
1045 return false;
1049 //Update console icon, if a console is attached
1050 #if QT_VERSION < QT_VERSION_CHECK(5,0,0)
1051 if(g_lamexp_console_attached && (!lamexp_detect_wine()))
1053 typedef DWORD (__stdcall *SetConsoleIconFun)(HICON);
1054 QLibrary kernel32("kernel32.dll");
1055 if(kernel32.load())
1057 SetConsoleIconFun SetConsoleIconPtr = (SetConsoleIconFun) kernel32.resolve("SetConsoleIcon");
1058 QPixmap pixmap = QIcon(":/icons/sound.png").pixmap(16, 16);
1059 if((SetConsoleIconPtr != NULL) && (!pixmap.isNull())) SetConsoleIconPtr(pixmap.toWinHICON());
1060 kernel32.unload();
1063 #endif
1065 //Done
1066 qt_initialized = true;
1067 return true;
1070 const QStringList &lamexp_arguments(void)
1072 QReadLocker readLock(&g_lamexp_argv.lock);
1074 if(!g_lamexp_argv.list)
1076 readLock.unlock();
1077 QWriteLocker writeLock(&g_lamexp_argv.lock);
1079 g_lamexp_argv.list = new QStringList;
1081 int nArgs = 0;
1082 LPWSTR *szArglist = CommandLineToArgvW(GetCommandLineW(), &nArgs);
1084 if(NULL != szArglist)
1086 for(int i = 0; i < nArgs; i++)
1088 (*g_lamexp_argv.list) << WCHAR2QSTR(szArglist[i]);
1090 LocalFree(szArglist);
1092 else
1094 qWarning("CommandLineToArgvW() has failed !!!");
1098 return (*g_lamexp_argv.list);
1102 * Locate known folder on local system
1104 const QString &lamexp_known_folder(lamexp_known_folder_t folder_id)
1106 typedef HRESULT (WINAPI *SHGetKnownFolderPathFun)(__in const GUID &rfid, __in DWORD dwFlags, __in HANDLE hToken, __out PWSTR *ppszPath);
1107 typedef HRESULT (WINAPI *SHGetFolderPathFun)(__in HWND hwndOwner, __in int nFolder, __in HANDLE hToken, __in DWORD dwFlags, __out LPWSTR pszPath);
1109 static const int CSIDL_LOCAL_APPDATA = 0x001c;
1110 static const int CSIDL_PROGRAM_FILES = 0x0026;
1111 static const int CSIDL_SYSTEM_FOLDER = 0x0025;
1112 static const GUID GUID_LOCAL_APPDATA = {0xF1B32785,0x6FBA,0x4FCF,{0x9D,0x55,0x7B,0x8E,0x7F,0x15,0x70,0x91}};
1113 static const GUID GUID_LOCAL_APPDATA_LOW = {0xA520A1A4,0x1780,0x4FF6,{0xBD,0x18,0x16,0x73,0x43,0xC5,0xAF,0x16}};
1114 static const GUID GUID_PROGRAM_FILES = {0x905e63b6,0xc1bf,0x494e,{0xb2,0x9c,0x65,0xb7,0x32,0xd3,0xd2,0x1a}};
1115 static const GUID GUID_SYSTEM_FOLDER = {0x1AC14E77,0x02E7,0x4E5D,{0xB7,0x44,0x2E,0xB1,0xAE,0x51,0x98,0xB7}};
1117 QReadLocker readLock(&g_lamexp_known_folder.lock);
1119 int folderCSIDL = -1;
1120 GUID folderGUID = {0x0000,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}};
1121 size_t folderCacheId = size_t(-1);
1123 switch(folder_id)
1125 case lamexp_folder_localappdata:
1126 folderCacheId = 0;
1127 folderCSIDL = CSIDL_LOCAL_APPDATA;
1128 folderGUID = GUID_LOCAL_APPDATA;
1129 break;
1130 case lamexp_folder_programfiles:
1131 folderCacheId = 1;
1132 folderCSIDL = CSIDL_PROGRAM_FILES;
1133 folderGUID = GUID_PROGRAM_FILES;
1134 break;
1135 case lamexp_folder_systemfolder:
1136 folderCacheId = 2;
1137 folderCSIDL = CSIDL_SYSTEM_FOLDER;
1138 folderGUID = GUID_SYSTEM_FOLDER;
1139 break;
1140 default:
1141 qWarning("Invalid 'known' folder was requested!");
1142 return *reinterpret_cast<QString*>(NULL);
1143 break;
1146 //Already in cache?
1147 if(g_lamexp_known_folder.knownFolders)
1149 if(g_lamexp_known_folder.knownFolders->contains(folderCacheId))
1151 return (*g_lamexp_known_folder.knownFolders)[folderCacheId];
1155 //Obtain write lock to initialize
1156 readLock.unlock();
1157 QWriteLocker writeLock(&g_lamexp_known_folder.lock);
1159 //Still not in cache?
1160 if(g_lamexp_known_folder.knownFolders)
1162 if(g_lamexp_known_folder.knownFolders->contains(folderCacheId))
1164 return (*g_lamexp_known_folder.knownFolders)[folderCacheId];
1168 static SHGetKnownFolderPathFun SHGetKnownFolderPathPtr = NULL;
1169 static SHGetFolderPathFun SHGetFolderPathPtr = NULL;
1171 //Lookup functions
1172 if((!SHGetKnownFolderPathPtr) && (!SHGetFolderPathPtr))
1174 QLibrary kernel32Lib("shell32.dll");
1175 if(kernel32Lib.load())
1177 SHGetKnownFolderPathPtr = (SHGetKnownFolderPathFun) kernel32Lib.resolve("SHGetKnownFolderPath");
1178 SHGetFolderPathPtr = (SHGetFolderPathFun) kernel32Lib.resolve("SHGetFolderPathW");
1182 QString folder;
1184 //Now try to get the folder path!
1185 if(SHGetKnownFolderPathPtr)
1187 WCHAR *path = NULL;
1188 if(SHGetKnownFolderPathPtr(folderGUID, 0x00008000, NULL, &path) == S_OK)
1190 //MessageBoxW(0, path, L"SHGetKnownFolderPath", MB_TOPMOST);
1191 QDir folderTemp = QDir(QDir::fromNativeSeparators(QString::fromUtf16(reinterpret_cast<const unsigned short*>(path))));
1192 if(!folderTemp.exists())
1194 folderTemp.mkpath(".");
1196 if(folderTemp.exists())
1198 folder = folderTemp.canonicalPath();
1200 CoTaskMemFree(path);
1203 else if(SHGetFolderPathPtr)
1205 WCHAR *path = new WCHAR[4096];
1206 if(SHGetFolderPathPtr(NULL, folderCSIDL, NULL, NULL, path) == S_OK)
1208 //MessageBoxW(0, path, L"SHGetFolderPathW", MB_TOPMOST);
1209 QDir folderTemp = QDir(QDir::fromNativeSeparators(QString::fromUtf16(reinterpret_cast<const unsigned short*>(path))));
1210 if(!folderTemp.exists())
1212 folderTemp.mkpath(".");
1214 if(folderTemp.exists())
1216 folder = folderTemp.canonicalPath();
1219 delete [] path;
1222 //Create cache
1223 if(!g_lamexp_known_folder.knownFolders)
1225 g_lamexp_known_folder.knownFolders = new QMap<size_t, QString>();
1228 //Update cache
1229 g_lamexp_known_folder.knownFolders->insert(folderCacheId, folder);
1230 return (*g_lamexp_known_folder.knownFolders)[folderCacheId];
1234 * Safely remove a file
1236 bool lamexp_remove_file(const QString &filename)
1238 if(!QFileInfo(filename).exists() || !QFileInfo(filename).isFile())
1240 return true;
1242 else
1244 if(!QFile::remove(filename))
1246 DWORD attributes = GetFileAttributesW(QWCHAR(filename));
1247 SetFileAttributesW(QWCHAR(filename), (attributes & (~FILE_ATTRIBUTE_READONLY)));
1248 if(!QFile::remove(filename))
1250 qWarning("Could not delete \"%s\"", filename.toLatin1().constData());
1251 return false;
1253 else
1255 return true;
1258 else
1260 return true;
1266 * Check if visual themes are enabled (WinXP and later)
1268 bool lamexp_themes_enabled(void)
1270 typedef int (WINAPI *IsAppThemedFun)(void);
1272 QReadLocker readLock(&g_lamexp_themes_enabled.lock);
1273 if(g_lamexp_themes_enabled.bInitialized)
1275 return g_lamexp_themes_enabled.bThemesEnabled;
1278 readLock.unlock();
1279 QWriteLocker writeLock(&g_lamexp_themes_enabled.lock);
1281 if(!g_lamexp_themes_enabled.bInitialized)
1283 g_lamexp_themes_enabled.bThemesEnabled = false;
1284 const lamexp_os_version_t &osVersion = lamexp_get_os_version();
1285 if(osVersion >= lamexp_winver_winxp)
1287 IsAppThemedFun IsAppThemedPtr = NULL;
1288 QLibrary uxTheme(QString("%1/UxTheme.dll").arg(lamexp_known_folder(lamexp_folder_systemfolder)));
1289 if(uxTheme.load())
1291 IsAppThemedPtr = (IsAppThemedFun) uxTheme.resolve("IsAppThemed");
1293 if(IsAppThemedPtr)
1295 g_lamexp_themes_enabled.bThemesEnabled = IsAppThemedPtr();
1296 if(!g_lamexp_themes_enabled.bThemesEnabled)
1298 qWarning("Theme support is disabled for this process!");
1302 g_lamexp_themes_enabled.bInitialized = true;
1305 return g_lamexp_themes_enabled.bThemesEnabled;
1309 * Get number of free bytes on disk
1311 unsigned __int64 lamexp_free_diskspace(const QString &path, bool *ok)
1313 ULARGE_INTEGER freeBytesAvailable, totalNumberOfBytes, totalNumberOfFreeBytes;
1314 if(GetDiskFreeSpaceExW(reinterpret_cast<const wchar_t*>(QDir::toNativeSeparators(path).utf16()), &freeBytesAvailable, &totalNumberOfBytes, &totalNumberOfFreeBytes))
1316 if(ok) *ok = true;
1317 return freeBytesAvailable.QuadPart;
1319 else
1321 if(ok) *ok = false;
1322 return 0;
1327 * Check if computer does support hibernation
1329 bool lamexp_is_hibernation_supported(void)
1331 bool hibernationSupported = false;
1333 SYSTEM_POWER_CAPABILITIES pwrCaps;
1334 SecureZeroMemory(&pwrCaps, sizeof(SYSTEM_POWER_CAPABILITIES));
1336 if(GetPwrCapabilities(&pwrCaps))
1338 hibernationSupported = pwrCaps.SystemS4 && pwrCaps.HiberFilePresent;
1341 return hibernationSupported;
1345 * Shutdown the computer
1347 bool lamexp_shutdown_computer(const QString &message, const unsigned long timeout, const bool forceShutdown, const bool hibernate)
1349 HANDLE hToken = NULL;
1351 if(OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
1353 TOKEN_PRIVILEGES privileges;
1354 memset(&privileges, 0, sizeof(TOKEN_PRIVILEGES));
1355 privileges.PrivilegeCount = 1;
1356 privileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
1358 if(LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &privileges.Privileges[0].Luid))
1360 if(AdjustTokenPrivileges(hToken, FALSE, &privileges, NULL, NULL, NULL))
1362 if(hibernate)
1364 if(SetSuspendState(TRUE, TRUE, TRUE))
1366 return true;
1369 const DWORD reason = SHTDN_REASON_MAJOR_APPLICATION | SHTDN_REASON_FLAG_PLANNED;
1370 return InitiateSystemShutdownEx(NULL, const_cast<wchar_t*>(QWCHAR(message)), timeout, forceShutdown ? TRUE : FALSE, FALSE, reason);
1375 return false;
1379 * Determines the current date, resistant against certain manipulations
1381 QDate lamexp_current_date_safe(void)
1383 const DWORD MAX_PROC = 1024;
1384 DWORD *processes = new DWORD[MAX_PROC];
1385 DWORD bytesReturned = 0;
1387 if(!EnumProcesses(processes, sizeof(DWORD) * MAX_PROC, &bytesReturned))
1389 LAMEXP_DELETE_ARRAY(processes);
1390 return QDate::currentDate();
1393 const DWORD procCount = bytesReturned / sizeof(DWORD);
1394 ULARGE_INTEGER lastStartTime;
1395 memset(&lastStartTime, 0, sizeof(ULARGE_INTEGER));
1397 for(DWORD i = 0; i < procCount; i++)
1399 HANDLE hProc = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, processes[i]);
1400 if(hProc)
1402 FILETIME processTime[4];
1403 if(GetProcessTimes(hProc, &processTime[0], &processTime[1], &processTime[2], &processTime[3]))
1405 ULARGE_INTEGER timeCreation;
1406 timeCreation.LowPart = processTime[0].dwLowDateTime;
1407 timeCreation.HighPart = processTime[0].dwHighDateTime;
1408 if(timeCreation.QuadPart > lastStartTime.QuadPart)
1410 lastStartTime.QuadPart = timeCreation.QuadPart;
1413 CloseHandle(hProc);
1417 LAMEXP_DELETE_ARRAY(processes);
1419 FILETIME lastStartTime_fileTime;
1420 lastStartTime_fileTime.dwHighDateTime = lastStartTime.HighPart;
1421 lastStartTime_fileTime.dwLowDateTime = lastStartTime.LowPart;
1423 FILETIME lastStartTime_localTime;
1424 if(!FileTimeToLocalFileTime(&lastStartTime_fileTime, &lastStartTime_localTime))
1426 memcpy(&lastStartTime_localTime, &lastStartTime_fileTime, sizeof(FILETIME));
1429 SYSTEMTIME lastStartTime_system;
1430 if(!FileTimeToSystemTime(&lastStartTime_localTime, &lastStartTime_system))
1432 memset(&lastStartTime_system, 0, sizeof(SYSTEMTIME));
1433 lastStartTime_system.wYear = 1970; lastStartTime_system.wMonth = lastStartTime_system.wDay = 1;
1436 const QDate currentDate = QDate::currentDate();
1437 const QDate processDate = QDate(lastStartTime_system.wYear, lastStartTime_system.wMonth, lastStartTime_system.wDay);
1438 return (currentDate >= processDate) ? currentDate : processDate;
1442 * Suspend calling thread for N milliseconds
1444 inline void lamexp_sleep(const unsigned int delay)
1446 Sleep(delay);
1449 bool lamexp_beep(int beepType)
1451 switch(beepType)
1453 case lamexp_beep_info: return MessageBeep(MB_ICONASTERISK) == TRUE; break;
1454 case lamexp_beep_warning: return MessageBeep(MB_ICONEXCLAMATION) == TRUE; break;
1455 case lamexp_beep_error: return MessageBeep(MB_ICONHAND) == TRUE; break;
1456 default: return false;
1461 * Play a sound (from resources)
1463 bool lamexp_play_sound(const unsigned short uiSoundIdx, const bool bAsync, const wchar_t *alias)
1465 if(alias)
1467 return PlaySound(alias, GetModuleHandle(NULL), (SND_ALIAS | (bAsync ? SND_ASYNC : SND_SYNC))) == TRUE;
1469 else
1471 return PlaySound(MAKEINTRESOURCE(uiSoundIdx), GetModuleHandle(NULL), (SND_RESOURCE | (bAsync ? SND_ASYNC : SND_SYNC))) == TRUE;
1476 * Play a sound (from resources)
1478 bool lamexp_play_sound_file(const QString &library, const unsigned short uiSoundIdx, const bool bAsync)
1480 bool result = false;
1481 HMODULE module = NULL;
1483 QFileInfo libraryFile(library);
1484 if(!libraryFile.isAbsolute())
1486 unsigned int buffSize = GetSystemDirectoryW(NULL, NULL) + 1;
1487 wchar_t *buffer = (wchar_t*) _malloca(buffSize * sizeof(wchar_t));
1488 unsigned int result = GetSystemDirectory(buffer, buffSize);
1489 if(result > 0 && result < buffSize)
1491 libraryFile.setFile(QString("%1/%2").arg(QDir::fromNativeSeparators(QString::fromUtf16(reinterpret_cast<const unsigned short*>(buffer))), library));
1493 _freea(buffer);
1496 module = LoadLibraryW(QWCHAR(QDir::toNativeSeparators(libraryFile.absoluteFilePath())));
1497 if(module)
1499 result = (PlaySound(MAKEINTRESOURCE(uiSoundIdx), module, (SND_RESOURCE | (bAsync ? SND_ASYNC : SND_SYNC))) == TRUE);
1500 FreeLibrary(module);
1503 return result;
1507 * Open file using the shell
1509 bool lamexp_exec_shell(const QWidget *win, const QString &url, const bool explore)
1511 return lamexp_exec_shell(win, url, QString(), QString(), explore);
1515 * Open file using the shell (with parameters)
1517 bool lamexp_exec_shell(const QWidget *win, const QString &url, const QString &parameters, const QString &directory, const bool explore)
1519 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;
1523 * Query value of the performance counter
1525 __int64 lamexp_perfcounter_value(void)
1527 LARGE_INTEGER counter;
1528 if(QueryPerformanceCounter(&counter) == TRUE)
1530 return counter.QuadPart;
1532 return -1;
1536 * Query frequency of the performance counter
1538 __int64 lamexp_perfcounter_frequ(void)
1540 LARGE_INTEGER frequency;
1541 if(QueryPerformanceFrequency(&frequency) == TRUE)
1543 return frequency.QuadPart;
1545 return -1;
1549 * Insert entry to the window's system menu
1551 bool lamexp_append_sysmenu(const QWidget *win, const unsigned int identifier, const QString &text)
1553 bool ok = false;
1555 if(HMENU hMenu = GetSystemMenu(win->winId(), FALSE))
1557 ok = (AppendMenuW(hMenu, MF_SEPARATOR, 0, 0) == TRUE);
1558 ok = (AppendMenuW(hMenu, MF_STRING, identifier, QWCHAR(text)) == TRUE);
1561 return ok;
1565 * Insert entry to the window's system menu
1567 bool lamexp_check_sysmenu_msg(void *message, const unsigned int identifier)
1569 return (((MSG*)message)->message == WM_SYSCOMMAND) && ((((MSG*)message)->wParam & 0xFFF0) == identifier);
1573 * Update system menu entry
1575 bool lamexp_update_sysmenu(const QWidget *win, const unsigned int identifier, const QString &text)
1577 bool ok = false;
1579 if(HMENU hMenu = ::GetSystemMenu(win->winId(), FALSE))
1581 ok = (ModifyMenu(hMenu, identifier, MF_STRING | MF_BYCOMMAND, identifier, QWCHAR(text)) == TRUE);
1583 return ok;
1587 * Display the window's close button
1589 bool lamexp_enable_close_button(const QWidget *win, const bool bEnable)
1591 bool ok = false;
1593 if(HMENU hMenu = GetSystemMenu(win->winId(), FALSE))
1595 ok = (EnableMenuItem(hMenu, SC_CLOSE, MF_BYCOMMAND | (bEnable ? MF_ENABLED : MF_GRAYED)) == TRUE);
1598 return ok;
1602 * Check whether ESC key has been pressed since the previous call to this function
1604 bool lamexp_check_escape_state(void)
1606 return (GetAsyncKeyState(VK_ESCAPE) & 0x0001) != 0;
1610 * Set the process priority class for current process
1612 bool lamexp_change_process_priority(const int priority)
1614 return lamexp_change_process_priority(GetCurrentProcess(), priority);
1618 * Set the process priority class for specified process
1620 bool lamexp_change_process_priority(const QProcess *proc, const int priority)
1622 if(Q_PID qPid = proc->pid())
1624 return lamexp_change_process_priority(qPid->hProcess, priority);
1626 else
1628 return false;
1633 * Set the process priority class for specified process
1635 bool lamexp_change_process_priority(void *hProcess, const int priority)
1637 bool ok = false;
1639 switch(qBound(-2, priority, 2))
1641 case 2:
1642 ok = (SetPriorityClass(hProcess, HIGH_PRIORITY_CLASS) == TRUE);
1643 break;
1644 case 1:
1645 if(!(ok = (SetPriorityClass(hProcess, ABOVE_NORMAL_PRIORITY_CLASS) == TRUE)))
1647 ok = (SetPriorityClass(hProcess, HIGH_PRIORITY_CLASS) == TRUE);
1649 break;
1650 case 0:
1651 ok = (SetPriorityClass(hProcess, NORMAL_PRIORITY_CLASS) == TRUE);
1652 break;
1653 case -1:
1654 if(!(ok = (SetPriorityClass(hProcess, BELOW_NORMAL_PRIORITY_CLASS) == TRUE)))
1656 ok = (SetPriorityClass(hProcess, IDLE_PRIORITY_CLASS) == TRUE);
1658 break;
1659 case -2:
1660 ok = (SetPriorityClass(hProcess, IDLE_PRIORITY_CLASS) == TRUE);
1661 break;
1664 return ok;
1668 * Returns the current file time
1670 unsigned __int64 lamexp_current_file_time(void)
1672 FILETIME fileTime;
1673 GetSystemTimeAsFileTime(&fileTime);
1675 ULARGE_INTEGER temp;
1676 temp.HighPart = fileTime.dwHighDateTime;
1677 temp.LowPart = fileTime.dwLowDateTime;
1679 return temp.QuadPart;
1683 * Bring the specifed window to the front
1685 bool lamexp_bring_to_front(const QWidget *win)
1687 const bool ret = (SetForegroundWindow(win->winId()) == TRUE);
1688 SwitchToThisWindow(win->winId(), TRUE);
1689 return ret;
1693 * Bring window of the specifed process to the front (callback)
1695 static BOOL CALLBACK lamexp_bring_process_to_front_helper(HWND hwnd, LPARAM lParam)
1697 DWORD processId = *reinterpret_cast<WORD*>(lParam);
1698 DWORD windowProcessId = NULL;
1699 GetWindowThreadProcessId(hwnd, &windowProcessId);
1700 if(windowProcessId == processId)
1702 SwitchToThisWindow(hwnd, TRUE);
1703 SetForegroundWindow(hwnd);
1704 return FALSE;
1707 return TRUE;
1711 * Bring window of the specifed process to the front
1713 bool lamexp_bring_process_to_front(const unsigned long pid)
1715 return EnumWindows(lamexp_bring_process_to_front_helper, reinterpret_cast<LPARAM>(&pid)) == TRUE;
1719 * Check the network connection status
1721 int lamexp_network_status(void)
1723 DWORD dwFlags;
1724 const BOOL ret = (IsNetworkAlive(&dwFlags) == TRUE);
1725 if(GetLastError() == 0)
1727 return (ret == TRUE) ? lamexp_network_yes : lamexp_network_non;
1729 return lamexp_network_err;
1733 * Retrun the process ID of the given QProcess
1735 unsigned long lamexp_process_id(const QProcess *proc)
1737 PROCESS_INFORMATION *procInf = proc->pid();
1738 return (procInf) ? procInf->dwProcessId : NULL;
1742 * Convert long path to short path
1744 QString lamexp_path_to_short(const QString &longPath)
1746 QString shortPath;
1747 DWORD buffSize = GetShortPathNameW(reinterpret_cast<const wchar_t*>(longPath.utf16()), NULL, NULL);
1749 if(buffSize > 0)
1751 wchar_t *buffer = new wchar_t[buffSize];
1752 DWORD result = GetShortPathNameW(reinterpret_cast<const wchar_t*>(longPath.utf16()), buffer, buffSize);
1754 if(result > 0 && result < buffSize)
1756 shortPath = QString::fromUtf16(reinterpret_cast<const unsigned short*>(buffer));
1759 delete[] buffer;
1762 return (shortPath.isEmpty() ? longPath : shortPath);
1766 * Open media file in external player
1768 bool lamexp_open_media_file(const QString &mediaFilePath)
1770 const static wchar_t *registryPrefix[2] = { L"SOFTWARE\\", L"SOFTWARE\\Wow6432Node\\" };
1771 const static wchar_t *registryKeys[3] =
1773 L"Microsoft\\Windows\\CurrentVersion\\Uninstall\\{97D341C8-B0D1-4E4A-A49A-C30B52F168E9}",
1774 L"Microsoft\\Windows\\CurrentVersion\\Uninstall\\{DB9E4EAB-2717-499F-8D56-4CC8A644AB60}",
1775 L"foobar2000"
1777 const static wchar_t *appNames[4] = { L"smplayer_portable.exe", L"smplayer.exe", L"MPUI.exe", L"foobar2000.exe" };
1778 const static wchar_t *valueNames[2] = { L"InstallLocation", L"InstallDir" };
1780 for(size_t i = 0; i < 3; i++)
1782 for(size_t j = 0; j < 2; j++)
1784 QString mplayerPath;
1785 HKEY registryKeyHandle = NULL;
1787 const QString currentKey = WCHAR2QSTR(registryPrefix[j]).append(WCHAR2QSTR(registryKeys[i]));
1788 if(RegOpenKeyExW(HKEY_LOCAL_MACHINE, QWCHAR(currentKey), 0, KEY_READ, &registryKeyHandle) == ERROR_SUCCESS)
1790 for(size_t k = 0; k < 2; k++)
1792 wchar_t Buffer[4096];
1793 DWORD BuffSize = sizeof(wchar_t*) * 4096;
1794 DWORD DataType = REG_NONE;
1795 if(RegQueryValueExW(registryKeyHandle, valueNames[k], 0, &DataType, reinterpret_cast<BYTE*>(Buffer), &BuffSize) == ERROR_SUCCESS)
1797 if((DataType == REG_SZ) || (DataType == REG_EXPAND_SZ) || (DataType == REG_LINK))
1799 mplayerPath = WCHAR2QSTR(Buffer);
1800 break;
1804 RegCloseKey(registryKeyHandle);
1807 if(!mplayerPath.isEmpty())
1809 QDir mplayerDir(mplayerPath);
1810 if(mplayerDir.exists())
1812 for(size_t k = 0; k < 4; k++)
1814 if(mplayerDir.exists(WCHAR2QSTR(appNames[k])))
1816 qDebug("Player found at:\n%s\n", QUTF8(mplayerDir.absoluteFilePath(WCHAR2QSTR(appNames[k]))));
1817 QProcess::startDetached(mplayerDir.absoluteFilePath(WCHAR2QSTR(appNames[k])), QStringList() << QDir::toNativeSeparators(mediaFilePath));
1818 return true;
1825 return false;
1829 * Fatal application exit
1831 #pragma intrinsic(_InterlockedExchange)
1832 void lamexp_fatal_exit(const wchar_t* exitMessage, const wchar_t* errorBoxMessage)
1834 static volatile long bFatalFlag = 0L;
1836 if(_InterlockedExchange(&bFatalFlag, 1L) == 0L)
1838 if(GetCurrentThreadId() != g_main_thread_id)
1840 HANDLE mainThread = OpenThread(THREAD_TERMINATE, FALSE, g_main_thread_id);
1841 if(mainThread) TerminateThread(mainThread, ULONG_MAX);
1844 if(errorBoxMessage)
1846 MessageBoxW(NULL, errorBoxMessage, L"LameXP - GURU MEDITATION", MB_ICONERROR | MB_TOPMOST | MB_TASKMODAL);
1849 for(;;)
1851 FatalAppExit(0, exitMessage);
1852 TerminateProcess(GetCurrentProcess(), -1);
1856 TerminateThread(GetCurrentThread(), -1);
1857 Sleep(INFINITE);
1861 * Finalization function (final clean-up)
1863 void lamexp_finalization(void)
1865 qDebug("lamexp_finalization()");
1867 //Free all tools
1868 lamexp_clean_all_tools();
1870 //Delete temporary files
1871 const QString &tempFolder = lamexp_temp_folder2();
1872 if(!tempFolder.isEmpty())
1874 bool success = false;
1875 for(int i = 0; i < 100; i++)
1877 if(lamexp_clean_folder(tempFolder))
1879 success = true;
1880 break;
1882 lamexp_sleep(100);
1884 if(!success)
1886 MessageBoxW(NULL, L"Sorry, LameXP was unable to clean up all temporary files. Some residual files in your TEMP directory may require manual deletion!", L"LameXP", MB_ICONEXCLAMATION|MB_TOPMOST);
1887 lamexp_exec_shell(NULL, tempFolder, QString(), QString(), true);
1891 //Clear folder cache
1892 LAMEXP_DELETE(g_lamexp_known_folder.knownFolders);
1894 //Clear languages
1895 lamexp_clean_all_translations();
1897 //Destroy Qt application object
1898 QApplication *application = dynamic_cast<QApplication*>(QApplication::instance());
1899 LAMEXP_DELETE(application);
1901 //Detach from shared memory
1902 lamexp_ipc_exit();
1904 //Free STDOUT and STDERR buffers
1905 if(g_lamexp_console_attached)
1907 if(std::filebuf *tmp = dynamic_cast<std::filebuf*>(std::cout.rdbuf()))
1909 std::cout.rdbuf(NULL);
1910 LAMEXP_DELETE(tmp);
1912 if(std::filebuf *tmp = dynamic_cast<std::filebuf*>(std::cerr.rdbuf()))
1914 std::cerr.rdbuf(NULL);
1915 LAMEXP_DELETE(tmp);
1919 //Close log file
1920 if(g_lamexp_log_file)
1922 fclose(g_lamexp_log_file);
1923 g_lamexp_log_file = NULL;
1926 //Free CLI Arguments
1927 LAMEXP_DELETE(g_lamexp_argv.list);
1929 //Free TEMP folder
1930 lamexp_temp_folder_clear();
1934 * Initialize debug thread
1936 static const HANDLE g_debug_thread1 = LAMEXP_DEBUG ? NULL : lamexp_debug_thread_init();
1939 * Get number private bytes [debug only]
1941 unsigned long lamexp_dbg_private_bytes(void)
1943 #if LAMEXP_DEBUG
1944 for(int i = 0; i < 8; i++) _heapmin();
1945 PROCESS_MEMORY_COUNTERS_EX memoryCounters;
1946 memoryCounters.cb = sizeof(PROCESS_MEMORY_COUNTERS_EX);
1947 GetProcessMemoryInfo(GetCurrentProcess(), (PPROCESS_MEMORY_COUNTERS) &memoryCounters, sizeof(PROCESS_MEMORY_COUNTERS_EX));
1948 return memoryCounters.PrivateUsage;
1949 #else
1950 THROW("Cannot call this function in a non-debug build!");
1951 #endif //LAMEXP_DEBUG
1955 * Output string to debugger [debug only]
1957 void lamexp_dbg_dbg_output_string(const char* format, ...)
1959 #if LAMEXP_DEBUG
1960 char buffer[256];
1961 va_list args;
1962 va_start (args, format);
1963 vsnprintf_s(buffer, 256, _TRUNCATE, format, args);
1964 OutputDebugStringA(buffer);
1965 va_end(args);
1966 #else
1967 THROW("Cannot call this function in a non-debug build!");
1968 #endif //LAMEXP_DEBUG
1971 ///////////////////////////////////////////////////////////////////////////////
1972 // INITIALIZATION
1973 ///////////////////////////////////////////////////////////////////////////////
1975 extern "C" void _lamexp_global_init_win32(void)
1977 if((!LAMEXP_DEBUG) && lamexp_check_for_debugger())
1979 lamexp_fatal_exit(L"Not a debug build. Please unload debugger and try again!");
1982 //Zero *before* constructors are called
1983 LAMEXP_ZERO_MEMORY(g_lamexp_argv);
1984 LAMEXP_ZERO_MEMORY(g_lamexp_known_folder);
1985 LAMEXP_ZERO_MEMORY(g_lamexp_os_version);
1986 LAMEXP_ZERO_MEMORY(g_lamexp_wine);
1987 LAMEXP_ZERO_MEMORY(g_lamexp_themes_enabled);