From e41ac245f62a01d7ebc8ba157d5897165cf5c248 Mon Sep 17 00:00:00 2001 From: MuldeR Date: Tue, 14 Jan 2014 23:27:43 +0100 Subject: [PATCH] Added shell extension (Explorer integration) support. --- MediaInfoXP.qrc | 2 + MediaInfoXP.vcxproj | 2 + MediaInfoXP.vcxproj.filters | 6 +++ gui/Dialog.ui | 32 +++++++++++++ res/ico_options.png | Bin 0 -> 512 bytes res/ico_shellext.png | Bin 0 -> 612 bytes src/MainWindow.cpp | 35 ++++++++++++++- src/MainWindow.h | 2 + src/ShellExtension.cpp | 78 ++++++++++++++++++++++++++++++++ src/ShellExtension.h | 35 +++++++++++++++ src/Utils.cpp | 87 +++++++++++++++++++++++++++++++++++- src/Utils.h | 16 +++++++ 12 files changed, 292 insertions(+), 3 deletions(-) create mode 100644 res/ico_options.png create mode 100644 res/ico_shellext.png create mode 100644 src/ShellExtension.cpp create mode 100644 src/ShellExtension.h diff --git a/MediaInfoXP.qrc b/MediaInfoXP.qrc index b5a728a..b002b1d 100644 --- a/MediaInfoXP.qrc +++ b/MediaInfoXP.qrc @@ -9,9 +9,11 @@ res/ico_folder.png res/ico_info.png res/ico_link.png + res/ico_options.png res/ico_paste.png res/ico_qt.png res/ico_quit.png + res/ico_shellext.png res/loading.png res/logo.png res/MediaInfo.i386.exe diff --git a/MediaInfoXP.vcxproj b/MediaInfoXP.vcxproj index c9e5454..0c7845b 100644 --- a/MediaInfoXP.vcxproj +++ b/MediaInfoXP.vcxproj @@ -127,6 +127,7 @@ + @@ -143,6 +144,7 @@ + diff --git a/MediaInfoXP.vcxproj.filters b/MediaInfoXP.vcxproj.filters index 27bf07e..258241c 100644 --- a/MediaInfoXP.vcxproj.filters +++ b/MediaInfoXP.vcxproj.filters @@ -48,6 +48,9 @@ Source Files + + Source Files + @@ -56,6 +59,9 @@ Header Files + + Header Files + diff --git a/gui/Dialog.ui b/gui/Dialog.ui index 52800cb..9880d70 100644 --- a/gui/Dialog.ui +++ b/gui/Dialog.ui @@ -230,12 +230,25 @@ Application + + + Preferences + + + + :/res/ico_options.png:/res/ico_options.png + + + + + + @@ -341,6 +354,25 @@ Save to File... + + + true + + + false + + + Enable the Shell Integration + + + + + true + + + Enable Verbose Output + + analyzeButton diff --git a/res/ico_options.png b/res/ico_options.png new file mode 100644 index 0000000000000000000000000000000000000000..67de2c6ccbeac17742f56cf7391e72b2bf5033ba GIT binary patch literal 512 zcmV+b0{{JqP)CQDsH?WF>AIFt zQuJ}i;w2$ZUU#3SZ6RY0Gw;kZ&ol1~2ky^QZ(fom$=jNJZt!z7w_pH~wdQ;R)Gh%BbQFCx+Nm!4SuS-vkr`vhhrX zM*>w%e+v~?m@q~ImPAgtLkR_3U<2F8LP3W5=LJ*ZN|S5p#sf4YFr$p~Q~Z*0Ngxf2 zjk#J#<7EAlhzlrV53~GF&pIzcCN_lz9@05UeoUXiK%N z#x+4o*i_c|6_Uu1+&TIho?3@y4k-#b8Y_o94zW*B3a1ne2-Y5s0uke$$|@=}OP-i= zNYZQA=>PrZu0MfSL=b8UhD_={W4IY1{b{)U)*gc45xtL%IYLY&hF;d`@GzI&7H&D# zh;z_BX$#hqh@q?AY3sJTod2%*Yd)_>YM0#q&ixGuh+PQsneK)F0000PDrjnPX=rH; zqQ${l4iyS4Fv&4giDwVmm?Q$ zhTL&8OyXERuCJ_Y++wrjMj8GD99k(+b> z<{<5wp8G;7au@E7lX7q%1U@V;^Dm<#Bbba-gga)&*~B}OVT z8FJ_8^ce^a9*{dnoOjg?w)UFTS_KNZh~pjN>QDihNJTD3CPDxgha7@4JUq?D&XIEY9KSYW_M1j`N1m2BQ6{jt9pgXOIG5 z7fYv3PRIVYk-8wpOV0eq;C3`{e8D((T~xwBz-I8+ZE$ y`XBWUUFlg}deaE*PP<-CUAQ$+zVt#$I(`F{%rIviW}jLB0000font(); _font.setBold(BOLD); WIDGET->setFont(_font); } @@ -105,6 +106,7 @@ CMainWindow::CMainWindow(const QString &tempFolder, QWidget *parent) connect(ui->actionLink_MediaInfo, SIGNAL(triggered()), this, SLOT(linkTriggered())); connect(ui->actionLink_Discuss, SIGNAL(triggered()), this, SLOT(linkTriggered())); connect(ui->actionAbout, SIGNAL(triggered()), this, SLOT(showAboutScreen())); + connect(ui->actionShellExtension, SIGNAL(toggled(bool)), this, SLOT(updateShellExtension(bool))); ui->versionLabel->installEventFilter(this); //Context menu @@ -192,6 +194,8 @@ void CMainWindow::showEvent(QShowEvent *event) { QTimer::singleShot(0, this, SLOT(analyzeFiles())); } + + QTimer::singleShot(1250, this, SLOT(initShellExtension())); m_firstShow = false; } } @@ -325,6 +329,7 @@ void CMainWindow::analyzeFiles(void) ui->actionCopyToClipboard->setEnabled(false); ui->actionSave->setEnabled(false); ui->actionOpen->setEnabled(false); + ui->menuPreferences->setEnabled(false); //Show banner m_floatingLabel->show(); @@ -356,14 +361,20 @@ void CMainWindow::analyzeNextFile(void) ui->actionOpen->setEnabled(true); ui->analyzeButton->setEnabled(true); ui->exitButton->setEnabled(true); + ui->menuPreferences->setEnabled(true); return; } const QString filePath = m_pendingFiles.takeFirst(); + //Generate the command line + QStringList commandLine; + if(ui->actionVerboseOutput->isChecked()) commandLine << "--Full"; + commandLine << QDir::toNativeSeparators(filePath); + //Start analyziation qDebug("Analyzing media file:\n%s\n", filePath.toUtf8().constData()); - m_process->start(mediaInfoPath, QStringList() << QDir::toNativeSeparators(filePath)); + m_process->start(mediaInfoPath, commandLine); //Wait for process to start if(!m_process->waitForStarted()) @@ -375,6 +386,7 @@ void CMainWindow::analyzeNextFile(void) ui->actionOpen->setEnabled(true); ui->analyzeButton->setEnabled(true); ui->exitButton->setEnabled(true); + ui->menuPreferences->setEnabled(true); return; } @@ -538,6 +550,27 @@ void CMainWindow::processFinished(void) ui->actionOpen->setEnabled(true); ui->analyzeButton->setEnabled(true); ui->exitButton->setEnabled(true); + ui->menuPreferences->setEnabled(true); +} + +void CMainWindow::initShellExtension(void) +{ + const bool isEnabled = ShellExtension::getEnabled(); + + if(isEnabled) + { + ShellExtension::setEnabled(true); + } + + ui->actionShellExtension->blockSignals(true); + ui->actionShellExtension->setChecked(isEnabled); + ui->actionShellExtension->setEnabled(true); + ui->actionShellExtension->blockSignals(false); +} + +void CMainWindow::updateShellExtension(bool checked) +{ + ShellExtension::setEnabled(checked); } void CMainWindow::linkTriggered(void) diff --git a/src/MainWindow.h b/src/MainWindow.h index b937281..f3e9035 100644 --- a/src/MainWindow.h +++ b/src/MainWindow.h @@ -54,6 +54,8 @@ private slots: void linkTriggered(void); void showAboutScreen(void); void updateSize(void); + void initShellExtension(void); + void updateShellExtension(bool checked); protected: virtual void showEvent(QShowEvent *event); diff --git a/src/ShellExtension.cpp b/src/ShellExtension.cpp new file mode 100644 index 0000000..ba8b905 --- /dev/null +++ b/src/ShellExtension.cpp @@ -0,0 +1,78 @@ +/////////////////////////////////////////////////////////////////////////////// +// MediaInfoXP +// Copyright (C) 2004-2014 LoRd_MuldeR +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// http://www.gnu.org/licenses/gpl-2.0.txt +/////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "ShellExtension.h" +#include "Utils.h" + +#include +#include + +#define MIXP_REGISTRY_KEY "Software\\Classes\\*\\shell\\MediaInfoXP" +#define MIXP_REGISTRY_VAL "_shellExtEnabled" + +bool ShellExtension::getEnabled(void) +{ + quint32 value = 0; + if(mixp_reg_value_read(mixp_root_user, MIXP_REGISTRY_KEY, MIXP_REGISTRY_VAL, value)) + { + return value; + } + return false; +} + +bool ShellExtension::setEnabled(bool enabled) +{ + if(enabled) + { + qDebug("Installing the shell extension..."); + if(mixp_reg_value_write(mixp_root_user, MIXP_REGISTRY_KEY, QString(), tr("Analyze file with MediaInfoXP"))) + { + const QString appPath = QDir::toNativeSeparators(QApplication::applicationFilePath()); + const QString command = QString().sprintf("\"%ls\" --open \"%%1\"", appPath.utf16()); + if(mixp_reg_value_write(mixp_root_user, MIXP_REGISTRY_KEY"\\command", QString(), command)) + { + if(mixp_reg_value_write(mixp_root_user, MIXP_REGISTRY_KEY, MIXP_REGISTRY_VAL, 1)) + { + qDebug("Success.\n"); + mixp_shell_change_notification(); + return true; + } + } + } + qWarning("Failed to install the shell extension!\n"); + mixp_reg_key_delete(mixp_root_user, MIXP_REGISTRY_KEY); + return false; + } + else + { + qDebug("Un-installing the shell extension..."); + if(!mixp_reg_key_delete(mixp_root_user, MIXP_REGISTRY_KEY)) + { + qWarning("Failed to un-install the shell extension!\n"); + return false; + } + qDebug("Success.\n"); + mixp_shell_change_notification(); + return true; + } +} diff --git a/src/ShellExtension.h b/src/ShellExtension.h new file mode 100644 index 0000000..b00d908 --- /dev/null +++ b/src/ShellExtension.h @@ -0,0 +1,35 @@ +/////////////////////////////////////////////////////////////////////////////// +// MediaInfoXP +// Copyright (C) 2004-2014 LoRd_MuldeR +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// http://www.gnu.org/licenses/gpl-2.0.txt +/////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include + +class ShellExtension : public QObject +{ +public: + static bool getEnabled(void); + static bool setEnabled(bool enabled); + +private: + ShellExtension(void) {} + ~ShellExtension(void) {} +}; diff --git a/src/Utils.cpp b/src/Utils.cpp index 352df41..b3ce35e 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -29,6 +29,7 @@ #include #include #include +#include //StdLib #include @@ -119,8 +120,8 @@ static QString mixp_tryLockFolder(const QString &folderPath, QFile **lockfile) */ static const QString &mixp_known_folder(mixp_known_folder_t folder_id) { - static const int CSIDL_FLAG_CREATE = 0x8000; - typedef enum { KF_FLAG_CREATE = 0x00008000 } kf_flags_t; + //static const int CSIDL_FLAG_CREATE = 0x8000; + //typedef enum { KF_FLAG_CREATE = 0x00008000 } kf_flags_t; struct { @@ -477,6 +478,88 @@ bool mixp_beep(int beepType) } } +/* + * Registry root key + */ +static HKEY mixp_reg_root(int rootKey) +{ + switch(rootKey) + { + case mixp_root_classes: return HKEY_CLASSES_ROOT; break; + case mixp_root_user: return HKEY_CURRENT_USER; break; + case mixp_root_machine: return HKEY_LOCAL_MACHINE; break; + default: throw "Unknown root reg value was specified!"; + } +} + +/* + * Write registry value + */ +bool mixp_reg_value_write(int rootKey, const QString &keyName, const QString &valueName, const quint32 value) +{ + bool success = false; HKEY hKey = NULL; + if(RegCreateKeyEx(mixp_reg_root(rootKey), QWCHAR(keyName), 0, NULL, 0, KEY_WRITE, NULL, &hKey, NULL) == ERROR_SUCCESS) + { + if(RegSetValueEx(hKey, valueName.isEmpty() ? NULL : QWCHAR(valueName), 0, REG_DWORD, reinterpret_cast(&value), sizeof(quint32)) == ERROR_SUCCESS) + { + success = true; + } + CloseHandle(hKey); + } + return success; +} + +/* + * Write registry value + */ +bool mixp_reg_value_write(int rootKey, const QString &keyName, const QString &valueName, const QString &value) +{ + bool success = false; HKEY hKey = NULL; + if(RegCreateKeyEx(mixp_reg_root(rootKey), QWCHAR(keyName), 0, NULL, 0, KEY_WRITE, NULL, &hKey, NULL) == ERROR_SUCCESS) + { + if(RegSetValueEx(hKey, valueName.isEmpty() ? NULL : QWCHAR(valueName), 0, REG_SZ, reinterpret_cast(value.utf16()), (value.length() + 1) * sizeof(wchar_t)) == ERROR_SUCCESS) + { + success = true; + } + CloseHandle(hKey); + } + return success; +} + +/* + * Read registry value + */ +bool mixp_reg_value_read(int rootKey, const QString &keyName, const QString &valueName, quint32 &value) +{ + bool success = false; HKEY hKey = NULL; + if(RegOpenKeyEx(mixp_reg_root(rootKey), QWCHAR(keyName), 0, KEY_READ, &hKey) == ERROR_SUCCESS) + { + DWORD size = sizeof(quint32), type = -1; + if(RegQueryValueEx(hKey, valueName.isEmpty() ? NULL : QWCHAR(valueName), 0, &type, reinterpret_cast(&value), &size) == ERROR_SUCCESS) + { + success = (type == REG_DWORD); + } + CloseHandle(hKey); + } + return success; +} + +/* + * Delete registry key + */ +bool mixp_reg_key_delete(int rootKey, const QString &keyName) +{ + return (RegDeleteTree(mixp_reg_root(rootKey), QWCHAR(keyName)) == ERROR_SUCCESS); +} + +/* + * Shell notification + */ +void mixp_shell_change_notification(void) +{ + SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL); +} + /* * Global init */ diff --git a/src/Utils.h b/src/Utils.h index d54ee6b..3c14eaa 100644 --- a/src/Utils.h +++ b/src/Utils.h @@ -43,6 +43,15 @@ typedef enum } mixp_beep_t; +//Regsitry root +typedef enum +{ + mixp_root_classes = 0, + mixp_root_user = 1, + mixp_root_machine = 2, +} +mixp_reg_root_t; + //Utils QString mixp_getTempFolder(QFile **lockfile); bool mixp_clean_folder(const QString &folderPath); @@ -51,6 +60,13 @@ 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); +void mixp_shell_change_notification(void); + +//Regsitry +bool mixp_reg_value_write(int rootKey, const QString &keyName, const QString &valueName, const quint32 value); +bool mixp_reg_value_write(int rootKey, const QString &keyName, const QString &valueName, const QString &value); +bool mixp_reg_value_read(int rootKey, const QString &keyName, const QString &valueName, quint32 &value); +bool mixp_reg_key_delete(int rootKey, const QString &keyName); //Init void _mixp_global_init(void);