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 zcmV;*6*cOKP)D_|(`m7w5)tbsrRf&2dPJF!`Ak~=eJ=FUvc=Xvgf-po03&fM=k z_bk690uY5{l9Gmy#GOQG2P9F3J?TmNnyfmZAvKV^t?h^DeO7mg@uw0XFB*+Z+Ec(3 zh(rkNMCDa5OpjdWiP- z?v{}|8mC7W>?w#W4)Jr{1*}r9QZj&xfy;mgfnNdt1U>=Qsn;gpsF9_m5%}1hRS%r* zkVG^aSX|4V^={xz^#V8nxEii@Lns#(m*X&bbUaVd}n8#LeFqFlI*EBYdz8rjTb+Kp; zJglZ66M+^+zy`mu3h0Dvza6OJntH&Wfh}reZfOK;@DoSW2z#cQ16RdyYHpkdi~$-L z0UP|p{{fdE+iC}^x$byiq#BX$L#*nIfDOJN3Ot8wuWhK|+9tqQ#IUHF5wO8eY(!4) zrp9sYslYqHLLk!!*x(n6)SUNL;7}abU!z9tyAeZuBVdCsm;qdXc#70S1K@GQr1LZ* zV1r-y9Owe9jr02RfX~z-FWCs#;0L}#4nF3`d3_zV$a@#~g%Pm94;%z~Av+cEatW{= zIr%dJHYA**KsJzLp-e;IHRQk~%?Q|#XrhQw`~w!sM35utmH5D}!U))an&S?$Sf&f& zN!{59*x(1o1H&zrX^9vT{m}^6;0GR4qp=l^17@nJh!LtYIBjz z^2usGe7X^Eu-JfDdu1XA1fRsXCKK@T^BSE*F&=sz#*efa%j^CjdKH~#=zf=fWyiESp12NAPEtt z;f>+eF2t_GDYqcjeMZ0`cx|3b{tRM#*g;BfOe61%}FlhNcAQ3Wqhy=7gzT!9>L7y*ZP zKAcVb`@^NwM*{J=b?p2VlBP=s_Zk6*oAqi$waO_tw@3jDW+#e^R|y zM^)U2ct*Ive4OtIgB-&2GXf4b`-pS%KL$_WP7uEBz{i^E8bpjeY$M=sF;$7iDkow+ zwSbjTSO>pEyj6^VYoIRB0SQFX12Lev3W<5!2KP_0oKTF!p0L9};yC%T!6J=y^@}yP zsO>aW0_}=K(mAPyFZKboXj+aqHLlh)&(pJI*|Y42M9Qh@nbb#eq>VysZu1f2npQsP*CCrb5&#_$_axmc*Hlj< z;J3AX3UL*%2Fc^l1Lv;kzX1M*?0ZfGn){%SGl*`fo1>6D&XS5jm zf$6HF4w8a(6XIN%$Y;Ay& zxg%kh2VM9=eXDWJ(y_J(ID*8oov(!DC08H;{LV~J-xp&q!w{;?T{O4nLydKHs|^B< zAl?C^NZi&}8zigyg$cNK3C^~#254^2#~SO(3cG+KNSxgvK4?or#6zJ=0`9%gLD@d& z&A7QnV_g@blE#Epz@u>(^-weQl$cKO_`XZAABZ{~*`?9N2F(lR4q+AW4Txcj-)Ms5 zA3om0dlsrGj9vO`Y|CECN2hm6=P(MmHImcJue8T`2qvpI*@L|VIa>GQD12@h1w0MN z@Oc~Wz}t|hYaRYnU!<`u8#UH-4us1V;yPsO$~KJ~H>O*+ZglF@iT3T=)22-u8Z~M} zette%w{9gjHI#P&P^ZVi*Ct#A(2Jb_(|D)r)}x2UdFjjW^yPD=Ul4%uHIf zYDH#dCSALBW#Pig=K>QaPNYMJ4tCoDaMjx%cw&^2o`_p{OYK;ZpC&$0?x3zx{kGAd->&;e;#$KA~!deZQIIc!OG0cq*=3OcKh%j z9z3U=!2S@9z$XTM8|?yY9>%=#$}6l`v4R#YTF|_Cb6U1+$*NVWYW~J#WKR;OL_9*uRK5Oe|C&hS`NR78G$KKc39eqFD<_FC%HsZ;K~_uqe? z-MeiMENzh!uOgS9)jKhHFMKXwouhEE#y+J6UBC_8 zzCoQjb;!xdVZww7l}_E(uV2rQAw$@=Z=dh`p+Ug9qFCx2fdg;MQ_t0JM}r288#j*Z z?CeT^`}EUK88Bdg_uv93cw7jT{%m1bmQRI+VYuwVf{{q&O?w<|_p)S7C$<)G|N zpR}VQJAy9YFWjg!J-zadkxSwQadbTD@^fm6MAfv*CXH>;c`Usn=-X&()Z9$x&k}p~ z?BUTzA1(Ku#vO->tn}bHo#e2*P66v2fqx9TfQylsTUsNFfA!T@+<*W5UiG2230P+? zjvZle>YS@vz%5(0Br7Yc+)Z&q3Kw(YN1j z1Y8B<0@&tN=#80M74;pCz&g_d=oIi_AU`YuUWbG*4H9EKy3aXC;1|2-oTHztbMysD z!W3HSZe(BB@m#o|pnxe;rj&cHu&}U_Gp7R;*F8G z)rIB&kMDVngR-;HyGMPV#=729yAYwxk?}S#2>;|T&Q)S6^zfdkz|{`Qzo5B2=WDF% z=LK+>(`?O9(}^PqZpWu;9{Qul_x&AUH(bys=uL}d1ZSurtTxe5wjdi_L@r~Ln;Ie$L9!|vvl&jenO?6F;HN8nP8VwC&uy=6r5@Ms_ z20ej@hI$TDg<+8qa5y+yO&_eXK`r{+qPM1c<{$?cM!+E?2}xONb>Fu@jgSXjYF9g; zi>A6BudefkU^5)(Y_UufxJ@mL++u*H>BC~+b0gqzavt!IjdCMgocEUM>JOUgdaR}! z8G=cDwE(l~12_>F>vG$!0x~t!^By%sE;0fRCJ|sd*0VG{i#Wf!%}`DCJP^-NZwMY^ zY^?BSAxGzKA9c6KnImZ_3y8yl&L=X`@tz3$QA0gbQBIpRVUCi6!|#CCh=0GgScz$lhi$wEG3Ru`?s!LEGXe*P zK8Sl#yrD@q0~dNM-VESQO$)c3M!@0WcHm{=-!7Yp94&w1aXbHl^Ms9SfoWC>7yEJP|56R#^TBx7@i{rfhHQ=v!lkF%LIT}Xa z2jgA1nGx9EbX7n9@rZXl;_-W90>yiZ8abWt5is6PK_g)Q&_vB&m#7iAI(8ubYiHq2 zl9=ikhqI8j2N1&_TdBs(6e96NkO)GLQ`rx%B3sl*H3M&QYt+OQz_kwR_!ICiCkq8b z;)Hu0@He1S4cC6IM!MJWPtd~SkP|*9OvhmeS0iBWNmarf1$3z9x^I!tShMhF%;N{t z{MRlU)HDbq;9$@RIT`Cq)xK+aNK%zofz|jYx@JXw4czCT{BGcSGyr(T=YzeNG;>nJ4ikzIzOG4qiTupV|GX};bGc|SX2KlTK`6IipRs}ZvgY>1ae zYHn_K&v!O*T8I&_ArVZ*exkyqh>gZEBVa=!_!F{wVu#hpwxKIQ5RHHhHE|Ku1Qw}* z_mM<1ZUs*<0yb1j8{i*6n$3~-DqPOlX9R4hiu#CWa8ny)R{&SyLBdHRU_&fY5xa{H zHp;$<`0sg=6VC|PP>~4Y1#+d0vd;rI;Gw0Q5wM{mW3iqRH;Q;v+=j>2a^@t?P?r0U zXqQ$fLShrYn1}`&0UJsgj`g5_+mRd?YZKLIGlejK80b7|vCL}3eSd8t8*T(_7HngI zhb_)`p9C()`vm4@3Ssz}WF$A-?H0=HM2zwm`=t{`z_pWlh;`WSEtGi|iE!yFqkA)j zsC~3Tyg%Xm&g(xw%pf=WwL@kEu00GwY!u=V?_OXC z;?uX;&z&+OaQLYUJVpHBpWZ^kq;3mB=Zt{EO$WpcsC^vQZbafVyc?trnkhs$Nk)!^ z*Tf;-ok(cZGlM2xGXjT`Q;{Hn=htxE0VK}acsw$FGy*nMM=Fw|Vl>qU9VtX&lKma{ zA?Tep0uBe4Azs6$)iB~d9~R*n0f&S3h%G~PhZ5U>Nr;j9p0GUtBj8|i0uq*Wa5bOd zXTSvD6(k;6C@}&K7OjxzHiL+rk8MAaTVopVacy`YM!>eh+OXReb<>sPctO;LNA~j z627SbInG_CUZ3ILGy{GSaMH67^;E#oq{uV1@L8V#bU~7EcSVkTzd({24pjf<8o^o= zaOCLG*Q3cvv(>!I3;E92vnOd`$e(L-BqzpMKx-tEdohv^?E_?+YYR4$`xz=O;*K8c zPg2qsM7R^l?cfGq6NyaPy*Dy3pwB9qe<$5eL;T9>s`pZXbS2b!YL5R6;(A_WWab|K 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