1 ///////////////////////////////////////////////////////////////////////////////
2 // LameXP - Audio Encoder Front-End
3 // Copyright (C) 2004-2013 LoRd_MuldeR <MuldeR2@GMX.de>
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 2 of the License, or
8 // (at your option) any later version, but always including the *additional*
9 // restrictions defined in the "License.txt" file.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License along
17 // with this program; if not, write to the Free Software Foundation, Inc.,
18 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 // http://www.gnu.org/licenses/gpl-2.0.txt
21 ///////////////////////////////////////////////////////////////////////////////
27 #define WIN32_LEAN_AND_MEAN
34 #include <QApplication>
35 #include <QMessageBox>
41 #include <QPlastiqueStyle>
42 #include <QImageReader>
43 #include <QSharedMemory>
45 #include <QStringList>
46 #include <QSystemSemaphore>
52 #include <QTranslator>
55 #include <QLibraryInfo>
57 #include <QReadWriteLock>
58 #include <QReadLocker>
59 #include <QWriteLocker>
63 #define LAMEXP_INC_CONFIG
66 #include "LockedFile.h"
67 #include "strnatcmp.h"
89 //Initialize static Qt plugins
91 #if QT_VERSION < QT_VERSION_CHECK(5,0,0)
95 Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin
)
96 Q_IMPORT_PLUGIN(QICOPlugin
)
100 #define LAMEXP_ZERO_MEMORY(X) SecureZeroMemory(&X, sizeof(X))
103 #define _LAMEXP_MAKE_STR(STR) #STR
104 #define LAMEXP_MAKE_STR(STR) _LAMEXP_MAKE_STR(STR)
107 #define CLEAN_OUTPUT_STRING(STR) do \
109 const char CTRL_CHARS[3] = { '\r', '\n', '\t' }; \
110 for(size_t i = 0; i < 3; i++) \
112 while(char *pos = strchr((STR), CTRL_CHARS[i])) *pos = char(0x20); \
118 #define TRIM_LEFT(STR) do \
120 const char WHITE_SPACE[4] = { char(0x20), '\r', '\n', '\t' }; \
121 for(size_t i = 0; i < 4; i++) \
123 while(*(STR) == WHITE_SPACE[i]) (STR)++; \
128 ///////////////////////////////////////////////////////////////////////////////
130 ///////////////////////////////////////////////////////////////////////////////
132 static const size_t g_lamexp_ipc_slots
= 128;
136 unsigned int command
;
137 unsigned int reserved_1
;
138 unsigned int reserved_2
;
139 char parameter
[4096];
145 unsigned int pos_write
;
146 unsigned int pos_read
;
147 lamexp_ipc_data_t data
[g_lamexp_ipc_slots
];
151 ///////////////////////////////////////////////////////////////////////////////
153 ///////////////////////////////////////////////////////////////////////////////
158 unsigned int ver_major
;
159 unsigned int ver_minor
;
160 unsigned int ver_build
;
161 unsigned int ver_confg
;
162 char *ver_release_name
;
167 (10 * VER_LAMEXP_MINOR_HI
) + VER_LAMEXP_MINOR_LO
,
174 static QDate g_lamexp_version_date
;
175 static const char *g_lamexp_months
[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
176 static const char *g_lamexp_version_raw_date
= __DATE__
;
177 static const char *g_lamexp_version_raw_time
= __TIME__
;
179 //Console attached flag
180 static bool g_lamexp_console_attached
= false;
182 //Official web-site URL
183 static const char *g_lamexp_website_url
= "http://lamexp.sourceforge.net/";
184 static const char *g_lamexp_support_url
= "http://forum.doom9.org/showthread.php?t=157726";
185 static const char *g_lamexp_mulders_url
= "http://muldersoft.com/";
187 //Tool versions (expected versions!)
188 static const unsigned int g_lamexp_toolver_neroaac
= VER_LAMEXP_TOOL_NEROAAC
;
189 static const unsigned int g_lamexp_toolver_fhgaacenc
= VER_LAMEXP_TOOL_FHGAACENC
;
190 static const unsigned int g_lamexp_toolver_qaacenc
= VER_LAMEXP_TOOL_QAAC
;
191 static const unsigned int g_lamexp_toolver_coreaudio
= VER_LAMEXP_TOOL_COREAUDIO
;
196 QMap
<size_t, QString
> *knownFolders
;
199 g_lamexp_known_folder
;
207 g_lamexp_temp_folder
;
212 QMap
<QString
, LockedFile
*> *registry
;
213 QMap
<QString
, unsigned int> *versions
;
214 QMap
<QString
, QString
> *tags
;
222 QMap
<QString
, QString
> *files
;
223 QMap
<QString
, QString
> *names
;
224 QMap
<QString
, unsigned int> *sysid
;
225 QMap
<QString
, unsigned int> *cntry
;
228 g_lamexp_translation
;
233 QTranslator
*instance
;
236 g_lamexp_currentTranslator
;
250 lamexp_os_version_t version
;
259 bool bPortableModeEnabled
;
264 //Win32 Theme support
271 g_lamexp_themes_enabled
;
277 char *semaphore_read
;
278 char *semaphore_read_mutex
;
279 char *semaphore_write
;
280 char *semaphore_write_mutex
;
284 "{21A68A42-6923-43bb-9CF6-64BF151942EE}",
285 "{7A605549-F58C-4d78-B4E5-06EFC34F405B}",
286 "{60AA8D04-F6B8-497d-81EB-0F600F4A65B5}",
287 "{726061D5-1615-4B82-871C-75FD93458E46}",
288 "{1A616023-AA6A-4519-8AF3-F7736E899977}"
292 QSharedMemory
*sharedmem
;
293 QSystemSemaphore
*semaphore_read
;
294 QSystemSemaphore
*semaphore_read_mutex
;
295 QSystemSemaphore
*semaphore_write
;
296 QSystemSemaphore
*semaphore_write_mutex
;
302 static const char *g_lamexp_imageformats
[] = {"bmp", "png", "jpg", "gif", "ico", "xpm", NULL
}; //"svg"
305 static QMutex g_lamexp_message_mutex
;
308 static const DWORD g_main_thread_id
= GetCurrentThreadId();
311 static FILE *g_lamexp_log_file
= NULL
;
314 const char* LAMEXP_DEFAULT_LANGID
= "en";
315 const char* LAMEXP_DEFAULT_TRANSLATION
= "LameXP_EN.qm";
317 //Known Windows versions - maps marketing names to the actual Windows NT versions
318 const lamexp_os_version_t lamexp_winver_win2k
= {5,0};
319 const lamexp_os_version_t lamexp_winver_winxp
= {5,1};
320 const lamexp_os_version_t lamexp_winver_xpx64
= {5,2};
321 const lamexp_os_version_t lamexp_winver_vista
= {6,0};
322 const lamexp_os_version_t lamexp_winver_win70
= {6,1};
323 const lamexp_os_version_t lamexp_winver_win80
= {6,2};
324 const lamexp_os_version_t lamexp_winver_win81
= {6,3};
327 static const char *GURU_MEDITATION
= "\n\nGURU MEDITATION !!!\n\n";
329 ///////////////////////////////////////////////////////////////////////////////
331 ///////////////////////////////////////////////////////////////////////////////
334 * Disclaimer: Parts of the following code were borrowed from MPC-HC project: http://mpc-hc.sf.net/
338 #if defined(__INTEL_COMPILER)
339 #if (__INTEL_COMPILER >= 1300)
340 static const char *g_lamexp_version_compiler
= "ICL 13." LAMEXP_MAKE_STR(__INTEL_COMPILER_BUILD_DATE
);
341 #elif (__INTEL_COMPILER >= 1200)
342 static const char *g_lamexp_version_compiler
= "ICL 12." LAMEXP_MAKE_STR(__INTEL_COMPILER_BUILD_DATE
);
343 #elif (__INTEL_COMPILER >= 1100)
344 static const char *g_lamexp_version_compiler
= "ICL 11.x";
345 #elif (__INTEL_COMPILER >= 1000)
346 static const char *g_lamexp_version_compiler
= "ICL 10.x";
348 #error Compiler is not supported!
350 #elif defined(_MSC_VER)
351 #if (_MSC_VER == 1800)
352 #if (_MSC_FULL_VER < 180021005)
353 static const char *g_lamexp_version_compiler
= "MSVC 2013-Beta";
354 #elif (_MSC_FULL_VER == 180021005)
355 static const char *g_lamexp_version_compiler
= "MSVC 2013";
357 #error Compiler version is not supported yet!
359 #elif (_MSC_VER == 1700)
360 #if (_MSC_FULL_VER < 170050727)
361 static const char *g_lamexp_version_compiler
= "MSVC 2012-Beta";
362 #elif (_MSC_FULL_VER < 170051020)
363 static const char *g_lamexp_version_compiler
= "MSVC 2012";
364 #elif (_MSC_FULL_VER < 170051106)
365 static const char *g_lamexp_version_compiler
= "MSVC 2012.1-CTP";
366 #elif (_MSC_FULL_VER < 170060315)
367 static const char *g_lamexp_version_compiler
= "MSVC 2012.1";
368 #elif (_MSC_FULL_VER < 170060610)
369 static const char *g_lamexp_version_compiler
= "MSVC 2012.2";
370 #elif (_MSC_FULL_VER == 170060610)
371 static const char *g_lamexp_version_compiler
= "MSVC 2012.3";
373 #error Compiler version is not supported yet!
375 #elif (_MSC_VER == 1600)
376 #if (_MSC_FULL_VER < 160040219)
377 static const char *g_lamexp_version_compiler
= "MSVC 2010";
378 #elif (_MSC_FULL_VER == 160040219)
379 static const char *g_lamexp_version_compiler
= "MSVC 2010-SP1";
381 #error Compiler version is not supported yet!
383 #elif (_MSC_VER == 1500)
384 #if (_MSC_FULL_VER >= 150030729)
385 static const char *g_lamexp_version_compiler
= "MSVC 2008-SP1";
387 static const char *g_lamexp_version_compiler
= "MSVC 2008";
390 #error Compiler is not supported!
393 // Note: /arch:SSE and /arch:SSE2 are only available for the x86 platform
394 #if !defined(_M_X64) && defined(_M_IX86_FP)
395 #if (_M_IX86_FP == 1)
396 LAMEXP_COMPILER_WARNING("SSE instruction set is enabled!")
397 #elif (_M_IX86_FP == 2)
398 LAMEXP_COMPILER_WARNING("SSE2 (or higher) instruction set is enabled!")
402 #error Compiler is not supported!
405 //Architecture detection
407 static const char *g_lamexp_version_arch
= "x64";
408 #elif defined(_M_IX86)
409 static const char *g_lamexp_version_arch
= "x86";
411 #error Architecture is not supported!
414 ///////////////////////////////////////////////////////////////////////////////
416 ///////////////////////////////////////////////////////////////////////////////
421 unsigned int lamexp_version_major(void) { return g_lamexp_version
.ver_major
; }
422 unsigned int lamexp_version_minor(void) { return g_lamexp_version
.ver_minor
; }
423 unsigned int lamexp_version_build(void) { return g_lamexp_version
.ver_build
; }
424 unsigned int lamexp_version_confg(void) { return g_lamexp_version
.ver_confg
; }
425 const char *lamexp_version_release(void) { return g_lamexp_version
.ver_release_name
; }
426 const char *lamexp_version_time(void) { return g_lamexp_version_raw_time
; }
427 const char *lamexp_version_compiler(void) { return g_lamexp_version_compiler
; }
428 const char *lamexp_version_arch(void) { return g_lamexp_version_arch
; }
429 unsigned int lamexp_toolver_neroaac(void) { return g_lamexp_toolver_neroaac
; }
430 unsigned int lamexp_toolver_fhgaacenc(void) { return g_lamexp_toolver_fhgaacenc
; }
431 unsigned int lamexp_toolver_qaacenc(void) { return g_lamexp_toolver_qaacenc
; }
432 unsigned int lamexp_toolver_coreaudio(void) { return g_lamexp_toolver_coreaudio
; }
437 const char *lamexp_website_url(void) { return g_lamexp_website_url
; }
438 const char *lamexp_mulders_url(void) { return g_lamexp_mulders_url
; }
439 const char *lamexp_support_url(void) { return g_lamexp_support_url
; }
442 * Check for Demo (pre-release) version
444 bool lamexp_version_demo(void)
447 bool releaseVersion
= false;
448 if(!strncpy_s(buffer
, 128, g_lamexp_version
.ver_release_name
, _TRUNCATE
))
450 char *context
, *prefix
= strtok_s(buffer
, "-,; ", &context
);
453 releaseVersion
= (!_stricmp(prefix
, "Final")) || (!_stricmp(prefix
, "Hotfix"));
456 return (!releaseVersion
);
460 * Calculate expiration date
462 QDate
lamexp_version_expires(void)
464 return lamexp_version_date().addDays(LAMEXP_DEBUG
? 7 : 30);
468 * Convert month string to integer value
470 static int lamexp_month2int(const char *str
)
474 for(int j
= 0; j
< 12; j
++)
476 if(!_strcmpi(str
, g_lamexp_months
[j
]))
487 * Get build date date
489 const QDate
&lamexp_version_date(void)
491 //Format of __DATE__ is defined as: "MMM DD YYYY"
492 if(!g_lamexp_version_date
.isValid())
494 int date
[3] = {0, 0, 0};
495 char temp_m
[4], temp_d
[3], temp_y
[5];
497 temp_m
[0] = g_lamexp_version_raw_date
[0x0];
498 temp_m
[1] = g_lamexp_version_raw_date
[0x1];
499 temp_m
[2] = g_lamexp_version_raw_date
[0x2];
502 temp_d
[0] = g_lamexp_version_raw_date
[0x4];
503 temp_d
[1] = g_lamexp_version_raw_date
[0x5];
506 temp_y
[0] = g_lamexp_version_raw_date
[0x7];
507 temp_y
[1] = g_lamexp_version_raw_date
[0x8];
508 temp_y
[2] = g_lamexp_version_raw_date
[0x9];
509 temp_y
[3] = g_lamexp_version_raw_date
[0xA];
512 date
[0] = atoi(temp_y
);
513 date
[1] = lamexp_month2int(temp_m
);
514 date
[2] = atoi(temp_d
);
516 if((date
[0] > 0) && (date
[1] > 0) && (date
[2] > 0))
519 g_lamexp_version_date
= QDate(date
[0], date
[1], date
[2]);
523 THROW("Internal error: Date format could not be recognized!");
527 return g_lamexp_version_date
;
530 static bool lamexp_verify_os_version(const DWORD major
, const DWORD minor
)
532 OSVERSIONINFOEXW osvi
;
533 DWORDLONG dwlConditionMask
= 0;
535 //Initialize the OSVERSIONINFOEX structure
536 memset(&osvi
, 0, sizeof(OSVERSIONINFOEXW
));
537 osvi
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFOEXW
);
538 osvi
.dwMajorVersion
= major
;
539 osvi
.dwMinorVersion
= minor
;
540 osvi
.dwPlatformId
= VER_PLATFORM_WIN32_NT
;
542 //Initialize the condition mask
543 VER_SET_CONDITION(dwlConditionMask
, VER_MAJORVERSION
, VER_GREATER_EQUAL
);
544 VER_SET_CONDITION(dwlConditionMask
, VER_MINORVERSION
, VER_GREATER_EQUAL
);
545 VER_SET_CONDITION(dwlConditionMask
, VER_PLATFORMID
, VER_EQUAL
);
548 const BOOL ret
= VerifyVersionInfoW(&osvi
, VER_MAJORVERSION
| VER_MINORVERSION
| VER_PLATFORMID
, dwlConditionMask
);
553 if(GetLastError() != ERROR_OLD_WIN_VERSION
)
555 qWarning("VerifyVersionInfo() system call has failed!");
559 return (ret
!= FALSE
);
563 * Determine the *real* Windows version
565 static bool lamexp_get_real_os_version(unsigned int *major
, unsigned int *minor
, bool *pbOverride
)
570 //Initialize local variables
571 OSVERSIONINFOEXW osvi
;
572 memset(&osvi
, 0, sizeof(OSVERSIONINFOEXW
));
573 osvi
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFOEXW
);
575 //Try GetVersionEx() first
576 if(GetVersionExW((LPOSVERSIONINFOW
)&osvi
) == FALSE
)
578 qWarning("GetVersionEx() has failed, cannot detect Windows version!");
582 //Make sure we are running on NT
583 if(osvi
.dwPlatformId
== VER_PLATFORM_WIN32_NT
)
585 *major
= osvi
.dwMajorVersion
;
586 *minor
= osvi
.dwMinorVersion
;
590 qWarning("Not running on Windows NT, unsupported operating system!");
594 //Determine the real *major* version first
597 const DWORD nextMajor
= (*major
) + 1;
598 if(lamexp_verify_os_version(nextMajor
, 0))
608 //Now also determine the real *minor* version
611 const DWORD nextMinor
= (*minor
) + 1;
612 if(lamexp_verify_os_version((*major
), nextMinor
))
625 * Get the native operating system version
627 const lamexp_os_version_t
&lamexp_get_os_version(void)
629 QReadLocker
readLock(&g_lamexp_os_version
.lock
);
631 //Already initialized?
632 if(g_lamexp_os_version
.bInitialized
)
634 return g_lamexp_os_version
.version
;
638 QWriteLocker
writeLock(&g_lamexp_os_version
.lock
);
641 if(!g_lamexp_os_version
.bInitialized
)
643 unsigned int major
, minor
; bool oflag
;
644 if(lamexp_get_real_os_version(&major
, &minor
, &oflag
))
646 g_lamexp_os_version
.version
.versionMajor
= major
;
647 g_lamexp_os_version
.version
.versionMinor
= minor
;
648 g_lamexp_os_version
.version
.overrideFlag
= oflag
;
649 g_lamexp_os_version
.bInitialized
= true;
653 qWarning("Failed to determin the operating system version!");
657 return g_lamexp_os_version
.version
;
661 * Check if we are running under wine
663 bool lamexp_detect_wine(void)
665 static bool isWine
= false;
666 static bool isWine_initialized
= false;
668 if(!isWine_initialized
)
670 QLibrary
ntdll("ntdll.dll");
673 if(ntdll
.resolve("wine_nt_to_unix_file_name") != NULL
) isWine
= true;
674 if(ntdll
.resolve("wine_get_version") != NULL
) isWine
= true;
677 isWine_initialized
= true;
684 * Global exception handler
686 LONG WINAPI
lamexp_exception_handler(__in
struct _EXCEPTION_POINTERS
*ExceptionInfo
)
688 lamexp_fatal_exit(L
"Unhandeled exception handler invoked, application will exit!");
693 * Invalid parameters handler
695 void lamexp_invalid_param_handler(const wchar_t* exp
, const wchar_t* fun
, const wchar_t* fil
, unsigned int, uintptr_t)
697 lamexp_fatal_exit(L
"Invalid parameter handler invoked, application will exit!");
701 * Change console text color
703 static void lamexp_console_color(FILE* file
, WORD attributes
)
705 const HANDLE hConsole
= (HANDLE
)(_get_osfhandle(_fileno(file
)));
706 if((hConsole
!= NULL
) && (hConsole
!= INVALID_HANDLE_VALUE
))
708 SetConsoleTextAttribute(hConsole
, attributes
);
713 * Output logging message to console
715 static void lamexp_write_console(const int type
, const char *msg
)
719 if(_isatty(_fileno(stderr
)))
721 UINT oldOutputCP
= GetConsoleOutputCP();
722 if(oldOutputCP
!= CP_UTF8
) SetConsoleOutputCP(CP_UTF8
);
728 lamexp_console_color(stderr
, FOREGROUND_RED
| FOREGROUND_INTENSITY
);
729 fprintf(stderr
, GURU_MEDITATION
);
730 fprintf(stderr
, "%s\n", msg
);
734 lamexp_console_color(stderr
, FOREGROUND_GREEN
| FOREGROUND_RED
| FOREGROUND_INTENSITY
);
735 fprintf(stderr
, "%s\n", msg
);
739 lamexp_console_color(stderr
, FOREGROUND_BLUE
| FOREGROUND_GREEN
| FOREGROUND_RED
| FOREGROUND_INTENSITY
);
740 fprintf(stderr
, "%s\n", msg
);
745 lamexp_console_color(stderr
, FOREGROUND_BLUE
| FOREGROUND_GREEN
| FOREGROUND_RED
);
746 if(oldOutputCP
!= CP_UTF8
) SetConsoleOutputCP(oldOutputCP
);
751 /*ignore any exception that might occur here!*/
756 * Output logging message to debugger
758 static void lamexp_write_dbg_out(const int type
, const char *msg
)
760 const char *FORMAT
= "[LameXP][%c] %s\n";
765 const char* input
= msg
;
772 _snprintf_s(buffer
, 512, _TRUNCATE
, FORMAT
, 'C', input
);
775 _snprintf_s(buffer
, 512, _TRUNCATE
, FORMAT
, 'W', input
);
778 _snprintf_s(buffer
, 512, _TRUNCATE
, FORMAT
, 'I', input
);
782 char *temp
= &buffer
[0];
783 CLEAN_OUTPUT_STRING(temp
);
784 OutputDebugStringA(temp
);
788 /*ignore any exception that might occur here!*/
793 * Output logging message to logfile
795 static void lamexp_write_logfile(const int type
, const char *msg
)
797 const char *FORMAT
= "[%c][%04u] %s\r\n";
801 if(g_lamexp_log_file
)
804 strncpy_s(buffer
, 512, msg
, _TRUNCATE
);
806 char *temp
= &buffer
[0];
808 CLEAN_OUTPUT_STRING(temp
);
810 const unsigned int timestamp
= static_cast<unsigned int>(_time64(NULL
) % 3600I64
);
816 fprintf(g_lamexp_log_file
, FORMAT
, 'C', timestamp
, temp
);
819 fprintf(g_lamexp_log_file
, FORMAT
, 'W', timestamp
, temp
);
822 fprintf(g_lamexp_log_file
, FORMAT
, 'I', timestamp
, temp
);
826 fflush(g_lamexp_log_file
);
831 /*ignore any exception that might occur here!*/
838 void lamexp_message_handler(QtMsgType type
, const char *msg
)
840 if((!msg
) || (!(msg
[0])))
845 QMutexLocker
lock(&g_lamexp_message_mutex
);
847 if(g_lamexp_log_file
)
849 lamexp_write_logfile(type
, msg
);
852 if(g_lamexp_console_attached
)
854 lamexp_write_console(type
, msg
);
858 lamexp_write_dbg_out(type
, msg
);
861 if((type
== QtCriticalMsg
) || (type
== QtFatalMsg
))
864 lamexp_fatal_exit(L
"The application has encountered a critical error and will exit now!", QWCHAR(QString::fromUtf8(msg
)));
869 * Initialize the console
871 void lamexp_init_console(const QStringList
&argv
)
873 bool enableConsole
= (LAMEXP_DEBUG
) || ((VER_LAMEXP_CONSOLE_ENABLED
) && lamexp_version_demo());
877 wchar_t *logfile
= NULL
;
878 size_t logfile_len
= 0;
879 if(!_wdupenv_s(&logfile
, &logfile_len
, L
"LAMEXP_LOGFILE"))
881 if(logfile
&& (logfile_len
> 0))
884 if(!_wfopen_s(&temp
, logfile
, L
"wb"))
886 fprintf(temp
, "%c%c%c", char(0xEF), char(0xBB), char(0xBF));
887 g_lamexp_log_file
= temp
;
896 for(int i
= 0; i
< argv
.count(); i
++)
898 if(!argv
.at(i
).compare("--console", Qt::CaseInsensitive
))
900 enableConsole
= true;
902 else if(!argv
.at(i
).compare("--no-console", Qt::CaseInsensitive
))
904 enableConsole
= false;
911 if(!g_lamexp_console_attached
)
913 if(AllocConsole() != FALSE
)
915 SetConsoleCtrlHandler(NULL
, TRUE
);
916 SetConsoleTitle(L
"LameXP - Audio Encoder Front-End | Debug Console");
917 SetConsoleOutputCP(CP_UTF8
);
918 g_lamexp_console_attached
= true;
922 if(g_lamexp_console_attached
)
924 //-------------------------------------------------------------------
925 //See: http://support.microsoft.com/default.aspx?scid=kb;en-us;105305
926 //-------------------------------------------------------------------
927 const int flags
= _O_WRONLY
| _O_U8TEXT
;
928 int hCrtStdOut
= _open_osfhandle((intptr_t) GetStdHandle(STD_OUTPUT_HANDLE
), flags
);
929 int hCrtStdErr
= _open_osfhandle((intptr_t) GetStdHandle(STD_ERROR_HANDLE
), flags
);
930 FILE *hfStdOut
= (hCrtStdOut
>= 0) ? _fdopen(hCrtStdOut
, "wb") : NULL
;
931 FILE *hfStdErr
= (hCrtStdErr
>= 0) ? _fdopen(hCrtStdErr
, "wb") : NULL
;
932 if(hfStdOut
) { *stdout
= *hfStdOut
; std::cout
.rdbuf(new std::filebuf(hfStdOut
)); }
933 if(hfStdErr
) { *stderr
= *hfStdErr
; std::cerr
.rdbuf(new std::filebuf(hfStdErr
)); }
936 HWND hwndConsole
= GetConsoleWindow();
938 if((hwndConsole
!= NULL
) && (hwndConsole
!= INVALID_HANDLE_VALUE
))
940 HMENU hMenu
= GetSystemMenu(hwndConsole
, 0);
941 EnableMenuItem(hMenu
, SC_CLOSE
, MF_BYCOMMAND
| MF_GRAYED
);
942 RemoveMenu(hMenu
, SC_CLOSE
, MF_BYCOMMAND
);
944 SetWindowPos(hwndConsole
, HWND_TOP
, 0, 0, 0, 0, SWP_NOMOVE
|SWP_NOSIZE
|SWP_NOZORDER
|SWP_FRAMECHANGED
);
945 SetWindowLong(hwndConsole
, GWL_STYLE
, GetWindowLong(hwndConsole
, GWL_STYLE
) & (~WS_MAXIMIZEBOX
) & (~WS_MINIMIZEBOX
));
946 SetWindowPos(hwndConsole
, HWND_TOP
, 0, 0, 0, 0, SWP_NOMOVE
|SWP_NOSIZE
|SWP_NOZORDER
|SWP_FRAMECHANGED
);
952 * Detect CPU features
954 lamexp_cpu_t
lamexp_detect_cpu_features(const QStringList
&argv
)
956 typedef BOOL (WINAPI
*IsWow64ProcessFun
)(__in HANDLE hProcess
, __out PBOOL Wow64Process
);
958 lamexp_cpu_t features
;
959 SYSTEM_INFO systemInfo
;
960 int CPUInfo
[4] = {-1};
961 char CPUIdentificationString
[0x40];
962 char CPUBrandString
[0x40];
964 memset(&features
, 0, sizeof(lamexp_cpu_t
));
965 memset(&systemInfo
, 0, sizeof(SYSTEM_INFO
));
966 memset(CPUIdentificationString
, 0, sizeof(CPUIdentificationString
));
967 memset(CPUBrandString
, 0, sizeof(CPUBrandString
));
970 memcpy(CPUIdentificationString
, &CPUInfo
[1], sizeof(int));
971 memcpy(CPUIdentificationString
+ 4, &CPUInfo
[3], sizeof(int));
972 memcpy(CPUIdentificationString
+ 8, &CPUInfo
[2], sizeof(int));
973 features
.intel
= (_stricmp(CPUIdentificationString
, "GenuineIntel") == 0);
974 strncpy_s(features
.vendor
, 0x40, CPUIdentificationString
, _TRUNCATE
);
979 features
.mmx
= (CPUInfo
[3] & 0x800000) || false;
980 features
.sse
= (CPUInfo
[3] & 0x2000000) || false;
981 features
.sse2
= (CPUInfo
[3] & 0x4000000) || false;
982 features
.ssse3
= (CPUInfo
[2] & 0x200) || false;
983 features
.sse3
= (CPUInfo
[2] & 0x1) || false;
984 features
.ssse3
= (CPUInfo
[2] & 0x200) || false;
985 features
.stepping
= CPUInfo
[0] & 0xf;
986 features
.model
= ((CPUInfo
[0] >> 4) & 0xf) + (((CPUInfo
[0] >> 16) & 0xf) << 4);
987 features
.family
= ((CPUInfo
[0] >> 8) & 0xf) + ((CPUInfo
[0] >> 20) & 0xff);
990 __cpuid(CPUInfo
, 0x80000000);
991 int nExIds
= qMax
<int>(qMin
<int>(CPUInfo
[0], 0x80000004), 0x80000000);
993 for(int i
= 0x80000002; i
<= nExIds
; ++i
)
999 memcpy(CPUBrandString
, CPUInfo
, sizeof(CPUInfo
));
1002 memcpy(CPUBrandString
+ 16, CPUInfo
, sizeof(CPUInfo
));
1005 memcpy(CPUBrandString
+ 32, CPUInfo
, sizeof(CPUInfo
));
1010 strncpy_s(features
.brand
, 0x40, CPUBrandString
, _TRUNCATE
);
1012 if(strlen(features
.brand
) < 1) strncpy_s(features
.brand
, 0x40, "Unknown", _TRUNCATE
);
1013 if(strlen(features
.vendor
) < 1) strncpy_s(features
.vendor
, 0x40, "Unknown", _TRUNCATE
);
1015 #if (!(defined(_M_X64) || defined(_M_IA64)))
1016 QLibrary
Kernel32Lib("kernel32.dll");
1017 if(IsWow64ProcessFun IsWow64ProcessPtr
= (IsWow64ProcessFun
) Kernel32Lib
.resolve("IsWow64Process"))
1019 BOOL x64flag
= FALSE
;
1020 if(IsWow64ProcessPtr(GetCurrentProcess(), &x64flag
))
1022 features
.x64
= (x64flag
== TRUE
);
1026 features
.x64
= true;
1029 DWORD_PTR procAffinity
, sysAffinity
;
1030 if(GetProcessAffinityMask(GetCurrentProcess(), &procAffinity
, &sysAffinity
))
1032 for(DWORD_PTR mask
= 1; mask
; mask
<<= 1)
1034 features
.count
+= ((sysAffinity
& mask
) ? (1) : (0));
1037 if(features
.count
< 1)
1039 GetNativeSystemInfo(&systemInfo
);
1040 features
.count
= qBound(1UL, systemInfo
.dwNumberOfProcessors
, 64UL);
1043 if(argv
.count() > 0)
1046 for(int i
= 0; i
< argv
.count(); i
++)
1048 if(!argv
[i
].compare("--force-cpu-no-64bit", Qt::CaseInsensitive
)) { flag
= true; features
.x64
= false; }
1049 if(!argv
[i
].compare("--force-cpu-no-sse", Qt::CaseInsensitive
)) { flag
= true; features
.sse
= features
.sse2
= features
.sse3
= features
.ssse3
= false; }
1050 if(!argv
[i
].compare("--force-cpu-no-intel", Qt::CaseInsensitive
)) { flag
= true; features
.intel
= false; }
1052 if(flag
) qWarning("CPU flags overwritten by user-defined parameters. Take care!\n");
1059 * Check for debugger (detect routine)
1061 static __forceinline
bool lamexp_check_for_debugger(void)
1065 CloseHandle((HANDLE
)((DWORD_PTR
)-3));
1077 return IsDebuggerPresent();
1083 * Check for debugger (thread proc)
1085 static unsigned int __stdcall
lamexp_debug_thread_proc(LPVOID lpParameter
)
1087 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_LOWEST
);
1090 if(lamexp_check_for_debugger())
1092 lamexp_fatal_exit(L
"Not a debug build. Please unload debugger and try again!");
1100 * Check for debugger (startup routine)
1102 static HANDLE
lamexp_debug_thread_init()
1104 if(lamexp_check_for_debugger())
1106 lamexp_fatal_exit(L
"Not a debug build. Please unload debugger and try again!");
1108 const uintptr_t h
= _beginthreadex(NULL
, 0, lamexp_debug_thread_proc
, NULL
, 0, NULL
);
1109 return (HANDLE
)(h
^0xdeadbeef);
1113 * Computus according to H. Lichtenberg
1115 static bool lamexp_computus(const QDate
&date
)
1117 int X
= date
.year();
1120 int M
= 15 + (3*K
+ 3) / 4 - (8*K
+ 13) / 25;
1121 int D
= (19*A
+ M
) % 30;
1122 int S
= 2 - (3*K
+ 3) / 4;
1123 int R
= D
/ 29 + (D
/ 28 - D
/ 29) * (A
/ 11);
1124 int OG
= 21 + D
- R
;
1125 int SZ
= 7 - (X
+ X
/ 4 + S
) % 7;
1126 int OE
= 7 - (OG
- SZ
) % 7;
1131 return (date
.month() == 4) && (date
.day() == (OS
- 31));
1135 return (date
.month() == 3) && (date
.day() == OS
);
1140 * Check for Thanksgiving
1142 static bool lamexp_thanksgiving(const QDate
&date
)
1146 switch(QDate(date
.year(), 11, 1).dayOfWeek())
1148 case 1: day
= 25; break;
1149 case 2: day
= 24; break;
1150 case 3: day
= 23; break;
1151 case 4: day
= 22; break;
1152 case 5: day
= 28; break;
1153 case 6: day
= 27; break;
1154 case 7: day
= 26; break;
1157 return (date
.month() == 11) && (date
.day() == day
);
1161 * Initialize app icon
1163 QIcon
lamexp_app_icon(const QDate
*date
, const QTime
*time
)
1165 QDate currentDate
= (date
) ? QDate(*date
) : QDate::currentDate();
1166 QTime currentTime
= (time
) ? QTime(*time
) : QTime::currentTime();
1168 if(lamexp_thanksgiving(currentDate
))
1170 return QIcon(":/MainIcon6.png");
1172 else if(((currentDate
.month() == 12) && (currentDate
.day() == 31) && (currentTime
.hour() >= 20)) || ((currentDate
.month() == 1) && (currentDate
.day() == 1) && (currentTime
.hour() <= 19)))
1174 return QIcon(":/MainIcon5.png");
1176 else if(((currentDate
.month() == 10) && (currentDate
.day() == 31) && (currentTime
.hour() >= 12)) || ((currentDate
.month() == 11) && (currentDate
.day() == 1) && (currentTime
.hour() <= 11)))
1178 return QIcon(":/MainIcon4.png");
1180 else if((currentDate
.month() == 12) && (currentDate
.day() >= 24) && (currentDate
.day() <= 26))
1182 return QIcon(":/MainIcon3.png");
1184 else if(lamexp_computus(currentDate
))
1186 return QIcon(":/MainIcon2.png");
1190 return QIcon(":/MainIcon1.png");
1195 * Broadcast event to all windows
1197 static bool lamexp_broadcast(int eventType
, bool onlyToVisible
)
1199 if(QApplication
*app
= dynamic_cast<QApplication
*>(QApplication::instance()))
1201 qDebug("Broadcasting %d", eventType
);
1204 QEvent
poEvent(static_cast<QEvent::Type
>(eventType
));
1205 QWidgetList list
= app
->topLevelWidgets();
1207 while(!list
.isEmpty())
1209 QWidget
*widget
= list
.takeFirst();
1210 if(!onlyToVisible
|| widget
->isVisible())
1212 if(!app
->sendEvent(widget
, &poEvent
))
1219 qDebug("Broadcast %d done (%s)", eventType
, (allOk
? "OK" : "Stopped"));
1224 qWarning("Broadcast failed, could not get QApplication instance!");
1232 static bool lamexp_event_filter(void *message
, long *result
)
1234 if((!(LAMEXP_DEBUG
)) && lamexp_check_for_debugger())
1236 lamexp_fatal_exit(L
"Not a debug build. Please unload debugger and try again!");
1239 switch(reinterpret_cast<MSG
*>(message
)->message
)
1241 case WM_QUERYENDSESSION
:
1242 qWarning("WM_QUERYENDSESSION message received!");
1243 *result
= lamexp_broadcast(lamexp_event_queryendsession
, false) ? TRUE
: FALSE
;
1246 qWarning("WM_ENDSESSION message received!");
1247 if(reinterpret_cast<MSG
*>(message
)->wParam
== TRUE
)
1249 lamexp_broadcast(lamexp_event_endsession
, false);
1250 if(QApplication
*app
= reinterpret_cast<QApplication
*>(QApplication::instance()))
1252 app
->closeAllWindows();
1255 lamexp_finalization();
1261 /*ignore this message and let Qt handle it*/
1267 * Check for process elevation
1269 static bool lamexp_check_elevation(void)
1271 typedef enum { lamexp_token_elevationType_class
= 18, lamexp_token_elevation_class
= 20 } LAMEXP_TOKEN_INFORMATION_CLASS
;
1272 typedef enum { lamexp_elevationType_default
= 1, lamexp_elevationType_full
, lamexp_elevationType_limited
} LAMEXP_TOKEN_ELEVATION_TYPE
;
1274 HANDLE hToken
= NULL
;
1275 bool bIsProcessElevated
= false;
1277 if(OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY
, &hToken
))
1279 LAMEXP_TOKEN_ELEVATION_TYPE tokenElevationType
;
1281 if(GetTokenInformation(hToken
, (TOKEN_INFORMATION_CLASS
) lamexp_token_elevationType_class
, &tokenElevationType
, sizeof(LAMEXP_TOKEN_ELEVATION_TYPE
), &returnLength
))
1283 if(returnLength
== sizeof(LAMEXP_TOKEN_ELEVATION_TYPE
))
1285 switch(tokenElevationType
)
1287 case lamexp_elevationType_default
:
1288 qDebug("Process token elevation type: Default -> UAC is disabled.\n");
1290 case lamexp_elevationType_full
:
1291 qWarning("Process token elevation type: Full -> potential security risk!\n");
1292 bIsProcessElevated
= true;
1294 case lamexp_elevationType_limited
:
1295 qDebug("Process token elevation type: Limited -> not elevated.\n");
1300 CloseHandle(hToken
);
1304 qWarning("Failed to open process token!");
1307 return !bIsProcessElevated
;
1311 * Initialize Qt framework
1313 bool lamexp_init_qt(int argc
, char* argv
[])
1315 static bool qt_initialized
= false;
1316 typedef BOOL (WINAPI
*SetDllDirectoryProc
)(WCHAR
*lpPathName
);
1317 const QStringList
&arguments
= lamexp_arguments();
1319 //Don't initialized again, if done already
1325 //Secure DLL loading
1326 QLibrary
kernel32("kernel32.dll");
1329 SetDllDirectoryProc pSetDllDirectory
= (SetDllDirectoryProc
) kernel32
.resolve("SetDllDirectoryW");
1330 if(pSetDllDirectory
!= NULL
) pSetDllDirectory(L
"");
1333 //Extract executable name from argv[] array
1334 QString executableName
= QLatin1String("LameXP.exe");
1335 if(arguments
.count() > 0)
1337 static const char *delimiters
= "\\/:?";
1338 executableName
= arguments
[0].trimmed();
1339 for(int i
= 0; delimiters
[i
]; i
++)
1341 int temp
= executableName
.lastIndexOf(QChar(delimiters
[i
]));
1342 if(temp
>= 0) executableName
= executableName
.mid(temp
+ 1);
1344 executableName
= executableName
.trimmed();
1345 if(executableName
.isEmpty())
1347 executableName
= QLatin1String("LameXP.exe");
1353 qDebug("Using Qt v%s [%s], %s, %s", qVersion(), QLibraryInfo::buildDate().toString(Qt::ISODate
).toLatin1().constData(), (qSharedBuild() ? "DLL" : "Static"), QLibraryInfo::buildKey().toLatin1().constData());
1354 qDebug("Compiled with Qt v%s [%s], %s\n", QT_VERSION_STR
, QT_PACKAGEDATE_STR
, QT_BUILD_KEY
);
1355 if(_stricmp(qVersion(), QT_VERSION_STR
))
1357 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());
1360 if(QLibraryInfo::buildKey().compare(QString::fromLatin1(QT_BUILD_KEY
), Qt::CaseInsensitive
))
1362 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());
1366 qDebug("Using Qt v%s [%s], %s", qVersion(), QLibraryInfo::buildDate().toString(Qt::ISODate
).toLatin1().constData(), (qSharedBuild() ? "DLL" : "Static"));
1367 qDebug("Compiled with Qt v%s [%s]\n", QT_VERSION_STR
, QT_PACKAGEDATE_STR
);
1370 //Check the Windows version
1371 const lamexp_os_version_t
&osVersionNo
= lamexp_get_os_version();
1372 if(osVersionNo
< lamexp_winver_winxp
)
1374 qFatal("%s", QApplication::tr("Executable '%1' requires Windows XP or later.").arg(executableName
).toLatin1().constData());
1377 //Supported Windows version?
1378 if(osVersionNo
== lamexp_winver_winxp
)
1380 qDebug("Running on Windows XP or Windows XP Media Center Edition.\n"); //lamexp_check_compatibility_mode("GetLargePageMinimum", executableName);
1382 else if(osVersionNo
== lamexp_winver_xpx64
)
1384 qDebug("Running on Windows Server 2003, Windows Server 2003 R2 or Windows XP x64.\n"); //lamexp_check_compatibility_mode("GetLocaleInfoEx", executableName);
1386 else if(osVersionNo
== lamexp_winver_vista
)
1388 qDebug("Running on Windows Vista or Windows Server 2008.\n"); //lamexp_check_compatibility_mode("CreateRemoteThreadEx", executableName*/);
1390 else if(osVersionNo
== lamexp_winver_win70
)
1392 qDebug("Running on Windows 7 or Windows Server 2008 R2.\n"); //lamexp_check_compatibility_mode("CreateFile2", executableName);
1394 else if(osVersionNo
== lamexp_winver_win80
)
1396 qDebug("Running on Windows 8 or Windows Server 2012.\n"); //lamexp_check_compatibility_mode("FindPackagesByPackageFamily", executableName);
1398 else if(osVersionNo
== lamexp_winver_win81
)
1400 qDebug("Running on Windows 8.1 or Windows Server 2012 R2.\n"); //lamexp_check_compatibility_mode(NULL, executableName);
1404 const QString message
= QString().sprintf("Running on an unknown WindowsNT-based system (v%u.%u).", osVersionNo
.versionMajor
, osVersionNo
.versionMinor
);
1405 qWarning("%s\n", QUTF8(message
));
1406 MessageBoxW(NULL
, QWCHAR(message
), L
"LameXP", MB_OK
| MB_TOPMOST
| MB_ICONWARNING
);
1409 //Check for compat mode
1410 if(osVersionNo
.overrideFlag
&& (osVersionNo
<= lamexp_winver_win81
))
1412 qWarning("Windows compatibility mode detected!");
1413 if(!arguments
.contains("--ignore-compat-mode", Qt::CaseInsensitive
))
1415 qFatal("%s", QApplication::tr("Executable '%1' doesn't support Windows compatibility mode.").arg(executableName
).toLatin1().constData());
1421 if(lamexp_detect_wine())
1423 qWarning("It appears we are running under Wine, unexpected things might happen!\n");
1426 //Set text Codec for locale
1427 QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"));
1429 //Create Qt application instance
1430 QApplication
*application
= new QApplication(argc
, argv
);
1432 //Load plugins from application directory
1433 QCoreApplication::setLibraryPaths(QStringList() << QApplication::applicationDirPath());
1434 qDebug("Library Path:\n%s\n", QUTF8(QApplication::libraryPaths().first()));
1436 //Set application properties
1437 application
->setApplicationName("LameXP - Audio Encoder Front-End");
1438 application
->setApplicationVersion(QString().sprintf("%d.%02d.%04d", lamexp_version_major(), lamexp_version_minor(), lamexp_version_build()));
1439 application
->setOrganizationName("LoRd_MuldeR");
1440 application
->setOrganizationDomain("mulder.at.gg");
1441 application
->setWindowIcon(lamexp_app_icon());
1442 application
->setEventFilter(lamexp_event_filter
);
1444 //Check for supported image formats
1445 QList
<QByteArray
> supportedFormats
= QImageReader::supportedImageFormats();
1446 for(int i
= 0; g_lamexp_imageformats
[i
]; i
++)
1448 if(!supportedFormats
.contains(g_lamexp_imageformats
[i
]))
1450 qFatal("Qt initialization error: QImageIOHandler for '%s' missing!", g_lamexp_imageformats
[i
]);
1455 //Add default translations
1456 QWriteLocker
writeLockTranslations(&g_lamexp_translation
.lock
);
1457 if(!g_lamexp_translation
.files
) g_lamexp_translation
.files
= new QMap
<QString
, QString
>();
1458 if(!g_lamexp_translation
.names
) g_lamexp_translation
.names
= new QMap
<QString
, QString
>();
1459 g_lamexp_translation
.files
->insert(LAMEXP_DEFAULT_LANGID
, "");
1460 g_lamexp_translation
.names
->insert(LAMEXP_DEFAULT_LANGID
, "English");
1461 writeLockTranslations
.unlock();
1463 //Check for process elevation
1464 if((!lamexp_check_elevation()) && (!lamexp_detect_wine()))
1466 QMessageBox
messageBox(QMessageBox::Warning
, "LameXP", "<nobr>LameXP was started with 'elevated' rights, altough LameXP does not need these rights.<br>Running an applications with unnecessary rights is a potential security risk!</nobr>", QMessageBox::NoButton
, NULL
, Qt::Dialog
| Qt::MSWindowsFixedSizeDialogHint
| Qt::WindowStaysOnTopHint
);
1467 messageBox
.addButton("Quit Program (Recommended)", QMessageBox::NoRole
);
1468 messageBox
.addButton("Ignore", QMessageBox::NoRole
);
1469 if(messageBox
.exec() == 0)
1475 //Update console icon, if a console is attached
1476 #if QT_VERSION < QT_VERSION_CHECK(5,0,0)
1477 if(g_lamexp_console_attached
&& (!lamexp_detect_wine()))
1479 typedef DWORD (__stdcall
*SetConsoleIconFun
)(HICON
);
1480 QLibrary
kernel32("kernel32.dll");
1483 SetConsoleIconFun SetConsoleIconPtr
= (SetConsoleIconFun
) kernel32
.resolve("SetConsoleIcon");
1484 if(SetConsoleIconPtr
!= NULL
) SetConsoleIconPtr(QIcon(":/icons/sound.png").pixmap(16, 16).toWinHICON());
1491 qt_initialized
= true;
1498 int lamexp_init_ipc(void)
1500 QWriteLocker
writeLock(&g_lamexp_ipc_ptr
.lock
);
1502 if(g_lamexp_ipc_ptr
.sharedmem
&& g_lamexp_ipc_ptr
.semaphore_read
&& g_lamexp_ipc_ptr
.semaphore_write
&& g_lamexp_ipc_ptr
.semaphore_read_mutex
&& g_lamexp_ipc_ptr
.semaphore_write_mutex
)
1507 g_lamexp_ipc_ptr
.semaphore_read
= new QSystemSemaphore(QString(g_lamexp_ipc_uuid
.semaphore_read
), 0);
1508 g_lamexp_ipc_ptr
.semaphore_write
= new QSystemSemaphore(QString(g_lamexp_ipc_uuid
.semaphore_write
), 0);
1509 g_lamexp_ipc_ptr
.semaphore_read_mutex
= new QSystemSemaphore(QString(g_lamexp_ipc_uuid
.semaphore_read_mutex
), 0);
1510 g_lamexp_ipc_ptr
.semaphore_write_mutex
= new QSystemSemaphore(QString(g_lamexp_ipc_uuid
.semaphore_write_mutex
), 0);
1512 if(g_lamexp_ipc_ptr
.semaphore_read
->error() != QSystemSemaphore::NoError
)
1514 QString errorMessage
= g_lamexp_ipc_ptr
.semaphore_read
->errorString();
1515 LAMEXP_DELETE(g_lamexp_ipc_ptr
.semaphore_read
);
1516 LAMEXP_DELETE(g_lamexp_ipc_ptr
.semaphore_write
);
1517 LAMEXP_DELETE(g_lamexp_ipc_ptr
.semaphore_read_mutex
);
1518 LAMEXP_DELETE(g_lamexp_ipc_ptr
.semaphore_write_mutex
);
1519 qFatal("Failed to create system smaphore: %s", QUTF8(errorMessage
));
1522 if(g_lamexp_ipc_ptr
.semaphore_write
->error() != QSystemSemaphore::NoError
)
1524 QString errorMessage
= g_lamexp_ipc_ptr
.semaphore_write
->errorString();
1525 LAMEXP_DELETE(g_lamexp_ipc_ptr
.semaphore_read
);
1526 LAMEXP_DELETE(g_lamexp_ipc_ptr
.semaphore_write
);
1527 LAMEXP_DELETE(g_lamexp_ipc_ptr
.semaphore_read_mutex
);
1528 LAMEXP_DELETE(g_lamexp_ipc_ptr
.semaphore_write_mutex
);
1529 qFatal("Failed to create system smaphore: %s", QUTF8(errorMessage
));
1532 if(g_lamexp_ipc_ptr
.semaphore_read_mutex
->error() != QSystemSemaphore::NoError
)
1534 QString errorMessage
= g_lamexp_ipc_ptr
.semaphore_read_mutex
->errorString();
1535 LAMEXP_DELETE(g_lamexp_ipc_ptr
.semaphore_read
);
1536 LAMEXP_DELETE(g_lamexp_ipc_ptr
.semaphore_write
);
1537 LAMEXP_DELETE(g_lamexp_ipc_ptr
.semaphore_read_mutex
);
1538 LAMEXP_DELETE(g_lamexp_ipc_ptr
.semaphore_write_mutex
);
1539 qFatal("Failed to create system smaphore: %s", QUTF8(errorMessage
));
1542 if(g_lamexp_ipc_ptr
.semaphore_write_mutex
->error() != QSystemSemaphore::NoError
)
1544 QString errorMessage
= g_lamexp_ipc_ptr
.semaphore_write_mutex
->errorString();
1545 LAMEXP_DELETE(g_lamexp_ipc_ptr
.semaphore_read
);
1546 LAMEXP_DELETE(g_lamexp_ipc_ptr
.semaphore_write
);
1547 LAMEXP_DELETE(g_lamexp_ipc_ptr
.semaphore_read_mutex
);
1548 LAMEXP_DELETE(g_lamexp_ipc_ptr
.semaphore_write_mutex
);
1549 qFatal("Failed to create system smaphore: %s", QUTF8(errorMessage
));
1553 g_lamexp_ipc_ptr
.sharedmem
= new QSharedMemory(QString(g_lamexp_ipc_uuid
.sharedmem
), NULL
);
1555 if(!g_lamexp_ipc_ptr
.sharedmem
->create(sizeof(lamexp_ipc_t
)))
1557 if(g_lamexp_ipc_ptr
.sharedmem
->error() == QSharedMemory::AlreadyExists
)
1559 g_lamexp_ipc_ptr
.sharedmem
->attach();
1560 if(g_lamexp_ipc_ptr
.sharedmem
->error() == QSharedMemory::NoError
)
1566 QString errorMessage
= g_lamexp_ipc_ptr
.sharedmem
->errorString();
1567 LAMEXP_DELETE(g_lamexp_ipc_ptr
.sharedmem
);
1568 qFatal("Failed to attach to shared memory: %s", QUTF8(errorMessage
));
1574 QString errorMessage
= g_lamexp_ipc_ptr
.sharedmem
->errorString();
1575 LAMEXP_DELETE(g_lamexp_ipc_ptr
.sharedmem
);
1576 qFatal("Failed to create shared memory: %s", QUTF8(errorMessage
));
1581 memset(g_lamexp_ipc_ptr
.sharedmem
->data(), 0, sizeof(lamexp_ipc_t
));
1582 g_lamexp_ipc_ptr
.semaphore_write
->release(g_lamexp_ipc_slots
);
1583 g_lamexp_ipc_ptr
.semaphore_read_mutex
->release();
1584 g_lamexp_ipc_ptr
.semaphore_write_mutex
->release();
1592 void lamexp_ipc_send(unsigned int command
, const char* message
)
1594 QReadLocker
readLock(&g_lamexp_ipc_ptr
.lock
);
1596 if(!g_lamexp_ipc_ptr
.sharedmem
|| !g_lamexp_ipc_ptr
.semaphore_read
|| !g_lamexp_ipc_ptr
.semaphore_write
|| !g_lamexp_ipc_ptr
.semaphore_read_mutex
|| !g_lamexp_ipc_ptr
.semaphore_write_mutex
)
1598 THROW("Shared memory for IPC not initialized yet.");
1601 lamexp_ipc_data_t ipc_data
;
1602 memset(&ipc_data
, 0, sizeof(lamexp_ipc_data_t
));
1603 ipc_data
.command
= command
;
1607 strncpy_s(ipc_data
.parameter
, 4096, message
, _TRUNCATE
);
1610 if(g_lamexp_ipc_ptr
.semaphore_write
->acquire())
1612 if(g_lamexp_ipc_ptr
.semaphore_write_mutex
->acquire())
1614 lamexp_ipc_t
*ptr
= reinterpret_cast<lamexp_ipc_t
*>(g_lamexp_ipc_ptr
.sharedmem
->data());
1615 memcpy(&ptr
->data
[ptr
->pos_write
], &ipc_data
, sizeof(lamexp_ipc_data_t
));
1616 ptr
->pos_write
= (ptr
->pos_write
+ 1) % g_lamexp_ipc_slots
;
1617 g_lamexp_ipc_ptr
.semaphore_read
->release();
1618 g_lamexp_ipc_ptr
.semaphore_write_mutex
->release();
1626 void lamexp_ipc_read(unsigned int *command
, char* message
, size_t buffSize
)
1628 QReadLocker
readLock(&g_lamexp_ipc_ptr
.lock
);
1633 if(!g_lamexp_ipc_ptr
.sharedmem
|| !g_lamexp_ipc_ptr
.semaphore_read
|| !g_lamexp_ipc_ptr
.semaphore_write
|| !g_lamexp_ipc_ptr
.semaphore_read_mutex
|| !g_lamexp_ipc_ptr
.semaphore_write_mutex
)
1635 THROW("Shared memory for IPC not initialized yet.");
1638 lamexp_ipc_data_t ipc_data
;
1639 memset(&ipc_data
, 0, sizeof(lamexp_ipc_data_t
));
1641 if(g_lamexp_ipc_ptr
.semaphore_read
->acquire())
1643 if(g_lamexp_ipc_ptr
.semaphore_read_mutex
->acquire())
1645 lamexp_ipc_t
*ptr
= reinterpret_cast<lamexp_ipc_t
*>(g_lamexp_ipc_ptr
.sharedmem
->data());
1646 memcpy(&ipc_data
, &ptr
->data
[ptr
->pos_read
], sizeof(lamexp_ipc_data_t
));
1647 ptr
->pos_read
= (ptr
->pos_read
+ 1) % g_lamexp_ipc_slots
;
1648 g_lamexp_ipc_ptr
.semaphore_write
->release();
1649 g_lamexp_ipc_ptr
.semaphore_read_mutex
->release();
1651 if(!(ipc_data
.reserved_1
|| ipc_data
.reserved_2
))
1653 *command
= ipc_data
.command
;
1654 strncpy_s(message
, buffSize
, ipc_data
.parameter
, _TRUNCATE
);
1658 qWarning("Malformed IPC message, will be ignored");
1665 * Check for LameXP "portable" mode
1667 bool lamexp_portable_mode(void)
1669 QReadLocker
readLock(&g_lamexp_portable
.lock
);
1671 if(g_lamexp_portable
.bInitialized
)
1673 return g_lamexp_portable
.bPortableModeEnabled
;
1677 QWriteLocker
writeLock(&g_lamexp_portable
.lock
);
1679 if(!g_lamexp_portable
.bInitialized
)
1681 if(VER_LAMEXP_PORTABLE_EDITION
)
1683 qWarning("LameXP portable edition!\n");
1684 g_lamexp_portable
.bPortableModeEnabled
= true;
1688 QString baseName
= QFileInfo(QApplication::applicationFilePath()).completeBaseName();
1689 int idx1
= baseName
.indexOf("lamexp", 0, Qt::CaseInsensitive
);
1690 int idx2
= baseName
.lastIndexOf("portable", -1, Qt::CaseInsensitive
);
1691 g_lamexp_portable
.bPortableModeEnabled
= (idx1
>= 0) && (idx2
>= 0) && (idx1
< idx2
);
1693 g_lamexp_portable
.bInitialized
= true;
1696 return g_lamexp_portable
.bPortableModeEnabled
;
1700 * Get a random string
1702 QString
lamexp_rand_str(const bool bLong
)
1704 const QUuid uuid
= QUuid::createUuid().toString();
1706 const unsigned int u1
= uuid
.data1
;
1707 const unsigned int u2
= (((unsigned int)(uuid
.data2
)) << 16) | ((unsigned int)(uuid
.data3
));
1708 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]));
1709 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]));
1711 return bLong
? QString().sprintf("%08x%08x%08x%08x", u1
, u2
, u3
, u4
) : QString().sprintf("%08x%08x", (u1
^ u2
), (u3
^ u4
));
1716 * Try to initialize the folder (with *write* access)
1718 static QString
lamexp_try_init_folder(const QString
&folderPath
)
1720 bool success
= false;
1722 const QFileInfo
folderInfo(folderPath
);
1723 const QDir
folderDir(folderInfo
.absoluteFilePath());
1725 //Create folder, if it does *not* exist yet
1726 if(!folderDir
.exists())
1728 folderDir
.mkpath(".");
1731 //Make sure folder exists now *and* is writable
1732 if(folderDir
.exists())
1734 QFile
testFile(folderDir
.absoluteFilePath(QString("~%1.tmp").arg(lamexp_rand_str())));
1735 if(testFile
.open(QIODevice::ReadWrite
))
1737 const QByteArray testData
= QByteArray("Lorem ipsum dolor sit amet, consectetur, adipisci velit!");
1738 if(testFile
.write(testData
) >= strlen(testData
))
1747 return (success
? folderDir
.canonicalPath() : QString());
1751 * Initialize LameXP temp folder
1753 #define INIT_TEMP_FOLDER(OUT,TMP) do \
1755 (OUT) = lamexp_try_init_folder(QString("%1/%2").arg((TMP), lamexp_rand_str())); \
1760 * Get LameXP temp folder
1762 const QString
&lamexp_temp_folder2(void)
1764 QReadLocker
readLock(&g_lamexp_temp_folder
.lock
);
1766 //Already initialized?
1767 if(g_lamexp_temp_folder
.path
&& (!g_lamexp_temp_folder
.path
->isEmpty()))
1769 if(QDir(*g_lamexp_temp_folder
.path
).exists())
1771 return *g_lamexp_temp_folder
.path
;
1775 //Obtain the write lock to initilaize
1777 QWriteLocker
writeLock(&g_lamexp_temp_folder
.lock
);
1779 //Still uninitilaized?
1780 if(g_lamexp_temp_folder
.path
&& (!g_lamexp_temp_folder
.path
->isEmpty()))
1782 if(QDir(*g_lamexp_temp_folder
.path
).exists())
1784 return *g_lamexp_temp_folder
.path
;
1788 //Create the string, if not done yet
1789 if(!g_lamexp_temp_folder
.path
)
1791 g_lamexp_temp_folder
.path
= new QString();
1794 g_lamexp_temp_folder
.path
->clear();
1796 //Try the %TMP% or %TEMP% directory first
1797 QString tempPath
= lamexp_try_init_folder(QDir::temp().absolutePath());
1798 if(!tempPath
.isEmpty())
1800 INIT_TEMP_FOLDER(*g_lamexp_temp_folder
.path
, tempPath
);
1803 //Otherwise create TEMP folder in %LOCALAPPDATA%
1804 if(g_lamexp_temp_folder
.path
->isEmpty())
1806 tempPath
= lamexp_try_init_folder(QString("%1/Temp").arg(lamexp_known_folder(lamexp_folder_localappdata
)));
1807 if(!tempPath
.isEmpty())
1809 INIT_TEMP_FOLDER(*g_lamexp_temp_folder
.path
, tempPath
);
1813 //Failed to create TEMP folder?
1814 if(g_lamexp_temp_folder
.path
->isEmpty())
1816 qFatal("Temporary directory could not be initialized !!!");
1819 return *g_lamexp_temp_folder
.path
;
1825 bool lamexp_clean_folder(const QString
&folderPath
)
1827 QDir
tempFolder(folderPath
);
1828 if(tempFolder
.exists())
1830 QFileInfoList entryList
= tempFolder
.entryInfoList(QDir::AllEntries
| QDir::NoDotAndDotDot
);
1832 for(int i
= 0; i
< entryList
.count(); i
++)
1834 if(entryList
.at(i
).isDir())
1836 lamexp_clean_folder(entryList
.at(i
).canonicalFilePath());
1840 for(int j
= 0; j
< 3; j
++)
1842 if(lamexp_remove_file(entryList
.at(i
).canonicalFilePath()))
1849 return tempFolder
.rmdir(".");
1857 void lamexp_register_tool(const QString
&toolName
, LockedFile
*file
, unsigned int version
, const QString
*tag
)
1859 QWriteLocker
writeLock(&g_lamexp_tools
.lock
);
1861 if(!g_lamexp_tools
.registry
) g_lamexp_tools
.registry
= new QMap
<QString
, LockedFile
*>();
1862 if(!g_lamexp_tools
.versions
) g_lamexp_tools
.versions
= new QMap
<QString
, unsigned int>();
1863 if(!g_lamexp_tools
.tags
) g_lamexp_tools
.tags
= new QMap
<QString
, QString
>();
1865 if(g_lamexp_tools
.registry
->contains(toolName
.toLower()))
1867 THROW("lamexp_register_tool: Tool is already registered!");
1870 g_lamexp_tools
.registry
->insert(toolName
.toLower(), file
);
1871 g_lamexp_tools
.versions
->insert(toolName
.toLower(), version
);
1872 g_lamexp_tools
.tags
->insert(toolName
.toLower(), (tag
) ? (*tag
) : QString());
1878 bool lamexp_check_tool(const QString
&toolName
)
1880 QReadLocker
readLock(&g_lamexp_tools
.lock
);
1881 return (g_lamexp_tools
.registry
) ? g_lamexp_tools
.registry
->contains(toolName
.toLower()) : false;
1887 const QString
lamexp_lookup_tool(const QString
&toolName
)
1889 QReadLocker
readLock(&g_lamexp_tools
.lock
);
1891 if(g_lamexp_tools
.registry
)
1893 if(g_lamexp_tools
.registry
->contains(toolName
.toLower()))
1895 return g_lamexp_tools
.registry
->value(toolName
.toLower())->filePath();
1909 * Lookup tool version
1911 unsigned int lamexp_tool_version(const QString
&toolName
, QString
*tag
)
1913 QReadLocker
readLock(&g_lamexp_tools
.lock
);
1914 if(tag
) tag
->clear();
1916 if(g_lamexp_tools
.versions
)
1918 if(g_lamexp_tools
.versions
->contains(toolName
.toLower()))
1922 if(g_lamexp_tools
.tags
->contains(toolName
.toLower())) *tag
= g_lamexp_tools
.tags
->value(toolName
.toLower());
1924 return g_lamexp_tools
.versions
->value(toolName
.toLower());
1938 * Version number to human-readable string
1940 const QString
lamexp_version2string(const QString
&pattern
, unsigned int version
, const QString
&defaultText
, const QString
*tag
)
1942 if(version
== UINT_MAX
)
1947 QString result
= pattern
;
1948 int digits
= result
.count("?", Qt::CaseInsensitive
);
1956 QString versionStr
= QString().sprintf(QString().sprintf("%%0%du", digits
).toLatin1().constData(), version
);
1957 int index
= result
.indexOf("?", Qt::CaseInsensitive
);
1959 while(index
>= 0 && pos
< versionStr
.length())
1961 result
[index
] = versionStr
[pos
++];
1962 index
= result
.indexOf("?", Qt::CaseInsensitive
);
1967 result
.replace(QChar('#'), *tag
, Qt::CaseInsensitive
);
1974 * Register a new translation
1976 bool lamexp_translation_register(const QString
&langId
, const QString
&qmFile
, const QString
&langName
, unsigned int &systemId
, unsigned int &country
)
1978 QWriteLocker
writeLockTranslations(&g_lamexp_translation
.lock
);
1980 if(qmFile
.isEmpty() || langName
.isEmpty() || systemId
< 1)
1985 if(!g_lamexp_translation
.files
) g_lamexp_translation
.files
= new QMap
<QString
, QString
>();
1986 if(!g_lamexp_translation
.names
) g_lamexp_translation
.names
= new QMap
<QString
, QString
>();
1987 if(!g_lamexp_translation
.sysid
) g_lamexp_translation
.sysid
= new QMap
<QString
, unsigned int>();
1988 if(!g_lamexp_translation
.cntry
) g_lamexp_translation
.cntry
= new QMap
<QString
, unsigned int>();
1990 g_lamexp_translation
.files
->insert(langId
, qmFile
);
1991 g_lamexp_translation
.names
->insert(langId
, langName
);
1992 g_lamexp_translation
.sysid
->insert(langId
, systemId
);
1993 g_lamexp_translation
.cntry
->insert(langId
, country
);
1999 * Get list of all translations
2001 QStringList
lamexp_query_translations(void)
2003 QReadLocker
readLockTranslations(&g_lamexp_translation
.lock
);
2004 return (g_lamexp_translation
.files
) ? g_lamexp_translation
.files
->keys() : QStringList();
2008 * Get translation name
2010 QString
lamexp_translation_name(const QString
&langId
)
2012 QReadLocker
readLockTranslations(&g_lamexp_translation
.lock
);
2013 return (g_lamexp_translation
.names
) ? g_lamexp_translation
.names
->value(langId
.toLower(), QString()) : QString();
2017 * Get translation system id
2019 unsigned int lamexp_translation_sysid(const QString
&langId
)
2021 QReadLocker
readLockTranslations(&g_lamexp_translation
.lock
);
2022 return (g_lamexp_translation
.sysid
) ? g_lamexp_translation
.sysid
->value(langId
.toLower(), 0) : 0;
2026 * Get translation script id
2028 unsigned int lamexp_translation_country(const QString
&langId
)
2030 QReadLocker
readLockTranslations(&g_lamexp_translation
.lock
);
2031 return (g_lamexp_translation
.cntry
) ? g_lamexp_translation
.cntry
->value(langId
.toLower(), 0) : 0;
2035 * Install a new translator
2037 bool lamexp_install_translator(const QString
&langId
)
2039 bool success
= false;
2040 const QString
qmFileToPath(":/localization/%1");
2042 if(langId
.isEmpty() || langId
.toLower().compare(LAMEXP_DEFAULT_LANGID
) == 0)
2044 success
= lamexp_install_translator_from_file(qmFileToPath
.arg(LAMEXP_DEFAULT_TRANSLATION
));
2048 QReadLocker
readLock(&g_lamexp_translation
.lock
);
2049 QString qmFile
= (g_lamexp_translation
.files
) ? g_lamexp_translation
.files
->value(langId
.toLower(), QString()) : QString();
2052 if(!qmFile
.isEmpty())
2054 success
= lamexp_install_translator_from_file(qmFileToPath
.arg(qmFile
));
2058 qWarning("Translation '%s' not available!", langId
.toLatin1().constData());
2066 * Install a new translator from file
2068 bool lamexp_install_translator_from_file(const QString
&qmFile
)
2070 QWriteLocker
writeLock(&g_lamexp_currentTranslator
.lock
);
2071 bool success
= false;
2073 if(!g_lamexp_currentTranslator
.instance
)
2075 g_lamexp_currentTranslator
.instance
= new QTranslator();
2078 if(!qmFile
.isEmpty())
2080 QString qmPath
= QFileInfo(qmFile
).canonicalFilePath();
2081 QApplication::removeTranslator(g_lamexp_currentTranslator
.instance
);
2082 if(success
= g_lamexp_currentTranslator
.instance
->load(qmPath
))
2084 QApplication::installTranslator(g_lamexp_currentTranslator
.instance
);
2088 qWarning("Failed to load translation:\n\"%s\"", qmPath
.toLatin1().constData());
2093 QApplication::removeTranslator(g_lamexp_currentTranslator
.instance
);
2100 const QStringList
&lamexp_arguments(void)
2102 QReadLocker
readLock(&g_lamexp_argv
.lock
);
2104 if(!g_lamexp_argv
.list
)
2107 QWriteLocker
writeLock(&g_lamexp_argv
.lock
);
2109 g_lamexp_argv
.list
= new QStringList
;
2112 LPWSTR
*szArglist
= CommandLineToArgvW(GetCommandLineW(), &nArgs
);
2114 if(NULL
!= szArglist
)
2116 for(int i
= 0; i
< nArgs
; i
++)
2118 (*g_lamexp_argv
.list
) << WCHAR2QSTR(szArglist
[i
]);
2120 LocalFree(szArglist
);
2124 qWarning("CommandLineToArgvW() has failed !!!");
2128 return (*g_lamexp_argv
.list
);
2132 * Locate known folder on local system
2134 const QString
&lamexp_known_folder(lamexp_known_folder_t folder_id
)
2136 typedef HRESULT (WINAPI
*SHGetKnownFolderPathFun
)(__in
const GUID
&rfid
, __in DWORD dwFlags
, __in HANDLE hToken
, __out PWSTR
*ppszPath
);
2137 typedef HRESULT (WINAPI
*SHGetFolderPathFun
)(__in HWND hwndOwner
, __in
int nFolder
, __in HANDLE hToken
, __in DWORD dwFlags
, __out LPWSTR pszPath
);
2139 static const int CSIDL_LOCAL_APPDATA
= 0x001c;
2140 static const int CSIDL_PROGRAM_FILES
= 0x0026;
2141 static const int CSIDL_SYSTEM_FOLDER
= 0x0025;
2142 static const GUID GUID_LOCAL_APPDATA
= {0xF1B32785,0x6FBA,0x4FCF,{0x9D,0x55,0x7B,0x8E,0x7F,0x15,0x70,0x91}};
2143 static const GUID GUID_LOCAL_APPDATA_LOW
= {0xA520A1A4,0x1780,0x4FF6,{0xBD,0x18,0x16,0x73,0x43,0xC5,0xAF,0x16}};
2144 static const GUID GUID_PROGRAM_FILES
= {0x905e63b6,0xc1bf,0x494e,{0xb2,0x9c,0x65,0xb7,0x32,0xd3,0xd2,0x1a}};
2145 static const GUID GUID_SYSTEM_FOLDER
= {0x1AC14E77,0x02E7,0x4E5D,{0xB7,0x44,0x2E,0xB1,0xAE,0x51,0x98,0xB7}};
2147 QReadLocker
readLock(&g_lamexp_known_folder
.lock
);
2149 int folderCSIDL
= -1;
2150 GUID folderGUID
= {0x0000,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}};
2151 size_t folderCacheId
= size_t(-1);
2155 case lamexp_folder_localappdata
:
2157 folderCSIDL
= CSIDL_LOCAL_APPDATA
;
2158 folderGUID
= GUID_LOCAL_APPDATA
;
2160 case lamexp_folder_programfiles
:
2162 folderCSIDL
= CSIDL_PROGRAM_FILES
;
2163 folderGUID
= GUID_PROGRAM_FILES
;
2165 case lamexp_folder_systemfolder
:
2167 folderCSIDL
= CSIDL_SYSTEM_FOLDER
;
2168 folderGUID
= GUID_SYSTEM_FOLDER
;
2171 qWarning("Invalid 'known' folder was requested!");
2172 return *reinterpret_cast<QString
*>(NULL
);
2177 if(g_lamexp_known_folder
.knownFolders
)
2179 if(g_lamexp_known_folder
.knownFolders
->contains(folderCacheId
))
2181 return (*g_lamexp_known_folder
.knownFolders
)[folderCacheId
];
2185 //Obtain write lock to initialize
2187 QWriteLocker
writeLock(&g_lamexp_known_folder
.lock
);
2189 //Still not in cache?
2190 if(g_lamexp_known_folder
.knownFolders
)
2192 if(g_lamexp_known_folder
.knownFolders
->contains(folderCacheId
))
2194 return (*g_lamexp_known_folder
.knownFolders
)[folderCacheId
];
2198 static SHGetKnownFolderPathFun SHGetKnownFolderPathPtr
= NULL
;
2199 static SHGetFolderPathFun SHGetFolderPathPtr
= NULL
;
2202 if((!SHGetKnownFolderPathPtr
) && (!SHGetFolderPathPtr
))
2204 QLibrary
kernel32Lib("shell32.dll");
2205 if(kernel32Lib
.load())
2207 SHGetKnownFolderPathPtr
= (SHGetKnownFolderPathFun
) kernel32Lib
.resolve("SHGetKnownFolderPath");
2208 SHGetFolderPathPtr
= (SHGetFolderPathFun
) kernel32Lib
.resolve("SHGetFolderPathW");
2214 //Now try to get the folder path!
2215 if(SHGetKnownFolderPathPtr
)
2218 if(SHGetKnownFolderPathPtr(folderGUID
, 0x00008000, NULL
, &path
) == S_OK
)
2220 //MessageBoxW(0, path, L"SHGetKnownFolderPath", MB_TOPMOST);
2221 QDir folderTemp
= QDir(QDir::fromNativeSeparators(QString::fromUtf16(reinterpret_cast<const unsigned short*>(path
))));
2222 if(!folderTemp
.exists())
2224 folderTemp
.mkpath(".");
2226 if(folderTemp
.exists())
2228 folder
= folderTemp
.canonicalPath();
2230 CoTaskMemFree(path
);
2233 else if(SHGetFolderPathPtr
)
2235 WCHAR
*path
= new WCHAR
[4096];
2236 if(SHGetFolderPathPtr(NULL
, folderCSIDL
, NULL
, NULL
, path
) == S_OK
)
2238 //MessageBoxW(0, path, L"SHGetFolderPathW", MB_TOPMOST);
2239 QDir folderTemp
= QDir(QDir::fromNativeSeparators(QString::fromUtf16(reinterpret_cast<const unsigned short*>(path
))));
2240 if(!folderTemp
.exists())
2242 folderTemp
.mkpath(".");
2244 if(folderTemp
.exists())
2246 folder
= folderTemp
.canonicalPath();
2253 if(!g_lamexp_known_folder
.knownFolders
)
2255 g_lamexp_known_folder
.knownFolders
= new QMap
<size_t, QString
>();
2259 g_lamexp_known_folder
.knownFolders
->insert(folderCacheId
, folder
);
2260 return (*g_lamexp_known_folder
.knownFolders
)[folderCacheId
];
2264 * Safely remove a file
2266 bool lamexp_remove_file(const QString
&filename
)
2268 if(!QFileInfo(filename
).exists() || !QFileInfo(filename
).isFile())
2274 if(!QFile::remove(filename
))
2276 DWORD attributes
= GetFileAttributesW(QWCHAR(filename
));
2277 SetFileAttributesW(QWCHAR(filename
), (attributes
& (~FILE_ATTRIBUTE_READONLY
)));
2278 if(!QFile::remove(filename
))
2280 qWarning("Could not delete \"%s\"", filename
.toLatin1().constData());
2296 * Check if visual themes are enabled (WinXP and later)
2298 bool lamexp_themes_enabled(void)
2300 typedef int (WINAPI
*IsAppThemedFun
)(void);
2302 QReadLocker
readLock(&g_lamexp_themes_enabled
.lock
);
2303 if(g_lamexp_themes_enabled
.bInitialized
)
2305 return g_lamexp_themes_enabled
.bThemesEnabled
;
2309 QWriteLocker
writeLock(&g_lamexp_themes_enabled
.lock
);
2311 if(!g_lamexp_themes_enabled
.bInitialized
)
2313 g_lamexp_themes_enabled
.bThemesEnabled
= false;
2314 const lamexp_os_version_t
&osVersion
= lamexp_get_os_version();
2315 if(osVersion
>= lamexp_winver_winxp
)
2317 IsAppThemedFun IsAppThemedPtr
= NULL
;
2318 QLibrary
uxTheme(QString("%1/UxTheme.dll").arg(lamexp_known_folder(lamexp_folder_systemfolder
)));
2321 IsAppThemedPtr
= (IsAppThemedFun
) uxTheme
.resolve("IsAppThemed");
2325 g_lamexp_themes_enabled
.bThemesEnabled
= IsAppThemedPtr();
2326 if(!g_lamexp_themes_enabled
.bThemesEnabled
)
2328 qWarning("Theme support is disabled for this process!");
2332 g_lamexp_themes_enabled
.bInitialized
= true;
2335 return g_lamexp_themes_enabled
.bThemesEnabled
;
2339 * Get number of free bytes on disk
2341 unsigned __int64
lamexp_free_diskspace(const QString
&path
, bool *ok
)
2343 ULARGE_INTEGER freeBytesAvailable
, totalNumberOfBytes
, totalNumberOfFreeBytes
;
2344 if(GetDiskFreeSpaceExW(reinterpret_cast<const wchar_t*>(QDir::toNativeSeparators(path
).utf16()), &freeBytesAvailable
, &totalNumberOfBytes
, &totalNumberOfFreeBytes
))
2347 return freeBytesAvailable
.QuadPart
;
2357 * Check if computer does support hibernation
2359 bool lamexp_is_hibernation_supported(void)
2361 bool hibernationSupported
= false;
2363 SYSTEM_POWER_CAPABILITIES pwrCaps
;
2364 SecureZeroMemory(&pwrCaps
, sizeof(SYSTEM_POWER_CAPABILITIES
));
2366 if(GetPwrCapabilities(&pwrCaps
))
2368 hibernationSupported
= pwrCaps
.SystemS4
&& pwrCaps
.HiberFilePresent
;
2371 return hibernationSupported
;
2375 * Shutdown the computer
2377 bool lamexp_shutdown_computer(const QString
&message
, const unsigned long timeout
, const bool forceShutdown
, const bool hibernate
)
2379 HANDLE hToken
= NULL
;
2381 if(OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES
| TOKEN_QUERY
, &hToken
))
2383 TOKEN_PRIVILEGES privileges
;
2384 memset(&privileges
, 0, sizeof(TOKEN_PRIVILEGES
));
2385 privileges
.PrivilegeCount
= 1;
2386 privileges
.Privileges
[0].Attributes
= SE_PRIVILEGE_ENABLED
;
2388 if(LookupPrivilegeValue(NULL
, SE_SHUTDOWN_NAME
, &privileges
.Privileges
[0].Luid
))
2390 if(AdjustTokenPrivileges(hToken
, FALSE
, &privileges
, NULL
, NULL
, NULL
))
2394 if(SetSuspendState(TRUE
, TRUE
, TRUE
))
2399 const DWORD reason
= SHTDN_REASON_MAJOR_APPLICATION
| SHTDN_REASON_FLAG_PLANNED
;
2400 return InitiateSystemShutdownEx(NULL
, const_cast<wchar_t*>(QWCHAR(message
)), timeout
, forceShutdown
? TRUE
: FALSE
, FALSE
, reason
);
2409 * Make a window blink (to draw user's attention)
2411 void lamexp_blink_window(QWidget
*poWindow
, unsigned int count
, unsigned int delay
)
2413 static QMutex blinkMutex
;
2415 const double maxOpac
= 1.0;
2416 const double minOpac
= 0.3;
2417 const double delOpac
= 0.1;
2419 if(!blinkMutex
.tryLock())
2421 qWarning("Blinking is already in progress, skipping!");
2427 const int steps
= static_cast<int>(ceil(maxOpac
- minOpac
) / delOpac
);
2428 const int sleep
= static_cast<int>(floor(static_cast<double>(delay
) / static_cast<double>(steps
)));
2429 const double opacity
= poWindow
->windowOpacity();
2431 for(unsigned int i
= 0; i
< count
; i
++)
2433 for(double x
= maxOpac
; x
>= minOpac
; x
-= delOpac
)
2435 poWindow
->setWindowOpacity(x
);
2436 QApplication::processEvents();
2440 for(double x
= minOpac
; x
<= maxOpac
; x
+= delOpac
)
2442 poWindow
->setWindowOpacity(x
);
2443 QApplication::processEvents();
2448 poWindow
->setWindowOpacity(opacity
);
2449 QApplication::processEvents();
2450 blinkMutex
.unlock();
2454 blinkMutex
.unlock();
2455 qWarning("Exception error while blinking!");
2460 * Remove forbidden characters from a filename
2462 const QString
lamexp_clean_filename(const QString
&str
)
2464 QString
newStr(str
);
2465 QRegExp
rx("\"(.+)\"");
2466 rx
.setMinimal(true);
2468 newStr
.replace("\\", "-");
2469 newStr
.replace(" / ", ", ");
2470 newStr
.replace("/", ",");
2471 newStr
.replace(":", "-");
2472 newStr
.replace("*", "x");
2473 newStr
.replace("?", "");
2474 newStr
.replace("<", "[");
2475 newStr
.replace(">", "]");
2476 newStr
.replace("|", "!");
2477 newStr
.replace(rx
, "`\\1´");
2478 newStr
.replace("\"", "'");
2480 return newStr
.simplified();
2484 * Remove forbidden characters from a file path
2486 const QString
lamexp_clean_filepath(const QString
&str
)
2488 QStringList parts
= QString(str
).replace("\\", "/").split("/");
2490 for(int i
= 0; i
< parts
.count(); i
++)
2492 parts
[i
] = lamexp_clean_filename(parts
[i
]);
2495 return parts
.join("/");
2499 * Get a list of all available Qt Text Codecs
2501 QStringList
lamexp_available_codepages(bool noAliases
)
2503 QStringList codecList
;
2505 QList
<QByteArray
> availableCodecs
= QTextCodec::availableCodecs();
2506 while(!availableCodecs
.isEmpty())
2508 QByteArray current
= availableCodecs
.takeFirst();
2509 if(!(current
.startsWith("system") || current
.startsWith("System")))
2511 codecList
<< QString::fromLatin1(current
.constData(), current
.size());
2514 if(QTextCodec
*currentCodec
= QTextCodec::codecForName(current
.constData()))
2517 QList
<QByteArray
> aliases
= currentCodec
->aliases();
2518 while(!aliases
.isEmpty()) availableCodecs
.removeAll(aliases
.takeFirst());
2528 * Robert Jenkins' 96 bit Mix Function
2529 * Source: http://www.concentric.net/~Ttwang/tech/inthash.htm
2531 static unsigned int lamexp_mix(const unsigned int x
, const unsigned int y
, const unsigned int z
)
2537 a
=a
-b
; a
=a
-c
; a
=a
^(c
>> 13);
2538 b
=b
-c
; b
=b
-a
; b
=b
^(a
<< 8);
2539 c
=c
-a
; c
=c
-b
; c
=c
^(b
>> 13);
2540 a
=a
-b
; a
=a
-c
; a
=a
^(c
>> 12);
2541 b
=b
-c
; b
=b
-a
; b
=b
^(a
<< 16);
2542 c
=c
-a
; c
=c
-b
; c
=c
^(b
>> 5);
2543 a
=a
-b
; a
=a
-c
; a
=a
^(c
>> 3);
2544 b
=b
-c
; b
=b
-a
; b
=b
^(a
<< 10);
2545 c
=c
-a
; c
=c
-b
; c
=c
^(b
>> 15);
2551 * Seeds the random number generator
2552 * Note: Altough rand_s() doesn't need a seed, this must be called pripr to lamexp_rand(), just to to be sure!
2554 void lamexp_seed_rand(void)
2556 qsrand(lamexp_mix(clock(), time(NULL
), _getpid()));
2560 * Returns a randum number
2561 * Note: This function uses rand_s() if available, but falls back to qrand() otherwise
2563 unsigned int lamexp_rand(void)
2567 if(rand_s(&rnd
) == 0)
2572 for(size_t i
= 0; i
< sizeof(unsigned int); i
++)
2574 rnd
= (rnd
<< 8) ^ qrand();
2581 * Determines the current date, resistant against certain manipulations
2583 QDate
lamexp_current_date_safe(void)
2585 const DWORD MAX_PROC
= 1024;
2586 DWORD
*processes
= new DWORD
[MAX_PROC
];
2587 DWORD bytesReturned
= 0;
2589 if(!EnumProcesses(processes
, sizeof(DWORD
) * MAX_PROC
, &bytesReturned
))
2591 LAMEXP_DELETE_ARRAY(processes
);
2592 return QDate::currentDate();
2595 const DWORD procCount
= bytesReturned
/ sizeof(DWORD
);
2596 ULARGE_INTEGER lastStartTime
;
2597 memset(&lastStartTime
, 0, sizeof(ULARGE_INTEGER
));
2599 for(DWORD i
= 0; i
< procCount
; i
++)
2601 HANDLE hProc
= OpenProcess(PROCESS_QUERY_INFORMATION
, FALSE
, processes
[i
]);
2604 FILETIME processTime
[4];
2605 if(GetProcessTimes(hProc
, &processTime
[0], &processTime
[1], &processTime
[2], &processTime
[3]))
2607 ULARGE_INTEGER timeCreation
;
2608 timeCreation
.LowPart
= processTime
[0].dwLowDateTime
;
2609 timeCreation
.HighPart
= processTime
[0].dwHighDateTime
;
2610 if(timeCreation
.QuadPart
> lastStartTime
.QuadPart
)
2612 lastStartTime
.QuadPart
= timeCreation
.QuadPart
;
2619 LAMEXP_DELETE_ARRAY(processes
);
2621 FILETIME lastStartTime_fileTime
;
2622 lastStartTime_fileTime
.dwHighDateTime
= lastStartTime
.HighPart
;
2623 lastStartTime_fileTime
.dwLowDateTime
= lastStartTime
.LowPart
;
2625 FILETIME lastStartTime_localTime
;
2626 if(!FileTimeToLocalFileTime(&lastStartTime_fileTime
, &lastStartTime_localTime
))
2628 memcpy(&lastStartTime_localTime
, &lastStartTime_fileTime
, sizeof(FILETIME
));
2631 SYSTEMTIME lastStartTime_system
;
2632 if(!FileTimeToSystemTime(&lastStartTime_localTime
, &lastStartTime_system
))
2634 memset(&lastStartTime_system
, 0, sizeof(SYSTEMTIME
));
2635 lastStartTime_system
.wYear
= 1970; lastStartTime_system
.wMonth
= lastStartTime_system
.wDay
= 1;
2638 const QDate currentDate
= QDate::currentDate();
2639 const QDate processDate
= QDate(lastStartTime_system
.wYear
, lastStartTime_system
.wMonth
, lastStartTime_system
.wDay
);
2640 return (currentDate
>= processDate
) ? currentDate
: processDate
;
2645 * Natural Order String Comparison - the 'lessThan' helper function
2647 static bool lamexp_natural_string_sort_helper(const QString
&str1
, const QString
&str2
)
2649 return (strnatcmp(QWCHAR(str1
), QWCHAR(str2
)) < 0);
2653 * Natural Order String Comparison - the 'lessThan' helper function *with* case folding
2655 static bool lamexp_natural_string_sort_helper_fold_case(const QString
&str1
, const QString
&str2
)
2657 return (strnatcasecmp(QWCHAR(str1
), QWCHAR(str2
)) < 0);
2661 * Natural Order String Comparison - the main sorting function
2663 void lamexp_natural_string_sort(QStringList
&list
, const bool bIgnoreCase
)
2665 qSort(list
.begin(), list
.end(), bIgnoreCase
? lamexp_natural_string_sort_helper_fold_case
: lamexp_natural_string_sort_helper
);
2669 * Suspend calling thread for N milliseconds
2671 inline void lamexp_sleep(const unsigned int delay
)
2676 bool lamexp_beep(int beepType
)
2680 case lamexp_beep_info
: return MessageBeep(MB_ICONASTERISK
) == TRUE
; break;
2681 case lamexp_beep_warning
: return MessageBeep(MB_ICONEXCLAMATION
) == TRUE
; break;
2682 case lamexp_beep_error
: return MessageBeep(MB_ICONHAND
) == TRUE
; break;
2683 default: return false;
2688 * Play a sound (from resources)
2690 bool lamexp_play_sound(const unsigned short uiSoundIdx
, const bool bAsync
, const wchar_t *alias
)
2694 return PlaySound(alias
, GetModuleHandle(NULL
), (SND_ALIAS
| (bAsync
? SND_ASYNC
: SND_SYNC
))) == TRUE
;
2698 return PlaySound(MAKEINTRESOURCE(uiSoundIdx
), GetModuleHandle(NULL
), (SND_RESOURCE
| (bAsync
? SND_ASYNC
: SND_SYNC
))) == TRUE
;
2703 * Play a sound (from resources)
2705 bool lamexp_play_sound_file(const QString
&library
, const unsigned short uiSoundIdx
, const bool bAsync
)
2707 bool result
= false;
2708 HMODULE module
= NULL
;
2710 QFileInfo
libraryFile(library
);
2711 if(!libraryFile
.isAbsolute())
2713 unsigned int buffSize
= GetSystemDirectoryW(NULL
, NULL
) + 1;
2714 wchar_t *buffer
= (wchar_t*) _malloca(buffSize
* sizeof(wchar_t));
2715 unsigned int result
= GetSystemDirectory(buffer
, buffSize
);
2716 if(result
> 0 && result
< buffSize
)
2718 libraryFile
.setFile(QString("%1/%2").arg(QDir::fromNativeSeparators(QString::fromUtf16(reinterpret_cast<const unsigned short*>(buffer
))), library
));
2723 module
= LoadLibraryW(QWCHAR(QDir::toNativeSeparators(libraryFile
.absoluteFilePath())));
2726 result
= (PlaySound(MAKEINTRESOURCE(uiSoundIdx
), module
, (SND_RESOURCE
| (bAsync
? SND_ASYNC
: SND_SYNC
))) == TRUE
);
2727 FreeLibrary(module
);
2734 * Open file using the shell
2736 bool lamexp_exec_shell(const QWidget
*win
, const QString
&url
, const bool explore
)
2738 return lamexp_exec_shell(win
, url
, QString(), QString(), explore
);
2742 * Open file using the shell (with parameters)
2744 bool lamexp_exec_shell(const QWidget
*win
, const QString
&url
, const QString
¶meters
, const QString
&directory
, const bool explore
)
2746 return ((int) ShellExecuteW(((win
) ? win
->winId() : NULL
), (explore
? L
"explore" : L
"open"), QWCHAR(url
), ((!parameters
.isEmpty()) ? QWCHAR(parameters
) : NULL
), ((!directory
.isEmpty()) ? QWCHAR(directory
) : NULL
), SW_SHOW
)) > 32;
2750 * Query value of the performance counter
2752 __int64
lamexp_perfcounter_value(void)
2754 LARGE_INTEGER counter
;
2755 if(QueryPerformanceCounter(&counter
) == TRUE
)
2757 return counter
.QuadPart
;
2763 * Query frequency of the performance counter
2765 __int64
lamexp_perfcounter_frequ(void)
2767 LARGE_INTEGER frequency
;
2768 if(QueryPerformanceFrequency(&frequency
) == TRUE
)
2770 return frequency
.QuadPart
;
2776 * Insert entry to the window's system menu
2778 bool lamexp_append_sysmenu(const QWidget
*win
, const unsigned int identifier
, const QString
&text
)
2782 if(HMENU hMenu
= GetSystemMenu(win
->winId(), FALSE
))
2784 ok
= (AppendMenuW(hMenu
, MF_SEPARATOR
, 0, 0) == TRUE
);
2785 ok
= (AppendMenuW(hMenu
, MF_STRING
, identifier
, QWCHAR(text
)) == TRUE
);
2792 * Insert entry to the window's system menu
2794 bool lamexp_check_sysmenu_msg(void *message
, const unsigned int identifier
)
2796 return (((MSG
*)message
)->message
== WM_SYSCOMMAND
) && ((((MSG
*)message
)->wParam
& 0xFFF0) == identifier
);
2800 * Update system menu entry
2802 bool lamexp_update_sysmenu(const QWidget
*win
, const unsigned int identifier
, const QString
&text
)
2806 if(HMENU hMenu
= ::GetSystemMenu(win
->winId(), FALSE
))
2808 ok
= (ModifyMenu(hMenu
, identifier
, MF_STRING
| MF_BYCOMMAND
, identifier
, QWCHAR(text
)) == TRUE
);
2814 * Display the window's close button
2816 bool lamexp_enable_close_button(const QWidget
*win
, const bool bEnable
)
2820 if(HMENU hMenu
= GetSystemMenu(win
->winId(), FALSE
))
2822 ok
= (EnableMenuItem(hMenu
, SC_CLOSE
, MF_BYCOMMAND
| (bEnable
? MF_ENABLED
: MF_GRAYED
)) == TRUE
);
2829 * Check whether ESC key has been pressed since the previous call to this function
2831 bool lamexp_check_escape_state(void)
2833 return (GetAsyncKeyState(VK_ESCAPE
) & 0x0001) != 0;
2837 * Set the process priority class for current process
2839 bool lamexp_change_process_priority(const int priority
)
2841 return lamexp_change_process_priority(GetCurrentProcess(), priority
);
2845 * Set the process priority class for specified process
2847 bool lamexp_change_process_priority(const QProcess
*proc
, const int priority
)
2849 if(Q_PID qPid
= proc
->pid())
2851 return lamexp_change_process_priority(qPid
->hProcess
, priority
);
2860 * Set the process priority class for specified process
2862 bool lamexp_change_process_priority(void *hProcess
, const int priority
)
2866 switch(qBound(-2, priority
, 2))
2869 ok
= (SetPriorityClass(hProcess
, HIGH_PRIORITY_CLASS
) == TRUE
);
2872 if(!(ok
= (SetPriorityClass(hProcess
, ABOVE_NORMAL_PRIORITY_CLASS
) == TRUE
)))
2874 ok
= (SetPriorityClass(hProcess
, HIGH_PRIORITY_CLASS
) == TRUE
);
2878 ok
= (SetPriorityClass(hProcess
, NORMAL_PRIORITY_CLASS
) == TRUE
);
2881 if(!(ok
= (SetPriorityClass(hProcess
, BELOW_NORMAL_PRIORITY_CLASS
) == TRUE
)))
2883 ok
= (SetPriorityClass(hProcess
, IDLE_PRIORITY_CLASS
) == TRUE
);
2887 ok
= (SetPriorityClass(hProcess
, IDLE_PRIORITY_CLASS
) == TRUE
);
2895 * Returns the current file time
2897 unsigned __int64
lamexp_current_file_time(void)
2900 GetSystemTimeAsFileTime(&fileTime
);
2902 ULARGE_INTEGER temp
;
2903 temp
.HighPart
= fileTime
.dwHighDateTime
;
2904 temp
.LowPart
= fileTime
.dwLowDateTime
;
2906 return temp
.QuadPart
;
2910 * Bring the specifed window to the front
2912 bool lamexp_bring_to_front(const QWidget
*win
)
2914 const bool ret
= (SetForegroundWindow(win
->winId()) == TRUE
);
2915 SwitchToThisWindow(win
->winId(), TRUE
);
2920 * Bring window of the specifed process to the front (callback)
2922 static BOOL CALLBACK
lamexp_bring_process_to_front_helper(HWND hwnd
, LPARAM lParam
)
2924 DWORD processId
= *reinterpret_cast<WORD
*>(lParam
);
2925 DWORD windowProcessId
= NULL
;
2926 GetWindowThreadProcessId(hwnd
, &windowProcessId
);
2927 if(windowProcessId
== processId
)
2929 SwitchToThisWindow(hwnd
, TRUE
);
2930 SetForegroundWindow(hwnd
);
2938 * Bring window of the specifed process to the front
2940 bool lamexp_bring_process_to_front(const unsigned long pid
)
2942 return EnumWindows(lamexp_bring_process_to_front_helper
, reinterpret_cast<LPARAM
>(&pid
)) == TRUE
;
2946 * Check the network connection status
2948 int lamexp_network_status(void)
2951 const BOOL ret
= (IsNetworkAlive(&dwFlags
) == TRUE
);
2952 if(GetLastError() == 0)
2954 return (ret
== TRUE
) ? lamexp_network_yes
: lamexp_network_non
;
2956 return lamexp_network_err
;
2960 * Retrun the process ID of the given QProcess
2962 unsigned long lamexp_process_id(const QProcess
*proc
)
2964 PROCESS_INFORMATION
*procInf
= proc
->pid();
2965 return (procInf
) ? procInf
->dwProcessId
: NULL
;
2969 * Convert long path to short path
2971 QString
lamexp_path_to_short(const QString
&longPath
)
2974 DWORD buffSize
= GetShortPathNameW(reinterpret_cast<const wchar_t*>(longPath
.utf16()), NULL
, NULL
);
2978 wchar_t *buffer
= new wchar_t[buffSize
];
2979 DWORD result
= GetShortPathNameW(reinterpret_cast<const wchar_t*>(longPath
.utf16()), buffer
, buffSize
);
2981 if(result
> 0 && result
< buffSize
)
2983 shortPath
= QString::fromUtf16(reinterpret_cast<const unsigned short*>(buffer
));
2989 return (shortPath
.isEmpty() ? longPath
: shortPath
);
2993 * Open media file in external player
2995 bool lamexp_open_media_file(const QString
&mediaFilePath
)
2997 const static wchar_t *registryPrefix
[2] = { L
"SOFTWARE\\", L
"SOFTWARE\\Wow6432Node\\" };
2998 const static wchar_t *registryKeys
[3] =
3000 L
"Microsoft\\Windows\\CurrentVersion\\Uninstall\\{97D341C8-B0D1-4E4A-A49A-C30B52F168E9}",
3001 L
"Microsoft\\Windows\\CurrentVersion\\Uninstall\\{DB9E4EAB-2717-499F-8D56-4CC8A644AB60}",
3004 const static wchar_t *appNames
[4] = { L
"smplayer_portable.exe", L
"smplayer.exe", L
"MPUI.exe", L
"foobar2000.exe" };
3005 const static wchar_t *valueNames
[2] = { L
"InstallLocation", L
"InstallDir" };
3007 for(size_t i
= 0; i
< 3; i
++)
3009 for(size_t j
= 0; j
< 2; j
++)
3011 QString mplayerPath
;
3012 HKEY registryKeyHandle
= NULL
;
3014 const QString currentKey
= WCHAR2QSTR(registryPrefix
[j
]).append(WCHAR2QSTR(registryKeys
[i
]));
3015 if(RegOpenKeyExW(HKEY_LOCAL_MACHINE
, QWCHAR(currentKey
), 0, KEY_READ
, ®istryKeyHandle
) == ERROR_SUCCESS
)
3017 for(size_t k
= 0; k
< 2; k
++)
3019 wchar_t Buffer
[4096];
3020 DWORD BuffSize
= sizeof(wchar_t*) * 4096;
3021 DWORD DataType
= REG_NONE
;
3022 if(RegQueryValueExW(registryKeyHandle
, valueNames
[k
], 0, &DataType
, reinterpret_cast<BYTE
*>(Buffer
), &BuffSize
) == ERROR_SUCCESS
)
3024 if((DataType
== REG_SZ
) || (DataType
== REG_EXPAND_SZ
) || (DataType
== REG_LINK
))
3026 mplayerPath
= WCHAR2QSTR(Buffer
);
3031 RegCloseKey(registryKeyHandle
);
3034 if(!mplayerPath
.isEmpty())
3036 QDir
mplayerDir(mplayerPath
);
3037 if(mplayerDir
.exists())
3039 for(size_t k
= 0; k
< 4; k
++)
3041 if(mplayerDir
.exists(WCHAR2QSTR(appNames
[k
])))
3043 qDebug("Player found at:\n%s\n", QUTF8(mplayerDir
.absoluteFilePath(WCHAR2QSTR(appNames
[k
]))));
3044 QProcess::startDetached(mplayerDir
.absoluteFilePath(WCHAR2QSTR(appNames
[k
])), QStringList() << QDir::toNativeSeparators(mediaFilePath
));
3056 * Setup QPorcess object
3058 void lamexp_init_process(QProcess
&process
, const QString
&wokringDir
)
3060 //Environment variable names
3061 static const char *const s_envvar_names
[] =
3063 "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
3066 const QString tempDir
= QDir::toNativeSeparators(lamexp_temp_folder2());
3068 QProcessEnvironment env
= process
.processEnvironment();
3069 if(env
.isEmpty()) env
= QProcessEnvironment::systemEnvironment();
3071 //Setup TEMP directory
3072 env
.insert("TEMP", tempDir
);
3073 env
.insert("TMP", tempDir
);
3074 env
.insert("TMPDIR", tempDir
);
3075 env
.insert("HOME", tempDir
);
3076 env
.insert("USERPROFILE", tempDir
);
3077 env
.insert("HOMEPATH", tempDir
);
3079 //Setup PATH variable
3080 const QString path
= env
.value("PATH", QString());
3081 env
.insert("PATH", path
.isEmpty() ? tempDir
: QString("%1;%2").arg(tempDir
, path
));
3083 //Clean a number of enviroment variables that might affect our tools
3084 for(size_t i
= 0; s_envvar_names
[i
]; i
++)
3086 env
.remove(QString::fromLatin1(s_envvar_names
[i
]));
3087 env
.remove(QString::fromLatin1(s_envvar_names
[i
]).toLower());
3090 process
.setWorkingDirectory(wokringDir
);
3091 process
.setProcessChannelMode(QProcess::MergedChannels
);
3092 process
.setReadChannel(QProcess::StandardOutput
);
3093 process
.setProcessEnvironment(env
);
3097 * Entry point checks
3099 static DWORD
lamexp_entry_check(void);
3100 static DWORD g_lamexp_entry_check_result
= lamexp_entry_check();
3101 static DWORD g_lamexp_entry_check_flag
= 0x789E09B2;
3102 static DWORD
lamexp_entry_check(void)
3104 volatile DWORD retVal
= 0xA199B5AF;
3105 if(g_lamexp_entry_check_flag
!= 0x8761F64D)
3107 lamexp_fatal_exit(L
"Application initialization has failed, take care!");
3113 * Application entry point (runs before static initializers)
3117 int WinMainCRTStartup(void);
3119 int lamexp_entry_point(void)
3121 if((!LAMEXP_DEBUG
) && lamexp_check_for_debugger())
3123 lamexp_fatal_exit(L
"Not a debug build. Please unload debugger and try again!");
3125 if(g_lamexp_entry_check_flag
!= 0x789E09B2)
3127 lamexp_fatal_exit(L
"Application initialization has failed, take care!");
3130 //Zero *before* constructors are called
3131 LAMEXP_ZERO_MEMORY(g_lamexp_argv
);
3132 LAMEXP_ZERO_MEMORY(g_lamexp_tools
);
3133 LAMEXP_ZERO_MEMORY(g_lamexp_currentTranslator
);
3134 LAMEXP_ZERO_MEMORY(g_lamexp_translation
);
3135 LAMEXP_ZERO_MEMORY(g_lamexp_known_folder
);
3136 LAMEXP_ZERO_MEMORY(g_lamexp_temp_folder
);
3137 LAMEXP_ZERO_MEMORY(g_lamexp_ipc_ptr
);
3138 LAMEXP_ZERO_MEMORY(g_lamexp_os_version
);
3139 LAMEXP_ZERO_MEMORY(g_lamexp_themes_enabled
);
3140 LAMEXP_ZERO_MEMORY(g_lamexp_portable
);
3142 //Make sure we will pass the check
3143 g_lamexp_entry_check_flag
= ~g_lamexp_entry_check_flag
;
3145 //Now initialize the C Runtime library!
3146 return WinMainCRTStartup();
3151 * Fatal application exit
3153 #pragma intrinsic(_InterlockedExchange)
3154 void lamexp_fatal_exit(const wchar_t* exitMessage
, const wchar_t* errorBoxMessage
)
3156 static volatile long bFatalFlag
= 0L;
3158 if(_InterlockedExchange(&bFatalFlag
, 1L) == 0L)
3160 if(GetCurrentThreadId() != g_main_thread_id
)
3162 HANDLE mainThread
= OpenThread(THREAD_TERMINATE
, FALSE
, g_main_thread_id
);
3163 if(mainThread
) TerminateThread(mainThread
, ULONG_MAX
);
3168 MessageBoxW(NULL
, errorBoxMessage
, L
"LameXP - GURU MEDITATION", MB_ICONERROR
| MB_TOPMOST
| MB_TASKMODAL
);
3173 FatalAppExit(0, exitMessage
);
3174 TerminateProcess(GetCurrentProcess(), -1);
3178 TerminateThread(GetCurrentThread(), -1);
3183 * Finalization function (final clean-up)
3185 void lamexp_finalization(void)
3187 qDebug("lamexp_finalization()");
3190 if(g_lamexp_tools
.registry
)
3192 QStringList keys
= g_lamexp_tools
.registry
->keys();
3193 for(int i
= 0; i
< keys
.count(); i
++)
3195 LAMEXP_DELETE((*g_lamexp_tools
.registry
)[keys
.at(i
)]);
3197 LAMEXP_DELETE(g_lamexp_tools
.registry
);
3198 LAMEXP_DELETE(g_lamexp_tools
.versions
);
3199 LAMEXP_DELETE(g_lamexp_tools
.tags
);
3202 //Delete temporary files
3203 if(g_lamexp_temp_folder
.path
)
3205 if(!g_lamexp_temp_folder
.path
->isEmpty())
3207 bool success
= false;
3208 for(int i
= 0; i
< 100; i
++)
3210 if(lamexp_clean_folder(*g_lamexp_temp_folder
.path
))
3219 MessageBoxW(NULL
, L
"Sorry, LameXP was unable to clean up all temporary files. Some residual files in your TEMP directory may require manual deletion!", L
"LameXP", MB_ICONEXCLAMATION
|MB_TOPMOST
);
3220 lamexp_exec_shell(NULL
, *g_lamexp_temp_folder
.path
, QString(), QString(), true);
3223 LAMEXP_DELETE(g_lamexp_temp_folder
.path
);
3226 //Clear folder cache
3227 LAMEXP_DELETE(g_lamexp_known_folder
.knownFolders
);
3230 if(g_lamexp_currentTranslator
.instance
)
3232 QApplication::removeTranslator(g_lamexp_currentTranslator
.instance
);
3233 LAMEXP_DELETE(g_lamexp_currentTranslator
.instance
);
3235 LAMEXP_DELETE(g_lamexp_translation
.files
);
3236 LAMEXP_DELETE(g_lamexp_translation
.names
);
3237 LAMEXP_DELETE(g_lamexp_translation
.cntry
);
3238 LAMEXP_DELETE(g_lamexp_translation
.sysid
);
3240 //Destroy Qt application object
3241 QApplication
*application
= dynamic_cast<QApplication
*>(QApplication::instance());
3242 LAMEXP_DELETE(application
);
3244 //Detach from shared memory
3245 if(g_lamexp_ipc_ptr
.sharedmem
) g_lamexp_ipc_ptr
.sharedmem
->detach();
3246 LAMEXP_DELETE(g_lamexp_ipc_ptr
.sharedmem
);
3247 LAMEXP_DELETE(g_lamexp_ipc_ptr
.semaphore_read
);
3248 LAMEXP_DELETE(g_lamexp_ipc_ptr
.semaphore_write
);
3249 LAMEXP_DELETE(g_lamexp_ipc_ptr
.semaphore_read_mutex
);
3250 LAMEXP_DELETE(g_lamexp_ipc_ptr
.semaphore_write_mutex
);
3252 //Free STDOUT and STDERR buffers
3253 if(g_lamexp_console_attached
)
3255 if(std::filebuf
*tmp
= dynamic_cast<std::filebuf
*>(std::cout
.rdbuf()))
3257 std::cout
.rdbuf(NULL
);
3260 if(std::filebuf
*tmp
= dynamic_cast<std::filebuf
*>(std::cerr
.rdbuf()))
3262 std::cerr
.rdbuf(NULL
);
3268 if(g_lamexp_log_file
)
3270 fclose(g_lamexp_log_file
);
3271 g_lamexp_log_file
= NULL
;
3274 //Free CLI Arguments
3275 LAMEXP_DELETE(g_lamexp_argv
.list
);
3279 * Initialize debug thread
3281 static const HANDLE g_debug_thread1
= LAMEXP_DEBUG
? NULL
: lamexp_debug_thread_init();
3284 * Get number private bytes [debug only]
3286 unsigned long lamexp_dbg_private_bytes(void)
3289 for(int i
= 0; i
< 8; i
++) _heapmin();
3290 PROCESS_MEMORY_COUNTERS_EX memoryCounters
;
3291 memoryCounters
.cb
= sizeof(PROCESS_MEMORY_COUNTERS_EX
);
3292 GetProcessMemoryInfo(GetCurrentProcess(), (PPROCESS_MEMORY_COUNTERS
) &memoryCounters
, sizeof(PROCESS_MEMORY_COUNTERS_EX
));
3293 return memoryCounters
.PrivateUsage
;
3295 THROW("Cannot call this function in a non-debug build!");
3296 #endif //LAMEXP_DEBUG