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 267c65f..5e8c100 100644 Binary files a/res/logo.png and b/res/logo.png differ 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 ###############################################