OSDN Git Service

9da66d0348016ac7190dd4b4f414600d53ed2bee
[x264-launcher/x264-launcher.git] / src / global.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Simple x264 Launcher
3 // Copyright (C) 2004-2014 LoRd_MuldeR <MuldeR2@GMX.de>
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 2 of the License, or
8 // (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License along
16 // with this program; if not, write to the Free Software Foundation, Inc.,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 //
19 // http://www.gnu.org/licenses/gpl-2.0.txt
20 ///////////////////////////////////////////////////////////////////////////////
21
22 //x264 includes
23 #include "global.h"
24 #include "targetver.h"
25
26 //Windows includes
27 #define NOMINMAX
28 #define WIN32_LEAN_AND_MEAN
29 #include <Windows.h>
30 #include <MMSystem.h>
31 #include <ShellAPI.h>
32 #include <Objbase.h>
33 #include <Psapi.h>
34 #include <SensAPI.h>
35
36 //C++ includes
37 #include <stdio.h>
38 #include <string.h>
39 #include <iostream>
40 #include <time.h>
41
42 //VLD
43 #include <vld.h>
44
45 //Version
46 #define ENABLE_X264_VERSION_INCLUDE
47 #include "version.h"
48 #undef  ENABLE_X264_VERSION_INCLUDE
49
50 //Qt includes
51 #include <QApplication>
52 #include <QMessageBox>
53 #include <QDir>
54 #include <QUuid>
55 #include <QMap>
56 #include <QDate>
57 #include <QIcon>
58 #include <QPlastiqueStyle>
59 #include <QImageReader>
60 #include <QSharedMemory>
61 #include <QSysInfo>
62 #include <QStringList>
63 #include <QSystemSemaphore>
64 #include <QDesktopServices>
65 #include <QMutex>
66 #include <QTextCodec>
67 #include <QLibrary>
68 #include <QRegExp>
69 #include <QResource>
70 #include <QTranslator>
71 #include <QEventLoop>
72 #include <QTimer>
73 #include <QLibraryInfo>
74 #include <QEvent>
75 #include <QReadLocker>
76 #include <QWriteLocker>
77 #include <QProcess>
78
79 //CRT includes
80 #include <fstream>
81 #include <io.h>
82 #include <fcntl.h>
83 #include <intrin.h>
84 #include <process.h>
85
86 //Debug only includes
87 #if X264_DEBUG
88 #include <Psapi.h>
89 #endif
90
91 //Global types
92 typedef HRESULT (WINAPI *SHGetKnownFolderPath_t)(const GUID &rfid, DWORD dwFlags, HANDLE hToken, PWSTR *ppszPath);
93 typedef HRESULT (WINAPI *SHGetFolderPath_t)(HWND hwndOwner, int nFolder, HANDLE hToken, DWORD dwFlags, LPWSTR pszPath);
94
95 //Global vars
96 static bool g_x264_console_attached = false;
97 static QMutex g_x264_message_mutex;
98 static const DWORD g_main_thread_id = GetCurrentThreadId();
99 static FILE *g_x264_log_file = NULL;
100 static QDate g_x264_version_date;
101
102 //Const
103 static const char *g_x264_months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
104 static const char *g_x264_imageformats[] = {"png", "jpg", "gif", "ico", "svg", NULL};
105
106 //Build version
107 static const struct
108 {
109         unsigned int ver_major;
110         unsigned int ver_minor;
111         unsigned int ver_patch;
112         unsigned int ver_build;
113         const char* ver_date;
114         const char* ver_time;
115 }
116 g_x264_version =
117 {
118         (VER_X264_MAJOR),
119         (VER_X264_MINOR),
120         (VER_X264_PATCH),
121         (VER_X264_BUILD),
122         __DATE__,
123         __TIME__,
124 };
125
126 //CLI Arguments
127 static struct
128 {
129         QStringList *list;
130         QReadWriteLock lock;
131 }
132 g_x264_argv;
133
134 //OS Version
135 static struct
136 {
137         bool bInitialized;
138         x264_os_version_t version;
139         QReadWriteLock lock;
140 }
141 g_x264_os_version;
142
143 //Special folders
144 static struct
145 {
146         QMap<size_t, QString> *knownFolders;
147         SHGetKnownFolderPath_t getKnownFolderPath;
148         SHGetFolderPath_t getFolderPath;
149         QReadWriteLock lock;
150 }
151 g_x264_known_folder;
152
153 //%TEMP% folder
154 static struct
155 {
156         QString *path;
157         QReadWriteLock lock;
158 }
159 g_x264_temp_folder;
160
161 //Wine detection
162 static struct
163 {
164         bool bInitialized;
165         bool bIsWine;
166         QReadWriteLock lock;
167 }
168 g_x264_wine;
169
170 //Portable Mode
171 static struct
172 {
173         bool bInitialized;
174         bool bPortableModeEnabled;
175         QReadWriteLock lock;
176 }
177 g_x264_portable;
178
179 //Known Windows versions - maps marketing names to the actual Windows NT versions
180 const x264_os_version_t x264_winver_win2k = {5,0};
181 const x264_os_version_t x264_winver_winxp = {5,1};
182 const x264_os_version_t x264_winver_xpx64 = {5,2};
183 const x264_os_version_t x264_winver_vista = {6,0};
184 const x264_os_version_t x264_winver_win70 = {6,1};
185 const x264_os_version_t x264_winver_win80 = {6,2};
186 const x264_os_version_t x264_winver_win81 = {6,3};
187
188 //GURU MEDITATION
189 static const char *GURU_MEDITATION = "\n\nGURU MEDITATION !!!\n\n";
190
191 ///////////////////////////////////////////////////////////////////////////////
192 // MACROS
193 ///////////////////////////////////////////////////////////////////////////////
194
195 //String helper
196 #define CLEAN_OUTPUT_STRING(STR) do \
197 { \
198         const char CTRL_CHARS[3] = { '\r', '\n', '\t' }; \
199         for(size_t i = 0; i < 3; i++) \
200         { \
201                 while(char *pos = strchr((STR), CTRL_CHARS[i])) *pos = char(0x20); \
202         } \
203 } \
204 while(0)
205
206 //String helper
207 #define TRIM_LEFT(STR) do \
208 { \
209         const char WHITE_SPACE[4] = { char(0x20), '\r', '\n', '\t' }; \
210         for(size_t i = 0; i < 4; i++) \
211         { \
212                 while(*(STR) == WHITE_SPACE[i]) (STR)++; \
213         } \
214 } \
215 while(0)
216
217 //Check for CLI flag
218 static inline bool _CHECK_FLAG(const int argc, char **argv, const char *flag)
219 {
220         for(int i = 1; i < argc; i++)
221         {
222                 if(_stricmp(argv[i], flag) == 0) return true;
223         }
224         return false;
225 }
226
227 #define CHECK_FLAG(FLAG) _CHECK_FLAG(argc, argv, "--" FLAG)
228 #define X264_ZERO_MEMORY(X) SecureZeroMemory(&X, sizeof(X))
229
230 ///////////////////////////////////////////////////////////////////////////////
231 // COMPILER INFO
232 ///////////////////////////////////////////////////////////////////////////////
233
234 /*
235  * Disclaimer: Parts of the following code were borrowed from MPC-HC project: http://mpc-hc.sf.net/
236  */
237
238 //Compiler detection
239 #if defined(__INTEL_COMPILER)
240         #if (__INTEL_COMPILER >= 1300)
241                 static const char *g_x264_version_compiler = "ICL 13." X264_MAKE_STR(__INTEL_COMPILER_BUILD_DATE);
242         #elif (__INTEL_COMPILER >= 1200)
243                 static const char *g_x264_version_compiler = "ICL 12." X264_MAKE_STR(__INTEL_COMPILER_BUILD_DATE);
244         #elif (__INTEL_COMPILER >= 1100)
245                 static const char *g_x264_version_compiler = "ICL 11.x";
246         #elif (__INTEL_COMPILER >= 1000)
247                 static const char *g_x264_version_compiler = "ICL 10.x";
248         #else
249                 #error Compiler is not supported!
250         #endif
251 #elif defined(_MSC_VER)
252         #if (_MSC_VER == 1800)
253                 #if (_MSC_FULL_VER < 180021005)
254                         static const char *g_x264_version_compiler = "MSVC 2013-Beta";
255                 #elif (_MSC_FULL_VER == 180021005)
256                         static const char *g_x264_version_compiler = "MSVC 2013";
257                 #else
258                         #error Compiler version is not supported yet!
259                 #endif
260         #elif (_MSC_VER == 1700)
261                 #if (_MSC_FULL_VER < 170050727)
262                         static const char *g_x264_version_compiler = "MSVC 2012-Beta";
263                 #elif (_MSC_FULL_VER < 170051020)
264                         static const char *g_x264_version_compiler = "MSVC 2012";
265                 #elif (_MSC_FULL_VER < 170051106)
266                         static const char *g_x264_version_compiler = "MSVC 2012.1-CTP";
267                 #elif (_MSC_FULL_VER < 170060315)
268                         static const char *g_x264_version_compiler = "MSVC 2012.1";
269                 #elif (_MSC_FULL_VER < 170060610)
270                         static const char *g_x264_version_compiler = "MSVC 2012.2";
271                 #elif (_MSC_FULL_VER < 170061030)
272                         static const char *g_x264_version_compiler = "MSVC 2012.3";
273                 #elif (_MSC_FULL_VER == 170061030)
274                         static const char *g_x264_version_compiler = "MSVC 2012.4";
275                 #else
276                         #error Compiler version is not supported yet!
277                 #endif
278         #elif (_MSC_VER == 1600)
279                 #if (_MSC_FULL_VER < 160040219)
280                         static const char *g_x264_version_compiler = "MSVC 2010";
281                 #elif (_MSC_FULL_VER == 160040219)
282                         static const char *g_x264_version_compiler = "MSVC 2010-SP1";
283                 #else
284                         #error Compiler version is not supported yet!
285                 #endif
286         #elif (_MSC_VER == 1500)
287                 #if (_MSC_FULL_VER >= 150030729)
288                         static const char *g_x264_version_compiler = "MSVC 2008-SP1";
289                 #else
290                         static const char *g_x264_version_compiler = "MSVC 2008";
291                 #endif
292         #else
293                 #error Compiler is not supported!
294         #endif
295
296         // Note: /arch:SSE and /arch:SSE2 are only available for the x86 platform
297         #if !defined(_M_X64) && defined(_M_IX86_FP)
298                 #if (_M_IX86_FP == 1)
299                         X264_COMPILER_WARNING("SSE instruction set is enabled!")
300                 #elif (_M_IX86_FP == 2)
301                         X264_COMPILER_WARNING("SSE2 (or higher) instruction set is enabled!")
302                 #endif
303         #endif
304 #else
305         #error Compiler is not supported!
306 #endif
307
308 //Architecture detection
309 #if defined(_M_X64)
310         static const char *g_x264_version_arch = "x64";
311 #elif defined(_M_IX86)
312         static const char *g_x264_version_arch = "x86";
313 #else
314         #error Architecture is not supported!
315 #endif
316
317 ///////////////////////////////////////////////////////////////////////////////
318 // GLOBAL FUNCTIONS
319 ///////////////////////////////////////////////////////////////////////////////
320
321 static __forceinline bool x264_check_for_debugger(void);
322
323 /*
324  * Suspend calling thread for N milliseconds
325  */
326 inline void x264_sleep(const unsigned int delay)
327 {
328         Sleep(delay);
329 }
330
331 /*
332  * Global exception handler
333  */
334 LONG WINAPI x264_exception_handler(__in struct _EXCEPTION_POINTERS *ExceptionInfo)
335 {
336         if(GetCurrentThreadId() != g_main_thread_id)
337         {
338                 HANDLE mainThread = OpenThread(THREAD_TERMINATE, FALSE, g_main_thread_id);
339                 if(mainThread) TerminateThread(mainThread, ULONG_MAX);
340         }
341
342         x264_fatal_exit(L"Unhandeled exception handler invoked, application will exit!");
343         return LONG_MAX;
344 }
345
346 /*
347  * Invalid parameters handler
348  */
349 void x264_invalid_param_handler(const wchar_t*, const wchar_t*, const wchar_t*, unsigned int, uintptr_t)
350 {
351         if(GetCurrentThreadId() != g_main_thread_id)
352         {
353                 HANDLE mainThread = OpenThread(THREAD_TERMINATE, FALSE, g_main_thread_id);
354                 if(mainThread) TerminateThread(mainThread, ULONG_MAX);
355         }
356
357         x264_fatal_exit(L"Invalid parameter handler invoked, application will exit!");
358 }
359
360 /*
361  * Get a random string
362  */
363 QString x264_rand_str(const bool bLong)
364 {
365         const QUuid uuid = QUuid::createUuid().toString();
366
367         const unsigned int u1 = uuid.data1;
368         const unsigned int u2 = (((unsigned int)(uuid.data2)) << 16) | ((unsigned int)(uuid.data3));
369         const unsigned int u3 = (((unsigned int)(uuid.data4[0])) << 24) | (((unsigned int)(uuid.data4[1])) << 16) | (((unsigned int)(uuid.data4[2])) << 8) | ((unsigned int)(uuid.data4[3]));
370         const unsigned int u4 = (((unsigned int)(uuid.data4[4])) << 24) | (((unsigned int)(uuid.data4[5])) << 16) | (((unsigned int)(uuid.data4[6])) << 8) | ((unsigned int)(uuid.data4[7]));
371
372         return bLong ? QString().sprintf("%08x%08x%08x%08x", u1, u2, u3, u4) : QString().sprintf("%08x%08x", (u1 ^ u2), (u3 ^ u4));
373 }
374
375 /*
376  * Robert Jenkins' 96 bit Mix Function
377  * Source: http://www.concentric.net/~Ttwang/tech/inthash.htm
378  */
379 static unsigned int x264_mix(const unsigned int x, const unsigned int y, const unsigned int z)
380 {
381         unsigned int a = x;
382         unsigned int b = y;
383         unsigned int c = z;
384         
385         a=a-b;  a=a-c;  a=a^(c >> 13);
386         b=b-c;  b=b-a;  b=b^(a << 8); 
387         c=c-a;  c=c-b;  c=c^(b >> 13);
388         a=a-b;  a=a-c;  a=a^(c >> 12);
389         b=b-c;  b=b-a;  b=b^(a << 16);
390         c=c-a;  c=c-b;  c=c^(b >> 5);
391         a=a-b;  a=a-c;  a=a^(c >> 3);
392         b=b-c;  b=b-a;  b=b^(a << 10);
393         c=c-a;  c=c-b;  c=c^(b >> 15);
394
395         return c;
396 }
397
398 /*
399  * Seeds the random number generator
400  * Note: Altough rand_s() doesn't need a seed, this must be called pripr to x264_rand(), just to to be sure!
401  */
402 void x264_seed_rand(void)
403 {
404         qsrand(x264_mix(clock(), time(NULL), _getpid()));
405 }
406
407 /*
408  * Returns a randum number
409  * Note: This function uses rand_s() if available, but falls back to qrand() otherwise
410  */
411 unsigned int x264_rand(void)
412 {
413         quint32 rnd = 0;
414
415         if(rand_s(&rnd) == 0)
416         {
417                 return rnd;
418         }
419
420         for(size_t i = 0; i < sizeof(unsigned int); i++)
421         {
422                 rnd = (rnd << 8) ^ qrand();
423         }
424
425         return rnd;
426 }
427
428 /*
429  * Change console text color
430  */
431 static void x264_console_color(FILE* file, WORD attributes)
432 {
433         const HANDLE hConsole = (HANDLE)(_get_osfhandle(_fileno(file)));
434         if((hConsole != NULL) && (hConsole != INVALID_HANDLE_VALUE))
435         {
436                 SetConsoleTextAttribute(hConsole, attributes);
437         }
438 }
439
440 /*
441  * Determines the current date, resistant against certain manipulations
442  */
443 QDate x264_current_date_safe(void)
444 {
445         const DWORD MAX_PROC = 1024;
446         DWORD *processes = new DWORD[MAX_PROC];
447         DWORD bytesReturned = 0;
448         
449         if(!EnumProcesses(processes, sizeof(DWORD) * MAX_PROC, &bytesReturned))
450         {
451                 X264_DELETE_ARRAY(processes);
452                 return QDate::currentDate();
453         }
454
455         const DWORD procCount = bytesReturned / sizeof(DWORD);
456         ULARGE_INTEGER lastStartTime;
457         memset(&lastStartTime, 0, sizeof(ULARGE_INTEGER));
458
459         for(DWORD i = 0; i < procCount; i++)
460         {
461                 HANDLE hProc = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, processes[i]);
462                 if(hProc)
463                 {
464                         FILETIME processTime[4];
465                         if(GetProcessTimes(hProc, &processTime[0], &processTime[1], &processTime[2], &processTime[3]))
466                         {
467                                 ULARGE_INTEGER timeCreation;
468                                 timeCreation.LowPart = processTime[0].dwLowDateTime;
469                                 timeCreation.HighPart = processTime[0].dwHighDateTime;
470                                 if(timeCreation.QuadPart > lastStartTime.QuadPart)
471                                 {
472                                         lastStartTime.QuadPart = timeCreation.QuadPart;
473                                 }
474                         }
475                         CloseHandle(hProc);
476                 }
477         }
478
479         X264_DELETE_ARRAY(processes);
480         
481         FILETIME lastStartTime_fileTime;
482         lastStartTime_fileTime.dwHighDateTime = lastStartTime.HighPart;
483         lastStartTime_fileTime.dwLowDateTime = lastStartTime.LowPart;
484
485         FILETIME lastStartTime_localTime;
486         if(!FileTimeToLocalFileTime(&lastStartTime_fileTime, &lastStartTime_localTime))
487         {
488                 memcpy(&lastStartTime_localTime, &lastStartTime_fileTime, sizeof(FILETIME));
489         }
490         
491         SYSTEMTIME lastStartTime_system;
492         if(!FileTimeToSystemTime(&lastStartTime_localTime, &lastStartTime_system))
493         {
494                 memset(&lastStartTime_system, 0, sizeof(SYSTEMTIME));
495                 lastStartTime_system.wYear = 1970; lastStartTime_system.wMonth = lastStartTime_system.wDay = 1;
496         }
497
498         const QDate currentDate = QDate::currentDate();
499         const QDate processDate = QDate(lastStartTime_system.wYear, lastStartTime_system.wMonth, lastStartTime_system.wDay);
500         return (currentDate >= processDate) ? currentDate : processDate;
501 }
502
503 /*
504  * Output logging message to console
505  */
506 static void x264_write_console(const int type, const char *msg)
507 {       
508         __try
509         {
510                 if(_isatty(_fileno(stderr)))
511                 {
512                         UINT oldOutputCP = GetConsoleOutputCP();
513                         if(oldOutputCP != CP_UTF8) SetConsoleOutputCP(CP_UTF8);
514
515                         switch(type)
516                         {
517                         case QtCriticalMsg:
518                         case QtFatalMsg:
519                                 x264_console_color(stderr, FOREGROUND_RED | FOREGROUND_INTENSITY);
520                                 fprintf(stderr, GURU_MEDITATION);
521                                 fprintf(stderr, "%s\n", msg);
522                                 fflush(stderr);
523                                 break;
524                         case QtWarningMsg:
525                                 x264_console_color(stderr, FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY);
526                                 fprintf(stderr, "%s\n", msg);
527                                 fflush(stderr);
528                                 break;
529                         default:
530                                 x264_console_color(stderr, FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY);
531                                 fprintf(stderr, "%s\n", msg);
532                                 fflush(stderr);
533                                 break;
534                         }
535         
536                         x264_console_color(stderr, FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED);
537                         if(oldOutputCP != CP_UTF8) SetConsoleOutputCP(oldOutputCP);
538                 }
539         }
540         __except(1)
541         {
542                 /*ignore any exception that might occur here!*/
543         }
544 }
545
546 /*
547  * Output logging message to debugger
548  */
549 static void x264_write_dbg_out(const int type, const char *msg)
550 {       
551         const char *FORMAT = "[sx264l][%c] %s\n";
552
553         __try
554         {
555                 char buffer[512];
556                 const char* input = msg;
557                 TRIM_LEFT(input);
558                 
559                 switch(type)
560                 {
561                 case QtCriticalMsg:
562                 case QtFatalMsg:
563                         _snprintf_s(buffer, 512, _TRUNCATE, FORMAT, 'C', input);
564                         break;
565                 case QtWarningMsg:
566                         _snprintf_s(buffer, 512, _TRUNCATE, FORMAT, 'W', input);
567                         break;
568                 default:
569                         _snprintf_s(buffer, 512, _TRUNCATE, FORMAT, 'I', input);
570                         break;
571                 }
572
573                 char *temp = &buffer[0];
574                 CLEAN_OUTPUT_STRING(temp);
575                 OutputDebugStringA(temp);
576         }
577         __except(1)
578         {
579                 /*ignore any exception that might occur here!*/
580         }
581 }
582
583 /*
584  * Output logging message to logfile
585  */
586 static void x264_write_logfile(const int type, const char *msg)
587 {       
588         const char *FORMAT = "[%c][%04u] %s\r\n";
589
590         __try
591         {
592                 if(g_x264_log_file)
593                 {
594                         char buffer[512];
595                         strncpy_s(buffer, 512, msg, _TRUNCATE);
596
597                         char *temp = &buffer[0];
598                         TRIM_LEFT(temp);
599                         CLEAN_OUTPUT_STRING(temp);
600                         
601                         const unsigned int timestamp = static_cast<unsigned int>(_time64(NULL) % 3600I64);
602
603                         switch(type)
604                         {
605                         case QtCriticalMsg:
606                         case QtFatalMsg:
607                                 fprintf(g_x264_log_file, FORMAT, 'C', timestamp, temp);
608                                 break;
609                         case QtWarningMsg:
610                                 fprintf(g_x264_log_file, FORMAT, 'W', timestamp, temp);
611                                 break;
612                         default:
613                                 fprintf(g_x264_log_file, FORMAT, 'I', timestamp, temp);
614                                 break;
615                         }
616
617                         fflush(g_x264_log_file);
618                 }
619         }
620         __except(1)
621         {
622                 /*ignore any exception that might occur here!*/
623         }
624 }
625
626 /*
627  * Qt message handler
628  */
629 void x264_message_handler(QtMsgType type, const char *msg)
630 {
631         if((!msg) || (!(msg[0])))
632         {
633                 return;
634         }
635
636         QMutexLocker lock(&g_x264_message_mutex);
637
638         if(g_x264_log_file)
639         {
640                 x264_write_logfile(type, msg);
641         }
642
643         if(g_x264_console_attached)
644         {
645                 x264_write_console(type, msg);
646         }
647         else
648         {
649                 x264_write_dbg_out(type, msg);
650         }
651
652         if((type == QtCriticalMsg) || (type == QtFatalMsg))
653         {
654                 lock.unlock();
655                 x264_fatal_exit(L"The application has encountered a critical error and will exit now!", QString::fromUtf8(msg).toLatin1().constData());
656         }
657 }
658
659 /*
660  * Initialize the console
661  */
662 void x264_init_console(const int argc, char **argv)
663 {
664         bool enableConsole = x264_is_prerelease() || (X264_DEBUG);
665
666         if(_environ)
667         {
668                 wchar_t *logfile = NULL;
669                 size_t logfile_len = 0;
670                 if(!_wdupenv_s(&logfile, &logfile_len, L"X264_LAUNCHER_LOGFILE"))
671                 {
672                         if(logfile && (logfile_len > 0))
673                         {
674                                 FILE *temp = NULL;
675                                 if(!_wfopen_s(&temp, logfile, L"wb"))
676                                 {
677                                         fprintf(temp, "%c%c%c", 0xEF, 0xBB, 0xBF);
678                                         g_x264_log_file = temp;
679                                 }
680                                 free(logfile);
681                         }
682                 }
683         }
684
685         if(!X264_DEBUG)
686         {
687
688                 if(CHECK_FLAG("console"))    enableConsole = true;
689                 if(CHECK_FLAG("no-console")) enableConsole = false;
690         }
691
692         if(enableConsole)
693         {
694                 if(!g_x264_console_attached)
695                 {
696                         if(AllocConsole())
697                         {
698                                 SetConsoleCtrlHandler(NULL, TRUE);
699                                 SetConsoleTitle(L"Simple x264 Launcher | Debug Console");
700                                 SetConsoleOutputCP(CP_UTF8);
701                                 g_x264_console_attached = true;
702                         }
703                 }
704                 
705                 if(g_x264_console_attached)
706                 {
707                         //-------------------------------------------------------------------
708                         //See: http://support.microsoft.com/default.aspx?scid=kb;en-us;105305
709                         //-------------------------------------------------------------------
710                         const int flags = _O_WRONLY | _O_U8TEXT;
711                         int hCrtStdOut = _open_osfhandle((intptr_t) GetStdHandle(STD_OUTPUT_HANDLE), flags);
712                         int hCrtStdErr = _open_osfhandle((intptr_t) GetStdHandle(STD_ERROR_HANDLE), flags);
713                         FILE *hfStdOut = (hCrtStdOut >= 0) ? _fdopen(hCrtStdOut, "wb") : NULL;
714                         FILE *hfStdErr = (hCrtStdErr >= 0) ? _fdopen(hCrtStdErr, "wb") : NULL;
715                         if(hfStdOut) { *stdout = *hfStdOut; std::cout.rdbuf(new std::filebuf(hfStdOut)); }
716                         if(hfStdErr) { *stderr = *hfStdErr; std::cerr.rdbuf(new std::filebuf(hfStdErr)); }
717                 }
718
719                 HWND hwndConsole = GetConsoleWindow();
720
721                 if((hwndConsole != NULL) && (hwndConsole != INVALID_HANDLE_VALUE))
722                 {
723                         HMENU hMenu = GetSystemMenu(hwndConsole, 0);
724                         EnableMenuItem(hMenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);
725                         RemoveMenu(hMenu, SC_CLOSE, MF_BYCOMMAND);
726
727                         SetWindowPos(hwndConsole, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_FRAMECHANGED);
728                         SetWindowLong(hwndConsole, GWL_STYLE, GetWindowLong(hwndConsole, GWL_STYLE) & (~WS_MAXIMIZEBOX) & (~WS_MINIMIZEBOX));
729                         SetWindowPos(hwndConsole, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_FRAMECHANGED);
730                 }
731         }
732 }
733
734 /*
735  * Version info
736  */
737 unsigned int x264_version_major(void)
738 {
739         return g_x264_version.ver_major;
740 }
741
742 unsigned int x264_version_minor(void)
743 {
744         return (g_x264_version.ver_minor * 10) + (g_x264_version.ver_patch % 10);
745 }
746
747 unsigned int x264_version_build(void)
748 {
749         return g_x264_version.ver_build;
750 }
751
752 const char *x264_version_compiler(void)
753 {
754         return g_x264_version_compiler;
755 }
756
757 const char *x264_version_arch(void)
758 {
759         return g_x264_version_arch;
760 }
761
762 /*
763  * Get CLI arguments
764  */
765 const QStringList &x264_arguments(void)
766 {
767         QReadLocker readLock(&g_x264_argv.lock);
768
769         if(!g_x264_argv.list)
770         {
771                 readLock.unlock();
772                 QWriteLocker writeLock(&g_x264_argv.lock);
773
774                 g_x264_argv.list = new QStringList;
775
776                 int nArgs = 0;
777                 LPWSTR *szArglist = CommandLineToArgvW(GetCommandLineW(), &nArgs);
778
779                 if(NULL != szArglist)
780                 {
781                         for(int i = 0; i < nArgs; i++)
782                         {
783                                 (*g_x264_argv.list) << WCHAR2QSTR(szArglist[i]);
784                         }
785                         LocalFree(szArglist);
786                 }
787                 else
788                 {
789                         qWarning("CommandLineToArgvW() has failed !!!");
790                 }
791         }
792
793         return (*g_x264_argv.list);
794 }
795
796 /*
797  * Check for portable mode
798  */
799 bool x264_portable(void)
800 {
801         QReadLocker readLock(&g_x264_portable.lock);
802
803         if(g_x264_portable.bInitialized)
804         {
805                 return g_x264_portable.bPortableModeEnabled;
806         }
807         
808         readLock.unlock();
809         QWriteLocker writeLock(&g_x264_portable.lock);
810
811         if(!g_x264_portable.bInitialized)
812         {
813                 if(VER_X264_PORTABLE_EDITION)
814                 {
815                         qWarning("Simple x264 Launcher portable edition!\n");
816                         g_x264_portable.bPortableModeEnabled = true;
817                 }
818                 else
819                 {
820                         QString baseName = QFileInfo(QApplication::applicationFilePath()).completeBaseName();
821                         int idx1 = baseName.indexOf("x264", 0, Qt::CaseInsensitive);
822                         int idx2 = baseName.lastIndexOf("portable", -1, Qt::CaseInsensitive);
823                         g_x264_portable.bPortableModeEnabled = (idx1 >= 0) && (idx2 >= 0) && (idx1 < idx2);
824                 }
825                 g_x264_portable.bInitialized = true;
826         }
827         
828         return g_x264_portable.bPortableModeEnabled;
829 }
830
831 /*
832  * Get data path (i.e. path to store config files)
833  */
834 const QString &x264_data_path(void)
835 {
836         static QString pathCache;
837         
838         if(pathCache.isNull())
839         {
840                 if(!x264_portable())
841                 {
842                         pathCache = QDesktopServices::storageLocation(QDesktopServices::DataLocation);
843                 }
844                 if(pathCache.isEmpty() || x264_portable())
845                 {
846                         pathCache = QApplication::applicationDirPath();
847                 }
848                 if(!QDir(pathCache).mkpath("."))
849                 {
850                         qWarning("Data directory could not be created:\n%s\n", pathCache.toUtf8().constData());
851                         pathCache = QDir::currentPath();
852                 }
853         }
854         
855         return pathCache;
856 }
857
858 /*
859  * Get build date date
860  */
861 const QDate &x264_version_date(void)
862 {
863         if(!g_x264_version_date.isValid())
864         {
865                 int date[3] = {0, 0, 0}; char temp[12] = {'\0'};
866                 strncpy_s(temp, 12, g_x264_version.ver_date, _TRUNCATE);
867
868                 if(strlen(temp) == 11)
869                 {
870                         temp[3] = temp[6] = '\0';
871                         date[2] = atoi(&temp[4]);
872                         date[0] = atoi(&temp[7]);
873                         
874                         for(int j = 0; j < 12; j++)
875                         {
876                                 if(!_strcmpi(&temp[0], g_x264_months[j]))
877                                 {
878                                         date[1] = j+1;
879                                         break;
880                                 }
881                         }
882
883                         g_x264_version_date = QDate(date[0], date[1], date[2]);
884                 }
885
886                 if(!g_x264_version_date.isValid())
887                 {
888                         qFatal("Internal error: Date format could not be recognized!");
889                 }
890         }
891
892         return g_x264_version_date;
893 }
894
895 const char *x264_version_time(void)
896 {
897         return g_x264_version.ver_time;
898 }
899
900 bool x264_is_prerelease(void)
901 {
902         return (VER_X264_PRE_RELEASE);
903 }
904
905 /*
906  * CPUID prototype (actual function is in ASM code)
907  */
908 extern "C"
909 {
910         void x264_cpu_cpuid(unsigned int op, unsigned int *eax, unsigned int *ebx, unsigned int *ecx, unsigned int *edx);
911 }
912
913 /*
914  * Detect CPU features
915  */
916 x264_cpu_t x264_detect_cpu_features(const int argc, char **argv)
917 {
918         typedef BOOL (WINAPI *IsWow64ProcessFun)(__in HANDLE hProcess, __out PBOOL Wow64Process);
919
920         x264_cpu_t features;
921         SYSTEM_INFO systemInfo;
922         unsigned int CPUInfo[4];
923         char CPUIdentificationString[0x40];
924         char CPUBrandString[0x40];
925
926         memset(&features, 0, sizeof(x264_cpu_t));
927         memset(&systemInfo, 0, sizeof(SYSTEM_INFO));
928         memset(CPUIdentificationString, 0, sizeof(CPUIdentificationString));
929         memset(CPUBrandString, 0, sizeof(CPUBrandString));
930         
931         x264_cpu_cpuid(0, &CPUInfo[0], &CPUInfo[1], &CPUInfo[2], &CPUInfo[3]);
932         memcpy(CPUIdentificationString, &CPUInfo[1], sizeof(int));
933         memcpy(CPUIdentificationString + 4, &CPUInfo[3], sizeof(int));
934         memcpy(CPUIdentificationString + 8, &CPUInfo[2], sizeof(int));
935         features.intel = (_stricmp(CPUIdentificationString, "GenuineIntel") == 0);
936         strncpy_s(features.vendor, 0x40, CPUIdentificationString, _TRUNCATE);
937
938         if(CPUInfo[0] >= 1)
939         {
940                 x264_cpu_cpuid(1, &CPUInfo[0], &CPUInfo[1], &CPUInfo[2], &CPUInfo[3]);
941                 features.mmx = (CPUInfo[3] & 0x800000) || false;
942                 features.sse = (CPUInfo[3] & 0x2000000) || false;
943                 features.sse2 = (CPUInfo[3] & 0x4000000) || false;
944                 features.ssse3 = (CPUInfo[2] & 0x200) || false;
945                 features.sse3 = (CPUInfo[2] & 0x1) || false;
946                 features.ssse3 = (CPUInfo[2] & 0x200) || false;
947                 features.stepping = CPUInfo[0] & 0xf;
948                 features.model = ((CPUInfo[0] >> 4) & 0xf) + (((CPUInfo[0] >> 16) & 0xf) << 4);
949                 features.family = ((CPUInfo[0] >> 8) & 0xf) + ((CPUInfo[0] >> 20) & 0xff);
950                 if(features.sse) features.mmx2 = true; //MMXEXT is a subset of SSE!
951         }
952
953         x264_cpu_cpuid(0x80000000, &CPUInfo[0], &CPUInfo[1], &CPUInfo[2], &CPUInfo[3]);
954         int nExIds = qMax<int>(qMin<int>(CPUInfo[0], 0x80000004), 0x80000000);
955
956         if((_stricmp(CPUIdentificationString, "AuthenticAMD") == 0) && (nExIds >= 0x80000001U))
957         {
958                 x264_cpu_cpuid(0x80000001, &CPUInfo[0], &CPUInfo[1], &CPUInfo[2], &CPUInfo[3]);
959                 features.mmx2 = features.mmx2 || (CPUInfo[3] & 0x00400000U);
960         }
961
962         for(int i = 0x80000002; i <= nExIds; ++i)
963         {
964                 x264_cpu_cpuid(i, &CPUInfo[0], &CPUInfo[1], &CPUInfo[2], &CPUInfo[3]);
965                 switch(i)
966                 {
967                 case 0x80000002:
968                         memcpy(CPUBrandString, CPUInfo, sizeof(CPUInfo));
969                         break;
970                 case 0x80000003:
971                         memcpy(CPUBrandString + 16, CPUInfo, sizeof(CPUInfo));
972                         break;
973                 case 0x80000004:
974                         memcpy(CPUBrandString + 32, CPUInfo, sizeof(CPUInfo));
975                         break;
976                 }
977         }
978
979         strncpy_s(features.brand, 0x40, CPUBrandString, _TRUNCATE);
980
981         if(strlen(features.brand) < 1) strncpy_s(features.brand, 0x40, "Unknown", _TRUNCATE);
982         if(strlen(features.vendor) < 1) strncpy_s(features.vendor, 0x40, "Unknown", _TRUNCATE);
983
984 #if (!(defined(_M_X64) || defined(_M_IA64)))
985         QLibrary Kernel32Lib("kernel32.dll");
986         if(IsWow64ProcessFun IsWow64ProcessPtr = (IsWow64ProcessFun) Kernel32Lib.resolve("IsWow64Process"))
987         {
988                 BOOL x64flag = FALSE;
989                 if(IsWow64ProcessPtr(GetCurrentProcess(), &x64flag))
990                 {
991                         features.x64 = (x64flag == TRUE);
992                 }
993         }
994 #else
995         features.x64 = true;
996 #endif
997
998         DWORD_PTR procAffinity, sysAffinity;
999         if(GetProcessAffinityMask(GetCurrentProcess(), &procAffinity, &sysAffinity))
1000         {
1001                 for(DWORD_PTR mask = 1; mask; mask <<= 1)
1002                 {
1003                         features.count += ((sysAffinity & mask) ? (1) : (0));
1004                 }
1005         }
1006         if(features.count < 1)
1007         {
1008                 GetNativeSystemInfo(&systemInfo);
1009                 features.count = qBound(1UL, systemInfo.dwNumberOfProcessors, 64UL);
1010         }
1011
1012         bool flag = false;
1013         if(CHECK_FLAG("force-cpu-no-64bit")) { flag = true; features.x64 = false; }
1014         if(CHECK_FLAG("force-cpu-no-sse"))   { flag = true; features.sse = features.sse2 = features.sse3 = features.ssse3 = false; }
1015         if(CHECK_FLAG("force-cpu-no-intel")) { flag = true; features.intel = false; }
1016         if(flag) qWarning("CPU flags overwritten by user-defined parameters. Take care!\n");
1017
1018         return features;
1019 }
1020
1021 /*
1022  * Verify a specific Windows version
1023  */
1024 static bool x264_verify_os_version(const DWORD major, const DWORD minor)
1025 {
1026         OSVERSIONINFOEXW osvi;
1027         DWORDLONG dwlConditionMask = 0;
1028
1029         //Initialize the OSVERSIONINFOEX structure
1030         memset(&osvi, 0, sizeof(OSVERSIONINFOEXW));
1031         osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW);
1032         osvi.dwMajorVersion = major;
1033         osvi.dwMinorVersion = minor;
1034         osvi.dwPlatformId = VER_PLATFORM_WIN32_NT;
1035
1036         //Initialize the condition mask
1037         VER_SET_CONDITION(dwlConditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL);
1038         VER_SET_CONDITION(dwlConditionMask, VER_MINORVERSION, VER_GREATER_EQUAL);
1039         VER_SET_CONDITION(dwlConditionMask, VER_PLATFORMID, VER_EQUAL);
1040
1041         // Perform the test
1042         const BOOL ret = VerifyVersionInfoW(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_PLATFORMID, dwlConditionMask);
1043
1044         //Error checking
1045         if(!ret)
1046         {
1047                 if(GetLastError() != ERROR_OLD_WIN_VERSION)
1048                 {
1049                         qWarning("VerifyVersionInfo() system call has failed!");
1050                 }
1051         }
1052
1053         return (ret != FALSE);
1054 }
1055
1056 /*
1057  * Determine the *real* Windows version
1058  */
1059 static bool x264_get_real_os_version(unsigned int *major, unsigned int *minor, bool *pbOverride)
1060 {
1061         *major = *minor = 0;
1062         *pbOverride = false;
1063         
1064         //Initialize local variables
1065         OSVERSIONINFOEXW osvi;
1066         memset(&osvi, 0, sizeof(OSVERSIONINFOEXW));
1067         osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW);
1068
1069         //Try GetVersionEx() first
1070         if(GetVersionExW((LPOSVERSIONINFOW)&osvi) == FALSE)
1071         {
1072                 qWarning("GetVersionEx() has failed, cannot detect Windows version!");
1073                 return false;
1074         }
1075
1076         //Make sure we are running on NT
1077         if(osvi.dwPlatformId == VER_PLATFORM_WIN32_NT)
1078         {
1079                 *major = osvi.dwMajorVersion;
1080                 *minor = osvi.dwMinorVersion;
1081         }
1082         else
1083         {
1084                 qWarning("Not running on Windows NT, unsupported operating system!");
1085                 return false;
1086         }
1087
1088         //Determine the real *major* version first
1089         forever
1090         {
1091                 const DWORD nextMajor = (*major) + 1;
1092                 if(x264_verify_os_version(nextMajor, 0))
1093                 {
1094                         *pbOverride = true;
1095                         *major = nextMajor;
1096                         *minor = 0;
1097                         continue;
1098                 }
1099                 break;
1100         }
1101
1102         //Now also determine the real *minor* version
1103         forever
1104         {
1105                 const DWORD nextMinor = (*minor) + 1;
1106                 if(x264_verify_os_version((*major), nextMinor))
1107                 {
1108                         *pbOverride = true;
1109                         *minor = nextMinor;
1110                         continue;
1111                 }
1112                 break;
1113         }
1114
1115         return true;
1116 }
1117
1118 /*
1119  * Get the native operating system version
1120  */
1121 const x264_os_version_t &x264_get_os_version(void)
1122 {
1123         QReadLocker readLock(&g_x264_os_version.lock);
1124
1125         //Already initialized?
1126         if(g_x264_os_version.bInitialized)
1127         {
1128                 return g_x264_os_version.version;
1129         }
1130         
1131         readLock.unlock();
1132         QWriteLocker writeLock(&g_x264_os_version.lock);
1133
1134         //Detect OS version
1135         if(!g_x264_os_version.bInitialized)
1136         {
1137                 unsigned int major, minor; bool oflag;
1138                 if(x264_get_real_os_version(&major, &minor, &oflag))
1139                 {
1140                         g_x264_os_version.version.versionMajor = major;
1141                         g_x264_os_version.version.versionMinor = minor;
1142                         g_x264_os_version.version.overrideFlag = oflag;
1143                         g_x264_os_version.bInitialized = true;
1144                 }
1145                 else
1146                 {
1147                         qWarning("Failed to determin the operating system version!");
1148                 }
1149         }
1150
1151         return g_x264_os_version.version;
1152 }
1153
1154 /*
1155  * Check for compatibility mode
1156  */
1157 static bool x264_check_compatibility_mode(const char *exportName, const char *executableName)
1158 {
1159         QLibrary kernel32("kernel32.dll");
1160
1161         if(exportName != NULL)
1162         {
1163                 if(kernel32.resolve(exportName) != NULL)
1164                 {
1165                         qWarning("Function '%s' exported from 'kernel32.dll' -> Windows compatibility mode!", exportName);
1166                         qFatal("%s", QApplication::tr("Executable '%1' doesn't support Windows compatibility mode.").arg(QString::fromLatin1(executableName)).toLatin1().constData());
1167                         return false;
1168                 }
1169         }
1170
1171         return true;
1172 }
1173
1174 /*
1175  * Check if we are running under wine
1176  */
1177 bool x264_detect_wine(void)
1178 {
1179         QReadLocker readLock(&g_x264_wine.lock);
1180
1181         //Already initialized?
1182         if(g_x264_wine.bInitialized)
1183         {
1184                 return g_x264_wine.bIsWine;
1185         }
1186         
1187         readLock.unlock();
1188         QWriteLocker writeLock(&g_x264_wine.lock);
1189
1190         if(!g_x264_wine.bInitialized)
1191         {
1192                 g_x264_wine.bIsWine = false;
1193                 QLibrary ntdll("ntdll.dll");
1194                 if(ntdll.load())
1195                 {
1196                         if(ntdll.resolve("wine_nt_to_unix_file_name") != NULL) g_x264_wine.bIsWine = true;
1197                         if(ntdll.resolve("wine_get_version") != NULL) g_x264_wine.bIsWine = true;
1198                         ntdll.unload();
1199                 }
1200                 g_x264_wine.bInitialized = true;
1201         }
1202
1203         return g_x264_wine.bIsWine;
1204 }
1205
1206 /*
1207  * Qt event filter
1208  */
1209 static bool x264_event_filter(void *message, long *result)
1210
1211         if((!(X264_DEBUG)) && x264_check_for_debugger())
1212         {
1213                 x264_fatal_exit(L"Not a debug build. Please unload debugger and try again!");
1214         }
1215         
1216         //switch(reinterpret_cast<MSG*>(message)->message)
1217         //{
1218         //case WM_QUERYENDSESSION:
1219         //      qWarning("WM_QUERYENDSESSION message received!");
1220         //      *result = x264_broadcast(x264_event_queryendsession, false) ? TRUE : FALSE;
1221         //      return true;
1222         //case WM_ENDSESSION:
1223         //      qWarning("WM_ENDSESSION message received!");
1224         //      if(reinterpret_cast<MSG*>(message)->wParam == TRUE)
1225         //      {
1226         //              x264_broadcast(x264_event_endsession, false);
1227         //              if(QApplication *app = reinterpret_cast<QApplication*>(QApplication::instance()))
1228         //              {
1229         //                      app->closeAllWindows();
1230         //                      app->quit();
1231         //              }
1232         //              x264_finalization();
1233         //              exit(1);
1234         //      }
1235         //      *result = 0;
1236         //      return true;
1237         //default:
1238         //      /*ignore this message and let Qt handle it*/
1239         //      return false;
1240         //}
1241
1242         return false;
1243 }
1244
1245 /*
1246  * Check for process elevation
1247  */
1248 static bool x264_process_is_elevated(bool *bIsUacEnabled = NULL)
1249 {
1250         bool bIsProcessElevated = false;
1251         if(bIsUacEnabled) *bIsUacEnabled = false;
1252         HANDLE hToken = NULL;
1253         
1254         if(OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
1255         {
1256                 TOKEN_ELEVATION_TYPE tokenElevationType;
1257                 DWORD returnLength;
1258                 if(GetTokenInformation(hToken, TokenElevationType, &tokenElevationType, sizeof(TOKEN_ELEVATION_TYPE), &returnLength))
1259                 {
1260                         if(returnLength == sizeof(TOKEN_ELEVATION_TYPE))
1261                         {
1262                                 switch(tokenElevationType)
1263                                 {
1264                                 case TokenElevationTypeDefault:
1265                                         qDebug("Process token elevation type: Default -> UAC is disabled.\n");
1266                                         break;
1267                                 case TokenElevationTypeFull:
1268                                         qWarning("Process token elevation type: Full -> potential security risk!\n");
1269                                         bIsProcessElevated = true;
1270                                         if(bIsUacEnabled) *bIsUacEnabled = true;
1271                                         break;
1272                                 case TokenElevationTypeLimited:
1273                                         qDebug("Process token elevation type: Limited -> not elevated.\n");
1274                                         if(bIsUacEnabled) *bIsUacEnabled = true;
1275                                         break;
1276                                 default:
1277                                         qWarning("Unknown tokenElevationType value: %d", tokenElevationType);
1278                                         break;
1279                                 }
1280                         }
1281                         else
1282                         {
1283                                 qWarning("GetTokenInformation() return an unexpected size!");
1284                         }
1285                 }
1286                 CloseHandle(hToken);
1287         }
1288         else
1289         {
1290                 qWarning("Failed to open process token!");
1291         }
1292
1293         return bIsProcessElevated;
1294 }
1295
1296 /*
1297  * Check if the current user is an administartor (helper function)
1298  */
1299 static bool x264_user_is_admin_helper(void)
1300 {
1301         HANDLE hToken = NULL;
1302         if(!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
1303         {
1304                 return false;
1305         }
1306
1307         DWORD dwSize = 0;
1308         if(!GetTokenInformation(hToken, TokenGroups, NULL, 0, &dwSize))
1309         {
1310                 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
1311                 {
1312                         CloseHandle(hToken);
1313                         return false;
1314                 }
1315         }
1316
1317         PTOKEN_GROUPS lpGroups = (PTOKEN_GROUPS) malloc(dwSize);
1318         if(!lpGroups)
1319         {
1320                 CloseHandle(hToken);
1321                 return false;
1322         }
1323
1324         if(!GetTokenInformation(hToken, TokenGroups, lpGroups, dwSize, &dwSize))
1325         {
1326                 free(lpGroups);
1327                 CloseHandle(hToken);
1328                 return false;
1329         }
1330
1331         PSID lpSid = NULL; SID_IDENTIFIER_AUTHORITY Authority = {SECURITY_NT_AUTHORITY};
1332         if(!AllocateAndInitializeSid(&Authority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &lpSid))
1333         {
1334                 free(lpGroups);
1335                 CloseHandle(hToken);
1336                 return false;
1337         }
1338
1339         bool bResult = false;
1340         for(DWORD i = 0; i < lpGroups->GroupCount; i++)
1341         {
1342                 if(EqualSid(lpSid, lpGroups->Groups[i].Sid))
1343                 {
1344                         bResult = true;
1345                         break;
1346                 }
1347         }
1348
1349         FreeSid(lpSid);
1350         free(lpGroups);
1351         CloseHandle(hToken);
1352         return bResult;
1353 }
1354
1355 /*
1356  * Check if the current user is an administartor
1357  */
1358 bool x264_user_is_admin(void)
1359 {
1360         bool isAdmin = false;
1361
1362         //Check for process elevation and UAC support first!
1363         if(x264_process_is_elevated(&isAdmin))
1364         {
1365                 qWarning("Process is elevated -> user is admin!");
1366                 return true;
1367         }
1368         
1369         //If not elevated and UAC is not available -> user must be in admin group!
1370         if(!isAdmin)
1371         {
1372                 qDebug("UAC is disabled/unavailable -> checking for Administrators group");
1373                 isAdmin = x264_user_is_admin_helper();
1374         }
1375
1376         return isAdmin;
1377 }
1378
1379 /*
1380  * Initialize Qt framework
1381  */
1382 bool x264_init_qt(int &argc, char **argv)
1383 {
1384         static bool qt_initialized = false;
1385         typedef BOOL (WINAPI *SetDllDirectoryProc)(WCHAR *lpPathName);
1386         const QStringList &arguments = x264_arguments();
1387
1388         //Don't initialized again, if done already
1389         if(qt_initialized)
1390         {
1391                 return true;
1392         }
1393
1394         //Secure DLL loading
1395         QLibrary kernel32("kernel32.dll");
1396         if(kernel32.load())
1397         {
1398                 SetDllDirectoryProc pSetDllDirectory = (SetDllDirectoryProc) kernel32.resolve("SetDllDirectoryW");
1399                 if(pSetDllDirectory != NULL) pSetDllDirectory(L"");
1400         }
1401
1402         //Extract executable name from argv[] array
1403         QString executableName = QLatin1String("x264_launcher.exe");
1404         if(arguments.count() > 0)
1405         {
1406                 static const char *delimiters = "\\/:?";
1407                 executableName = arguments[0].trimmed();
1408                 for(int i = 0; delimiters[i]; i++)
1409                 {
1410                         int temp = executableName.lastIndexOf(QChar(delimiters[i]));
1411                         if(temp >= 0) executableName = executableName.mid(temp + 1);
1412                 }
1413                 executableName = executableName.trimmed();
1414                 if(executableName.isEmpty())
1415                 {
1416                         executableName = QLatin1String("x264_launcher.exe");
1417                 }
1418         }
1419
1420         //Check Qt version
1421 #ifdef QT_BUILD_KEY
1422         qDebug("Using Qt v%s [%s], %s, %s", qVersion(), QLibraryInfo::buildDate().toString(Qt::ISODate).toLatin1().constData(), (qSharedBuild() ? "DLL" : "Static"), QLibraryInfo::buildKey().toLatin1().constData());
1423         qDebug("Compiled with Qt v%s [%s], %s\n", QT_VERSION_STR, QT_PACKAGEDATE_STR, QT_BUILD_KEY);
1424         if(_stricmp(qVersion(), QT_VERSION_STR))
1425         {
1426                 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());
1427                 return false;
1428         }
1429         if(QLibraryInfo::buildKey().compare(QString::fromLatin1(QT_BUILD_KEY), Qt::CaseInsensitive))
1430         {
1431                 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());
1432                 return false;
1433         }
1434 #else
1435         qDebug("Using Qt v%s [%s], %s", qVersion(), QLibraryInfo::buildDate().toString(Qt::ISODate).toLatin1().constData(), (qSharedBuild() ? "DLL" : "Static"));
1436         qDebug("Compiled with Qt v%s [%s]\n", QT_VERSION_STR, QT_PACKAGEDATE_STR);
1437 #endif
1438
1439         //Check the Windows version
1440         const x264_os_version_t &osVersionNo = x264_get_os_version();
1441         if(osVersionNo < x264_winver_winxp)
1442         {
1443                 qFatal("%s", QApplication::tr("Executable '%1' requires Windows XP or later.").arg(executableName).toLatin1().constData());
1444         }
1445
1446         //Supported Windows version?
1447         if(osVersionNo == x264_winver_winxp)
1448         {
1449                 qDebug("Running on Windows XP or Windows XP Media Center Edition.\n");                                          //x264_check_compatibility_mode("GetLargePageMinimum", executableName);
1450         }
1451         else if(osVersionNo == x264_winver_xpx64)
1452         {
1453                 qDebug("Running on Windows Server 2003, Windows Server 2003 R2 or Windows XP x64.\n");          //x264_check_compatibility_mode("GetLocaleInfoEx", executableName);
1454         }
1455         else if(osVersionNo == x264_winver_vista)
1456         {
1457                 qDebug("Running on Windows Vista or Windows Server 2008.\n");                                                           //x264_check_compatibility_mode("CreateRemoteThreadEx", executableName*/);
1458         }
1459         else if(osVersionNo == x264_winver_win70)
1460         {
1461                 qDebug("Running on Windows 7 or Windows Server 2008 R2.\n");                                                            //x264_check_compatibility_mode("CreateFile2", executableName);
1462         }
1463         else if(osVersionNo == x264_winver_win80)
1464         {
1465                 qDebug("Running on Windows 8 or Windows Server 2012.\n");                                                                       //x264_check_compatibility_mode("FindPackagesByPackageFamily", executableName);
1466         }
1467         else if(osVersionNo == x264_winver_win81)
1468         {
1469                 qDebug("Running on Windows 8.1 or Windows Server 2012 R2.\n");                                                          //x264_check_compatibility_mode(NULL, executableName);
1470         }
1471         else
1472         {
1473                 const QString message = QString().sprintf("Running on an unknown WindowsNT-based system (v%u.%u).", osVersionNo.versionMajor, osVersionNo.versionMinor);
1474                 qWarning("%s\n", QUTF8(message));
1475                 MessageBoxW(NULL, QWCHAR(message), L"Simple x264 Launcher", MB_OK | MB_TOPMOST | MB_ICONWARNING);
1476         }
1477
1478         //Check for compat mode
1479         if(osVersionNo.overrideFlag && (osVersionNo <= x264_winver_win81))
1480         {
1481                 qWarning("Windows compatibility mode detected!");
1482                 if(!arguments.contains("--ignore-compat-mode", Qt::CaseInsensitive))
1483                 {
1484                         qFatal("%s", QApplication::tr("Executable '%1' doesn't support Windows compatibility mode.").arg(executableName).toLatin1().constData());
1485                         return false;
1486                 }
1487         }
1488
1489         //Check for Wine
1490         if(x264_detect_wine())
1491         {
1492                 qWarning("It appears we are running under Wine, unexpected things might happen!\n");
1493         }
1494
1495         //Set text Codec for locale
1496         QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"));
1497
1498         //Create Qt application instance
1499         QApplication *application = new QApplication(argc, argv);
1500
1501         //Load plugins from application directory
1502         QCoreApplication::setLibraryPaths(QStringList() << QApplication::applicationDirPath());
1503         qDebug("Library Path:\n%s\n", QUTF8(QApplication::libraryPaths().first()));
1504
1505         //Create Qt application instance and setup version info
1506         application->setApplicationName("Simple x264 Launcher");
1507         application->setApplicationVersion(QString().sprintf("%d.%02d", x264_version_major(), x264_version_minor())); 
1508         application->setOrganizationName("LoRd_MuldeR");
1509         application->setOrganizationDomain("mulder.at.gg");
1510         application->setWindowIcon(QIcon(":/icons/movie.ico"));
1511         application->setEventFilter(x264_event_filter);
1512
1513         //Check for supported image formats
1514         QList<QByteArray> supportedFormats = QImageReader::supportedImageFormats();
1515         for(int i = 0; g_x264_imageformats[i]; i++)
1516         {
1517                 if(!supportedFormats.contains(g_x264_imageformats[i]))
1518                 {
1519                         qFatal("Qt initialization error: QImageIOHandler for '%s' missing!", g_x264_imageformats[i]);
1520                         return false;
1521                 }
1522         }
1523         
1524         //Add default translations
1525         /*
1526         QWriteLocker writeLockTranslations(&g_x264_translation.lock);
1527         if(!g_x264_translation.files) g_x264_translation.files = new QMap<QString, QString>();
1528         if(!g_x264_translation.names) g_x264_translation.names = new QMap<QString, QString>();
1529         g_x264_translation.files->insert(X264_DEFAULT_LANGID, "");
1530         g_x264_translation.names->insert(X264_DEFAULT_LANGID, "English");
1531         writeLockTranslations.unlock();
1532         */
1533
1534         //Check for process elevation
1535         if(x264_process_is_elevated() && (!x264_detect_wine()))
1536         {
1537                 QMessageBox messageBox(QMessageBox::Warning, "Simple x264 Launcher", "<nobr>Simple x264 Launcher was started with 'elevated' rights, altough it 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);
1538                 messageBox.addButton("Quit Program (Recommended)", QMessageBox::NoRole);
1539                 messageBox.addButton("Ignore", QMessageBox::NoRole);
1540                 if(messageBox.exec() == 0)
1541                 {
1542                         return false;
1543                 }
1544         }
1545
1546         //Update console icon, if a console is attached
1547 #if QT_VERSION < QT_VERSION_CHECK(5,0,0)
1548         if(g_x264_console_attached && (!x264_detect_wine()))
1549         {
1550                 typedef DWORD (__stdcall *SetConsoleIconFun)(HICON);
1551                 QLibrary kernel32("kernel32.dll");
1552                 if(kernel32.load())
1553                 {
1554                         SetConsoleIconFun SetConsoleIconPtr = (SetConsoleIconFun) kernel32.resolve("SetConsoleIcon");
1555                         QPixmap pixmap = QIcon(":/icons/movie.ico").pixmap(16, 16);
1556                         if((SetConsoleIconPtr != NULL) && (!pixmap.isNull())) SetConsoleIconPtr(pixmap.toWinHICON());
1557                         kernel32.unload();
1558                 }
1559         }
1560 #endif
1561
1562         //Done
1563         qt_initialized = true;
1564         return true;
1565 }
1566
1567 /*
1568  * Suspend or resume process
1569  */
1570 bool x264_suspendProcess(const QProcess *proc, const bool suspend)
1571 {
1572         if(Q_PID pid = proc->pid())
1573         {
1574                 if(suspend)
1575                 {
1576                         return (SuspendThread(pid->hThread) != ((DWORD) -1));
1577                 }
1578                 else
1579                 {
1580                         return (ResumeThread(pid->hThread) != ((DWORD) -1));
1581                 }
1582         }
1583         else
1584         {
1585                 return false;
1586         }
1587 }
1588
1589 /*
1590  * Convert path to short/ANSI path
1591  */
1592 QString x264_path2ansi(const QString &longPath, bool makeLowercase)
1593 {
1594         QString shortPath = longPath;
1595         
1596         const QString longPathNative = QDir::toNativeSeparators(longPath);
1597         DWORD buffSize = GetShortPathNameW(QWCHAR(longPathNative), NULL, NULL);
1598         
1599         if(buffSize > 0)
1600         {
1601                 wchar_t *buffer = (wchar_t*) _malloca(sizeof(wchar_t) * buffSize);
1602                 DWORD result = GetShortPathNameW(QWCHAR(longPathNative), buffer, buffSize);
1603
1604                 if((result > 0) && (result < buffSize))
1605                 {
1606                         shortPath = QDir::fromNativeSeparators(QString::fromUtf16(reinterpret_cast<const unsigned short*>(buffer), result));
1607
1608                         if(makeLowercase)
1609                         {
1610                                 QFileInfo info(shortPath);
1611                                 shortPath = QString("%1/%2").arg(info.absolutePath(), info.fileName().toLower());
1612                         }
1613                 }
1614
1615                 _freea(buffer);
1616                 buffer = NULL;
1617         }
1618
1619         return shortPath;
1620 }
1621
1622 /*
1623  * Set the process priority class for current process
1624  */
1625 bool x264_change_process_priority(const int priority)
1626 {
1627         return x264_change_process_priority(GetCurrentProcess(), priority);
1628 }
1629
1630 /*
1631  * Set the process priority class for specified process
1632  */
1633 bool x264_change_process_priority(const QProcess *proc, const int priority)
1634 {
1635         if(Q_PID qPid = proc->pid())
1636         {
1637                 return x264_change_process_priority(qPid->hProcess, priority);
1638         }
1639         else
1640         {
1641                 return false;
1642         }
1643 }
1644
1645 /*
1646  * Set the process priority class for specified process
1647  */
1648 bool x264_change_process_priority(void *hProcess, const int priority)
1649 {
1650         bool ok = false;
1651
1652         switch(qBound(-2, priority, 2))
1653         {
1654         case 2:
1655                 ok = (SetPriorityClass(hProcess, HIGH_PRIORITY_CLASS) == TRUE);
1656                 break;
1657         case 1:
1658                 if(!(ok = (SetPriorityClass(hProcess, ABOVE_NORMAL_PRIORITY_CLASS) == TRUE)))
1659                 {
1660                         ok = (SetPriorityClass(hProcess, HIGH_PRIORITY_CLASS) == TRUE);
1661                 }
1662                 break;
1663         case 0:
1664                 ok = (SetPriorityClass(hProcess, NORMAL_PRIORITY_CLASS) == TRUE);
1665                 break;
1666         case -1:
1667                 if(!(ok = (SetPriorityClass(hProcess, BELOW_NORMAL_PRIORITY_CLASS) == TRUE)))
1668                 {
1669                         ok = (SetPriorityClass(hProcess, IDLE_PRIORITY_CLASS) == TRUE);
1670                 }
1671                 break;
1672         case -2:
1673                 ok = (SetPriorityClass(hProcess, IDLE_PRIORITY_CLASS) == TRUE);
1674                 break;
1675         }
1676
1677         return ok;
1678 }
1679
1680 /*
1681  * Play a sound (from resources)
1682  */
1683 bool x264_play_sound(const unsigned short uiSoundIdx, const bool bAsync, const wchar_t *alias)
1684 {
1685         if(alias)
1686         {
1687                 return PlaySound(alias, GetModuleHandle(NULL), (SND_ALIAS | (bAsync ? SND_ASYNC : SND_SYNC))) == TRUE;
1688         }
1689         else
1690         {
1691                 return PlaySound(MAKEINTRESOURCE(uiSoundIdx), GetModuleHandle(NULL), (SND_RESOURCE | (bAsync ? SND_ASYNC : SND_SYNC))) == TRUE;
1692         }
1693 }
1694
1695 /*
1696  * Current process ID
1697  */
1698 unsigned int x264_process_id(void)
1699 {
1700         return GetCurrentProcessId();
1701 }
1702
1703 /*
1704  * Current process ID
1705  */
1706 unsigned int x264_process_id(QProcess &process)
1707 {
1708         if(Q_PID pid = process.pid())
1709         {
1710                 return pid->dwProcessId;
1711         }
1712         return NULL;
1713 }
1714
1715 /*
1716  * Make a window blink (to draw user's attention)
1717  */
1718 void x264_blink_window(QWidget *poWindow, unsigned int count, unsigned int delay)
1719 {
1720         static QMutex blinkMutex;
1721
1722         const double maxOpac = 1.0;
1723         const double minOpac = 0.3;
1724         const double delOpac = 0.1;
1725
1726         if(!blinkMutex.tryLock())
1727         {
1728                 qWarning("Blinking is already in progress, skipping!");
1729                 return;
1730         }
1731         
1732         try
1733         {
1734                 const int steps = static_cast<int>(ceil(maxOpac - minOpac) / delOpac);
1735                 const int sleep = static_cast<int>(floor(static_cast<double>(delay) / static_cast<double>(steps)));
1736                 const double opacity = poWindow->windowOpacity();
1737         
1738                 for(unsigned int i = 0; i < count; i++)
1739                 {
1740                         for(double x = maxOpac; x >= minOpac; x -= delOpac)
1741                         {
1742                                 poWindow->setWindowOpacity(x);
1743                                 QApplication::processEvents();
1744                                 Sleep(sleep);
1745                         }
1746
1747                         for(double x = minOpac; x <= maxOpac; x += delOpac)
1748                         {
1749                                 poWindow->setWindowOpacity(x);
1750                                 QApplication::processEvents();
1751                                 Sleep(sleep);
1752                         }
1753                 }
1754
1755                 poWindow->setWindowOpacity(opacity);
1756                 QApplication::processEvents();
1757                 blinkMutex.unlock();
1758         }
1759         catch(...)
1760         {
1761                 blinkMutex.unlock();
1762                 qWarning("Exception error while blinking!");
1763         }
1764 }
1765
1766 /*
1767  * Bring the specifed window to the front
1768  */
1769 static bool x264_bring_to_front(const HWND hWin)
1770 {
1771         if(hWin)
1772         {
1773                 const bool ret = (SetForegroundWindow(hWin) != FALSE);
1774                 SwitchToThisWindow(hWin, TRUE);
1775                 return ret;
1776         }
1777         return false;
1778 }
1779
1780 /*
1781  * Bring the specifed window to the front
1782  */
1783 bool x264_bring_to_front(const QWidget *win)
1784 {
1785         if(win)
1786         {
1787                 return x264_bring_to_front(win->winId());
1788         }
1789         return false;
1790 }
1791
1792 /*
1793  * Bring window of the specifed process to the front (callback)
1794  */
1795 static BOOL CALLBACK x264_bring_process_to_front_helper(HWND hwnd, LPARAM lParam)
1796 {
1797         DWORD processId = *reinterpret_cast<WORD*>(lParam);
1798         DWORD windowProcessId = NULL;
1799         GetWindowThreadProcessId(hwnd, &windowProcessId);
1800         if(windowProcessId == processId)
1801         {
1802                 x264_bring_to_front(hwnd);
1803                 return FALSE;
1804         }
1805         return TRUE;
1806 }
1807
1808 /*
1809  * Bring window of the specifed process to the front
1810  */
1811 bool x264_bring_process_to_front(const unsigned long pid)
1812 {
1813         return EnumWindows(x264_bring_process_to_front_helper, reinterpret_cast<LPARAM>(&pid)) == TRUE;
1814 }
1815
1816 /*
1817  * Check if file is a valid Win32/Win64 executable
1818  */
1819 bool x264_is_executable(const QString &path)
1820 {
1821         bool bIsExecutable = false;
1822         DWORD binaryType;
1823         if(GetBinaryType(QWCHAR(QDir::toNativeSeparators(path)), &binaryType))
1824         {
1825                 bIsExecutable = (binaryType == SCS_32BIT_BINARY || binaryType == SCS_64BIT_BINARY);
1826         }
1827         return bIsExecutable;
1828 }
1829
1830 /*
1831  * Read value from registry
1832  */
1833 QString x264_query_reg_string(const bool bUser, const QString &path, const QString &name)
1834 {
1835         QString result; HKEY hKey = NULL;
1836         if(RegOpenKey((bUser ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE), QWCHAR(path), &hKey) == ERROR_SUCCESS)
1837         {
1838                 const size_t DATA_LEN = 2048; wchar_t data[DATA_LEN];
1839                 DWORD type = REG_NONE, size = sizeof(wchar_t) * DATA_LEN;
1840                 if(RegQueryValueEx(hKey, QWCHAR(name), NULL, &type, ((BYTE*)&data[0]), &size) == ERROR_SUCCESS)
1841                 {
1842                         if((type == REG_SZ) || (type == REG_EXPAND_SZ))
1843                         {
1844                                 result = WCHAR2QSTR(&data[0]);
1845                         }
1846                 }
1847                 RegCloseKey(hKey);
1848         }
1849         return result;
1850 }
1851
1852 /*
1853  * Locate known folder on local system
1854  */
1855 const QString &x264_known_folder(x264_known_folder_t folder_id)
1856 {
1857         static const int CSIDL_FLAG_CREATE = 0x8000;
1858         typedef enum { KF_FLAG_CREATE = 0x00008000 } kf_flags_t;
1859         
1860         struct
1861         {
1862                 const int csidl;
1863                 const GUID guid;
1864         }
1865         static s_folders[] =
1866         {
1867                 { 0x001c, {0xF1B32785,0x6FBA,0x4FCF,{0x9D,0x55,0x7B,0x8E,0x7F,0x15,0x70,0x91}} },  //CSIDL_LOCAL_APPDATA
1868                 { 0x0026, {0x905e63b6,0xc1bf,0x494e,{0xb2,0x9c,0x65,0xb7,0x32,0xd3,0xd2,0x1a}} },  //CSIDL_PROGRAM_FILES
1869                 { 0x0024, {0xF38BF404,0x1D43,0x42F2,{0x93,0x05,0x67,0xDE,0x0B,0x28,0xFC,0x23}} },  //CSIDL_WINDOWS_FOLDER
1870                 { 0x0025, {0x1AC14E77,0x02E7,0x4E5D,{0xB7,0x44,0x2E,0xB1,0xAE,0x51,0x98,0xB7}} },  //CSIDL_SYSTEM_FOLDER
1871         };
1872
1873         size_t folderId = size_t(-1);
1874
1875         switch(folder_id)
1876         {
1877                 case x264_folder_localappdata: folderId = 0; break;
1878                 case x264_folder_programfiles: folderId = 1; break;
1879                 case x264_folder_systroot_dir: folderId = 2; break;
1880                 case x264_folder_systemfolder: folderId = 3; break;
1881         }
1882
1883         if(folderId == size_t(-1))
1884         {
1885                 qWarning("Invalid 'known' folder was requested!");
1886                 return *reinterpret_cast<QString*>(NULL);
1887         }
1888
1889         QReadLocker readLock(&g_x264_known_folder.lock);
1890
1891         //Already in cache?
1892         if(g_x264_known_folder.knownFolders)
1893         {
1894                 if(g_x264_known_folder.knownFolders->contains(folderId))
1895                 {
1896                         return (*g_x264_known_folder.knownFolders)[folderId];
1897                 }
1898         }
1899
1900         //Obtain write lock to initialize
1901         readLock.unlock();
1902         QWriteLocker writeLock(&g_x264_known_folder.lock);
1903
1904         //Still not in cache?
1905         if(g_x264_known_folder.knownFolders)
1906         {
1907                 if(g_x264_known_folder.knownFolders->contains(folderId))
1908                 {
1909                         return (*g_x264_known_folder.knownFolders)[folderId];
1910                 }
1911         }
1912
1913         //Initialize on first call
1914         if(!g_x264_known_folder.knownFolders)
1915         {
1916                 QLibrary shell32("shell32.dll");
1917                 if(shell32.load())
1918                 {
1919                         g_x264_known_folder.getFolderPath =      (SHGetFolderPath_t)      shell32.resolve("SHGetFolderPathW");
1920                         g_x264_known_folder.getKnownFolderPath = (SHGetKnownFolderPath_t) shell32.resolve("SHGetKnownFolderPath");
1921                 }
1922                 g_x264_known_folder.knownFolders = new QMap<size_t, QString>();
1923         }
1924
1925         QString folderPath;
1926
1927         //Now try to get the folder path!
1928         if(g_x264_known_folder.getKnownFolderPath)
1929         {
1930                 WCHAR *path = NULL;
1931                 if(g_x264_known_folder.getKnownFolderPath(s_folders[folderId].guid, KF_FLAG_CREATE, NULL, &path) == S_OK)
1932                 {
1933                         //MessageBoxW(0, path, L"SHGetKnownFolderPath", MB_TOPMOST);
1934                         QDir folderTemp = QDir(QDir::fromNativeSeparators(QString::fromUtf16(reinterpret_cast<const unsigned short*>(path))));
1935                         if(folderTemp.exists())
1936                         {
1937                                 folderPath = folderTemp.canonicalPath();
1938                         }
1939                         CoTaskMemFree(path);
1940                 }
1941         }
1942         else if(g_x264_known_folder.getFolderPath)
1943         {
1944                 WCHAR *path = new WCHAR[4096];
1945                 if(g_x264_known_folder.getFolderPath(NULL, s_folders[folderId].csidl | CSIDL_FLAG_CREATE, NULL, NULL, path) == S_OK)
1946                 {
1947                         //MessageBoxW(0, path, L"SHGetFolderPathW", MB_TOPMOST);
1948                         QDir folderTemp = QDir(QDir::fromNativeSeparators(QString::fromUtf16(reinterpret_cast<const unsigned short*>(path))));
1949                         if(folderTemp.exists())
1950                         {
1951                                 folderPath = folderTemp.canonicalPath();
1952                         }
1953                 }
1954                 X264_DELETE_ARRAY(path);
1955         }
1956
1957         //Update cache
1958         g_x264_known_folder.knownFolders->insert(folderId, folderPath);
1959         return (*g_x264_known_folder.knownFolders)[folderId];
1960 }
1961
1962 /*
1963  * Try to initialize the folder (with *write* access)
1964  */
1965 static QString x264_try_init_folder(const QString &folderPath)
1966 {
1967         static const char *DATA = "Lorem ipsum dolor sit amet, consectetur, adipisci velit!";
1968         
1969         bool success = false;
1970
1971         const QFileInfo folderInfo(folderPath);
1972         const QDir folderDir(folderInfo.absoluteFilePath());
1973
1974         //Create folder, if it does *not* exist yet
1975         for(int i = 0; i < 16; i++)
1976         {
1977                 if(folderDir.exists()) break;
1978                 folderDir.mkpath(".");
1979         }
1980
1981         //Make sure folder exists now *and* is writable
1982         if(folderDir.exists())
1983         {
1984                 const QByteArray testData = QByteArray(DATA);
1985                 for(int i = 0; i < 32; i++)
1986                 {
1987                         QFile testFile(folderDir.absoluteFilePath(QString("~%1.tmp").arg(x264_rand_str())));
1988                         if(testFile.open(QIODevice::ReadWrite | QIODevice::Truncate))
1989                         {
1990                                 if(testFile.write(testData) >= testData.size())
1991                                 {
1992                                         success = true;
1993                                 }
1994                                 testFile.remove();
1995                                 testFile.close();
1996                         }
1997                         if(success) break;
1998                 }
1999         }
2000
2001         return (success ? folderDir.canonicalPath() : QString());
2002 }
2003
2004 /*
2005  * Detect the TEMP directory
2006  */
2007 const QString &x264_temp_directory(void)
2008 {
2009         QReadLocker readLock(&g_x264_temp_folder.lock);
2010
2011         if(g_x264_temp_folder.path)
2012         {
2013                 return *g_x264_temp_folder.path;
2014         }
2015
2016         readLock.unlock();
2017         QWriteLocker writeLock(&g_x264_temp_folder.lock);
2018
2019         if(!g_x264_temp_folder.path)
2020         {
2021                 //Try %TEMP% first
2022                 g_x264_temp_folder.path = new QString(x264_try_init_folder(QDir::temp().absolutePath()));
2023
2024                 //Fall back to %LOCALAPPDATA%, if %TEMP% didn't work
2025                 if(g_x264_temp_folder.path->isEmpty())
2026                 {
2027                         qWarning("%%TEMP%% directory not found -> falling back to %%LOCALAPPDATA%%");
2028                         static const x264_known_folder_t folderId[2] = { x264_folder_localappdata, x264_folder_systroot_dir };
2029                         for(size_t id = 0; (g_x264_temp_folder.path->isEmpty() && (id < 2)); id++)
2030                         {
2031                                 const QString &localAppData = x264_known_folder(x264_folder_localappdata);
2032                                 if(!localAppData.isEmpty())
2033                                 {
2034                                         *g_x264_temp_folder.path = x264_try_init_folder(QString("%1/Temp").arg(localAppData));
2035                                 }
2036                                 else
2037                                 {
2038                                         qWarning("%%LOCALAPPDATA%% directory could not be found!");
2039                                 }
2040                         }
2041                 }
2042
2043                 //Failed to init TEMP folder?
2044                 if(g_x264_temp_folder.path->isEmpty())
2045                 {
2046                         qWarning("Temporary directory could not be initialized !!!");
2047                 }
2048         }
2049
2050         return *g_x264_temp_folder.path;
2051 }
2052
2053 /*
2054  * Display the window's close button
2055  */
2056 bool x264_enable_close_button(const QWidget *win, const bool bEnable)
2057 {
2058         bool ok = false;
2059
2060         if(HMENU hMenu = GetSystemMenu(win->winId(), FALSE))
2061         {
2062                 ok = (EnableMenuItem(hMenu, SC_CLOSE, MF_BYCOMMAND | (bEnable ? MF_ENABLED : MF_GRAYED)) == TRUE);
2063         }
2064
2065         return ok;
2066 }
2067
2068 /*
2069  * Play beep sound
2070  */
2071 bool x264_beep(int beepType)
2072 {
2073         switch(beepType)
2074         {
2075                 case x264_beep_info:    return MessageBeep(MB_ICONASTERISK) == TRUE;    break;
2076                 case x264_beep_warning: return MessageBeep(MB_ICONEXCLAMATION) == TRUE; break;
2077                 case x264_beep_error:   return MessageBeep(MB_ICONHAND) == TRUE;        break;
2078                 default: return false;
2079         }
2080 }
2081
2082 /*
2083  * Shutdown the computer
2084  */
2085 bool x264_shutdown_computer(const QString &message, const unsigned long timeout, const bool forceShutdown)
2086 {
2087         HANDLE hToken = NULL;
2088
2089         if(OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
2090         {
2091                 TOKEN_PRIVILEGES privileges;
2092                 memset(&privileges, 0, sizeof(TOKEN_PRIVILEGES));
2093                 privileges.PrivilegeCount = 1;
2094                 privileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
2095                 
2096                 if(LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &privileges.Privileges[0].Luid))
2097                 {
2098                         if(AdjustTokenPrivileges(hToken, FALSE, &privileges, NULL, NULL, NULL))
2099                         {
2100                                 const DWORD reason = SHTDN_REASON_MAJOR_APPLICATION | SHTDN_REASON_FLAG_PLANNED;
2101                                 return InitiateSystemShutdownEx(NULL, const_cast<wchar_t*>(QWCHAR(message)), timeout, forceShutdown ? TRUE : FALSE, FALSE, reason);
2102                         }
2103                 }
2104         }
2105         
2106         return false;
2107 }
2108
2109 /*
2110  * Check the network connection status
2111  */
2112 int x264_network_status(void)
2113 {
2114         DWORD dwFlags;
2115         const BOOL ret = IsNetworkAlive(&dwFlags);
2116         if(GetLastError() == 0)
2117         {
2118                 return (ret != FALSE) ? x264_network_yes : x264_network_non;
2119         }
2120         return x264_network_err;
2121 }
2122
2123 /*
2124  * Setup QPorcess object
2125  */
2126 void x264_init_process(QProcess &process, const QString &wokringDir, const bool bReplaceTempDir)
2127 {
2128         //Environment variable names
2129         static const char *const s_envvar_names_temp[] =
2130         {
2131                 "TEMP", "TMP", "TMPDIR", "HOME", "USERPROFILE", "HOMEPATH", NULL
2132         };
2133         static const char *const s_envvar_names_remove[] =
2134         {
2135                 "WGETRC", "SYSTEM_WGETRC", "HTTP_PROXY", "FTP_PROXY", "NO_PROXY", "GNUPGHOME", "LC_ALL", "LC_COLLATE", "LC_CTYPE", "LC_MESSAGES", "LC_MONETARY", "LC_NUMERIC", "LC_TIME", "LANG", NULL
2136         };
2137
2138         //Initialize environment
2139         QProcessEnvironment env = process.processEnvironment();
2140         if(env.isEmpty()) env = QProcessEnvironment::systemEnvironment();
2141
2142         //Clean a number of enviroment variables that might affect our tools
2143         for(size_t i = 0; s_envvar_names_remove[i]; i++)
2144         {
2145                 env.remove(QString::fromLatin1(s_envvar_names_remove[i]));
2146                 env.remove(QString::fromLatin1(s_envvar_names_remove[i]).toLower());
2147         }
2148
2149         const QString tempDir = QDir::toNativeSeparators(x264_temp_directory());
2150
2151         //Replace TEMP directory in environment
2152         if(bReplaceTempDir)
2153         {
2154                 for(size_t i = 0; s_envvar_names_temp[i]; i++)
2155                 {
2156                         env.insert(s_envvar_names_temp[i], tempDir);
2157                 }
2158         }
2159
2160         //Setup PATH variable
2161         const QString path = env.value("PATH", QString()).trimmed();
2162         env.insert("PATH", path.isEmpty() ? tempDir : QString("%1;%2").arg(tempDir, path));
2163         
2164         //Setup QPorcess object
2165         process.setWorkingDirectory(wokringDir);
2166         process.setProcessChannelMode(QProcess::MergedChannels);
2167         process.setReadChannel(QProcess::StandardOutput);
2168         process.setProcessEnvironment(env);
2169 }
2170
2171 /*
2172  * Inform the system that it is in use, thereby preventing the system from entering sleep
2173  */
2174 bool x264_set_thread_execution_state(const bool systemRequired)
2175 {
2176         EXECUTION_STATE state = NULL;
2177         if(systemRequired)
2178         {
2179                 state = SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_AWAYMODE_REQUIRED);
2180         }
2181         else
2182         {
2183                 state = SetThreadExecutionState(ES_CONTINUOUS);
2184         }
2185         return (state != NULL);
2186 }
2187
2188 /*
2189  * Exception class
2190  */
2191 X264Exception::X264Exception(const char *message, ...)
2192 :
2193         runtime_error(message)
2194 {
2195         va_list args;
2196         va_start(args, message);
2197         vsnprintf_s(m_message, MAX_MSGLEN, _TRUNCATE, message, args);
2198         va_end(args);
2199 }
2200
2201 /*
2202  * Check for debugger (detect routine)
2203  */
2204 static __forceinline bool x264_check_for_debugger(void)
2205 {
2206         __try
2207         {
2208                 CloseHandle((HANDLE)((DWORD_PTR)-3));
2209         }
2210         __except(1)
2211         {
2212                 return true;
2213         }
2214         __try 
2215         {
2216                 __debugbreak();
2217         }
2218         __except(1) 
2219         {
2220                 return IsDebuggerPresent();
2221         }
2222         return true;
2223 }
2224
2225 /*
2226  * Check for debugger (thread proc)
2227  */
2228 static unsigned int __stdcall x264_debug_thread_proc(LPVOID lpParameter)
2229 {
2230         SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_LOWEST);
2231         forever
2232         {
2233                 if(x264_check_for_debugger())
2234                 {
2235                         x264_fatal_exit(L"Not a debug build. Please unload debugger and try again!");
2236                         return 666;
2237                 }
2238                 x264_sleep(100);
2239         }
2240 }
2241
2242 /*
2243  * Check for debugger (startup routine)
2244  */
2245 static HANDLE x264_debug_thread_init()
2246 {
2247         if(x264_check_for_debugger())
2248         {
2249                 x264_fatal_exit(L"Not a debug build. Please unload debugger and try again!");
2250         }
2251         const uintptr_t h = _beginthreadex(NULL, 0, x264_debug_thread_proc, NULL, 0, NULL);
2252         return (HANDLE)(h^0xdeadbeef);
2253 }
2254
2255 /*
2256  * Fatal application exit
2257  */
2258 #pragma intrinsic(_InterlockedExchange)
2259 void x264_fatal_exit(const wchar_t* exitMessage, const char* errorBoxMessage)
2260 {
2261         static volatile long bFatalFlag = 0L;
2262
2263         if(_InterlockedExchange(&bFatalFlag, 1L) == 0L)
2264         {
2265                 if(GetCurrentThreadId() != g_main_thread_id)
2266                 {
2267                         HANDLE mainThread = OpenThread(THREAD_TERMINATE, FALSE, g_main_thread_id);
2268                         if(mainThread) TerminateThread(mainThread, ULONG_MAX);
2269                 }
2270         
2271                 if(errorBoxMessage)
2272                 {
2273                         MessageBoxA(NULL, errorBoxMessage, "Simple x264 Launcher - GURU MEDITATION", MB_ICONERROR | MB_TOPMOST | MB_TASKMODAL);
2274                 }
2275
2276                 FatalAppExit(0, exitMessage);
2277
2278                 for(;;)
2279                 {
2280                         TerminateProcess(GetCurrentProcess(), -1);
2281                 }
2282         }
2283 }
2284
2285 /*
2286  * Entry point checks
2287  */
2288 static DWORD x264_entry_check(void);
2289 static DWORD g_x264_entry_check_result = x264_entry_check();
2290 static DWORD g_x264_entry_check_flag = 0x789E09B2;
2291 static DWORD x264_entry_check(void)
2292 {
2293         volatile DWORD retVal = 0xA199B5AF;
2294         if(g_x264_entry_check_flag != 0x8761F64D)
2295         {
2296                 x264_fatal_exit(L"Application initialization has failed, take care!");
2297         }
2298         return retVal;
2299 }
2300
2301 /*
2302  * Application entry point (runs before static initializers)
2303  */
2304 extern "C"
2305 {
2306         int WinMainCRTStartup(void);
2307         
2308         int x264_entry_point(void)
2309         {
2310                 if((!X264_DEBUG) && x264_check_for_debugger())
2311                 {
2312                         x264_fatal_exit(L"Not a debug build. Please unload debugger and try again!");
2313                 }
2314                 if(g_x264_entry_check_flag != 0x789E09B2)
2315                 {
2316                         x264_fatal_exit(L"Application initialization has failed, take care!");
2317                 }
2318
2319                 //Zero *before* constructors are called
2320                 X264_ZERO_MEMORY(g_x264_argv);
2321                 X264_ZERO_MEMORY(g_x264_os_version);
2322                 X264_ZERO_MEMORY(g_x264_portable);
2323                 X264_ZERO_MEMORY(g_x264_known_folder);
2324                 X264_ZERO_MEMORY(g_x264_temp_folder);
2325
2326                 //Make sure we will pass the check
2327                 g_x264_entry_check_flag = ~g_x264_entry_check_flag;
2328
2329                 //Now initialize the C Runtime library!
2330                 return WinMainCRTStartup();
2331         }
2332 }
2333
2334 /*
2335  * Initialize debug thread
2336  */
2337 static const HANDLE g_debug_thread = X264_DEBUG ? NULL : x264_debug_thread_init();
2338
2339 /*
2340  * Get number private bytes [debug only]
2341  */
2342 size_t x264_dbg_private_bytes(void)
2343 {
2344 #if X264_DEBUG
2345         PROCESS_MEMORY_COUNTERS_EX memoryCounters;
2346         memoryCounters.cb = sizeof(PROCESS_MEMORY_COUNTERS_EX);
2347         GetProcessMemoryInfo(GetCurrentProcess(), (PPROCESS_MEMORY_COUNTERS) &memoryCounters, sizeof(PROCESS_MEMORY_COUNTERS_EX));
2348         return memoryCounters.PrivateUsage;
2349 #else
2350         THROW("Cannot call this function in a non-debug build!");
2351 #endif //X264_DEBUG
2352 }
2353
2354 /*
2355  * Finalization function
2356  */
2357 void x264_finalization(void)
2358 {
2359         //Destroy Qt application object
2360         QApplication *application = dynamic_cast<QApplication*>(QApplication::instance());
2361         X264_DELETE(application);
2362
2363         //Free STDOUT and STDERR buffers
2364         if(g_x264_console_attached)
2365         {
2366                 if(std::filebuf *tmp = dynamic_cast<std::filebuf*>(std::cout.rdbuf()))
2367                 {
2368                         std::cout.rdbuf(NULL);
2369                         X264_DELETE(tmp);
2370                 }
2371                 if(std::filebuf *tmp = dynamic_cast<std::filebuf*>(std::cerr.rdbuf()))
2372                 {
2373                         std::cerr.rdbuf(NULL);
2374                         X264_DELETE(tmp);
2375                 }
2376         }
2377         
2378         //Clear CLI args
2379         X264_DELETE(g_x264_argv.list);
2380
2381         //Clear folders cache
2382         X264_DELETE(g_x264_known_folder.knownFolders);
2383         X264_DELETE(g_x264_temp_folder.path);
2384 }