OSDN Git Service

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