OSDN Git Service

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