OSDN Git Service

Improved processing dialog + setup a proper "big" window icon for application windows...
[lamexp/LameXP.git] / src / Global_Win32.cpp
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.
10 //
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.
15 //
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.
19 //
20 // http://www.gnu.org/licenses/gpl-2.0.txt
21 ///////////////////////////////////////////////////////////////////////////////
22
23 #include "Global.h"
24
25 //Target version
26 #include "Targetver.h"
27
28 //Visual Leaks Detector
29 #include <vld.h>
30
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>
42
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 <QMutex>
55 #include <QPlastiqueStyle>
56 #include <QProcess>
57 #include <QReadWriteLock>
58 #include <QRegExp>
59 #include <QSysInfo>
60 #include <QTextCodec>
61 #include <QTimer>
62 #include <QTranslator>
63 #include <QUuid>
64
65 //LameXP includes
66 #define LAMEXP_INC_CONFIG
67 #include "Resource.h"
68 #include "Config.h"
69
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>
81
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
92
93 ///////////////////////////////////////////////////////////////////////////////
94 // HELPER MACROS
95 ///////////////////////////////////////////////////////////////////////////////
96
97 #define _LAMEXP_MAKE_STR(STR) #STR
98 #define LAMEXP_MAKE_STR(STR) _LAMEXP_MAKE_STR(STR)
99
100 //String helper
101 #define CLEAN_OUTPUT_STRING(STR) do \
102 { \
103         const char CTRL_CHARS[3] = { '\r', '\n', '\t' }; \
104         for(size_t i = 0; i < 3; i++) \
105         { \
106                 while(char *pos = strchr((STR), CTRL_CHARS[i])) *pos = char(0x20); \
107         } \
108 } \
109 while(0)
110
111 //String helper
112 #define TRIM_LEFT(STR) do \
113 { \
114         const char WHITE_SPACE[4] = { char(0x20), '\r', '\n', '\t' }; \
115         for(size_t i = 0; i < 4; i++) \
116         { \
117                 while(*(STR) == WHITE_SPACE[i]) (STR)++; \
118         } \
119 } \
120 while(0)
121
122 ///////////////////////////////////////////////////////////////////////////////
123 // GLOBAL VARS
124 ///////////////////////////////////////////////////////////////////////////////
125
126 //Console attached flag
127 static bool g_lamexp_console_attached = false;
128
129 //Special folders
130 static struct
131 {
132         QMap<size_t, QString> *knownFolders;
133         QReadWriteLock lock;
134 }
135 g_lamexp_known_folder;
136
137 //CLI Arguments
138 static struct
139 {
140         QStringList *list;
141         QReadWriteLock lock;
142 }
143 g_lamexp_argv;
144
145 //OS Version
146 static struct
147 {
148         bool bInitialized;
149         lamexp_os_version_t version;
150         QReadWriteLock lock;
151 }
152 g_lamexp_os_version;
153
154 //Wine detection
155 static struct
156 {
157         bool bInitialized;
158         bool bIsWine;
159         QReadWriteLock lock;
160 }
161 g_lamexp_wine;
162
163 //Win32 Theme support
164 static struct
165 {
166         bool bInitialized;
167         bool bThemesEnabled;
168         QReadWriteLock lock;
169 }
170 g_lamexp_themes_enabled;
171
172 //Win32 DWM API functions
173 static struct
174 {
175         bool bInitialized;
176         HRESULT (__stdcall *dwmIsCompositionEnabled)(BOOL *bEnabled);
177         HRESULT (__stdcall *dwmExtendFrameIntoClientArea)(HWND hWnd, const MARGINS* pMarInset);
178         HRESULT (__stdcall *dwmEnableBlurBehindWindow)(HWND hWnd, const DWM_BLURBEHIND* pBlurBehind);
179         QLibrary *dwmapi_dll;
180         QReadWriteLock lock;
181 }
182 g_lamexp_dwmapi;
183
184 //Image formats
185 static const char *g_lamexp_imageformats[] = {"bmp", "png", "jpg", "gif", "ico", "xpm", NULL}; //"svg"
186
187 //Global locks
188 static QMutex g_lamexp_message_mutex;
189
190 //Main thread ID
191 static const DWORD g_main_thread_id = GetCurrentThreadId();
192
193 //Log file
194 static FILE *g_lamexp_log_file = NULL;
195
196 //Localization
197 const char* LAMEXP_DEFAULT_LANGID = "en";
198 const char* LAMEXP_DEFAULT_TRANSLATION = "LameXP_EN.qm";
199
200 //Known Windows versions - maps marketing names to the actual Windows NT versions
201 const lamexp_os_version_t lamexp_winver_win2k = {5,0};
202 const lamexp_os_version_t lamexp_winver_winxp = {5,1};
203 const lamexp_os_version_t lamexp_winver_xpx64 = {5,2};
204 const lamexp_os_version_t lamexp_winver_vista = {6,0};
205 const lamexp_os_version_t lamexp_winver_win70 = {6,1};
206 const lamexp_os_version_t lamexp_winver_win80 = {6,2};
207 const lamexp_os_version_t lamexp_winver_win81 = {6,3};
208
209 //GURU MEDITATION
210 static const char *GURU_MEDITATION = "\n\nGURU MEDITATION !!!\n\n";
211
212 ///////////////////////////////////////////////////////////////////////////////
213 // GLOBAL FUNCTIONS
214 ///////////////////////////////////////////////////////////////////////////////
215
216 /*
217  * Verify a specific Windows version
218  */
219 static bool lamexp_verify_os_version(const DWORD major, const DWORD minor)
220 {
221         OSVERSIONINFOEXW osvi;
222         DWORDLONG dwlConditionMask = 0;
223
224         //Initialize the OSVERSIONINFOEX structure
225         memset(&osvi, 0, sizeof(OSVERSIONINFOEXW));
226         osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW);
227         osvi.dwMajorVersion = major;
228         osvi.dwMinorVersion = minor;
229         osvi.dwPlatformId = VER_PLATFORM_WIN32_NT;
230
231         //Initialize the condition mask
232         VER_SET_CONDITION(dwlConditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL);
233         VER_SET_CONDITION(dwlConditionMask, VER_MINORVERSION, VER_GREATER_EQUAL);
234         VER_SET_CONDITION(dwlConditionMask, VER_PLATFORMID, VER_EQUAL);
235
236         // Perform the test
237         const BOOL ret = VerifyVersionInfoW(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_PLATFORMID, dwlConditionMask);
238
239         //Error checking
240         if(!ret)
241         {
242                 if(GetLastError() != ERROR_OLD_WIN_VERSION)
243                 {
244                         qWarning("VerifyVersionInfo() system call has failed!");
245                 }
246         }
247
248         return (ret != FALSE);
249 }
250
251 /*
252  * Determine the *real* Windows version
253  */
254 static bool lamexp_get_real_os_version(unsigned int *major, unsigned int *minor, bool *pbOverride)
255 {
256         *major = *minor = 0;
257         *pbOverride = false;
258         
259         //Initialize local variables
260         OSVERSIONINFOEXW osvi;
261         memset(&osvi, 0, sizeof(OSVERSIONINFOEXW));
262         osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW);
263
264         //Try GetVersionEx() first
265         if(GetVersionExW((LPOSVERSIONINFOW)&osvi) == FALSE)
266         {
267                 qWarning("GetVersionEx() has failed, cannot detect Windows version!");
268                 return false;
269         }
270
271         //Make sure we are running on NT
272         if(osvi.dwPlatformId == VER_PLATFORM_WIN32_NT)
273         {
274                 *major = osvi.dwMajorVersion;
275                 *minor = osvi.dwMinorVersion;
276         }
277         else
278         {
279                 qWarning("Not running on Windows NT, unsupported operating system!");
280                 return false;
281         }
282
283         //Determine the real *major* version first
284         forever
285         {
286                 const DWORD nextMajor = (*major) + 1;
287                 if(lamexp_verify_os_version(nextMajor, 0))
288                 {
289                         *pbOverride = true;
290                         *major = nextMajor;
291                         *minor = 0;
292                         continue;
293                 }
294                 break;
295         }
296
297         //Now also determine the real *minor* version
298         forever
299         {
300                 const DWORD nextMinor = (*minor) + 1;
301                 if(lamexp_verify_os_version((*major), nextMinor))
302                 {
303                         *pbOverride = true;
304                         *minor = nextMinor;
305                         continue;
306                 }
307                 break;
308         }
309
310         return true;
311 }
312
313 /*
314  * Get the native operating system version
315  */
316 const lamexp_os_version_t &lamexp_get_os_version(void)
317 {
318         QReadLocker readLock(&g_lamexp_os_version.lock);
319
320         //Already initialized?
321         if(g_lamexp_os_version.bInitialized)
322         {
323                 return g_lamexp_os_version.version;
324         }
325         
326         readLock.unlock();
327         QWriteLocker writeLock(&g_lamexp_os_version.lock);
328
329         //Detect OS version
330         if(!g_lamexp_os_version.bInitialized)
331         {
332                 unsigned int major, minor; bool oflag;
333                 if(lamexp_get_real_os_version(&major, &minor, &oflag))
334                 {
335                         g_lamexp_os_version.version.versionMajor = major;
336                         g_lamexp_os_version.version.versionMinor = minor;
337                         g_lamexp_os_version.version.overrideFlag = oflag;
338                         g_lamexp_os_version.bInitialized = true;
339                 }
340                 else
341                 {
342                         qWarning("Failed to determin the operating system version!");
343                 }
344         }
345
346         return g_lamexp_os_version.version;
347 }
348
349 /*
350  * Check if we are running under wine
351  */
352 bool lamexp_detect_wine(void)
353 {
354         QReadLocker readLock(&g_lamexp_wine.lock);
355
356         //Already initialized?
357         if(g_lamexp_wine.bInitialized)
358         {
359                 return g_lamexp_wine.bIsWine;
360         }
361         
362         readLock.unlock();
363         QWriteLocker writeLock(&g_lamexp_wine.lock);
364
365         if(!g_lamexp_wine.bInitialized)
366         {
367                 g_lamexp_wine.bIsWine = false;
368                 QLibrary ntdll("ntdll.dll");
369                 if(ntdll.load())
370                 {
371                         if(ntdll.resolve("wine_nt_to_unix_file_name") != NULL) g_lamexp_wine.bIsWine = true;
372                         if(ntdll.resolve("wine_get_version") != NULL) g_lamexp_wine.bIsWine = true;
373                         ntdll.unload();
374                 }
375                 g_lamexp_wine.bInitialized = true;
376         }
377
378         return g_lamexp_wine.bIsWine;
379 }
380
381 /*
382  * Change console text color
383  */
384 static void lamexp_console_color(FILE* file, WORD attributes)
385 {
386         const HANDLE hConsole = (HANDLE)(_get_osfhandle(_fileno(file)));
387         if((hConsole != NULL) && (hConsole != INVALID_HANDLE_VALUE))
388         {
389                 SetConsoleTextAttribute(hConsole, attributes);
390         }
391 }
392
393 /*
394  * Output logging message to console
395  */
396 static void lamexp_write_console(const int type, const char *msg)
397 {       
398         __try
399         {
400                 if(_isatty(_fileno(stderr)))
401                 {
402                         UINT oldOutputCP = GetConsoleOutputCP();
403                         if(oldOutputCP != CP_UTF8) SetConsoleOutputCP(CP_UTF8);
404
405                         switch(type)
406                         {
407                         case QtCriticalMsg:
408                         case QtFatalMsg:
409                                 lamexp_console_color(stderr, FOREGROUND_RED | FOREGROUND_INTENSITY);
410                                 fprintf(stderr, GURU_MEDITATION);
411                                 fprintf(stderr, "%s\n", msg);
412                                 fflush(stderr);
413                                 break;
414                         case QtWarningMsg:
415                                 lamexp_console_color(stderr, FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY);
416                                 fprintf(stderr, "%s\n", msg);
417                                 fflush(stderr);
418                                 break;
419                         default:
420                                 lamexp_console_color(stderr, FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY);
421                                 fprintf(stderr, "%s\n", msg);
422                                 fflush(stderr);
423                                 break;
424                         }
425         
426                         lamexp_console_color(stderr, FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED);
427                         if(oldOutputCP != CP_UTF8) SetConsoleOutputCP(oldOutputCP);
428                 }
429         }
430         __except(1)
431         {
432                 /*ignore any exception that might occur here!*/
433         }
434 }
435
436 /*
437  * Output logging message to debugger
438  */
439 static void lamexp_write_dbg_out(const int type, const char *msg)
440 {       
441         const char *FORMAT = "[LameXP][%c] %s\n";
442
443         __try
444         {
445                 char buffer[512];
446                 const char* input = msg;
447                 TRIM_LEFT(input);
448                 
449                 switch(type)
450                 {
451                 case QtCriticalMsg:
452                 case QtFatalMsg:
453                         _snprintf_s(buffer, 512, _TRUNCATE, FORMAT, 'C', input);
454                         break;
455                 case QtWarningMsg:
456                         _snprintf_s(buffer, 512, _TRUNCATE, FORMAT, 'W', input);
457                         break;
458                 default:
459                         _snprintf_s(buffer, 512, _TRUNCATE, FORMAT, 'I', input);
460                         break;
461                 }
462
463                 char *temp = &buffer[0];
464                 CLEAN_OUTPUT_STRING(temp);
465                 OutputDebugStringA(temp);
466         }
467         __except(1)
468         {
469                 /*ignore any exception that might occur here!*/
470         }
471 }
472
473 /*
474  * Output logging message to logfile
475  */
476 static void lamexp_write_logfile(const int type, const char *msg)
477 {       
478         const char *FORMAT = "[%c][%04u] %s\r\n";
479
480         __try
481         {
482                 if(g_lamexp_log_file)
483                 {
484                         char buffer[512];
485                         strncpy_s(buffer, 512, msg, _TRUNCATE);
486
487                         char *temp = &buffer[0];
488                         TRIM_LEFT(temp);
489                         CLEAN_OUTPUT_STRING(temp);
490                         
491                         const unsigned int timestamp = static_cast<unsigned int>(_time64(NULL) % 3600I64);
492
493                         switch(type)
494                         {
495                         case QtCriticalMsg:
496                         case QtFatalMsg:
497                                 fprintf(g_lamexp_log_file, FORMAT, 'C', timestamp, temp);
498                                 break;
499                         case QtWarningMsg:
500                                 fprintf(g_lamexp_log_file, FORMAT, 'W', timestamp, temp);
501                                 break;
502                         default:
503                                 fprintf(g_lamexp_log_file, FORMAT, 'I', timestamp, temp);
504                                 break;
505                         }
506
507                         fflush(g_lamexp_log_file);
508                 }
509         }
510         __except(1)
511         {
512                 /*ignore any exception that might occur here!*/
513         }
514 }
515
516 /*
517  * Qt message handler
518  */
519 void lamexp_message_handler(QtMsgType type, const char *msg)
520 {
521         if((!msg) || (!(msg[0])))
522         {
523                 return;
524         }
525
526         QMutexLocker lock(&g_lamexp_message_mutex);
527
528         if(g_lamexp_log_file)
529         {
530                 lamexp_write_logfile(type, msg);
531         }
532
533         if(g_lamexp_console_attached)
534         {
535                 lamexp_write_console(type, msg);
536         }
537         else
538         {
539                 lamexp_write_dbg_out(type, msg);
540         }
541
542         if((type == QtCriticalMsg) || (type == QtFatalMsg))
543         {
544                 lock.unlock();
545                 lamexp_fatal_exit(L"The application has encountered a critical error and will exit now!", QWCHAR(QString::fromUtf8(msg)));
546         }
547 }
548
549 /*
550  * Invalid parameters handler
551  */
552 static void lamexp_invalid_param_handler(const wchar_t* exp, const wchar_t* fun, const wchar_t* fil, unsigned int, uintptr_t)
553 {
554         lamexp_fatal_exit(L"Invalid parameter handler invoked, application will exit!");
555 }
556
557 /*
558  * Signal handler
559  */
560 static void lamexp_signal_handler(int signal_num)
561 {
562         signal(signal_num, lamexp_signal_handler);
563         lamexp_fatal_exit(L"Signal handler invoked, application will exit!");
564 }
565
566 /*
567  * Global exception handler
568  */
569 static LONG WINAPI lamexp_exception_handler(struct _EXCEPTION_POINTERS *ExceptionInfo)
570 {
571         lamexp_fatal_exit(L"Unhandeled exception handler invoked, application will exit!");
572         return LONG_MAX;
573 }
574
575 /*
576  * Initialize error handlers
577  */
578 void lamexp_init_error_handlers(void)
579 {
580         SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
581         SetUnhandledExceptionFilter(lamexp_exception_handler);
582         SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
583         _set_invalid_parameter_handler(lamexp_invalid_param_handler);
584         
585         static const int signal_num[6] = { SIGABRT, SIGFPE, SIGILL, SIGINT, SIGSEGV, SIGTERM };
586
587         for(size_t i = 0; i < 6; i++)
588         {
589                 signal(signal_num[i], lamexp_signal_handler);
590         }
591 }
592
593 /*
594  * Initialize the console
595  */
596 void lamexp_init_console(const QStringList &argv)
597 {
598         bool enableConsole = (LAMEXP_DEBUG) || ((VER_LAMEXP_CONSOLE_ENABLED) && lamexp_version_demo());
599
600         if(_environ)
601         {
602                 wchar_t *logfile = NULL;
603                 size_t logfile_len = 0;
604                 if(!_wdupenv_s(&logfile, &logfile_len, L"LAMEXP_LOGFILE"))
605                 {
606                         if(logfile && (logfile_len > 0))
607                         {
608                                 FILE *temp = NULL;
609                                 if(!_wfopen_s(&temp, logfile, L"wb"))
610                                 {
611                                         fprintf(temp, "%c%c%c", char(0xEF), char(0xBB), char(0xBF));
612                                         g_lamexp_log_file = temp;
613                                 }
614                                 free(logfile);
615                         }
616                 }
617         }
618
619         if(!LAMEXP_DEBUG)
620         {
621                 for(int i = 0; i < argv.count(); i++)
622                 {
623                         if(!argv.at(i).compare("--console", Qt::CaseInsensitive))
624                         {
625                                 enableConsole = true;
626                         }
627                         else if(!argv.at(i).compare("--no-console", Qt::CaseInsensitive))
628                         {
629                                 enableConsole = false;
630                         }
631                 }
632         }
633
634         if(enableConsole)
635         {
636                 if(!g_lamexp_console_attached)
637                 {
638                         if(AllocConsole() != FALSE)
639                         {
640                                 SetConsoleCtrlHandler(NULL, TRUE);
641                                 SetConsoleTitle(L"LameXP - Audio Encoder Front-End | Debug Console");
642                                 SetConsoleOutputCP(CP_UTF8);
643                                 g_lamexp_console_attached = true;
644                         }
645                 }
646                 
647                 if(g_lamexp_console_attached)
648                 {
649                         //-------------------------------------------------------------------
650                         //See: http://support.microsoft.com/default.aspx?scid=kb;en-us;105305
651                         //-------------------------------------------------------------------
652                         const int flags = _O_WRONLY | _O_U8TEXT;
653                         int hCrtStdOut = _open_osfhandle((intptr_t) GetStdHandle(STD_OUTPUT_HANDLE), flags);
654                         int hCrtStdErr = _open_osfhandle((intptr_t) GetStdHandle(STD_ERROR_HANDLE),  flags);
655                         FILE *hfStdOut = (hCrtStdOut >= 0) ? _fdopen(hCrtStdOut, "wb") : NULL;
656                         FILE *hfStdErr = (hCrtStdErr >= 0) ? _fdopen(hCrtStdErr, "wb") : NULL;
657                         if(hfStdOut) { *stdout = *hfStdOut; std::cout.rdbuf(new std::filebuf(hfStdOut)); }
658                         if(hfStdErr) { *stderr = *hfStdErr; std::cerr.rdbuf(new std::filebuf(hfStdErr)); }
659                 }
660
661                 HWND hwndConsole = GetConsoleWindow();
662
663                 if((hwndConsole != NULL) && (hwndConsole != INVALID_HANDLE_VALUE))
664                 {
665                         HMENU hMenu = GetSystemMenu(hwndConsole, 0);
666                         EnableMenuItem(hMenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);
667                         RemoveMenu(hMenu, SC_CLOSE, MF_BYCOMMAND);
668
669                         SetWindowPos(hwndConsole, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_FRAMECHANGED);
670                         SetWindowLong(hwndConsole, GWL_STYLE, GetWindowLong(hwndConsole, GWL_STYLE) & (~WS_MAXIMIZEBOX) & (~WS_MINIMIZEBOX));
671                         SetWindowPos(hwndConsole, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_FRAMECHANGED);
672                 }
673         }
674 }
675
676 /*
677  * Detect CPU features
678  */
679 lamexp_cpu_t lamexp_detect_cpu_features(const QStringList &argv)
680 {
681         typedef BOOL (WINAPI *IsWow64ProcessFun)(__in HANDLE hProcess, __out PBOOL Wow64Process);
682
683         lamexp_cpu_t features;
684         SYSTEM_INFO systemInfo;
685         int CPUInfo[4] = {-1};
686         char CPUIdentificationString[0x40];
687         char CPUBrandString[0x40];
688
689         memset(&features, 0, sizeof(lamexp_cpu_t));
690         memset(&systemInfo, 0, sizeof(SYSTEM_INFO));
691         memset(CPUIdentificationString, 0, sizeof(CPUIdentificationString));
692         memset(CPUBrandString, 0, sizeof(CPUBrandString));
693         
694         __cpuid(CPUInfo, 0);
695         memcpy(CPUIdentificationString, &CPUInfo[1], sizeof(int));
696         memcpy(CPUIdentificationString + 4, &CPUInfo[3], sizeof(int));
697         memcpy(CPUIdentificationString + 8, &CPUInfo[2], sizeof(int));
698         features.intel = (_stricmp(CPUIdentificationString, "GenuineIntel") == 0);
699         strncpy_s(features.vendor, 0x40, CPUIdentificationString, _TRUNCATE);
700
701         if(CPUInfo[0] >= 1)
702         {
703                 __cpuid(CPUInfo, 1);
704                 features.mmx = (CPUInfo[3] & 0x800000) || false;
705                 features.sse = (CPUInfo[3] & 0x2000000) || false;
706                 features.sse2 = (CPUInfo[3] & 0x4000000) || false;
707                 features.ssse3 = (CPUInfo[2] & 0x200) || false;
708                 features.sse3 = (CPUInfo[2] & 0x1) || false;
709                 features.ssse3 = (CPUInfo[2] & 0x200) || false;
710                 features.stepping = CPUInfo[0] & 0xf;
711                 features.model = ((CPUInfo[0] >> 4) & 0xf) + (((CPUInfo[0] >> 16) & 0xf) << 4);
712                 features.family = ((CPUInfo[0] >> 8) & 0xf) + ((CPUInfo[0] >> 20) & 0xff);
713         }
714
715         __cpuid(CPUInfo, 0x80000000);
716         int nExIds = qMax<int>(qMin<int>(CPUInfo[0], 0x80000004), 0x80000000);
717
718         for(int i = 0x80000002; i <= nExIds; ++i)
719         {
720                 __cpuid(CPUInfo, i);
721                 switch(i)
722                 {
723                 case 0x80000002:
724                         memcpy(CPUBrandString, CPUInfo, sizeof(CPUInfo));
725                         break;
726                 case 0x80000003:
727                         memcpy(CPUBrandString + 16, CPUInfo, sizeof(CPUInfo));
728                         break;
729                 case 0x80000004:
730                         memcpy(CPUBrandString + 32, CPUInfo, sizeof(CPUInfo));
731                         break;
732                 }
733         }
734
735         strncpy_s(features.brand, 0x40, CPUBrandString, _TRUNCATE);
736
737         if(strlen(features.brand) < 1) strncpy_s(features.brand, 0x40, "Unknown", _TRUNCATE);
738         if(strlen(features.vendor) < 1) strncpy_s(features.vendor, 0x40, "Unknown", _TRUNCATE);
739
740 #if (!(defined(_M_X64) || defined(_M_IA64)))
741         QLibrary Kernel32Lib("kernel32.dll");
742         if(IsWow64ProcessFun IsWow64ProcessPtr = (IsWow64ProcessFun) Kernel32Lib.resolve("IsWow64Process"))
743         {
744                 BOOL x64flag = FALSE;
745                 if(IsWow64ProcessPtr(GetCurrentProcess(), &x64flag))
746                 {
747                         features.x64 = (x64flag == TRUE);
748                 }
749         }
750 #else
751         features.x64 = true;
752 #endif
753
754         DWORD_PTR procAffinity, sysAffinity;
755         if(GetProcessAffinityMask(GetCurrentProcess(), &procAffinity, &sysAffinity))
756         {
757                 for(DWORD_PTR mask = 1; mask; mask <<= 1)
758                 {
759                         features.count += ((sysAffinity & mask) ? (1) : (0));
760                 }
761         }
762         if(features.count < 1)
763         {
764                 GetNativeSystemInfo(&systemInfo);
765                 features.count = qBound(1UL, systemInfo.dwNumberOfProcessors, 64UL);
766         }
767
768         if(argv.count() > 0)
769         {
770                 bool flag = false;
771                 for(int i = 0; i < argv.count(); i++)
772                 {
773                         if(!argv[i].compare("--force-cpu-no-64bit", Qt::CaseInsensitive)) { flag = true; features.x64 = false; }
774                         if(!argv[i].compare("--force-cpu-no-sse", Qt::CaseInsensitive)) { flag = true; features.sse = features.sse2 = features.sse3 = features.ssse3 = false; }
775                         if(!argv[i].compare("--force-cpu-no-intel", Qt::CaseInsensitive)) { flag = true; features.intel = false; }
776                 }
777                 if(flag) qWarning("CPU flags overwritten by user-defined parameters. Take care!\n");
778         }
779
780         return features;
781 }
782
783 /*
784  * Check for debugger (detect routine)
785  */
786 static __forceinline bool lamexp_check_for_debugger(void)
787 {
788         __try
789         {
790                 CloseHandle((HANDLE)((DWORD_PTR)-3));
791         }
792         __except(1)
793         {
794                 return true;
795         }
796         __try 
797         {
798                 __debugbreak();
799         }
800         __except(1) 
801         {
802                 return IsDebuggerPresent();
803         }
804         return true;
805 }
806
807 /*
808  * Check for debugger (thread proc)
809  */
810 static unsigned int __stdcall lamexp_debug_thread_proc(LPVOID lpParameter)
811 {
812         SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_LOWEST);
813         forever
814         {
815                 if(lamexp_check_for_debugger())
816                 {
817                         lamexp_fatal_exit(L"Not a debug build. Please unload debugger and try again!");
818                         return 666;
819                 }
820                 lamexp_sleep(100);
821         }
822 }
823
824 /*
825  * Check for debugger (startup routine)
826  */
827 static HANDLE lamexp_debug_thread_init()
828 {
829         if(lamexp_check_for_debugger())
830         {
831                 lamexp_fatal_exit(L"Not a debug build. Please unload debugger and try again!");
832         }
833         const uintptr_t h = _beginthreadex(NULL, 0, lamexp_debug_thread_proc, NULL, 0, NULL);
834         return (HANDLE)(h^0xdeadbeef);
835 }
836
837 /*
838  * Qt event filter
839  */
840 static bool lamexp_event_filter(void *message, long *result)
841
842         if((!(LAMEXP_DEBUG)) && lamexp_check_for_debugger())
843         {
844                 lamexp_fatal_exit(L"Not a debug build. Please unload debugger and try again!");
845         }
846         
847         switch(reinterpret_cast<MSG*>(message)->message)
848         {
849         case WM_QUERYENDSESSION:
850                 qWarning("WM_QUERYENDSESSION message received!");
851                 *result = lamexp_broadcast(lamexp_event_queryendsession, false) ? TRUE : FALSE;
852                 return true;
853         case WM_ENDSESSION:
854                 qWarning("WM_ENDSESSION message received!");
855                 if(reinterpret_cast<MSG*>(message)->wParam == TRUE)
856                 {
857                         lamexp_broadcast(lamexp_event_endsession, false);
858                         if(QApplication *app = reinterpret_cast<QApplication*>(QApplication::instance()))
859                         {
860                                 app->closeAllWindows();
861                                 app->quit();
862                         }
863                         lamexp_finalization();
864                         exit(1);
865                 }
866                 *result = 0;
867                 return true;
868         default:
869                 /*ignore this message and let Qt handle it*/
870                 return false;
871         }
872 }
873
874 /*
875  * Check for process elevation
876  */
877 static bool lamexp_check_elevation(void)
878 {
879         typedef enum { lamexp_token_elevationType_class = 18, lamexp_token_elevation_class = 20 } LAMEXP_TOKEN_INFORMATION_CLASS;
880         typedef enum { lamexp_elevationType_default = 1, lamexp_elevationType_full, lamexp_elevationType_limited } LAMEXP_TOKEN_ELEVATION_TYPE;
881
882         HANDLE hToken = NULL;
883         bool bIsProcessElevated = false;
884         
885         if(OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
886         {
887                 LAMEXP_TOKEN_ELEVATION_TYPE tokenElevationType;
888                 DWORD returnLength;
889                 if(GetTokenInformation(hToken, (TOKEN_INFORMATION_CLASS) lamexp_token_elevationType_class, &tokenElevationType, sizeof(LAMEXP_TOKEN_ELEVATION_TYPE), &returnLength))
890                 {
891                         if(returnLength == sizeof(LAMEXP_TOKEN_ELEVATION_TYPE))
892                         {
893                                 switch(tokenElevationType)
894                                 {
895                                 case lamexp_elevationType_default:
896                                         qDebug("Process token elevation type: Default -> UAC is disabled.\n");
897                                         break;
898                                 case lamexp_elevationType_full:
899                                         qWarning("Process token elevation type: Full -> potential security risk!\n");
900                                         bIsProcessElevated = true;
901                                         break;
902                                 case lamexp_elevationType_limited:
903                                         qDebug("Process token elevation type: Limited -> not elevated.\n");
904                                         break;
905                                 }
906                         }
907                 }
908                 CloseHandle(hToken);
909         }
910         else
911         {
912                 qWarning("Failed to open process token!");
913         }
914
915         return !bIsProcessElevated;
916 }
917
918 /*
919  * Convert QIcon to HICON -> caller is responsible for destroying the HICON!
920  */
921 static HICON lamexp_qicon2hicon(const QIcon &icon, const int w, const int h)
922 {
923         if(!icon.isNull())
924         {
925                 QPixmap pixmap = icon.pixmap(w, h);
926                 if(!pixmap.isNull())
927                 {
928                         return pixmap.toWinHICON();
929                 }
930         }
931         return NULL;
932 }
933
934 /*
935  * Initialize Qt framework
936  */
937 bool lamexp_init_qt(int argc, char* argv[])
938 {
939         static bool qt_initialized = false;
940         typedef BOOL (WINAPI *SetDllDirectoryProc)(WCHAR *lpPathName);
941         const QStringList &arguments = lamexp_arguments();
942
943         //Don't initialized again, if done already
944         if(qt_initialized)
945         {
946                 return true;
947         }
948
949         //Secure DLL loading
950         QLibrary kernel32("kernel32.dll");
951         if(kernel32.load())
952         {
953                 SetDllDirectoryProc pSetDllDirectory = (SetDllDirectoryProc) kernel32.resolve("SetDllDirectoryW");
954                 if(pSetDllDirectory != NULL) pSetDllDirectory(L"");
955         }
956
957         //Extract executable name from argv[] array
958         QString executableName = QLatin1String("LameXP.exe");
959         if(arguments.count() > 0)
960         {
961                 static const char *delimiters = "\\/:?";
962                 executableName = arguments[0].trimmed();
963                 for(int i = 0; delimiters[i]; i++)
964                 {
965                         int temp = executableName.lastIndexOf(QChar(delimiters[i]));
966                         if(temp >= 0) executableName = executableName.mid(temp + 1);
967                 }
968                 executableName = executableName.trimmed();
969                 if(executableName.isEmpty())
970                 {
971                         executableName = QLatin1String("LameXP.exe");
972                 }
973         }
974
975         //Check Qt version
976 #ifdef QT_BUILD_KEY
977         qDebug("Using Qt v%s [%s], %s, %s", qVersion(), QLibraryInfo::buildDate().toString(Qt::ISODate).toLatin1().constData(), (qSharedBuild() ? "DLL" : "Static"), QLibraryInfo::buildKey().toLatin1().constData());
978         qDebug("Compiled with Qt v%s [%s], %s\n", QT_VERSION_STR, QT_PACKAGEDATE_STR, QT_BUILD_KEY);
979         if(_stricmp(qVersion(), QT_VERSION_STR))
980         {
981                 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());
982                 return false;
983         }
984         if(QLibraryInfo::buildKey().compare(QString::fromLatin1(QT_BUILD_KEY), Qt::CaseInsensitive))
985         {
986                 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());
987                 return false;
988         }
989 #else
990         qDebug("Using Qt v%s [%s], %s", qVersion(), QLibraryInfo::buildDate().toString(Qt::ISODate).toLatin1().constData(), (qSharedBuild() ? "DLL" : "Static"));
991         qDebug("Compiled with Qt v%s [%s]\n", QT_VERSION_STR, QT_PACKAGEDATE_STR);
992 #endif
993
994         //Check the Windows version
995         const lamexp_os_version_t &osVersionNo = lamexp_get_os_version();
996         if(osVersionNo < lamexp_winver_winxp)
997         {
998                 qFatal("%s", QApplication::tr("Executable '%1' requires Windows XP or later.").arg(executableName).toLatin1().constData());
999         }
1000
1001         //Supported Windows version?
1002         if(osVersionNo == lamexp_winver_winxp)
1003         {
1004                 qDebug("Running on Windows XP or Windows XP Media Center Edition.\n");                                          //lamexp_check_compatibility_mode("GetLargePageMinimum", executableName);
1005         }
1006         else if(osVersionNo == lamexp_winver_xpx64)
1007         {
1008                 qDebug("Running on Windows Server 2003, Windows Server 2003 R2 or Windows XP x64.\n");          //lamexp_check_compatibility_mode("GetLocaleInfoEx", executableName);
1009         }
1010         else if(osVersionNo == lamexp_winver_vista)
1011         {
1012                 qDebug("Running on Windows Vista or Windows Server 2008.\n");                                                           //lamexp_check_compatibility_mode("CreateRemoteThreadEx", executableName*/);
1013         }
1014         else if(osVersionNo == lamexp_winver_win70)
1015         {
1016                 qDebug("Running on Windows 7 or Windows Server 2008 R2.\n");                                                            //lamexp_check_compatibility_mode("CreateFile2", executableName);
1017         }
1018         else if(osVersionNo == lamexp_winver_win80)
1019         {
1020                 qDebug("Running on Windows 8 or Windows Server 2012.\n");                                                                       //lamexp_check_compatibility_mode("FindPackagesByPackageFamily", executableName);
1021         }
1022         else if(osVersionNo == lamexp_winver_win81)
1023         {
1024                 qDebug("Running on Windows 8.1 or Windows Server 2012 R2.\n");                                                          //lamexp_check_compatibility_mode(NULL, executableName);
1025         }
1026         else
1027         {
1028                 const QString message = QString().sprintf("Running on an unknown WindowsNT-based system (v%u.%u).", osVersionNo.versionMajor, osVersionNo.versionMinor);
1029                 qWarning("%s\n", QUTF8(message));
1030                 MessageBoxW(NULL, QWCHAR(message), L"LameXP", MB_OK | MB_TOPMOST | MB_ICONWARNING);
1031         }
1032
1033         //Check for compat mode
1034         if(osVersionNo.overrideFlag && (osVersionNo <= lamexp_winver_win81))
1035         {
1036                 qWarning("Windows compatibility mode detected!");
1037                 if(!arguments.contains("--ignore-compat-mode", Qt::CaseInsensitive))
1038                 {
1039                         qFatal("%s", QApplication::tr("Executable '%1' doesn't support Windows compatibility mode.").arg(executableName).toLatin1().constData());
1040                         return false;
1041                 }
1042         }
1043
1044         //Check for Wine
1045         if(lamexp_detect_wine())
1046         {
1047                 qWarning("It appears we are running under Wine, unexpected things might happen!\n");
1048         }
1049
1050         //Set text Codec for locale
1051         QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"));
1052
1053         //Create Qt application instance
1054         QApplication *application = new QApplication(argc, argv);
1055
1056         //Load plugins from application directory
1057         QCoreApplication::setLibraryPaths(QStringList() << QApplication::applicationDirPath());
1058         qDebug("Library Path:\n%s\n", QUTF8(QApplication::libraryPaths().first()));
1059
1060         //Set application properties
1061         application->setApplicationName("LameXP - Audio Encoder Front-End");
1062         application->setApplicationVersion(QString().sprintf("%d.%02d.%04d", lamexp_version_major(), lamexp_version_minor(), lamexp_version_build())); 
1063         application->setOrganizationName("LoRd_MuldeR");
1064         application->setOrganizationDomain("mulder.at.gg");
1065         application->setWindowIcon(lamexp_app_icon());
1066         application->setEventFilter(lamexp_event_filter);
1067
1068         //Check for supported image formats
1069         QList<QByteArray> supportedFormats = QImageReader::supportedImageFormats();
1070         for(int i = 0; g_lamexp_imageformats[i]; i++)
1071         {
1072                 if(!supportedFormats.contains(g_lamexp_imageformats[i]))
1073                 {
1074                         qFatal("Qt initialization error: QImageIOHandler for '%s' missing!", g_lamexp_imageformats[i]);
1075                         return false;
1076                 }
1077         }
1078         
1079         //Add the default translations
1080         lamexp_translation_init();
1081
1082         //Check for process elevation
1083         if((!lamexp_check_elevation()) && (!lamexp_detect_wine()))
1084         {
1085                 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);
1086                 messageBox.addButton("Quit Program (Recommended)", QMessageBox::NoRole);
1087                 messageBox.addButton("Ignore", QMessageBox::NoRole);
1088                 if(messageBox.exec() == 0)
1089                 {
1090                         return false;
1091                 }
1092         }
1093
1094         //Update console icon, if a console is attached
1095 #if QT_VERSION < QT_VERSION_CHECK(5,0,0)
1096         if(g_lamexp_console_attached && (!lamexp_detect_wine()))
1097         {
1098                 QLibrary kernel32("kernel32.dll");
1099                 if(kernel32.load())
1100                 {
1101                         typedef DWORD (__stdcall *SetConsoleIconFun)(HICON);
1102                         if(SetConsoleIconFun SetConsoleIconPtr = (SetConsoleIconFun) kernel32.resolve("SetConsoleIcon"))
1103                         {
1104                                 if(HICON hIcon = lamexp_qicon2hicon(QIcon(":/icons/sound.png"), 16, 16))
1105                                 {
1106                                         SetConsoleIconPtr(hIcon);
1107                                         DestroyIcon(hIcon);
1108                                 }
1109                         }
1110                 }
1111         }
1112 #endif
1113
1114         //Done
1115         qt_initialized = true;
1116         return true;
1117 }
1118
1119 const QStringList &lamexp_arguments(void)
1120 {
1121         QReadLocker readLock(&g_lamexp_argv.lock);
1122
1123         if(!g_lamexp_argv.list)
1124         {
1125                 readLock.unlock();
1126                 QWriteLocker writeLock(&g_lamexp_argv.lock);
1127
1128                 g_lamexp_argv.list = new QStringList;
1129
1130                 int nArgs = 0;
1131                 LPWSTR *szArglist = CommandLineToArgvW(GetCommandLineW(), &nArgs);
1132
1133                 if(NULL != szArglist)
1134                 {
1135                         for(int i = 0; i < nArgs; i++)
1136                         {
1137                                 (*g_lamexp_argv.list) << WCHAR2QSTR(szArglist[i]);
1138                         }
1139                         LocalFree(szArglist);
1140                 }
1141                 else
1142                 {
1143                         qWarning("CommandLineToArgvW() has failed !!!");
1144                 }
1145         }
1146
1147         return (*g_lamexp_argv.list);
1148 }
1149
1150 /*
1151  * Locate known folder on local system
1152  */
1153 const QString &lamexp_known_folder(lamexp_known_folder_t folder_id)
1154 {
1155         typedef HRESULT (WINAPI *SHGetKnownFolderPathFun)(__in const GUID &rfid, __in DWORD dwFlags, __in HANDLE hToken, __out PWSTR *ppszPath);
1156         typedef HRESULT (WINAPI *SHGetFolderPathFun)(__in HWND hwndOwner, __in int nFolder, __in HANDLE hToken, __in DWORD dwFlags, __out LPWSTR pszPath);
1157
1158         static const int CSIDL_LOCAL_APPDATA = 0x001c;
1159         static const int CSIDL_PROGRAM_FILES = 0x0026;
1160         static const int CSIDL_SYSTEM_FOLDER = 0x0025;
1161         static const GUID GUID_LOCAL_APPDATA = {0xF1B32785,0x6FBA,0x4FCF,{0x9D,0x55,0x7B,0x8E,0x7F,0x15,0x70,0x91}};
1162         static const GUID GUID_LOCAL_APPDATA_LOW = {0xA520A1A4,0x1780,0x4FF6,{0xBD,0x18,0x16,0x73,0x43,0xC5,0xAF,0x16}};
1163         static const GUID GUID_PROGRAM_FILES = {0x905e63b6,0xc1bf,0x494e,{0xb2,0x9c,0x65,0xb7,0x32,0xd3,0xd2,0x1a}};
1164         static const GUID GUID_SYSTEM_FOLDER = {0x1AC14E77,0x02E7,0x4E5D,{0xB7,0x44,0x2E,0xB1,0xAE,0x51,0x98,0xB7}};
1165
1166         QReadLocker readLock(&g_lamexp_known_folder.lock);
1167
1168         int folderCSIDL = -1;
1169         GUID folderGUID = {0x0000,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}};
1170         size_t folderCacheId = size_t(-1);
1171
1172         switch(folder_id)
1173         {
1174         case lamexp_folder_localappdata:
1175                 folderCacheId = 0;
1176                 folderCSIDL = CSIDL_LOCAL_APPDATA;
1177                 folderGUID = GUID_LOCAL_APPDATA;
1178                 break;
1179         case lamexp_folder_programfiles:
1180                 folderCacheId = 1;
1181                 folderCSIDL = CSIDL_PROGRAM_FILES;
1182                 folderGUID = GUID_PROGRAM_FILES;
1183                 break;
1184         case lamexp_folder_systemfolder:
1185                 folderCacheId = 2;
1186                 folderCSIDL = CSIDL_SYSTEM_FOLDER;
1187                 folderGUID = GUID_SYSTEM_FOLDER;
1188                 break;
1189         default:
1190                 qWarning("Invalid 'known' folder was requested!");
1191                 return *reinterpret_cast<QString*>(NULL);
1192                 break;
1193         }
1194
1195         //Already in cache?
1196         if(g_lamexp_known_folder.knownFolders)
1197         {
1198                 if(g_lamexp_known_folder.knownFolders->contains(folderCacheId))
1199                 {
1200                         return (*g_lamexp_known_folder.knownFolders)[folderCacheId];
1201                 }
1202         }
1203
1204         //Obtain write lock to initialize
1205         readLock.unlock();
1206         QWriteLocker writeLock(&g_lamexp_known_folder.lock);
1207
1208         //Still not in cache?
1209         if(g_lamexp_known_folder.knownFolders)
1210         {
1211                 if(g_lamexp_known_folder.knownFolders->contains(folderCacheId))
1212                 {
1213                         return (*g_lamexp_known_folder.knownFolders)[folderCacheId];
1214                 }
1215         }
1216
1217         static SHGetKnownFolderPathFun SHGetKnownFolderPathPtr = NULL;
1218         static SHGetFolderPathFun SHGetFolderPathPtr = NULL;
1219
1220         //Lookup functions
1221         if((!SHGetKnownFolderPathPtr) && (!SHGetFolderPathPtr))
1222         {
1223                 QLibrary kernel32Lib("shell32.dll");
1224                 if(kernel32Lib.load())
1225                 {
1226                         SHGetKnownFolderPathPtr = (SHGetKnownFolderPathFun) kernel32Lib.resolve("SHGetKnownFolderPath");
1227                         SHGetFolderPathPtr = (SHGetFolderPathFun) kernel32Lib.resolve("SHGetFolderPathW");
1228                 }
1229         }
1230
1231         QString folder;
1232
1233         //Now try to get the folder path!
1234         if(SHGetKnownFolderPathPtr)
1235         {
1236                 WCHAR *path = NULL;
1237                 if(SHGetKnownFolderPathPtr(folderGUID, 0x00008000, NULL, &path) == S_OK)
1238                 {
1239                         //MessageBoxW(0, path, L"SHGetKnownFolderPath", MB_TOPMOST);
1240                         QDir folderTemp = QDir(QDir::fromNativeSeparators(QString::fromUtf16(reinterpret_cast<const unsigned short*>(path))));
1241                         if(!folderTemp.exists())
1242                         {
1243                                 folderTemp.mkpath(".");
1244                         }
1245                         if(folderTemp.exists())
1246                         {
1247                                 folder = folderTemp.canonicalPath();
1248                         }
1249                         CoTaskMemFree(path);
1250                 }
1251         }
1252         else if(SHGetFolderPathPtr)
1253         {
1254                 WCHAR *path = new WCHAR[4096];
1255                 if(SHGetFolderPathPtr(NULL, folderCSIDL, NULL, NULL, path) == S_OK)
1256                 {
1257                         //MessageBoxW(0, path, L"SHGetFolderPathW", MB_TOPMOST);
1258                         QDir folderTemp = QDir(QDir::fromNativeSeparators(QString::fromUtf16(reinterpret_cast<const unsigned short*>(path))));
1259                         if(!folderTemp.exists())
1260                         {
1261                                 folderTemp.mkpath(".");
1262                         }
1263                         if(folderTemp.exists())
1264                         {
1265                                 folder = folderTemp.canonicalPath();
1266                         }
1267                 }
1268                 delete [] path;
1269         }
1270
1271         //Create cache
1272         if(!g_lamexp_known_folder.knownFolders)
1273         {
1274                 g_lamexp_known_folder.knownFolders = new QMap<size_t, QString>();
1275         }
1276
1277         //Update cache
1278         g_lamexp_known_folder.knownFolders->insert(folderCacheId, folder);
1279         return (*g_lamexp_known_folder.knownFolders)[folderCacheId];
1280 }
1281
1282 /*
1283  * Safely remove a file
1284  */
1285 bool lamexp_remove_file(const QString &filename)
1286 {
1287         if(!QFileInfo(filename).exists() || !QFileInfo(filename).isFile())
1288         {
1289                 return true;
1290         }
1291         else
1292         {
1293                 if(!QFile::remove(filename))
1294                 {
1295                         static const DWORD attrMask = FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM;
1296                         const DWORD attributes = GetFileAttributesW(QWCHAR(filename));
1297                         if(attributes & attrMask)
1298                         {
1299                                 SetFileAttributesW(QWCHAR(filename), FILE_ATTRIBUTE_NORMAL);
1300                         }
1301                         if(!QFile::remove(filename))
1302                         {
1303                                 qWarning("Could not delete \"%s\"", filename.toLatin1().constData());
1304                                 return false;
1305                         }
1306                         else
1307                         {
1308                                 return true;
1309                         }
1310                 }
1311                 else
1312                 {
1313                         return true;
1314                 }
1315         }
1316 }
1317
1318 /*
1319  * Check if visual themes are enabled (WinXP and later)
1320  */
1321 bool lamexp_themes_enabled(void)
1322 {
1323         typedef int (WINAPI *IsAppThemedFun)(void);
1324         
1325         QReadLocker readLock(&g_lamexp_themes_enabled.lock);
1326         if(g_lamexp_themes_enabled.bInitialized)
1327         {
1328                 return g_lamexp_themes_enabled.bThemesEnabled;
1329         }
1330
1331         readLock.unlock();
1332         QWriteLocker writeLock(&g_lamexp_themes_enabled.lock);
1333
1334         if(!g_lamexp_themes_enabled.bInitialized)
1335         {
1336                 g_lamexp_themes_enabled.bThemesEnabled = false;
1337                 const lamexp_os_version_t &osVersion = lamexp_get_os_version();
1338                 if(osVersion >= lamexp_winver_winxp)
1339                 {
1340                         IsAppThemedFun IsAppThemedPtr = NULL;
1341                         QLibrary uxTheme(QString("%1/UxTheme.dll").arg(lamexp_known_folder(lamexp_folder_systemfolder)));
1342                         if(uxTheme.load())
1343                         {
1344                                 IsAppThemedPtr = (IsAppThemedFun) uxTheme.resolve("IsAppThemed");
1345                         }
1346                         if(IsAppThemedPtr)
1347                         {
1348                                 g_lamexp_themes_enabled.bThemesEnabled = IsAppThemedPtr();
1349                                 if(!g_lamexp_themes_enabled.bThemesEnabled)
1350                                 {
1351                                         qWarning("Theme support is disabled for this process!");
1352                                 }
1353                         }
1354                 }
1355                 g_lamexp_themes_enabled.bInitialized = true;
1356         }
1357
1358         return g_lamexp_themes_enabled.bThemesEnabled;
1359 }
1360
1361 /*
1362  * Get number of free bytes on disk
1363  */
1364 unsigned __int64 lamexp_free_diskspace(const QString &path, bool *ok)
1365 {
1366         ULARGE_INTEGER freeBytesAvailable, totalNumberOfBytes, totalNumberOfFreeBytes;
1367         if(GetDiskFreeSpaceExW(reinterpret_cast<const wchar_t*>(QDir::toNativeSeparators(path).utf16()), &freeBytesAvailable, &totalNumberOfBytes, &totalNumberOfFreeBytes))
1368         {
1369                 if(ok) *ok = true;
1370                 return freeBytesAvailable.QuadPart;
1371         }
1372         else
1373         {
1374                 if(ok) *ok = false;
1375                 return 0;
1376         }
1377 }
1378
1379 /*
1380  * Check if computer does support hibernation
1381  */
1382 bool lamexp_is_hibernation_supported(void)
1383 {
1384         bool hibernationSupported = false;
1385
1386         SYSTEM_POWER_CAPABILITIES pwrCaps;
1387         SecureZeroMemory(&pwrCaps, sizeof(SYSTEM_POWER_CAPABILITIES));
1388         
1389         if(GetPwrCapabilities(&pwrCaps))
1390         {
1391                 hibernationSupported = pwrCaps.SystemS4 && pwrCaps.HiberFilePresent;
1392         }
1393
1394         return hibernationSupported;
1395 }
1396
1397 /*
1398  * Shutdown the computer
1399  */
1400 bool lamexp_shutdown_computer(const QString &message, const unsigned long timeout, const bool forceShutdown, const bool hibernate)
1401 {
1402         HANDLE hToken = NULL;
1403
1404         if(OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
1405         {
1406                 TOKEN_PRIVILEGES privileges;
1407                 memset(&privileges, 0, sizeof(TOKEN_PRIVILEGES));
1408                 privileges.PrivilegeCount = 1;
1409                 privileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
1410                 
1411                 if(LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &privileges.Privileges[0].Luid))
1412                 {
1413                         if(AdjustTokenPrivileges(hToken, FALSE, &privileges, NULL, NULL, NULL))
1414                         {
1415                                 if(hibernate)
1416                                 {
1417                                         if(SetSuspendState(TRUE, TRUE, TRUE))
1418                                         {
1419                                                 return true;
1420                                         }
1421                                 }
1422                                 const DWORD reason = SHTDN_REASON_MAJOR_APPLICATION | SHTDN_REASON_FLAG_PLANNED;
1423                                 return InitiateSystemShutdownEx(NULL, const_cast<wchar_t*>(QWCHAR(message)), timeout, forceShutdown ? TRUE : FALSE, FALSE, reason);
1424                         }
1425                 }
1426         }
1427         
1428         return false;
1429 }
1430
1431 /*
1432  * Determines the current date, resistant against certain manipulations
1433  */
1434 QDate lamexp_current_date_safe(void)
1435 {
1436         const DWORD MAX_PROC = 1024;
1437         DWORD *processes = new DWORD[MAX_PROC];
1438         DWORD bytesReturned = 0;
1439         
1440         if(!EnumProcesses(processes, sizeof(DWORD) * MAX_PROC, &bytesReturned))
1441         {
1442                 LAMEXP_DELETE_ARRAY(processes);
1443                 return QDate::currentDate();
1444         }
1445
1446         const DWORD procCount = bytesReturned / sizeof(DWORD);
1447         ULARGE_INTEGER lastStartTime;
1448         memset(&lastStartTime, 0, sizeof(ULARGE_INTEGER));
1449
1450         for(DWORD i = 0; i < procCount; i++)
1451         {
1452                 HANDLE hProc = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, processes[i]);
1453                 if(hProc)
1454                 {
1455                         FILETIME processTime[4];
1456                         if(GetProcessTimes(hProc, &processTime[0], &processTime[1], &processTime[2], &processTime[3]))
1457                         {
1458                                 ULARGE_INTEGER timeCreation;
1459                                 timeCreation.LowPart = processTime[0].dwLowDateTime;
1460                                 timeCreation.HighPart = processTime[0].dwHighDateTime;
1461                                 if(timeCreation.QuadPart > lastStartTime.QuadPart)
1462                                 {
1463                                         lastStartTime.QuadPart = timeCreation.QuadPart;
1464                                 }
1465                         }
1466                         CloseHandle(hProc);
1467                 }
1468         }
1469
1470         LAMEXP_DELETE_ARRAY(processes);
1471         
1472         FILETIME lastStartTime_fileTime;
1473         lastStartTime_fileTime.dwHighDateTime = lastStartTime.HighPart;
1474         lastStartTime_fileTime.dwLowDateTime = lastStartTime.LowPart;
1475
1476         FILETIME lastStartTime_localTime;
1477         if(!FileTimeToLocalFileTime(&lastStartTime_fileTime, &lastStartTime_localTime))
1478         {
1479                 memcpy(&lastStartTime_localTime, &lastStartTime_fileTime, sizeof(FILETIME));
1480         }
1481         
1482         SYSTEMTIME lastStartTime_system;
1483         if(!FileTimeToSystemTime(&lastStartTime_localTime, &lastStartTime_system))
1484         {
1485                 memset(&lastStartTime_system, 0, sizeof(SYSTEMTIME));
1486                 lastStartTime_system.wYear = 1970; lastStartTime_system.wMonth = lastStartTime_system.wDay = 1;
1487         }
1488
1489         const QDate currentDate = QDate::currentDate();
1490         const QDate processDate = QDate(lastStartTime_system.wYear, lastStartTime_system.wMonth, lastStartTime_system.wDay);
1491         return (currentDate >= processDate) ? currentDate : processDate;
1492 }
1493
1494 /*
1495  * Suspend calling thread for N milliseconds
1496  */
1497 inline void lamexp_sleep(const unsigned int delay)
1498 {
1499         Sleep(delay);
1500 }
1501
1502 bool lamexp_beep(int beepType)
1503 {
1504         switch(beepType)
1505         {
1506                 case lamexp_beep_info:    return MessageBeep(MB_ICONASTERISK) == TRUE;    break;
1507                 case lamexp_beep_warning: return MessageBeep(MB_ICONEXCLAMATION) == TRUE; break;
1508                 case lamexp_beep_error:   return MessageBeep(MB_ICONHAND) == TRUE;        break;
1509                 default: return false;
1510         }
1511 }
1512
1513 /*
1514  * Play a sound (from resources)
1515  */
1516 bool lamexp_play_sound(const unsigned short uiSoundIdx, const bool bAsync, const wchar_t *alias)
1517 {
1518         if(alias)
1519         {
1520                 return PlaySound(alias, GetModuleHandle(NULL), (SND_ALIAS | (bAsync ? SND_ASYNC : SND_SYNC))) == TRUE;
1521         }
1522         else
1523         {
1524                 return PlaySound(MAKEINTRESOURCE(uiSoundIdx), GetModuleHandle(NULL), (SND_RESOURCE | (bAsync ? SND_ASYNC : SND_SYNC))) == TRUE;
1525         }
1526 }
1527
1528 /*
1529  * Play a sound (from resources)
1530  */
1531 bool lamexp_play_sound_file(const QString &library, const unsigned short uiSoundIdx, const bool bAsync)
1532 {
1533         bool result = false;
1534         HMODULE module = NULL;
1535
1536         QFileInfo libraryFile(library);
1537         if(!libraryFile.isAbsolute())
1538         {
1539                 unsigned int buffSize = GetSystemDirectoryW(NULL, NULL) + 1;
1540                 wchar_t *buffer = (wchar_t*) _malloca(buffSize * sizeof(wchar_t));
1541                 unsigned int result = GetSystemDirectory(buffer, buffSize);
1542                 if(result > 0 && result < buffSize)
1543                 {
1544                         libraryFile.setFile(QString("%1/%2").arg(QDir::fromNativeSeparators(QString::fromUtf16(reinterpret_cast<const unsigned short*>(buffer))), library));
1545                 }
1546                 _freea(buffer);
1547         }
1548
1549         module = LoadLibraryW(QWCHAR(QDir::toNativeSeparators(libraryFile.absoluteFilePath())));
1550         if(module)
1551         {
1552                 result = (PlaySound(MAKEINTRESOURCE(uiSoundIdx), module, (SND_RESOURCE | (bAsync ? SND_ASYNC : SND_SYNC))) == TRUE);
1553                 FreeLibrary(module);
1554         }
1555
1556         return result;
1557 }
1558
1559 /*
1560  * Open file using the shell
1561  */
1562 bool lamexp_exec_shell(const QWidget *win, const QString &url, const bool explore)
1563 {
1564         return lamexp_exec_shell(win, url, QString(), QString(), explore);
1565 }
1566
1567 /*
1568  * Open file using the shell (with parameters)
1569  */
1570 bool lamexp_exec_shell(const QWidget *win, const QString &url, const QString &parameters, const QString &directory, const bool explore)
1571 {
1572         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;
1573 }
1574
1575         /*
1576  * Query value of the performance counter
1577  */
1578 __int64 lamexp_perfcounter_value(void)
1579 {
1580         LARGE_INTEGER counter;
1581         if(QueryPerformanceCounter(&counter) == TRUE)
1582         {
1583                 return counter.QuadPart;
1584         }
1585         return -1;
1586 }
1587
1588 /*
1589  * Query frequency of the performance counter
1590  */
1591 __int64 lamexp_perfcounter_frequ(void)
1592 {
1593         LARGE_INTEGER frequency;
1594         if(QueryPerformanceFrequency(&frequency) == TRUE)
1595         {
1596                 return frequency.QuadPart;
1597         }
1598         return -1;
1599 }
1600
1601 /*
1602  * Insert entry to the window's system menu
1603  */
1604 bool lamexp_append_sysmenu(const QWidget *win, const unsigned int identifier, const QString &text)
1605 {
1606         bool ok = false;
1607         
1608         if(HMENU hMenu = GetSystemMenu(win->winId(), FALSE))
1609         {
1610                 ok = (AppendMenuW(hMenu, MF_SEPARATOR, 0, 0) == TRUE);
1611                 ok = (AppendMenuW(hMenu, MF_STRING, identifier, QWCHAR(text)) == TRUE);
1612         }
1613
1614         return ok;
1615 }
1616
1617 /*
1618  * Insert entry to the window's system menu
1619  */
1620 bool lamexp_check_sysmenu_msg(void *message, const unsigned int identifier)
1621 {
1622         return (((MSG*)message)->message == WM_SYSCOMMAND) && ((((MSG*)message)->wParam & 0xFFF0) == identifier);
1623 }
1624
1625 /*
1626  * Update system menu entry
1627  */
1628 bool lamexp_update_sysmenu(const QWidget *win, const unsigned int identifier, const QString &text)
1629 {
1630         bool ok = false;
1631         
1632         if(HMENU hMenu = ::GetSystemMenu(win->winId(), FALSE))
1633         {
1634                 ok = (ModifyMenu(hMenu, identifier, MF_STRING | MF_BYCOMMAND, identifier, QWCHAR(text)) == TRUE);
1635         }
1636         return ok;
1637 }
1638
1639 /*
1640  * Display the window's close button
1641  */
1642 bool lamexp_enable_close_button(const QWidget *win, const bool bEnable)
1643 {
1644         bool ok = false;
1645
1646         if(HMENU hMenu = GetSystemMenu(win->winId(), FALSE))
1647         {
1648                 ok = (EnableMenuItem(hMenu, SC_CLOSE, MF_BYCOMMAND | (bEnable ? MF_ENABLED : MF_GRAYED)) == TRUE);
1649         }
1650
1651         return ok;
1652 }
1653
1654 /*
1655  * Check whether ESC key has been pressed since the previous call to this function
1656  */
1657 bool lamexp_check_escape_state(void)
1658 {
1659         return (GetAsyncKeyState(VK_ESCAPE) & 0x0001) != 0;
1660 }
1661
1662 /*
1663  * Set the process priority class for current process
1664  */
1665 bool lamexp_change_process_priority(const int priority)
1666 {
1667         return lamexp_change_process_priority(GetCurrentProcess(), priority);
1668 }
1669
1670 /*
1671  * Set the process priority class for specified process
1672  */
1673 bool lamexp_change_process_priority(const QProcess *proc, const int priority)
1674 {
1675         if(Q_PID qPid = proc->pid())
1676         {
1677                 return lamexp_change_process_priority(qPid->hProcess, priority);
1678         }
1679         else
1680         {
1681                 return false;
1682         }
1683 }
1684
1685 /*
1686  * Set the process priority class for specified process
1687  */
1688 bool lamexp_change_process_priority(void *hProcess, const int priority)
1689 {
1690         bool ok = false;
1691
1692         switch(qBound(-2, priority, 2))
1693         {
1694         case 2:
1695                 ok = (SetPriorityClass(hProcess, HIGH_PRIORITY_CLASS) == TRUE);
1696                 break;
1697         case 1:
1698                 if(!(ok = (SetPriorityClass(hProcess, ABOVE_NORMAL_PRIORITY_CLASS) == TRUE)))
1699                 {
1700                         ok = (SetPriorityClass(hProcess, HIGH_PRIORITY_CLASS) == TRUE);
1701                 }
1702                 break;
1703         case 0:
1704                 ok = (SetPriorityClass(hProcess, NORMAL_PRIORITY_CLASS) == TRUE);
1705                 break;
1706         case -1:
1707                 if(!(ok = (SetPriorityClass(hProcess, BELOW_NORMAL_PRIORITY_CLASS) == TRUE)))
1708                 {
1709                         ok = (SetPriorityClass(hProcess, IDLE_PRIORITY_CLASS) == TRUE);
1710                 }
1711                 break;
1712         case -2:
1713                 ok = (SetPriorityClass(hProcess, IDLE_PRIORITY_CLASS) == TRUE);
1714                 break;
1715         }
1716
1717         return ok;
1718 }
1719
1720 /*
1721  * Returns the current file time
1722  */
1723 unsigned __int64 lamexp_current_file_time(void)
1724 {
1725         FILETIME fileTime;
1726         GetSystemTimeAsFileTime(&fileTime);
1727
1728         ULARGE_INTEGER temp;
1729         temp.HighPart = fileTime.dwHighDateTime;
1730         temp.LowPart = fileTime.dwLowDateTime;
1731
1732         return temp.QuadPart;
1733 }
1734
1735 /*
1736  * Bring the specifed window to the front
1737  */
1738 bool lamexp_bring_to_front(const QWidget *win)
1739 {
1740         const bool ret = (SetForegroundWindow(win->winId()) == TRUE);
1741         SwitchToThisWindow(win->winId(), TRUE);
1742         return ret;
1743 }
1744
1745 /*
1746  * Bring window of the specifed process to the front (callback)
1747  */
1748 static BOOL CALLBACK lamexp_bring_process_to_front_helper(HWND hwnd, LPARAM lParam)
1749 {
1750         DWORD processId = *reinterpret_cast<WORD*>(lParam);
1751         DWORD windowProcessId = NULL;
1752         GetWindowThreadProcessId(hwnd, &windowProcessId);
1753         if(windowProcessId == processId)
1754         {
1755                 SwitchToThisWindow(hwnd, TRUE);
1756                 SetForegroundWindow(hwnd);
1757                 return FALSE;
1758         }
1759
1760         return TRUE;
1761 }
1762
1763 /*
1764  * Bring window of the specifed process to the front
1765  */
1766 bool lamexp_bring_process_to_front(const unsigned long pid)
1767 {
1768         return EnumWindows(lamexp_bring_process_to_front_helper, reinterpret_cast<LPARAM>(&pid)) == TRUE;
1769 }
1770
1771 /*
1772  * Check the network connection status
1773  */
1774 int lamexp_network_status(void)
1775 {
1776         DWORD dwFlags;
1777         const BOOL ret = (IsNetworkAlive(&dwFlags) == TRUE);
1778         if(GetLastError() == 0)
1779         {
1780                 return (ret == TRUE) ? lamexp_network_yes : lamexp_network_non;
1781         }
1782         return lamexp_network_err;
1783 }
1784
1785 /*
1786  * Retrun the process ID of the given QProcess
1787  */
1788 unsigned long lamexp_process_id(const QProcess *proc)
1789 {
1790         PROCESS_INFORMATION *procInf = proc->pid();
1791         return (procInf) ? procInf->dwProcessId : NULL;
1792 }
1793
1794 /*
1795  * Convert long path to short path
1796  */
1797 QString lamexp_path_to_short(const QString &longPath)
1798 {
1799         QString shortPath;
1800         DWORD buffSize = GetShortPathNameW(reinterpret_cast<const wchar_t*>(longPath.utf16()), NULL, NULL);
1801         
1802         if(buffSize > 0)
1803         {
1804                 wchar_t *buffer = new wchar_t[buffSize];
1805                 DWORD result = GetShortPathNameW(reinterpret_cast<const wchar_t*>(longPath.utf16()), buffer, buffSize);
1806
1807                 if(result > 0 && result < buffSize)
1808                 {
1809                         shortPath = QString::fromUtf16(reinterpret_cast<const unsigned short*>(buffer));
1810                 }
1811
1812                 delete[] buffer;
1813         }
1814
1815         return (shortPath.isEmpty() ? longPath : shortPath);
1816 }
1817
1818 /*
1819  * Open media file in external player
1820  */
1821 bool lamexp_open_media_file(const QString &mediaFilePath)
1822 {
1823         const static wchar_t *registryPrefix[2] = { L"SOFTWARE\\", L"SOFTWARE\\Wow6432Node\\" };
1824         const static wchar_t *registryKeys[3] = 
1825         {
1826                 L"Microsoft\\Windows\\CurrentVersion\\Uninstall\\{97D341C8-B0D1-4E4A-A49A-C30B52F168E9}",
1827                 L"Microsoft\\Windows\\CurrentVersion\\Uninstall\\{DB9E4EAB-2717-499F-8D56-4CC8A644AB60}",
1828                 L"foobar2000"
1829         };
1830         const static wchar_t *appNames[4] = { L"smplayer_portable.exe", L"smplayer.exe", L"MPUI.exe", L"foobar2000.exe" };
1831         const static wchar_t *valueNames[2] = { L"InstallLocation", L"InstallDir" };
1832
1833         for(size_t i = 0; i < 3; i++)
1834         {
1835                 for(size_t j = 0; j < 2; j++)
1836                 {
1837                         QString mplayerPath;
1838                         HKEY registryKeyHandle = NULL;
1839
1840                         const QString currentKey = WCHAR2QSTR(registryPrefix[j]).append(WCHAR2QSTR(registryKeys[i]));
1841                         if(RegOpenKeyExW(HKEY_LOCAL_MACHINE, QWCHAR(currentKey), 0, KEY_READ, &registryKeyHandle) == ERROR_SUCCESS)
1842                         {
1843                                 for(size_t k = 0; k < 2; k++)
1844                                 {
1845                                         wchar_t Buffer[4096];
1846                                         DWORD BuffSize = sizeof(wchar_t*) * 4096;
1847                                         DWORD DataType = REG_NONE;
1848                                         if(RegQueryValueExW(registryKeyHandle, valueNames[k], 0, &DataType, reinterpret_cast<BYTE*>(Buffer), &BuffSize) == ERROR_SUCCESS)
1849                                         {
1850                                                 if((DataType == REG_SZ) || (DataType == REG_EXPAND_SZ) || (DataType == REG_LINK))
1851                                                 {
1852                                                         mplayerPath = WCHAR2QSTR(Buffer);
1853                                                         break;
1854                                                 }
1855                                         }
1856                                 }
1857                                 RegCloseKey(registryKeyHandle);
1858                         }
1859
1860                         if(!mplayerPath.isEmpty())
1861                         {
1862                                 QDir mplayerDir(mplayerPath);
1863                                 if(mplayerDir.exists())
1864                                 {
1865                                         for(size_t k = 0; k < 4; k++)
1866                                         {
1867                                                 if(mplayerDir.exists(WCHAR2QSTR(appNames[k])))
1868                                                 {
1869                                                         qDebug("Player found at:\n%s\n", QUTF8(mplayerDir.absoluteFilePath(WCHAR2QSTR(appNames[k]))));
1870                                                         QProcess::startDetached(mplayerDir.absoluteFilePath(WCHAR2QSTR(appNames[k])), QStringList() << QDir::toNativeSeparators(mediaFilePath));
1871                                                         return true;
1872                                                 }
1873                                         }
1874                                 }
1875                         }
1876                 }
1877         }
1878         return false;
1879 }
1880
1881 static void lamexp_init_dwmapi(void)
1882 {
1883         QReadLocker writeLock(&g_lamexp_dwmapi.lock);
1884
1885         //Not initialized yet?
1886         if(g_lamexp_dwmapi.bInitialized)
1887         {
1888                 return;
1889         }
1890         
1891         //Reset function pointers
1892         g_lamexp_dwmapi.dwmIsCompositionEnabled = NULL;
1893         g_lamexp_dwmapi.dwmExtendFrameIntoClientArea = NULL;
1894         g_lamexp_dwmapi.dwmEnableBlurBehindWindow = NULL;
1895                         
1896         //Does OS support DWM?
1897         if(lamexp_get_os_version() >= lamexp_winver_vista)
1898         {
1899                 //Load DWMAPI.DLL
1900                 g_lamexp_dwmapi.dwmapi_dll = new QLibrary("dwmapi.dll");
1901                 if(g_lamexp_dwmapi.dwmapi_dll->load())
1902                 {
1903                         //Initialize function pointers
1904                         g_lamexp_dwmapi.dwmIsCompositionEnabled      = (HRESULT (__stdcall*)(BOOL*))                       g_lamexp_dwmapi.dwmapi_dll->resolve("DwmIsCompositionEnabled");
1905                         g_lamexp_dwmapi.dwmExtendFrameIntoClientArea = (HRESULT (__stdcall*)(HWND, const MARGINS*))        g_lamexp_dwmapi.dwmapi_dll->resolve("DwmExtendFrameIntoClientArea");
1906                         g_lamexp_dwmapi.dwmEnableBlurBehindWindow    = (HRESULT (__stdcall*)(HWND, const DWM_BLURBEHIND*)) g_lamexp_dwmapi.dwmapi_dll->resolve("DwmEnableBlurBehindWindow");
1907                 }
1908                 else
1909                 {
1910                         LAMEXP_DELETE(g_lamexp_dwmapi.dwmapi_dll);
1911                         qWarning("Failed to load DWMAPI.DLL on a DWM-enabled system!");
1912                 }
1913         }
1914
1915         g_lamexp_dwmapi.bInitialized = true;
1916 }
1917
1918 /*
1919  * Enable "sheet of glass" effect on the given Window
1920  */
1921 bool lamexp_sheet_of_glass(QWidget *window)
1922 {
1923         QReadLocker readLock(&g_lamexp_dwmapi.lock);
1924
1925         //Initialize the DWM API
1926         while(!g_lamexp_dwmapi.bInitialized)
1927         {
1928                 readLock.unlock();
1929                 lamexp_init_dwmapi();
1930                 readLock.relock();
1931         }
1932
1933         BOOL bCompositionEnabled = FALSE;
1934
1935         //Required functions available?
1936         if((g_lamexp_dwmapi.dwmIsCompositionEnabled != NULL) && (g_lamexp_dwmapi.dwmExtendFrameIntoClientArea != NULL) && (g_lamexp_dwmapi.dwmEnableBlurBehindWindow != NULL))
1937         {
1938                 //Check if composition is currently enabled
1939                 if(HRESULT hr = g_lamexp_dwmapi.dwmIsCompositionEnabled(&bCompositionEnabled))
1940                 {
1941                         qWarning("DwmIsCompositionEnabled function has failed! (error %d)", hr);
1942                         return false;
1943                 }
1944         }
1945         
1946         //All functions available *and* composition enabled?
1947         if(!bCompositionEnabled)
1948         {
1949                 return false;
1950         }
1951
1952         //Enable the "sheet of glass" effect on this window
1953         MARGINS margins = {-1, -1, -1, -1};
1954         if(HRESULT hr = g_lamexp_dwmapi.dwmExtendFrameIntoClientArea(window->winId(), &margins))
1955         {
1956                 qWarning("DwmExtendFrameIntoClientArea function has failed! (error %d)", hr);
1957                 return false;
1958         }
1959
1960         //Create and populate the Blur Behind structure
1961         DWM_BLURBEHIND bb;
1962         memset(&bb, 0, sizeof(DWM_BLURBEHIND));
1963         bb.fEnable = TRUE;
1964         bb.dwFlags = DWM_BB_ENABLE;
1965         if(HRESULT hr = g_lamexp_dwmapi.dwmEnableBlurBehindWindow(window->winId(), &bb))
1966         {
1967                 qWarning("DwmEnableBlurBehindWindow function has failed! (error %d)", hr);
1968                 return false;
1969         }
1970
1971         //Required for Qt
1972         window->setAutoFillBackground(false);
1973         window->setAttribute(Qt::WA_TranslucentBackground);
1974         window->setAttribute(Qt::WA_NoSystemBackground);
1975
1976         return true;
1977 }
1978
1979 /*
1980  * Update "sheet of glass" effect on the given Window
1981  */
1982 bool lamexp_sheet_of_glass_update(QWidget *window)
1983 {
1984         QReadLocker readLock(&g_lamexp_dwmapi.lock);
1985
1986         //Initialize the DWM API
1987         while(!g_lamexp_dwmapi.bInitialized)
1988         {
1989                 readLock.unlock();
1990                 lamexp_init_dwmapi();
1991                 readLock.relock();
1992         }
1993
1994         BOOL bCompositionEnabled = FALSE;
1995
1996         //Required functions available?
1997         if((g_lamexp_dwmapi.dwmIsCompositionEnabled != NULL) && (g_lamexp_dwmapi.dwmEnableBlurBehindWindow != NULL))
1998         {
1999                 //Check if composition is currently enabled
2000                 if(HRESULT hr = g_lamexp_dwmapi.dwmIsCompositionEnabled(&bCompositionEnabled))
2001                 {
2002                         qWarning("DwmIsCompositionEnabled function has failed! (error %d)", hr);
2003                         return false;
2004                 }
2005         }
2006         
2007         //All functions available *and* composition enabled?
2008         if(!bCompositionEnabled)
2009         {
2010                 return false;
2011         }
2012
2013         //Create and populate the Blur Behind structure
2014         DWM_BLURBEHIND bb;
2015         memset(&bb, 0, sizeof(DWM_BLURBEHIND));
2016         bb.fEnable = TRUE;
2017         bb.dwFlags = DWM_BB_ENABLE;
2018         if(HRESULT hr = g_lamexp_dwmapi.dwmEnableBlurBehindWindow(window->winId(), &bb))
2019         {
2020                 qWarning("DwmEnableBlurBehindWindow function has failed! (error %d)", hr);
2021                 return false;
2022         }
2023
2024         return true;
2025 }
2026
2027 /*
2028  * Update the window icon
2029  */
2030 bool lamexp_set_window_icon(QWidget *window, const QIcon &icon, const bool bIsBigIcon)
2031 {
2032         if(!icon.isNull())
2033         {
2034                 const int extend = (bIsBigIcon ? 32 : 16);
2035                 if(HICON hIcon = lamexp_qicon2hicon(icon, extend, extend))
2036                 {
2037                         SendMessage(window->winId(), WM_SETICON, (bIsBigIcon ? ICON_BIG : ICON_SMALL), LPARAM(hIcon));
2038                         //DestroyIcon(hIcon); /*FIXME: Destroying the icon here will remove it from the window*/
2039                 }
2040                 return true;
2041         }
2042         return false;
2043 }
2044
2045 /*
2046  * Get system color info
2047  */
2048 QColor lamexp_system_color(const int color_id)
2049 {
2050         int nIndex = -1;
2051
2052         switch(color_id)
2053         {
2054         case lamexp_syscolor_text:
2055                 nIndex = COLOR_WINDOWTEXT;       /*Text in windows*/
2056                 break;
2057         case lamexp_syscolor_background:
2058                 nIndex = COLOR_WINDOW;           /*Window background*/
2059                 break;
2060         case lamexp_syscolor_caption:
2061                 nIndex = COLOR_CAPTIONTEXT;      /*Text in caption, size box, and scroll bar arrow box*/
2062                 break;
2063         default:
2064                 qWarning("Unknown system color id (%d) specified!", color_id);
2065                 nIndex = COLOR_WINDOWTEXT;
2066         }
2067         
2068         const DWORD rgb = GetSysColor(nIndex);
2069         QColor color(GetRValue(rgb), GetGValue(rgb), GetBValue(rgb));
2070         return color;
2071 }
2072
2073 /*
2074  * Fatal application exit
2075  */
2076 #pragma intrinsic(_InterlockedExchange)
2077 void lamexp_fatal_exit(const wchar_t* exitMessage, const wchar_t* errorBoxMessage)
2078 {
2079         static volatile long bFatalFlag = 0L;
2080
2081         if(_InterlockedExchange(&bFatalFlag, 1L) == 0L)
2082         {
2083                 if(GetCurrentThreadId() != g_main_thread_id)
2084                 {
2085                         HANDLE mainThread = OpenThread(THREAD_TERMINATE, FALSE, g_main_thread_id);
2086                         if(mainThread) TerminateThread(mainThread, ULONG_MAX);
2087                 }
2088         
2089                 if(errorBoxMessage)
2090                 {
2091                         MessageBoxW(NULL, errorBoxMessage, L"LameXP - GURU MEDITATION", MB_ICONERROR | MB_TOPMOST | MB_TASKMODAL);
2092                 }
2093
2094                 for(;;)
2095                 {
2096                         FatalAppExit(0, exitMessage);
2097                         TerminateProcess(GetCurrentProcess(), -1);
2098                 }
2099         }
2100
2101         TerminateThread(GetCurrentThread(), -1);
2102         Sleep(INFINITE);
2103 }
2104
2105 /*
2106  * Finalization function (final clean-up)
2107  */
2108 void lamexp_finalization(void)
2109 {
2110         qDebug("lamexp_finalization()");
2111         
2112         //Free all tools
2113         lamexp_clean_all_tools();
2114         
2115         //Delete temporary files
2116         const QString &tempFolder = lamexp_temp_folder2();
2117         if(!tempFolder.isEmpty())
2118         {
2119                 bool success = false;
2120                 for(int i = 0; i < 100; i++)
2121                 {
2122                         if(lamexp_clean_folder(tempFolder))
2123                         {
2124                                 success = true;
2125                                 break;
2126                         }
2127                         lamexp_sleep(100);
2128                 }
2129                 if(!success)
2130                 {
2131                         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);
2132                         lamexp_exec_shell(NULL, tempFolder, QString(), QString(), true);
2133                 }
2134         }
2135
2136         //Clear folder cache
2137         LAMEXP_DELETE(g_lamexp_known_folder.knownFolders);
2138
2139         //Clear languages
2140         lamexp_clean_all_translations();
2141
2142         //Destroy Qt application object
2143         QApplication *application = dynamic_cast<QApplication*>(QApplication::instance());
2144         LAMEXP_DELETE(application);
2145
2146         //Release DWM API
2147         g_lamexp_dwmapi.dwmIsCompositionEnabled = NULL;
2148         g_lamexp_dwmapi.dwmExtendFrameIntoClientArea = NULL;
2149         g_lamexp_dwmapi.dwmEnableBlurBehindWindow = NULL;
2150         LAMEXP_DELETE(g_lamexp_dwmapi.dwmapi_dll);
2151
2152         //Detach from shared memory
2153         lamexp_ipc_exit();
2154
2155         //Free STDOUT and STDERR buffers
2156         if(g_lamexp_console_attached)
2157         {
2158                 if(std::filebuf *tmp = dynamic_cast<std::filebuf*>(std::cout.rdbuf()))
2159                 {
2160                         std::cout.rdbuf(NULL);
2161                         LAMEXP_DELETE(tmp);
2162                 }
2163                 if(std::filebuf *tmp = dynamic_cast<std::filebuf*>(std::cerr.rdbuf()))
2164                 {
2165                         std::cerr.rdbuf(NULL);
2166                         LAMEXP_DELETE(tmp);
2167                 }
2168         }
2169
2170         //Close log file
2171         if(g_lamexp_log_file)
2172         {
2173                 fclose(g_lamexp_log_file);
2174                 g_lamexp_log_file = NULL;
2175         }
2176
2177         //Free CLI Arguments
2178         LAMEXP_DELETE(g_lamexp_argv.list);
2179
2180         //Free TEMP folder
2181         lamexp_temp_folder_clear();
2182 }
2183
2184 /*
2185  * Initialize debug thread
2186  */
2187 static const HANDLE g_debug_thread1 = LAMEXP_DEBUG ? NULL : lamexp_debug_thread_init();
2188
2189 /*
2190  * Get number private bytes [debug only]
2191  */
2192 unsigned long lamexp_dbg_private_bytes(void)
2193 {
2194 #if LAMEXP_DEBUG
2195         for(int i = 0; i < 8; i++) _heapmin();
2196         PROCESS_MEMORY_COUNTERS_EX memoryCounters;
2197         memoryCounters.cb = sizeof(PROCESS_MEMORY_COUNTERS_EX);
2198         GetProcessMemoryInfo(GetCurrentProcess(), (PPROCESS_MEMORY_COUNTERS) &memoryCounters, sizeof(PROCESS_MEMORY_COUNTERS_EX));
2199         return memoryCounters.PrivateUsage;
2200 #else
2201         THROW("Cannot call this function in a non-debug build!");
2202 #endif //LAMEXP_DEBUG
2203 }
2204
2205 /*
2206  * Output string to debugger [debug only]
2207  */
2208 void lamexp_dbg_dbg_output_string(const char* format, ...)
2209 {
2210 #if LAMEXP_DEBUG
2211         char buffer[256];
2212         va_list args;
2213         va_start (args, format);
2214         vsnprintf_s(buffer, 256, _TRUNCATE, format, args);
2215         OutputDebugStringA(buffer);
2216         va_end(args);
2217 #else
2218         THROW("Cannot call this function in a non-debug build!");
2219 #endif //LAMEXP_DEBUG
2220 }
2221
2222 ///////////////////////////////////////////////////////////////////////////////
2223 // INITIALIZATION
2224 ///////////////////////////////////////////////////////////////////////////////
2225
2226 extern "C" void _lamexp_global_init_win32(void)
2227 {
2228         if((!LAMEXP_DEBUG) && lamexp_check_for_debugger())
2229         {
2230                 lamexp_fatal_exit(L"Not a debug build. Please unload debugger and try again!");
2231         }
2232
2233         //Zero *before* constructors are called
2234         LAMEXP_ZERO_MEMORY(g_lamexp_argv);
2235         LAMEXP_ZERO_MEMORY(g_lamexp_known_folder);
2236         LAMEXP_ZERO_MEMORY(g_lamexp_os_version);
2237         LAMEXP_ZERO_MEMORY(g_lamexp_wine);
2238         LAMEXP_ZERO_MEMORY(g_lamexp_themes_enabled);
2239         LAMEXP_ZERO_MEMORY(g_lamexp_dwmapi);
2240 }