OSDN Git Service

3091ee6e32b8e1985033f84d35d3b6ea984ee411
[x264-launcher/x264-launcher.git] / src / global.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Simple x264 Launcher
3 // Copyright (C) 2004-2013 LoRd_MuldeR <MuldeR2@GMX.de>
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 2 of the License, or
8 // (at your option) any later version.
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 //Version
27 #define ENABLE_X264_VERSION_INCLUDE
28 #include "version.h"
29 #undef  ENABLE_X264_VERSION_INCLUDE
30
31 //Windows includes
32 #define NOMINMAX
33 #define WIN32_LEAN_AND_MEAN
34 #include <Windows.h>
35 #include <MMSystem.h>
36 #include <ShellAPI.h>
37
38 //C++ includes
39 #include <stdio.h>
40 #include <string.h>
41 #include <iostream>
42 #include <time.h>
43
44 //VLD
45 #include <vld.h>
46
47 //Qt includes
48 #include <QApplication>
49 #include <QMessageBox>
50 #include <QDir>
51 #include <QUuid>
52 #include <QMap>
53 #include <QDate>
54 #include <QIcon>
55 #include <QPlastiqueStyle>
56 #include <QImageReader>
57 #include <QSharedMemory>
58 #include <QSysInfo>
59 #include <QStringList>
60 #include <QSystemSemaphore>
61 #include <QDesktopServices>
62 #include <QMutex>
63 #include <QTextCodec>
64 #include <QLibrary>
65 #include <QRegExp>
66 #include <QResource>
67 #include <QTranslator>
68 #include <QEventLoop>
69 #include <QTimer>
70 #include <QLibraryInfo>
71 #include <QEvent>
72 #include <QReadLocker>
73 #include <QWriteLocker>
74 #include <QProcess>
75
76 //CRT includes
77 #include <fstream>
78 #include <io.h>
79 #include <fcntl.h>
80 #include <intrin.h>
81 #include <process.h>
82
83 //Debug only includes
84 #if X264_DEBUG
85 #include <Psapi.h>
86 #endif
87
88 //Global vars
89 static bool g_x264_console_attached = false;
90 static QMutex g_x264_message_mutex;
91 static const DWORD g_main_thread_id = GetCurrentThreadId();
92 static FILE *g_x264_log_file = NULL;
93 static QDate g_x264_version_date;
94
95 //Const
96 static const char *g_x264_months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
97 static const char *g_x264_imageformats[] = {"png", "jpg", "gif", "ico", "svg", NULL};
98
99 //Build version
100 static const struct
101 {
102         unsigned int ver_major;
103         unsigned int ver_minor;
104         unsigned int ver_patch;
105         unsigned int ver_build;
106         const char* ver_date;
107         const char* ver_time;
108         unsigned int ver_x264_minimum_rev;
109         unsigned int ver_x264_current_api;
110         unsigned int ver_x264_avs2yuv_ver;
111 }
112 g_x264_version =
113 {
114         (VER_X264_MAJOR),
115         (VER_X264_MINOR),
116         (VER_X264_PATCH),
117         (VER_X264_BUILD),
118         __DATE__,
119         __TIME__,
120         (VER_X264_MINIMUM_REV),
121         (VER_X264_CURRENT_API),
122         (VER_X264_AVS2YUV_VER)
123 };
124
125 //CLI Arguments
126 static struct
127 {
128         QStringList *list;
129         QReadWriteLock lock;
130 }
131 g_x264_argv;
132
133 //OS Version
134 static struct
135 {
136         bool bInitialized;
137         x264_os_version_t version;
138         QReadWriteLock lock;
139 }
140 g_x264_os_version;
141
142 //Wine detection
143 static struct
144 {
145         bool bInitialized;
146         bool bIsWine;
147         QReadWriteLock lock;
148 }
149 g_x264_wine;
150
151 //Portable Mode
152 static struct
153 {
154         bool bInitialized;
155         bool bPortableModeEnabled;
156         QReadWriteLock lock;
157 }
158 g_x264_portable;
159
160 //Known Windows versions - maps marketing names to the actual Windows NT versions
161 const x264_os_version_t x264_winver_win2k = {5,0};
162 const x264_os_version_t x264_winver_winxp = {5,1};
163 const x264_os_version_t x264_winver_xpx64 = {5,2};
164 const x264_os_version_t x264_winver_vista = {6,0};
165 const x264_os_version_t x264_winver_win70 = {6,1};
166 const x264_os_version_t x264_winver_win80 = {6,2};
167 const x264_os_version_t x264_winver_win81 = {6,3};
168
169 //GURU MEDITATION
170 static const char *GURU_MEDITATION = "\n\nGURU MEDITATION !!!\n\n";
171
172 ///////////////////////////////////////////////////////////////////////////////
173 // MACROS
174 ///////////////////////////////////////////////////////////////////////////////
175
176 //String helper
177 #define CLEAN_OUTPUT_STRING(STR) do \
178 { \
179         const char CTRL_CHARS[3] = { '\r', '\n', '\t' }; \
180         for(size_t i = 0; i < 3; i++) \
181         { \
182                 while(char *pos = strchr((STR), CTRL_CHARS[i])) *pos = char(0x20); \
183         } \
184 } \
185 while(0)
186
187 //String helper
188 #define TRIM_LEFT(STR) do \
189 { \
190         const char WHITE_SPACE[4] = { char(0x20), '\r', '\n', '\t' }; \
191         for(size_t i = 0; i < 4; i++) \
192         { \
193                 while(*(STR) == WHITE_SPACE[i]) (STR)++; \
194         } \
195 } \
196 while(0)
197
198 #define X264_ZERO_MEMORY(X) SecureZeroMemory(&X, sizeof(X))
199
200 ///////////////////////////////////////////////////////////////////////////////
201 // COMPILER INFO
202 ///////////////////////////////////////////////////////////////////////////////
203
204 /*
205  * Disclaimer: Parts of the following code were borrowed from MPC-HC project: http://mpc-hc.sf.net/
206  */
207
208 //Compiler detection
209 #if defined(__INTEL_COMPILER)
210         #if (__INTEL_COMPILER >= 1300)
211                 static const char *g_x264_version_compiler = "ICL 13." X264_MAKE_STR(__INTEL_COMPILER_BUILD_DATE);
212         #elif (__INTEL_COMPILER >= 1200)
213                 static const char *g_x264_version_compiler = "ICL 12." X264_MAKE_STR(__INTEL_COMPILER_BUILD_DATE);
214         #elif (__INTEL_COMPILER >= 1100)
215                 static const char *g_x264_version_compiler = "ICL 11.x";
216         #elif (__INTEL_COMPILER >= 1000)
217                 static const char *g_x264_version_compiler = "ICL 10.x";
218         #else
219                 #error Compiler is not supported!
220         #endif
221 #elif defined(_MSC_VER)
222         #if (_MSC_VER == 1800)
223                 #if (_MSC_FULL_VER < 180021005)
224                         static const char *g_x264_version_compiler = "MSVC 2013-Beta";
225                 #elif (_MSC_FULL_VER == 180021005)
226                         static const char *g_x264_version_compiler = "MSVC 2013";
227                 #else
228                         #error Compiler version is not supported yet!
229                 #endif
230         #elif (_MSC_VER == 1700)
231                 #if (_MSC_FULL_VER < 170050727)
232                         static const char *g_x264_version_compiler = "MSVC 2012-Beta";
233                 #elif (_MSC_FULL_VER < 170051020)
234                         static const char *g_x264_version_compiler = "MSVC 2012";
235                 #elif (_MSC_FULL_VER < 170051106)
236                         static const char *g_x264_version_compiler = "MSVC 2012.1-CTP";
237                 #elif (_MSC_FULL_VER < 170060315)
238                         static const char *g_x264_version_compiler = "MSVC 2012.1";
239                 #elif (_MSC_FULL_VER < 170060610)
240                         static const char *g_x264_version_compiler = "MSVC 2012.2";
241                 #elif (_MSC_FULL_VER == 170060610)
242                         static const char *g_x264_version_compiler = "MSVC 2012.3";
243                 #else
244                         #error Compiler version is not supported yet!
245                 #endif
246         #elif (_MSC_VER == 1600)
247                 #if (_MSC_FULL_VER < 160040219)
248                         static const char *g_x264_version_compiler = "MSVC 2010";
249                 #elif (_MSC_FULL_VER == 160040219)
250                         static const char *g_x264_version_compiler = "MSVC 2010-SP1";
251                 #else
252                         #error Compiler version is not supported yet!
253                 #endif
254         #elif (_MSC_VER == 1500)
255                 #if (_MSC_FULL_VER >= 150030729)
256                         static const char *g_x264_version_compiler = "MSVC 2008-SP1";
257                 #else
258                         static const char *g_x264_version_compiler = "MSVC 2008";
259                 #endif
260         #else
261                 #error Compiler is not supported!
262         #endif
263
264         // Note: /arch:SSE and /arch:SSE2 are only available for the x86 platform
265         #if !defined(_M_X64) && defined(_M_IX86_FP)
266                 #if (_M_IX86_FP == 1)
267                         X264_COMPILER_WARNING("SSE instruction set is enabled!")
268                 #elif (_M_IX86_FP == 2)
269                         X264_COMPILER_WARNING("SSE2 (or higher) instruction set is enabled!")
270                 #endif
271         #endif
272 #else
273         #error Compiler is not supported!
274 #endif
275
276 //Architecture detection
277 #if defined(_M_X64)
278         static const char *g_x264_version_arch = "x64";
279 #elif defined(_M_IX86)
280         static const char *g_x264_version_arch = "x86";
281 #else
282         #error Architecture is not supported!
283 #endif
284
285 ///////////////////////////////////////////////////////////////////////////////
286 // GLOBAL FUNCTIONS
287 ///////////////////////////////////////////////////////////////////////////////
288
289 static __forceinline bool x264_check_for_debugger(void);
290
291 /*
292  * Suspend calling thread for N milliseconds
293  */
294 inline void x264_sleep(const unsigned int delay)
295 {
296         Sleep(delay);
297 }
298
299 /*
300  * Global exception handler
301  */
302 LONG WINAPI x264_exception_handler(__in struct _EXCEPTION_POINTERS *ExceptionInfo)
303 {
304         if(GetCurrentThreadId() != g_main_thread_id)
305         {
306                 HANDLE mainThread = OpenThread(THREAD_TERMINATE, FALSE, g_main_thread_id);
307                 if(mainThread) TerminateThread(mainThread, ULONG_MAX);
308         }
309
310         x264_fatal_exit(L"Unhandeled exception handler invoked, application will exit!");
311         return LONG_MAX;
312 }
313
314 /*
315  * Invalid parameters handler
316  */
317 void x264_invalid_param_handler(const wchar_t*, const wchar_t*, const wchar_t*, unsigned int, uintptr_t)
318 {
319         if(GetCurrentThreadId() != g_main_thread_id)
320         {
321                 HANDLE mainThread = OpenThread(THREAD_TERMINATE, FALSE, g_main_thread_id);
322                 if(mainThread) TerminateThread(mainThread, ULONG_MAX);
323         }
324
325         x264_fatal_exit(L"Invalid parameter handler invoked, application will exit!");
326 }
327
328 /*
329  * Change console text color
330  */
331 static void x264_console_color(FILE* file, WORD attributes)
332 {
333         const HANDLE hConsole = (HANDLE)(_get_osfhandle(_fileno(file)));
334         if((hConsole != NULL) && (hConsole != INVALID_HANDLE_VALUE))
335         {
336                 SetConsoleTextAttribute(hConsole, attributes);
337         }
338 }
339
340 /*
341  * Output logging message to console
342  */
343 static void x264_write_console(const int type, const char *msg)
344 {       
345         __try
346         {
347                 if(_isatty(_fileno(stderr)))
348                 {
349                         UINT oldOutputCP = GetConsoleOutputCP();
350                         if(oldOutputCP != CP_UTF8) SetConsoleOutputCP(CP_UTF8);
351
352                         switch(type)
353                         {
354                         case QtCriticalMsg:
355                         case QtFatalMsg:
356                                 x264_console_color(stderr, FOREGROUND_RED | FOREGROUND_INTENSITY);
357                                 fprintf(stderr, GURU_MEDITATION);
358                                 fprintf(stderr, "%s\n", msg);
359                                 fflush(stderr);
360                                 break;
361                         case QtWarningMsg:
362                                 x264_console_color(stderr, FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY);
363                                 fprintf(stderr, "%s\n", msg);
364                                 fflush(stderr);
365                                 break;
366                         default:
367                                 x264_console_color(stderr, FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY);
368                                 fprintf(stderr, "%s\n", msg);
369                                 fflush(stderr);
370                                 break;
371                         }
372         
373                         x264_console_color(stderr, FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED);
374                         if(oldOutputCP != CP_UTF8) SetConsoleOutputCP(oldOutputCP);
375                 }
376         }
377         __except(1)
378         {
379                 /*ignore any exception that might occur here!*/
380         }
381 }
382
383 /*
384  * Output logging message to debugger
385  */
386 static void x264_write_dbg_out(const int type, const char *msg)
387 {       
388         const char *FORMAT = "[sx264l][%c] %s\n";
389
390         __try
391         {
392                 char buffer[512];
393                 const char* input = msg;
394                 TRIM_LEFT(input);
395                 
396                 switch(type)
397                 {
398                 case QtCriticalMsg:
399                 case QtFatalMsg:
400                         _snprintf_s(buffer, 512, _TRUNCATE, FORMAT, 'C', input);
401                         break;
402                 case QtWarningMsg:
403                         _snprintf_s(buffer, 512, _TRUNCATE, FORMAT, 'W', input);
404                         break;
405                 default:
406                         _snprintf_s(buffer, 512, _TRUNCATE, FORMAT, 'I', input);
407                         break;
408                 }
409
410                 char *temp = &buffer[0];
411                 CLEAN_OUTPUT_STRING(temp);
412                 OutputDebugStringA(temp);
413         }
414         __except(1)
415         {
416                 /*ignore any exception that might occur here!*/
417         }
418 }
419
420 /*
421  * Output logging message to logfile
422  */
423 static void x264_write_logfile(const int type, const char *msg)
424 {       
425         const char *FORMAT = "[%c][%04u] %s\r\n";
426
427         __try
428         {
429                 if(g_x264_log_file)
430                 {
431                         char buffer[512];
432                         strncpy_s(buffer, 512, msg, _TRUNCATE);
433
434                         char *temp = &buffer[0];
435                         TRIM_LEFT(temp);
436                         CLEAN_OUTPUT_STRING(temp);
437                         
438                         const unsigned int timestamp = static_cast<unsigned int>(_time64(NULL) % 3600I64);
439
440                         switch(type)
441                         {
442                         case QtCriticalMsg:
443                         case QtFatalMsg:
444                                 fprintf(g_x264_log_file, FORMAT, 'C', timestamp, temp);
445                                 break;
446                         case QtWarningMsg:
447                                 fprintf(g_x264_log_file, FORMAT, 'W', timestamp, temp);
448                                 break;
449                         default:
450                                 fprintf(g_x264_log_file, FORMAT, 'I', timestamp, temp);
451                                 break;
452                         }
453
454                         fflush(g_x264_log_file);
455                 }
456         }
457         __except(1)
458         {
459                 /*ignore any exception that might occur here!*/
460         }
461 }
462
463 /*
464  * Qt message handler
465  */
466 void x264_message_handler(QtMsgType type, const char *msg)
467 {
468         if((!msg) || (!(msg[0])))
469         {
470                 return;
471         }
472
473         QMutexLocker lock(&g_x264_message_mutex);
474
475         if(g_x264_log_file)
476         {
477                 x264_write_logfile(type, msg);
478         }
479
480         if(g_x264_console_attached)
481         {
482                 x264_write_console(type, msg);
483         }
484         else
485         {
486                 x264_write_dbg_out(type, msg);
487         }
488
489         if((type == QtCriticalMsg) || (type == QtFatalMsg))
490         {
491                 lock.unlock();
492                 x264_fatal_exit(L"The application has encountered a critical error and will exit now!", QWCHAR(QString::fromUtf8(msg)));
493         }
494 }
495
496 /*
497  * Initialize the console
498  */
499 void x264_init_console(const QStringList &argv)
500 {
501         bool enableConsole = x264_is_prerelease() || (X264_DEBUG);
502
503         if(_environ)
504         {
505                 wchar_t *logfile = NULL;
506                 size_t logfile_len = 0;
507                 if(!_wdupenv_s(&logfile, &logfile_len, L"X264_LOGFILE"))
508                 {
509                         if(logfile && (logfile_len > 0))
510                         {
511                                 FILE *temp = NULL;
512                                 if(!_wfopen_s(&temp, logfile, L"wb"))
513                                 {
514                                         fprintf(temp, "%c%c%c", char(0xEF), char(0xBB), char(0xBF));
515                                         g_x264_log_file = temp;
516                                 }
517                                 free(logfile);
518                         }
519                 }
520         }
521
522         if(!X264_DEBUG)
523         {
524                 for(int i = 0; i < argv.count(); i++)
525                 {
526                         if(!argv.at(i).compare("--console", Qt::CaseInsensitive))
527                         {
528                                 enableConsole = true;
529                         }
530                         else if(!argv.at(i).compare("--no-console", Qt::CaseInsensitive))
531                         {
532                                 enableConsole = false;
533                         }
534                 }
535         }
536
537         if(enableConsole)
538         {
539                 if(!g_x264_console_attached)
540                 {
541                         if(AllocConsole() != FALSE)
542                         {
543                                 SetConsoleCtrlHandler(NULL, TRUE);
544                                 SetConsoleTitle(L"Simple x264 Launcher | Debug Console");
545                                 SetConsoleOutputCP(CP_UTF8);
546                                 g_x264_console_attached = true;
547                         }
548                 }
549                 
550                 if(g_x264_console_attached)
551                 {
552                         //-------------------------------------------------------------------
553                         //See: http://support.microsoft.com/default.aspx?scid=kb;en-us;105305
554                         //-------------------------------------------------------------------
555                         const int flags = _O_WRONLY | _O_U8TEXT;
556                         int hCrtStdOut = _open_osfhandle((intptr_t) GetStdHandle(STD_OUTPUT_HANDLE), flags);
557                         int hCrtStdErr = _open_osfhandle((intptr_t) GetStdHandle(STD_ERROR_HANDLE),  flags);
558                         FILE *hfStdOut = (hCrtStdOut >= 0) ? _fdopen(hCrtStdOut, "wb") : NULL;
559                         FILE *hfStdErr = (hCrtStdErr >= 0) ? _fdopen(hCrtStdErr, "wb") : NULL;
560                         if(hfStdOut) { *stdout = *hfStdOut; std::cout.rdbuf(new std::filebuf(hfStdOut)); }
561                         if(hfStdErr) { *stderr = *hfStdErr; std::cerr.rdbuf(new std::filebuf(hfStdErr)); }
562                 }
563
564                 HWND hwndConsole = GetConsoleWindow();
565
566                 if((hwndConsole != NULL) && (hwndConsole != INVALID_HANDLE_VALUE))
567                 {
568                         HMENU hMenu = GetSystemMenu(hwndConsole, 0);
569                         EnableMenuItem(hMenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);
570                         RemoveMenu(hMenu, SC_CLOSE, MF_BYCOMMAND);
571
572                         SetWindowPos(hwndConsole, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_FRAMECHANGED);
573                         SetWindowLong(hwndConsole, GWL_STYLE, GetWindowLong(hwndConsole, GWL_STYLE) & (~WS_MAXIMIZEBOX) & (~WS_MINIMIZEBOX));
574                         SetWindowPos(hwndConsole, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_FRAMECHANGED);
575                 }
576         }
577 }
578
579 /*
580  * Initialize the console
581  */
582 void x264_init_console(int argc, char* argv[])
583 {
584         bool enableConsole = x264_is_prerelease() || (X264_DEBUG);
585
586         if(_environ)
587         {
588                 wchar_t *logfile = NULL;
589                 size_t logfile_len = 0;
590                 if(!_wdupenv_s(&logfile, &logfile_len, L"X264_LAUNCHER_LOGFILE"))
591                 {
592                         if(logfile && (logfile_len > 0))
593                         {
594                                 FILE *temp = NULL;
595                                 if(!_wfopen_s(&temp, logfile, L"wb"))
596                                 {
597                                         fprintf(temp, "%c%c%c", 0xEF, 0xBB, 0xBF);
598                                         g_x264_log_file = temp;
599                                 }
600                                 free(logfile);
601                         }
602                 }
603         }
604
605         if(!X264_DEBUG)
606         {
607                 for(int i = 0; i < argc; i++)
608                 {
609                         if(!_stricmp(argv[i], "--console"))
610                         {
611                                 enableConsole = true;
612                         }
613                         else if(!_stricmp(argv[i], "--no-console"))
614                         {
615                                 enableConsole = false;
616                         }
617                 }
618         }
619
620         if(enableConsole)
621         {
622                 if(!g_x264_console_attached)
623                 {
624                         if(AllocConsole())
625                         {
626                                 SetConsoleCtrlHandler(NULL, TRUE);
627                                 SetConsoleTitle(L"Simple x264 Launcher | Debug Console");
628                                 SetConsoleOutputCP(CP_UTF8);
629                                 g_x264_console_attached = true;
630                         }
631                 }
632                 
633                 if(g_x264_console_attached)
634                 {
635                         //-------------------------------------------------------------------
636                         //See: http://support.microsoft.com/default.aspx?scid=kb;en-us;105305
637                         //-------------------------------------------------------------------
638                         const int flags = _O_WRONLY | _O_U8TEXT;
639                         int hCrtStdOut = _open_osfhandle((intptr_t) GetStdHandle(STD_OUTPUT_HANDLE), flags);
640                         int hCrtStdErr = _open_osfhandle((intptr_t) GetStdHandle(STD_ERROR_HANDLE), flags);
641                         FILE *hfStdOut = (hCrtStdOut >= 0) ? _fdopen(hCrtStdOut, "wb") : NULL;
642                         FILE *hfStdErr = (hCrtStdErr >= 0) ? _fdopen(hCrtStdErr, "wb") : NULL;
643                         if(hfStdOut) { *stdout = *hfStdOut; std::cout.rdbuf(new std::filebuf(hfStdOut)); }
644                         if(hfStdErr) { *stderr = *hfStdErr; std::cerr.rdbuf(new std::filebuf(hfStdErr)); }
645                 }
646
647                 HWND hwndConsole = GetConsoleWindow();
648
649                 if((hwndConsole != NULL) && (hwndConsole != INVALID_HANDLE_VALUE))
650                 {
651                         HMENU hMenu = GetSystemMenu(hwndConsole, 0);
652                         EnableMenuItem(hMenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);
653                         RemoveMenu(hMenu, SC_CLOSE, MF_BYCOMMAND);
654
655                         SetWindowPos(hwndConsole, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_FRAMECHANGED);
656                         SetWindowLong(hwndConsole, GWL_STYLE, GetWindowLong(hwndConsole, GWL_STYLE) & (~WS_MAXIMIZEBOX) & (~WS_MINIMIZEBOX));
657                         SetWindowPos(hwndConsole, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_FRAMECHANGED);
658                 }
659         }
660 }
661
662 /*
663  * Version info
664  */
665 unsigned int x264_version_major(void)
666 {
667         return g_x264_version.ver_major;
668 }
669
670 unsigned int x264_version_minor(void)
671 {
672         return (g_x264_version.ver_minor * 10) + (g_x264_version.ver_patch % 10);
673 }
674
675 unsigned int x264_version_build(void)
676 {
677         return g_x264_version.ver_build;
678 }
679
680 const char *x264_version_compiler(void)
681 {
682         return g_x264_version_compiler;
683 }
684
685 const char *x264_version_arch(void)
686 {
687         return g_x264_version_arch;
688 }
689
690 unsigned int x264_version_x264_minimum_rev(void)
691 {
692         return g_x264_version.ver_x264_minimum_rev;
693 }
694
695 unsigned int x264_version_x264_current_api(void)
696 {
697         return g_x264_version.ver_x264_current_api;
698 }
699
700 unsigned int x264_version_x264_avs2yuv_ver(void)
701 {
702         return g_x264_version.ver_x264_avs2yuv_ver;
703 }
704
705 /*
706  * Get CLI arguments
707  */
708 const QStringList &x264_arguments(void)
709 {
710         QReadLocker readLock(&g_x264_argv.lock);
711
712         if(!g_x264_argv.list)
713         {
714                 readLock.unlock();
715                 QWriteLocker writeLock(&g_x264_argv.lock);
716
717                 g_x264_argv.list = new QStringList;
718
719                 int nArgs = 0;
720                 LPWSTR *szArglist = CommandLineToArgvW(GetCommandLineW(), &nArgs);
721
722                 if(NULL != szArglist)
723                 {
724                         for(int i = 0; i < nArgs; i++)
725                         {
726                                 (*g_x264_argv.list) << WCHAR2QSTR(szArglist[i]);
727                         }
728                         LocalFree(szArglist);
729                 }
730                 else
731                 {
732                         qWarning("CommandLineToArgvW() has failed !!!");
733                 }
734         }
735
736         return (*g_x264_argv.list);
737 }
738
739 /*
740  * Check for portable mode
741  */
742 bool x264_portable(void)
743 {
744         QReadLocker readLock(&g_x264_portable.lock);
745
746         if(g_x264_portable.bInitialized)
747         {
748                 return g_x264_portable.bPortableModeEnabled;
749         }
750         
751         readLock.unlock();
752         QWriteLocker writeLock(&g_x264_portable.lock);
753
754         if(!g_x264_portable.bInitialized)
755         {
756                 if(VER_X264_PORTABLE_EDITION)
757                 {
758                         qWarning("Simple x264 Launcher portable edition!\n");
759                         g_x264_portable.bPortableModeEnabled = true;
760                 }
761                 else
762                 {
763                         QString baseName = QFileInfo(QApplication::applicationFilePath()).completeBaseName();
764                         int idx1 = baseName.indexOf("x264", 0, Qt::CaseInsensitive);
765                         int idx2 = baseName.lastIndexOf("portable", -1, Qt::CaseInsensitive);
766                         g_x264_portable.bPortableModeEnabled = (idx1 >= 0) && (idx2 >= 0) && (idx1 < idx2);
767                 }
768                 g_x264_portable.bInitialized = true;
769         }
770         
771         return g_x264_portable.bPortableModeEnabled;
772 }
773
774 /*
775  * Get data path (i.e. path to store config files)
776  */
777 const QString &x264_data_path(void)
778 {
779         static QString pathCache;
780         
781         if(pathCache.isNull())
782         {
783                 if(!x264_portable())
784                 {
785                         pathCache = QDesktopServices::storageLocation(QDesktopServices::DataLocation);
786                 }
787                 if(pathCache.isEmpty() || x264_portable())
788                 {
789                         pathCache = QApplication::applicationDirPath();
790                 }
791                 if(!QDir(pathCache).mkpath("."))
792                 {
793                         qWarning("Data directory could not be created:\n%s\n", pathCache.toUtf8().constData());
794                         pathCache = QDir::currentPath();
795                 }
796         }
797         
798         return pathCache;
799 }
800
801 /*
802  * Get build date date
803  */
804 const QDate &x264_version_date(void)
805 {
806         if(!g_x264_version_date.isValid())
807         {
808                 int date[3] = {0, 0, 0}; char temp[12] = {'\0'};
809                 strncpy_s(temp, 12, g_x264_version.ver_date, _TRUNCATE);
810
811                 if(strlen(temp) == 11)
812                 {
813                         temp[3] = temp[6] = '\0';
814                         date[2] = atoi(&temp[4]);
815                         date[0] = atoi(&temp[7]);
816                         
817                         for(int j = 0; j < 12; j++)
818                         {
819                                 if(!_strcmpi(&temp[0], g_x264_months[j]))
820                                 {
821                                         date[1] = j+1;
822                                         break;
823                                 }
824                         }
825
826                         g_x264_version_date = QDate(date[0], date[1], date[2]);
827                 }
828
829                 if(!g_x264_version_date.isValid())
830                 {
831                         qFatal("Internal error: Date format could not be recognized!");
832                 }
833         }
834
835         return g_x264_version_date;
836 }
837
838 const char *x264_version_time(void)
839 {
840         return g_x264_version.ver_time;
841 }
842
843 bool x264_is_prerelease(void)
844 {
845         return (VER_X264_PRE_RELEASE);
846 }
847
848 /*
849  * CPUID prototype (actual function is in ASM code)
850  */
851 extern "C"
852 {
853         void x264_cpu_cpuid(unsigned int op, unsigned int *eax, unsigned int *ebx, unsigned int *ecx, unsigned int *edx);
854 }
855
856 /*
857  * Detect CPU features
858  */
859 x264_cpu_t x264_detect_cpu_features(const QStringList &argv)
860 {
861         typedef BOOL (WINAPI *IsWow64ProcessFun)(__in HANDLE hProcess, __out PBOOL Wow64Process);
862
863         x264_cpu_t features;
864         SYSTEM_INFO systemInfo;
865         unsigned int CPUInfo[4];
866         char CPUIdentificationString[0x40];
867         char CPUBrandString[0x40];
868
869         memset(&features, 0, sizeof(x264_cpu_t));
870         memset(&systemInfo, 0, sizeof(SYSTEM_INFO));
871         memset(CPUIdentificationString, 0, sizeof(CPUIdentificationString));
872         memset(CPUBrandString, 0, sizeof(CPUBrandString));
873         
874         x264_cpu_cpuid(0, &CPUInfo[0], &CPUInfo[1], &CPUInfo[2], &CPUInfo[3]);
875         memcpy(CPUIdentificationString, &CPUInfo[1], sizeof(int));
876         memcpy(CPUIdentificationString + 4, &CPUInfo[3], sizeof(int));
877         memcpy(CPUIdentificationString + 8, &CPUInfo[2], sizeof(int));
878         features.intel = (_stricmp(CPUIdentificationString, "GenuineIntel") == 0);
879         strncpy_s(features.vendor, 0x40, CPUIdentificationString, _TRUNCATE);
880
881         if(CPUInfo[0] >= 1)
882         {
883                 x264_cpu_cpuid(1, &CPUInfo[0], &CPUInfo[1], &CPUInfo[2], &CPUInfo[3]);
884                 features.mmx = (CPUInfo[3] & 0x800000) || false;
885                 features.sse = (CPUInfo[3] & 0x2000000) || false;
886                 features.sse2 = (CPUInfo[3] & 0x4000000) || false;
887                 features.ssse3 = (CPUInfo[2] & 0x200) || false;
888                 features.sse3 = (CPUInfo[2] & 0x1) || false;
889                 features.ssse3 = (CPUInfo[2] & 0x200) || false;
890                 features.stepping = CPUInfo[0] & 0xf;
891                 features.model = ((CPUInfo[0] >> 4) & 0xf) + (((CPUInfo[0] >> 16) & 0xf) << 4);
892                 features.family = ((CPUInfo[0] >> 8) & 0xf) + ((CPUInfo[0] >> 20) & 0xff);
893                 if(features.sse) features.mmx2 = true; //MMXEXT is a subset of SSE!
894         }
895
896         x264_cpu_cpuid(0x80000000, &CPUInfo[0], &CPUInfo[1], &CPUInfo[2], &CPUInfo[3]);
897         int nExIds = qMax<int>(qMin<int>(CPUInfo[0], 0x80000004), 0x80000000);
898
899         if((_stricmp(CPUIdentificationString, "AuthenticAMD") == 0) && (nExIds >= 0x80000001U))
900         {
901                 x264_cpu_cpuid(0x80000001, &CPUInfo[0], &CPUInfo[1], &CPUInfo[2], &CPUInfo[3]);
902                 features.mmx2 = features.mmx2 || (CPUInfo[3] & 0x00400000U);
903         }
904
905         for(int i = 0x80000002; i <= nExIds; ++i)
906         {
907                 x264_cpu_cpuid(i, &CPUInfo[0], &CPUInfo[1], &CPUInfo[2], &CPUInfo[3]);
908                 switch(i)
909                 {
910                 case 0x80000002:
911                         memcpy(CPUBrandString, CPUInfo, sizeof(CPUInfo));
912                         break;
913                 case 0x80000003:
914                         memcpy(CPUBrandString + 16, CPUInfo, sizeof(CPUInfo));
915                         break;
916                 case 0x80000004:
917                         memcpy(CPUBrandString + 32, CPUInfo, sizeof(CPUInfo));
918                         break;
919                 }
920         }
921
922         strncpy_s(features.brand, 0x40, CPUBrandString, _TRUNCATE);
923
924         if(strlen(features.brand) < 1) strncpy_s(features.brand, 0x40, "Unknown", _TRUNCATE);
925         if(strlen(features.vendor) < 1) strncpy_s(features.vendor, 0x40, "Unknown", _TRUNCATE);
926
927 #if (!(defined(_M_X64) || defined(_M_IA64)))
928         QLibrary Kernel32Lib("kernel32.dll");
929         if(IsWow64ProcessFun IsWow64ProcessPtr = (IsWow64ProcessFun) Kernel32Lib.resolve("IsWow64Process"))
930         {
931                 BOOL x64flag = FALSE;
932                 if(IsWow64ProcessPtr(GetCurrentProcess(), &x64flag))
933                 {
934                         features.x64 = (x64flag == TRUE);
935                 }
936         }
937 #else
938         features.x64 = true;
939 #endif
940
941         DWORD_PTR procAffinity, sysAffinity;
942         if(GetProcessAffinityMask(GetCurrentProcess(), &procAffinity, &sysAffinity))
943         {
944                 for(DWORD_PTR mask = 1; mask; mask <<= 1)
945                 {
946                         features.count += ((sysAffinity & mask) ? (1) : (0));
947                 }
948         }
949         if(features.count < 1)
950         {
951                 GetNativeSystemInfo(&systemInfo);
952                 features.count = qBound(1UL, systemInfo.dwNumberOfProcessors, 64UL);
953         }
954
955         if(argv.count() > 0)
956         {
957                 bool flag = false;
958                 for(int i = 0; i < argv.count(); i++)
959                 {
960                         if(!argv[i].compare("--force-cpu-no-64bit", Qt::CaseInsensitive)) { flag = true; features.x64 = false; }
961                         if(!argv[i].compare("--force-cpu-no-sse", Qt::CaseInsensitive)) { flag = true; features.sse = features.sse2 = features.sse3 = features.ssse3 = false; }
962                         if(!argv[i].compare("--force-cpu-no-intel", Qt::CaseInsensitive)) { flag = true; features.intel = false; }
963                 }
964                 if(flag) qWarning("CPU flags overwritten by user-defined parameters. Take care!\n");
965         }
966
967         return features;
968 }
969
970 /*
971  * Verify a specific Windows version
972  */
973 static bool x264_verify_os_version(const DWORD major, const DWORD minor)
974 {
975         OSVERSIONINFOEXW osvi;
976         DWORDLONG dwlConditionMask = 0;
977
978         //Initialize the OSVERSIONINFOEX structure
979         memset(&osvi, 0, sizeof(OSVERSIONINFOEXW));
980         osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW);
981         osvi.dwMajorVersion = major;
982         osvi.dwMinorVersion = minor;
983         osvi.dwPlatformId = VER_PLATFORM_WIN32_NT;
984
985         //Initialize the condition mask
986         VER_SET_CONDITION(dwlConditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL);
987         VER_SET_CONDITION(dwlConditionMask, VER_MINORVERSION, VER_GREATER_EQUAL);
988         VER_SET_CONDITION(dwlConditionMask, VER_PLATFORMID, VER_EQUAL);
989
990         // Perform the test
991         const BOOL ret = VerifyVersionInfoW(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_PLATFORMID, dwlConditionMask);
992
993         //Error checking
994         if(!ret)
995         {
996                 if(GetLastError() != ERROR_OLD_WIN_VERSION)
997                 {
998                         qWarning("VerifyVersionInfo() system call has failed!");
999                 }
1000         }
1001
1002         return (ret != FALSE);
1003 }
1004
1005 /*
1006  * Determine the *real* Windows version
1007  */
1008 static bool x264_get_real_os_version(unsigned int *major, unsigned int *minor, bool *pbOverride)
1009 {
1010         *major = *minor = 0;
1011         *pbOverride = false;
1012         
1013         //Initialize local variables
1014         OSVERSIONINFOEXW osvi;
1015         memset(&osvi, 0, sizeof(OSVERSIONINFOEXW));
1016         osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW);
1017
1018         //Try GetVersionEx() first
1019         if(GetVersionExW((LPOSVERSIONINFOW)&osvi) == FALSE)
1020         {
1021                 qWarning("GetVersionEx() has failed, cannot detect Windows version!");
1022                 return false;
1023         }
1024
1025         //Make sure we are running on NT
1026         if(osvi.dwPlatformId == VER_PLATFORM_WIN32_NT)
1027         {
1028                 *major = osvi.dwMajorVersion;
1029                 *minor = osvi.dwMinorVersion;
1030         }
1031         else
1032         {
1033                 qWarning("Not running on Windows NT, unsupported operating system!");
1034                 return false;
1035         }
1036
1037         //Determine the real *major* version first
1038         forever
1039         {
1040                 const DWORD nextMajor = (*major) + 1;
1041                 if(x264_verify_os_version(nextMajor, 0))
1042                 {
1043                         *pbOverride = true;
1044                         *major = nextMajor;
1045                         *minor = 0;
1046                         continue;
1047                 }
1048                 break;
1049         }
1050
1051         //Now also determine the real *minor* version
1052         forever
1053         {
1054                 const DWORD nextMinor = (*minor) + 1;
1055                 if(x264_verify_os_version((*major), nextMinor))
1056                 {
1057                         *pbOverride = true;
1058                         *minor = nextMinor;
1059                         continue;
1060                 }
1061                 break;
1062         }
1063
1064         return true;
1065 }
1066
1067 /*
1068  * Get the native operating system version
1069  */
1070 const x264_os_version_t &x264_get_os_version(void)
1071 {
1072         QReadLocker readLock(&g_x264_os_version.lock);
1073
1074         //Already initialized?
1075         if(g_x264_os_version.bInitialized)
1076         {
1077                 return g_x264_os_version.version;
1078         }
1079         
1080         readLock.unlock();
1081         QWriteLocker writeLock(&g_x264_os_version.lock);
1082
1083         //Detect OS version
1084         if(!g_x264_os_version.bInitialized)
1085         {
1086                 unsigned int major, minor; bool oflag;
1087                 if(x264_get_real_os_version(&major, &minor, &oflag))
1088                 {
1089                         g_x264_os_version.version.versionMajor = major;
1090                         g_x264_os_version.version.versionMinor = minor;
1091                         g_x264_os_version.version.overrideFlag = oflag;
1092                         g_x264_os_version.bInitialized = true;
1093                 }
1094                 else
1095                 {
1096                         qWarning("Failed to determin the operating system version!");
1097                 }
1098         }
1099
1100         return g_x264_os_version.version;
1101 }
1102
1103 /*
1104  * Check for compatibility mode
1105  */
1106 static bool x264_check_compatibility_mode(const char *exportName, const char *executableName)
1107 {
1108         QLibrary kernel32("kernel32.dll");
1109
1110         if(exportName != NULL)
1111         {
1112                 if(kernel32.resolve(exportName) != NULL)
1113                 {
1114                         qWarning("Function '%s' exported from 'kernel32.dll' -> Windows compatibility mode!", exportName);
1115                         qFatal("%s", QApplication::tr("Executable '%1' doesn't support Windows compatibility mode.").arg(QString::fromLatin1(executableName)).toLatin1().constData());
1116                         return false;
1117                 }
1118         }
1119
1120         return true;
1121 }
1122
1123 /*
1124  * Check if we are running under wine
1125  */
1126 bool x264_detect_wine(void)
1127 {
1128         QReadLocker readLock(&g_x264_wine.lock);
1129
1130         //Already initialized?
1131         if(g_x264_wine.bInitialized)
1132         {
1133                 return g_x264_wine.bIsWine;
1134         }
1135         
1136         readLock.unlock();
1137         QWriteLocker writeLock(&g_x264_wine.lock);
1138
1139         if(!g_x264_wine.bInitialized)
1140         {
1141                 g_x264_wine.bIsWine = false;
1142                 QLibrary ntdll("ntdll.dll");
1143                 if(ntdll.load())
1144                 {
1145                         if(ntdll.resolve("wine_nt_to_unix_file_name") != NULL) g_x264_wine.bIsWine = true;
1146                         if(ntdll.resolve("wine_get_version") != NULL) g_x264_wine.bIsWine = true;
1147                         ntdll.unload();
1148                 }
1149                 g_x264_wine.bInitialized = true;
1150         }
1151
1152         return g_x264_wine.bIsWine;
1153 }
1154
1155 /*
1156  * Qt event filter
1157  */
1158 static bool x264_event_filter(void *message, long *result)
1159
1160         if((!(X264_DEBUG)) && x264_check_for_debugger())
1161         {
1162                 x264_fatal_exit(L"Not a debug build. Please unload debugger and try again!");
1163         }
1164         
1165         //switch(reinterpret_cast<MSG*>(message)->message)
1166         //{
1167         //case WM_QUERYENDSESSION:
1168         //      qWarning("WM_QUERYENDSESSION message received!");
1169         //      *result = x264_broadcast(x264_event_queryendsession, false) ? TRUE : FALSE;
1170         //      return true;
1171         //case WM_ENDSESSION:
1172         //      qWarning("WM_ENDSESSION message received!");
1173         //      if(reinterpret_cast<MSG*>(message)->wParam == TRUE)
1174         //      {
1175         //              x264_broadcast(x264_event_endsession, false);
1176         //              if(QApplication *app = reinterpret_cast<QApplication*>(QApplication::instance()))
1177         //              {
1178         //                      app->closeAllWindows();
1179         //                      app->quit();
1180         //              }
1181         //              x264_finalization();
1182         //              exit(1);
1183         //      }
1184         //      *result = 0;
1185         //      return true;
1186         //default:
1187         //      /*ignore this message and let Qt handle it*/
1188         //      return false;
1189         //}
1190
1191         return false;
1192 }
1193
1194 /*
1195  * Check for process elevation
1196  */
1197 static bool x264_check_elevation(void)
1198 {
1199         typedef enum { x264_token_elevationType_class = 18, x264_token_elevation_class = 20 } X264_TOKEN_INFORMATION_CLASS;
1200         typedef enum { x264_elevationType_default = 1, x264_elevationType_full, x264_elevationType_limited } X264_TOKEN_ELEVATION_TYPE;
1201
1202         HANDLE hToken = NULL;
1203         bool bIsProcessElevated = false;
1204         
1205         if(OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
1206         {
1207                 X264_TOKEN_ELEVATION_TYPE tokenElevationType;
1208                 DWORD returnLength;
1209                 if(GetTokenInformation(hToken, (TOKEN_INFORMATION_CLASS) x264_token_elevationType_class, &tokenElevationType, sizeof(X264_TOKEN_ELEVATION_TYPE), &returnLength))
1210                 {
1211                         if(returnLength == sizeof(X264_TOKEN_ELEVATION_TYPE))
1212                         {
1213                                 switch(tokenElevationType)
1214                                 {
1215                                 case x264_elevationType_default:
1216                                         qDebug("Process token elevation type: Default -> UAC is disabled.\n");
1217                                         break;
1218                                 case x264_elevationType_full:
1219                                         qWarning("Process token elevation type: Full -> potential security risk!\n");
1220                                         bIsProcessElevated = true;
1221                                         break;
1222                                 case x264_elevationType_limited:
1223                                         qDebug("Process token elevation type: Limited -> not elevated.\n");
1224                                         break;
1225                                 }
1226                         }
1227                 }
1228                 CloseHandle(hToken);
1229         }
1230         else
1231         {
1232                 qWarning("Failed to open process token!");
1233         }
1234
1235         return !bIsProcessElevated;
1236 }
1237
1238 /*
1239  * Initialize Qt framework
1240  */
1241 bool x264_init_qt(int argc, char* argv[])
1242 {
1243         static bool qt_initialized = false;
1244         typedef BOOL (WINAPI *SetDllDirectoryProc)(WCHAR *lpPathName);
1245         const QStringList &arguments = x264_arguments();
1246
1247         //Don't initialized again, if done already
1248         if(qt_initialized)
1249         {
1250                 return true;
1251         }
1252
1253         //Secure DLL loading
1254         QLibrary kernel32("kernel32.dll");
1255         if(kernel32.load())
1256         {
1257                 SetDllDirectoryProc pSetDllDirectory = (SetDllDirectoryProc) kernel32.resolve("SetDllDirectoryW");
1258                 if(pSetDllDirectory != NULL) pSetDllDirectory(L"");
1259         }
1260
1261         //Extract executable name from argv[] array
1262         QString executableName = QLatin1String("x264_launcher.exe");
1263         if(arguments.count() > 0)
1264         {
1265                 static const char *delimiters = "\\/:?";
1266                 executableName = arguments[0].trimmed();
1267                 for(int i = 0; delimiters[i]; i++)
1268                 {
1269                         int temp = executableName.lastIndexOf(QChar(delimiters[i]));
1270                         if(temp >= 0) executableName = executableName.mid(temp + 1);
1271                 }
1272                 executableName = executableName.trimmed();
1273                 if(executableName.isEmpty())
1274                 {
1275                         executableName = QLatin1String("x264_launcher.exe");
1276                 }
1277         }
1278
1279         //Check Qt version
1280 #ifdef QT_BUILD_KEY
1281         qDebug("Using Qt v%s [%s], %s, %s", qVersion(), QLibraryInfo::buildDate().toString(Qt::ISODate).toLatin1().constData(), (qSharedBuild() ? "DLL" : "Static"), QLibraryInfo::buildKey().toLatin1().constData());
1282         qDebug("Compiled with Qt v%s [%s], %s\n", QT_VERSION_STR, QT_PACKAGEDATE_STR, QT_BUILD_KEY);
1283         if(_stricmp(qVersion(), QT_VERSION_STR))
1284         {
1285                 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());
1286                 return false;
1287         }
1288         if(QLibraryInfo::buildKey().compare(QString::fromLatin1(QT_BUILD_KEY), Qt::CaseInsensitive))
1289         {
1290                 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());
1291                 return false;
1292         }
1293 #else
1294         qDebug("Using Qt v%s [%s], %s", qVersion(), QLibraryInfo::buildDate().toString(Qt::ISODate).toLatin1().constData(), (qSharedBuild() ? "DLL" : "Static"));
1295         qDebug("Compiled with Qt v%s [%s]\n", QT_VERSION_STR, QT_PACKAGEDATE_STR);
1296 #endif
1297
1298         //Check the Windows version
1299         const x264_os_version_t &osVersionNo = x264_get_os_version();
1300         if(osVersionNo < x264_winver_winxp)
1301         {
1302                 qFatal("%s", QApplication::tr("Executable '%1' requires Windows XP or later.").arg(executableName).toLatin1().constData());
1303         }
1304
1305         //Supported Windows version?
1306         if(osVersionNo == x264_winver_winxp)
1307         {
1308                 qDebug("Running on Windows XP or Windows XP Media Center Edition.\n");                                          //x264_check_compatibility_mode("GetLargePageMinimum", executableName);
1309         }
1310         else if(osVersionNo == x264_winver_xpx64)
1311         {
1312                 qDebug("Running on Windows Server 2003, Windows Server 2003 R2 or Windows XP x64.\n");          //x264_check_compatibility_mode("GetLocaleInfoEx", executableName);
1313         }
1314         else if(osVersionNo == x264_winver_vista)
1315         {
1316                 qDebug("Running on Windows Vista or Windows Server 2008.\n");                                                           //x264_check_compatibility_mode("CreateRemoteThreadEx", executableName*/);
1317         }
1318         else if(osVersionNo == x264_winver_win70)
1319         {
1320                 qDebug("Running on Windows 7 or Windows Server 2008 R2.\n");                                                            //x264_check_compatibility_mode("CreateFile2", executableName);
1321         }
1322         else if(osVersionNo == x264_winver_win80)
1323         {
1324                 qDebug("Running on Windows 8 or Windows Server 2012.\n");                                                                       //x264_check_compatibility_mode("FindPackagesByPackageFamily", executableName);
1325         }
1326         else if(osVersionNo == x264_winver_win81)
1327         {
1328                 qDebug("Running on Windows 8.1 or Windows Server 2012 R2.\n");                                                          //x264_check_compatibility_mode(NULL, executableName);
1329         }
1330         else
1331         {
1332                 const QString message = QString().sprintf("Running on an unknown WindowsNT-based system (v%u.%u).", osVersionNo.versionMajor, osVersionNo.versionMinor);
1333                 qWarning("%s\n", QUTF8(message));
1334                 MessageBoxW(NULL, QWCHAR(message), L"Simple x264 Launcher", MB_OK | MB_TOPMOST | MB_ICONWARNING);
1335         }
1336
1337         //Check for compat mode
1338         if(osVersionNo.overrideFlag && (osVersionNo <= x264_winver_win81))
1339         {
1340                 qWarning("Windows compatibility mode detected!");
1341                 if(!arguments.contains("--ignore-compat-mode", Qt::CaseInsensitive))
1342                 {
1343                         qFatal("%s", QApplication::tr("Executable '%1' doesn't support Windows compatibility mode.").arg(executableName).toLatin1().constData());
1344                         return false;
1345                 }
1346         }
1347
1348         //Check for Wine
1349         if(x264_detect_wine())
1350         {
1351                 qWarning("It appears we are running under Wine, unexpected things might happen!\n");
1352         }
1353
1354         //Set text Codec for locale
1355         QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"));
1356
1357         //Create Qt application instance
1358         QApplication *application = new QApplication(argc, argv);
1359
1360         //Load plugins from application directory
1361         QCoreApplication::setLibraryPaths(QStringList() << QApplication::applicationDirPath());
1362         qDebug("Library Path:\n%s\n", QUTF8(QApplication::libraryPaths().first()));
1363
1364         //Create Qt application instance and setup version info
1365         application->setApplicationName("Simple x264 Launcher");
1366         application->setApplicationVersion(QString().sprintf("%d.%02d", x264_version_major(), x264_version_minor())); 
1367         application->setOrganizationName("LoRd_MuldeR");
1368         application->setOrganizationDomain("mulder.at.gg");
1369         application->setWindowIcon(QIcon(":/icons/movie.ico"));
1370         application->setEventFilter(x264_event_filter);
1371
1372         //Check for supported image formats
1373         QList<QByteArray> supportedFormats = QImageReader::supportedImageFormats();
1374         for(int i = 0; g_x264_imageformats[i]; i++)
1375         {
1376                 if(!supportedFormats.contains(g_x264_imageformats[i]))
1377                 {
1378                         qFatal("Qt initialization error: QImageIOHandler for '%s' missing!", g_x264_imageformats[i]);
1379                         return false;
1380                 }
1381         }
1382         
1383         //Add default translations
1384         /*
1385         QWriteLocker writeLockTranslations(&g_x264_translation.lock);
1386         if(!g_x264_translation.files) g_x264_translation.files = new QMap<QString, QString>();
1387         if(!g_x264_translation.names) g_x264_translation.names = new QMap<QString, QString>();
1388         g_x264_translation.files->insert(X264_DEFAULT_LANGID, "");
1389         g_x264_translation.names->insert(X264_DEFAULT_LANGID, "English");
1390         writeLockTranslations.unlock();
1391         */
1392
1393         //Check for process elevation
1394         if((!x264_check_elevation()) && (!x264_detect_wine()))
1395         {
1396                 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);
1397                 messageBox.addButton("Quit Program (Recommended)", QMessageBox::NoRole);
1398                 messageBox.addButton("Ignore", QMessageBox::NoRole);
1399                 if(messageBox.exec() == 0)
1400                 {
1401                         return false;
1402                 }
1403         }
1404
1405         //Update console icon, if a console is attached
1406 #if QT_VERSION < QT_VERSION_CHECK(5,0,0)
1407         if(g_x264_console_attached && (!x264_detect_wine()))
1408         {
1409                 typedef DWORD (__stdcall *SetConsoleIconFun)(HICON);
1410                 QLibrary kernel32("kernel32.dll");
1411                 if(kernel32.load())
1412                 {
1413                         SetConsoleIconFun SetConsoleIconPtr = (SetConsoleIconFun) kernel32.resolve("SetConsoleIcon");
1414                         QPixmap pixmap = QIcon(":/icons/movie.ico").pixmap(16, 16);
1415                         if((SetConsoleIconPtr != NULL) && (!pixmap.isNull())) SetConsoleIconPtr(pixmap.toWinHICON());
1416                         kernel32.unload();
1417                 }
1418         }
1419 #endif
1420
1421         //Done
1422         qt_initialized = true;
1423         return true;
1424 }
1425
1426 /*
1427  * Suspend or resume process
1428  */
1429 bool x264_suspendProcess(const QProcess *proc, const bool suspend)
1430 {
1431         if(Q_PID pid = proc->pid())
1432         {
1433                 if(suspend)
1434                 {
1435                         return (SuspendThread(pid->hThread) != ((DWORD) -1));
1436                 }
1437                 else
1438                 {
1439                         return (ResumeThread(pid->hThread) != ((DWORD) -1));
1440                 }
1441         }
1442         else
1443         {
1444                 return false;
1445         }
1446 }
1447
1448 /*
1449  * Convert path to short/ANSI path
1450  */
1451 QString x264_path2ansi(const QString &longPath)
1452 {
1453         QString shortPath = longPath;
1454         
1455         DWORD buffSize = GetShortPathNameW(reinterpret_cast<const wchar_t*>(longPath.utf16()), NULL, NULL);
1456         
1457         if(buffSize > 0)
1458         {
1459                 wchar_t *buffer = new wchar_t[buffSize];
1460                 DWORD result = GetShortPathNameW(reinterpret_cast<const wchar_t*>(longPath.utf16()), buffer, buffSize);
1461
1462                 if((result > 0) && (result < buffSize))
1463                 {
1464                         shortPath = QString::fromUtf16(reinterpret_cast<const unsigned short*>(buffer), result);
1465                 }
1466
1467                 delete[] buffer;
1468                 buffer = NULL;
1469         }
1470
1471         return shortPath;
1472 }
1473
1474 /*
1475  * Set the process priority class for current process
1476  */
1477 bool x264_change_process_priority(const int priority)
1478 {
1479         return x264_change_process_priority(GetCurrentProcess(), priority);
1480 }
1481
1482 /*
1483  * Set the process priority class for specified process
1484  */
1485 bool x264_change_process_priority(const QProcess *proc, const int priority)
1486 {
1487         if(Q_PID qPid = proc->pid())
1488         {
1489                 return x264_change_process_priority(qPid->hProcess, priority);
1490         }
1491         else
1492         {
1493                 return false;
1494         }
1495 }
1496
1497 /*
1498  * Set the process priority class for specified process
1499  */
1500 bool x264_change_process_priority(void *hProcess, const int priority)
1501 {
1502         bool ok = false;
1503
1504         switch(qBound(-2, priority, 2))
1505         {
1506         case 2:
1507                 ok = (SetPriorityClass(hProcess, HIGH_PRIORITY_CLASS) == TRUE);
1508                 break;
1509         case 1:
1510                 if(!(ok = (SetPriorityClass(hProcess, ABOVE_NORMAL_PRIORITY_CLASS) == TRUE)))
1511                 {
1512                         ok = (SetPriorityClass(hProcess, HIGH_PRIORITY_CLASS) == TRUE);
1513                 }
1514                 break;
1515         case 0:
1516                 ok = (SetPriorityClass(hProcess, NORMAL_PRIORITY_CLASS) == TRUE);
1517                 break;
1518         case -1:
1519                 if(!(ok = (SetPriorityClass(hProcess, BELOW_NORMAL_PRIORITY_CLASS) == TRUE)))
1520                 {
1521                         ok = (SetPriorityClass(hProcess, IDLE_PRIORITY_CLASS) == TRUE);
1522                 }
1523                 break;
1524         case -2:
1525                 ok = (SetPriorityClass(hProcess, IDLE_PRIORITY_CLASS) == TRUE);
1526                 break;
1527         }
1528
1529         return ok;
1530 }
1531
1532 /*
1533  * Play a sound (from resources)
1534  */
1535 bool x264_play_sound(const unsigned short uiSoundIdx, const bool bAsync, const wchar_t *alias)
1536 {
1537         if(alias)
1538         {
1539                 return PlaySound(alias, GetModuleHandle(NULL), (SND_ALIAS | (bAsync ? SND_ASYNC : SND_SYNC))) == TRUE;
1540         }
1541         else
1542         {
1543                 return PlaySound(MAKEINTRESOURCE(uiSoundIdx), GetModuleHandle(NULL), (SND_RESOURCE | (bAsync ? SND_ASYNC : SND_SYNC))) == TRUE;
1544         }
1545 }
1546
1547 /*
1548  * Current process ID
1549  */
1550 unsigned int x264_process_id(void)
1551 {
1552         return GetCurrentProcessId();
1553 }
1554
1555 /*
1556  * Make a window blink (to draw user's attention)
1557  */
1558 void x264_blink_window(QWidget *poWindow, unsigned int count, unsigned int delay)
1559 {
1560         static QMutex blinkMutex;
1561
1562         const double maxOpac = 1.0;
1563         const double minOpac = 0.3;
1564         const double delOpac = 0.1;
1565
1566         if(!blinkMutex.tryLock())
1567         {
1568                 qWarning("Blinking is already in progress, skipping!");
1569                 return;
1570         }
1571         
1572         try
1573         {
1574                 const int steps = static_cast<int>(ceil(maxOpac - minOpac) / delOpac);
1575                 const int sleep = static_cast<int>(floor(static_cast<double>(delay) / static_cast<double>(steps)));
1576                 const double opacity = poWindow->windowOpacity();
1577         
1578                 for(unsigned int i = 0; i < count; i++)
1579                 {
1580                         for(double x = maxOpac; x >= minOpac; x -= delOpac)
1581                         {
1582                                 poWindow->setWindowOpacity(x);
1583                                 QApplication::processEvents();
1584                                 Sleep(sleep);
1585                         }
1586
1587                         for(double x = minOpac; x <= maxOpac; x += delOpac)
1588                         {
1589                                 poWindow->setWindowOpacity(x);
1590                                 QApplication::processEvents();
1591                                 Sleep(sleep);
1592                         }
1593                 }
1594
1595                 poWindow->setWindowOpacity(opacity);
1596                 QApplication::processEvents();
1597                 blinkMutex.unlock();
1598         }
1599         catch(...)
1600         {
1601                 blinkMutex.unlock();
1602                 qWarning("Exception error while blinking!");
1603         }
1604 }
1605
1606 /*
1607  * Bring the specifed window to the front
1608  */
1609 bool x264_bring_to_front(const QWidget *win)
1610 {
1611         const bool ret = (SetForegroundWindow(win->winId()) == TRUE);
1612         SwitchToThisWindow(win->winId(), TRUE);
1613         return ret;
1614 }
1615
1616 /*
1617  * Check if file is a valid Win32/Win64 executable
1618  */
1619 bool x264_is_executable(const QString &path)
1620 {
1621         bool bIsExecutable = false;
1622         DWORD binaryType;
1623         if(GetBinaryType(QWCHAR(QDir::toNativeSeparators(path)), &binaryType))
1624         {
1625                 bIsExecutable = (binaryType == SCS_32BIT_BINARY || binaryType == SCS_64BIT_BINARY);
1626         }
1627         return bIsExecutable;
1628 }
1629
1630 /*
1631  * Read value from registry
1632  */
1633 QString x264_query_reg_string(const bool bUser, const QString &path, const QString &name)
1634 {
1635         QString result; HKEY hKey = NULL;
1636         if(RegOpenKey((bUser ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE), QWCHAR(path), &hKey) == ERROR_SUCCESS)
1637         {
1638                 const size_t DATA_LEN = 2048; wchar_t data[DATA_LEN];
1639                 DWORD type = REG_NONE, size = sizeof(wchar_t) * DATA_LEN;
1640                 if(RegQueryValueEx(hKey, QWCHAR(name), NULL, &type, ((BYTE*)&data[0]), &size) == ERROR_SUCCESS)
1641                 {
1642                         if((type == REG_SZ) || (type == REG_EXPAND_SZ))
1643                         {
1644                                 result = WCHAR2QSTR(&data[0]);
1645                         }
1646                 }
1647                 RegCloseKey(hKey);
1648         }
1649         return result;
1650 }
1651
1652 /*
1653  * Display the window's close button
1654  */
1655 bool x264_enable_close_button(const QWidget *win, const bool bEnable)
1656 {
1657         bool ok = false;
1658
1659         if(HMENU hMenu = GetSystemMenu(win->winId(), FALSE))
1660         {
1661                 ok = (EnableMenuItem(hMenu, SC_CLOSE, MF_BYCOMMAND | (bEnable ? MF_ENABLED : MF_GRAYED)) == TRUE);
1662         }
1663
1664         return ok;
1665 }
1666
1667 bool x264_beep(int beepType)
1668 {
1669         switch(beepType)
1670         {
1671                 case x264_beep_info:    return MessageBeep(MB_ICONASTERISK) == TRUE;    break;
1672                 case x264_beep_warning: return MessageBeep(MB_ICONEXCLAMATION) == TRUE; break;
1673                 case x264_beep_error:   return MessageBeep(MB_ICONHAND) == TRUE;        break;
1674                 default: return false;
1675         }
1676 }
1677
1678 /*
1679  * Shutdown the computer
1680  */
1681 bool x264_shutdown_computer(const QString &message, const unsigned long timeout, const bool forceShutdown)
1682 {
1683         HANDLE hToken = NULL;
1684
1685         if(OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
1686         {
1687                 TOKEN_PRIVILEGES privileges;
1688                 memset(&privileges, 0, sizeof(TOKEN_PRIVILEGES));
1689                 privileges.PrivilegeCount = 1;
1690                 privileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
1691                 
1692                 if(LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &privileges.Privileges[0].Luid))
1693                 {
1694                         if(AdjustTokenPrivileges(hToken, FALSE, &privileges, NULL, NULL, NULL))
1695                         {
1696                                 const DWORD reason = SHTDN_REASON_MAJOR_APPLICATION | SHTDN_REASON_FLAG_PLANNED;
1697                                 return InitiateSystemShutdownEx(NULL, const_cast<wchar_t*>(QWCHAR(message)), timeout, forceShutdown ? TRUE : FALSE, FALSE, reason);
1698                         }
1699                 }
1700         }
1701         
1702         return false;
1703 }
1704
1705 /*
1706  * Check for debugger (detect routine)
1707  */
1708 static __forceinline bool x264_check_for_debugger(void)
1709 {
1710         __try
1711         {
1712                 CloseHandle((HANDLE)((DWORD_PTR)-3));
1713         }
1714         __except(1)
1715         {
1716                 return true;
1717         }
1718         __try 
1719         {
1720                 __debugbreak();
1721         }
1722         __except(1) 
1723         {
1724                 return IsDebuggerPresent();
1725         }
1726         return true;
1727 }
1728
1729 /*
1730  * Check for debugger (thread proc)
1731  */
1732 static unsigned int __stdcall x264_debug_thread_proc(LPVOID lpParameter)
1733 {
1734         SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_LOWEST);
1735         forever
1736         {
1737                 if(x264_check_for_debugger())
1738                 {
1739                         x264_fatal_exit(L"Not a debug build. Please unload debugger and try again!");
1740                         return 666;
1741                 }
1742                 x264_sleep(100);
1743         }
1744 }
1745
1746 /*
1747  * Check for debugger (startup routine)
1748  */
1749 static HANDLE x264_debug_thread_init()
1750 {
1751         if(x264_check_for_debugger())
1752         {
1753                 x264_fatal_exit(L"Not a debug build. Please unload debugger and try again!");
1754         }
1755         const uintptr_t h = _beginthreadex(NULL, 0, x264_debug_thread_proc, NULL, 0, NULL);
1756         return (HANDLE)(h^0xdeadbeef);
1757 }
1758
1759 /*
1760  * Fatal application exit
1761  */
1762 #pragma intrinsic(_InterlockedExchange)
1763 void x264_fatal_exit(const wchar_t* exitMessage, const wchar_t* errorBoxMessage)
1764 {
1765         static volatile long bFatalFlag = 0L;
1766
1767         if(_InterlockedExchange(&bFatalFlag, 1L) == 0L)
1768         {
1769                 if(GetCurrentThreadId() != g_main_thread_id)
1770                 {
1771                         HANDLE mainThread = OpenThread(THREAD_TERMINATE, FALSE, g_main_thread_id);
1772                         if(mainThread) TerminateThread(mainThread, ULONG_MAX);
1773                 }
1774         
1775                 if(errorBoxMessage)
1776                 {
1777                         MessageBoxW(NULL, errorBoxMessage, L"Simple x264 Launcher - GURU MEDITATION", MB_ICONERROR | MB_TOPMOST | MB_TASKMODAL);
1778                 }
1779
1780                 FatalAppExit(0, exitMessage);
1781
1782                 for(;;)
1783                 {
1784                         TerminateProcess(GetCurrentProcess(), -1);
1785                 }
1786         }
1787 }
1788
1789 /*
1790  * Entry point checks
1791  */
1792 static DWORD x264_entry_check(void);
1793 static DWORD g_x264_entry_check_result = x264_entry_check();
1794 static DWORD g_x264_entry_check_flag = 0x789E09B2;
1795 static DWORD x264_entry_check(void)
1796 {
1797         volatile DWORD retVal = 0xA199B5AF;
1798         if(g_x264_entry_check_flag != 0x8761F64D)
1799         {
1800                 x264_fatal_exit(L"Application initialization has failed, take care!");
1801         }
1802         return retVal;
1803 }
1804
1805 /*
1806  * Application entry point (runs before static initializers)
1807  */
1808 extern "C"
1809 {
1810         int WinMainCRTStartup(void);
1811         
1812         int x264_entry_point(void)
1813         {
1814                 if((!X264_DEBUG) && x264_check_for_debugger())
1815                 {
1816                         x264_fatal_exit(L"Not a debug build. Please unload debugger and try again!");
1817                 }
1818                 if(g_x264_entry_check_flag != 0x789E09B2)
1819                 {
1820                         x264_fatal_exit(L"Application initialization has failed, take care!");
1821                 }
1822
1823                 //Zero *before* constructors are called
1824                 X264_ZERO_MEMORY(g_x264_argv);
1825                 X264_ZERO_MEMORY(g_x264_os_version);
1826                 X264_ZERO_MEMORY(g_x264_portable);
1827
1828                 //Make sure we will pass the check
1829                 g_x264_entry_check_flag = ~g_x264_entry_check_flag;
1830
1831                 //Now initialize the C Runtime library!
1832                 return WinMainCRTStartup();
1833         }
1834 }
1835
1836 /*
1837  * Initialize debug thread
1838  */
1839 static const HANDLE g_debug_thread = X264_DEBUG ? NULL : x264_debug_thread_init();
1840
1841 /*
1842  * Get number private bytes [debug only]
1843  */
1844 size_t x264_dbg_private_bytes(void)
1845 {
1846 #if X264_DEBUG
1847         PROCESS_MEMORY_COUNTERS_EX memoryCounters;
1848         memoryCounters.cb = sizeof(PROCESS_MEMORY_COUNTERS_EX);
1849         GetProcessMemoryInfo(GetCurrentProcess(), (PPROCESS_MEMORY_COUNTERS) &memoryCounters, sizeof(PROCESS_MEMORY_COUNTERS_EX));
1850         return memoryCounters.PrivateUsage;
1851 #else
1852         throw "Cannot call this function in a non-debug build!";
1853 #endif //X264_DEBUG
1854 }
1855
1856 /*
1857  * Finalization function
1858  */
1859 void x264_finalization(void)
1860 {
1861         //Destroy Qt application object
1862         QApplication *application = dynamic_cast<QApplication*>(QApplication::instance());
1863         X264_DELETE(application);
1864
1865         //Free STDOUT and STDERR buffers
1866         if(g_x264_console_attached)
1867         {
1868                 if(std::filebuf *tmp = dynamic_cast<std::filebuf*>(std::cout.rdbuf()))
1869                 {
1870                         std::cout.rdbuf(NULL);
1871                         X264_DELETE(tmp);
1872                 }
1873                 if(std::filebuf *tmp = dynamic_cast<std::filebuf*>(std::cerr.rdbuf()))
1874                 {
1875                         std::cerr.rdbuf(NULL);
1876                         X264_DELETE(tmp);
1877                 }
1878         }
1879 }