Detect WMA File Decoder component at runtime + suggest download if not installed.
[LameXP.git] / src / Global.cpp
blob0b3218a40f379e91c27580a951ecd5f03281b07a
1 ///////////////////////////////////////////////////////////////////////////////
2 // LameXP - Audio Encoder Front-End
3 // Copyright (C) 2004-2010 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.
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.
19 // http://www.gnu.org/licenses/gpl-2.0.txt
20 ///////////////////////////////////////////////////////////////////////////////
22 #include "Global.h"
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>
43 //LameXP includes
44 #include "Resource.h"
45 #include "LockedFile.h"
47 //Windows includes
48 #include <Windows.h>
50 //CRT includes
51 #include <stdio.h>
52 #include <io.h>
53 #include <fcntl.h>
54 #include <intrin.h>
56 //Debug only includes
57 #ifdef _DEBUG
58 #include <Psapi.h>
59 #endif //_DEBUG
61 //Static build only macros
62 #ifdef QT_NODLL
63 #pragma warning(disable:4101)
64 #define LAMEXP_INIT_QT_STATIC_PLUGIN(X) Q_IMPORT_PLUGIN(X)
65 #else
66 #define LAMEXP_INIT_QT_STATIC_PLUGIN(X)
67 #endif
69 ///////////////////////////////////////////////////////////////////////////////
70 // TYPES
71 ///////////////////////////////////////////////////////////////////////////////
73 typedef struct
75 unsigned int command;
76 unsigned int reserved_1;
77 unsigned int reserved_2;
78 char parameter[4096];
79 } lamexp_ipc_t;
81 ///////////////////////////////////////////////////////////////////////////////
82 // GLOBAL VARS
83 ///////////////////////////////////////////////////////////////////////////////
85 //Build version
86 static const unsigned int g_lamexp_version_major = VER_LAMEXP_MAJOR;
87 static const unsigned int g_lamexp_version_minor = VER_LAMEXP_MINOR;
88 static const unsigned int g_lamexp_version_build = VER_LAMEXP_BUILD;
89 static const char *g_lamexp_version_release = VER_LAMEXP_SUFFIX_STR;
91 //Build date
92 static QDate g_lamexp_version_date;
93 static const char *g_lamexp_months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
94 static const char *g_lamexp_version_raw_date = __DATE__;
96 //Compiler version
97 #if _MSC_VER == 1400
98 static const char *g_lamexp_version_compiler = "MSVC 8.0";
99 #else
100 #if _MSC_VER == 1500
101 static const char *g_lamexp_version_compiler = "MSVC 9.0";
102 #else
103 #if _MSC_VER == 1600
104 static const char *g_lamexp_version_compiler = "MSVC 10.0";
105 #else
106 static const char *g_lamexp_version_compiler = "UNKNOWN";
107 #endif
108 #endif
109 #endif
111 //Tool versions (expected)
112 static const unsigned int g_lamexp_toolver_neroaac = VER_LAMEXP_TOOL_NEROAAC;
114 //Special folders
115 static QString g_lamexp_temp_folder;
117 //Tools
118 static QMap<QString, LockedFile*> g_lamexp_tool_registry;
119 static QMap<QString, unsigned int> g_lamexp_tool_versions;
121 //Shared memory
122 static const char *g_lamexp_sharedmem_uuid = "{21A68A42-6923-43bb-9CF6-64BF151942EE}";
123 static QSharedMemory *g_lamexp_sharedmem_ptr = NULL;
124 static const char *g_lamexp_semaphore_read_uuid = "{7A605549-F58C-4d78-B4E5-06EFC34F405B}";
125 static QSystemSemaphore *g_lamexp_semaphore_read_ptr = NULL;
126 static const char *g_lamexp_semaphore_write_uuid = "{60AA8D04-F6B8-497d-81EB-0F600F4A65B5}";
127 static QSystemSemaphore *g_lamexp_semaphore_write_ptr = NULL;
129 //Image formats
130 static const char *g_lamexp_imageformats[] = {"png", "gif", "ico", "svg", NULL};
132 //Global locks
133 static QMutex g_lamexp_message_mutex;
135 ///////////////////////////////////////////////////////////////////////////////
136 // GLOBAL FUNCTIONS
137 ///////////////////////////////////////////////////////////////////////////////
140 * Version getters
142 unsigned int lamexp_version_major(void) { return g_lamexp_version_major; }
143 unsigned int lamexp_version_minor(void) { return g_lamexp_version_minor; }
144 unsigned int lamexp_version_build(void) { return g_lamexp_version_build; }
145 const char *lamexp_version_release(void) { return g_lamexp_version_release; }
146 const char *lamexp_version_compiler(void) {return g_lamexp_version_compiler; }
147 unsigned int lamexp_toolver_neroaac(void) { return g_lamexp_toolver_neroaac; }
149 bool lamexp_version_demo(void)
152 return LAMEXP_DEBUG || !(strstr(g_lamexp_version_release, "Final") || strstr(g_lamexp_version_release, "Hotfix"));
156 * Get build date date
158 const QDate &lamexp_version_date(void)
160 if(!g_lamexp_version_date.isValid())
162 char temp[32];
163 int date[3];
165 char *this_token = NULL;
166 char *next_token = NULL;
168 strcpy_s(temp, 32, g_lamexp_version_raw_date);
169 this_token = strtok_s(temp, " ", &next_token);
171 for(int i = 0; i < 3; i++)
173 date[i] = -1;
174 if(this_token)
176 for(int j = 0; j < 12; j++)
178 if(!_strcmpi(this_token, g_lamexp_months[j]))
180 date[i] = j+1;
181 break;
184 if(date[i] < 0)
186 date[i] = atoi(this_token);
188 this_token = strtok_s(NULL, " ", &next_token);
192 if(date[0] >= 0 && date[1] >= 0 && date[2] >= 0)
194 g_lamexp_version_date = QDate(date[2], date[0], date[1]);
198 return g_lamexp_version_date;
202 * Qt message handler
204 void lamexp_message_handler(QtMsgType type, const char *msg)
206 static HANDLE hConsole = NULL;
207 QMutexLocker lock(&g_lamexp_message_mutex);
209 if(!hConsole)
211 hConsole = CreateFile(L"CONOUT$", GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL);
212 if(hConsole == INVALID_HANDLE_VALUE) hConsole = NULL;
215 CONSOLE_SCREEN_BUFFER_INFO bufferInfo;
216 GetConsoleScreenBufferInfo(hConsole, &bufferInfo);
217 SetConsoleOutputCP(CP_UTF8);
219 switch(type)
221 case QtCriticalMsg:
222 case QtFatalMsg:
223 fflush(stdout);
224 fflush(stderr);
225 SetConsoleTextAttribute(hConsole, FOREGROUND_RED | FOREGROUND_INTENSITY);
226 fwprintf(stderr, L"\nCRITICAL ERROR !!!\n%S\n\n", msg);
227 MessageBoxW(NULL, (wchar_t*) QString::fromUtf8(msg).utf16(), L"LameXP - CRITICAL ERROR", MB_ICONERROR | MB_TOPMOST | MB_TASKMODAL);
228 break;
229 case QtWarningMsg:
230 SetConsoleTextAttribute(hConsole, FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY);
231 //MessageBoxW(NULL, (wchar_t*) QString::fromUtf8(msg).utf16(), L"LameXP - CRITICAL ERROR", MB_ICONWARNING | MB_TOPMOST | MB_TASKMODAL);
232 fwprintf(stderr, L"%S\n", msg);
233 fflush(stderr);
234 break;
235 default:
236 SetConsoleTextAttribute(hConsole, FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY);
237 fwprintf(stderr, L"%S\n", msg);
238 fflush(stderr);
239 break;
242 SetConsoleTextAttribute(hConsole, FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED);
244 if(type == QtCriticalMsg || type == QtFatalMsg)
246 lock.unlock();
247 FatalAppExit(0, L"The application has encountered a critical error and will exit now!");
248 TerminateProcess(GetCurrentProcess(), -1);
253 * Initialize the console
255 void lamexp_init_console(int argc, char* argv[])
257 for(int i = 0; i < argc; i++)
259 if(lamexp_version_demo() || !_stricmp(argv[i], "--console"))
261 if(AllocConsole())
263 //See: http://support.microsoft.com/default.aspx?scid=kb;en-us;105305
264 int hCrtStdOut = _open_osfhandle((long) GetStdHandle(STD_OUTPUT_HANDLE), _O_TEXT);
265 int hCrtStdErr = _open_osfhandle((long) GetStdHandle(STD_ERROR_HANDLE), _O_TEXT);
266 FILE *hfStdOut = _fdopen(hCrtStdOut, "w");
267 FILE *hfStderr = _fdopen(hCrtStdErr, "w");
268 *stdout = *hfStdOut;
269 *stderr = *hfStderr;
270 setvbuf(stdout, NULL, _IONBF, 0);
271 setvbuf(stderr, NULL, _IONBF, 0);
274 HMENU hMenu = GetSystemMenu(GetConsoleWindow(), 0);
275 EnableMenuItem(hMenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);
276 RemoveMenu(hMenu, SC_CLOSE, MF_BYCOMMAND);
278 SetConsoleCtrlHandler(NULL, TRUE);
279 SetConsoleTitle(L"LameXP - Audio Encoder Front-End | Debug Console");
280 SetConsoleOutputCP(CP_UTF8);
282 break;
288 * Detect CPU features
290 lamexp_cpu_t lamexp_detect_cpu_features(void)
292 typedef BOOL (WINAPI *IsWow64ProcessFun)(__in HANDLE hProcess, __out PBOOL Wow64Process);
293 typedef VOID (WINAPI *GetNativeSystemInfoFun)(__out LPSYSTEM_INFO lpSystemInfo);
295 static IsWow64ProcessFun IsWow64ProcessPtr = NULL;
296 static GetNativeSystemInfoFun GetNativeSystemInfoPtr = NULL;
298 lamexp_cpu_t features;
299 SYSTEM_INFO systemInfo;
300 int CPUInfo[4] = {-1};
301 char CPUIdentificationString[0x40];
302 char CPUBrandString[0x40];
304 memset(&features, 0, sizeof(lamexp_cpu_t));
305 memset(&systemInfo, 0, sizeof(SYSTEM_INFO));
306 memset(CPUIdentificationString, 0, sizeof(CPUIdentificationString));
307 memset(CPUBrandString, 0, sizeof(CPUBrandString));
309 __cpuid(CPUInfo, 0);
310 memcpy(CPUIdentificationString, &CPUInfo[1], sizeof(int));
311 memcpy(CPUIdentificationString + 4, &CPUInfo[3], sizeof(int));
312 memcpy(CPUIdentificationString + 8, &CPUInfo[2], sizeof(int));
313 features.intel = (_stricmp(CPUIdentificationString, "GenuineIntel") == 0);
314 strcpy_s(features.vendor, 0x40, CPUIdentificationString);
316 if(CPUInfo[0] >= 1)
318 __cpuid(CPUInfo, 1);
319 features.mmx = (CPUInfo[3] & 0x800000) || false;
320 features.sse = (CPUInfo[3] & 0x2000000) || false;
321 features.sse2 = (CPUInfo[3] & 0x4000000) || false;
322 features.ssse3 = (CPUInfo[2] & 0x200) || false;
323 features.sse3 = (CPUInfo[2] & 0x1) || false;
324 features.ssse3 = (CPUInfo[2] & 0x200) || false;
325 features.stepping = CPUInfo[0] & 0xf;
326 features.model = ((CPUInfo[0] >> 4) & 0xf) + (((CPUInfo[0] >> 16) & 0xf) << 4);
327 features.family = ((CPUInfo[0] >> 8) & 0xf) + ((CPUInfo[0] >> 20) & 0xff);
330 __cpuid(CPUInfo, 0x80000000);
331 int nExIds = CPUInfo[0];
333 for(int i = 0x80000000; i <= nExIds; ++i)
335 __cpuid(CPUInfo, i);
336 if(i == 0x80000002) memcpy(CPUBrandString, CPUInfo, sizeof(CPUInfo));
337 else if(i == 0x80000003) memcpy(CPUBrandString + 16, CPUInfo, sizeof(CPUInfo));
338 else if(i == 0x80000004) memcpy(CPUBrandString + 32, CPUInfo, sizeof(CPUInfo));
341 strcpy_s(features.brand, 0x40, CPUBrandString);
343 #if !defined(_M_X64 ) && !defined(_M_IA64)
344 if(!IsWow64ProcessPtr || !GetNativeSystemInfoPtr)
346 QLibrary Kernel32Lib("kernel32.dll");
347 IsWow64ProcessPtr = (IsWow64ProcessFun) Kernel32Lib.resolve("IsWow64Process");
348 GetNativeSystemInfoPtr = (GetNativeSystemInfoFun) Kernel32Lib.resolve("GetNativeSystemInfo");
350 if(IsWow64ProcessPtr)
352 BOOL x64 = FALSE;
353 if(IsWow64ProcessPtr(GetCurrentProcess(), &x64))
355 features.x64 = x64;
358 if(GetNativeSystemInfoPtr)
360 GetNativeSystemInfoPtr(&systemInfo);
362 else
364 GetSystemInfo(&systemInfo);
366 features.count = systemInfo.dwNumberOfProcessors;
367 #else
368 GetNativeSystemInfo(&systemInfo);
369 features.count = systemInfo.dwNumberOfProcessors;
370 features.x64 = true;
371 #endif
373 return features;
377 * Check for debugger
379 void WINAPI debugThreadProc(__in LPVOID lpParameter)
381 BOOL remoteDebuggerPresent = FALSE;
382 //CheckRemoteDebuggerPresent(GetCurrentProcess, &remoteDebuggerPresent);
384 while(!IsDebuggerPresent() && !remoteDebuggerPresent)
386 Sleep(333);
387 //CheckRemoteDebuggerPresent(GetCurrentProcess, &remoteDebuggerPresent);
390 TerminateProcess(GetCurrentProcess(), -1);
395 * Initialize Qt framework
397 bool lamexp_init_qt(int argc, char* argv[])
399 static bool qt_initialized = false;
401 //Don't initialized again, if done already
402 if(qt_initialized)
404 return true;
407 //Check Qt version
408 qDebug("Using Qt Framework v%s, compiled with Qt v%s", qVersion(), QT_VERSION_STR);
409 QT_REQUIRE_VERSION(argc, argv, QT_VERSION_STR);
411 //Check the Windows version
412 switch(QSysInfo::windowsVersion() & QSysInfo::WV_NT_based)
414 case QSysInfo::WV_2000:
415 qDebug("Running on Windows 2000 (not offically supported!).\n");
416 break;
417 case QSysInfo::WV_XP:
418 qDebug("Running on Windows XP.\n\n");
419 break;
420 case QSysInfo::WV_2003:
421 qDebug("Running on Windows Server 2003 or Windows XP Professional x64 Edition.\n");
422 break;
423 case QSysInfo::WV_VISTA:
424 qDebug("Running on Windows Vista or Windows Server 200.8\n");
425 break;
426 case QSysInfo::WV_WINDOWS7:
427 qDebug("Running on Windows 7 or Windows Server 2008 R2.\n");
428 break;
429 default:
430 qFatal("Unsupported OS, only Windows 2000 or later is supported!");
431 break;
434 //Create Qt application instance and setup version info
435 QApplication *application = new QApplication(argc, argv);
436 application->setApplicationName("LameXP - Audio Encoder Front-End");
437 application->setApplicationVersion(QString().sprintf("%d.%02d.%04d", lamexp_version_major(), lamexp_version_minor(), lamexp_version_build()));
438 application->setOrganizationName("LoRd_MuldeR");
439 application->setOrganizationDomain("mulder.dummwiedeutsch.de");
440 application->setWindowIcon(QIcon(":/MainIcon.png"));
442 //Load plugins from application directory
443 QCoreApplication::setLibraryPaths(QStringList() << QApplication::applicationDirPath());
444 qDebug("Library Path:\n%s\n", QApplication::libraryPaths().first().toUtf8().constData());
446 //Init static Qt plugins
447 LAMEXP_INIT_QT_STATIC_PLUGIN(qico);
448 LAMEXP_INIT_QT_STATIC_PLUGIN(qsvg);
450 //Check for supported image formats
451 QList<QByteArray> supportedFormats = QImageReader::supportedImageFormats();
452 for(int i = 0; g_lamexp_imageformats[i]; i++)
454 if(!supportedFormats.contains(g_lamexp_imageformats[i]))
456 qFatal("Qt initialization error: At least one image format plugin is missing! (%s)", g_lamexp_imageformats[i]);
457 return false;
461 //Done
462 qt_initialized = true;
463 return true;
467 * Initialize IPC
469 int lamexp_init_ipc(void)
471 if(g_lamexp_sharedmem_ptr && g_lamexp_semaphore_read_ptr && g_lamexp_semaphore_write_ptr)
473 return 0;
476 g_lamexp_semaphore_read_ptr = new QSystemSemaphore(QString(g_lamexp_semaphore_read_uuid), 0);
477 g_lamexp_semaphore_write_ptr = new QSystemSemaphore(QString(g_lamexp_semaphore_write_uuid), 0);
479 if(g_lamexp_semaphore_read_ptr->error() != QSystemSemaphore::NoError)
481 QString errorMessage = g_lamexp_semaphore_read_ptr->errorString();
482 LAMEXP_DELETE(g_lamexp_semaphore_read_ptr);
483 LAMEXP_DELETE(g_lamexp_semaphore_write_ptr);
484 qFatal("Failed to create system smaphore: %s", errorMessage.toUtf8().constData());
485 return -1;
487 if(g_lamexp_semaphore_write_ptr->error() != QSystemSemaphore::NoError)
489 QString errorMessage = g_lamexp_semaphore_write_ptr->errorString();
490 LAMEXP_DELETE(g_lamexp_semaphore_read_ptr);
491 LAMEXP_DELETE(g_lamexp_semaphore_write_ptr);
492 qFatal("Failed to create system smaphore: %s", errorMessage.toUtf8().constData());
493 return -1;
496 g_lamexp_sharedmem_ptr = new QSharedMemory(QString(g_lamexp_sharedmem_uuid), NULL);
498 if(!g_lamexp_sharedmem_ptr->create(sizeof(lamexp_ipc_t)))
500 if(g_lamexp_sharedmem_ptr->error() == QSharedMemory::AlreadyExists)
502 g_lamexp_sharedmem_ptr->attach();
503 if(g_lamexp_sharedmem_ptr->error() == QSharedMemory::NoError)
505 return 1;
507 else
509 QString errorMessage = g_lamexp_sharedmem_ptr->errorString();
510 qFatal("Failed to attach to shared memory: %s", errorMessage.toUtf8().constData());
511 return -1;
514 else
516 QString errorMessage = g_lamexp_sharedmem_ptr->errorString();
517 qFatal("Failed to create shared memory: %s", errorMessage.toUtf8().constData());
518 return -1;
522 memset(g_lamexp_sharedmem_ptr->data(), 0, sizeof(lamexp_ipc_t));
523 g_lamexp_semaphore_write_ptr->release();
525 return 0;
529 * IPC send message
531 void lamexp_ipc_send(unsigned int command, const char* message)
533 if(!g_lamexp_sharedmem_ptr || !g_lamexp_semaphore_read_ptr || !g_lamexp_semaphore_write_ptr)
535 throw "Shared memory for IPC not initialized yet.";
538 lamexp_ipc_t *lamexp_ipc = new lamexp_ipc_t;
539 memset(lamexp_ipc, 0, sizeof(lamexp_ipc_t));
540 lamexp_ipc->command = command;
541 if(message)
543 strcpy_s(lamexp_ipc->parameter, 4096, message);
546 if(g_lamexp_semaphore_write_ptr->acquire())
548 memcpy(g_lamexp_sharedmem_ptr->data(), lamexp_ipc, sizeof(lamexp_ipc_t));
549 g_lamexp_semaphore_read_ptr->release();
552 LAMEXP_DELETE(lamexp_ipc);
556 * IPC read message
558 void lamexp_ipc_read(unsigned int *command, char* message, size_t buffSize)
560 *command = 0;
561 message[0] = '\0';
563 if(!g_lamexp_sharedmem_ptr || !g_lamexp_semaphore_read_ptr || !g_lamexp_semaphore_write_ptr)
565 throw "Shared memory for IPC not initialized yet.";
568 lamexp_ipc_t *lamexp_ipc = new lamexp_ipc_t;
569 memset(lamexp_ipc, 0, sizeof(lamexp_ipc_t));
571 if(g_lamexp_semaphore_read_ptr->acquire())
573 memcpy(lamexp_ipc, g_lamexp_sharedmem_ptr->data(), sizeof(lamexp_ipc_t));
574 g_lamexp_semaphore_write_ptr->release();
576 if(!(lamexp_ipc->reserved_1 || lamexp_ipc->reserved_2))
578 *command = lamexp_ipc->command;
579 strcpy_s(message, buffSize, lamexp_ipc->parameter);
581 else
583 qWarning("Malformed IPC message, will be ignored");
587 LAMEXP_DELETE(lamexp_ipc);
591 * Get a random string
593 QString lamexp_rand_str(void)
595 QRegExp regExp("\\{(\\w+)-(\\w+)-(\\w+)-(\\w+)-(\\w+)\\}");
596 QString uuid = QUuid::createUuid().toString();
598 if(regExp.indexIn(uuid) >= 0)
600 return QString().append(regExp.cap(1)).append(regExp.cap(2)).append(regExp.cap(3)).append(regExp.cap(4)).append(regExp.cap(5));
603 throw "The RegExp didn't match on the UUID string. This shouldn't happen ;-)";
607 * Get LameXP temp folder
609 const QString &lamexp_temp_folder(void)
611 typedef HRESULT (WINAPI *SHGetKnownFolderPathFun)(__in const GUID &rfid, __in DWORD dwFlags, __in HANDLE hToken, __out PWSTR *ppszPath);
612 typedef HRESULT (WINAPI *SHGetFolderPathFun)(__in HWND hwndOwner, __in int nFolder, __in HANDLE hToken, __in DWORD dwFlags, __out LPWSTR pszPath);
614 static const char *TEMP_STR = "Temp";
615 static const int CSIDL_LOCAL_APPDATA = 0x001c;
616 static const GUID LocalAppDataID={0xF1B32785,0x6FBA,0x4FCF,{0x9D,0x55,0x7B,0x8E,0x7F,0x15,0x70,0x91}};
617 static const GUID LocalAppDataLowID={0xA520A1A4,0x1780,0x4FF6,{0xBD,0x18,0x16,0x73,0x43,0xC5,0xAF,0x16}};
619 if(g_lamexp_temp_folder.isEmpty())
621 QDir temp = QDir::temp();
623 QLibrary Kernel32Lib("shell32.dll");
624 SHGetKnownFolderPathFun SHGetKnownFolderPathPtr = (SHGetKnownFolderPathFun) Kernel32Lib.resolve("SHGetKnownFolderPath");
625 SHGetFolderPathFun SHGetFolderPathPtr = (SHGetFolderPathFun) Kernel32Lib.resolve("SHGetFolderPathW");
627 if(SHGetKnownFolderPathPtr)
629 WCHAR *localAppDataPath = NULL;
630 if(SHGetKnownFolderPathPtr(LocalAppDataID, 0x00008000, NULL, &localAppDataPath) == S_OK)
632 QDir localAppData = QDir(QDir::fromNativeSeparators(QString::fromUtf16(reinterpret_cast<const unsigned short*>(localAppDataPath))));
633 if(localAppData.exists())
635 if(!localAppData.entryList(QDir::AllDirs).contains(TEMP_STR))
637 localAppData.mkdir(TEMP_STR);
639 if(localAppData.cd(TEMP_STR))
641 temp.setPath(localAppData.canonicalPath());
644 CoTaskMemFree(localAppDataPath);
647 else if(SHGetFolderPathPtr)
649 WCHAR *localAppDataPath = new WCHAR[4096];
650 if(SHGetFolderPathPtr(NULL, CSIDL_LOCAL_APPDATA, NULL, NULL, localAppDataPath) == S_OK)
652 QDir localAppData = QDir(QDir::fromNativeSeparators(QString::fromUtf16(reinterpret_cast<const unsigned short*>(localAppDataPath))));
653 if(localAppData.exists())
655 if(!localAppData.entryList(QDir::AllDirs).contains(TEMP_STR))
657 localAppData.mkdir(TEMP_STR);
659 if(localAppData.cd(TEMP_STR))
661 temp.setPath(localAppData.canonicalPath());
665 delete [] localAppDataPath;
668 if(!temp.exists())
670 temp.mkpath(".");
671 if(!temp.exists())
673 qFatal("The system's temporary directory does not exist:\n%s", temp.absolutePath().toUtf8().constData());
674 return g_lamexp_temp_folder;
678 QString subDir = QString("%1.tmp").arg(lamexp_rand_str());
679 if(!temp.mkdir(subDir))
681 qFatal("Temporary directory could not be created:\n%s", QString("%1/%2").arg(temp.canonicalPath(), subDir).toUtf8().constData());
682 return g_lamexp_temp_folder;
684 if(!temp.cd(subDir))
686 qFatal("Temporary directory could not be entered:\n%s", QString("%1/%2").arg(temp.canonicalPath(), subDir).toUtf8().constData());
687 return g_lamexp_temp_folder;
690 QFile testFile(QString("%1/.%2").arg(temp.canonicalPath(), lamexp_rand_str()));
691 if(!testFile.open(QIODevice::ReadWrite) || testFile.write("LAMEXP_TEST\n") < 12)
693 qFatal("Write access to temporary directory has been denied:\n%s", temp.canonicalPath().toUtf8().constData());
694 return g_lamexp_temp_folder;
697 testFile.close();
698 QFile::remove(testFile.fileName());
700 g_lamexp_temp_folder = temp.canonicalPath();
703 return g_lamexp_temp_folder;
707 * Clean folder
709 bool lamexp_clean_folder(const QString folderPath)
711 QDir tempFolder(folderPath);
712 QFileInfoList entryList = tempFolder.entryInfoList();
714 for(int i = 0; i < entryList.count(); i++)
716 if(entryList.at(i).fileName().compare(".") == 0 || entryList.at(i).fileName().compare("..") == 0)
718 continue;
721 if(entryList.at(i).isDir())
723 lamexp_clean_folder(entryList.at(i).canonicalFilePath());
725 else
727 QFile::remove(entryList.at(i).canonicalFilePath());
731 tempFolder.rmdir(".");
732 return !tempFolder.exists();
736 * Finalization function (final clean-up)
738 void lamexp_finalization(void)
740 //Free all tools
741 if(!g_lamexp_tool_registry.isEmpty())
743 QStringList keys = g_lamexp_tool_registry.keys();
744 for(int i = 0; i < keys.count(); i++)
746 LAMEXP_DELETE(g_lamexp_tool_registry[keys.at(i)]);
748 g_lamexp_tool_registry.clear();
749 g_lamexp_tool_versions.clear();
752 //Delete temporary files
753 if(!g_lamexp_temp_folder.isEmpty())
755 for(int i = 0; i < 100; i++)
757 if(lamexp_clean_folder(g_lamexp_temp_folder)) break;
758 Sleep(125);
760 g_lamexp_temp_folder.clear();
763 //Destroy Qt application object
764 QApplication *application = dynamic_cast<QApplication*>(QApplication::instance());
765 LAMEXP_DELETE(application);
767 //Detach from shared memory
768 if(g_lamexp_sharedmem_ptr) g_lamexp_sharedmem_ptr->detach();
769 LAMEXP_DELETE(g_lamexp_sharedmem_ptr);
770 LAMEXP_DELETE(g_lamexp_semaphore_read_ptr);
771 LAMEXP_DELETE(g_lamexp_semaphore_write_ptr);
775 * Register tool
777 void lamexp_register_tool(const QString &toolName, LockedFile *file, unsigned int version)
779 if(g_lamexp_tool_registry.contains(toolName.toLower()))
781 throw "lamexp_register_tool: Tool is already registered!";
784 g_lamexp_tool_registry.insert(toolName.toLower(), file);
785 g_lamexp_tool_versions.insert(toolName.toLower(), version);
789 * Check for tool
791 bool lamexp_check_tool(const QString &toolName)
793 return g_lamexp_tool_registry.contains(toolName.toLower());
797 * Lookup tool
799 const QString lamexp_lookup_tool(const QString &toolName)
801 if(g_lamexp_tool_registry.contains(toolName.toLower()))
803 return g_lamexp_tool_registry.value(toolName.toLower())->filePath();
805 else
807 return QString();
812 * Lookup tool
814 unsigned int lamexp_tool_version(const QString &toolName)
816 if(g_lamexp_tool_versions.contains(toolName.toLower()))
818 return g_lamexp_tool_versions.value(toolName.toLower());
820 else
822 return UINT_MAX;
827 * Version number to human-readable string
829 const QString lamexp_version2string(const QString &pattern, unsigned int version)
831 QString result = pattern;
832 int digits = result.count("?", Qt::CaseInsensitive);
834 if(digits < 1)
836 return result;
839 int pos = 0;
840 QString versionStr = QString().sprintf(QString().sprintf("%%0%du", digits).toLatin1().constData(), version);
841 int index = result.indexOf("?", Qt::CaseInsensitive);
843 while(index >= 0 && pos < versionStr.length())
845 result[index] = versionStr[pos++];
846 index = result.indexOf("?", Qt::CaseInsensitive);
849 return result;
854 * Get number private bytes [debug only]
856 SIZE_T lamexp_dbg_private_bytes(void)
858 #ifdef _DEBUG
859 PROCESS_MEMORY_COUNTERS_EX memoryCounters;
860 memoryCounters.cb = sizeof(PROCESS_MEMORY_COUNTERS_EX);
861 GetProcessMemoryInfo(GetCurrentProcess(), (PPROCESS_MEMORY_COUNTERS) &memoryCounters, sizeof(PROCESS_MEMORY_COUNTERS_EX));
862 return memoryCounters.PrivateUsage;
863 #else
864 throw "Cannot call this function in a non-debug build!";
865 #endif //_DEBUG