OSDN Git Service

c797ee24e6ef2b9a3290f46cecd39032fc35ef00
[lamexp/LameXP.git] / src / Global.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // LameXP - Audio Encoder Front-End
3 // Copyright (C) 2004-2011 LoRd_MuldeR <MuldeR2@GMX.de>
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 2 of the License, or
8 // (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License along
16 // with this program; if not, write to the Free Software Foundation, Inc.,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 //
19 // http://www.gnu.org/licenses/gpl-2.0.txt
20 ///////////////////////////////////////////////////////////////////////////////
21
22 #include "Global.h"
23
24 //Qt includes
25 #include <QApplication>
26 #include <QMessageBox>
27 #include <QDir>
28 #include <QUuid>
29 #include <QMap>
30 #include <QDate>
31 #include <QIcon>
32 #include <QPlastiqueStyle>
33 #include <QImageReader>
34 #include <QSharedMemory>
35 #include <QSysInfo>
36 #include <QStringList>
37 #include <QSystemSemaphore>
38 #include <QMutex>
39 #include <QTextCodec>
40 #include <QLibrary>
41 #include <QRegExp>
42 #include <QResource>
43 #include <QTranslator>
44
45 //LameXP includes
46 #include "Resource.h"
47 #include "LockedFile.h"
48
49 //Windows includes
50 #include <Windows.h>
51
52 //CRT includes
53 #include <stdio.h>
54 #include <io.h>
55 #include <fcntl.h>
56 #include <intrin.h>
57
58 //Debug only includes
59 #ifdef _DEBUG
60 #ifndef _WIN32_WINNT
61 #define _WIN32_WINNT 0x0501
62 #endif
63 #if(_WIN32_WINNT < 0x0501)
64 #undef _WIN32_WINNT
65 #define _WIN32_WINNT 0x0501
66 #endif
67 #include <Psapi.h>
68 #endif //_DEBUG
69
70 //Static build only macros
71 #ifdef QT_NODLL
72 #pragma warning(disable:4101)
73 #define LAMEXP_INIT_QT_STATIC_PLUGIN(X) Q_IMPORT_PLUGIN(X)
74 #else
75 #define LAMEXP_INIT_QT_STATIC_PLUGIN(X)
76 #endif
77
78 ///////////////////////////////////////////////////////////////////////////////
79 // TYPES
80 ///////////////////////////////////////////////////////////////////////////////
81
82 typedef struct
83 {
84         unsigned int command;
85         unsigned int reserved_1;
86         unsigned int reserved_2;
87         char parameter[4096];
88 } lamexp_ipc_t;
89
90 ///////////////////////////////////////////////////////////////////////////////
91 // GLOBAL VARS
92 ///////////////////////////////////////////////////////////////////////////////
93
94 //Build version
95 static const struct
96 {
97         unsigned int ver_major;
98         unsigned int ver_minor;
99         unsigned int ver_build;
100         char *ver_release_name;
101 }
102 g_lamexp_version =
103 {
104         VER_LAMEXP_MAJOR,
105         VER_LAMEXP_MINOR,
106         VER_LAMEXP_BUILD,
107         VER_LAMEXP_RNAME
108 };
109
110 //Build date
111 static QDate g_lamexp_version_date;
112 static const char *g_lamexp_months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
113 static const char *g_lamexp_version_raw_date = __DATE__;
114
115 //Console attached flag
116 static bool g_lamexp_console_attached = false;
117
118 //Compiler version
119 #if _MSC_VER == 1400
120         static const char *g_lamexp_version_compiler = "MSVC 8.0";
121 #else
122         #if _MSC_VER == 1500
123                 static const char *g_lamexp_version_compiler = "MSVC 9.0";
124         #else
125                 #if _MSC_VER == 1600
126                         static const char *g_lamexp_version_compiler = "MSVC 10.0";
127                 #else
128                         static const char *g_lamexp_version_compiler = "UNKNOWN";
129                 #endif
130         #endif
131 #endif
132
133 //Official web-site URL
134 static const char *g_lamexp_website_url = "http://mulder.dummwiedeutsch.de/";
135
136 //Tool versions (expected)
137 static const unsigned int g_lamexp_toolver_neroaac = VER_LAMEXP_TOOL_NEROAAC;
138
139 //Special folders
140 static QString g_lamexp_temp_folder;
141
142 //Tools
143 static QMap<QString, LockedFile*> g_lamexp_tool_registry;
144 static QMap<QString, unsigned int> g_lamexp_tool_versions;
145
146 //Languages
147 static struct
148 {
149         QMap<QString, QString> files;
150         QMap<QString, QString> names;
151         QMap<QString, unsigned int> sysid;
152 }
153 g_lamexp_translation;
154
155 //Translator
156 static QTranslator *g_lamexp_currentTranslator = NULL;
157
158 //Shared memory
159 static const struct
160 {
161         char *sharedmem;
162         char *semaphore_read;
163         char *semaphore_write;
164 }
165 g_lamexp_ipc_uuid =
166 {
167         "{21A68A42-6923-43bb-9CF6-64BF151942EE}",
168         "{7A605549-F58C-4d78-B4E5-06EFC34F405B}",
169         "{60AA8D04-F6B8-497d-81EB-0F600F4A65B5}"
170 };
171 static struct
172 {
173         QSharedMemory *sharedmem;
174         QSystemSemaphore *semaphore_read;
175         QSystemSemaphore *semaphore_write;
176 }
177 g_lamexp_ipc_ptr =
178 {
179         NULL, NULL, NULL
180 };
181
182 //Image formats
183 static const char *g_lamexp_imageformats[] = {"png", "gif", "ico", "svg", NULL};
184
185 //Global locks
186 static QMutex g_lamexp_message_mutex;
187
188 ///////////////////////////////////////////////////////////////////////////////
189 // GLOBAL FUNCTIONS
190 ///////////////////////////////////////////////////////////////////////////////
191
192 /*
193  * Version getters
194  */
195 unsigned int lamexp_version_major(void) { return g_lamexp_version.ver_major; }
196 unsigned int lamexp_version_minor(void) { return g_lamexp_version.ver_minor; }
197 unsigned int lamexp_version_build(void) { return g_lamexp_version.ver_build; }
198 const char *lamexp_version_release(void) { return g_lamexp_version.ver_release_name; }
199 const char *lamexp_version_compiler(void) {return g_lamexp_version_compiler; }
200 unsigned int lamexp_toolver_neroaac(void) { return g_lamexp_toolver_neroaac; }
201 const char *lamexp_website_url(void) { return g_lamexp_website_url; }
202
203 bool lamexp_version_demo(void)
204 {
205         return LAMEXP_DEBUG || !(strstr(g_lamexp_version.ver_release_name, "Final") || strstr(g_lamexp_version.ver_release_name, "Hotfix"));
206 }
207
208 QDate lamexp_version_expires(void)
209 {
210         return lamexp_version_date().addDays(30);
211 }
212
213 /*
214  * Get build date date
215  */
216 const QDate &lamexp_version_date(void)
217 {
218         if(!g_lamexp_version_date.isValid())
219         {
220                 char temp[32];
221                 int date[3];
222
223                 char *this_token = NULL;
224                 char *next_token = NULL;
225
226                 strcpy_s(temp, 32, g_lamexp_version_raw_date);
227                 this_token = strtok_s(temp, " ", &next_token);
228
229                 for(int i = 0; i < 3; i++)
230                 {
231                         date[i] = -1;
232                         if(this_token)
233                         {
234                                 for(int j = 0; j < 12; j++)
235                                 {
236                                         if(!_strcmpi(this_token, g_lamexp_months[j]))
237                                         {
238                                                 date[i] = j+1;
239                                                 break;
240                                         }
241                                 }
242                                 if(date[i] < 0)
243                                 {
244                                         date[i] = atoi(this_token);
245                                 }
246                                 this_token = strtok_s(NULL, " ", &next_token);
247                         }
248                 }
249
250                 if(date[0] >= 0 && date[1] >= 0 && date[2] >= 0)
251                 {
252                         g_lamexp_version_date = QDate(date[2], date[0], date[1]);
253                 }
254         }
255
256         return g_lamexp_version_date;
257 }
258
259 /*
260  * Qt message handler
261  */
262 void lamexp_message_handler(QtMsgType type, const char *msg)
263 {
264         static HANDLE hConsole = NULL;
265         QMutexLocker lock(&g_lamexp_message_mutex);
266
267         if(!hConsole)
268         {
269                 if(g_lamexp_console_attached)
270                 {
271                         hConsole = CreateFile(L"CONOUT$", GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL);
272                         if(hConsole == INVALID_HANDLE_VALUE) hConsole = NULL;
273                 }
274         }
275
276         if(hConsole)
277         {
278                 CONSOLE_SCREEN_BUFFER_INFO bufferInfo;
279                 GetConsoleScreenBufferInfo(hConsole, &bufferInfo);
280                 SetConsoleOutputCP(CP_UTF8);
281
282                 switch(type)
283                 {
284                 case QtCriticalMsg:
285                 case QtFatalMsg:
286                         fflush(stdout);
287                         fflush(stderr);
288                         SetConsoleTextAttribute(hConsole, FOREGROUND_RED | FOREGROUND_INTENSITY);
289                         fwprintf(stderr, L"\nGURU MEDITATION !!!\n%S\n\n", msg);
290                         MessageBoxW(NULL, (wchar_t*) QString::fromUtf8(msg).utf16(), L"LameXP - GURU MEDITATION", MB_ICONERROR | MB_TOPMOST | MB_TASKMODAL);
291                         break;
292                 case QtWarningMsg:
293                         SetConsoleTextAttribute(hConsole, FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY);
294                         fwprintf(stderr, L"%S\n", msg);
295                         fflush(stderr);
296                         break;
297                 default:
298                         SetConsoleTextAttribute(hConsole, FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY);
299                         fwprintf(stderr, L"%S\n", msg);
300                         fflush(stderr);
301                         break;
302                 }
303         
304                 SetConsoleTextAttribute(hConsole, FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED);
305         }
306         else
307         {
308                 char temp_buffer[1024];
309
310                 switch(type)
311                 {
312                 case QtCriticalMsg:
313                 case QtFatalMsg:
314                         sprintf_s(temp_buffer, 1024, "[LameXP][C] %s", msg);
315                         break;
316                 case QtWarningMsg:
317                         sprintf_s(temp_buffer, 1024, "[LameXP][W] %s", msg);
318                         break;
319                 default:
320                         sprintf_s(temp_buffer, 1024, "[LameXP][I] %s", msg);
321                         break;
322                 }
323
324                 OutputDebugStringA(temp_buffer);
325         }
326
327         if(type == QtCriticalMsg || type == QtFatalMsg)
328         {
329                 lock.unlock();
330                 FatalAppExit(0, L"The application has encountered a critical error and will exit now!");
331                 TerminateProcess(GetCurrentProcess(), -1);
332         }
333  }
334
335 /*
336  * Initialize the console
337  */
338 void lamexp_init_console(int argc, char* argv[])
339 {
340         bool enableConsole = lamexp_version_demo();
341         
342         for(int i = 0; i < argc; i++)
343         {
344                 if(!_stricmp(argv[i], "--console"))
345                 {
346                         enableConsole = true;
347                 }
348                 else if(!_stricmp(argv[i], "--no-console"))
349                 {
350                         enableConsole = false;
351                 }
352         }
353
354         if(enableConsole)
355         {
356                 if(!g_lamexp_console_attached)
357                 {
358                         g_lamexp_console_attached = AllocConsole();
359                 }
360                 
361                 if(g_lamexp_console_attached)
362                 {
363                         //-------------------------------------------------------------------
364                         //See: http://support.microsoft.com/default.aspx?scid=kb;en-us;105305
365                         //-------------------------------------------------------------------
366                         int hCrtStdOut = _open_osfhandle((long) GetStdHandle(STD_OUTPUT_HANDLE), _O_TEXT);
367                         int hCrtStdErr = _open_osfhandle((long) GetStdHandle(STD_ERROR_HANDLE), _O_TEXT);
368                         FILE *hfStdOut = _fdopen(hCrtStdOut, "w");
369                         FILE *hfStderr = _fdopen(hCrtStdErr, "w");
370                         *stdout = *hfStdOut;
371                         *stderr = *hfStderr;
372                         setvbuf(stdout, NULL, _IONBF, 0);
373                         setvbuf(stderr, NULL, _IONBF, 0);
374                 }
375
376                 if(HWND hwndConsole = GetConsoleWindow())
377                 {
378                         HMENU hMenu = GetSystemMenu(hwndConsole, 0);
379                         EnableMenuItem(hMenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);
380                         RemoveMenu(hMenu, SC_CLOSE, MF_BYCOMMAND);
381
382                         SetWindowLong(hwndConsole, GWL_STYLE, GetWindowLong(hwndConsole, GWL_STYLE) & (~WS_MAXIMIZEBOX));
383                         SetWindowLong(hwndConsole, GWL_STYLE, GetWindowLong(hwndConsole, GWL_STYLE) & (~WS_MINIMIZEBOX));
384                         
385                         SetConsoleCtrlHandler(NULL, TRUE);
386                         SetConsoleTitle(L"LameXP - Audio Encoder Front-End | Debug Console");
387                         SetConsoleOutputCP(CP_UTF8);
388                 }
389         }
390 }
391
392 /*
393  * Detect CPU features
394  */
395 lamexp_cpu_t lamexp_detect_cpu_features(void)
396 {
397         typedef BOOL (WINAPI *IsWow64ProcessFun)(__in HANDLE hProcess, __out PBOOL Wow64Process);
398         typedef VOID (WINAPI *GetNativeSystemInfoFun)(__out LPSYSTEM_INFO lpSystemInfo);
399         
400         static IsWow64ProcessFun IsWow64ProcessPtr = NULL;
401         static GetNativeSystemInfoFun GetNativeSystemInfoPtr = NULL;
402
403         lamexp_cpu_t features;
404         SYSTEM_INFO systemInfo;
405         int CPUInfo[4] = {-1};
406         char CPUIdentificationString[0x40];
407         char CPUBrandString[0x40];
408
409         memset(&features, 0, sizeof(lamexp_cpu_t));
410         memset(&systemInfo, 0, sizeof(SYSTEM_INFO));
411         memset(CPUIdentificationString, 0, sizeof(CPUIdentificationString));
412         memset(CPUBrandString, 0, sizeof(CPUBrandString));
413         
414         __cpuid(CPUInfo, 0);
415         memcpy(CPUIdentificationString, &CPUInfo[1], sizeof(int));
416         memcpy(CPUIdentificationString + 4, &CPUInfo[3], sizeof(int));
417         memcpy(CPUIdentificationString + 8, &CPUInfo[2], sizeof(int));
418         features.intel = (_stricmp(CPUIdentificationString, "GenuineIntel") == 0);
419         strcpy_s(features.vendor, 0x40, CPUIdentificationString);
420
421         if(CPUInfo[0] >= 1)
422         {
423                 __cpuid(CPUInfo, 1);
424                 features.mmx = (CPUInfo[3] & 0x800000) || false;
425                 features.sse = (CPUInfo[3] & 0x2000000) || false;
426                 features.sse2 = (CPUInfo[3] & 0x4000000) || false;
427                 features.ssse3 = (CPUInfo[2] & 0x200) || false;
428                 features.sse3 = (CPUInfo[2] & 0x1) || false;
429                 features.ssse3 = (CPUInfo[2] & 0x200) || false;
430                 features.stepping = CPUInfo[0] & 0xf;
431                 features.model = ((CPUInfo[0] >> 4) & 0xf) + (((CPUInfo[0] >> 16) & 0xf) << 4);
432                 features.family = ((CPUInfo[0] >> 8) & 0xf) + ((CPUInfo[0] >> 20) & 0xff);
433         }
434
435         __cpuid(CPUInfo, 0x80000000);
436         int nExIds = max(min(CPUInfo[0], 0x80000004), 0x80000000);
437
438         for(int i = 0x80000002; i <= nExIds; ++i)
439         {
440                 __cpuid(CPUInfo, i);
441                 switch(i)
442                 {
443                 case 0x80000002:
444                         memcpy(CPUBrandString, CPUInfo, sizeof(CPUInfo));
445                         break;
446                 case 0x80000003:
447                         memcpy(CPUBrandString + 16, CPUInfo, sizeof(CPUInfo));
448                         break;
449                 case 0x80000004:
450                         memcpy(CPUBrandString + 32, CPUInfo, sizeof(CPUInfo));
451                         break;
452                 }
453         }
454
455         strcpy_s(features.brand, 0x40, CPUBrandString);
456
457         if(strlen(features.brand) < 1) strcpy_s(features.brand, 0x40, "Unknown");
458         if(strlen(features.vendor) < 1) strcpy_s(features.vendor, 0x40, "Unknown");
459
460 #if !defined(_M_X64 ) && !defined(_M_IA64)
461         if(!IsWow64ProcessPtr || !GetNativeSystemInfoPtr)
462         {
463                 QLibrary Kernel32Lib("kernel32.dll");
464                 IsWow64ProcessPtr = (IsWow64ProcessFun) Kernel32Lib.resolve("IsWow64Process");
465                 GetNativeSystemInfoPtr = (GetNativeSystemInfoFun) Kernel32Lib.resolve("GetNativeSystemInfo");
466         }
467         if(IsWow64ProcessPtr)
468         {
469                 BOOL x64 = FALSE;
470                 if(IsWow64ProcessPtr(GetCurrentProcess(), &x64))
471                 {
472                         features.x64 = x64;
473                 }
474         }
475         if(GetNativeSystemInfoPtr)
476         {
477                 GetNativeSystemInfoPtr(&systemInfo);
478         }
479         else
480         {
481                 GetSystemInfo(&systemInfo);
482         }
483         features.count = systemInfo.dwNumberOfProcessors;
484 #else
485         GetNativeSystemInfo(&systemInfo);
486         features.count = systemInfo.dwNumberOfProcessors;
487         features.x64 = true;
488 #endif
489
490         return features;
491 }
492
493 /*
494  * Check for debugger
495  */
496 #if !defined(_DEBUG) || defined(NDEBUG)
497 void WINAPI lamexp_debug_thread_proc(__in LPVOID lpParameter)
498 {
499         while(!IsDebuggerPresent())
500         {
501                 Sleep(333);
502         }
503         TerminateProcess(GetCurrentProcess(), -1);
504 }
505 HANDLE lamexp_debug_thread_init(void)
506 {
507         if(IsDebuggerPresent())
508         {
509                 FatalAppExit(0, L"Not a debug build. Please unload debugger and try again!");
510                 TerminateProcess(GetCurrentProcess(), -1);
511         }
512         return CreateThread(NULL, NULL, reinterpret_cast<LPTHREAD_START_ROUTINE>(&lamexp_debug_thread_proc), NULL, NULL, NULL);
513 }
514 static const HANDLE g_debug_thread = lamexp_debug_thread_init();
515 #endif
516
517 /*
518  * Check for compatibility mode
519  */
520 static bool lamexp_check_compatibility_mode(const char *exportName)
521 {
522         QLibrary kernel32("kernel32.dll");
523
524         if(exportName != NULL)
525         {
526                 if(kernel32.resolve(exportName) != NULL)
527                 {
528                         qFatal("Windows compatibility mode detected. Program will exit!");
529                         return false;
530                 }
531         }
532
533         return true;
534 }
535
536 /*
537  * Check for process elevation
538  */
539 static bool lamexp_check_elevation(void)
540 {
541         typedef enum { lamexp_token_elevationType_class = 18, lamexp_token_elevation_class = 20 } LAMEXP_TOKEN_INFORMATION_CLASS;
542         typedef enum { lamexp_elevationType_default = 1, lamexp_elevationType_full, lamexp_elevationType_limited } LAMEXP_TOKEN_ELEVATION_TYPE;
543
544         HANDLE hToken = NULL;
545         bool bIsProcessElevated = false;
546         
547         if(OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
548         {
549                 LAMEXP_TOKEN_ELEVATION_TYPE tokenElevationType;
550                 DWORD returnLength;
551                 if(GetTokenInformation(hToken, (TOKEN_INFORMATION_CLASS) lamexp_token_elevationType_class, &tokenElevationType, sizeof(LAMEXP_TOKEN_ELEVATION_TYPE), &returnLength))
552                 {
553                         if(returnLength == sizeof(LAMEXP_TOKEN_ELEVATION_TYPE))
554                         {
555                                 switch(tokenElevationType)
556                                 {
557                                 case lamexp_elevationType_default:
558                                         qDebug("Process token elevation type: Default -> UAC is disabled.\n");
559                                         break;
560                                 case lamexp_elevationType_full:
561                                         qWarning("Process token elevation type: Full -> potential security risk!\n");
562                                         bIsProcessElevated = true;
563                                         break;
564                                 case lamexp_elevationType_limited:
565                                         qDebug("Process token elevation type: Limited -> not elevated.\n");
566                                         break;
567                                 }
568                         }
569                 }
570                 CloseHandle(hToken);
571         }
572         else
573         {
574                 qWarning("Failed to open process token!");
575         }
576
577         return !bIsProcessElevated;
578 }
579
580 /*
581  * Initialize Qt framework
582  */
583 bool lamexp_init_qt(int argc, char* argv[])
584 {
585         static bool qt_initialized = false;
586
587         //Don't initialized again, if done already
588         if(qt_initialized)
589         {
590                 return true;
591         }
592         
593         //Check Qt version
594         qDebug("Using Qt Framework v%s, compiled with Qt v%s", qVersion(), QT_VERSION_STR);
595         QT_REQUIRE_VERSION(argc, argv, QT_VERSION_STR);
596         
597         //Check the Windows version
598         switch(QSysInfo::windowsVersion() & QSysInfo::WV_NT_based)
599         {
600         case QSysInfo::WV_2000:
601                 qDebug("Running on Windows 2000 (not offically supported!).\n");
602                 lamexp_check_compatibility_mode("GetNativeSystemInfo");
603                 break;
604         case QSysInfo::WV_XP:
605                 qDebug("Running on Windows XP.\n");
606                 lamexp_check_compatibility_mode("GetLargePageMinimum");
607                 break;
608         case QSysInfo::WV_2003:
609                 qDebug("Running on Windows Server 2003 or Windows XP x64-Edition.\n");
610                 lamexp_check_compatibility_mode("GetLocaleInfoEx");
611                 break;
612         case QSysInfo::WV_VISTA:
613                 qDebug("Running on Windows Vista or Windows Server 2008.\n");
614                 lamexp_check_compatibility_mode("CreateRemoteThreadEx");
615                 break;
616         case QSysInfo::WV_WINDOWS7:
617                 qDebug("Running on Windows 7 or Windows Server 2008 R2.\n");
618                 lamexp_check_compatibility_mode(NULL);
619                 break;
620         default:
621                 qFatal("Unsupported OS, only Windows 2000 or later is supported!");
622                 break;
623         }
624
625         //Create Qt application instance and setup version info
626         QApplication *application = new QApplication(argc, argv);
627         application->setApplicationName("LameXP - Audio Encoder Front-End");
628         application->setApplicationVersion(QString().sprintf("%d.%02d.%04d", lamexp_version_major(), lamexp_version_minor(), lamexp_version_build())); 
629         application->setOrganizationName("LoRd_MuldeR");
630         application->setOrganizationDomain("mulder.dummwiedeutsch.de");
631         application->setWindowIcon(QIcon(":/MainIcon.png"));
632         
633         //Load plugins from application directory
634         QCoreApplication::setLibraryPaths(QStringList() << QApplication::applicationDirPath());
635         qDebug("Library Path:\n%s\n", QApplication::libraryPaths().first().toUtf8().constData());
636
637         //Init static Qt plugins
638         LAMEXP_INIT_QT_STATIC_PLUGIN(qico);
639         LAMEXP_INIT_QT_STATIC_PLUGIN(qsvg);
640
641         //Check for supported image formats
642         QList<QByteArray> supportedFormats = QImageReader::supportedImageFormats();
643         for(int i = 0; g_lamexp_imageformats[i]; i++)
644         {
645                 if(!supportedFormats.contains(g_lamexp_imageformats[i]))
646                 {
647                         qFatal("Qt initialization error: At least one image format plugin is missing! (%s)", g_lamexp_imageformats[i]);
648                         return false;
649                 }
650         }
651
652         //Add default translations
653         g_lamexp_translation.files.insert(LAMEXP_DEFAULT_LANGID, "");
654         g_lamexp_translation.names.insert(LAMEXP_DEFAULT_LANGID, "English");
655
656         //Init language files
657         //lamexp_init_translations();
658
659         //Check for process elevation
660         if(!lamexp_check_elevation())
661         {
662                 if(QMessageBox::warning(NULL, "LameXP", "<nobr>LameXP was started with elevated rights. This is a potential security risk!</nobr>", "Quit Program (Recommended)", "Ignore") == 0)
663                 {
664                         return false;
665                 }
666         }
667
668         //Done
669         qt_initialized = true;
670         return true;
671 }
672
673 /*
674  * Initialize IPC
675  */
676 int lamexp_init_ipc(void)
677 {
678         if(g_lamexp_ipc_ptr.sharedmem && g_lamexp_ipc_ptr.semaphore_read && g_lamexp_ipc_ptr.semaphore_write)
679         {
680                 return 0;
681         }
682
683         g_lamexp_ipc_ptr.semaphore_read = new QSystemSemaphore(QString(g_lamexp_ipc_uuid.semaphore_read), 0);
684         g_lamexp_ipc_ptr.semaphore_write = new QSystemSemaphore(QString(g_lamexp_ipc_uuid.semaphore_write), 0);
685
686         if(g_lamexp_ipc_ptr.semaphore_read->error() != QSystemSemaphore::NoError)
687         {
688                 QString errorMessage = g_lamexp_ipc_ptr.semaphore_read->errorString();
689                 LAMEXP_DELETE(g_lamexp_ipc_ptr.semaphore_read);
690                 LAMEXP_DELETE(g_lamexp_ipc_ptr.semaphore_write);
691                 qFatal("Failed to create system smaphore: %s", errorMessage.toUtf8().constData());
692                 return -1;
693         }
694         if(g_lamexp_ipc_ptr.semaphore_write->error() != QSystemSemaphore::NoError)
695         {
696                 QString errorMessage = g_lamexp_ipc_ptr.semaphore_write->errorString();
697                 LAMEXP_DELETE(g_lamexp_ipc_ptr.semaphore_read);
698                 LAMEXP_DELETE(g_lamexp_ipc_ptr.semaphore_write);
699                 qFatal("Failed to create system smaphore: %s", errorMessage.toUtf8().constData());
700                 return -1;
701         }
702
703         g_lamexp_ipc_ptr.sharedmem = new QSharedMemory(QString(g_lamexp_ipc_uuid.sharedmem), NULL);
704         
705         if(!g_lamexp_ipc_ptr.sharedmem->create(sizeof(lamexp_ipc_t)))
706         {
707                 if(g_lamexp_ipc_ptr.sharedmem->error() == QSharedMemory::AlreadyExists)
708                 {
709                         g_lamexp_ipc_ptr.sharedmem->attach();
710                         if(g_lamexp_ipc_ptr.sharedmem->error() == QSharedMemory::NoError)
711                         {
712                                 return 1;
713                         }
714                         else
715                         {
716                                 QString errorMessage = g_lamexp_ipc_ptr.sharedmem->errorString();
717                                 qFatal("Failed to attach to shared memory: %s", errorMessage.toUtf8().constData());
718                                 return -1;
719                         }
720                 }
721                 else
722                 {
723                         QString errorMessage = g_lamexp_ipc_ptr.sharedmem->errorString();
724                         qFatal("Failed to create shared memory: %s", errorMessage.toUtf8().constData());
725                         return -1;
726                 }
727         }
728
729         memset(g_lamexp_ipc_ptr.sharedmem->data(), 0, sizeof(lamexp_ipc_t));
730         g_lamexp_ipc_ptr.semaphore_write->release();
731
732         return 0;
733 }
734
735 /*
736  * IPC send message
737  */
738 void lamexp_ipc_send(unsigned int command, const char* message)
739 {
740         if(!g_lamexp_ipc_ptr.sharedmem || !g_lamexp_ipc_ptr.semaphore_read || !g_lamexp_ipc_ptr.semaphore_write)
741         {
742                 throw "Shared memory for IPC not initialized yet.";
743         }
744
745         lamexp_ipc_t *lamexp_ipc = new lamexp_ipc_t;
746         memset(lamexp_ipc, 0, sizeof(lamexp_ipc_t));
747         lamexp_ipc->command = command;
748         if(message)
749         {
750                 strcpy_s(lamexp_ipc->parameter, 4096, message);
751         }
752
753         if(g_lamexp_ipc_ptr.semaphore_write->acquire())
754         {
755                 memcpy(g_lamexp_ipc_ptr.sharedmem->data(), lamexp_ipc, sizeof(lamexp_ipc_t));
756                 g_lamexp_ipc_ptr.semaphore_read->release();
757         }
758
759         LAMEXP_DELETE(lamexp_ipc);
760 }
761
762 /*
763  * IPC read message
764  */
765 void lamexp_ipc_read(unsigned int *command, char* message, size_t buffSize)
766 {
767         *command = 0;
768         message[0] = '\0';
769         
770         if(!g_lamexp_ipc_ptr.sharedmem || !g_lamexp_ipc_ptr.semaphore_read || !g_lamexp_ipc_ptr.semaphore_write)
771         {
772                 throw "Shared memory for IPC not initialized yet.";
773         }
774
775         lamexp_ipc_t *lamexp_ipc = new lamexp_ipc_t;
776         memset(lamexp_ipc, 0, sizeof(lamexp_ipc_t));
777
778         if(g_lamexp_ipc_ptr.semaphore_read->acquire())
779         {
780                 memcpy(lamexp_ipc, g_lamexp_ipc_ptr.sharedmem->data(), sizeof(lamexp_ipc_t));
781                 g_lamexp_ipc_ptr.semaphore_write->release();
782
783                 if(!(lamexp_ipc->reserved_1 || lamexp_ipc->reserved_2))
784                 {
785                         *command = lamexp_ipc->command;
786                         strcpy_s(message, buffSize, lamexp_ipc->parameter);
787                 }
788                 else
789                 {
790                         qWarning("Malformed IPC message, will be ignored");
791                 }
792         }
793
794         LAMEXP_DELETE(lamexp_ipc);
795 }
796
797 /*
798  * Check for LameXP "portable" mode
799  */
800 bool lamexp_portable_mode(void)
801 {
802         QString baseName = QFileInfo(QApplication::applicationFilePath()).completeBaseName();
803         return baseName.contains("lamexp", Qt::CaseInsensitive) && baseName.contains("portable", Qt::CaseInsensitive);
804 }
805
806 /*
807  * Get a random string
808  */
809 QString lamexp_rand_str(void)
810 {
811         QRegExp regExp("\\{(\\w+)-(\\w+)-(\\w+)-(\\w+)-(\\w+)\\}");
812         QString uuid = QUuid::createUuid().toString();
813
814         if(regExp.indexIn(uuid) >= 0)
815         {
816                 return QString().append(regExp.cap(1)).append(regExp.cap(2)).append(regExp.cap(3)).append(regExp.cap(4)).append(regExp.cap(5));
817         }
818
819         throw "The RegExp didn't match on the UUID string. This shouldn't happen ;-)";
820 }
821
822 /*
823  * Get LameXP temp folder
824  */
825 const QString &lamexp_temp_folder2(void)
826 {
827         static const char *TEMP_STR = "Temp";
828
829         if(g_lamexp_temp_folder.isEmpty())
830         {
831                 QDir temp = QDir::temp();
832                 QDir localAppData = QDir(lamexp_known_folder(lamexp_folder_localappdata));
833
834                 if(!localAppData.path().isEmpty() && localAppData.exists())
835                 {
836                         if(!localAppData.entryList(QDir::AllDirs).contains(TEMP_STR, Qt::CaseInsensitive))
837                         {
838                                 localAppData.mkdir(TEMP_STR);
839                         }
840                         if(localAppData.cd(TEMP_STR))
841                         {
842                                 temp.setPath(localAppData.absolutePath());
843                         }
844                 }
845
846                 if(!temp.exists())
847                 {
848                         temp.mkpath(".");
849                         if(!temp.exists())
850                         {
851                                 qFatal("The system's temporary directory does not exist:\n%s", temp.absolutePath().toUtf8().constData());
852                                 return g_lamexp_temp_folder;
853                         }
854                 }
855
856                 QString subDir = QString("%1.tmp").arg(lamexp_rand_str());
857                 if(!temp.mkdir(subDir))
858                 {
859                         qFatal("Temporary directory could not be created:\n%s", QString("%1/%2").arg(temp.canonicalPath(), subDir).toUtf8().constData());
860                         return g_lamexp_temp_folder;
861                 }
862                 if(!temp.cd(subDir))
863                 {
864                         qFatal("Temporary directory could not be entered:\n%s", QString("%1/%2").arg(temp.canonicalPath(), subDir).toUtf8().constData());
865                         return g_lamexp_temp_folder;
866                 }
867                 
868                 QFile testFile(QString("%1/.%2").arg(temp.canonicalPath(), lamexp_rand_str()));
869                 if(!testFile.open(QIODevice::ReadWrite) || testFile.write("LAMEXP_TEST\n") < 12)
870                 {
871                         qFatal("Write access to temporary directory has been denied:\n%s", temp.canonicalPath().toUtf8().constData());
872                         return g_lamexp_temp_folder;
873                 }
874
875                 testFile.close();
876                 QFile::remove(testFile.fileName());
877                 
878                 g_lamexp_temp_folder = temp.canonicalPath();
879         }
880         
881         return g_lamexp_temp_folder;
882 }
883
884 /*
885  * Clean folder
886  */
887 bool lamexp_clean_folder(const QString folderPath)
888 {
889         QDir tempFolder(folderPath);
890         QFileInfoList entryList = tempFolder.entryInfoList(QDir::AllEntries | QDir::NoDotAndDotDot);
891
892         for(int i = 0; i < entryList.count(); i++)
893         {
894                 if(entryList.at(i).isDir())
895                 {
896                         lamexp_clean_folder(entryList.at(i).canonicalFilePath());
897                 }
898                 else
899                 {
900                         for(int j = 0; j < 3; j++)
901                         {
902                                 if(lamexp_remove_file(entryList.at(i).canonicalFilePath()))
903                                 {
904                                         break;
905                                 }
906                         }
907                 }
908         }
909         
910         tempFolder.rmdir(".");
911         return !tempFolder.exists();
912 }
913
914 /*
915  * Register tool
916  */
917 void lamexp_register_tool(const QString &toolName, LockedFile *file, unsigned int version)
918 {
919         if(g_lamexp_tool_registry.contains(toolName.toLower()))
920         {
921                 throw "lamexp_register_tool: Tool is already registered!";
922         }
923
924         g_lamexp_tool_registry.insert(toolName.toLower(), file);
925         g_lamexp_tool_versions.insert(toolName.toLower(), version);
926 }
927
928 /*
929  * Check for tool
930  */
931 bool lamexp_check_tool(const QString &toolName)
932 {
933         return g_lamexp_tool_registry.contains(toolName.toLower());
934 }
935
936 /*
937  * Lookup tool path
938  */
939 const QString lamexp_lookup_tool(const QString &toolName)
940 {
941         if(g_lamexp_tool_registry.contains(toolName.toLower()))
942         {
943                 return g_lamexp_tool_registry.value(toolName.toLower())->filePath();
944         }
945         else
946         {
947                 return QString();
948         }
949 }
950
951 /*
952  * Lookup tool version
953  */
954 unsigned int lamexp_tool_version(const QString &toolName)
955 {
956         if(g_lamexp_tool_versions.contains(toolName.toLower()))
957         {
958                 return g_lamexp_tool_versions.value(toolName.toLower());
959         }
960         else
961         {
962                 return UINT_MAX;
963         }
964 }
965
966 /*
967  * Version number to human-readable string
968  */
969 const QString lamexp_version2string(const QString &pattern, unsigned int version, const QString &defaultText)
970 {
971         if(version == UINT_MAX)
972         {
973                 return defaultText;
974         }
975         
976         QString result = pattern;
977         int digits = result.count("?", Qt::CaseInsensitive);
978         
979         if(digits < 1)
980         {
981                 return result;
982         }
983         
984         int pos = 0;
985         QString versionStr = QString().sprintf(QString().sprintf("%%0%du", digits).toLatin1().constData(), version);
986         int index = result.indexOf("?", Qt::CaseInsensitive);
987         
988         while(index >= 0 && pos < versionStr.length())
989         {
990                 result[index] = versionStr[pos++];
991                 index = result.indexOf("?", Qt::CaseInsensitive);
992         }
993
994         return result;
995 }
996
997 /*
998  * Register a new translation
999  */
1000 bool lamexp_translation_register(const QString &langId, const QString &qmFile, const QString &langName, unsigned int &systemId)
1001 {
1002         if(qmFile.isEmpty() || langName.isEmpty() || systemId < 1)
1003         {
1004                 return false;
1005         }
1006
1007         g_lamexp_translation.files.insert(langId, qmFile);
1008         g_lamexp_translation.names.insert(langId, langName);
1009         g_lamexp_translation.sysid.insert(langId, systemId);
1010
1011         return true;
1012 }
1013
1014 /*
1015  * Get list of all translations
1016  */
1017 QStringList lamexp_query_translations(void)
1018 {
1019         return g_lamexp_translation.files.keys();
1020 }
1021
1022 /*
1023  * Get translation name
1024  */
1025 QString lamexp_translation_name(const QString &langId)
1026 {
1027         return g_lamexp_translation.names.value(langId.toLower(), QString());
1028 }
1029
1030 /*
1031  * Get translation system id
1032  */
1033 unsigned int lamexp_translation_sysid(const QString &langId)
1034 {
1035         return g_lamexp_translation.sysid.value(langId.toLower(), 0);
1036 }
1037
1038 /*
1039  * Install a new translator
1040  */
1041 bool lamexp_install_translator(const QString &langId)
1042 {
1043         bool success = false;
1044
1045         if(langId.isEmpty() || langId.toLower().compare(LAMEXP_DEFAULT_LANGID) == 0)
1046         {
1047                 success = lamexp_install_translator_from_file(QString());
1048         }
1049         else
1050         {
1051                 QString qmFile = g_lamexp_translation.files.value(langId.toLower(), QString());
1052                 if(!qmFile.isEmpty())
1053                 {
1054                         success = lamexp_install_translator_from_file(QString(":/localization/%1").arg(qmFile));
1055                 }
1056                 else
1057                 {
1058                         qWarning("Translation '%s' not available!", langId.toLatin1().constData());
1059                 }
1060         }
1061
1062         return success;
1063 }
1064
1065 /*
1066  * Install a new translator from file
1067  */
1068 bool lamexp_install_translator_from_file(const QString &qmFile)
1069 {
1070         bool success = false;
1071
1072         if(!g_lamexp_currentTranslator)
1073         {
1074                 g_lamexp_currentTranslator = new QTranslator();
1075         }
1076
1077         if(!qmFile.isEmpty())
1078         {
1079                 QString qmPath = QFileInfo(qmFile).canonicalFilePath();
1080                 QApplication::removeTranslator(g_lamexp_currentTranslator);
1081                 success = g_lamexp_currentTranslator->load(qmPath);
1082                 QApplication::installTranslator(g_lamexp_currentTranslator);
1083                 if(!success)
1084                 {
1085                         qWarning("Failed to load translation:\n\"%s\"", qmPath.toLatin1().constData());
1086                 }
1087         }
1088         else
1089         {
1090                 QApplication::removeTranslator(g_lamexp_currentTranslator);
1091                 success = true;
1092         }
1093
1094         return success;
1095 }
1096
1097 /*
1098  * Locate known folder on local system
1099  */
1100 QString lamexp_known_folder(lamexp_known_folder_t folder_id)
1101 {
1102         typedef HRESULT (WINAPI *SHGetKnownFolderPathFun)(__in const GUID &rfid, __in DWORD dwFlags, __in HANDLE hToken, __out PWSTR *ppszPath);
1103         typedef HRESULT (WINAPI *SHGetFolderPathFun)(__in HWND hwndOwner, __in int nFolder, __in HANDLE hToken, __in DWORD dwFlags, __out LPWSTR pszPath);
1104
1105         static const int CSIDL_LOCAL_APPDATA = 0x001c;
1106         static const int CSIDL_PROGRAM_FILES = 0x0026;
1107         static const int CSIDL_SYSTEM_FOLDER = 0x0025;
1108         static const GUID GUID_LOCAL_APPDATA = {0xF1B32785,0x6FBA,0x4FCF,{0x9D,0x55,0x7B,0x8E,0x7F,0x15,0x70,0x91}};
1109         static const GUID GUID_LOCAL_APPDATA_LOW = {0xA520A1A4,0x1780,0x4FF6,{0xBD,0x18,0x16,0x73,0x43,0xC5,0xAF,0x16}};
1110         static const GUID GUID_PROGRAM_FILES = {0x905e63b6,0xc1bf,0x494e,{0xb2,0x9c,0x65,0xb7,0x32,0xd3,0xd2,0x1a}};
1111         static const GUID GUID_SYSTEM_FOLDER = {0x1AC14E77,0x02E7,0x4E5D,{0xB7,0x44,0x2E,0xB1,0xAE,0x51,0x98,0xB7}};
1112
1113         static QLibrary *Kernel32Lib = NULL;
1114         static SHGetKnownFolderPathFun SHGetKnownFolderPathPtr = NULL;
1115         static SHGetFolderPathFun SHGetFolderPathPtr = NULL;
1116
1117         if((!SHGetKnownFolderPathPtr) && (!SHGetFolderPathPtr))
1118         {
1119                 if(!Kernel32Lib) Kernel32Lib = new QLibrary("shell32.dll");
1120                 SHGetKnownFolderPathPtr = (SHGetKnownFolderPathFun) Kernel32Lib->resolve("SHGetKnownFolderPath");
1121                 SHGetFolderPathPtr = (SHGetFolderPathFun) Kernel32Lib->resolve("SHGetFolderPathW");
1122         }
1123
1124         int folderCSIDL = -1;
1125         GUID folderGUID = {0x0000,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}};
1126
1127         switch(folder_id)
1128         {
1129         case lamexp_folder_localappdata:
1130                 folderCSIDL = CSIDL_LOCAL_APPDATA;
1131                 folderGUID = GUID_LOCAL_APPDATA;
1132                 break;
1133         case lamexp_folder_programfiles:
1134                 folderCSIDL = CSIDL_PROGRAM_FILES;
1135                 folderGUID = GUID_PROGRAM_FILES;
1136                 break;
1137         case lamexp_folder_systemfolder:
1138                 folderCSIDL = CSIDL_SYSTEM_FOLDER;
1139                 folderGUID = GUID_SYSTEM_FOLDER;
1140                 break;
1141         default:
1142                 return QString();
1143                 break;
1144         }
1145
1146         QString folder;
1147
1148         if(SHGetKnownFolderPathPtr)
1149         {
1150                 WCHAR *path = NULL;
1151                 if(SHGetKnownFolderPathPtr(folderGUID, 0x00008000, NULL, &path) == S_OK)
1152                 {
1153                         //MessageBoxW(0, path, L"SHGetKnownFolderPath", MB_TOPMOST);
1154                         QDir folderTemp = QDir(QDir::fromNativeSeparators(QString::fromUtf16(reinterpret_cast<const unsigned short*>(path))));
1155                         if(!folderTemp.exists())
1156                         {
1157                                 folderTemp.mkpath(".");
1158                         }
1159                         if(folderTemp.exists())
1160                         {
1161                                 folder = folderTemp.canonicalPath();
1162                         }
1163                         CoTaskMemFree(path);
1164                 }
1165         }
1166         else if(SHGetFolderPathPtr)
1167         {
1168                 WCHAR *path = new WCHAR[4096];
1169                 if(SHGetFolderPathPtr(NULL, folderCSIDL, NULL, NULL, path) == S_OK)
1170                 {
1171                         //MessageBoxW(0, path, L"SHGetFolderPathW", MB_TOPMOST);
1172                         QDir folderTemp = QDir(QDir::fromNativeSeparators(QString::fromUtf16(reinterpret_cast<const unsigned short*>(path))));
1173                         if(!folderTemp.exists())
1174                         {
1175                                 folderTemp.mkpath(".");
1176                         }
1177                         if(folderTemp.exists())
1178                         {
1179                                 folder = folderTemp.canonicalPath();
1180                         }
1181                 }
1182                 delete [] path;
1183         }
1184
1185         return folder;
1186 }
1187
1188 /*
1189  * Safely remove a file
1190  */
1191 bool lamexp_remove_file(const QString &filename)
1192 {
1193         if(!QFileInfo(filename).exists() || !QFileInfo(filename).isFile())
1194         {
1195                 return true;
1196         }
1197         else
1198         {
1199                 if(!QFile::remove(filename))
1200                 {
1201                         DWORD attributes = GetFileAttributesW(QWCHAR(filename));
1202                         SetFileAttributesW(QWCHAR(filename), (attributes & (~FILE_ATTRIBUTE_READONLY)));
1203                         if(!QFile::remove(filename))
1204                         {
1205                                 qWarning("Could not delete \"%s\"", filename.toLatin1().constData());
1206                                 return false;
1207                         }
1208                         else
1209                         {
1210                                 return true;
1211                         }
1212                 }
1213                 else
1214                 {
1215                         return true;
1216                 }
1217         }
1218 }
1219
1220 /*
1221  * Check if visual themes are enabled (WinXP and later)
1222  */
1223 bool lamexp_themes_enabled(void)
1224 {
1225         typedef int (WINAPI *IsAppThemedFun)(void);
1226         
1227         bool isAppThemed = false;
1228         QLibrary uxTheme(QString("%1/UxTheme.dll").arg(lamexp_known_folder(lamexp_folder_systemfolder)));
1229         IsAppThemedFun IsAppThemedPtr = (IsAppThemedFun) uxTheme.resolve("IsAppThemed");
1230
1231         if(IsAppThemedPtr)
1232         {
1233                 isAppThemed = IsAppThemedPtr();
1234                 if(!isAppThemed)
1235                 {
1236                         qWarning("Theme support is disabled for this process!");
1237                 }
1238         }
1239
1240         return isAppThemed;
1241 }
1242
1243 /*
1244  * Get number of free bytes on disk
1245  */
1246 __int64 lamexp_free_diskspace(const QString &path)
1247 {
1248         ULARGE_INTEGER freeBytesAvailable, totalNumberOfBytes, totalNumberOfFreeBytes;
1249         if(GetDiskFreeSpaceExW(reinterpret_cast<const wchar_t*>(QDir::toNativeSeparators(path).utf16()), &freeBytesAvailable, &totalNumberOfBytes, &totalNumberOfFreeBytes))
1250         {
1251                 return freeBytesAvailable.QuadPart;
1252         }
1253         else
1254         {
1255                 return 0;
1256         }
1257 }
1258
1259 /*
1260  * Finalization function (final clean-up)
1261  */
1262 void lamexp_finalization(void)
1263 {
1264         //Free all tools
1265         if(!g_lamexp_tool_registry.isEmpty())
1266         {
1267                 QStringList keys = g_lamexp_tool_registry.keys();
1268                 for(int i = 0; i < keys.count(); i++)
1269                 {
1270                         LAMEXP_DELETE(g_lamexp_tool_registry[keys.at(i)]);
1271                 }
1272                 g_lamexp_tool_registry.clear();
1273                 g_lamexp_tool_versions.clear();
1274         }
1275         
1276         //Delete temporary files
1277         if(!g_lamexp_temp_folder.isEmpty())
1278         {
1279                 for(int i = 0; i < 100; i++)
1280                 {
1281                         if(lamexp_clean_folder(g_lamexp_temp_folder))
1282                         {
1283                                 break;
1284                         }
1285                         Sleep(125);
1286                 }
1287                 g_lamexp_temp_folder.clear();
1288         }
1289
1290         //Clear languages
1291         if(g_lamexp_currentTranslator)
1292         {
1293                 QApplication::removeTranslator(g_lamexp_currentTranslator);
1294                 LAMEXP_DELETE(g_lamexp_currentTranslator);
1295         }
1296         g_lamexp_translation.files.clear();
1297         g_lamexp_translation.names.clear();
1298
1299         //Destroy Qt application object
1300         QApplication *application = dynamic_cast<QApplication*>(QApplication::instance());
1301         LAMEXP_DELETE(application);
1302
1303         //Detach from shared memory
1304         if(g_lamexp_ipc_ptr.sharedmem) g_lamexp_ipc_ptr.sharedmem->detach();
1305         LAMEXP_DELETE(g_lamexp_ipc_ptr.sharedmem);
1306         LAMEXP_DELETE(g_lamexp_ipc_ptr.semaphore_read);
1307         LAMEXP_DELETE(g_lamexp_ipc_ptr.semaphore_write);
1308 }
1309
1310 /*
1311  * Get number private bytes [debug only]
1312  */
1313 SIZE_T lamexp_dbg_private_bytes(void)
1314 {
1315 #ifdef _DEBUG
1316         PROCESS_MEMORY_COUNTERS_EX memoryCounters;
1317         memoryCounters.cb = sizeof(PROCESS_MEMORY_COUNTERS_EX);
1318         GetProcessMemoryInfo(GetCurrentProcess(), (PPROCESS_MEMORY_COUNTERS) &memoryCounters, sizeof(PROCESS_MEMORY_COUNTERS_EX));
1319         return memoryCounters.PrivateUsage;
1320 #else
1321         throw "Cannot call this function in a non-debug build!";
1322 #endif //_DEBUG
1323 }