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 ///////////////////////////////////////////////////////////////////////////////
26 #include "Targetver.h"
28 //Visual Leaks Detector
33 #define WIN32_LEAN_AND_MEAN
44 #include <QApplication>
49 #include <QImageReader>
51 #include <QLibraryInfo>
53 #include <QMessageBox>
55 #include <QPlastiqueStyle>
57 #include <QReadWriteLock>
62 #include <QTranslator>
66 #define LAMEXP_INC_CONFIG
82 //Initialize static Qt plugins
84 #if QT_VERSION < QT_VERSION_CHECK(5,0,0)
88 Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin)
89 Q_IMPORT_PLUGIN(QICOPlugin)
93 ///////////////////////////////////////////////////////////////////////////////
95 ///////////////////////////////////////////////////////////////////////////////
97 #define _LAMEXP_MAKE_STR(STR) #STR
98 #define LAMEXP_MAKE_STR(STR) _LAMEXP_MAKE_STR(STR)
101 #define CLEAN_OUTPUT_STRING(STR) do \
103 const char CTRL_CHARS[3] = { '\r', '\n', '\t' }; \
104 for(size_t i = 0; i < 3; i++) \
106 while(char *pos = strchr((STR), CTRL_CHARS[i])) *pos = char(0x20); \
112 #define TRIM_LEFT(STR) do \
114 const char WHITE_SPACE[4] = { char(0x20), '\r', '\n', '\t' }; \
115 for(size_t i = 0; i < 4; i++) \
117 while(*(STR) == WHITE_SPACE[i]) (STR)++; \
122 ///////////////////////////////////////////////////////////////////////////////
124 ///////////////////////////////////////////////////////////////////////////////
126 //Console attached flag
127 static bool g_lamexp_console_attached = false;
132 QMap<size_t, QString> *knownFolders;
135 g_lamexp_known_folder;
149 lamexp_os_version_t version;
163 //Win32 Theme support
170 g_lamexp_themes_enabled;
172 //Win32 DWM API functions
176 HRESULT (__stdcall *dwmIsCompositionEnabled)(BOOL *bEnabled);
177 HRESULT (__stdcall *dwmExtendFrameIntoClientArea)(HWND hWnd, const MARGINS* pMarInset);
178 HRESULT (__stdcall *dwmEnableBlurBehindWindow)(HWND hWnd, const DWM_BLURBEHIND* pBlurBehind);
179 QLibrary *dwmapi_dll;
185 static const char *g_lamexp_imageformats[] = {"bmp", "png", "jpg", "gif", "ico", "xpm", NULL}; //"svg"
188 static QMutex g_lamexp_message_mutex;
191 static const DWORD g_main_thread_id = GetCurrentThreadId();
194 static FILE *g_lamexp_log_file = NULL;
197 const char* LAMEXP_DEFAULT_LANGID = "en";
198 const char* LAMEXP_DEFAULT_TRANSLATION = "LameXP_EN.qm";
200 //Known Windows versions - maps marketing names to the actual Windows NT versions
201 const lamexp_os_version_t lamexp_winver_win2k = {5,0};
202 const lamexp_os_version_t lamexp_winver_winxp = {5,1};
203 const lamexp_os_version_t lamexp_winver_xpx64 = {5,2};
204 const lamexp_os_version_t lamexp_winver_vista = {6,0};
205 const lamexp_os_version_t lamexp_winver_win70 = {6,1};
206 const lamexp_os_version_t lamexp_winver_win80 = {6,2};
207 const lamexp_os_version_t lamexp_winver_win81 = {6,3};
210 static const char *GURU_MEDITATION = "\n\nGURU MEDITATION !!!\n\n";
212 ///////////////////////////////////////////////////////////////////////////////
214 ///////////////////////////////////////////////////////////////////////////////
217 * Verify a specific Windows version
219 static bool lamexp_verify_os_version(const DWORD major, const DWORD minor)
221 OSVERSIONINFOEXW osvi;
222 DWORDLONG dwlConditionMask = 0;
224 //Initialize the OSVERSIONINFOEX structure
225 memset(&osvi, 0, sizeof(OSVERSIONINFOEXW));
226 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW);
227 osvi.dwMajorVersion = major;
228 osvi.dwMinorVersion = minor;
229 osvi.dwPlatformId = VER_PLATFORM_WIN32_NT;
231 //Initialize the condition mask
232 VER_SET_CONDITION(dwlConditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL);
233 VER_SET_CONDITION(dwlConditionMask, VER_MINORVERSION, VER_GREATER_EQUAL);
234 VER_SET_CONDITION(dwlConditionMask, VER_PLATFORMID, VER_EQUAL);
237 const BOOL ret = VerifyVersionInfoW(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_PLATFORMID, dwlConditionMask);
242 if(GetLastError() != ERROR_OLD_WIN_VERSION)
244 qWarning("VerifyVersionInfo() system call has failed!");
248 return (ret != FALSE);
252 * Determine the *real* Windows version
254 static bool lamexp_get_real_os_version(unsigned int *major, unsigned int *minor, bool *pbOverride)
259 //Initialize local variables
260 OSVERSIONINFOEXW osvi;
261 memset(&osvi, 0, sizeof(OSVERSIONINFOEXW));
262 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW);
264 //Try GetVersionEx() first
265 if(GetVersionExW((LPOSVERSIONINFOW)&osvi) == FALSE)
267 qWarning("GetVersionEx() has failed, cannot detect Windows version!");
271 //Make sure we are running on NT
272 if(osvi.dwPlatformId == VER_PLATFORM_WIN32_NT)
274 *major = osvi.dwMajorVersion;
275 *minor = osvi.dwMinorVersion;
279 qWarning("Not running on Windows NT, unsupported operating system!");
283 //Determine the real *major* version first
286 const DWORD nextMajor = (*major) + 1;
287 if(lamexp_verify_os_version(nextMajor, 0))
297 //Now also determine the real *minor* version
300 const DWORD nextMinor = (*minor) + 1;
301 if(lamexp_verify_os_version((*major), nextMinor))
314 * Get the native operating system version
316 const lamexp_os_version_t &lamexp_get_os_version(void)
318 QReadLocker readLock(&g_lamexp_os_version.lock);
320 //Already initialized?
321 if(g_lamexp_os_version.bInitialized)
323 return g_lamexp_os_version.version;
327 QWriteLocker writeLock(&g_lamexp_os_version.lock);
330 if(!g_lamexp_os_version.bInitialized)
332 unsigned int major, minor; bool oflag;
333 if(lamexp_get_real_os_version(&major, &minor, &oflag))
335 g_lamexp_os_version.version.versionMajor = major;
336 g_lamexp_os_version.version.versionMinor = minor;
337 g_lamexp_os_version.version.overrideFlag = oflag;
338 g_lamexp_os_version.bInitialized = true;
342 qWarning("Failed to determin the operating system version!");
346 return g_lamexp_os_version.version;
350 * Check if we are running under wine
352 bool lamexp_detect_wine(void)
354 QReadLocker readLock(&g_lamexp_wine.lock);
356 //Already initialized?
357 if(g_lamexp_wine.bInitialized)
359 return g_lamexp_wine.bIsWine;
363 QWriteLocker writeLock(&g_lamexp_wine.lock);
365 if(!g_lamexp_wine.bInitialized)
367 g_lamexp_wine.bIsWine = false;
368 QLibrary ntdll("ntdll.dll");
371 if(ntdll.resolve("wine_nt_to_unix_file_name") != NULL) g_lamexp_wine.bIsWine = true;
372 if(ntdll.resolve("wine_get_version") != NULL) g_lamexp_wine.bIsWine = true;
375 g_lamexp_wine.bInitialized = true;
378 return g_lamexp_wine.bIsWine;
382 * Change console text color
384 static void lamexp_console_color(FILE* file, WORD attributes)
386 const HANDLE hConsole = (HANDLE)(_get_osfhandle(_fileno(file)));
387 if((hConsole != NULL) && (hConsole != INVALID_HANDLE_VALUE))
389 SetConsoleTextAttribute(hConsole, attributes);
394 * Output logging message to console
396 static void lamexp_write_console(const int type, const char *msg)
400 if(_isatty(_fileno(stderr)))
402 UINT oldOutputCP = GetConsoleOutputCP();
403 if(oldOutputCP != CP_UTF8) SetConsoleOutputCP(CP_UTF8);
409 lamexp_console_color(stderr, FOREGROUND_RED | FOREGROUND_INTENSITY);
410 fprintf(stderr, GURU_MEDITATION);
411 fprintf(stderr, "%s\n", msg);
415 lamexp_console_color(stderr, FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY);
416 fprintf(stderr, "%s\n", msg);
420 lamexp_console_color(stderr, FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY);
421 fprintf(stderr, "%s\n", msg);
426 lamexp_console_color(stderr, FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED);
427 if(oldOutputCP != CP_UTF8) SetConsoleOutputCP(oldOutputCP);
432 /*ignore any exception that might occur here!*/
437 * Output logging message to debugger
439 static void lamexp_write_dbg_out(const int type, const char *msg)
441 const char *FORMAT = "[LameXP][%c] %s\n";
446 const char* input = msg;
453 _snprintf_s(buffer, 512, _TRUNCATE, FORMAT, 'C', input);
456 _snprintf_s(buffer, 512, _TRUNCATE, FORMAT, 'W', input);
459 _snprintf_s(buffer, 512, _TRUNCATE, FORMAT, 'I', input);
463 char *temp = &buffer[0];
464 CLEAN_OUTPUT_STRING(temp);
465 OutputDebugStringA(temp);
469 /*ignore any exception that might occur here!*/
474 * Output logging message to logfile
476 static void lamexp_write_logfile(const int type, const char *msg)
478 const char *FORMAT = "[%c][%04u] %s\r\n";
482 if(g_lamexp_log_file)
485 strncpy_s(buffer, 512, msg, _TRUNCATE);
487 char *temp = &buffer[0];
489 CLEAN_OUTPUT_STRING(temp);
491 const unsigned int timestamp = static_cast<unsigned int>(_time64(NULL) % 3600I64);
497 fprintf(g_lamexp_log_file, FORMAT, 'C', timestamp, temp);
500 fprintf(g_lamexp_log_file, FORMAT, 'W', timestamp, temp);
503 fprintf(g_lamexp_log_file, FORMAT, 'I', timestamp, temp);
507 fflush(g_lamexp_log_file);
512 /*ignore any exception that might occur here!*/
519 void lamexp_message_handler(QtMsgType type, const char *msg)
521 if((!msg) || (!(msg[0])))
526 QMutexLocker lock(&g_lamexp_message_mutex);
528 if(g_lamexp_log_file)
530 lamexp_write_logfile(type, msg);
533 if(g_lamexp_console_attached)
535 lamexp_write_console(type, msg);
539 lamexp_write_dbg_out(type, msg);
542 if((type == QtCriticalMsg) || (type == QtFatalMsg))
545 lamexp_fatal_exit(L"The application has encountered a critical error and will exit now!", QWCHAR(QString::fromUtf8(msg)));
550 * Invalid parameters handler
552 static void lamexp_invalid_param_handler(const wchar_t* exp, const wchar_t* fun, const wchar_t* fil, unsigned int, uintptr_t)
554 lamexp_fatal_exit(L"Invalid parameter handler invoked, application will exit!");
560 static void lamexp_signal_handler(int signal_num)
562 signal(signal_num, lamexp_signal_handler);
563 lamexp_fatal_exit(L"Signal handler invoked, application will exit!");
567 * Global exception handler
569 static LONG WINAPI lamexp_exception_handler(struct _EXCEPTION_POINTERS *ExceptionInfo)
571 lamexp_fatal_exit(L"Unhandeled exception handler invoked, application will exit!");
576 * Initialize error handlers
578 void lamexp_init_error_handlers(void)
580 SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
581 SetUnhandledExceptionFilter(lamexp_exception_handler);
582 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
583 _set_invalid_parameter_handler(lamexp_invalid_param_handler);
585 static const int signal_num[6] = { SIGABRT, SIGFPE, SIGILL, SIGINT, SIGSEGV, SIGTERM };
587 for(size_t i = 0; i < 6; i++)
589 signal(signal_num[i], lamexp_signal_handler);
594 * Initialize the console
596 void lamexp_init_console(const QStringList &argv)
598 bool enableConsole = (LAMEXP_DEBUG) || ((VER_LAMEXP_CONSOLE_ENABLED) && lamexp_version_demo());
602 wchar_t *logfile = NULL;
603 size_t logfile_len = 0;
604 if(!_wdupenv_s(&logfile, &logfile_len, L"LAMEXP_LOGFILE"))
606 if(logfile && (logfile_len > 0))
609 if(!_wfopen_s(&temp, logfile, L"wb"))
611 fprintf(temp, "%c%c%c", char(0xEF), char(0xBB), char(0xBF));
612 g_lamexp_log_file = temp;
621 for(int i = 0; i < argv.count(); i++)
623 if(!argv.at(i).compare("--console", Qt::CaseInsensitive))
625 enableConsole = true;
627 else if(!argv.at(i).compare("--no-console", Qt::CaseInsensitive))
629 enableConsole = false;
636 if(!g_lamexp_console_attached)
638 if(AllocConsole() != FALSE)
640 SetConsoleCtrlHandler(NULL, TRUE);
641 SetConsoleTitle(L"LameXP - Audio Encoder Front-End | Debug Console");
642 SetConsoleOutputCP(CP_UTF8);
643 g_lamexp_console_attached = true;
647 if(g_lamexp_console_attached)
649 //-------------------------------------------------------------------
650 //See: http://support.microsoft.com/default.aspx?scid=kb;en-us;105305
651 //-------------------------------------------------------------------
652 const int flags = _O_WRONLY | _O_U8TEXT;
653 int hCrtStdOut = _open_osfhandle((intptr_t) GetStdHandle(STD_OUTPUT_HANDLE), flags);
654 int hCrtStdErr = _open_osfhandle((intptr_t) GetStdHandle(STD_ERROR_HANDLE), flags);
655 FILE *hfStdOut = (hCrtStdOut >= 0) ? _fdopen(hCrtStdOut, "wb") : NULL;
656 FILE *hfStdErr = (hCrtStdErr >= 0) ? _fdopen(hCrtStdErr, "wb") : NULL;
657 if(hfStdOut) { *stdout = *hfStdOut; std::cout.rdbuf(new std::filebuf(hfStdOut)); }
658 if(hfStdErr) { *stderr = *hfStdErr; std::cerr.rdbuf(new std::filebuf(hfStdErr)); }
661 HWND hwndConsole = GetConsoleWindow();
663 if((hwndConsole != NULL) && (hwndConsole != INVALID_HANDLE_VALUE))
665 HMENU hMenu = GetSystemMenu(hwndConsole, 0);
666 EnableMenuItem(hMenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);
667 RemoveMenu(hMenu, SC_CLOSE, MF_BYCOMMAND);
669 SetWindowPos(hwndConsole, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_FRAMECHANGED);
670 SetWindowLong(hwndConsole, GWL_STYLE, GetWindowLong(hwndConsole, GWL_STYLE) & (~WS_MAXIMIZEBOX) & (~WS_MINIMIZEBOX));
671 SetWindowPos(hwndConsole, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_FRAMECHANGED);
677 * Detect CPU features
679 lamexp_cpu_t lamexp_detect_cpu_features(const QStringList &argv)
681 typedef BOOL (WINAPI *IsWow64ProcessFun)(__in HANDLE hProcess, __out PBOOL Wow64Process);
683 lamexp_cpu_t features;
684 SYSTEM_INFO systemInfo;
685 int CPUInfo[4] = {-1};
686 char CPUIdentificationString[0x40];
687 char CPUBrandString[0x40];
689 memset(&features, 0, sizeof(lamexp_cpu_t));
690 memset(&systemInfo, 0, sizeof(SYSTEM_INFO));
691 memset(CPUIdentificationString, 0, sizeof(CPUIdentificationString));
692 memset(CPUBrandString, 0, sizeof(CPUBrandString));
695 memcpy(CPUIdentificationString, &CPUInfo[1], sizeof(int));
696 memcpy(CPUIdentificationString + 4, &CPUInfo[3], sizeof(int));
697 memcpy(CPUIdentificationString + 8, &CPUInfo[2], sizeof(int));
698 features.intel = (_stricmp(CPUIdentificationString, "GenuineIntel") == 0);
699 strncpy_s(features.vendor, 0x40, CPUIdentificationString, _TRUNCATE);
704 features.mmx = (CPUInfo[3] & 0x800000) || false;
705 features.sse = (CPUInfo[3] & 0x2000000) || false;
706 features.sse2 = (CPUInfo[3] & 0x4000000) || false;
707 features.ssse3 = (CPUInfo[2] & 0x200) || false;
708 features.sse3 = (CPUInfo[2] & 0x1) || false;
709 features.ssse3 = (CPUInfo[2] & 0x200) || false;
710 features.stepping = CPUInfo[0] & 0xf;
711 features.model = ((CPUInfo[0] >> 4) & 0xf) + (((CPUInfo[0] >> 16) & 0xf) << 4);
712 features.family = ((CPUInfo[0] >> 8) & 0xf) + ((CPUInfo[0] >> 20) & 0xff);
715 __cpuid(CPUInfo, 0x80000000);
716 int nExIds = qMax<int>(qMin<int>(CPUInfo[0], 0x80000004), 0x80000000);
718 for(int i = 0x80000002; i <= nExIds; ++i)
724 memcpy(CPUBrandString, CPUInfo, sizeof(CPUInfo));
727 memcpy(CPUBrandString + 16, CPUInfo, sizeof(CPUInfo));
730 memcpy(CPUBrandString + 32, CPUInfo, sizeof(CPUInfo));
735 strncpy_s(features.brand, 0x40, CPUBrandString, _TRUNCATE);
737 if(strlen(features.brand) < 1) strncpy_s(features.brand, 0x40, "Unknown", _TRUNCATE);
738 if(strlen(features.vendor) < 1) strncpy_s(features.vendor, 0x40, "Unknown", _TRUNCATE);
740 #if (!(defined(_M_X64) || defined(_M_IA64)))
741 QLibrary Kernel32Lib("kernel32.dll");
742 if(IsWow64ProcessFun IsWow64ProcessPtr = (IsWow64ProcessFun) Kernel32Lib.resolve("IsWow64Process"))
744 BOOL x64flag = FALSE;
745 if(IsWow64ProcessPtr(GetCurrentProcess(), &x64flag))
747 features.x64 = (x64flag == TRUE);
754 DWORD_PTR procAffinity, sysAffinity;
755 if(GetProcessAffinityMask(GetCurrentProcess(), &procAffinity, &sysAffinity))
757 for(DWORD_PTR mask = 1; mask; mask <<= 1)
759 features.count += ((sysAffinity & mask) ? (1) : (0));
762 if(features.count < 1)
764 GetNativeSystemInfo(&systemInfo);
765 features.count = qBound(1UL, systemInfo.dwNumberOfProcessors, 64UL);
771 for(int i = 0; i < argv.count(); i++)
773 if(!argv[i].compare("--force-cpu-no-64bit", Qt::CaseInsensitive)) { flag = true; features.x64 = false; }
774 if(!argv[i].compare("--force-cpu-no-sse", Qt::CaseInsensitive)) { flag = true; features.sse = features.sse2 = features.sse3 = features.ssse3 = false; }
775 if(!argv[i].compare("--force-cpu-no-intel", Qt::CaseInsensitive)) { flag = true; features.intel = false; }
777 if(flag) qWarning("CPU flags overwritten by user-defined parameters. Take care!\n");
784 * Check for debugger (detect routine)
786 static __forceinline bool lamexp_check_for_debugger(void)
790 CloseHandle((HANDLE)((DWORD_PTR)-3));
802 return IsDebuggerPresent();
808 * Check for debugger (thread proc)
810 static unsigned int __stdcall lamexp_debug_thread_proc(LPVOID lpParameter)
812 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_LOWEST);
815 if(lamexp_check_for_debugger())
817 lamexp_fatal_exit(L"Not a debug build. Please unload debugger and try again!");
825 * Check for debugger (startup routine)
827 static HANDLE lamexp_debug_thread_init()
829 if(lamexp_check_for_debugger())
831 lamexp_fatal_exit(L"Not a debug build. Please unload debugger and try again!");
833 const uintptr_t h = _beginthreadex(NULL, 0, lamexp_debug_thread_proc, NULL, 0, NULL);
834 return (HANDLE)(h^0xdeadbeef);
840 static bool lamexp_event_filter(void *message, long *result)
842 if((!(LAMEXP_DEBUG)) && lamexp_check_for_debugger())
844 lamexp_fatal_exit(L"Not a debug build. Please unload debugger and try again!");
847 switch(reinterpret_cast<MSG*>(message)->message)
849 case WM_QUERYENDSESSION:
850 qWarning("WM_QUERYENDSESSION message received!");
851 *result = lamexp_broadcast(lamexp_event_queryendsession, false) ? TRUE : FALSE;
854 qWarning("WM_ENDSESSION message received!");
855 if(reinterpret_cast<MSG*>(message)->wParam == TRUE)
857 lamexp_broadcast(lamexp_event_endsession, false);
858 if(QApplication *app = reinterpret_cast<QApplication*>(QApplication::instance()))
860 app->closeAllWindows();
863 lamexp_finalization();
869 /*ignore this message and let Qt handle it*/
875 * Check for process elevation
877 static bool lamexp_check_elevation(void)
879 typedef enum { lamexp_token_elevationType_class = 18, lamexp_token_elevation_class = 20 } LAMEXP_TOKEN_INFORMATION_CLASS;
880 typedef enum { lamexp_elevationType_default = 1, lamexp_elevationType_full, lamexp_elevationType_limited } LAMEXP_TOKEN_ELEVATION_TYPE;
882 HANDLE hToken = NULL;
883 bool bIsProcessElevated = false;
885 if(OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
887 LAMEXP_TOKEN_ELEVATION_TYPE tokenElevationType;
889 if(GetTokenInformation(hToken, (TOKEN_INFORMATION_CLASS) lamexp_token_elevationType_class, &tokenElevationType, sizeof(LAMEXP_TOKEN_ELEVATION_TYPE), &returnLength))
891 if(returnLength == sizeof(LAMEXP_TOKEN_ELEVATION_TYPE))
893 switch(tokenElevationType)
895 case lamexp_elevationType_default:
896 qDebug("Process token elevation type: Default -> UAC is disabled.\n");
898 case lamexp_elevationType_full:
899 qWarning("Process token elevation type: Full -> potential security risk!\n");
900 bIsProcessElevated = true;
902 case lamexp_elevationType_limited:
903 qDebug("Process token elevation type: Limited -> not elevated.\n");
912 qWarning("Failed to open process token!");
915 return !bIsProcessElevated;
919 * Convert QIcon to HICON -> caller is responsible for destroying the HICON!
921 static HICON lamexp_qicon2hicon(const QIcon &icon, const int w, const int h)
925 QPixmap pixmap = icon.pixmap(w, h);
928 return pixmap.toWinHICON();
935 * Initialize Qt framework
937 bool lamexp_init_qt(int argc, char* argv[])
939 static bool qt_initialized = false;
940 typedef BOOL (WINAPI *SetDllDirectoryProc)(WCHAR *lpPathName);
941 const QStringList &arguments = lamexp_arguments();
943 //Don't initialized again, if done already
950 QLibrary kernel32("kernel32.dll");
953 SetDllDirectoryProc pSetDllDirectory = (SetDllDirectoryProc) kernel32.resolve("SetDllDirectoryW");
954 if(pSetDllDirectory != NULL) pSetDllDirectory(L"");
957 //Extract executable name from argv[] array
958 QString executableName = QLatin1String("LameXP.exe");
959 if(arguments.count() > 0)
961 static const char *delimiters = "\\/:?";
962 executableName = arguments[0].trimmed();
963 for(int i = 0; delimiters[i]; i++)
965 int temp = executableName.lastIndexOf(QChar(delimiters[i]));
966 if(temp >= 0) executableName = executableName.mid(temp + 1);
968 executableName = executableName.trimmed();
969 if(executableName.isEmpty())
971 executableName = QLatin1String("LameXP.exe");
977 qDebug("Using Qt v%s [%s], %s, %s", qVersion(), QLibraryInfo::buildDate().toString(Qt::ISODate).toLatin1().constData(), (qSharedBuild() ? "DLL" : "Static"), QLibraryInfo::buildKey().toLatin1().constData());
978 qDebug("Compiled with Qt v%s [%s], %s\n", QT_VERSION_STR, QT_PACKAGEDATE_STR, QT_BUILD_KEY);
979 if(_stricmp(qVersion(), QT_VERSION_STR))
981 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());
984 if(QLibraryInfo::buildKey().compare(QString::fromLatin1(QT_BUILD_KEY), Qt::CaseInsensitive))
986 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());
990 qDebug("Using Qt v%s [%s], %s", qVersion(), QLibraryInfo::buildDate().toString(Qt::ISODate).toLatin1().constData(), (qSharedBuild() ? "DLL" : "Static"));
991 qDebug("Compiled with Qt v%s [%s]\n", QT_VERSION_STR, QT_PACKAGEDATE_STR);
994 //Check the Windows version
995 const lamexp_os_version_t &osVersionNo = lamexp_get_os_version();
996 if(osVersionNo < lamexp_winver_winxp)
998 qFatal("%s", QApplication::tr("Executable '%1' requires Windows XP or later.").arg(executableName).toLatin1().constData());
1001 //Supported Windows version?
1002 if(osVersionNo == lamexp_winver_winxp)
1004 qDebug("Running on Windows XP or Windows XP Media Center Edition.\n"); //lamexp_check_compatibility_mode("GetLargePageMinimum", executableName);
1006 else if(osVersionNo == lamexp_winver_xpx64)
1008 qDebug("Running on Windows Server 2003, Windows Server 2003 R2 or Windows XP x64.\n"); //lamexp_check_compatibility_mode("GetLocaleInfoEx", executableName);
1010 else if(osVersionNo == lamexp_winver_vista)
1012 qDebug("Running on Windows Vista or Windows Server 2008.\n"); //lamexp_check_compatibility_mode("CreateRemoteThreadEx", executableName*/);
1014 else if(osVersionNo == lamexp_winver_win70)
1016 qDebug("Running on Windows 7 or Windows Server 2008 R2.\n"); //lamexp_check_compatibility_mode("CreateFile2", executableName);
1018 else if(osVersionNo == lamexp_winver_win80)
1020 qDebug("Running on Windows 8 or Windows Server 2012.\n"); //lamexp_check_compatibility_mode("FindPackagesByPackageFamily", executableName);
1022 else if(osVersionNo == lamexp_winver_win81)
1024 qDebug("Running on Windows 8.1 or Windows Server 2012 R2.\n"); //lamexp_check_compatibility_mode(NULL, executableName);
1028 const QString message = QString().sprintf("Running on an unknown WindowsNT-based system (v%u.%u).", osVersionNo.versionMajor, osVersionNo.versionMinor);
1029 qWarning("%s\n", QUTF8(message));
1030 MessageBoxW(NULL, QWCHAR(message), L"LameXP", MB_OK | MB_TOPMOST | MB_ICONWARNING);
1033 //Check for compat mode
1034 if(osVersionNo.overrideFlag && (osVersionNo <= lamexp_winver_win81))
1036 qWarning("Windows compatibility mode detected!");
1037 if(!arguments.contains("--ignore-compat-mode", Qt::CaseInsensitive))
1039 qFatal("%s", QApplication::tr("Executable '%1' doesn't support Windows compatibility mode.").arg(executableName).toLatin1().constData());
1045 if(lamexp_detect_wine())
1047 qWarning("It appears we are running under Wine, unexpected things might happen!\n");
1050 //Set text Codec for locale
1051 QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"));
1053 //Create Qt application instance
1054 QApplication *application = new QApplication(argc, argv);
1056 //Load plugins from application directory
1057 QCoreApplication::setLibraryPaths(QStringList() << QApplication::applicationDirPath());
1058 qDebug("Library Path:\n%s\n", QUTF8(QApplication::libraryPaths().first()));
1060 //Set application properties
1061 application->setApplicationName("LameXP - Audio Encoder Front-End");
1062 application->setApplicationVersion(QString().sprintf("%d.%02d.%04d", lamexp_version_major(), lamexp_version_minor(), lamexp_version_build()));
1063 application->setOrganizationName("LoRd_MuldeR");
1064 application->setOrganizationDomain("mulder.at.gg");
1065 application->setWindowIcon(lamexp_app_icon());
1066 application->setEventFilter(lamexp_event_filter);
1068 //Check for supported image formats
1069 QList<QByteArray> supportedFormats = QImageReader::supportedImageFormats();
1070 for(int i = 0; g_lamexp_imageformats[i]; i++)
1072 if(!supportedFormats.contains(g_lamexp_imageformats[i]))
1074 qFatal("Qt initialization error: QImageIOHandler for '%s' missing!", g_lamexp_imageformats[i]);
1079 //Add the default translations
1080 lamexp_translation_init();
1082 //Check for process elevation
1083 if((!lamexp_check_elevation()) && (!lamexp_detect_wine()))
1085 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);
1086 messageBox.addButton("Quit Program (Recommended)", QMessageBox::NoRole);
1087 messageBox.addButton("Ignore", QMessageBox::NoRole);
1088 if(messageBox.exec() == 0)
1094 //Update console icon, if a console is attached
1095 #if QT_VERSION < QT_VERSION_CHECK(5,0,0)
1096 if(g_lamexp_console_attached && (!lamexp_detect_wine()))
1098 QLibrary kernel32("kernel32.dll");
1101 typedef DWORD (__stdcall *SetConsoleIconFun)(HICON);
1102 if(SetConsoleIconFun SetConsoleIconPtr = (SetConsoleIconFun) kernel32.resolve("SetConsoleIcon"))
1104 if(HICON hIcon = lamexp_qicon2hicon(QIcon(":/icons/sound.png"), 16, 16))
1106 SetConsoleIconPtr(hIcon);
1115 qt_initialized = true;
1119 const QStringList &lamexp_arguments(void)
1121 QReadLocker readLock(&g_lamexp_argv.lock);
1123 if(!g_lamexp_argv.list)
1126 QWriteLocker writeLock(&g_lamexp_argv.lock);
1128 g_lamexp_argv.list = new QStringList;
1131 LPWSTR *szArglist = CommandLineToArgvW(GetCommandLineW(), &nArgs);
1133 if(NULL != szArglist)
1135 for(int i = 0; i < nArgs; i++)
1137 (*g_lamexp_argv.list) << WCHAR2QSTR(szArglist[i]);
1139 LocalFree(szArglist);
1143 qWarning("CommandLineToArgvW() has failed !!!");
1147 return (*g_lamexp_argv.list);
1151 * Locate known folder on local system
1153 const QString &lamexp_known_folder(lamexp_known_folder_t folder_id)
1155 typedef HRESULT (WINAPI *SHGetKnownFolderPathFun)(__in const GUID &rfid, __in DWORD dwFlags, __in HANDLE hToken, __out PWSTR *ppszPath);
1156 typedef HRESULT (WINAPI *SHGetFolderPathFun)(__in HWND hwndOwner, __in int nFolder, __in HANDLE hToken, __in DWORD dwFlags, __out LPWSTR pszPath);
1158 static const int CSIDL_LOCAL_APPDATA = 0x001c;
1159 static const int CSIDL_PROGRAM_FILES = 0x0026;
1160 static const int CSIDL_SYSTEM_FOLDER = 0x0025;
1161 static const GUID GUID_LOCAL_APPDATA = {0xF1B32785,0x6FBA,0x4FCF,{0x9D,0x55,0x7B,0x8E,0x7F,0x15,0x70,0x91}};
1162 static const GUID GUID_LOCAL_APPDATA_LOW = {0xA520A1A4,0x1780,0x4FF6,{0xBD,0x18,0x16,0x73,0x43,0xC5,0xAF,0x16}};
1163 static const GUID GUID_PROGRAM_FILES = {0x905e63b6,0xc1bf,0x494e,{0xb2,0x9c,0x65,0xb7,0x32,0xd3,0xd2,0x1a}};
1164 static const GUID GUID_SYSTEM_FOLDER = {0x1AC14E77,0x02E7,0x4E5D,{0xB7,0x44,0x2E,0xB1,0xAE,0x51,0x98,0xB7}};
1166 QReadLocker readLock(&g_lamexp_known_folder.lock);
1168 int folderCSIDL = -1;
1169 GUID folderGUID = {0x0000,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}};
1170 size_t folderCacheId = size_t(-1);
1174 case lamexp_folder_localappdata:
1176 folderCSIDL = CSIDL_LOCAL_APPDATA;
1177 folderGUID = GUID_LOCAL_APPDATA;
1179 case lamexp_folder_programfiles:
1181 folderCSIDL = CSIDL_PROGRAM_FILES;
1182 folderGUID = GUID_PROGRAM_FILES;
1184 case lamexp_folder_systemfolder:
1186 folderCSIDL = CSIDL_SYSTEM_FOLDER;
1187 folderGUID = GUID_SYSTEM_FOLDER;
1190 qWarning("Invalid 'known' folder was requested!");
1191 return *reinterpret_cast<QString*>(NULL);
1196 if(g_lamexp_known_folder.knownFolders)
1198 if(g_lamexp_known_folder.knownFolders->contains(folderCacheId))
1200 return (*g_lamexp_known_folder.knownFolders)[folderCacheId];
1204 //Obtain write lock to initialize
1206 QWriteLocker writeLock(&g_lamexp_known_folder.lock);
1208 //Still not in cache?
1209 if(g_lamexp_known_folder.knownFolders)
1211 if(g_lamexp_known_folder.knownFolders->contains(folderCacheId))
1213 return (*g_lamexp_known_folder.knownFolders)[folderCacheId];
1217 static SHGetKnownFolderPathFun SHGetKnownFolderPathPtr = NULL;
1218 static SHGetFolderPathFun SHGetFolderPathPtr = NULL;
1221 if((!SHGetKnownFolderPathPtr) && (!SHGetFolderPathPtr))
1223 QLibrary kernel32Lib("shell32.dll");
1224 if(kernel32Lib.load())
1226 SHGetKnownFolderPathPtr = (SHGetKnownFolderPathFun) kernel32Lib.resolve("SHGetKnownFolderPath");
1227 SHGetFolderPathPtr = (SHGetFolderPathFun) kernel32Lib.resolve("SHGetFolderPathW");
1233 //Now try to get the folder path!
1234 if(SHGetKnownFolderPathPtr)
1237 if(SHGetKnownFolderPathPtr(folderGUID, 0x00008000, NULL, &path) == S_OK)
1239 //MessageBoxW(0, path, L"SHGetKnownFolderPath", MB_TOPMOST);
1240 QDir folderTemp = QDir(QDir::fromNativeSeparators(QString::fromUtf16(reinterpret_cast<const unsigned short*>(path))));
1241 if(!folderTemp.exists())
1243 folderTemp.mkpath(".");
1245 if(folderTemp.exists())
1247 folder = folderTemp.canonicalPath();
1249 CoTaskMemFree(path);
1252 else if(SHGetFolderPathPtr)
1254 WCHAR *path = new WCHAR[4096];
1255 if(SHGetFolderPathPtr(NULL, folderCSIDL, NULL, NULL, path) == S_OK)
1257 //MessageBoxW(0, path, L"SHGetFolderPathW", MB_TOPMOST);
1258 QDir folderTemp = QDir(QDir::fromNativeSeparators(QString::fromUtf16(reinterpret_cast<const unsigned short*>(path))));
1259 if(!folderTemp.exists())
1261 folderTemp.mkpath(".");
1263 if(folderTemp.exists())
1265 folder = folderTemp.canonicalPath();
1272 if(!g_lamexp_known_folder.knownFolders)
1274 g_lamexp_known_folder.knownFolders = new QMap<size_t, QString>();
1278 g_lamexp_known_folder.knownFolders->insert(folderCacheId, folder);
1279 return (*g_lamexp_known_folder.knownFolders)[folderCacheId];
1283 * Safely remove a file
1285 bool lamexp_remove_file(const QString &filename)
1287 if(!QFileInfo(filename).exists() || !QFileInfo(filename).isFile())
1293 if(!QFile::remove(filename))
1295 static const DWORD attrMask = FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM;
1296 const DWORD attributes = GetFileAttributesW(QWCHAR(filename));
1297 if(attributes & attrMask)
1299 SetFileAttributesW(QWCHAR(filename), FILE_ATTRIBUTE_NORMAL);
1301 if(!QFile::remove(filename))
1303 qWarning("Could not delete \"%s\"", filename.toLatin1().constData());
1319 * Check if visual themes are enabled (WinXP and later)
1321 bool lamexp_themes_enabled(void)
1323 typedef int (WINAPI *IsAppThemedFun)(void);
1325 QReadLocker readLock(&g_lamexp_themes_enabled.lock);
1326 if(g_lamexp_themes_enabled.bInitialized)
1328 return g_lamexp_themes_enabled.bThemesEnabled;
1332 QWriteLocker writeLock(&g_lamexp_themes_enabled.lock);
1334 if(!g_lamexp_themes_enabled.bInitialized)
1336 g_lamexp_themes_enabled.bThemesEnabled = false;
1337 const lamexp_os_version_t &osVersion = lamexp_get_os_version();
1338 if(osVersion >= lamexp_winver_winxp)
1340 IsAppThemedFun IsAppThemedPtr = NULL;
1341 QLibrary uxTheme(QString("%1/UxTheme.dll").arg(lamexp_known_folder(lamexp_folder_systemfolder)));
1344 IsAppThemedPtr = (IsAppThemedFun) uxTheme.resolve("IsAppThemed");
1348 g_lamexp_themes_enabled.bThemesEnabled = IsAppThemedPtr();
1349 if(!g_lamexp_themes_enabled.bThemesEnabled)
1351 qWarning("Theme support is disabled for this process!");
1355 g_lamexp_themes_enabled.bInitialized = true;
1358 return g_lamexp_themes_enabled.bThemesEnabled;
1362 * Get number of free bytes on disk
1364 unsigned __int64 lamexp_free_diskspace(const QString &path, bool *ok)
1366 ULARGE_INTEGER freeBytesAvailable, totalNumberOfBytes, totalNumberOfFreeBytes;
1367 if(GetDiskFreeSpaceExW(reinterpret_cast<const wchar_t*>(QDir::toNativeSeparators(path).utf16()), &freeBytesAvailable, &totalNumberOfBytes, &totalNumberOfFreeBytes))
1370 return freeBytesAvailable.QuadPart;
1380 * Check if computer does support hibernation
1382 bool lamexp_is_hibernation_supported(void)
1384 bool hibernationSupported = false;
1386 SYSTEM_POWER_CAPABILITIES pwrCaps;
1387 SecureZeroMemory(&pwrCaps, sizeof(SYSTEM_POWER_CAPABILITIES));
1389 if(GetPwrCapabilities(&pwrCaps))
1391 hibernationSupported = pwrCaps.SystemS4 && pwrCaps.HiberFilePresent;
1394 return hibernationSupported;
1398 * Shutdown the computer
1400 bool lamexp_shutdown_computer(const QString &message, const unsigned long timeout, const bool forceShutdown, const bool hibernate)
1402 HANDLE hToken = NULL;
1404 if(OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
1406 TOKEN_PRIVILEGES privileges;
1407 memset(&privileges, 0, sizeof(TOKEN_PRIVILEGES));
1408 privileges.PrivilegeCount = 1;
1409 privileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
1411 if(LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &privileges.Privileges[0].Luid))
1413 if(AdjustTokenPrivileges(hToken, FALSE, &privileges, NULL, NULL, NULL))
1417 if(SetSuspendState(TRUE, TRUE, TRUE))
1422 const DWORD reason = SHTDN_REASON_MAJOR_APPLICATION | SHTDN_REASON_FLAG_PLANNED;
1423 return InitiateSystemShutdownEx(NULL, const_cast<wchar_t*>(QWCHAR(message)), timeout, forceShutdown ? TRUE : FALSE, FALSE, reason);
1432 * Determines the current date, resistant against certain manipulations
1434 QDate lamexp_current_date_safe(void)
1436 const DWORD MAX_PROC = 1024;
1437 DWORD *processes = new DWORD[MAX_PROC];
1438 DWORD bytesReturned = 0;
1440 if(!EnumProcesses(processes, sizeof(DWORD) * MAX_PROC, &bytesReturned))
1442 LAMEXP_DELETE_ARRAY(processes);
1443 return QDate::currentDate();
1446 const DWORD procCount = bytesReturned / sizeof(DWORD);
1447 ULARGE_INTEGER lastStartTime;
1448 memset(&lastStartTime, 0, sizeof(ULARGE_INTEGER));
1450 for(DWORD i = 0; i < procCount; i++)
1452 HANDLE hProc = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, processes[i]);
1455 FILETIME processTime[4];
1456 if(GetProcessTimes(hProc, &processTime[0], &processTime[1], &processTime[2], &processTime[3]))
1458 ULARGE_INTEGER timeCreation;
1459 timeCreation.LowPart = processTime[0].dwLowDateTime;
1460 timeCreation.HighPart = processTime[0].dwHighDateTime;
1461 if(timeCreation.QuadPart > lastStartTime.QuadPart)
1463 lastStartTime.QuadPart = timeCreation.QuadPart;
1470 LAMEXP_DELETE_ARRAY(processes);
1472 FILETIME lastStartTime_fileTime;
1473 lastStartTime_fileTime.dwHighDateTime = lastStartTime.HighPart;
1474 lastStartTime_fileTime.dwLowDateTime = lastStartTime.LowPart;
1476 FILETIME lastStartTime_localTime;
1477 if(!FileTimeToLocalFileTime(&lastStartTime_fileTime, &lastStartTime_localTime))
1479 memcpy(&lastStartTime_localTime, &lastStartTime_fileTime, sizeof(FILETIME));
1482 SYSTEMTIME lastStartTime_system;
1483 if(!FileTimeToSystemTime(&lastStartTime_localTime, &lastStartTime_system))
1485 memset(&lastStartTime_system, 0, sizeof(SYSTEMTIME));
1486 lastStartTime_system.wYear = 1970; lastStartTime_system.wMonth = lastStartTime_system.wDay = 1;
1489 const QDate currentDate = QDate::currentDate();
1490 const QDate processDate = QDate(lastStartTime_system.wYear, lastStartTime_system.wMonth, lastStartTime_system.wDay);
1491 return (currentDate >= processDate) ? currentDate : processDate;
1495 * Suspend calling thread for N milliseconds
1497 inline void lamexp_sleep(const unsigned int delay)
1502 bool lamexp_beep(int beepType)
1506 case lamexp_beep_info: return MessageBeep(MB_ICONASTERISK) == TRUE; break;
1507 case lamexp_beep_warning: return MessageBeep(MB_ICONEXCLAMATION) == TRUE; break;
1508 case lamexp_beep_error: return MessageBeep(MB_ICONHAND) == TRUE; break;
1509 default: return false;
1514 * Play a sound (from resources)
1516 bool lamexp_play_sound(const unsigned short uiSoundIdx, const bool bAsync, const wchar_t *alias)
1520 return PlaySound(alias, GetModuleHandle(NULL), (SND_ALIAS | (bAsync ? SND_ASYNC : SND_SYNC))) == TRUE;
1524 return PlaySound(MAKEINTRESOURCE(uiSoundIdx), GetModuleHandle(NULL), (SND_RESOURCE | (bAsync ? SND_ASYNC : SND_SYNC))) == TRUE;
1529 * Play a sound (from resources)
1531 bool lamexp_play_sound_file(const QString &library, const unsigned short uiSoundIdx, const bool bAsync)
1533 bool result = false;
1534 HMODULE module = NULL;
1536 QFileInfo libraryFile(library);
1537 if(!libraryFile.isAbsolute())
1539 unsigned int buffSize = GetSystemDirectoryW(NULL, NULL) + 1;
1540 wchar_t *buffer = (wchar_t*) _malloca(buffSize * sizeof(wchar_t));
1541 unsigned int result = GetSystemDirectory(buffer, buffSize);
1542 if(result > 0 && result < buffSize)
1544 libraryFile.setFile(QString("%1/%2").arg(QDir::fromNativeSeparators(QString::fromUtf16(reinterpret_cast<const unsigned short*>(buffer))), library));
1549 module = LoadLibraryW(QWCHAR(QDir::toNativeSeparators(libraryFile.absoluteFilePath())));
1552 result = (PlaySound(MAKEINTRESOURCE(uiSoundIdx), module, (SND_RESOURCE | (bAsync ? SND_ASYNC : SND_SYNC))) == TRUE);
1553 FreeLibrary(module);
1560 * Open file using the shell
1562 bool lamexp_exec_shell(const QWidget *win, const QString &url, const bool explore)
1564 return lamexp_exec_shell(win, url, QString(), QString(), explore);
1568 * Open file using the shell (with parameters)
1570 bool lamexp_exec_shell(const QWidget *win, const QString &url, const QString ¶meters, const QString &directory, const bool explore)
1572 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;
1576 * Query value of the performance counter
1578 __int64 lamexp_perfcounter_value(void)
1580 LARGE_INTEGER counter;
1581 if(QueryPerformanceCounter(&counter) == TRUE)
1583 return counter.QuadPart;
1589 * Query frequency of the performance counter
1591 __int64 lamexp_perfcounter_frequ(void)
1593 LARGE_INTEGER frequency;
1594 if(QueryPerformanceFrequency(&frequency) == TRUE)
1596 return frequency.QuadPart;
1602 * Insert entry to the window's system menu
1604 bool lamexp_append_sysmenu(const QWidget *win, const unsigned int identifier, const QString &text)
1608 if(HMENU hMenu = GetSystemMenu(win->winId(), FALSE))
1610 ok = (AppendMenuW(hMenu, MF_SEPARATOR, 0, 0) == TRUE);
1611 ok = (AppendMenuW(hMenu, MF_STRING, identifier, QWCHAR(text)) == TRUE);
1618 * Insert entry to the window's system menu
1620 bool lamexp_check_sysmenu_msg(void *message, const unsigned int identifier)
1622 return (((MSG*)message)->message == WM_SYSCOMMAND) && ((((MSG*)message)->wParam & 0xFFF0) == identifier);
1626 * Update system menu entry
1628 bool lamexp_update_sysmenu(const QWidget *win, const unsigned int identifier, const QString &text)
1632 if(HMENU hMenu = ::GetSystemMenu(win->winId(), FALSE))
1634 ok = (ModifyMenu(hMenu, identifier, MF_STRING | MF_BYCOMMAND, identifier, QWCHAR(text)) == TRUE);
1640 * Display the window's close button
1642 bool lamexp_enable_close_button(const QWidget *win, const bool bEnable)
1646 if(HMENU hMenu = GetSystemMenu(win->winId(), FALSE))
1648 ok = (EnableMenuItem(hMenu, SC_CLOSE, MF_BYCOMMAND | (bEnable ? MF_ENABLED : MF_GRAYED)) == TRUE);
1655 * Check whether ESC key has been pressed since the previous call to this function
1657 bool lamexp_check_escape_state(void)
1659 return (GetAsyncKeyState(VK_ESCAPE) & 0x0001) != 0;
1663 * Set the process priority class for current process
1665 bool lamexp_change_process_priority(const int priority)
1667 return lamexp_change_process_priority(GetCurrentProcess(), priority);
1671 * Set the process priority class for specified process
1673 bool lamexp_change_process_priority(const QProcess *proc, const int priority)
1675 if(Q_PID qPid = proc->pid())
1677 return lamexp_change_process_priority(qPid->hProcess, priority);
1686 * Set the process priority class for specified process
1688 bool lamexp_change_process_priority(void *hProcess, const int priority)
1692 switch(qBound(-2, priority, 2))
1695 ok = (SetPriorityClass(hProcess, HIGH_PRIORITY_CLASS) == TRUE);
1698 if(!(ok = (SetPriorityClass(hProcess, ABOVE_NORMAL_PRIORITY_CLASS) == TRUE)))
1700 ok = (SetPriorityClass(hProcess, HIGH_PRIORITY_CLASS) == TRUE);
1704 ok = (SetPriorityClass(hProcess, NORMAL_PRIORITY_CLASS) == TRUE);
1707 if(!(ok = (SetPriorityClass(hProcess, BELOW_NORMAL_PRIORITY_CLASS) == TRUE)))
1709 ok = (SetPriorityClass(hProcess, IDLE_PRIORITY_CLASS) == TRUE);
1713 ok = (SetPriorityClass(hProcess, IDLE_PRIORITY_CLASS) == TRUE);
1721 * Returns the current file time
1723 unsigned __int64 lamexp_current_file_time(void)
1726 GetSystemTimeAsFileTime(&fileTime);
1728 ULARGE_INTEGER temp;
1729 temp.HighPart = fileTime.dwHighDateTime;
1730 temp.LowPart = fileTime.dwLowDateTime;
1732 return temp.QuadPart;
1736 * Bring the specifed window to the front
1738 bool lamexp_bring_to_front(const QWidget *win)
1740 const bool ret = (SetForegroundWindow(win->winId()) == TRUE);
1741 SwitchToThisWindow(win->winId(), TRUE);
1746 * Bring window of the specifed process to the front (callback)
1748 static BOOL CALLBACK lamexp_bring_process_to_front_helper(HWND hwnd, LPARAM lParam)
1750 DWORD processId = *reinterpret_cast<WORD*>(lParam);
1751 DWORD windowProcessId = NULL;
1752 GetWindowThreadProcessId(hwnd, &windowProcessId);
1753 if(windowProcessId == processId)
1755 SwitchToThisWindow(hwnd, TRUE);
1756 SetForegroundWindow(hwnd);
1764 * Bring window of the specifed process to the front
1766 bool lamexp_bring_process_to_front(const unsigned long pid)
1768 return EnumWindows(lamexp_bring_process_to_front_helper, reinterpret_cast<LPARAM>(&pid)) == TRUE;
1772 * Check the network connection status
1774 int lamexp_network_status(void)
1777 const BOOL ret = (IsNetworkAlive(&dwFlags) == TRUE);
1778 if(GetLastError() == 0)
1780 return (ret == TRUE) ? lamexp_network_yes : lamexp_network_non;
1782 return lamexp_network_err;
1786 * Retrun the process ID of the given QProcess
1788 unsigned long lamexp_process_id(const QProcess *proc)
1790 PROCESS_INFORMATION *procInf = proc->pid();
1791 return (procInf) ? procInf->dwProcessId : NULL;
1795 * Convert long path to short path
1797 QString lamexp_path_to_short(const QString &longPath)
1800 DWORD buffSize = GetShortPathNameW(reinterpret_cast<const wchar_t*>(longPath.utf16()), NULL, NULL);
1804 wchar_t *buffer = new wchar_t[buffSize];
1805 DWORD result = GetShortPathNameW(reinterpret_cast<const wchar_t*>(longPath.utf16()), buffer, buffSize);
1807 if(result > 0 && result < buffSize)
1809 shortPath = QString::fromUtf16(reinterpret_cast<const unsigned short*>(buffer));
1815 return (shortPath.isEmpty() ? longPath : shortPath);
1819 * Open media file in external player
1821 bool lamexp_open_media_file(const QString &mediaFilePath)
1823 const static wchar_t *registryPrefix[2] = { L"SOFTWARE\\", L"SOFTWARE\\Wow6432Node\\" };
1824 const static wchar_t *registryKeys[3] =
1826 L"Microsoft\\Windows\\CurrentVersion\\Uninstall\\{97D341C8-B0D1-4E4A-A49A-C30B52F168E9}",
1827 L"Microsoft\\Windows\\CurrentVersion\\Uninstall\\{DB9E4EAB-2717-499F-8D56-4CC8A644AB60}",
1830 const static wchar_t *appNames[4] = { L"smplayer_portable.exe", L"smplayer.exe", L"MPUI.exe", L"foobar2000.exe" };
1831 const static wchar_t *valueNames[2] = { L"InstallLocation", L"InstallDir" };
1833 for(size_t i = 0; i < 3; i++)
1835 for(size_t j = 0; j < 2; j++)
1837 QString mplayerPath;
1838 HKEY registryKeyHandle = NULL;
1840 const QString currentKey = WCHAR2QSTR(registryPrefix[j]).append(WCHAR2QSTR(registryKeys[i]));
1841 if(RegOpenKeyExW(HKEY_LOCAL_MACHINE, QWCHAR(currentKey), 0, KEY_READ, ®istryKeyHandle) == ERROR_SUCCESS)
1843 for(size_t k = 0; k < 2; k++)
1845 wchar_t Buffer[4096];
1846 DWORD BuffSize = sizeof(wchar_t*) * 4096;
1847 DWORD DataType = REG_NONE;
1848 if(RegQueryValueExW(registryKeyHandle, valueNames[k], 0, &DataType, reinterpret_cast<BYTE*>(Buffer), &BuffSize) == ERROR_SUCCESS)
1850 if((DataType == REG_SZ) || (DataType == REG_EXPAND_SZ) || (DataType == REG_LINK))
1852 mplayerPath = WCHAR2QSTR(Buffer);
1857 RegCloseKey(registryKeyHandle);
1860 if(!mplayerPath.isEmpty())
1862 QDir mplayerDir(mplayerPath);
1863 if(mplayerDir.exists())
1865 for(size_t k = 0; k < 4; k++)
1867 if(mplayerDir.exists(WCHAR2QSTR(appNames[k])))
1869 qDebug("Player found at:\n%s\n", QUTF8(mplayerDir.absoluteFilePath(WCHAR2QSTR(appNames[k]))));
1870 QProcess::startDetached(mplayerDir.absoluteFilePath(WCHAR2QSTR(appNames[k])), QStringList() << QDir::toNativeSeparators(mediaFilePath));
1881 static void lamexp_init_dwmapi(void)
1883 QReadLocker writeLock(&g_lamexp_dwmapi.lock);
1885 //Not initialized yet?
1886 if(g_lamexp_dwmapi.bInitialized)
1891 //Reset function pointers
1892 g_lamexp_dwmapi.dwmIsCompositionEnabled = NULL;
1893 g_lamexp_dwmapi.dwmExtendFrameIntoClientArea = NULL;
1894 g_lamexp_dwmapi.dwmEnableBlurBehindWindow = NULL;
1896 //Does OS support DWM?
1897 if(lamexp_get_os_version() >= lamexp_winver_vista)
1900 g_lamexp_dwmapi.dwmapi_dll = new QLibrary("dwmapi.dll");
1901 if(g_lamexp_dwmapi.dwmapi_dll->load())
1903 //Initialize function pointers
1904 g_lamexp_dwmapi.dwmIsCompositionEnabled = (HRESULT (__stdcall*)(BOOL*)) g_lamexp_dwmapi.dwmapi_dll->resolve("DwmIsCompositionEnabled");
1905 g_lamexp_dwmapi.dwmExtendFrameIntoClientArea = (HRESULT (__stdcall*)(HWND, const MARGINS*)) g_lamexp_dwmapi.dwmapi_dll->resolve("DwmExtendFrameIntoClientArea");
1906 g_lamexp_dwmapi.dwmEnableBlurBehindWindow = (HRESULT (__stdcall*)(HWND, const DWM_BLURBEHIND*)) g_lamexp_dwmapi.dwmapi_dll->resolve("DwmEnableBlurBehindWindow");
1910 LAMEXP_DELETE(g_lamexp_dwmapi.dwmapi_dll);
1911 qWarning("Failed to load DWMAPI.DLL on a DWM-enabled system!");
1915 g_lamexp_dwmapi.bInitialized = true;
1919 * Enable "sheet of glass" effect on the given Window
1921 bool lamexp_sheet_of_glass(QWidget *window)
1923 QReadLocker readLock(&g_lamexp_dwmapi.lock);
1925 //Initialize the DWM API
1926 while(!g_lamexp_dwmapi.bInitialized)
1929 lamexp_init_dwmapi();
1933 BOOL bCompositionEnabled = FALSE;
1935 //Required functions available?
1936 if((g_lamexp_dwmapi.dwmIsCompositionEnabled != NULL) && (g_lamexp_dwmapi.dwmExtendFrameIntoClientArea != NULL) && (g_lamexp_dwmapi.dwmEnableBlurBehindWindow != NULL))
1938 //Check if composition is currently enabled
1939 if(HRESULT hr = g_lamexp_dwmapi.dwmIsCompositionEnabled(&bCompositionEnabled))
1941 qWarning("DwmIsCompositionEnabled function has failed! (error %d)", hr);
1946 //All functions available *and* composition enabled?
1947 if(!bCompositionEnabled)
1952 //Enable the "sheet of glass" effect on this window
1953 MARGINS margins = {-1, -1, -1, -1};
1954 if(HRESULT hr = g_lamexp_dwmapi.dwmExtendFrameIntoClientArea(window->winId(), &margins))
1956 qWarning("DwmExtendFrameIntoClientArea function has failed! (error %d)", hr);
1960 //Create and populate the Blur Behind structure
1962 memset(&bb, 0, sizeof(DWM_BLURBEHIND));
1964 bb.dwFlags = DWM_BB_ENABLE;
1965 if(HRESULT hr = g_lamexp_dwmapi.dwmEnableBlurBehindWindow(window->winId(), &bb))
1967 qWarning("DwmEnableBlurBehindWindow function has failed! (error %d)", hr);
1972 window->setAutoFillBackground(false);
1973 window->setAttribute(Qt::WA_TranslucentBackground);
1974 window->setAttribute(Qt::WA_NoSystemBackground);
1980 * Update "sheet of glass" effect on the given Window
1982 bool lamexp_sheet_of_glass_update(QWidget *window)
1984 QReadLocker readLock(&g_lamexp_dwmapi.lock);
1986 //Initialize the DWM API
1987 while(!g_lamexp_dwmapi.bInitialized)
1990 lamexp_init_dwmapi();
1994 BOOL bCompositionEnabled = FALSE;
1996 //Required functions available?
1997 if((g_lamexp_dwmapi.dwmIsCompositionEnabled != NULL) && (g_lamexp_dwmapi.dwmEnableBlurBehindWindow != NULL))
1999 //Check if composition is currently enabled
2000 if(HRESULT hr = g_lamexp_dwmapi.dwmIsCompositionEnabled(&bCompositionEnabled))
2002 qWarning("DwmIsCompositionEnabled function has failed! (error %d)", hr);
2007 //All functions available *and* composition enabled?
2008 if(!bCompositionEnabled)
2013 //Create and populate the Blur Behind structure
2015 memset(&bb, 0, sizeof(DWM_BLURBEHIND));
2017 bb.dwFlags = DWM_BB_ENABLE;
2018 if(HRESULT hr = g_lamexp_dwmapi.dwmEnableBlurBehindWindow(window->winId(), &bb))
2020 qWarning("DwmEnableBlurBehindWindow function has failed! (error %d)", hr);
2028 * Update the window icon
2030 bool lamexp_set_window_icon(QWidget *window, const QIcon &icon, const bool bIsBigIcon)
2034 const int extend = (bIsBigIcon ? 32 : 16);
2035 if(HICON hIcon = lamexp_qicon2hicon(icon, extend, extend))
2037 SendMessage(window->winId(), WM_SETICON, (bIsBigIcon ? ICON_BIG : ICON_SMALL), LPARAM(hIcon));
2038 //DestroyIcon(hIcon); /*FIXME: Destroying the icon here will remove it from the window*/
2046 * Get system color info
2048 QColor lamexp_system_color(const int color_id)
2054 case lamexp_syscolor_text:
2055 nIndex = COLOR_WINDOWTEXT; /*Text in windows*/
2057 case lamexp_syscolor_background:
2058 nIndex = COLOR_WINDOW; /*Window background*/
2060 case lamexp_syscolor_caption:
2061 nIndex = COLOR_CAPTIONTEXT; /*Text in caption, size box, and scroll bar arrow box*/
2064 qWarning("Unknown system color id (%d) specified!", color_id);
2065 nIndex = COLOR_WINDOWTEXT;
2068 const DWORD rgb = GetSysColor(nIndex);
2069 QColor color(GetRValue(rgb), GetGValue(rgb), GetBValue(rgb));
2074 * Fatal application exit
2076 #pragma intrinsic(_InterlockedExchange)
2077 void lamexp_fatal_exit(const wchar_t* exitMessage, const wchar_t* errorBoxMessage)
2079 static volatile long bFatalFlag = 0L;
2081 if(_InterlockedExchange(&bFatalFlag, 1L) == 0L)
2083 if(GetCurrentThreadId() != g_main_thread_id)
2085 HANDLE mainThread = OpenThread(THREAD_TERMINATE, FALSE, g_main_thread_id);
2086 if(mainThread) TerminateThread(mainThread, ULONG_MAX);
2091 MessageBoxW(NULL, errorBoxMessage, L"LameXP - GURU MEDITATION", MB_ICONERROR | MB_TOPMOST | MB_TASKMODAL);
2096 FatalAppExit(0, exitMessage);
2097 TerminateProcess(GetCurrentProcess(), -1);
2101 TerminateThread(GetCurrentThread(), -1);
2106 * Finalization function (final clean-up)
2108 void lamexp_finalization(void)
2110 qDebug("lamexp_finalization()");
2113 lamexp_clean_all_tools();
2115 //Delete temporary files
2116 const QString &tempFolder = lamexp_temp_folder2();
2117 if(!tempFolder.isEmpty())
2119 bool success = false;
2120 for(int i = 0; i < 100; i++)
2122 if(lamexp_clean_folder(tempFolder))
2131 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);
2132 lamexp_exec_shell(NULL, tempFolder, QString(), QString(), true);
2136 //Clear folder cache
2137 LAMEXP_DELETE(g_lamexp_known_folder.knownFolders);
2140 lamexp_clean_all_translations();
2142 //Destroy Qt application object
2143 QApplication *application = dynamic_cast<QApplication*>(QApplication::instance());
2144 LAMEXP_DELETE(application);
2147 g_lamexp_dwmapi.dwmIsCompositionEnabled = NULL;
2148 g_lamexp_dwmapi.dwmExtendFrameIntoClientArea = NULL;
2149 g_lamexp_dwmapi.dwmEnableBlurBehindWindow = NULL;
2150 LAMEXP_DELETE(g_lamexp_dwmapi.dwmapi_dll);
2152 //Detach from shared memory
2155 //Free STDOUT and STDERR buffers
2156 if(g_lamexp_console_attached)
2158 if(std::filebuf *tmp = dynamic_cast<std::filebuf*>(std::cout.rdbuf()))
2160 std::cout.rdbuf(NULL);
2163 if(std::filebuf *tmp = dynamic_cast<std::filebuf*>(std::cerr.rdbuf()))
2165 std::cerr.rdbuf(NULL);
2171 if(g_lamexp_log_file)
2173 fclose(g_lamexp_log_file);
2174 g_lamexp_log_file = NULL;
2177 //Free CLI Arguments
2178 LAMEXP_DELETE(g_lamexp_argv.list);
2181 lamexp_temp_folder_clear();
2185 * Initialize debug thread
2187 static const HANDLE g_debug_thread1 = LAMEXP_DEBUG ? NULL : lamexp_debug_thread_init();
2190 * Get number private bytes [debug only]
2192 unsigned long lamexp_dbg_private_bytes(void)
2195 for(int i = 0; i < 8; i++) _heapmin();
2196 PROCESS_MEMORY_COUNTERS_EX memoryCounters;
2197 memoryCounters.cb = sizeof(PROCESS_MEMORY_COUNTERS_EX);
2198 GetProcessMemoryInfo(GetCurrentProcess(), (PPROCESS_MEMORY_COUNTERS) &memoryCounters, sizeof(PROCESS_MEMORY_COUNTERS_EX));
2199 return memoryCounters.PrivateUsage;
2201 THROW("Cannot call this function in a non-debug build!");
2202 #endif //LAMEXP_DEBUG
2206 * Output string to debugger [debug only]
2208 void lamexp_dbg_dbg_output_string(const char* format, ...)
2213 va_start (args, format);
2214 vsnprintf_s(buffer, 256, _TRUNCATE, format, args);
2215 OutputDebugStringA(buffer);
2218 THROW("Cannot call this function in a non-debug build!");
2219 #endif //LAMEXP_DEBUG
2222 ///////////////////////////////////////////////////////////////////////////////
2224 ///////////////////////////////////////////////////////////////////////////////
2226 extern "C" void _lamexp_global_init_win32(void)
2228 if((!LAMEXP_DEBUG) && lamexp_check_for_debugger())
2230 lamexp_fatal_exit(L"Not a debug build. Please unload debugger and try again!");
2233 //Zero *before* constructors are called
2234 LAMEXP_ZERO_MEMORY(g_lamexp_argv);
2235 LAMEXP_ZERO_MEMORY(g_lamexp_known_folder);
2236 LAMEXP_ZERO_MEMORY(g_lamexp_os_version);
2237 LAMEXP_ZERO_MEMORY(g_lamexp_wine);
2238 LAMEXP_ZERO_MEMORY(g_lamexp_themes_enabled);
2239 LAMEXP_ZERO_MEMORY(g_lamexp_dwmapi);