Added shell extension (Explorer integration) support.

This commit is contained in:
LoRd_MuldeR 2014-01-14 23:27:43 +01:00
parent d69fd69219
commit e41ac245f6
12 changed files with 292 additions and 3 deletions

View File

@ -9,9 +9,11 @@
<file>res/ico_folder.png</file>
<file>res/ico_info.png</file>
<file>res/ico_link.png</file>
<file>res/ico_options.png</file>
<file>res/ico_paste.png</file>
<file>res/ico_qt.png</file>
<file>res/ico_quit.png</file>
<file>res/ico_shellext.png</file>
<file>res/loading.png</file>
<file>res/logo.png</file>
<file>res/MediaInfo.i386.exe</file>

View File

@ -127,6 +127,7 @@
<ItemGroup>
<ClCompile Include="src\Main.cpp" />
<ClCompile Include="src\MainWindow.cpp" />
<ClCompile Include="src\ShellExtension.cpp" />
<ClCompile Include="src\Utils.cpp" />
<ClCompile Include="tmp\Common\moc\MOC_MainWindow.cpp" />
<ClCompile Include="tmp\Common\rcc\RCC_MediaInfoXP.cpp" />
@ -143,6 +144,7 @@
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\Config.h" />
<ClInclude Include="src\ShellExtension.h" />
<ClInclude Include="src\Utils.h" />
</ItemGroup>
<ItemGroup>

View File

@ -48,6 +48,9 @@
<ClCompile Include="src\Utils.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\ShellExtension.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\Config.h">
@ -56,6 +59,9 @@
<ClInclude Include="src\Utils.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\ShellExtension.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="MediaInfoXP.rcx" />

View File

@ -230,12 +230,25 @@
<property name="title">
<string>Application</string>
</property>
<widget class="QMenu" name="menuPreferences">
<property name="title">
<string>Preferences</string>
</property>
<property name="icon">
<iconset resource="../MediaInfoXP.qrc">
<normaloff>:/res/ico_options.png</normaloff>:/res/ico_options.png</iconset>
</property>
<addaction name="actionShellExtension"/>
<addaction name="actionVerboseOutput"/>
</widget>
<addaction name="actionOpen"/>
<addaction name="separator"/>
<addaction name="actionSave"/>
<addaction name="actionCopyToClipboard"/>
<addaction name="actionClear"/>
<addaction name="separator"/>
<addaction name="menuPreferences"/>
<addaction name="separator"/>
<addaction name="actionExit"/>
</widget>
<widget class="QMenu" name="menuHelp">
@ -341,6 +354,25 @@
<string>Save to File...</string>
</property>
</action>
<action name="actionShellExtension">
<property name="checkable">
<bool>true</bool>
</property>
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Enable the Shell Integration</string>
</property>
</action>
<action name="actionVerboseOutput">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Enable Verbose Output</string>
</property>
</action>
</widget>
<tabstops>
<tabstop>analyzeButton</tabstop>

BIN
res/ico_options.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 512 B

BIN
res/ico_shellext.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 612 B

View File

@ -46,6 +46,7 @@
//Internal
#include "Config.h"
#include "Utils.h"
#include "ShellExtension.h"
//Macros
#define SET_FONT_BOLD(WIDGET,BOLD) { QFont _font = WIDGET->font(); _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)

View File

@ -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);

78
src/ShellExtension.cpp Normal file
View File

@ -0,0 +1,78 @@
///////////////////////////////////////////////////////////////////////////////
// MediaInfoXP
// Copyright (C) 2004-2014 LoRd_MuldeR <MuldeR2@GMX.de>
//
// 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 <QApplication>
#include <QDir>
#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;
}
}

35
src/ShellExtension.h Normal file
View File

@ -0,0 +1,35 @@
///////////////////////////////////////////////////////////////////////////////
// MediaInfoXP
// Copyright (C) 2004-2014 LoRd_MuldeR <MuldeR2@GMX.de>
//
// 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 <QObject>
class ShellExtension : public QObject
{
public:
static bool getEnabled(void);
static bool setEnabled(bool enabled);
private:
ShellExtension(void) {}
~ShellExtension(void) {}
};

View File

@ -29,6 +29,7 @@
#include <fcntl.h>
#include <Objbase.h>
#include <Psapi.h>
#include <Shlobj.h>
//StdLib
#include <cstdio>
@ -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<const BYTE*>(&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<const BYTE*>(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<BYTE*>(&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
*/

View File

@ -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);