From 524a39e472ba85bc720b6e621b7e0d8271e8db32 Mon Sep 17 00:00:00 2001 From: MuldeR Date: Sat, 7 Dec 2013 19:42:07 +0100 Subject: [PATCH] Ported various code updates from LameXP and upgraded build environment to VS2013. Also updated MediaInfo binary to v0.7.65. --- MediaInfoXP.vcxproj | 11 +- doc/Changelog.txt | 33 ++++ res/logo.png | Bin 17788 -> 7600 bytes src/Config.h | 4 +- src/Main.cpp | 19 +++ src/MainWindow.cpp | 104 ++++++------- src/MainWindow.h | 7 +- src/Utils.cpp | 357 +++++++++++++++++++++++++++++++++----------- src/Utils.h | 20 ++- z_build.bat | 4 +- 10 files changed, 401 insertions(+), 158 deletions(-) diff --git a/MediaInfoXP.vcxproj b/MediaInfoXP.vcxproj index 2430222..c9e5454 100644 --- a/MediaInfoXP.vcxproj +++ b/MediaInfoXP.vcxproj @@ -1,5 +1,5 @@  - + Debug @@ -19,13 +19,13 @@ Application true - v110 + v120_xp Unicode Application false - v110_xp + v120_xp true Unicode @@ -61,7 +61,7 @@ Console true - $(SolutionDir)..\LameXP_Qt\LameXP\etc\Prerequisites\qt4_static\lib;%(AdditionalLibraryDirectories) + $(SolutionDir)..\LameXP_Qt\LameXP\etc\Prerequisites\qt4_static.VS2013\lib;%(AdditionalLibraryDirectories) @@ -91,13 +91,14 @@ false true true - $(SolutionDir)..\LameXP_Qt\etc\Prerequisites\qt4_static\lib;$(SolutionDir)..\LameXP_Qt\etc\Prerequisites\qt4_static\plugins\imageformats;$(SolutionDir)..\LameXP_Qt\etc\Prerequisites\EncodePointer\lib\;%(AdditionalLibraryDirectories) + $(SolutionDir)..\LameXP_Qt\etc\Prerequisites\qt4_static.VS2013\lib;$(SolutionDir)..\LameXP_Qt\etc\Prerequisites\qt4_static.VS2013\plugins\imageformats;$(SolutionDir)..\LameXP_Qt\etc\Prerequisites\EncodePointer\lib\;%(AdditionalLibraryDirectories) QtCore.lib;QtGui.lib;QtSvg.lib;qtmain.lib;qsvg.lib;qico.lib;qtga.lib;Winmm.lib;imm32.lib;ws2_32.lib;Shlwapi.lib;Wininet.lib;PowrProf.lib;psapi.lib;EncodePointer.lib;%(AdditionalDependencies) false LinkVerboseLib true true "/MANIFESTDEPENDENCY:type=%27win32%27 name=%27Microsoft.Windows.Common-Controls%27 version=%276.0.0.0%27 publicKeyToken=%276595b64144ccf1df%27 language=%27*%27 processorArchitecture=%27*%27" %(AdditionalOptions) + UseLinkTimeCodeGeneration diff --git a/doc/Changelog.txt b/doc/Changelog.txt index abfee98..6bdd778 100644 --- a/doc/Changelog.txt +++ b/doc/Changelog.txt @@ -8,6 +8,39 @@ bug reports and feature request are here : https://sourceforge.net/p/mediainfo/_list/tickets +Version 0.7.65, 2013-11-20 +-------------- ++ MXF: forcing detection of MPEG Video in case EssenceCompression is not present but MPEG2VideoDescriptor is present ++ GXF: detection of some captions and time codes event if they are not present at the beginning of the file (testing middle of the file) ++ DASH MPD: basic support ++ HDS F4M (Flash Media Manifest): basic support ++ DCP AssetMap (AM), PackageList (PKL) and CompositionPlaylist (CPL): basic support ++ IMF AssetMap (AM), PackageList (PKL) and CompositionPlaylist (CPL): basic support ++ Mac dylib: looking for the dylib in @executable_path and CFBundleCopyExecutableURL dir ++ AAC: option for instantaneous bitrate in fast detect mode (MediaInfoLib only) ++ FTP (custom builds only): support of UTF-8 file names ++ Colour description: colour_description_present added, better separation between bitstream values and container values ++ MPEG-4: RLE, color space and bit depth ++ Law rating: support of CEA-608 XDS Content Advisory in MPEG-PS, MPEG-Ts, LXF, GXF ++ MPEG-4/MOV: Bug found in one file, sample size is 16 with a 32-bit CodecID ("fl32"), correcting the output of MediaInfo +x #B775, AVI: AVI can use negative height for raw to signal that it's coded top-down, not bottom-up +x #B780, MPEG-TS: crash with some files having PAT/PMT change between begin and end of the file +x #B782, PBCore 1.2: some fields were not in the right order +x #B784, some humain readable strings were not removed when the corresponding field is removed +x #B787, MPEG-4/QuickTime: Erratic appereance of Bitrate Mode +x #B798: setlocale() remove from DLL +x #B785, DVCPRO HD: streams can be 8 or 10 bit, removing hard coded value from DV parser (MXF header value is used instead when applicable) +x MPEG-4: wrong demux of some E-AC-3 streams +x AAC: detection of HE-AACv2 was missing if the library is configured with fast detection +x MPEG Video: wrong computing of duration of raw stream in case of drop frame time code +x Automation, StreamKind type was set to integer, it is text +x MPEG-4: was reading lot of useless bytes from disk when the raw stream format is not known +x AVI: crash with some malformed text streams +x Reference/playlist files were not supported from FTP (custom builds only) +x MPEG-4/MOV: ScanOrder was using "stored" value instead of "displayed" value +x MXF: Detection of Dolby E was not working in some cases (regression in 0.7.62) +x MPEG-4/MOV: freeze with some files having mono 32-bit PCM + Version 0.7.64, 2013-07-05 -------------- + New canonical URL of the website: http://MediaArea.net/MediaInfo diff --git a/res/logo.png b/res/logo.png index 267c65f680cee488a7faa52fed7938b40801307a..5e8c1007278b9358a8f19e0b7ff3095f64f97301 100644 GIT binary patch literal 7600 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 S5_)I=0000-Vs0_+Kof(c}^47Ot! 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 T<|Guc00000NkvXXu0mjf%C;<+ diff --git a/src/Config.h b/src/Config.h index 925ddf0..32bf60c 100644 --- a/src/Config.h +++ b/src/Config.h @@ -21,12 +21,12 @@ //Version static unsigned int mixp_versionMajor = 2; -static unsigned int mixp_versionMinor = 5; +static unsigned int mixp_versionMinor = 6; //MediaInfo Version static unsigned int mixp_miVersionMajor = 0; static unsigned int mixp_miVersionMinor = 7; -static unsigned int mixp_miVersionPatch = 64; +static unsigned int mixp_miVersionPatch = 65; //Build date static const char *mixp_buildDate = __DATE__; diff --git a/src/Main.cpp b/src/Main.cpp index cead289..1b786f0 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #pragma intrinsic(_InterlockedExchange) @@ -159,6 +160,12 @@ void mixp_invalid_param_handler(const wchar_t* exp, const wchar_t* fun, const wc mixp_fatal_exit(L"Invalid parameter handler invoked, application will exit!"); } +static void mixp_signal_handler(int signal_num) +{ + signal(signal_num, mixp_signal_handler); + mixp_fatal_exit(L"Signal handler invoked, application will exit!"); +} + /////////////////////////////////////////////////////////////////////////////// // Message Handler /////////////////////////////////////////////////////////////////////////////// @@ -267,14 +274,26 @@ int main(int argc, char* argv[]) { if(MIXP_DEBUG) { + _mixp_global_init(); return _main(argc, argv); } else { __try { + SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX); SetUnhandledExceptionFilter(mixp_exception_handler); + SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL); _set_invalid_parameter_handler(mixp_invalid_param_handler); + + static const int signal_num[6] = { SIGABRT, SIGFPE, SIGILL, SIGINT, SIGSEGV, SIGTERM }; + + for(size_t i = 0; i < 6; i++) + { + signal(signal_num[i], mixp_signal_handler); + } + + _mixp_global_init(); return _main(argc, argv); } __except(1) diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index 1942392..2c63ef5 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -36,9 +36,12 @@ #include #include +//CRT +#include + //Win32 -#define WIN32_LEAN_AND_MEAN -#include +//#define WIN32_LEAN_AND_MEAN +//#include //Internal #include "Config.h" @@ -84,6 +87,9 @@ CMainWindow::CMainWindow(const QString &tempFolder, QWidget *parent) ui->setupUi(this); setMinimumSize(this->size()); + //Setup Icon + m_icon = mixp_set_window_icon(this, QIcon(":/res/logo.png"), true); + //Setup links ui->actionLink_MuldeR->setData(QVariant(QString::fromLatin1(LINK_MULDER))); ui->actionLink_MediaInfo->setData(QVariant(QString::fromLatin1(LINK_MEDIAINFO))); @@ -116,9 +122,11 @@ CMainWindow::CMainWindow(const QString &tempFolder, QWidget *parent) m_floatingLabel->insertActions(0, ui->textBrowser->actions()); //Clear - m_mediaInfoPath.clear(); - m_mediaInfoHandle = INVALID_HANDLE_VALUE; + m_mediaInfoHandle = NULL; m_process = NULL; + + //Randomize + qsrand((uint) time(NULL)); } //////////////////////////////////////////////////////////// @@ -127,13 +135,15 @@ CMainWindow::CMainWindow(const QString &tempFolder, QWidget *parent) CMainWindow::~CMainWindow(void) { - if(m_mediaInfoHandle != INVALID_HANDLE_VALUE) + if(m_mediaInfoHandle != NULL) { - CloseHandle(m_mediaInfoHandle); - m_mediaInfoHandle = INVALID_HANDLE_VALUE; + m_mediaInfoHandle->remove(); + MIXP_DELETE_OBJ(m_mediaInfoHandle); } MIXP_DELETE_OBJ(m_process); MIXP_DELETE_OBJ(m_floatingLabel); + + mixp_free_window_icon(m_icon); } //////////////////////////////////////////////////////////// @@ -255,7 +265,7 @@ void CMainWindow::keyPressEvent(QKeyEvent *e) { if(m_process && (m_process->state() != QProcess::NotRunning)) { - MessageBeep(MB_ICONERROR); + mixp_beep(mixp_beep_error); qWarning("Escape pressed, terminated process!"); m_process->kill(); } @@ -368,7 +378,7 @@ void CMainWindow::analyzeNextFile(void) return; } - qDebug("Process started successfully (PID: %u)", m_process->pid()->dwProcessId); + qDebug("Process started successfully (PID: %u)", 42); //m_process->pid()->dwProcessId); } void CMainWindow::analyzeButtonClicked(void) @@ -404,7 +414,7 @@ void CMainWindow::saveButtonClicked(void) { file.write(m_outputLines.join("\r\n").toUtf8()); file.close(); - MessageBeep(MB_ICONINFORMATION); + mixp_beep(mixp_beep_info); } else { @@ -424,7 +434,7 @@ void CMainWindow::copyToClipboardButtonClicked(void) if(QClipboard *clipboard = QApplication::clipboard()) { clipboard->setText(m_outputLines.join("\n")); - MessageBeep(MB_ICONINFORMATION); + mixp_beep(mixp_beep_info); } } @@ -511,7 +521,7 @@ void CMainWindow::processFinished(void) escapeHtmlChars(htmlData); //Highlight headers - htmlData.replaceInStrings(QRegExp("^(-+)$"), "\\1"); //Separator lines + htmlData.replaceInStrings(QRegExp("^(-+)$"), "\\1"); //Separator lines htmlData.replaceInStrings(QRegExp("^([^:<>]+):(.+)$"), "\\1:\\2"); //Info lines htmlData.replaceInStrings(QRegExp("^([^:<>]+)$"), "\\1"); //Heading lines @@ -608,18 +618,15 @@ void CMainWindow::updateSize(void) #define VALIDATE_MEDIAINFO(HANDLE) do \ { \ - if(HANDLE != INVALID_HANDLE_VALUE) \ + if((HANDLE)) \ { \ - QByteArray buffer(mediaInfoRes.size(), '\0'); DWORD bytesRead = 0; \ - if(GetFileSize(HANDLE, NULL) == mediaInfoRes.size()) \ - { \ - SetFilePointer(HANDLE, 0L, NULL, FILE_BEGIN); \ - ReadFile(HANDLE, buffer.data(), mediaInfoRes.size(), &bytesRead, NULL); \ - } \ - if(memcmp(buffer.constData(), mediaInfoRes.data(), mediaInfoRes.size()) != 0) \ + (HANDLE)->seek(0); \ + QByteArray buffer = (HANDLE)->readAll(); \ + if((buffer.size() != mediaInfoRes.size()) || (memcmp(buffer.constData(), mediaInfoRes.data(), mediaInfoRes.size()) != 0)) \ { \ qWarning("MediaInfo binary failed to validate!"); \ - m_mediaInfoPath.clear(); \ + (HANDLE)->remove(); \ + MIXP_DELETE_OBJ((HANDLE)); \ } \ } \ } \ @@ -628,71 +635,52 @@ while(0) QString CMainWindow::getMediaInfoPath(void) { QResource mediaInfoRes(":/res/MediaInfo.i386.exe"); - if(!mediaInfoRes.isValid()) + if((!mediaInfoRes.isValid()) || (!mediaInfoRes.data())) { qFatal("MediaInfo resource could not be initialized!"); return QString(); } - //Already existsing? - if(!m_mediaInfoPath.isEmpty()) - { - QFileInfo mediaInfoNfo(m_mediaInfoPath); - if(!(mediaInfoNfo.exists() && mediaInfoNfo.isFile())) - { - qWarning("MediaInfo binary does NOT seem to exist any longer!\n"); - m_mediaInfoPath.clear(); - } - } - //Validate file content VALIDATE_MEDIAINFO(m_mediaInfoHandle); //Extract MediaInfo - if(m_mediaInfoPath.isEmpty()) + if(!m_mediaInfoHandle) { qDebug("MediaInfo binary not existing yet, going to extract now...\n"); - if(m_mediaInfoHandle != INVALID_HANDLE_VALUE) + m_mediaInfoHandle = new QFile(QString("%1/MediaInfo_%2.exe").arg(m_tempFolder, QString().sprintf("%04x", qrand() % 0xFFFF))); + if(m_mediaInfoHandle->open(QIODevice::ReadWrite | QIODevice::Truncate)) { - CloseHandle(m_mediaInfoHandle); - m_mediaInfoHandle = INVALID_HANDLE_VALUE; - } - QString path = QString("%1/MediaInfo.exe").arg(m_tempFolder); - QFile mediaInfoFile(path); - if(mediaInfoFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) - { - if(mediaInfoFile.write(reinterpret_cast(mediaInfoRes.data()), mediaInfoRes.size()) == mediaInfoRes.size()) + if(m_mediaInfoHandle->write(reinterpret_cast(mediaInfoRes.data()), mediaInfoRes.size()) == mediaInfoRes.size()) { - m_mediaInfoPath = path; - qDebug("MediaInfo path is:\n%s\n", m_mediaInfoPath.toUtf8().constData()); + qDebug("MediaInfo path is:\n%s\n", m_mediaInfoHandle->fileName().toUtf8().constData()); + m_mediaInfoHandle->close(); + if(!m_mediaInfoHandle->open(QIODevice::ReadOnly)) + { + qWarning("Failed to open MediaInfo binary for reading!\n"); + m_mediaInfoHandle->remove(); + MIXP_DELETE_OBJ(m_mediaInfoHandle); + } } else { qWarning("Failed to write data to MediaInfo binary file!\n"); + m_mediaInfoHandle->remove(); + MIXP_DELETE_OBJ(m_mediaInfoHandle); } - mediaInfoFile.close(); } else { qWarning("Failed to open MediaInfo binary for writing!\n"); - } - } - - //Open file for reading - if((!m_mediaInfoPath.isEmpty()) && (m_mediaInfoHandle == INVALID_HANDLE_VALUE)) - { - m_mediaInfoHandle = CreateFileW(QWCHAR(QDir::toNativeSeparators(m_mediaInfoPath)), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0); - if(m_mediaInfoHandle == INVALID_HANDLE_VALUE) - { - qWarning("Failed to open the MediaInfo binary for reading!\n"); - m_mediaInfoPath.clear(); + MIXP_DELETE_OBJ(m_mediaInfoHandle); } } //Validate file content VALIDATE_MEDIAINFO(m_mediaInfoHandle); - return m_mediaInfoPath; + //Return current MediaInfo path + return m_mediaInfoHandle ? m_mediaInfoHandle->fileName() : QString(); } void CMainWindow::escapeHtmlChars(QStringList &strings) diff --git a/src/MainWindow.h b/src/MainWindow.h index abc98d1..3d1c702 100644 --- a/src/MainWindow.h +++ b/src/MainWindow.h @@ -30,7 +30,8 @@ namespace Ui { } class QProcess; class QLabel; -typedef void *HANDLE; +class QFile; +class mixp_icon_t; //MainWindow class class CMainWindow: public QMainWindow @@ -68,12 +69,12 @@ private: const QString &m_tempFolder; bool m_firstShow; - QString m_mediaInfoPath; - HANDLE m_mediaInfoHandle; + QFile *m_mediaInfoHandle; QProcess *m_process; QLabel *m_floatingLabel; QStringList m_pendingFiles; QStringList m_outputLines; + mixp_icon_t *m_icon; const QList> m_htmlEscape; diff --git a/src/Utils.cpp b/src/Utils.cpp index 1f62db9..3e24d71 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -22,6 +22,14 @@ #include "Utils.h" #include "Config.h" +//Win32 +#define WIN32_LEAN_AND_MEAN +#include +#include +#include +#include +#include + //StdLib #include #include @@ -36,45 +44,70 @@ #include #include #include +#include +#include +#include +#include -//Win32 -#define WIN32_LEAN_AND_MEAN -#include -#include -#include -#include -#include +//Function pointers +typedef HRESULT (WINAPI *SHGetKnownFolderPath_t)(const GUID &rfid, DWORD dwFlags, HANDLE hToken, PWSTR *ppszPath); +typedef HRESULT (WINAPI *SHGetFolderPath_t)(HWND hwndOwner, int nFolder, HANDLE hToken, DWORD dwFlags, LPWSTR pszPath); + +//Known folders +typedef enum +{ + mixp_folder_localappdata = 0, + mixp_folder_programfiles = 2, + mixp_folder_systemfolder = 3, + mixp_folder_systroot_dir = 4 +} +mixp_known_folder_t; + +//Known folder cache +static struct +{ + bool initialized; + QMap knownFolders; + SHGetKnownFolderPath_t getKnownFolderPath; + SHGetFolderPath_t getFolderPath; + QReadWriteLock lock; +} +g_mixp_known_folder; /* * Try to lock folder */ -QString mixp_tryLockFolder(const QString &folderPath, QFile **lockfile) +static QString mixp_tryLockFolder(const QString &folderPath, QFile **lockfile) { - const QString SUB_FOLDER = QUuid::createUuid().toString(); - const QByteArray WRITE_TEST_DATA = QByteArray("Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua."); + const QByteArray WRITE_TEST_DATA = QByteArray("Lorem ipsum dolor sit amet, consetetur sadipscing elitr!"); - QDir folder(folderPath); - if(!folder.exists()) + for(int i = 0; i < 32; i++) { - folder.mkdir("."); - } - - if(folder.exists()) - { - folder.mkdir(SUB_FOLDER); - if(folder.cd(SUB_FOLDER) && folder.exists()) + QDir folder(folderPath); + if(!folder.exists()) { - QFile *testFile = new QFile(QString("%1/~lock.tmp").arg(folder.canonicalPath())); - if(testFile->open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Unbuffered)) + folder.mkdir("."); + } + + if(folder.exists()) + { + const QString SUB_FOLDER = QUuid::createUuid().toString().remove('{').remove('}').remove('-').right(16); + + folder.mkdir(SUB_FOLDER); + if(folder.cd(SUB_FOLDER) && folder.exists()) { - if(testFile->write(WRITE_TEST_DATA) >= WRITE_TEST_DATA.size()) + QFile *testFile = new QFile(QString("%1/~lock.tmp").arg(folder.canonicalPath())); + if(testFile->open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Unbuffered)) { - *lockfile = testFile; - return folder.canonicalPath(); + if(testFile->write(WRITE_TEST_DATA) >= WRITE_TEST_DATA.size()) + { + *lockfile = testFile; + return folder.canonicalPath(); + } + testFile->remove(); } - testFile->remove(); + MIXP_DELETE_OBJ(testFile); } - MIXP_DELETE_OBJ(testFile); } } @@ -82,66 +115,107 @@ QString mixp_tryLockFolder(const QString &folderPath, QFile **lockfile) } /* - * Get AppData folder + * Locate known folder on local system */ -QString mixp_getAppDataFolder(void) +static const QString &mixp_known_folder(mixp_known_folder_t folder_id) { - typedef HRESULT (WINAPI *SHGetKnownFolderPathFun)(__in const GUID &rfid, __in DWORD dwFlags, __in HANDLE hToken, __out PWSTR *ppszPath); - typedef HRESULT (WINAPI *SHGetFolderPathFun)(__in HWND hwndOwner, __in int nFolder, __in HANDLE hToken, __in DWORD dwFlags, __out LPWSTR pszPath); - - static const int CSIDL_LOCAL_APPDATA = 0x001c; - static const GUID GUID_LOCAL_APPDATA = {0xF1B32785,0x6FBA,0x4FCF,{0x9D,0x55,0x7B,0x8E,0x7F,0x15,0x70,0x91}}; - - SHGetKnownFolderPathFun SHGetKnownFolderPathPtr = NULL; - SHGetFolderPathFun SHGetFolderPathPtr = NULL; - - QLibrary kernel32Lib("shell32.dll"); - if(kernel32Lib.load()) + static const int CSIDL_FLAG_CREATE = 0x8000; + typedef enum { KF_FLAG_CREATE = 0x00008000 } kf_flags_t; + + struct { - SHGetKnownFolderPathPtr = (SHGetKnownFolderPathFun) kernel32Lib.resolve("SHGetKnownFolderPath"); - SHGetFolderPathPtr = (SHGetFolderPathFun) kernel32Lib.resolve("SHGetFolderPathW"); + const int csidl; + const GUID guid; + } + static s_folders[] = + { + { 0x001c, {0xF1B32785,0x6FBA,0x4FCF,{0x9D,0x55,0x7B,0x8E,0x7F,0x15,0x70,0x91}} }, //CSIDL_LOCAL_APPDATA + { 0x0026, {0x905e63b6,0xc1bf,0x494e,{0xb2,0x9c,0x65,0xb7,0x32,0xd3,0xd2,0x1a}} }, //CSIDL_PROGRAM_FILES + { 0x0024, {0xF38BF404,0x1D43,0x42F2,{0x93,0x05,0x67,0xDE,0x0B,0x28,0xFC,0x23}} }, //CSIDL_WINDOWS_FOLDER + { 0x0025, {0x1AC14E77,0x02E7,0x4E5D,{0xB7,0x44,0x2E,0xB1,0xAE,0x51,0x98,0xB7}} }, //CSIDL_SYSTEM_FOLDER + }; + + size_t folderId = size_t(-1); + + switch(folder_id) + { + case mixp_folder_localappdata: folderId = 0; break; + case mixp_folder_programfiles: folderId = 1; break; + case mixp_folder_systroot_dir: folderId = 2; break; + case mixp_folder_systemfolder: folderId = 3; break; } - QString folder; - - if(SHGetKnownFolderPathPtr) + if(folderId == size_t(-1)) { - qDebug("SHGetKnownFolderPathPtr()\n"); - WCHAR *path = NULL; - if(SHGetKnownFolderPathPtr(GUID_LOCAL_APPDATA, 0x00008000, NULL, &path) == S_OK) + qWarning("Invalid 'known' folder was requested!"); + return *reinterpret_cast(NULL); + } + + QReadLocker readLock(&g_mixp_known_folder.lock); + + //Already in cache? + if(g_mixp_known_folder.knownFolders.contains(folderId)) + { + return g_mixp_known_folder.knownFolders[folderId]; + } + + //Obtain write lock to initialize + readLock.unlock(); + QWriteLocker writeLock(&g_mixp_known_folder.lock); + + //Still not in cache? + if(g_mixp_known_folder.knownFolders.contains(folderId)) + { + return g_mixp_known_folder.knownFolders[folderId]; + } + + //Initialize on first call + if(!g_mixp_known_folder.initialized) + { + QLibrary shell32("shell32.dll"); + if(shell32.load()) { + g_mixp_known_folder.getFolderPath = (SHGetFolderPath_t) shell32.resolve("SHGetFolderPathW"); + g_mixp_known_folder.getKnownFolderPath = (SHGetKnownFolderPath_t) shell32.resolve("SHGetKnownFolderPath"); + } + g_mixp_known_folder.initialized = true; + } + + QString folderPath; + + //Now try to get the folder path! + if(g_mixp_known_folder.getKnownFolderPath) + { + WCHAR *path = NULL; + if(g_mixp_known_folder.getKnownFolderPath(s_folders[folderId].guid, KF_FLAG_CREATE, NULL, &path) == S_OK) + { + //MessageBoxW(0, path, L"SHGetKnownFolderPath", MB_TOPMOST); QDir folderTemp = QDir(QDir::fromNativeSeparators(QString::fromUtf16(reinterpret_cast(path)))); - if(!folderTemp.exists()) - { - folderTemp.mkpath("."); - } if(folderTemp.exists()) { - folder = folderTemp.canonicalPath(); + folderPath = folderTemp.canonicalPath(); } CoTaskMemFree(path); } } - else if(SHGetFolderPathPtr) + else if(g_mixp_known_folder.getFolderPath) { - qDebug("SHGetFolderPathPtr()\n"); WCHAR *path = new WCHAR[4096]; - if(SHGetFolderPathPtr(NULL, CSIDL_LOCAL_APPDATA, NULL, NULL, path) == S_OK) + if(g_mixp_known_folder.getFolderPath(NULL, s_folders[folderId].csidl | CSIDL_FLAG_CREATE, NULL, NULL, path) == S_OK) { + //MessageBoxW(0, path, L"SHGetFolderPathW", MB_TOPMOST); QDir folderTemp = QDir(QDir::fromNativeSeparators(QString::fromUtf16(reinterpret_cast(path)))); - if(!folderTemp.exists()) - { - folderTemp.mkpath("."); - } if(folderTemp.exists()) { - folder = folderTemp.canonicalPath(); + folderPath = folderTemp.canonicalPath(); } } - delete [] path; + MIXP_DELETE_ARR(path); } - return folder; + //Update cache + g_mixp_known_folder.knownFolders.insert(folderId, folderPath); + return g_mixp_known_folder.knownFolders[folderId]; } /* @@ -158,18 +232,22 @@ QString mixp_getTempFolder(QFile **lockfile) return tempPath; } - qWarning("Failed to init %%TEMP%%, falling back to %%LOCALAPPDATA%%\n"); + qWarning("Failed to init %%TEMP%%, falling back to %%LOCALAPPDATA%% or %%SYSTEMROOT%%\n"); //Create TEMP folder in %LOCALAPPDATA% - QString localAppDataPath = mixp_getAppDataFolder(); - if(!localAppDataPath.isEmpty()) + for(int i = 0; i < 2; i++) { - if(QDir(localAppDataPath).exists()) + static const mixp_known_folder_t folderId[2] = { mixp_folder_localappdata, mixp_folder_systroot_dir }; + const QString &localAppDataPath = mixp_known_folder(folderId[i]); + if(!localAppDataPath.isEmpty()) { - tempPath = mixp_tryLockFolder(QString("%1/Temp").arg(localAppDataPath), lockfile); - if(!tempPath.isEmpty()) + if(QDir(localAppDataPath).exists()) { - return tempPath; + tempPath = mixp_tryLockFolder(QString("%1/Temp").arg(localAppDataPath), lockfile); + if(!tempPath.isEmpty()) + { + return tempPath; + } } } } @@ -178,37 +256,76 @@ QString mixp_getTempFolder(QFile **lockfile) } /* - * Clean folder + * Safely remove a file */ -void mixp_clean_folder(const QString &folderPath) +static bool mixp_remove_file(const QString &filename) { - QDir tempFolder(folderPath); - QFileInfoList entryList = tempFolder.entryInfoList(QDir::AllEntries | QDir::NoDotAndDotDot); - - for(int i = 0; i < entryList.count(); i++) + if(!QFileInfo(filename).exists() || !QFileInfo(filename).isFile()) { - if(entryList.at(i).isDir()) + return true; + } + else + { + if(!QFile::remove(filename)) { - mixp_clean_folder(entryList.at(i).canonicalFilePath()); + static const DWORD attrMask = FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM; + const DWORD attributes = GetFileAttributesW(QWCHAR(filename)); + if(attributes & attrMask) + { + SetFileAttributesW(QWCHAR(filename), FILE_ATTRIBUTE_NORMAL); + } + if(!QFile::remove(filename)) + { + qWarning("Could not delete \"%s\"", filename.toLatin1().constData()); + return false; + } + else + { + return true; + } } else { - for(int j = 0; j < 5; j++) - { - if(QFile::remove(entryList.at(i).canonicalFilePath())) - { - break; - } - } + return true; } } - - tempFolder.rmdir("."); } /* * Clean folder */ +bool mixp_clean_folder(const QString &folderPath) +{ + QDir tempFolder(folderPath); + if(tempFolder.exists()) + { + QFileInfoList entryList = tempFolder.entryInfoList(QDir::AllEntries | QDir::NoDotAndDotDot | QDir::Hidden); + + for(int i = 0; i < entryList.count(); i++) + { + if(entryList.at(i).isDir()) + { + mixp_clean_folder(entryList.at(i).canonicalFilePath()); + } + else + { + for(int j = 0; j < 3; j++) + { + if(mixp_remove_file(entryList.at(i).canonicalFilePath())) + { + break; + } + } + } + } + return tempFolder.rmdir("."); + } + return true; +} + +/* + * Get build date + */ QDate mixp_get_build_date(void) { QDate buildDate(2000, 1, 1); @@ -240,7 +357,7 @@ QDate mixp_get_build_date(void) } /* - * Clean folder + * Get current date */ QDate mixp_get_current_date(void) { @@ -301,3 +418,69 @@ QDate mixp_get_current_date(void) const QDate processDate = QDate(lastStartTime_system.wYear, lastStartTime_system.wMonth, lastStartTime_system.wDay); return (currentDate >= processDate) ? currentDate : processDate; } + +/* + * Convert QIcon to HICON -> caller is responsible for destroying the HICON! + */ +static HICON mixp_qicon2hicon(const QIcon &icon, const int w, const int h) +{ + if(!icon.isNull()) + { + QPixmap pixmap = icon.pixmap(w, h); + if(!pixmap.isNull()) + { + return pixmap.toWinHICON(); + } + } + return NULL; +} + +/* + * Update the window icon + */ +mixp_icon_t *mixp_set_window_icon(QWidget *window, const QIcon &icon, const bool bIsBigIcon) +{ + if(!icon.isNull()) + { + const int extend = (bIsBigIcon ? 32 : 16); + if(HICON hIcon = mixp_qicon2hicon(icon, extend, extend)) + { + SendMessage(window->winId(), WM_SETICON, (bIsBigIcon ? ICON_BIG : ICON_SMALL), LPARAM(hIcon)); + return reinterpret_cast(hIcon); + } + } + return NULL; +} + +/* + * Free window icon + */ +void mixp_free_window_icon(mixp_icon_t *icon) +{ + if(HICON hIcon = reinterpret_cast(icon)) + { + DestroyIcon(hIcon); + } +} + +/* + * Message Beep + */ +bool mixp_beep(int beepType) +{ + switch(beepType) + { + case mixp_beep_info: return (MessageBeep(MB_ICONASTERISK) != FALSE); break; + case mixp_beep_warning: return (MessageBeep(MB_ICONEXCLAMATION) != FALSE); break; + case mixp_beep_error: return (MessageBeep(MB_ICONHAND) != FALSE); break; + default: return false; + } +} + +/* + * Global init + */ +void _mixp_global_init(void) +{ + g_mixp_known_folder.initialized = false; +} diff --git a/src/Utils.h b/src/Utils.h index 35ef68e..9d058e3 100644 --- a/src/Utils.h +++ b/src/Utils.h @@ -25,14 +25,32 @@ #include class QDate; +class QWidget; +class QIcon; +class mixp_icon_t; //Helper macros #define MIXP_DELETE_OBJ(PTR) do { if((PTR)) { delete ((PTR)); (PTR) = NULL; } } while (0) #define MIXP_DELETE_ARR(PTR) do { if((PTR)) { delete [] ((PTR)); (PTR) = NULL; } } while (0) #define QWCHAR(STR) reinterpret_cast(STR.utf16()) +//Beep types +typedef enum +{ + mixp_beep_info = 0, + mixp_beep_warning = 1, + mixp_beep_error = 2 +} +mixp_beep_t; + //Utils QString mixp_getTempFolder(QFile **lockfile); -void mixp_clean_folder(const QString &folderPath); +bool mixp_clean_folder(const QString &folderPath); QDate mixp_get_build_date(void); QDate mixp_get_current_date(void); +mixp_icon_t *mixp_set_window_icon(QWidget *window, const QIcon &icon, const bool bIsBigIcon); +void mixp_free_window_icon(mixp_icon_t *icon); +bool mixp_beep(int beepType); + +//Init +void _mixp_global_init(void); diff --git a/z_build.bat b/z_build.bat index eb7c727..bf79e04 100644 --- a/z_build.bat +++ b/z_build.bat @@ -2,8 +2,8 @@ REM /////////////////////////////////////////////////////////////////////////// REM // Set Paths REM /////////////////////////////////////////////////////////////////////////// -set "MSVC_PATH=C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC" -set "QTVC_PATH=C:\Qt\4.8.4" +set "MSVC_PATH=C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC" +set "QTVC_PATH=C:\Qt\4.8.5" set "UPX3_PATH=C:\UPX" REM ###############################################