From 60b288a35403b0f000e9669c12ada936ae86fe45 Mon Sep 17 00:00:00 2001
From: cjee21 <77721854+cjee21@users.noreply.github.com>
Date: Thu, 28 Nov 2024 22:26:20 +0800
Subject: [PATCH 1/9] Add Windows shell extension for File Explorer context
menu
---
Project/MSVC2022/MediaInfo.sln | 10 +
.../MediaInfo_WindowsShellExtension.vcxproj | 207 ++++++++++++++++++
...Info_WindowsShellExtension.vcxproj.filters | 50 +++++
.../packages.config | 4 +
Source/WindowsShellExtension/Resource.rc | 33 +++
Source/WindowsShellExtension/dllmain.cpp | 203 +++++++++++++++++
Source/WindowsShellExtension/framework.h | 5 +
Source/WindowsShellExtension/pch.cpp | 5 +
Source/WindowsShellExtension/pch.h | 30 +++
Source/WindowsShellExtension/source.def | 8 +
10 files changed, 555 insertions(+)
create mode 100644 Project/MSVC2022/MediaInfo_WindowsShellExtension/MediaInfo_WindowsShellExtension.vcxproj
create mode 100644 Project/MSVC2022/MediaInfo_WindowsShellExtension/MediaInfo_WindowsShellExtension.vcxproj.filters
create mode 100644 Project/MSVC2022/MediaInfo_WindowsShellExtension/packages.config
create mode 100644 Source/WindowsShellExtension/Resource.rc
create mode 100644 Source/WindowsShellExtension/dllmain.cpp
create mode 100644 Source/WindowsShellExtension/framework.h
create mode 100644 Source/WindowsShellExtension/pch.cpp
create mode 100644 Source/WindowsShellExtension/pch.h
create mode 100644 Source/WindowsShellExtension/source.def
diff --git a/Project/MSVC2022/MediaInfo.sln b/Project/MSVC2022/MediaInfo.sln
index 3f2e4917f..35bdcb9cc 100644
--- a/Project/MSVC2022/MediaInfo.sln
+++ b/Project/MSVC2022/MediaInfo.sln
@@ -57,6 +57,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlibstat", "..\..\..\zlib\c
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RegressionTest", "..\..\..\MediaInfoLib\Project\MSVC2022\RegressionTest\RegressionTest.vcxproj", "{91C094CA-1170-4CE4-9B79-17324C8DACA8}"
EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MediaInfo_WindowsShellExtension", "MediaInfo_WindowsShellExtension\MediaInfo_WindowsShellExtension.vcxproj", "{E22FF9ED-8EC0-44B6-B313-55FC21B75F38}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
@@ -161,6 +163,14 @@ Global
{91C094CA-1170-4CE4-9B79-17324C8DACA8}.Release|Win32.Build.0 = Release|Win32
{91C094CA-1170-4CE4-9B79-17324C8DACA8}.Release|x64.ActiveCfg = Release|x64
{91C094CA-1170-4CE4-9B79-17324C8DACA8}.Release|x64.Build.0 = Release|x64
+ {E22FF9ED-8EC0-44B6-B313-55FC21B75F38}.Debug|Win32.ActiveCfg = Debug|Win32
+ {E22FF9ED-8EC0-44B6-B313-55FC21B75F38}.Debug|Win32.Build.0 = Debug|Win32
+ {E22FF9ED-8EC0-44B6-B313-55FC21B75F38}.Debug|x64.ActiveCfg = Debug|x64
+ {E22FF9ED-8EC0-44B6-B313-55FC21B75F38}.Debug|x64.Build.0 = Debug|x64
+ {E22FF9ED-8EC0-44B6-B313-55FC21B75F38}.Release|Win32.ActiveCfg = Release|Win32
+ {E22FF9ED-8EC0-44B6-B313-55FC21B75F38}.Release|Win32.Build.0 = Release|Win32
+ {E22FF9ED-8EC0-44B6-B313-55FC21B75F38}.Release|x64.ActiveCfg = Release|x64
+ {E22FF9ED-8EC0-44B6-B313-55FC21B75F38}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/Project/MSVC2022/MediaInfo_WindowsShellExtension/MediaInfo_WindowsShellExtension.vcxproj b/Project/MSVC2022/MediaInfo_WindowsShellExtension/MediaInfo_WindowsShellExtension.vcxproj
new file mode 100644
index 000000000..407d0cb16
--- /dev/null
+++ b/Project/MSVC2022/MediaInfo_WindowsShellExtension/MediaInfo_WindowsShellExtension.vcxproj
@@ -0,0 +1,207 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ Win32
+
+
+ Release
+ x64
+
+
+
+ 17.0
+ Win32Proj
+ {e22ff9ed-8ec0-44b6-b313-55fc21b75f38}
+ MediaInfoContextMenu
+ 10.0
+
+
+
+ DynamicLibrary
+ true
+ v143
+ Unicode
+
+
+ DynamicLibrary
+ true
+ v143
+ Unicode
+
+
+ DynamicLibrary
+ false
+ v143
+ true
+ Unicode
+
+
+ DynamicLibrary
+ false
+ v143
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ $(Platform)\$(Configuration)\
+ true
+
+
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ $(Platform)\$(Configuration)\
+ true
+
+
+ true
+
+
+ true
+
+
+
+ Level4
+ true
+ _DEBUG;MEDIAINFOCONTEXTMENU_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ true
+ Use
+ pch.h
+ stdcpp20
+
+
+ Windows
+ true
+ false
+ $(ProjectDir)..\..\..\Source\WindowsShellExtension\source.def
+
+
+
+
+ Level4
+ true
+ _DEBUG;MEDIAINFOCONTEXTMENU_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ true
+ Use
+ pch.h
+ stdcpp20
+
+
+ Windows
+ true
+ false
+ $(ProjectDir)..\..\..\Source\WindowsShellExtension\source.def
+
+
+
+
+ Level4
+ true
+ true
+ true
+ NDEBUG;MEDIAINFOCONTEXTMENU_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ true
+ Use
+ pch.h
+ stdcpp20
+ Guard
+ MultiThreaded
+ true
+
+
+ Windows
+ true
+ true
+ true
+ false
+ $(ProjectDir)..\..\..\Source\WindowsShellExtension\source.def
+ true
+ libucrt.lib;%(IgnoreSpecificDefaultLibraries)
+ /defaultlib:ucrt.lib /PDBALTPATH:%_PDB% %(AdditionalOptions)
+
+
+
+
+ Level4
+ true
+ true
+ true
+ NDEBUG;MEDIAINFOCONTEXTMENU_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ true
+ Use
+ pch.h
+ stdcpp20
+ Guard
+ MultiThreaded
+
+
+ Windows
+ true
+ true
+ true
+ false
+ $(ProjectDir)..\..\..\Source\WindowsShellExtension\source.def
+ true
+ libucrt.lib;%(IgnoreSpecificDefaultLibraries)
+ /defaultlib:ucrt.lib /PDBALTPATH:%_PDB% %(AdditionalOptions)
+
+
+
+
+
+
+
+
+
+
+ Create
+ Create
+ Create
+ Create
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
+
+
+
+
\ No newline at end of file
diff --git a/Project/MSVC2022/MediaInfo_WindowsShellExtension/MediaInfo_WindowsShellExtension.vcxproj.filters b/Project/MSVC2022/MediaInfo_WindowsShellExtension/MediaInfo_WindowsShellExtension.vcxproj.filters
new file mode 100644
index 000000000..4718a72c2
--- /dev/null
+++ b/Project/MSVC2022/MediaInfo_WindowsShellExtension/MediaInfo_WindowsShellExtension.vcxproj.filters
@@ -0,0 +1,50 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+
+
+ Source Files
+
+
+ Source Files
+
+
+
+
+ Resource Files
+
+
+
+
+
+ Source Files
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Project/MSVC2022/MediaInfo_WindowsShellExtension/packages.config b/Project/MSVC2022/MediaInfo_WindowsShellExtension/packages.config
new file mode 100644
index 000000000..04b661f41
--- /dev/null
+++ b/Project/MSVC2022/MediaInfo_WindowsShellExtension/packages.config
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/Source/WindowsShellExtension/Resource.rc b/Source/WindowsShellExtension/Resource.rc
new file mode 100644
index 000000000..b9a3f3c3e
--- /dev/null
+++ b/Source/WindowsShellExtension/Resource.rc
@@ -0,0 +1,33 @@
+#include
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 24,11,0,0
+ PRODUCTVERSION 24,11,0,0
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x40004L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0" // U.S. English (0x0409, 1033), Unicode (0x04B0, 1200)
+ BEGIN
+ VALUE "CompanyName", "MediaArea.net"
+ VALUE "FileDescription", "MediaInfo shell extension for File Explorer context menu"
+ VALUE "FileVersion", "24.11.0.0"
+ VALUE "LegalCopyright", "Copyright (C) 2002-2024 MediaArea.net SARL"
+ VALUE "OriginalFilename", "MediaInfo_WindowsShellExtension.dll"
+ VALUE "ProductName", "MediaInfo"
+ VALUE "ProductVersion", "24.11.0.0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
diff --git a/Source/WindowsShellExtension/dllmain.cpp b/Source/WindowsShellExtension/dllmain.cpp
new file mode 100644
index 000000000..ed56df1a1
--- /dev/null
+++ b/Source/WindowsShellExtension/dllmain.cpp
@@ -0,0 +1,203 @@
+/* Copyright (c) MediaArea.net SARL. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license that can
+ * be found in the License.html file in the root of the source tree.
+ */
+
+// dllmain.cpp : Defines the entry point for the DLL application.
+
+// IExplorerCommand File Explorer shell extension for context menu entry
+
+#include "pch.h"
+
+#pragma warning(disable : 4324)
+
+using Microsoft::WRL::ClassicCom;
+using Microsoft::WRL::ComPtr;
+using Microsoft::WRL::InhibitRoOriginateError;
+using Microsoft::WRL::Module;
+using Microsoft::WRL::ModuleType;
+using Microsoft::WRL::RuntimeClass;
+using Microsoft::WRL::RuntimeClassFlags;
+
+constexpr const wchar_t* menu_entry_title = L"MediaInfo";
+constexpr const wchar_t* exe_filename = L"MediaInfo.exe";
+
+BOOL APIENTRY DllMain(_In_ HMODULE hModule, _In_ DWORD ul_reason_for_call, _In_opt_ LPVOID lpReserved) {
+ UNREFERENCED_PARAMETER(hModule);
+ UNREFERENCED_PARAMETER(lpReserved);
+ switch (ul_reason_for_call) {
+ case DLL_PROCESS_ATTACH:
+ case DLL_THREAD_ATTACH:
+ case DLL_THREAD_DETACH:
+ case DLL_PROCESS_DETACH:
+ break;
+ }
+ return TRUE;
+}
+
+namespace {
+ // Extracted from
+ // https://source.chromium.org/chromium/chromium/src/+/main:base/command_line.cc;l=109-159
+
+ std::wstring QuoteForCommandLineArg(_In_ const std::wstring& arg) {
+ // We follow the quoting rules of CommandLineToArgvW.
+ // http://msdn.microsoft.com/en-us/library/17w5ykft.aspx
+ std::wstring quotable_chars(L" \\\"");
+ if (arg.find_first_of(quotable_chars) == std::wstring::npos) {
+ // No quoting necessary.
+ return arg;
+ }
+
+ std::wstring out;
+ out.push_back('"');
+ for (size_t i = 0; i < arg.size(); ++i) {
+ if (arg[i] == '\\') {
+ // Find the extent of this run of backslashes.
+ size_t start = i, end = start + 1;
+ for (; end < arg.size() && arg[end] == '\\'; ++end) {}
+ size_t backslash_count = end - start;
+
+ // Backslashes are escapes only if the run is followed by a double quote.
+ // Since we also will end the string with a double quote, we escape for
+ // either a double quote or the end of the string.
+ if (end == arg.size() || arg[end] == '"') {
+ // To quote, we need to output 2x as many backslashes.
+ backslash_count *= 2;
+ }
+ for (size_t j = 0; j < backslash_count; ++j)
+ out.push_back('\\');
+
+ // Advance i to one before the end to balance i++ in loop.
+ i = end - 1;
+ }
+ else if (arg[i] == '"') {
+ out.push_back('\\');
+ out.push_back('"');
+ }
+ else {
+ out.push_back(arg[i]);
+ }
+ }
+ out.push_back('"');
+
+ return out;
+ }
+
+}
+
+class __declspec(uuid("20669675-b281-4c4f-94fb-cb6fd3995545")) ExplorerCommandHandler final : public RuntimeClass, IExplorerCommand> {
+public:
+ // IExplorerCommand implementation:
+
+ IFACEMETHODIMP GetTitle(_In_opt_ IShellItemArray* items, _Outptr_ PWSTR* name) {
+ // Provide name for display in File Explorer context menu entry
+ UNREFERENCED_PARAMETER(items);
+ return SHStrDupW(menu_entry_title, name);
+ }
+
+ IFACEMETHODIMP GetIcon(_In_opt_ IShellItemArray* items, _Outptr_ PWSTR* icon) {
+ // Provide icon for display in File Explorer context menu entry
+ // Get path to application exe and use it as source for icon
+ UNREFERENCED_PARAMETER(items);
+ std::filesystem::path module_path{ wil::GetModuleFileNameW(wil::GetModuleInstanceHandle()) };
+ module_path = module_path.remove_filename();
+ module_path /= exe_filename;
+ return SHStrDupW(module_path.c_str(), icon);
+ }
+
+ IFACEMETHODIMP GetToolTip(_In_opt_ IShellItemArray* items, _Outptr_ PWSTR* infoTip) {
+ UNREFERENCED_PARAMETER(items);
+ *infoTip = nullptr;
+ return E_NOTIMPL;
+ }
+
+ IFACEMETHODIMP GetCanonicalName(_Out_ GUID* guidCommandName) {
+ *guidCommandName = GUID_NULL;
+ return S_OK;
+ }
+
+ IFACEMETHODIMP GetState(_In_opt_ IShellItemArray* items, _In_ BOOL okToBeSlow, _Out_ EXPCMDSTATE* cmdState) {
+ UNREFERENCED_PARAMETER(items);
+ UNREFERENCED_PARAMETER(okToBeSlow);
+ *cmdState = ECS_ENABLED;
+ return S_OK;
+ }
+
+ IFACEMETHODIMP GetFlags(_Out_ EXPCMDFLAGS* flags) {
+ *flags = ECF_DEFAULT;
+ return S_OK;
+ }
+
+ IFACEMETHODIMP EnumSubCommands(_Outptr_ IEnumExplorerCommand** enumCommands) {
+ *enumCommands = nullptr;
+ return E_NOTIMPL;
+ }
+
+ IFACEMETHODIMP Invoke(_In_opt_ IShellItemArray* items, _In_opt_ IBindCtx* bindCtx) {
+ // Process items passed by File Explorer when context menu entry is invoked
+ UNREFERENCED_PARAMETER(bindCtx);
+ if (items) {
+ // Return if no items
+ DWORD count;
+ RETURN_IF_FAILED(items->GetCount(&count));
+
+ // Get path to application exe
+ std::filesystem::path module_path{ wil::GetModuleFileNameW(wil::GetModuleInstanceHandle()) };
+ module_path = module_path.remove_filename();
+ module_path /= exe_filename;
+
+ // Prepare cmd line string to invoke application ("path\to\application.exe" "path\to\firstitem" "path\to\nextitem" ...)
+ auto command = wil::str_printf(LR"-("%s")-", module_path.c_str()); // Path to application.exe
+ // Add multiple selected files/folders to cmd line as parameters
+ for (DWORD i = 0; i < count; ++i) {
+ ComPtr item;
+ auto result = items->GetItemAt(i, &item);
+ if (SUCCEEDED(result)) {
+ wil::unique_cotaskmem_string path;
+ result = item->GetDisplayName(SIGDN_FILESYSPATH, &path);
+ if (SUCCEEDED(result)) {
+ // Append the item path to the existing command, adding quotes and escapes as needed
+ command = wil::str_printf(LR"-(%s %s)-", command.c_str(), QuoteForCommandLineArg(path.get()).c_str());
+ }
+ }
+ }
+
+ // Invoke application using CreateProcess with the command string prepared above
+ wil::unique_process_information process_info;
+ STARTUPINFOW startup_info = { sizeof(startup_info) };
+ RETURN_IF_WIN32_BOOL_FALSE(CreateProcessW(
+ nullptr,
+ command.data(),
+ nullptr /* lpProcessAttributes */,
+ nullptr /* lpThreadAttributes */,
+ false /* bInheritHandles */,
+ CREATE_NO_WINDOW,
+ nullptr,
+ nullptr,
+ &startup_info,
+ &process_info));
+ }
+ return S_OK;
+ }
+};
+
+CoCreatableClass(ExplorerCommandHandler)
+CoCreatableClassWrlCreatorMapInclude(ExplorerCommandHandler)
+
+_Check_return_
+STDAPI DllGetClassObject(_In_ REFCLSID rclsid, _In_ REFIID riid, _Outptr_ LPVOID* ppv) {
+ if (ppv == nullptr)
+ return E_POINTER;
+ *ppv = nullptr;
+ return Module::GetModule().GetClassObject(rclsid, riid, ppv);
+}
+
+__control_entrypoint(DllExport)
+STDAPI DllCanUnloadNow(void) {
+ return Module::GetModule().GetObjectCount() == 0 ? S_OK : S_FALSE;
+}
+
+STDAPI DllGetActivationFactory(_In_ HSTRING activatableClassId, _Out_ IActivationFactory** factory) {
+ return Module::GetModule().GetActivationFactory(activatableClassId, factory);
+}
\ No newline at end of file
diff --git a/Source/WindowsShellExtension/framework.h b/Source/WindowsShellExtension/framework.h
new file mode 100644
index 000000000..54b83e94f
--- /dev/null
+++ b/Source/WindowsShellExtension/framework.h
@@ -0,0 +1,5 @@
+#pragma once
+
+#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
+// Windows Header Files
+#include
diff --git a/Source/WindowsShellExtension/pch.cpp b/Source/WindowsShellExtension/pch.cpp
new file mode 100644
index 000000000..64b7eef6d
--- /dev/null
+++ b/Source/WindowsShellExtension/pch.cpp
@@ -0,0 +1,5 @@
+// pch.cpp: source file corresponding to the pre-compiled header
+
+#include "pch.h"
+
+// When you are using pre-compiled headers, this source file is necessary for compilation to succeed.
diff --git a/Source/WindowsShellExtension/pch.h b/Source/WindowsShellExtension/pch.h
new file mode 100644
index 000000000..226d865d6
--- /dev/null
+++ b/Source/WindowsShellExtension/pch.h
@@ -0,0 +1,30 @@
+// pch.h: This is a precompiled header file.
+// Files listed below are compiled only once, improving build performance for future builds.
+// This also affects IntelliSense performance, including code completion and many code browsing features.
+// However, files listed here are ALL re-compiled if any one of them is updated between builds.
+// Do not add files here that you will be updating frequently as this negates the performance advantage.
+
+#ifndef PCH_H
+#define PCH_H
+
+// add headers that you want to pre-compile here
+#include "framework.h"
+
+#include
+#include
+
+#include
+#include
+#pragma comment(lib, "shlwapi.lib")
+
+// Windows Runtime C++ Template Library (WRL)
+#include
+#include
+#include
+#pragma comment(lib, "runtimeobject.lib")
+
+// Windows Implementation Libraries (WIL)
+#include
+#include
+
+#endif //PCH_H
diff --git a/Source/WindowsShellExtension/source.def b/Source/WindowsShellExtension/source.def
new file mode 100644
index 000000000..57fb7042e
--- /dev/null
+++ b/Source/WindowsShellExtension/source.def
@@ -0,0 +1,8 @@
+; Declares the module parameters.
+
+LIBRARY
+
+EXPORTS
+ DllGetClassObject PRIVATE
+ DllCanUnloadNow PRIVATE
+ DllGetActivationFactory PRIVATE
\ No newline at end of file
From c13776d48983b39506f0d1ae2ee7d3d3dcef5bb2 Mon Sep 17 00:00:00 2001
From: cjee21 <77721854+cjee21@users.noreply.github.com>
Date: Thu, 28 Nov 2024 22:26:23 +0800
Subject: [PATCH 2/9] Rewrite shell extension in C++/WinRT
---
.../MediaInfo_WindowsShellExtension.vcxproj | 4 +
.../packages.config | 1 +
Source/WindowsShellExtension/dllmain.cpp | 133 ++++++++++--------
Source/WindowsShellExtension/pch.h | 7 +-
Source/WindowsShellExtension/source.def | 1 -
5 files changed, 84 insertions(+), 62 deletions(-)
diff --git a/Project/MSVC2022/MediaInfo_WindowsShellExtension/MediaInfo_WindowsShellExtension.vcxproj b/Project/MSVC2022/MediaInfo_WindowsShellExtension/MediaInfo_WindowsShellExtension.vcxproj
index 407d0cb16..f59ca09fb 100644
--- a/Project/MSVC2022/MediaInfo_WindowsShellExtension/MediaInfo_WindowsShellExtension.vcxproj
+++ b/Project/MSVC2022/MediaInfo_WindowsShellExtension/MediaInfo_WindowsShellExtension.vcxproj
@@ -1,5 +1,6 @@
+
Debug
@@ -196,12 +197,15 @@
+
This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
+
+
\ No newline at end of file
diff --git a/Project/MSVC2022/MediaInfo_WindowsShellExtension/packages.config b/Project/MSVC2022/MediaInfo_WindowsShellExtension/packages.config
index 04b661f41..2ddc908f4 100644
--- a/Project/MSVC2022/MediaInfo_WindowsShellExtension/packages.config
+++ b/Project/MSVC2022/MediaInfo_WindowsShellExtension/packages.config
@@ -1,4 +1,5 @@
+
\ No newline at end of file
diff --git a/Source/WindowsShellExtension/dllmain.cpp b/Source/WindowsShellExtension/dllmain.cpp
index ed56df1a1..ff148e99d 100644
--- a/Source/WindowsShellExtension/dllmain.cpp
+++ b/Source/WindowsShellExtension/dllmain.cpp
@@ -10,16 +10,6 @@
#include "pch.h"
-#pragma warning(disable : 4324)
-
-using Microsoft::WRL::ClassicCom;
-using Microsoft::WRL::ComPtr;
-using Microsoft::WRL::InhibitRoOriginateError;
-using Microsoft::WRL::Module;
-using Microsoft::WRL::ModuleType;
-using Microsoft::WRL::RuntimeClass;
-using Microsoft::WRL::RuntimeClassFlags;
-
constexpr const wchar_t* menu_entry_title = L"MediaInfo";
constexpr const wchar_t* exe_filename = L"MediaInfo.exe";
@@ -86,7 +76,7 @@ namespace {
}
-class __declspec(uuid("20669675-b281-4c4f-94fb-cb6fd3995545")) ExplorerCommandHandler final : public RuntimeClass, IExplorerCommand> {
+struct ExplorerCommandHandler : public winrt::implements {
public:
// IExplorerCommand implementation:
@@ -137,67 +127,98 @@ class __declspec(uuid("20669675-b281-4c4f-94fb-cb6fd3995545")) ExplorerCommandHa
IFACEMETHODIMP Invoke(_In_opt_ IShellItemArray* items, _In_opt_ IBindCtx* bindCtx) {
// Process items passed by File Explorer when context menu entry is invoked
UNREFERENCED_PARAMETER(bindCtx);
- if (items) {
- // Return if no items
- DWORD count;
- RETURN_IF_FAILED(items->GetCount(&count));
-
- // Get path to application exe
- std::filesystem::path module_path{ wil::GetModuleFileNameW(wil::GetModuleInstanceHandle()) };
- module_path = module_path.remove_filename();
- module_path /= exe_filename;
-
- // Prepare cmd line string to invoke application ("path\to\application.exe" "path\to\firstitem" "path\to\nextitem" ...)
- auto command = wil::str_printf(LR"-("%s")-", module_path.c_str()); // Path to application.exe
- // Add multiple selected files/folders to cmd line as parameters
- for (DWORD i = 0; i < count; ++i) {
- ComPtr item;
- auto result = items->GetItemAt(i, &item);
+
+ // Return if no items
+ if (!items)
+ return S_OK;
+
+ // Get count
+ DWORD count;
+ RETURN_IF_FAILED(items->GetCount(&count));
+
+ // Get path to application exe
+ std::filesystem::path module_path{ wil::GetModuleFileNameW(wil::GetModuleInstanceHandle()) };
+ module_path = module_path.remove_filename();
+ module_path /= exe_filename;
+
+ // Prepare cmd line string to invoke application ("path\to\application.exe" "path\to\firstitem" "path\to\nextitem" ...)
+ auto command = wil::str_printf(LR"-("%s")-", module_path.c_str()); // Path to application.exe
+ // Add multiple selected files/folders to cmd line as parameters
+ for (DWORD i = 0; i < count; ++i) {
+ winrt::com_ptr item;
+ auto result = items->GetItemAt(i, item.put());
+ if (SUCCEEDED(result)) {
+ wil::unique_cotaskmem_string path;
+ result = item->GetDisplayName(SIGDN_FILESYSPATH, &path);
if (SUCCEEDED(result)) {
- wil::unique_cotaskmem_string path;
- result = item->GetDisplayName(SIGDN_FILESYSPATH, &path);
- if (SUCCEEDED(result)) {
- // Append the item path to the existing command, adding quotes and escapes as needed
- command = wil::str_printf(LR"-(%s %s)-", command.c_str(), QuoteForCommandLineArg(path.get()).c_str());
- }
+ // Append the item path to the existing command, adding quotes and escapes as needed
+ command = wil::str_printf(LR"-(%s %s)-", command.c_str(), QuoteForCommandLineArg(path.get()).c_str());
}
}
-
- // Invoke application using CreateProcess with the command string prepared above
- wil::unique_process_information process_info;
- STARTUPINFOW startup_info = { sizeof(startup_info) };
- RETURN_IF_WIN32_BOOL_FALSE(CreateProcessW(
- nullptr,
- command.data(),
- nullptr /* lpProcessAttributes */,
- nullptr /* lpThreadAttributes */,
- false /* bInheritHandles */,
- CREATE_NO_WINDOW,
- nullptr,
- nullptr,
- &startup_info,
- &process_info));
}
+
+ // Invoke application using CreateProcess with the command string prepared above
+ wil::unique_process_information process_info;
+ STARTUPINFOW startup_info = { sizeof(startup_info) };
+ RETURN_IF_WIN32_BOOL_FALSE(CreateProcessW(
+ nullptr,
+ command.data(),
+ nullptr /* lpProcessAttributes */,
+ nullptr /* lpThreadAttributes */,
+ false /* bInheritHandles */,
+ CREATE_NO_WINDOW,
+ nullptr,
+ nullptr,
+ &startup_info,
+ &process_info));
+
return S_OK;
}
};
-CoCreatableClass(ExplorerCommandHandler)
-CoCreatableClassWrlCreatorMapInclude(ExplorerCommandHandler)
+struct DECLSPEC_UUID("20669675-b281-4c4f-94fb-cb6fd3995545") ClassFactory : public winrt::implements {
+public:
+
+ IFACEMETHODIMP CreateInstance(_In_opt_ IUnknown * pUnkOuter, _In_ REFIID riid, _COM_Outptr_ void** ppvObject) noexcept override {
+ UNREFERENCED_PARAMETER(pUnkOuter);
+ try {
+ return winrt::make()->QueryInterface(riid, ppvObject);
+ }
+ catch (...) {
+ return winrt::to_hresult();
+ }
+ }
+
+ IFACEMETHODIMP LockServer(_In_ BOOL fLock) noexcept override {
+ if (fLock)
+ ++winrt::get_module_lock();
+ else
+ --winrt::get_module_lock();
+ return S_OK;
+ }
+};
_Check_return_
STDAPI DllGetClassObject(_In_ REFCLSID rclsid, _In_ REFIID riid, _Outptr_ LPVOID* ppv) {
if (ppv == nullptr)
return E_POINTER;
*ppv = nullptr;
- return Module::GetModule().GetClassObject(rclsid, riid, ppv);
+ if (riid != IID_IClassFactory && riid != IID_IUnknown)
+ return E_NOINTERFACE;
+ if (rclsid != __uuidof(ClassFactory))
+ return E_INVALIDARG;
+ try {
+ return winrt::make()->QueryInterface(riid, ppv);
+ }
+ catch (...) {
+ return winrt::to_hresult();
+ }
}
__control_entrypoint(DllExport)
STDAPI DllCanUnloadNow(void) {
- return Module::GetModule().GetObjectCount() == 0 ? S_OK : S_FALSE;
-}
-
-STDAPI DllGetActivationFactory(_In_ HSTRING activatableClassId, _Out_ IActivationFactory** factory) {
- return Module::GetModule().GetActivationFactory(activatableClassId, factory);
+ if (winrt::get_module_lock())
+ return S_FALSE;
+ winrt::clear_factory_cache();
+ return S_OK;
}
\ No newline at end of file
diff --git a/Source/WindowsShellExtension/pch.h b/Source/WindowsShellExtension/pch.h
index 226d865d6..17677c3d0 100644
--- a/Source/WindowsShellExtension/pch.h
+++ b/Source/WindowsShellExtension/pch.h
@@ -17,11 +17,8 @@
#include
#pragma comment(lib, "shlwapi.lib")
-// Windows Runtime C++ Template Library (WRL)
-#include
-#include
-#include
-#pragma comment(lib, "runtimeobject.lib")
+// C++/WinRT
+#include
// Windows Implementation Libraries (WIL)
#include
diff --git a/Source/WindowsShellExtension/source.def b/Source/WindowsShellExtension/source.def
index 57fb7042e..e36932d40 100644
--- a/Source/WindowsShellExtension/source.def
+++ b/Source/WindowsShellExtension/source.def
@@ -5,4 +5,3 @@ LIBRARY
EXPORTS
DllGetClassObject PRIVATE
DllCanUnloadNow PRIVATE
- DllGetActivationFactory PRIVATE
\ No newline at end of file
From d48812ad14a9f165633a53d20def3715aba7ef24 Mon Sep 17 00:00:00 2001
From: cjee21 <77721854+cjee21@users.noreply.github.com>
Date: Thu, 28 Nov 2024 22:26:25 +0800
Subject: [PATCH 3/9] Enable hiding context menu entry of shell extension
---
Source/WindowsShellExtension/dllmain.cpp | 30 ++++++++++++++++++++++++
1 file changed, 30 insertions(+)
diff --git a/Source/WindowsShellExtension/dllmain.cpp b/Source/WindowsShellExtension/dllmain.cpp
index ff148e99d..3ebc7dae2 100644
--- a/Source/WindowsShellExtension/dllmain.cpp
+++ b/Source/WindowsShellExtension/dllmain.cpp
@@ -74,6 +74,24 @@ namespace {
return out;
}
+ // Extracted from
+ // https://learn.microsoft.com/en-us/archive/msdn-magazine/2017/may/c-use-modern-c-to-access-the-windows-registry#reading-a-dword-value-from-the-registry
+ DWORD RegGetDword(HKEY hKey, const std::wstring& subKey, const std::wstring& value) {
+ DWORD data{};
+ DWORD dataSize = sizeof(data);
+ LONG retCode = RegGetValue(
+ hKey,
+ subKey.c_str(),
+ value.c_str(),
+ RRF_RT_REG_DWORD,
+ nullptr,
+ &data,
+ &dataSize
+ );
+ if (retCode != ERROR_SUCCESS)
+ throw std::runtime_error("Cannot read DWORD from registry.");
+ return data;
+ }
}
struct ExplorerCommandHandler : public winrt::implements {
@@ -108,8 +126,20 @@ struct ExplorerCommandHandler : public winrt::implements
Date: Thu, 28 Nov 2024 22:26:26 +0800
Subject: [PATCH 4/9] Add Qt GUI support for Windows shell extension
---
.../MediaInfo_WindowsShellExtension.vcxproj | 93 +++++++++++++++++++
Source/WindowsShellExtension/dllmain.cpp | 53 ++++++++++-
2 files changed, 144 insertions(+), 2 deletions(-)
diff --git a/Project/MSVC2022/MediaInfo_WindowsShellExtension/MediaInfo_WindowsShellExtension.vcxproj b/Project/MSVC2022/MediaInfo_WindowsShellExtension/MediaInfo_WindowsShellExtension.vcxproj
index f59ca09fb..d78d4c302 100644
--- a/Project/MSVC2022/MediaInfo_WindowsShellExtension/MediaInfo_WindowsShellExtension.vcxproj
+++ b/Project/MSVC2022/MediaInfo_WindowsShellExtension/MediaInfo_WindowsShellExtension.vcxproj
@@ -10,6 +10,14 @@
Debug
x64
+
+ Release Qt
+ Win32
+
+
+ Release Qt
+ x64
+
Release
Win32
@@ -46,6 +54,14 @@
true
Unicode
+
+ DynamicLibrary
+ false
+ v143
+ true
+ Unicode
+ Spectre
+
DynamicLibrary
false
@@ -53,6 +69,14 @@
true
Unicode
+
+ DynamicLibrary
+ false
+ v143
+ true
+ Unicode
+ Spectre
+
@@ -67,9 +91,15 @@
+
+
+
+
+
+
$(SolutionDir)$(Platform)\$(Configuration)\
@@ -81,12 +111,20 @@
$(Platform)\$(Configuration)\
true
+
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ $(Platform)\$(Configuration)\
+ true
+
true
true
+
+ true
+
Level4
@@ -148,6 +186,33 @@
/defaultlib:ucrt.lib /PDBALTPATH:%_PDB% %(AdditionalOptions)
+
+
+ Level4
+ true
+ true
+ true
+ NDEBUG;MEDIAINFOCONTEXTMENU_EXPORTS;_WINDOWS;_USRDLL;MEDIAINFO_QT;%(PreprocessorDefinitions)
+ true
+ Use
+ pch.h
+ stdcpp20
+ Guard
+ MultiThreaded
+ true
+
+
+ Windows
+ true
+ true
+ true
+ false
+ $(ProjectDir)..\..\..\Source\WindowsShellExtension\source.def
+ true
+ libucrt.lib;%(IgnoreSpecificDefaultLibraries)
+ /defaultlib:ucrt.lib /PDBALTPATH:%_PDB% %(AdditionalOptions)
+
+
Level4
@@ -174,6 +239,32 @@
/defaultlib:ucrt.lib /PDBALTPATH:%_PDB% %(AdditionalOptions)
+
+
+ Level4
+ true
+ true
+ true
+ NDEBUG;MEDIAINFOCONTEXTMENU_EXPORTS;_WINDOWS;_USRDLL;MEDIAINFO_QT;%(PreprocessorDefinitions)
+ true
+ Use
+ pch.h
+ stdcpp20
+ Guard
+ MultiThreaded
+
+
+ Windows
+ true
+ true
+ true
+ false
+ $(ProjectDir)..\..\..\Source\WindowsShellExtension\source.def
+ true
+ libucrt.lib;%(IgnoreSpecificDefaultLibraries)
+ /defaultlib:ucrt.lib /PDBALTPATH:%_PDB% %(AdditionalOptions)
+
+
@@ -185,7 +276,9 @@
Create
Create
Create
+ Create
Create
+ Create
diff --git a/Source/WindowsShellExtension/dllmain.cpp b/Source/WindowsShellExtension/dllmain.cpp
index 3ebc7dae2..02d212a2e 100644
--- a/Source/WindowsShellExtension/dllmain.cpp
+++ b/Source/WindowsShellExtension/dllmain.cpp
@@ -10,6 +10,12 @@
#include "pch.h"
+#ifdef MEDIAINFO_QT
+ #define SHELLEXT_GUID "dea3006d-451d-4f0f-a2b2-c3250cb255b4"
+#else
+ #define SHELLEXT_GUID "20669675-b281-4c4f-94fb-cb6fd3995545"
+#endif // MEDIAINFO_QT
+
constexpr const wchar_t* menu_entry_title = L"MediaInfo";
constexpr const wchar_t* exe_filename = L"MediaInfo.exe";
@@ -92,6 +98,44 @@ namespace {
throw std::runtime_error("Cannot read DWORD from registry.");
return data;
}
+
+ // Adapted from
+ // https://learn.microsoft.com/en-us/archive/msdn-magazine/2017/may/c-use-modern-c-to-access-the-windows-registry#reading-a-string-value-from-the-registry
+ bool RegGetBool(HKEY hKey, const std::wstring& subKey, const std::wstring& value) {
+ DWORD dataSize{};
+ LONG retCode = RegGetValue(
+ hKey,
+ subKey.c_str(),
+ value.c_str(),
+ RRF_RT_REG_SZ,
+ nullptr,
+ nullptr,
+ &dataSize
+ );
+ if (retCode != ERROR_SUCCESS)
+ throw std::runtime_error("Cannot read string from registry.");
+ std::wstring data;
+ data.resize(dataSize / sizeof(wchar_t));
+ retCode = ::RegGetValue(
+ hKey,
+ subKey.c_str(),
+ value.c_str(),
+ RRF_RT_REG_SZ,
+ nullptr,
+ &data[0],
+ &dataSize
+ );
+ if (retCode != ERROR_SUCCESS)
+ throw std::runtime_error("Cannot read string from registry.");
+ DWORD stringLengthInWchars = dataSize / sizeof(wchar_t);
+ --stringLengthInWchars; // Exclude the NUL written by the Win32 API
+ data.resize(stringLengthInWchars);
+ if (data.compare(L"true") == 0)
+ return true;
+ if (data.compare(L"false") == 0)
+ return false;
+ throw std::runtime_error("Not a boolean.");
+ }
}
struct ExplorerCommandHandler : public winrt::implements {
@@ -131,7 +175,12 @@ struct ExplorerCommandHandler : public winrt::implements {
+struct DECLSPEC_UUID(SHELLEXT_GUID) ClassFactory : public winrt::implements {
public:
IFACEMETHODIMP CreateInstance(_In_opt_ IUnknown * pUnkOuter, _In_ REFIID riid, _COM_Outptr_ void** ppvObject) noexcept override {
From e62c65f49fcb6340fb4de0c4d4a8621683457937 Mon Sep 17 00:00:00 2001
From: cjee21 <77721854+cjee21@users.noreply.github.com>
Date: Thu, 28 Nov 2024 22:26:28 +0800
Subject: [PATCH 5/9] Add Windows sparse package
---
.../MSIX/AppxManifest.xml | 516 ++++++++++++++++++
.../Assets/Square150x150Logo.scale-400.png | Bin 0 -> 8513 bytes
...re44x44Logo.altform-unplated_scale-400.png | Bin 0 -> 5578 bytes
.../Assets/Square44x44Logo.scale-400.png | Bin 0 -> 4417 bytes
.../Resources/priconfig.xml | 32 ++
.../Resources/resources.pri | Bin 0 -> 1392 bytes
6 files changed, 548 insertions(+)
create mode 100644 Source/WindowsSparsePackage/MSIX/AppxManifest.xml
create mode 100644 Source/WindowsSparsePackage/Resources/Assets/Square150x150Logo.scale-400.png
create mode 100644 Source/WindowsSparsePackage/Resources/Assets/Square44x44Logo.altform-unplated_scale-400.png
create mode 100644 Source/WindowsSparsePackage/Resources/Assets/Square44x44Logo.scale-400.png
create mode 100644 Source/WindowsSparsePackage/Resources/priconfig.xml
create mode 100644 Source/WindowsSparsePackage/Resources/resources.pri
diff --git a/Source/WindowsSparsePackage/MSIX/AppxManifest.xml b/Source/WindowsSparsePackage/MSIX/AppxManifest.xml
new file mode 100644
index 000000000..b184b3889
--- /dev/null
+++ b/Source/WindowsSparsePackage/MSIX/AppxManifest.xml
@@ -0,0 +1,516 @@
+
+
+
+
+ MediaInfo
+ MEDIAAREA.NET
+ Assets\Square150x150Logo.png
+ true
+ disabled
+ disabled
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Source/WindowsSparsePackage/Resources/Assets/Square150x150Logo.scale-400.png b/Source/WindowsSparsePackage/Resources/Assets/Square150x150Logo.scale-400.png
new file mode 100644
index 0000000000000000000000000000000000000000..448471af90f0e0c9957b937cfe1af291170a8ec2
GIT binary patch
literal 8513
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
literal 0
HcmV?d00001
diff --git a/Source/WindowsSparsePackage/Resources/Assets/Square44x44Logo.altform-unplated_scale-400.png b/Source/WindowsSparsePackage/Resources/Assets/Square44x44Logo.altform-unplated_scale-400.png
new file mode 100644
index 0000000000000000000000000000000000000000..65a249d859a473a7c5462d7690a12a276448674f
GIT binary patch
literal 5578
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
Y4}2h%W$)TiGXMYp07*qoM6N<$f(X2wC;$Ke
literal 0
HcmV?d00001
diff --git a/Source/WindowsSparsePackage/Resources/Assets/Square44x44Logo.scale-400.png b/Source/WindowsSparsePackage/Resources/Assets/Square44x44Logo.scale-400.png
new file mode 100644
index 0000000000000000000000000000000000000000..d49d916f12ca0412229ff68e4a41fe84e8060a06
GIT binary patch
literal 4417
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
literal 0
HcmV?d00001
diff --git a/Source/WindowsSparsePackage/Resources/priconfig.xml b/Source/WindowsSparsePackage/Resources/priconfig.xml
new file mode 100644
index 000000000..1ae8ea2d0
--- /dev/null
+++ b/Source/WindowsSparsePackage/Resources/priconfig.xml
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Source/WindowsSparsePackage/Resources/resources.pri b/Source/WindowsSparsePackage/Resources/resources.pri
new file mode 100644
index 0000000000000000000000000000000000000000..b57f8418651661b102d3c9fae432274399885b66
GIT binary patch
literal 1392
zcmaJ>-D(q25T0!F14WBa3SKUv=uPSxRw>>Uv?x>&TCY?#OZFsL$o@2&LLQ^->i?ZNjvtb1CKow0Gv8jLy#b-hR0d(
z`hG3nP?sZ-)$0ZUNbPoUgM177F8q+x3q4Wii-$+#qr8_7aw^AiF0bVk4P|!oXI9~|
z1$Saja%}(Tw}uK>2W33#h}pD${@0(bri|MM$Pze4rXLK`Ffj$X=t8da^~bNDrT;_<
zX-f!PbD7FZd5Y(q7$6Zt`c_iuO9q*2k#lnQ-hsC>IdIuEM_lmx?n9e3ZxM0r2KPGNi3;ML#3NJ4aZ#8_A!iqt;n+NT
z?oF{yvq5&4r-Oym_ou#J$<$TdtC#i*;v{%fhq>|^!
zym``|CvoCgF3u8pVo0K1d#;{qFyQ3!q?MlKJ8!Pd*Ou?9oG;okA8p8mgY`ea>#?GyYfk8wEz4ze
Date: Thu, 28 Nov 2024 22:26:29 +0800
Subject: [PATCH 6/9] Add Windows package helper for sparse package
---
Project/MSVC2022/MediaInfo.sln | 10 +
.../MediaInfo_PackageHelper.vcxproj | 209 ++++++++++++++++++
.../MediaInfo_PackageHelper.vcxproj.filters | 53 +++++
.../MediaInfo_PackageHelper/packages.config | 5 +
Source/WindowsPackageHelper/Installer.cpp | 135 +++++++++++
Source/WindowsPackageHelper/Installer.h | 14 ++
Source/WindowsPackageHelper/Resource.rc | 33 +++
Source/WindowsPackageHelper/dllmain.cpp | 27 +++
Source/WindowsPackageHelper/framework.h | 5 +
Source/WindowsPackageHelper/pch.cpp | 5 +
Source/WindowsPackageHelper/pch.h | 27 +++
11 files changed, 523 insertions(+)
create mode 100644 Project/MSVC2022/MediaInfo_PackageHelper/MediaInfo_PackageHelper.vcxproj
create mode 100644 Project/MSVC2022/MediaInfo_PackageHelper/MediaInfo_PackageHelper.vcxproj.filters
create mode 100644 Project/MSVC2022/MediaInfo_PackageHelper/packages.config
create mode 100644 Source/WindowsPackageHelper/Installer.cpp
create mode 100644 Source/WindowsPackageHelper/Installer.h
create mode 100644 Source/WindowsPackageHelper/Resource.rc
create mode 100644 Source/WindowsPackageHelper/dllmain.cpp
create mode 100644 Source/WindowsPackageHelper/framework.h
create mode 100644 Source/WindowsPackageHelper/pch.cpp
create mode 100644 Source/WindowsPackageHelper/pch.h
diff --git a/Project/MSVC2022/MediaInfo.sln b/Project/MSVC2022/MediaInfo.sln
index 35bdcb9cc..911076a8b 100644
--- a/Project/MSVC2022/MediaInfo.sln
+++ b/Project/MSVC2022/MediaInfo.sln
@@ -59,6 +59,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RegressionTest", "..\..\..\
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MediaInfo_WindowsShellExtension", "MediaInfo_WindowsShellExtension\MediaInfo_WindowsShellExtension.vcxproj", "{E22FF9ED-8EC0-44B6-B313-55FC21B75F38}"
EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MediaInfo_PackageHelper", "MediaInfo_PackageHelper\MediaInfo_PackageHelper.vcxproj", "{D1D1AA15-F074-42AB-B5F4-DE34F5833F01}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
@@ -171,6 +173,14 @@ Global
{E22FF9ED-8EC0-44B6-B313-55FC21B75F38}.Release|Win32.Build.0 = Release|Win32
{E22FF9ED-8EC0-44B6-B313-55FC21B75F38}.Release|x64.ActiveCfg = Release|x64
{E22FF9ED-8EC0-44B6-B313-55FC21B75F38}.Release|x64.Build.0 = Release|x64
+ {D1D1AA15-F074-42AB-B5F4-DE34F5833F01}.Debug|Win32.ActiveCfg = Debug|Win32
+ {D1D1AA15-F074-42AB-B5F4-DE34F5833F01}.Debug|Win32.Build.0 = Debug|Win32
+ {D1D1AA15-F074-42AB-B5F4-DE34F5833F01}.Debug|x64.ActiveCfg = Debug|x64
+ {D1D1AA15-F074-42AB-B5F4-DE34F5833F01}.Debug|x64.Build.0 = Debug|x64
+ {D1D1AA15-F074-42AB-B5F4-DE34F5833F01}.Release|Win32.ActiveCfg = Release|Win32
+ {D1D1AA15-F074-42AB-B5F4-DE34F5833F01}.Release|Win32.Build.0 = Release|Win32
+ {D1D1AA15-F074-42AB-B5F4-DE34F5833F01}.Release|x64.ActiveCfg = Release|x64
+ {D1D1AA15-F074-42AB-B5F4-DE34F5833F01}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/Project/MSVC2022/MediaInfo_PackageHelper/MediaInfo_PackageHelper.vcxproj b/Project/MSVC2022/MediaInfo_PackageHelper/MediaInfo_PackageHelper.vcxproj
new file mode 100644
index 000000000..a8d5a8f1e
--- /dev/null
+++ b/Project/MSVC2022/MediaInfo_PackageHelper/MediaInfo_PackageHelper.vcxproj
@@ -0,0 +1,209 @@
+
+
+
+
+
+ Debug
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ Win32
+
+
+ Release
+ x64
+
+
+
+ 17.0
+ Win32Proj
+ {d1d1aa15-f074-42ab-b5f4-de34f5833f01}
+ MediaInfoPackageHelper
+ 10.0
+ MediaInfo_PackageHelper
+
+
+
+ DynamicLibrary
+ true
+ v143
+ Unicode
+
+
+ DynamicLibrary
+ true
+ v143
+ Unicode
+
+
+ DynamicLibrary
+ false
+ v143
+ true
+ Unicode
+
+
+ DynamicLibrary
+ false
+ v143
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ $(Platform)\$(Configuration)\
+ true
+
+
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ $(Platform)\$(Configuration)\
+ true
+
+
+ true
+
+
+ true
+
+
+
+ Level4
+ true
+ _DEBUG;MEDIAINFOPACKAGEHELPER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ true
+ Use
+ pch.h
+ stdcpp20
+
+
+ Windows
+ true
+ false
+
+
+
+
+ Level4
+ true
+ _DEBUG;MEDIAINFOPACKAGEHELPER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ true
+ Use
+ pch.h
+ stdcpp20
+
+
+ Windows
+ true
+ false
+
+
+
+
+ Level4
+ true
+ true
+ true
+ NDEBUG;MEDIAINFOPACKAGEHELPER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ true
+ Use
+ pch.h
+ stdcpp20
+ MultiThreaded
+ Guard
+ true
+
+
+ Windows
+ true
+ true
+ true
+ false
+ true
+ /defaultlib:ucrt.lib /PDBALTPATH:%_PDB% %(AdditionalOptions)
+ libucrt.lib;%(IgnoreSpecificDefaultLibraries)
+
+
+
+
+ Level4
+ true
+ true
+ true
+ NDEBUG;MEDIAINFOPACKAGEHELPER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ true
+ Use
+ pch.h
+ stdcpp20
+ MultiThreaded
+ Guard
+
+
+ Windows
+ true
+ true
+ true
+ false
+ true
+ /defaultlib:ucrt.lib /PDBALTPATH:%_PDB% %(AdditionalOptions)
+ libucrt.lib;%(IgnoreSpecificDefaultLibraries)
+
+
+
+
+
+
+
+
+
+
+
+
+ Create
+ Create
+ Create
+ Create
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Project/MSVC2022/MediaInfo_PackageHelper/MediaInfo_PackageHelper.vcxproj.filters b/Project/MSVC2022/MediaInfo_PackageHelper/MediaInfo_PackageHelper.vcxproj.filters
new file mode 100644
index 000000000..bca050230
--- /dev/null
+++ b/Project/MSVC2022/MediaInfo_PackageHelper/MediaInfo_PackageHelper.vcxproj.filters
@@ -0,0 +1,53 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+
+
+ Resource Files
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Project/MSVC2022/MediaInfo_PackageHelper/packages.config b/Project/MSVC2022/MediaInfo_PackageHelper/packages.config
new file mode 100644
index 000000000..2ddc908f4
--- /dev/null
+++ b/Project/MSVC2022/MediaInfo_PackageHelper/packages.config
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/Source/WindowsPackageHelper/Installer.cpp b/Source/WindowsPackageHelper/Installer.cpp
new file mode 100644
index 000000000..af79763f0
--- /dev/null
+++ b/Source/WindowsPackageHelper/Installer.cpp
@@ -0,0 +1,135 @@
+/* Copyright (c) MediaArea.net SARL. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license that can
+ * be found in the License.html file in the root of the source tree.
+ */
+
+// Functions for registration and removal of MediaInfo sparse package
+
+#include "pch.h"
+#include "Installer.h"
+
+using namespace winrt::Windows::ApplicationModel;
+using namespace winrt::Windows::Foundation;
+using namespace winrt::Windows::Foundation::Collections;
+using namespace winrt::Windows::Management::Deployment;
+
+using namespace MediaInfo_SparsePackage::Installer;
+
+const std::wstring SparsePackageName = L"MediaInfo";
+const std::wstring SparsePackageFileName = L"MediaInfo_SparsePackage.msix";
+
+static const std::wstring GetInstallationPath() {
+ std::filesystem::path module_path{ wil::GetModuleFileNameW(wil::GetModuleInstanceHandle()) };
+ return module_path.remove_filename().wstring();
+}
+
+static Package GetSparsePackage()
+{
+ PackageManager packageManager;
+ IIterable packages;
+
+ try {
+ packages = packageManager.FindPackages();
+ }
+ catch (winrt::hresult_error) {
+ return NULL;
+ }
+
+ for (const Package& package : packages) {
+ if (package.Id().Name() != SparsePackageName)
+ continue;
+
+ return package;
+ }
+
+ return NULL;
+}
+
+static HRESULT RegisterSparsePackage()
+{
+ // Cannot handle sparse packages in safe-mode
+ if (GetSystemMetrics(SM_CLEANBOOT) > 0)
+ return S_FALSE;
+
+ PackageManager packageManager;
+ StagePackageOptions options;
+
+ const std::wstring externalLocation = GetInstallationPath();
+ const std::wstring sparsePkgPath = externalLocation + L"\\" + SparsePackageFileName;
+
+ Uri externalUri(externalLocation);
+ Uri packageUri(sparsePkgPath);
+
+ options.ExternalLocationUri(externalUri);
+
+ auto deploymentOperation = packageManager.StagePackageByUriAsync(packageUri, options);
+ auto deployResult = deploymentOperation.get();
+
+ if (FAILED(deployResult.ExtendedErrorCode()))
+ return deployResult.ExtendedErrorCode();
+
+ Package package = GetSparsePackage();
+ if (package == NULL)
+ return S_FALSE;
+
+ winrt::hstring familyName = package.Id().FamilyName();
+ deploymentOperation = packageManager.ProvisionPackageForAllUsersAsync(familyName);
+ deployResult = deploymentOperation.get();
+
+ if (FAILED(deployResult.ExtendedErrorCode()))
+ return deployResult.ExtendedErrorCode();
+
+ return S_OK;
+}
+
+
+static HRESULT UnregisterSparsePackage()
+{
+ // Cannot handle sparse packages in safe-mode
+ if (GetSystemMetrics(SM_CLEANBOOT) > 0)
+ return S_FALSE;
+
+ const Package package = GetSparsePackage();
+ if (package == NULL)
+ return S_FALSE;
+
+ PackageManager packageManager;
+ winrt::hstring fullName = package.Id().FullName();
+ auto deploymentOperation = packageManager.RemovePackageAsync(fullName, RemovalOptions::RemoveForAllUsers);
+ auto deployResult = deploymentOperation.get();
+
+ if (FAILED(deployResult.ExtendedErrorCode()))
+ return deployResult.ExtendedErrorCode();
+
+ return S_OK;
+}
+
+STDAPI MediaInfo_SparsePackage::Installer::Install()
+{
+ HRESULT result;
+
+ // remove any old existing versions first
+ result = UnregisterSparsePackage();
+ if (FAILED(result))
+ return result;
+
+ result = RegisterSparsePackage();
+ if (FAILED(result))
+ return result;
+
+ SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL);
+
+ return S_OK;
+}
+
+STDAPI MediaInfo_SparsePackage::Installer::Uninstall()
+{
+ HRESULT result = UnregisterSparsePackage();
+ if (FAILED(result))
+ return result;
+
+ SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL);
+
+ return S_OK;
+}
\ No newline at end of file
diff --git a/Source/WindowsPackageHelper/Installer.h b/Source/WindowsPackageHelper/Installer.h
new file mode 100644
index 000000000..ac0e706de
--- /dev/null
+++ b/Source/WindowsPackageHelper/Installer.h
@@ -0,0 +1,14 @@
+/* Copyright (c) MediaArea.net SARL. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license that can
+ * be found in the License.html file in the root of the source tree.
+ */
+
+#pragma once
+#include "pch.h"
+
+namespace MediaInfo_SparsePackage::Installer
+{
+ extern "C" __declspec(dllexport) HRESULT __stdcall Install();
+ extern "C" __declspec(dllexport) HRESULT __stdcall Uninstall();
+}
\ No newline at end of file
diff --git a/Source/WindowsPackageHelper/Resource.rc b/Source/WindowsPackageHelper/Resource.rc
new file mode 100644
index 000000000..8fd5b38b0
--- /dev/null
+++ b/Source/WindowsPackageHelper/Resource.rc
@@ -0,0 +1,33 @@
+#include
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 24,11,0,0
+ PRODUCTVERSION 24,11,0,0
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x40004L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0" // U.S. English (0x0409, 1033), Unicode (0x04B0, 1200)
+ BEGIN
+ VALUE "CompanyName", "MediaArea.net"
+ VALUE "FileDescription", "MediaInfo package helper for handling sparse package"
+ VALUE "FileVersion", "24.11.0.0"
+ VALUE "LegalCopyright", "Copyright (C) 2002-2024 MediaArea.net SARL"
+ VALUE "OriginalFilename", "MediaInfo_PackageHelper.dll"
+ VALUE "ProductName", "MediaInfo"
+ VALUE "ProductVersion", "24.11.0.0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
diff --git a/Source/WindowsPackageHelper/dllmain.cpp b/Source/WindowsPackageHelper/dllmain.cpp
new file mode 100644
index 000000000..ba6d3efbb
--- /dev/null
+++ b/Source/WindowsPackageHelper/dllmain.cpp
@@ -0,0 +1,27 @@
+/* Copyright (c) MediaArea.net SARL. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license that can
+ * be found in the License.html file in the root of the source tree.
+ */
+
+// dllmain.cpp : Defines the entry point for the DLL application.
+#include "pch.h"
+
+BOOL APIENTRY DllMain( HMODULE hModule,
+ DWORD ul_reason_for_call,
+ LPVOID lpReserved
+ )
+{
+ UNREFERENCED_PARAMETER(hModule);
+ UNREFERENCED_PARAMETER(lpReserved);
+ switch (ul_reason_for_call)
+ {
+ case DLL_PROCESS_ATTACH:
+ case DLL_THREAD_ATTACH:
+ case DLL_THREAD_DETACH:
+ case DLL_PROCESS_DETACH:
+ break;
+ }
+ return TRUE;
+}
+
diff --git a/Source/WindowsPackageHelper/framework.h b/Source/WindowsPackageHelper/framework.h
new file mode 100644
index 000000000..54b83e94f
--- /dev/null
+++ b/Source/WindowsPackageHelper/framework.h
@@ -0,0 +1,5 @@
+#pragma once
+
+#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
+// Windows Header Files
+#include
diff --git a/Source/WindowsPackageHelper/pch.cpp b/Source/WindowsPackageHelper/pch.cpp
new file mode 100644
index 000000000..64b7eef6d
--- /dev/null
+++ b/Source/WindowsPackageHelper/pch.cpp
@@ -0,0 +1,5 @@
+// pch.cpp: source file corresponding to the pre-compiled header
+
+#include "pch.h"
+
+// When you are using pre-compiled headers, this source file is necessary for compilation to succeed.
diff --git a/Source/WindowsPackageHelper/pch.h b/Source/WindowsPackageHelper/pch.h
new file mode 100644
index 000000000..8d5678664
--- /dev/null
+++ b/Source/WindowsPackageHelper/pch.h
@@ -0,0 +1,27 @@
+// pch.h: This is a precompiled header file.
+// Files listed below are compiled only once, improving build performance for future builds.
+// This also affects IntelliSense performance, including code completion and many code browsing features.
+// However, files listed here are ALL re-compiled if any one of them is updated between builds.
+// Do not add files here that you will be updating frequently as this negates the performance advantage.
+
+#ifndef PCH_H
+#define PCH_H
+
+// add headers that you want to pre-compile here
+#include "framework.h"
+
+#include
+#include
+
+#include
+
+// C++/WinRT
+#include
+#include
+#include
+
+// Windows Implementation Libraries (WIL)
+#include
+#include
+
+#endif //PCH_H
From 940de7205976932da7566542ad0d62d7b7f830f1 Mon Sep 17 00:00:00 2001
From: cjee21 <77721854+cjee21@users.noreply.github.com>
Date: Thu, 28 Nov 2024 22:26:31 +0800
Subject: [PATCH 7/9] Windows GUI: Update installer for Windows 11 Explorer
context menu
---
Source/Install/MediaInfo_GUI_Windows.nsi | 22 ++++++++++++++++++++
Source/Install/MediaInfo_GUI_Windows_x64.nsi | 22 ++++++++++++++++++++
2 files changed, 44 insertions(+)
diff --git a/Source/Install/MediaInfo_GUI_Windows.nsi b/Source/Install/MediaInfo_GUI_Windows.nsi
index 15cdfc880..2db8810b2 100644
--- a/Source/Install/MediaInfo_GUI_Windows.nsi
+++ b/Source/Install/MediaInfo_GUI_Windows.nsi
@@ -142,6 +142,14 @@ Section "SectionPrincipale" SEC01
File "..\..\..\MediaInfoLib\Project\MSVC2022\x64\Release\MediaInfo.dll"
File "C:\Program Files (x86)\Embarcadero\Studio\22.0\Redist\win64\WebView2Loader.dll"
File "$%BPATH%\Windows\libcurl\x64\Release\LIBCURL.DLL"
+ ${If} ${AtLeastWin11}
+ File "..\..\Project\MSVC2022\x64\Release\MediaInfo_SparsePackage.msix"
+ File "..\..\Project\MSVC2022\x64\Release\MediaInfo_WindowsShellExtension.dll"
+ File "..\..\Project\MSVC2022\win32\Release\MediaInfo_PackageHelper.dll"
+ File "..\WindowsSparsePackage\Resources\resources.pri"
+ SetOutPath "$INSTDIR\Assets"
+ File "..\WindowsSparsePackage\Resources\Assets\*.png"
+ ${EndIf}
${Else}
File "/oname=MediaInfo.exe" "..\..\Project\BCB\GUI\Win32\Release\MediaInfo_GUI.exe"
File "..\..\..\MediaInfoLib\Project\MSVC2022\Win32\Release\MediaInfo_InfoTip.dll"
@@ -191,6 +199,10 @@ Section -Post
ExecWait '"$SYSDIR\regsvr32.exe" "$INSTDIR\MediaInfo_InfoTip.dll" /s'
!insertmacro MediaInfo_Extensions_Install
+ ${If} ${AtLeastWin11}
+ System::Call '"$INSTDIR\MediaInfo_PackageHelper.dll"::_Install@0() ? u'
+ ${EndIf}
+
${If} ${AtLeastWin7}
${GetSize} "$INSTDIR" "/S=0K" $0 $1 $2
IntFmt $0 "0x%08X" $0 ; Convert the decimal KB value in $0 to DWORD, put it right back into $0
@@ -212,6 +224,16 @@ Section Uninstall
ExecWait '"$INSTDIR\ffmpeg_plugin_uninst.exe" /S _?=$INSTDIR'
Delete "$INSTDIR\ffmpeg_plugin_uninst.exe"
+ ${If} ${AtLeastWin11}
+ System::Call '"$INSTDIR\MediaInfo_PackageHelper.dll"::_Uninstall@0() ? u'
+ !insertmacro UnInstallLib DLL NOTSHARED REBOOT_NOTPROTECTED "$INSTDIR\MediaInfo_PackageHelper.dll"
+ !insertmacro UnInstallLib DLL NOTSHARED REBOOT_NOTPROTECTED "$INSTDIR\MediaInfo_WindowsShellExtension.dll"
+ Delete "$INSTDIR\MediaInfo_SparsePackage.msix"
+ Delete "$INSTDIR\resources.pri"
+ Delete "$INSTDIR\Assets\*.png"
+ RMDir "$INSTDIR\Assets"
+ ${EndIf}
+
!insertmacro UnInstallLib DLL NOTSHARED REBOOT_NOTPROTECTED "$INSTDIR\MediaInfo.exe"
!insertmacro UnInstallLib DLL NOTSHARED REBOOT_NOTPROTECTED "$INSTDIR\MediaInfo.dll"
!insertmacro UnInstallLib DLL NOTSHARED REBOOT_NOTPROTECTED "$INSTDIR\MediaInfo_i386.dll"
diff --git a/Source/Install/MediaInfo_GUI_Windows_x64.nsi b/Source/Install/MediaInfo_GUI_Windows_x64.nsi
index 64a523108..026c2ca6c 100644
--- a/Source/Install/MediaInfo_GUI_Windows_x64.nsi
+++ b/Source/Install/MediaInfo_GUI_Windows_x64.nsi
@@ -147,6 +147,14 @@ Section "SectionPrincipale" SEC01
File "/oname=History.txt" "..\..\History_GUI.txt"
File "..\..\License.html"
File "/oname=ReadMe.txt" "..\..\Release\ReadMe_GUI_Windows.txt"
+ ${If} ${AtLeastWin11}
+ File "..\..\Project\MSVC2022\x64\Release\MediaInfo_SparsePackage.msix"
+ File "..\..\Project\MSVC2022\x64\Release\MediaInfo_WindowsShellExtension.dll"
+ File "..\..\Project\MSVC2022\win32\Release\MediaInfo_PackageHelper.dll"
+ File "..\WindowsSparsePackage\Resources\resources.pri"
+ SetOutPath "$INSTDIR\Assets"
+ File "..\WindowsSparsePackage\Resources\Assets\*.png"
+ ${EndIf}
SetOverwrite try
SetOutPath "$INSTDIR\Plugin\Custom"
File "..\Resource\Plugin\Custom\*.csv"
@@ -186,6 +194,10 @@ Section -Post
ExecWait '"$SYSDIR\regsvr32.exe" "$INSTDIR\MediaInfo_InfoTip.dll" /s'
!insertmacro MediaInfo_Extensions_Install
+ ${If} ${AtLeastWin11}
+ System::Call '"$INSTDIR\MediaInfo_PackageHelper.dll"::_Install@0() ? u'
+ ${EndIf}
+
${If} ${AtLeastWin7}
${GetSize} "$INSTDIR" "/S=0K" $0 $1 $2
IntFmt $0 "0x%08X" $0 ; Convert the decimal KB value in $0 to DWORD, put it right back into $0
@@ -207,6 +219,16 @@ Section Uninstall
ExecWait '"$INSTDIR\ffmpeg_plugin_uninst.exe" /S _?=$INSTDIR'
Delete "$INSTDIR\ffmpeg_plugin_uninst.exe"
+ ${If} ${AtLeastWin11}
+ System::Call '"$INSTDIR\MediaInfo_PackageHelper.dll"::_Uninstall@0() ? u'
+ !insertmacro UnInstallLib DLL NOTSHARED REBOOT_NOTPROTECTED "$INSTDIR\MediaInfo_PackageHelper.dll"
+ !insertmacro UnInstallLib DLL NOTSHARED REBOOT_NOTPROTECTED "$INSTDIR\MediaInfo_WindowsShellExtension.dll"
+ Delete "$INSTDIR\MediaInfo_SparsePackage.msix"
+ Delete "$INSTDIR\resources.pri"
+ Delete "$INSTDIR\Assets\*.png"
+ RMDir "$INSTDIR\Assets"
+ ${EndIf}
+
!insertmacro UnInstallLib DLL NOTSHARED REBOOT_NOTPROTECTED "$INSTDIR\MediaInfo.exe"
!insertmacro UnInstallLib DLL NOTSHARED REBOOT_NOTPROTECTED "$INSTDIR\MediaInfo.dll"
!insertmacro UnInstallLib DLL NOTSHARED REBOOT_NOTPROTECTED "$INSTDIR\MediaInfo_i386.dll"
From 44461cd07c63718f51e2cf3138489b5f1f9e392d Mon Sep 17 00:00:00 2001
From: cjee21 <77721854+cjee21@users.noreply.github.com>
Date: Thu, 28 Nov 2024 22:26:33 +0800
Subject: [PATCH 8/9] Windows GUI: Support new shell extension
---
Source/Common/Preferences.cpp | 45 +++++++++++++++++++++++++++---
Source/GUI/VCL/GUI_Preferences.cpp | 11 ++++++++
2 files changed, 52 insertions(+), 4 deletions(-)
diff --git a/Source/Common/Preferences.cpp b/Source/Common/Preferences.cpp
index 20e8a78f6..c6ea139ac 100644
--- a/Source/Common/Preferences.cpp
+++ b/Source/Common/Preferences.cpp
@@ -812,6 +812,43 @@ int Preferences::ExplorerShell()
}
}
+ //Controls for legacy shell extension
+ int32s LegacyShellExtension = Config.Read(__T("ShellExtension")).To_int32s();
+ int32s LegacyShellExtension_Folder = Config.Read(__T("ShellExtension_Folder")).To_int32s();
+
+ //Control writing registry for modern IExplorerCommand-based shell extension
+ bool ModernShellExtensionUsed = false;
+
+ //Check presence of modern IExplorerCommand-based shell extension and handle things accordingly
+ TRegistry* ModernReg = new TRegistry;
+ ModernReg->RootKey = HKEY_CLASSES_ROOT;
+ try {
+ //If modern shell extension is installed
+ if (ModernReg->OpenKeyReadOnly(__T("PackagedCom\\ClassIndex\\{20669675-B281-4C4F-94FB-CB6FD3995545}"))) {
+ LegacyShellExtension = 0; //Disable legacy shell extension
+ LegacyShellExtension_Folder = 0; //Disable legacy shell extension
+ ModernShellExtensionUsed = true; //Need to control modern shell extension
+ Config(__T("ShellExtension_Folder")) = __T("1"); //Disabling ShellExtension_Folder not implemented
+ ModernReg->CloseKey();
+ }
+ } catch (...) {}
+ delete ModernReg;
+
+ //Control modern IExplorerCommand-based shell extension
+ if (ModernShellExtensionUsed) {
+ TRegistry* ModernShellExtension = new TRegistry(KEY_WRITE);
+ try {
+ if (ModernShellExtension->OpenKey(__T("Software\\MediaArea\\MediaInfo"), true)) {
+ if (Config.Read(__T("ShellExtension")).To_int32s())
+ ModernShellExtension->DeleteValue("ShellExtension");
+ else
+ ModernShellExtension->WriteInteger("ShellExtension", 0);
+ ModernShellExtension->CloseKey();
+ }
+ } catch (...) {}
+ delete ModernShellExtension;
+ }
+
bool IsChanged=false;
if ( MajorVersion>=6 //Windows Vista or more
|| (MajorVersion==5 && MinorVersion>=1)) //WinXP or more in 5.x family
@@ -873,22 +910,22 @@ int Preferences::ExplorerShell()
ExplorerShell_Edit("Software\\Classes\\SystemFileAssociations\\video", 0, IsChanged);
//Adding/removing to SystemFileAssociations
- int32s ShellExtension=Config.Read(__T("ShellExtension")).To_int32s();
+ int32s ShellExtension=LegacyShellExtension;
for (size_t I1=0; I1OpenKey(List(I1, 0).c_str(), ShellExtension))
diff --git a/Source/GUI/VCL/GUI_Preferences.cpp b/Source/GUI/VCL/GUI_Preferences.cpp
index a2c2cdbca..e7b6abd4c 100644
--- a/Source/GUI/VCL/GUI_Preferences.cpp
+++ b/Source/GUI/VCL/GUI_Preferences.cpp
@@ -640,6 +640,17 @@ void __fastcall TPreferencesF::Setup_GeneralShow(TObject *Sender)
CB_InscrireShell->Checked=Prefs->Config(__T("ShellExtension")).To_int32s(); //Lecture Shell extension
CB_InscrireShell_Folder->Checked=Prefs->Config(__T("ShellExtension_Folder")).To_int32s(); //Lecture Shell extension
CB_InfoTip->Checked=Prefs->Config(__T("ShellInfoTip")).To_int32s(); //Lecture Shell extension
+
+ //Disable InscrireShell_Folder setting if modern IExplorerCommand-based shell extension is installed (not implemented)
+ TRegistry* ModernReg=new TRegistry;
+ ModernReg->RootKey = HKEY_CLASSES_ROOT;
+ try {
+ if (ModernReg->OpenKeyReadOnly(__T("PackagedCom\\ClassIndex\\{20669675-B281-4C4F-94FB-CB6FD3995545}"))) {
+ CB_InscrireShell_Folder->Enabled = false;
+ ModernReg->CloseKey();
+ }
+ } catch (...) {}
+ delete ModernReg;
}
//---------------------------------------------------------------------------
From cbc3df38d8b6a856f0c09027da5d89780d4e0d24 Mon Sep 17 00:00:00 2001
From: cjee21 <77721854+cjee21@users.noreply.github.com>
Date: Thu, 28 Nov 2024 22:26:34 +0800
Subject: [PATCH 9/9] Windows GUI: Enable controlling shell extension for
folders
---
Source/Common/Preferences.cpp | 7 +++--
Source/GUI/VCL/GUI_Preferences.cpp | 11 --------
Source/WindowsShellExtension/dllmain.cpp | 35 ++++++++++++++++++++++--
3 files changed, 38 insertions(+), 15 deletions(-)
diff --git a/Source/Common/Preferences.cpp b/Source/Common/Preferences.cpp
index c6ea139ac..5759da3e0 100644
--- a/Source/Common/Preferences.cpp
+++ b/Source/Common/Preferences.cpp
@@ -253,7 +253,7 @@ int Preferences::Config_Save()
if (Config(__T("Custom")).empty()) Config(__T("Custom"))=__T("Example");
if (Config(__T("CheckUpdate")).empty()) Config(__T("CheckUpdate"))=__T("1");
if (Config(__T("ShellExtension")).empty()) Config(__T("ShellExtension"))=__T("1");
- if (Config(__T("ShellExtension_Folder")).empty()) Config(__T("ShellExtension_Folder"))=__T("0");
+ if (Config(__T("ShellExtension_Folder")).empty()) Config(__T("ShellExtension_Folder"))=__T("1");
if (Config(__T("ShellInfoTip")).empty()) Config(__T("ShellInfoTip"))=__T("0");
if (Config(__T("ShowToolBar")).empty()) Config(__T("ShowToolBar"))=__T("1");
if (Config(__T("ShowMenu")).empty()) Config(__T("ShowMenu"))=__T("1");
@@ -828,7 +828,6 @@ int Preferences::ExplorerShell()
LegacyShellExtension = 0; //Disable legacy shell extension
LegacyShellExtension_Folder = 0; //Disable legacy shell extension
ModernShellExtensionUsed = true; //Need to control modern shell extension
- Config(__T("ShellExtension_Folder")) = __T("1"); //Disabling ShellExtension_Folder not implemented
ModernReg->CloseKey();
}
} catch (...) {}
@@ -843,6 +842,10 @@ int Preferences::ExplorerShell()
ModernShellExtension->DeleteValue("ShellExtension");
else
ModernShellExtension->WriteInteger("ShellExtension", 0);
+ if (Config.Read(__T("ShellExtension_Folder")).To_int32s())
+ ModernShellExtension->DeleteValue("ShellExtension_Folder");
+ else
+ ModernShellExtension->WriteInteger("ShellExtension_Folder", 0);
ModernShellExtension->CloseKey();
}
} catch (...) {}
diff --git a/Source/GUI/VCL/GUI_Preferences.cpp b/Source/GUI/VCL/GUI_Preferences.cpp
index e7b6abd4c..a2c2cdbca 100644
--- a/Source/GUI/VCL/GUI_Preferences.cpp
+++ b/Source/GUI/VCL/GUI_Preferences.cpp
@@ -640,17 +640,6 @@ void __fastcall TPreferencesF::Setup_GeneralShow(TObject *Sender)
CB_InscrireShell->Checked=Prefs->Config(__T("ShellExtension")).To_int32s(); //Lecture Shell extension
CB_InscrireShell_Folder->Checked=Prefs->Config(__T("ShellExtension_Folder")).To_int32s(); //Lecture Shell extension
CB_InfoTip->Checked=Prefs->Config(__T("ShellInfoTip")).To_int32s(); //Lecture Shell extension
-
- //Disable InscrireShell_Folder setting if modern IExplorerCommand-based shell extension is installed (not implemented)
- TRegistry* ModernReg=new TRegistry;
- ModernReg->RootKey = HKEY_CLASSES_ROOT;
- try {
- if (ModernReg->OpenKeyReadOnly(__T("PackagedCom\\ClassIndex\\{20669675-B281-4C4F-94FB-CB6FD3995545}"))) {
- CB_InscrireShell_Folder->Enabled = false;
- ModernReg->CloseKey();
- }
- } catch (...) {}
- delete ModernReg;
}
//---------------------------------------------------------------------------
diff --git a/Source/WindowsShellExtension/dllmain.cpp b/Source/WindowsShellExtension/dllmain.cpp
index 02d212a2e..5ea95b1c4 100644
--- a/Source/WindowsShellExtension/dllmain.cpp
+++ b/Source/WindowsShellExtension/dllmain.cpp
@@ -172,13 +172,30 @@ struct ExplorerCommandHandler : public winrt::implementsGetCount(&count));
+ if (count > 0) {
+ winrt::com_ptr item;
+ if (SUCCEEDED(items->GetItemAt(0, item.put()))) {
+ SFGAOF attribute = 0;
+ if (SUCCEEDED(item->GetAttributes(SFGAO_FOLDER, &attribute)))
+ if (attribute & SFGAO_FOLDER)
+ is_folder = true;
+ }
+ }
+ }
+
+ // Check for files
try {
#ifdef MEDIAINFO_QT
if (!RegGetBool(HKEY_CURRENT_USER, L"Software\\MediaArea.net\\MediaInfo", L"shellExtension"))
#else
- if (!RegGetDword(HKEY_CURRENT_USER, L"Software\\MediaArea\\MediaInfo", L"ShellExtension"))
+ if (!RegGetDword(HKEY_CURRENT_USER, L"Software\\MediaArea\\MediaInfo", L"ShellExtension") && !is_folder)
#endif // MEDIAINFO_QT
{
*cmdState = ECS_HIDDEN;
@@ -188,6 +205,20 @@ struct ExplorerCommandHandler : public winrt::implements