From 98b2af8400e177baeded9a60119e7d09d0f18f8f Mon Sep 17 00:00:00 2001 From: Christian Gaarden Gaardmark Date: Sat, 26 Oct 2024 14:45:57 -0700 Subject: [PATCH 01/24] super temp --- .../NewPlus.ShellExtension.win10.vcxproj | 235 ++++++++++++++++++ ...wPlus.ShellExtension.win10.vcxproj.filters | 36 +++ .../dll_main.cpp | 40 +++ .../pch.cpp | 5 + .../NewShellExtensionContextMenu.win10/pch.h | 37 +++ .../shell_context_menu_win10.cpp | 87 +++++++ .../shell_context_menu_win10.h | 37 +++ 7 files changed, 477 insertions(+) create mode 100644 src/modules/NewPlus/NewShellExtensionContextMenu.win10/NewPlus.ShellExtension.win10.vcxproj create mode 100644 src/modules/NewPlus/NewShellExtensionContextMenu.win10/NewPlus.ShellExtension.win10.vcxproj.filters create mode 100644 src/modules/NewPlus/NewShellExtensionContextMenu.win10/dll_main.cpp create mode 100644 src/modules/NewPlus/NewShellExtensionContextMenu.win10/pch.cpp create mode 100644 src/modules/NewPlus/NewShellExtensionContextMenu.win10/pch.h create mode 100644 src/modules/NewPlus/NewShellExtensionContextMenu.win10/shell_context_menu_win10.cpp create mode 100644 src/modules/NewPlus/NewShellExtensionContextMenu.win10/shell_context_menu_win10.h diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/NewPlus.ShellExtension.win10.vcxproj b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/NewPlus.ShellExtension.win10.vcxproj new file mode 100644 index 000000000000..0d774701ae37 --- /dev/null +++ b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/NewPlus.ShellExtension.win10.vcxproj @@ -0,0 +1,235 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + Debug + ARM64 + + + Release + ARM64 + + + + 17.0 + Win32Proj + {0db0f63a-d2f8-4da3-a650-2d0b8724218e} + NewPlusShellExtensionwin10 + 10.0.22621.0 + + + + DynamicLibrary + true + v143 + Unicode + + + DynamicLibrary + false + v143 + true + Unicode + + + DynamicLibrary + true + v143 + Unicode + + + DynamicLibrary + false + v143 + true + Unicode + + + DynamicLibrary + true + v143 + Unicode + + + DynamicLibrary + false + v143 + true + Unicode + + + + + + + + + + + + + + + + + + + + + + + + + + + PowerToys.NewPlus.ShellExtension.win10 + ..\..\..\..\$(Platform)\$(Configuration)\WinUI3Apps\ + + + PowerToys.NewPlus.ShellExtension.win10 + ..\..\..\..\$(Platform)\$(Configuration)\WinUI3Apps\ + + + + Level3 + true + WIN32;_DEBUG;NEWPLUSSHELLEXTENSIONWIN10_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + Use + ..\..\..\common\Telemetry;..\..\;..\..\..\;%(AdditionalIncludeDirectories) + false + + + Windows + true + false + + + + + Level3 + true + true + true + WIN32;NDEBUG;NEWPLUSSHELLEXTENSIONWIN10_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + Use + ..\..\..\common\Telemetry;..\..\;..\..\..\;%(AdditionalIncludeDirectories) + false + + + Windows + true + true + true + false + + + + + Level3 + true + _DEBUG;NEWPLUSSHELLEXTENSIONWIN10_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + Use + ..\..\..\common\Telemetry;..\..\;..\..\..\;%(AdditionalIncludeDirectories) + false + + + Windows + true + false + + + + + Level3 + true + true + true + NDEBUG;NEWPLUSSHELLEXTENSIONWIN10_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + Use + ..\..\..\common\Telemetry;..\..\;..\..\..\;%(AdditionalIncludeDirectories) + false + + + Windows + true + true + true + false + + + + + Level3 + true + _DEBUG;NEWPLUSSHELLEXTENSIONWIN10_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + Use + ..\..\..\common\Telemetry;..\..\;..\..\..\;%(AdditionalIncludeDirectories) + false + + + Windows + true + false + + + + + Level3 + true + true + true + NDEBUG;NEWPLUSSHELLEXTENSIONWIN10_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + Use + ..\..\..\common\Telemetry;..\..\;..\..\..\;%(AdditionalIncludeDirectories) + false + + + Windows + true + true + true + false + + + + + + + + + + Create + Create + Create + Create + Create + Create + + + + + + + \ No newline at end of file diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/NewPlus.ShellExtension.win10.vcxproj.filters b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/NewPlus.ShellExtension.win10.vcxproj.filters new file mode 100644 index 000000000000..9fb7c3d9c391 --- /dev/null +++ b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/NewPlus.ShellExtension.win10.vcxproj.filters @@ -0,0 +1,36 @@ + + + + + {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 + + + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/dll_main.cpp b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/dll_main.cpp new file mode 100644 index 000000000000..48c1509e4a42 --- /dev/null +++ b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/dll_main.cpp @@ -0,0 +1,40 @@ +// dllmain.cpp : Defines the entry point for the DLL application. +#include "pch.h" + +#include "shell_context_menu_win10.h" + +HMODULE module_instance_handle = 0; + +BOOL APIENTRY DllMain(HMODULE module_handle, DWORD ul_reason_for_call, LPVOID reserved) +{ + switch (ul_reason_for_call) + { + case DLL_PROCESS_ATTACH: + module_instance_handle = module_handle; + // Trace::RegisterProvider(); + // newplus::utilities::init_logger(); + break; + + case DLL_PROCESS_DETACH: + // Trace::UnregisterProvider(); + break; + } + return TRUE; +} + +STDAPI DllGetActivationFactory(_In_ HSTRING activatableClassId, _COM_Outptr_ IActivationFactory** factory) +{ + return Module::GetModule().GetActivationFactory(activatableClassId, factory); +} + +STDAPI DllCanUnloadNow() +{ + return Module::GetModule().GetObjectCount() == 0 ? S_OK : S_FALSE; +} + +STDAPI DllGetClassObject(_In_ REFCLSID rclsid, _In_ REFIID riid, _Outptr_ LPVOID FAR* ppv) +{ + return Module::GetModule().GetClassObject(rclsid, riid, ppv); +} + +CoCreatableClass(shell_context_menu) diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/pch.cpp b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/pch.cpp new file mode 100644 index 000000000000..64b7eef6d6b9 --- /dev/null +++ b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/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/src/modules/NewPlus/NewShellExtensionContextMenu.win10/pch.h b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/pch.h new file mode 100644 index 000000000000..981209e500e4 --- /dev/null +++ b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/pch.h @@ -0,0 +1,37 @@ +// Precompiled header file. + +#pragma once + +#define WIN32_LEAN_AND_MEAN +#define NOMCX +#define NOHELP +#define NOCOMM + +// Windows and STL +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// PowerToys project common +#include +#include +#include +#include +#include +#include + +// New project specific +#include "dll_main.h" +#include "template_folder.h" +#include "settings.h" +#include "new_utilities.h" diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/shell_context_menu_win10.cpp b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/shell_context_menu_win10.cpp new file mode 100644 index 000000000000..b3bf2992d5f1 --- /dev/null +++ b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/shell_context_menu_win10.cpp @@ -0,0 +1,87 @@ +#include "pch.h" + +#include "shell_context_menu.h" +#include "shell_context_sub_menu.h" +#include "shell_context_sub_menu_item.h" +#include "template_folder.h" +#include "new_utilities.h" +#include "settings.h" +#include "trace.h" +#include "Generated Files/resource.h" + +using namespace Microsoft::WRL; +using namespace newplus; + +#pragma region IExplorerCommand +IFACEMETHODIMP shell_context_menu::GetTitle(_In_opt_ IShellItemArray*, _Outptr_result_nullonfailure_ PWSTR* returned_title) +{ + static const std::wstring localized_context_menu_item = + GET_RESOURCE_STRING_FALLBACK(IDS_CONTEXT_MENU_ITEM_NEW, L"New+"); + + return SHStrDup(localized_context_menu_item.c_str(), returned_title); +} + +IFACEMETHODIMP shell_context_menu::GetIcon(_In_opt_ IShellItemArray*, _Outptr_result_nullonfailure_ PWSTR* returned_icon) +{ + *returned_icon = nullptr; + + static const auto icon_resource_filepath = utilities::get_new_icon_resource_filepath(module_instance_handle, ThemeHelpers::GetAppTheme()); + + return SHStrDup(icon_resource_filepath.c_str(), returned_icon); +} + +IFACEMETHODIMP shell_context_menu::GetToolTip(_In_opt_ IShellItemArray*, _Outptr_result_nullonfailure_ PWSTR* returned_tool_tip) +{ + *returned_tool_tip = nullptr; + return E_NOTIMPL; +} + +IFACEMETHODIMP shell_context_menu::GetCanonicalName(_Out_ GUID* returned_id) +{ + *returned_id = __uuidof(this); + return S_OK; +} + +IFACEMETHODIMP shell_context_menu::GetState(_In_opt_ IShellItemArray*, _In_ BOOL, _Out_ EXPCMDSTATE* returned_state) +{ + if (!NewSettingsInstance().GetEnabled()) + { + *returned_state = ECS_HIDDEN; + } + else + { + *returned_state = ECS_ENABLED; + } + + return S_OK; +} + +IFACEMETHODIMP shell_context_menu::Invoke(_In_opt_ IShellItemArray*, _In_opt_ IBindCtx*) noexcept +{ + return E_NOTIMPL; +} + +IFACEMETHODIMP shell_context_menu::GetFlags(_Out_ EXPCMDFLAGS* returned_menu_item_flags) +{ + *returned_menu_item_flags = ECF_HASSUBCOMMANDS; + return S_OK; +} + +IFACEMETHODIMP shell_context_menu::EnumSubCommands(_COM_Outptr_ IEnumExplorerCommand** returned_enum_commands) +{ + auto e = Make(site_of_folder); + return e->QueryInterface(IID_PPV_ARGS(returned_enum_commands)); +} +#pragma endregion + +#pragma region IObjectWithSite +IFACEMETHODIMP shell_context_menu::SetSite(_In_ IUnknown* site) noexcept +{ + this->site_of_folder = site; + return S_OK; +} +IFACEMETHODIMP shell_context_menu::GetSite(_In_ REFIID riid, _COM_Outptr_ void** returned_site) noexcept +{ + return this->site_of_folder.CopyTo(riid, returned_site); +} +#pragma endregion diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/shell_context_menu_win10.h b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/shell_context_menu_win10.h new file mode 100644 index 000000000000..564069254d37 --- /dev/null +++ b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/shell_context_menu_win10.h @@ -0,0 +1,37 @@ +#pragma once + +#include "pch.h" + +using namespace Microsoft::WRL; + +#define NEW_SHELL_EXTENSION_EXPLORER_COMMAND_UUID_STR "69824FC6-4660-4A09-9E7C-48DA63C6CC0F" + +// File Explorer context menu "New+" +class __declspec(uuid(NEW_SHELL_EXTENSION_EXPLORER_COMMAND_UUID_STR)) shell_context_menu final : + public RuntimeClass< + RuntimeClassFlags, + IExplorerCommand, + IObjectWithSite> +{ +public: +#pragma region IExplorerCommand + IFACEMETHODIMP GetTitle(_In_opt_ IShellItemArray*, _Outptr_result_nullonfailure_ PWSTR* returned_title); + IFACEMETHODIMP GetIcon(_In_opt_ IShellItemArray*, _Outptr_result_nullonfailure_ PWSTR* returned_icon); + IFACEMETHODIMP GetToolTip(_In_opt_ IShellItemArray*, _Outptr_result_nullonfailure_ PWSTR* returned_tool_tip); + IFACEMETHODIMP GetCanonicalName(_Out_ GUID* returned_id); + IFACEMETHODIMP GetState(_In_opt_ IShellItemArray*, _In_ BOOL, _Out_ EXPCMDSTATE* returned_state); + IFACEMETHODIMP Invoke(_In_opt_ IShellItemArray*, _In_opt_ IBindCtx*) noexcept; + IFACEMETHODIMP GetFlags(_Out_ EXPCMDFLAGS* returned_menu_item_flags); + IFACEMETHODIMP EnumSubCommands(_COM_Outptr_ IEnumExplorerCommand** returned_enum_commands); +#pragma endregion + +#pragma region IObjectWithSite + IFACEMETHODIMP SetSite(_In_ IUnknown* site) noexcept; + + IFACEMETHODIMP GetSite(_In_ REFIID riid, _COM_Outptr_ void** site) noexcept; +#pragma endregion + +protected: + HINSTANCE instance_handle = 0; + ComPtr site_of_folder; +}; From 1f79a735594ebcab1dc9143f12b932401c284908 Mon Sep 17 00:00:00 2001 From: Christian Gaarden Gaardmark Date: Sat, 26 Oct 2024 21:48:29 -0700 Subject: [PATCH 02/24] wip --- PowerToys.sln | 67 +++++---- .../NewPlus.ShellExtension.win10.vcxproj | 48 ++++++- ...wPlus.ShellExtension.win10.vcxproj.filters | 25 ++++ .../new.base.rc | 49 +++++++ .../packages.config | 4 + .../resource.base.h | 13 ++ .../resources.resx | 132 ++++++++++++++++++ .../shell_context_menu_win10.cpp | 112 +++++++++++++-- .../shell_context_menu_win10.h | 25 ++-- 9 files changed, 419 insertions(+), 56 deletions(-) create mode 100644 src/modules/NewPlus/NewShellExtensionContextMenu.win10/new.base.rc create mode 100644 src/modules/NewPlus/NewShellExtensionContextMenu.win10/packages.config create mode 100644 src/modules/NewPlus/NewShellExtensionContextMenu.win10/resource.base.h create mode 100644 src/modules/NewPlus/NewShellExtensionContextMenu.win10/resources.resx diff --git a/PowerToys.sln b/PowerToys.sln index 80722be402a3..e2052e4f3247 100644 --- a/PowerToys.sln +++ b/PowerToys.sln @@ -630,6 +630,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "EtwTrace", "src\common\Tele EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MouseWithoutBorders.UnitTests", "src\modules\MouseWithoutBorders\MouseWithoutBorders.UnitTests\MouseWithoutBorders.UnitTests.csproj", "{66614C26-314C-4B91-9071-76133422CFEF}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NewPlus.ShellExtension.win10", "src\modules\NewPlus\NewShellExtensionContextMenu.win10\NewPlus.ShellExtension.win10.vcxproj", "{0DB0F63A-D2F8-4DA3-A650-2D0B8724218E}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|ARM64 = Debug|ARM64 @@ -2246,6 +2248,30 @@ Global {8A08D663-4995-40E3-B42C-3F910625F284}.Release|x64.Build.0 = Release|x64 {8A08D663-4995-40E3-B42C-3F910625F284}.Release|x86.ActiveCfg = Release|x64 {8A08D663-4995-40E3-B42C-3F910625F284}.Release|x86.Build.0 = Release|x64 + {923DF87C-CA99-4D1C-B1D2-959174E95BFA}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {923DF87C-CA99-4D1C-B1D2-959174E95BFA}.Debug|ARM64.Build.0 = Debug|ARM64 + {923DF87C-CA99-4D1C-B1D2-959174E95BFA}.Debug|x64.ActiveCfg = Debug|x64 + {923DF87C-CA99-4D1C-B1D2-959174E95BFA}.Debug|x64.Build.0 = Debug|x64 + {923DF87C-CA99-4D1C-B1D2-959174E95BFA}.Debug|x86.ActiveCfg = Debug|x64 + {923DF87C-CA99-4D1C-B1D2-959174E95BFA}.Debug|x86.Build.0 = Debug|x64 + {923DF87C-CA99-4D1C-B1D2-959174E95BFA}.Release|ARM64.ActiveCfg = Release|ARM64 + {923DF87C-CA99-4D1C-B1D2-959174E95BFA}.Release|ARM64.Build.0 = Release|ARM64 + {923DF87C-CA99-4D1C-B1D2-959174E95BFA}.Release|x64.ActiveCfg = Release|x64 + {923DF87C-CA99-4D1C-B1D2-959174E95BFA}.Release|x64.Build.0 = Release|x64 + {923DF87C-CA99-4D1C-B1D2-959174E95BFA}.Release|x86.ActiveCfg = Release|x64 + {923DF87C-CA99-4D1C-B1D2-959174E95BFA}.Release|x86.Build.0 = Release|x64 + {D5E42C63-57C5-4EF6-AECE-1E2FCA725B77}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {D5E42C63-57C5-4EF6-AECE-1E2FCA725B77}.Debug|ARM64.Build.0 = Debug|ARM64 + {D5E42C63-57C5-4EF6-AECE-1E2FCA725B77}.Debug|x64.ActiveCfg = Debug|x64 + {D5E42C63-57C5-4EF6-AECE-1E2FCA725B77}.Debug|x64.Build.0 = Debug|x64 + {D5E42C63-57C5-4EF6-AECE-1E2FCA725B77}.Debug|x86.ActiveCfg = Debug|x64 + {D5E42C63-57C5-4EF6-AECE-1E2FCA725B77}.Debug|x86.Build.0 = Debug|x64 + {D5E42C63-57C5-4EF6-AECE-1E2FCA725B77}.Release|ARM64.ActiveCfg = Release|ARM64 + {D5E42C63-57C5-4EF6-AECE-1E2FCA725B77}.Release|ARM64.Build.0 = Release|ARM64 + {D5E42C63-57C5-4EF6-AECE-1E2FCA725B77}.Release|x64.ActiveCfg = Release|x64 + {D5E42C63-57C5-4EF6-AECE-1E2FCA725B77}.Release|x64.Build.0 = Release|x64 + {D5E42C63-57C5-4EF6-AECE-1E2FCA725B77}.Release|x86.ActiveCfg = Release|x64 + {D5E42C63-57C5-4EF6-AECE-1E2FCA725B77}.Release|x86.Build.0 = Release|x64 {D962A009-834F-4EEC-AABB-430DF8F98E39}.Debug|ARM64.ActiveCfg = Debug|ARM64 {D962A009-834F-4EEC-AABB-430DF8F98E39}.Debug|ARM64.Build.0 = Debug|ARM64 {D962A009-834F-4EEC-AABB-430DF8F98E39}.Debug|x64.ActiveCfg = Debug|x64 @@ -2646,30 +2672,6 @@ Global {F055103B-F80B-4D0C-BF48-057C55620033}.Release|x64.Build.0 = Release|x64 {F055103B-F80B-4D0C-BF48-057C55620033}.Release|x86.ActiveCfg = Release|x64 {F055103B-F80B-4D0C-BF48-057C55620033}.Release|x86.Build.0 = Release|x64 - {923DF87C-CA99-4D1C-B1D2-959174E95BFA}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {923DF87C-CA99-4D1C-B1D2-959174E95BFA}.Debug|ARM64.Build.0 = Debug|ARM64 - {923DF87C-CA99-4D1C-B1D2-959174E95BFA}.Debug|x64.ActiveCfg = Debug|x64 - {923DF87C-CA99-4D1C-B1D2-959174E95BFA}.Debug|x64.Build.0 = Debug|x64 - {923DF87C-CA99-4D1C-B1D2-959174E95BFA}.Debug|x86.ActiveCfg = Debug|x64 - {923DF87C-CA99-4D1C-B1D2-959174E95BFA}.Debug|x86.Build.0 = Debug|x64 - {923DF87C-CA99-4D1C-B1D2-959174E95BFA}.Release|ARM64.ActiveCfg = Release|ARM64 - {923DF87C-CA99-4D1C-B1D2-959174E95BFA}.Release|ARM64.Build.0 = Release|ARM64 - {923DF87C-CA99-4D1C-B1D2-959174E95BFA}.Release|x64.ActiveCfg = Release|x64 - {923DF87C-CA99-4D1C-B1D2-959174E95BFA}.Release|x64.Build.0 = Release|x64 - {923DF87C-CA99-4D1C-B1D2-959174E95BFA}.Release|x86.ActiveCfg = Release|x64 - {923DF87C-CA99-4D1C-B1D2-959174E95BFA}.Release|x86.Build.0 = Release|x64 - {D5E42C63-57C5-4EF6-AECE-1E2FCA725B77}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {D5E42C63-57C5-4EF6-AECE-1E2FCA725B77}.Debug|ARM64.Build.0 = Debug|ARM64 - {D5E42C63-57C5-4EF6-AECE-1E2FCA725B77}.Debug|x64.ActiveCfg = Debug|x64 - {D5E42C63-57C5-4EF6-AECE-1E2FCA725B77}.Debug|x64.Build.0 = Debug|x64 - {D5E42C63-57C5-4EF6-AECE-1E2FCA725B77}.Debug|x86.ActiveCfg = Debug|x64 - {D5E42C63-57C5-4EF6-AECE-1E2FCA725B77}.Debug|x86.Build.0 = Debug|x64 - {D5E42C63-57C5-4EF6-AECE-1E2FCA725B77}.Release|ARM64.ActiveCfg = Release|ARM64 - {D5E42C63-57C5-4EF6-AECE-1E2FCA725B77}.Release|ARM64.Build.0 = Release|ARM64 - {D5E42C63-57C5-4EF6-AECE-1E2FCA725B77}.Release|x64.ActiveCfg = Release|x64 - {D5E42C63-57C5-4EF6-AECE-1E2FCA725B77}.Release|x64.Build.0 = Release|x64 - {D5E42C63-57C5-4EF6-AECE-1E2FCA725B77}.Release|x86.ActiveCfg = Release|x64 - {D5E42C63-57C5-4EF6-AECE-1E2FCA725B77}.Release|x86.Build.0 = Release|x64 {B31FCC55-B5A4-4EA7-B414-2DCEAE6AF332}.Debug|ARM64.ActiveCfg = Debug|ARM64 {B31FCC55-B5A4-4EA7-B414-2DCEAE6AF332}.Debug|ARM64.Build.0 = Debug|ARM64 {B31FCC55-B5A4-4EA7-B414-2DCEAE6AF332}.Debug|x64.ActiveCfg = Debug|x64 @@ -2778,6 +2780,18 @@ Global {66614C26-314C-4B91-9071-76133422CFEF}.Release|x64.Build.0 = Release|x64 {66614C26-314C-4B91-9071-76133422CFEF}.Release|x86.ActiveCfg = Release|x64 {66614C26-314C-4B91-9071-76133422CFEF}.Release|x86.Build.0 = Release|x64 + {0DB0F63A-D2F8-4DA3-A650-2D0B8724218E}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {0DB0F63A-D2F8-4DA3-A650-2D0B8724218E}.Debug|ARM64.Build.0 = Debug|ARM64 + {0DB0F63A-D2F8-4DA3-A650-2D0B8724218E}.Debug|x64.ActiveCfg = Debug|x64 + {0DB0F63A-D2F8-4DA3-A650-2D0B8724218E}.Debug|x64.Build.0 = Debug|x64 + {0DB0F63A-D2F8-4DA3-A650-2D0B8724218E}.Debug|x86.ActiveCfg = Debug|Win32 + {0DB0F63A-D2F8-4DA3-A650-2D0B8724218E}.Debug|x86.Build.0 = Debug|Win32 + {0DB0F63A-D2F8-4DA3-A650-2D0B8724218E}.Release|ARM64.ActiveCfg = Release|ARM64 + {0DB0F63A-D2F8-4DA3-A650-2D0B8724218E}.Release|ARM64.Build.0 = Release|ARM64 + {0DB0F63A-D2F8-4DA3-A650-2D0B8724218E}.Release|x64.ActiveCfg = Release|x64 + {0DB0F63A-D2F8-4DA3-A650-2D0B8724218E}.Release|x64.Build.0 = Release|x64 + {0DB0F63A-D2F8-4DA3-A650-2D0B8724218E}.Release|x86.ActiveCfg = Release|Win32 + {0DB0F63A-D2F8-4DA3-A650-2D0B8724218E}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -2956,6 +2970,8 @@ Global {B5EB9FE9-37EF-47C3-B8B8-81AD3C2972C2} = {B6C42F16-73EB-477E-8B0D-4E6CF6C20AAC} {A663E672-B26D-4EC0-BEAB-FE2E424AC46F} = {B6C42F16-73EB-477E-8B0D-4E6CF6C20AAC} {8A08D663-4995-40E3-B42C-3F910625F284} = {322566EF-20DC-43A6-B9F8-616AF942579A} + {923DF87C-CA99-4D1C-B1D2-959174E95BFA} = {322566EF-20DC-43A6-B9F8-616AF942579A} + {D5E42C63-57C5-4EF6-AECE-1E2FCA725B77} = {322566EF-20DC-43A6-B9F8-616AF942579A} {D962A009-834F-4EEC-AABB-430DF8F98E39} = {322566EF-20DC-43A6-B9F8-616AF942579A} {9873BA05-4C41-4819-9283-CF45D795431B} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC} {FC373B24-3293-453C-AAF5-CF2909DCEE6A} = {9873BA05-4C41-4819-9283-CF45D795431B} @@ -2995,8 +3011,6 @@ Global {8ACB33D9-C95B-47D4-8363-9731EE0930A0} = {CA716AE6-FE5C-40AC-BB8F-2C87912687AC} {CA716AE6-FE5C-40AC-BB8F-2C87912687AC} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC} {F055103B-F80B-4D0C-BF48-057C55620033} = {5A7818A8-109C-4E1C-850D-1A654E234B0E} - {923DF87C-CA99-4D1C-B1D2-959174E95BFA} = {322566EF-20DC-43A6-B9F8-616AF942579A} - {D5E42C63-57C5-4EF6-AECE-1E2FCA725B77} = {322566EF-20DC-43A6-B9F8-616AF942579A} {A2221D7E-55E7-4BEA-90D1-4F162D670BBF} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC} {BE126CBB-AE12-406A-9837-A05ACFCA57A7} = {A2221D7E-55E7-4BEA-90D1-4F162D670BBF} {14CB58B7-D280-4A7A-95DE-4B2DF14EA000} = {A2221D7E-55E7-4BEA-90D1-4F162D670BBF} @@ -3009,6 +3023,7 @@ Global {37D07516-4185-43A4-924F-3C7A5D95ECF6} = {A2221D7E-55E7-4BEA-90D1-4F162D670BBF} {8F021B46-362B-485C-BFBA-CCF83E820CBD} = {8F62026A-294B-41C6-8839-87463613F216} {66614C26-314C-4B91-9071-76133422CFEF} = {B6C42F16-73EB-477E-8B0D-4E6CF6C20AAC} + {0DB0F63A-D2F8-4DA3-A650-2D0B8724218E} = {CA716AE6-FE5C-40AC-BB8F-2C87912687AC} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {C3A2F9D1-7930-4EF4-A6FC-7EE0A99821D0} diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/NewPlus.ShellExtension.win10.vcxproj b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/NewPlus.ShellExtension.win10.vcxproj index 0d774701ae37..1fad7ea3d04a 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/NewPlus.ShellExtension.win10.vcxproj +++ b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/NewPlus.ShellExtension.win10.vcxproj @@ -1,5 +1,10 @@ + + + + + Debug @@ -112,7 +117,7 @@ WIN32;_DEBUG;NEWPLUSSHELLEXTENSIONWIN10_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) true Use - ..\..\..\common\Telemetry;..\..\;..\..\..\;%(AdditionalIncludeDirectories) + ..\..\..\common\Telemetry;..\..\;..\..\..\;%(AdditionalIncludeDirectories);..\NewShellExtensionContextMenu false @@ -130,7 +135,7 @@ WIN32;NDEBUG;NEWPLUSSHELLEXTENSIONWIN10_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) true Use - ..\..\..\common\Telemetry;..\..\;..\..\..\;%(AdditionalIncludeDirectories) + ..\..\..\common\Telemetry;..\..\;..\..\..\;%(AdditionalIncludeDirectories);..\NewShellExtensionContextMenu false @@ -148,7 +153,7 @@ _DEBUG;NEWPLUSSHELLEXTENSIONWIN10_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) true Use - ..\..\..\common\Telemetry;..\..\;..\..\..\;%(AdditionalIncludeDirectories) + ..\..\..\common\Telemetry;..\..\;..\..\..\;%(AdditionalIncludeDirectories);..\NewShellExtensionContextMenu false @@ -166,7 +171,7 @@ NDEBUG;NEWPLUSSHELLEXTENSIONWIN10_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) true Use - ..\..\..\common\Telemetry;..\..\;..\..\..\;%(AdditionalIncludeDirectories) + ..\..\..\common\Telemetry;..\..\;..\..\..\;%(AdditionalIncludeDirectories);..\NewShellExtensionContextMenu false @@ -184,7 +189,7 @@ _DEBUG;NEWPLUSSHELLEXTENSIONWIN10_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) true Use - ..\..\..\common\Telemetry;..\..\;..\..\..\;%(AdditionalIncludeDirectories) + ..\..\..\common\Telemetry;..\..\;..\..\..\;%(AdditionalIncludeDirectories);..\NewShellExtensionContextMenu false @@ -202,7 +207,7 @@ NDEBUG;NEWPLUSSHELLEXTENSIONWIN10_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) true Use - ..\..\..\common\Telemetry;..\..\;..\..\..\;%(AdditionalIncludeDirectories) + ..\..\..\common\Telemetry;..\..\;..\..\..\;%(AdditionalIncludeDirectories);..\NewShellExtensionContextMenu false @@ -214,7 +219,9 @@ + + @@ -229,7 +236,36 @@ + + + + + + + + + + {d9b8fc84-322a-4f9f-bbb9-20915c47ddfd} + + + {6955446d-23f7-4023-9bb3-8657f904af99} + + + {98537082-0fdb-40de-abd8-0dc5a4269bab} + + + + + + + + + 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/src/modules/NewPlus/NewShellExtensionContextMenu.win10/NewPlus.ShellExtension.win10.vcxproj.filters b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/NewPlus.ShellExtension.win10.vcxproj.filters index 9fb7c3d9c391..2e71337bbf6c 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/NewPlus.ShellExtension.win10.vcxproj.filters +++ b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/NewPlus.ShellExtension.win10.vcxproj.filters @@ -13,6 +13,9 @@ {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 + + {4cea4fff-ccef-4b62-9e46-f33da2b9a0cc} + @@ -21,6 +24,12 @@ Header Files + + Header Files + + + Generated Files + @@ -33,4 +42,20 @@ Source Files + + + Resource Files + + + Generated Files + + + + + Resource Files + + + + + \ No newline at end of file diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/new.base.rc b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/new.base.rc new file mode 100644 index 000000000000..8cb286b60627 --- /dev/null +++ b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/new.base.rc @@ -0,0 +1,49 @@ +#include +#include "Generated Files/resource.h" +#include "../../../common/version/version.h" + +#define APSTUDIO_READONLY_SYMBOLS +#include "winres.h" +#undef APSTUDIO_READONLY_SYMBOLS + +1 VERSIONINFO + FILEVERSION FILE_VERSION + PRODUCTVERSION PRODUCT_VERSION + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS_NT_WINDOWS32 + FILETYPE VFT_DLL + FILESUBTYPE VFT2_UNKNOWN +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", COMPANY_NAME + VALUE "FileDescription", FILE_DESCRIPTION + VALUE "FileVersion", FILE_VERSION_STRING + VALUE "InternalName", INTERNAL_NAME + VALUE "LegalCopyright", COPYRIGHT_NOTE + VALUE "OriginalFilename", ORIGINAL_FILENAME + VALUE "ProductName", PRODUCT_NAME + VALUE "ProductVersion", PRODUCT_VERSION_STRING + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_NEWPLUS_ICON ICON "../NewShellExtensionContextMenu/Assets/NewPlus/New_light.ico" diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/packages.config b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/packages.config new file mode 100644 index 000000000000..7a9561b2b504 --- /dev/null +++ b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/resource.base.h b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/resource.base.h new file mode 100644 index 000000000000..7adcb35adce0 --- /dev/null +++ b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/resource.base.h @@ -0,0 +1,13 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. + +////////////////////////////// +// Non-localizable + +#define FILE_DESCRIPTION "PowerToys.New+" +#define INTERNAL_NAME "PowerToys.New+" +#define ORIGINAL_FILENAME "PowerToys.NewPlus.ShellExtension.dll" +#define IDI_NEWPLUS_ICON 1001 + +// Non-localizable +////////////////////////////// diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/resources.resx b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/resources.resx new file mode 100644 index 000000000000..7db1823f955f --- /dev/null +++ b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/resources.resx @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + New+ + The main context menu item that users click on. This should be localized to match New in Windows. e.g. Danish it would become Ny+ + + + Open templates + The menu item in the context menu that enables user to open the folder that contains their templates. + + + Templates + Default subfolder name where templates are stored. + + \ No newline at end of file diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/shell_context_menu_win10.cpp b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/shell_context_menu_win10.cpp index b3bf2992d5f1..a10d375d6fe8 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/shell_context_menu_win10.cpp +++ b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/shell_context_menu_win10.cpp @@ -1,6 +1,6 @@ #include "pch.h" -#include "shell_context_menu.h" +#include "shell_context_menu_win10.h" #include "shell_context_sub_menu.h" #include "shell_context_sub_menu_item.h" #include "template_folder.h" @@ -8,12 +8,32 @@ #include "settings.h" #include "trace.h" #include "Generated Files/resource.h" +#include using namespace Microsoft::WRL; using namespace newplus; +#pragma region IShellExtInit +IFACEMETHODIMP shell_context_menu_win10::Initialize(PCIDLIST_ABSOLUTE, IDataObject* site, HKEY) +{ +// cgaarden HACK UPDATE + if (!NewSettingsInstance().GetEnabled()) + { + return E_FAIL; + } + + if (site) // cgaarden NOT sure + { + site_of_folder = site; + } + + return S_OK; +} +#pragma endregion + #pragma region IExplorerCommand -IFACEMETHODIMP shell_context_menu::GetTitle(_In_opt_ IShellItemArray*, _Outptr_result_nullonfailure_ PWSTR* returned_title) +// cgaarden Hack is this interface actually called on Win10???? Why the duplication???? +IFACEMETHODIMP shell_context_menu_win10::GetTitle(_In_opt_ IShellItemArray*, _Outptr_result_nullonfailure_ PWSTR* returned_title) { static const std::wstring localized_context_menu_item = GET_RESOURCE_STRING_FALLBACK(IDS_CONTEXT_MENU_ITEM_NEW, L"New+"); @@ -21,7 +41,7 @@ IFACEMETHODIMP shell_context_menu::GetTitle(_In_opt_ IShellItemArray*, _Outptr_r return SHStrDup(localized_context_menu_item.c_str(), returned_title); } -IFACEMETHODIMP shell_context_menu::GetIcon(_In_opt_ IShellItemArray*, _Outptr_result_nullonfailure_ PWSTR* returned_icon) +IFACEMETHODIMP shell_context_menu_win10::GetIcon(_In_opt_ IShellItemArray*, _Outptr_result_nullonfailure_ PWSTR* returned_icon) { *returned_icon = nullptr; @@ -30,19 +50,19 @@ IFACEMETHODIMP shell_context_menu::GetIcon(_In_opt_ IShellItemArray*, _Outptr_re return SHStrDup(icon_resource_filepath.c_str(), returned_icon); } -IFACEMETHODIMP shell_context_menu::GetToolTip(_In_opt_ IShellItemArray*, _Outptr_result_nullonfailure_ PWSTR* returned_tool_tip) +IFACEMETHODIMP shell_context_menu_win10::GetToolTip(_In_opt_ IShellItemArray*, _Outptr_result_nullonfailure_ PWSTR* returned_tool_tip) { *returned_tool_tip = nullptr; return E_NOTIMPL; } -IFACEMETHODIMP shell_context_menu::GetCanonicalName(_Out_ GUID* returned_id) +IFACEMETHODIMP shell_context_menu_win10::GetCanonicalName(_Out_ GUID* returned_id) { *returned_id = __uuidof(this); return S_OK; } -IFACEMETHODIMP shell_context_menu::GetState(_In_opt_ IShellItemArray*, _In_ BOOL, _Out_ EXPCMDSTATE* returned_state) +IFACEMETHODIMP shell_context_menu_win10::GetState(_In_opt_ IShellItemArray*, _In_ BOOL, _Out_ EXPCMDSTATE* returned_state) { if (!NewSettingsInstance().GetEnabled()) { @@ -56,32 +76,94 @@ IFACEMETHODIMP shell_context_menu::GetState(_In_opt_ IShellItemArray*, _In_ BOOL return S_OK; } -IFACEMETHODIMP shell_context_menu::Invoke(_In_opt_ IShellItemArray*, _In_opt_ IBindCtx*) noexcept +IFACEMETHODIMP shell_context_menu_win10::Invoke(_In_opt_ IShellItemArray*, _In_opt_ IBindCtx*) noexcept { return E_NOTIMPL; } -IFACEMETHODIMP shell_context_menu::GetFlags(_Out_ EXPCMDFLAGS* returned_menu_item_flags) +IFACEMETHODIMP shell_context_menu_win10::GetFlags(_Out_ EXPCMDFLAGS* returned_menu_item_flags) { *returned_menu_item_flags = ECF_HASSUBCOMMANDS; return S_OK; } -IFACEMETHODIMP shell_context_menu::EnumSubCommands(_COM_Outptr_ IEnumExplorerCommand** returned_enum_commands) +IFACEMETHODIMP shell_context_menu_win10::EnumSubCommands(_COM_Outptr_ IEnumExplorerCommand** returned_enum_commands) { auto e = Make(site_of_folder); return e->QueryInterface(IID_PPV_ARGS(returned_enum_commands)); } #pragma endregion -#pragma region IObjectWithSite -IFACEMETHODIMP shell_context_menu::SetSite(_In_ IUnknown* site) noexcept +#pragma region IContextMenu +IFACEMETHODIMP shell_context_menu_win10::QueryContextMenu(HMENU menu_handle, UINT menu_index, UINT menu_first_cmd_id, UINT, UINT menu_flags) { - this->site_of_folder = site; - return S_OK; + if (!NewSettingsInstance().GetEnabled()) + { + return E_FAIL; + } + + // cgaarden NOT SURE what state of site_of_folder is + // cgaarden Update to NOT show Win10 menu when on Windows 11++ + HRESULT hr = E_UNEXPECTED; + if (site_of_folder && !(menu_flags & (CMF_DEFAULTONLY | CMF_VERBSONLY | CMF_OPTIMIZEFORINVOKE))) + { + static const std::wstring localized_context_menu_item = + GET_RESOURCE_STRING_FALLBACK(IDS_CONTEXT_MENU_ITEM_NEW, L"New+"); + + wchar_t menu_name[128] = { 0 }; + wcscpy_s(menu_name, ARRAYSIZE(menu_name), localized_context_menu_item.c_str()); + + // cgaarden Hack refactor this code + MENUITEMINFO mii; + mii.cbSize = sizeof(MENUITEMINFO); + mii.fMask = MIIM_STRING | MIIM_FTYPE | MIIM_ID | MIIM_STATE; + mii.wID = menu_first_cmd_id++; + mii.fType = MFT_STRING; + mii.dwTypeData = (PWSTR)menu_name; + mii.fState = MFS_ENABLED; + + // icon from file + HICON local_icon_handle = static_cast(LoadImage(module_instance_handle, MAKEINTRESOURCE(IDI_NEWPLUS_ICON), IMAGE_ICON, 16, 16, 0)); + if (local_icon_handle) + { + mii.fMask |= MIIM_BITMAP; + if (icon_handle == NULL) + { + icon_handle = CreateBitmapFromIcon(local_icon_handle); + } + mii.hbmpItem = icon_handle; + DestroyIcon(local_icon_handle); + } + + // cgaarden hack + if (!InsertMenuItem(menu_handle, menu_index, TRUE, &mii)) + { + hr = HRESULT_FROM_WIN32(GetLastError()); + } + else + { + // cgaarden what does MAKE_HRESULT do? Why not just set to S_OK? + hr = MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, 1); + } + } + + if (hr != S_OK) + { + // cgaarden Log error, if not S_SUCCESS + + } + + return hr; +} + +IFACEMETHODIMP shell_context_menu_win10::InvokeCommand(CMINVOKECOMMANDINFO* pici) +{ + return E_NOTIMPL; } -IFACEMETHODIMP shell_context_menu::GetSite(_In_ REFIID riid, _COM_Outptr_ void** returned_site) noexcept + +IFACEMETHODIMP shell_context_menu_win10::GetCommandString(UINT_PTR idCmd, UINT uType, UINT* pReserved, CHAR* pszName, UINT cchMax) { - return this->site_of_folder.CopyTo(riid, returned_site); + return E_NOTIMPL; } #pragma endregion + diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/shell_context_menu_win10.h b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/shell_context_menu_win10.h index 564069254d37..376d84febf95 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/shell_context_menu_win10.h +++ b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/shell_context_menu_win10.h @@ -4,16 +4,21 @@ using namespace Microsoft::WRL; -#define NEW_SHELL_EXTENSION_EXPLORER_COMMAND_UUID_STR "69824FC6-4660-4A09-9E7C-48DA63C6CC0F" +#define NEW_SHELL_EXTENSION_EXPLORER_COMMAND_WIN10_UUID_STR "FF90D477-E32A-4BE8-8CC5-A502A97F5401" -// File Explorer context menu "New+" -class __declspec(uuid(NEW_SHELL_EXTENSION_EXPLORER_COMMAND_UUID_STR)) shell_context_menu final : +// File Explorer context menu "New+" for Windows 10 +class __declspec(uuid(NEW_SHELL_EXTENSION_EXPLORER_COMMAND_WIN10_UUID_STR)) shell_context_menu_win10 final : public RuntimeClass< RuntimeClassFlags, + IShellExtInit, IExplorerCommand, - IObjectWithSite> + IContextMenu> { public: +#pragma region IShellExtInit + IFACEMETHODIMP Initialize(_In_opt_ PCIDLIST_ABSOLUTE, _In_ IDataObject* site, HKEY); +#pragma endregion + #pragma region IExplorerCommand IFACEMETHODIMP GetTitle(_In_opt_ IShellItemArray*, _Outptr_result_nullonfailure_ PWSTR* returned_title); IFACEMETHODIMP GetIcon(_In_opt_ IShellItemArray*, _Outptr_result_nullonfailure_ PWSTR* returned_icon); @@ -25,13 +30,15 @@ class __declspec(uuid(NEW_SHELL_EXTENSION_EXPLORER_COMMAND_UUID_STR)) shell_cont IFACEMETHODIMP EnumSubCommands(_COM_Outptr_ IEnumExplorerCommand** returned_enum_commands); #pragma endregion -#pragma region IObjectWithSite - IFACEMETHODIMP SetSite(_In_ IUnknown* site) noexcept; - - IFACEMETHODIMP GetSite(_In_ REFIID riid, _COM_Outptr_ void** site) noexcept; +#pragma region IContextMenu + IFACEMETHODIMP QueryContextMenu(HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags) override; + IFACEMETHODIMP InvokeCommand(CMINVOKECOMMANDINFO* pici) override; + IFACEMETHODIMP GetCommandString(UINT_PTR idCmd, UINT uType, UINT* pReserved, CHAR* pszName, UINT cchMax) override; #pragma endregion protected: HINSTANCE instance_handle = 0; - ComPtr site_of_folder; + HBITMAP icon_handle = nullptr; + + ComPtr site_of_folder; }; From aae4c3651d85d76d0be0e9c339fb0a989c87bfed Mon Sep 17 00:00:00 2001 From: Christian Gaarden Gaardmark Date: Sun, 27 Oct 2024 17:34:09 -0700 Subject: [PATCH 03/24] Dll now builds --- .../NewPlus.ShellExtension.win10.vcxproj | 76 ++++++++++++++++--- ...wPlus.ShellExtension.win10.vcxproj.filters | 64 ++++++++++++++-- .../dll.def | 5 ++ .../dll_main.cpp | 14 ++-- .../dll_main.h | 6 ++ .../new.base.rc | 64 ++++++++-------- .../packages.config | 3 +- .../pch.cpp | 2 - .../NewShellExtensionContextMenu.win10/pch.h | 2 + .../resource.base.h | 2 +- 10 files changed, 179 insertions(+), 59 deletions(-) create mode 100644 src/modules/NewPlus/NewShellExtensionContextMenu.win10/dll.def create mode 100644 src/modules/NewPlus/NewShellExtensionContextMenu.win10/dll_main.h diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/NewPlus.ShellExtension.win10.vcxproj b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/NewPlus.ShellExtension.win10.vcxproj index 1fad7ea3d04a..a9af1231f46f 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/NewPlus.ShellExtension.win10.vcxproj +++ b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/NewPlus.ShellExtension.win10.vcxproj @@ -1,6 +1,5 @@ - @@ -103,12 +102,34 @@ - PowerToys.NewPlus.ShellExtension.win10 ..\..\..\..\$(Platform)\$(Configuration)\WinUI3Apps\ + PowerToys.NewPlus.ShellExtension.win10 + $(SolutionDir)$(Platform)\$(Configuration)\TemporaryBuild\obj\$(ProjectName)\ + + - PowerToys.NewPlus.ShellExtension.win10 ..\..\..\..\$(Platform)\$(Configuration)\WinUI3Apps\ + PowerToys.NewPlus.ShellExtension.win10 + $(SolutionDir)$(Platform)\$(Configuration)\TemporaryBuild\obj\$(ProjectName)\ + + + + + + PowerToys.NewPlus.ShellExtension.win10 + + + + PowerToys.NewPlus.ShellExtension.win10 + + + + PowerToys.NewPlus.ShellExtension.win10 + + + + PowerToys.NewPlus.ShellExtension.win10 @@ -117,13 +138,16 @@ WIN32;_DEBUG;NEWPLUSSHELLEXTENSIONWIN10_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) true Use + pch.h + stdcpplatest ..\..\..\common\Telemetry;..\..\;..\..\..\;%(AdditionalIncludeDirectories);..\NewShellExtensionContextMenu - false Windows true false + dll.def + runtimeobject.lib;$(CoreLibraryDependencies) @@ -144,6 +168,8 @@ true true false + dll.def + runtimeobject.lib;$(CoreLibraryDependencies) @@ -160,6 +186,7 @@ Windows true false + runtimeobject.lib;$(CoreLibraryDependencies) @@ -180,6 +207,7 @@ true true false + runtimeobject.lib;$(CoreLibraryDependencies) @@ -196,6 +224,7 @@ Windows true false + runtimeobject.lib;$(CoreLibraryDependencies) @@ -216,15 +245,32 @@ true true false + runtimeobject.lib;$(CoreLibraryDependencies) + + + + + + + + + + + + + + + + Create @@ -238,34 +284,40 @@ - + - + + Designer + - - {d9b8fc84-322a-4f9f-bbb9-20915c47ddfd} - {6955446d-23f7-4023-9bb3-8657f904af99} + + {8f021b46-362b-485c-bfba-ccf83e820cbd} + {98537082-0fdb-40de-abd8-0dc5a4269bab} + + - + + 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/src/modules/NewPlus/NewShellExtensionContextMenu.win10/NewPlus.ShellExtension.win10.vcxproj.filters b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/NewPlus.ShellExtension.win10.vcxproj.filters index 2e71337bbf6c..1c737dac12c2 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/NewPlus.ShellExtension.win10.vcxproj.filters +++ b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/NewPlus.ShellExtension.win10.vcxproj.filters @@ -30,6 +30,33 @@ Generated Files + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + @@ -41,21 +68,46 @@ Source Files + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + - - Resource Files - Generated Files - + + + Source Files + + Resource Files - + + + Resource Files + - + \ No newline at end of file diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/dll.def b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/dll.def new file mode 100644 index 000000000000..f306dc6c1345 --- /dev/null +++ b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/dll.def @@ -0,0 +1,5 @@ +LIBRARY +EXPORTS +DllCanUnloadNow PRIVATE +DllGetClassObject PRIVATE +DllGetActivationFactory PRIVATE diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/dll_main.cpp b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/dll_main.cpp index 48c1509e4a42..877e8dfefda4 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/dll_main.cpp +++ b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/dll_main.cpp @@ -1,9 +1,13 @@ -// dllmain.cpp : Defines the entry point for the DLL application. #include "pch.h" #include "shell_context_menu_win10.h" +#include "dll_main.h" +#include "trace.h" + +#include HMODULE module_instance_handle = 0; +Shared::Trace::ETWTrace trace(L"NewPlusShellExtensionWin10"); BOOL APIENTRY DllMain(HMODULE module_handle, DWORD ul_reason_for_call, LPVOID reserved) { @@ -11,12 +15,12 @@ BOOL APIENTRY DllMain(HMODULE module_handle, DWORD ul_reason_for_call, LPVOID re { case DLL_PROCESS_ATTACH: module_instance_handle = module_handle; - // Trace::RegisterProvider(); - // newplus::utilities::init_logger(); + Trace::RegisterProvider(); + newplus::utilities::init_logger(); break; case DLL_PROCESS_DETACH: - // Trace::UnregisterProvider(); + Trace::UnregisterProvider(); break; } return TRUE; @@ -37,4 +41,4 @@ STDAPI DllGetClassObject(_In_ REFCLSID rclsid, _In_ REFIID riid, _Outptr_ LPVOID return Module::GetModule().GetClassObject(rclsid, riid, ppv); } -CoCreatableClass(shell_context_menu) +CoCreatableClass(shell_context_menu_win10) diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/dll_main.h b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/dll_main.h new file mode 100644 index 000000000000..9e980caa0db5 --- /dev/null +++ b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/dll_main.h @@ -0,0 +1,6 @@ +#pragma once + +#include + +extern HMODULE module_instance_handle; +extern Shared::Trace::ETWTrace trace; \ No newline at end of file diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/new.base.rc b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/new.base.rc index 8cb286b60627..90f26c856728 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/new.base.rc +++ b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/new.base.rc @@ -6,38 +6,38 @@ #include "winres.h" #undef APSTUDIO_READONLY_SYMBOLS -1 VERSIONINFO - FILEVERSION FILE_VERSION - PRODUCTVERSION PRODUCT_VERSION - FILEFLAGSMASK VS_FFI_FILEFLAGSMASK -#ifdef _DEBUG - FILEFLAGS VS_FF_DEBUG -#else - FILEFLAGS 0x0L -#endif - FILEOS VOS_NT_WINDOWS32 - FILETYPE VFT_DLL - FILESUBTYPE VFT2_UNKNOWN -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904b0" - BEGIN - VALUE "CompanyName", COMPANY_NAME - VALUE "FileDescription", FILE_DESCRIPTION - VALUE "FileVersion", FILE_VERSION_STRING - VALUE "InternalName", INTERNAL_NAME - VALUE "LegalCopyright", COPYRIGHT_NOTE - VALUE "OriginalFilename", ORIGINAL_FILENAME - VALUE "ProductName", PRODUCT_NAME - VALUE "ProductVersion", PRODUCT_VERSION_STRING - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1200 - END -END +//1 VERSIONINFO +// FILEVERSION FILE_VERSION +// PRODUCTVERSION PRODUCT_VERSION +// FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +//#ifdef _DEBUG +// FILEFLAGS VS_FF_DEBUG +//#else +// FILEFLAGS 0x0L +//#endif +// FILEOS VOS_NT_WINDOWS32 +// FILETYPE VFT_DLL +// FILESUBTYPE VFT2_UNKNOWN +//BEGIN +// BLOCK "StringFileInfo" +// BEGIN +// BLOCK "040904b0" +// BEGIN +// VALUE "CompanyName", COMPANY_NAME +// VALUE "FileDescription", FILE_DESCRIPTION +// VALUE "FileVersion", FILE_VERSION_STRING +// VALUE "InternalName", INTERNAL_NAME +// VALUE "LegalCopyright", COPYRIGHT_NOTE +// VALUE "OriginalFilename", ORIGINAL_FILENAME +// VALUE "ProductName", PRODUCT_NAME +// VALUE "ProductVersion", PRODUCT_VERSION_STRING +// END +// END +// BLOCK "VarFileInfo" +// BEGIN +// VALUE "Translation", 0x409, 1200 +// END +//END ///////////////////////////////////////////////////////////////////////////// // diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/packages.config b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/packages.config index 7a9561b2b504..ff4b05964868 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/packages.config +++ b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/packages.config @@ -1,4 +1,5 @@  - + + \ No newline at end of file diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/pch.cpp b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/pch.cpp index 64b7eef6d6b9..1a6a81e23883 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/pch.cpp +++ b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/pch.cpp @@ -1,5 +1,3 @@ // 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/src/modules/NewPlus/NewShellExtensionContextMenu.win10/pch.h b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/pch.h index 981209e500e4..3ddfa219b227 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/pch.h +++ b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/pch.h @@ -20,7 +20,9 @@ #include #include #include +#include #include +using namespace Microsoft::WRL; // PowerToys project common #include diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/resource.base.h b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/resource.base.h index 7adcb35adce0..113546d90960 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/resource.base.h +++ b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/resource.base.h @@ -6,7 +6,7 @@ #define FILE_DESCRIPTION "PowerToys.New+" #define INTERNAL_NAME "PowerToys.New+" -#define ORIGINAL_FILENAME "PowerToys.NewPlus.ShellExtension.dll" +#define ORIGINAL_FILENAME "PowerToys.NewPlus.ShellExtension.win10.dll" #define IDI_NEWPLUS_ICON 1001 // Non-localizable From fe549466c52ed69726beffd9ba3a08d7b6a7d8d8 Mon Sep 17 00:00:00 2001 From: Christian Gaarden Gaardmark Date: Mon, 28 Oct 2024 20:38:00 -0700 Subject: [PATCH 04/24] Updated installer - not tested --- installer/PowerToysSetup/NewPlus.wxs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/installer/PowerToysSetup/NewPlus.wxs b/installer/PowerToysSetup/NewPlus.wxs index 80fd5a94f4e2..c617225600ed 100644 --- a/installer/PowerToysSetup/NewPlus.wxs +++ b/installer/PowerToysSetup/NewPlus.wxs @@ -18,6 +18,19 @@ + + + + + + + + + + + + + From 923b335cf927c9d478b7adca249a820896b3e638 Mon Sep 17 00:00:00 2001 From: Christian Gaarden Gaardmark Date: Mon, 28 Oct 2024 20:40:10 -0700 Subject: [PATCH 05/24] Changed output dir --- .../NewPlus.ShellExtension.win10.vcxproj | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/NewPlus.ShellExtension.win10.vcxproj b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/NewPlus.ShellExtension.win10.vcxproj index a9af1231f46f..18c1c48ae3d5 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/NewPlus.ShellExtension.win10.vcxproj +++ b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/NewPlus.ShellExtension.win10.vcxproj @@ -104,32 +104,38 @@ ..\..\..\..\$(Platform)\$(Configuration)\WinUI3Apps\ PowerToys.NewPlus.ShellExtension.win10 - $(SolutionDir)$(Platform)\$(Configuration)\TemporaryBuild\obj\$(ProjectName)\ + $(Platform)\$(Configuration)\ ..\..\..\..\$(Platform)\$(Configuration)\WinUI3Apps\ PowerToys.NewPlus.ShellExtension.win10 - $(SolutionDir)$(Platform)\$(Configuration)\TemporaryBuild\obj\$(ProjectName)\ + $(Platform)\$(Configuration)\ PowerToys.NewPlus.ShellExtension.win10 + ..\..\..\..\$(Platform)\$(Configuration)\WinUI3Apps\ + $(Platform)\$(Configuration)\ PowerToys.NewPlus.ShellExtension.win10 + ..\..\..\..\$(Platform)\$(Configuration)\WinUI3Apps\ + $(Platform)\$(Configuration)\ PowerToys.NewPlus.ShellExtension.win10 + ..\..\..\..\$(Platform)\$(Configuration)\WinUI3Apps\ PowerToys.NewPlus.ShellExtension.win10 + ..\..\..\..\$(Platform)\$(Configuration)\WinUI3Apps\ From 5a997aa2c0171f181866bbade41e9d0ec79ab064 Mon Sep 17 00:00:00 2001 From: Christian Gaarden Gaardmark Date: Mon, 28 Oct 2024 20:43:31 -0700 Subject: [PATCH 06/24] Clean up --- installer/PowerToysSetup/NewPlus.wxs | 1 + 1 file changed, 1 insertion(+) diff --git a/installer/PowerToysSetup/NewPlus.wxs b/installer/PowerToysSetup/NewPlus.wxs index c617225600ed..4dd1c677010e 100644 --- a/installer/PowerToysSetup/NewPlus.wxs +++ b/installer/PowerToysSetup/NewPlus.wxs @@ -40,6 +40,7 @@ + From d4d456a848bef3518d24d5e5f85507a0e8c48884 Mon Sep 17 00:00:00 2001 From: Christian Gaarden Gaardmark Date: Mon, 4 Nov 2024 19:15:43 -0800 Subject: [PATCH 07/24] Initial win10 support is now working --- .../NewPlus.ShellExtension.win10.vcxproj | 8 + .../dll.def | 9 +- .../dll_main.cpp | 10 +- .../shell_context_menu_win10.cpp | 333 +++++++++++++----- .../shell_context_menu_win10.h | 38 +- .../new_utilities.h | 29 ++ .../shell_context_menu.cpp | 11 +- .../shell_context_menu.h | 2 +- .../shell_context_sub_menu.cpp | 4 +- .../shell_context_sub_menu.h | 3 +- .../shell_context_sub_menu_item.cpp | 10 +- .../shell_context_sub_menu_item.h | 4 +- .../template_folder.cpp | 5 + .../template_folder.h | 2 + .../template_item.cpp | 41 ++- .../template_item.h | 6 +- .../NewShellExtensionContextMenu/trace.cpp | 9 + .../NewShellExtensionContextMenu/trace.h | 1 + 18 files changed, 372 insertions(+), 153 deletions(-) diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/NewPlus.ShellExtension.win10.vcxproj b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/NewPlus.ShellExtension.win10.vcxproj index 18c1c48ae3d5..71d4c9355000 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/NewPlus.ShellExtension.win10.vcxproj +++ b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/NewPlus.ShellExtension.win10.vcxproj @@ -120,22 +120,26 @@ PowerToys.NewPlus.ShellExtension.win10 ..\..\..\..\$(Platform)\$(Configuration)\WinUI3Apps\ $(Platform)\$(Configuration)\ + PowerToys.NewPlus.ShellExtension.win10 ..\..\..\..\$(Platform)\$(Configuration)\WinUI3Apps\ $(Platform)\$(Configuration)\ + PowerToys.NewPlus.ShellExtension.win10 ..\..\..\..\$(Platform)\$(Configuration)\WinUI3Apps\ + PowerToys.NewPlus.ShellExtension.win10 ..\..\..\..\$(Platform)\$(Configuration)\WinUI3Apps\ + @@ -193,6 +197,7 @@ true false runtimeobject.lib;$(CoreLibraryDependencies) + dll.def @@ -214,6 +219,7 @@ true false runtimeobject.lib;$(CoreLibraryDependencies) + dll.def @@ -231,6 +237,7 @@ true false runtimeobject.lib;$(CoreLibraryDependencies) + dll.def @@ -252,6 +259,7 @@ true false runtimeobject.lib;$(CoreLibraryDependencies) + dll.def diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/dll.def b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/dll.def index f306dc6c1345..98766b8e2823 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/dll.def +++ b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/dll.def @@ -1,5 +1,6 @@ LIBRARY -EXPORTS -DllCanUnloadNow PRIVATE -DllGetClassObject PRIVATE -DllGetActivationFactory PRIVATE + +EXPORTS + DllGetClassObject PRIVATE + DllCanUnloadNow PRIVATE + DllGetActivationFactory PRIVATE \ No newline at end of file diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/dll_main.cpp b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/dll_main.cpp index 877e8dfefda4..edc46745ed52 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/dll_main.cpp +++ b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/dll_main.cpp @@ -15,12 +15,12 @@ BOOL APIENTRY DllMain(HMODULE module_handle, DWORD ul_reason_for_call, LPVOID re { case DLL_PROCESS_ATTACH: module_instance_handle = module_handle; - Trace::RegisterProvider(); - newplus::utilities::init_logger(); + //Trace::RegisterProvider(); + //newplus::utilities::init_logger(); break; case DLL_PROCESS_DETACH: - Trace::UnregisterProvider(); + //Trace::UnregisterProvider(); break; } return TRUE; @@ -42,3 +42,7 @@ STDAPI DllGetClassObject(_In_ REFCLSID rclsid, _In_ REFIID riid, _Outptr_ LPVOID } CoCreatableClass(shell_context_menu_win10) + + +// cgaarden remove +CoCreatableClassWrlCreatorMapInclude(shell_context_menu_win10) diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/shell_context_menu_win10.cpp b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/shell_context_menu_win10.cpp index a10d375d6fe8..57163ef8caac 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/shell_context_menu_win10.cpp +++ b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/shell_context_menu_win10.cpp @@ -3,167 +3,306 @@ #include "shell_context_menu_win10.h" #include "shell_context_sub_menu.h" #include "shell_context_sub_menu_item.h" -#include "template_folder.h" #include "new_utilities.h" #include "settings.h" #include "trace.h" #include "Generated Files/resource.h" #include +#include +#include +#pragma comment(lib, "gdiplus.lib") +using namespace Gdiplus; + using namespace Microsoft::WRL; using namespace newplus; -#pragma region IShellExtInit -IFACEMETHODIMP shell_context_menu_win10::Initialize(PCIDLIST_ABSOLUTE, IDataObject* site, HKEY) +shell_context_menu_win10::~shell_context_menu_win10() { -// cgaarden HACK UPDATE - if (!NewSettingsInstance().GetEnabled()) + for (const auto& handle : bitmap_handles) { - return E_FAIL; + DeleteObject(handle); } +} + - if (site) // cgaarden NOT sure +#pragma region IShellExtInit +IFACEMETHODIMP shell_context_menu_win10::Initialize(PCIDLIST_ABSOLUTE, IDataObject*, HKEY) +{ + // cgaarden HACK UPDATE- -- also check for whether win10 or not + if (!NewSettingsInstance().GetEnabled()) { - site_of_folder = site; + return E_FAIL; } return S_OK; } #pragma endregion -#pragma region IExplorerCommand -// cgaarden Hack is this interface actually called on Win10???? Why the duplication???? -IFACEMETHODIMP shell_context_menu_win10::GetTitle(_In_opt_ IShellItemArray*, _Outptr_result_nullonfailure_ PWSTR* returned_title) +#pragma region IContextMenu +IFACEMETHODIMP shell_context_menu_win10::QueryContextMenu(HMENU menu_handle, UINT menu_index, UINT menu_first_cmd_id, UINT menu_last_cmd_id, UINT menu_flags) { + // cgaarden Update to NOT show Win10 menu when on Windows 11++ + if (!NewSettingsInstance().GetEnabled()) + { + return E_FAIL; + } + + if (menu_flags & CMF_DEFAULTONLY) + { + return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, 0); + } + + trace.UpdateState(true); + + const auto icon_x = GetSystemMetrics(SM_CXSMICON); + const auto icon_y = GetSystemMetrics(SM_CYSMICON); + + // Create the initial context popup menu containing the list of templates and open templates action + HMENU sub_menu_of_templates = CreatePopupMenu(); + int menu_id = menu_first_cmd_id; + int sub_menu_index = 0; + + // Create the New+ menu item and point to the initial context popup menu static const std::wstring localized_context_menu_item = GET_RESOURCE_STRING_FALLBACK(IDS_CONTEXT_MENU_ITEM_NEW, L"New+"); + wchar_t newplus_menu_name[20] = { 0 }; + wcscpy_s(newplus_menu_name, ARRAYSIZE(newplus_menu_name), localized_context_menu_item.c_str()); + MENUITEMINFO newplus_menu_item; + newplus_menu_item.cbSize = sizeof(MENUITEMINFO); + newplus_menu_item.fMask = MIIM_STRING | MIIM_FTYPE | MIIM_ID | MIIM_SUBMENU; + newplus_menu_item.wID = menu_id; + newplus_menu_item.fType = MFT_STRING; + newplus_menu_item.dwTypeData = (PWSTR)newplus_menu_name; + newplus_menu_item.hSubMenu = sub_menu_of_templates; + const auto newplus_icon_index = 0; - return SHStrDup(localized_context_menu_item.c_str(), returned_title); -} + if (bitmap_handles.size() == 0) + { + const std::wstring icon_file = utilities::get_new_icon_resource_filepath(module_instance_handle, ThemeHelpers::GetAppTheme()).c_str(); + HICON local_icon_handle = static_cast(LoadImage(NULL, icon_file.c_str(), IMAGE_ICON, icon_x, icon_y, LR_LOADFROMFILE)); -IFACEMETHODIMP shell_context_menu_win10::GetIcon(_In_opt_ IShellItemArray*, _Outptr_result_nullonfailure_ PWSTR* returned_icon) -{ - *returned_icon = nullptr; + if (local_icon_handle) + { + bitmap_handles.push_back(CreateBitmapFromIcon(local_icon_handle)); + DestroyIcon(local_icon_handle); + } + } + if (bitmap_handles.size() > newplus_icon_index && bitmap_handles[newplus_icon_index]) + { + newplus_menu_item.fMask |= MIIM_BITMAP; + newplus_menu_item.hbmpItem = bitmap_handles[newplus_icon_index]; + } - static const auto icon_resource_filepath = utilities::get_new_icon_resource_filepath(module_instance_handle, ThemeHelpers::GetAppTheme()); + menu_id++; - return SHStrDup(icon_resource_filepath.c_str(), returned_icon); -} + // Determine the New+ Template folder location + const std::filesystem::path template_folder_root = utilities::get_new_template_folder_location(); -IFACEMETHODIMP shell_context_menu_win10::GetToolTip(_In_opt_ IShellItemArray*, _Outptr_result_nullonfailure_ PWSTR* returned_tool_tip) -{ - *returned_tool_tip = nullptr; - return E_NOTIMPL; -} + // Create the New+ Template folder location if it doesn't exist (very rare scenario) + utilities::create_folder_if_not_exist(template_folder_root); -IFACEMETHODIMP shell_context_menu_win10::GetCanonicalName(_Out_ GUID* returned_id) -{ - *returned_id = __uuidof(this); - return S_OK; -} + // Scan the folder for any files and folders (the templates) + templates = new template_folder(template_folder_root); + templates->rescan_template_folder(); -IFACEMETHODIMP shell_context_menu_win10::GetState(_In_opt_ IShellItemArray*, _In_ BOOL, _Out_ EXPCMDSTATE* returned_state) -{ - if (!NewSettingsInstance().GetEnabled()) + // Add template items to context menu + const auto number_of_templates = templates->list_of_templates.size(); + int index = 0; + for (; index < number_of_templates; index++) { - *returned_state = ECS_HIDDEN; + const auto template_item = templates->get_template_item(index); + wchar_t menu_name[256] = { 0 }; + wcscpy_s(menu_name, ARRAYSIZE(menu_name), template_item->get_menu_title(!utilities::get_newplus_setting_hide_extension(), !utilities::get_newplus_setting_hide_starting_digits()).c_str()); + MENUITEMINFO newplus_menu_item_template; + newplus_menu_item_template.cbSize = sizeof(MENUITEMINFO); + newplus_menu_item_template.fMask = MIIM_STRING | MIIM_FTYPE | MIIM_ID | MIIM_DATA; + newplus_menu_item_template.wID = menu_id; + newplus_menu_item_template.fType = MFT_STRING; + newplus_menu_item_template.dwTypeData = (PWSTR)menu_name; + const auto current_template_icon_index = index + 1; + if (bitmap_handles.size() <= current_template_icon_index) + { + HICON template_icon_handle = template_item->get_explorer_icon_handle(); + if (template_icon_handle) + { + bitmap_handles.push_back(CreateBitmapFromIcon(template_icon_handle)); + DestroyIcon(template_icon_handle); + } + } + if (bitmap_handles.size() > current_template_icon_index && bitmap_handles[current_template_icon_index]) + { + newplus_menu_item_template.fMask |= MIIM_BITMAP; + newplus_menu_item_template.hbmpItem = bitmap_handles[current_template_icon_index]; + } + + InsertMenuItem(sub_menu_of_templates, sub_menu_index, TRUE, &newplus_menu_item_template); + menu_id++; + sub_menu_index++; } - else + + + // Add separator to context menu + MENUITEMINFO menu_item_separator; + menu_item_separator.cbSize = sizeof(MENUITEMINFO); + menu_item_separator.fMask = MIIM_FTYPE; + menu_item_separator.fType = MFT_SEPARATOR; + InsertMenuItem(sub_menu_of_templates, sub_menu_index, TRUE, &menu_item_separator); + sub_menu_index++; + + // Add "Open templates" item to context menu + static const std::wstring localized_context_menu_item_open_templates = + GET_RESOURCE_STRING_FALLBACK(IDS_CONTEXT_MENU_ITEM_OPEN_TEMPLATES, L"Open templates"); + wchar_t menu_name_open[256] = { 0 }; + wcscpy_s(menu_name_open, ARRAYSIZE(menu_name_open), localized_context_menu_item_open_templates.c_str()); + const auto open_folder_item = Make(template_folder_root); + MENUITEMINFO newplus_menu_item_open_templates; + newplus_menu_item_open_templates.cbSize = sizeof(MENUITEMINFO); + newplus_menu_item_open_templates.fMask = MIIM_STRING | MIIM_FTYPE | MIIM_ID; + newplus_menu_item_open_templates.wID = menu_id; + newplus_menu_item_open_templates.fType = MFT_STRING; + newplus_menu_item_open_templates.dwTypeData = (PWSTR)menu_name_open; + + const auto open_templates_icon_index = index + 1; + if (bitmap_handles.size() <= open_templates_icon_index) + { + const std::wstring icon_file = utilities::get_open_templates_icon_resource_filepath(module_instance_handle, ThemeHelpers::GetAppTheme()).c_str(); + HICON open_template_icon_handle = static_cast(LoadImage(NULL, icon_file.c_str(), IMAGE_ICON, icon_x, icon_y, LR_LOADFROMFILE)); + if (open_template_icon_handle) + { + bitmap_handles.push_back(CreateBitmapFromIcon(open_template_icon_handle)); + DestroyIcon(open_template_icon_handle); + } + } + if (bitmap_handles.size() > open_templates_icon_index && bitmap_handles[open_templates_icon_index]) { - *returned_state = ECS_ENABLED; + newplus_menu_item_open_templates.fMask |= MIIM_BITMAP; + newplus_menu_item_open_templates.hbmpItem = bitmap_handles[open_templates_icon_index]; } - return S_OK; -} + InsertMenuItem(sub_menu_of_templates, sub_menu_index, TRUE, &newplus_menu_item_open_templates); + menu_id++; -IFACEMETHODIMP shell_context_menu_win10::Invoke(_In_opt_ IShellItemArray*, _In_opt_ IBindCtx*) noexcept -{ - return E_NOTIMPL; -} -IFACEMETHODIMP shell_context_menu_win10::GetFlags(_Out_ EXPCMDFLAGS* returned_menu_item_flags) -{ - *returned_menu_item_flags = ECF_HASSUBCOMMANDS; - return S_OK; -} + // Log that context menu was shown and with how many items + Trace::EventShowTemplateItems(number_of_templates); -IFACEMETHODIMP shell_context_menu_win10::EnumSubCommands(_COM_Outptr_ IEnumExplorerCommand** returned_enum_commands) -{ - auto e = Make(site_of_folder); - return e->QueryInterface(IID_PPV_ARGS(returned_enum_commands)); + trace.Flush(); + trace.UpdateState(false); + + if (!InsertMenuItem(menu_handle, menu_index, TRUE, &newplus_menu_item)) + { + return HRESULT_FROM_WIN32(GetLastError()); + // cgaarden Log error, if not S_SUCCESS + } + else + { + const auto number_of_items_inserted = menu_id - menu_first_cmd_id; + return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, number_of_items_inserted); + } } -#pragma endregion -#pragma region IContextMenu -IFACEMETHODIMP shell_context_menu_win10::QueryContextMenu(HMENU menu_handle, UINT menu_index, UINT menu_first_cmd_id, UINT, UINT menu_flags) +IFACEMETHODIMP shell_context_menu_win10::InvokeCommand(CMINVOKECOMMANDINFO* params) { - if (!NewSettingsInstance().GetEnabled()) + if (!params) { return E_FAIL; } - // cgaarden NOT SURE what state of site_of_folder is - // cgaarden Update to NOT show Win10 menu when on Windows 11++ - HRESULT hr = E_UNEXPECTED; - if (site_of_folder && !(menu_flags & (CMF_DEFAULTONLY | CMF_VERBSONLY | CMF_OPTIMIZEFORINVOKE))) - { - static const std::wstring localized_context_menu_item = - GET_RESOURCE_STRING_FALLBACK(IDS_CONTEXT_MENU_ITEM_NEW, L"New+"); - - wchar_t menu_name[128] = { 0 }; - wcscpy_s(menu_name, ARRAYSIZE(menu_name), localized_context_menu_item.c_str()); - - // cgaarden Hack refactor this code - MENUITEMINFO mii; - mii.cbSize = sizeof(MENUITEMINFO); - mii.fMask = MIIM_STRING | MIIM_FTYPE | MIIM_ID | MIIM_STATE; - mii.wID = menu_first_cmd_id++; - mii.fType = MFT_STRING; - mii.dwTypeData = (PWSTR)menu_name; - mii.fState = MFS_ENABLED; - - // icon from file - HICON local_icon_handle = static_cast(LoadImage(module_instance_handle, MAKEINTRESOURCE(IDI_NEWPLUS_ICON), IMAGE_ICON, 16, 16, 0)); - if (local_icon_handle) + const auto selected_menu_item_index = LOWORD(params->lpVerb) - 1; + if (selected_menu_item_index < 0) + { + return E_FAIL; + } + + trace.UpdateState(true); + + HRESULT hr = S_OK; + const auto number_of_templates = templates->list_of_templates.size(); + const bool is_template_item = selected_menu_item_index < number_of_templates; + + if (is_template_item) + { + // it's a template item + + try { - mii.fMask |= MIIM_BITMAP; - if (icon_handle == NULL) + Logger::info(L"Copying template"); + + const auto template_entry = templates->get_template_item(selected_menu_item_index); + + // Determine target path of where context menu was displayed + const auto target_path_name = utilities::get_path_from_folder_view(target_folder_view); + + // Determine initial filename + std::filesystem::path source_fullpath = template_entry->path; + std::filesystem::path target_fullpath = std::wstring(target_path_name); + + // Only append name to target if source is not a directory + if (!utilities::is_directory(source_fullpath)) { - icon_handle = CreateBitmapFromIcon(local_icon_handle); + target_fullpath.append(template_entry->get_target_filename(!utilities::get_newplus_setting_hide_starting_digits())); } - mii.hbmpItem = icon_handle; - DestroyIcon(local_icon_handle); - } - // cgaarden hack - if (!InsertMenuItem(menu_handle, menu_index, TRUE, &mii)) - { - hr = HRESULT_FROM_WIN32(GetLastError()); + // Copy file and determine final filename + std::filesystem::path target_final_fullpath = template_entry->copy_object_to(GetActiveWindow(), target_fullpath); + + Trace::EventCopyTemplate(target_final_fullpath.extension().c_str()); + + // Refresh folder items + SHChangeNotify(SHCNE_CREATE, SHCNF_PATH | SHCNF_FLUSH, target_final_fullpath.wstring().c_str(), NULL); + + // Enter rename mode + template_entry->enter_rename_mode(target_folder_view, target_final_fullpath); + + Trace::EventCopyTemplateResult(S_OK); } - else + catch (const std::exception& ex) { - // cgaarden what does MAKE_HRESULT do? Why not just set to S_OK? - hr = MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, 1); + Trace::EventCopyTemplateResult(S_FALSE); + Logger::error(ex.what()); + + hr = S_FALSE; } } - - if (hr != S_OK) + else { - // cgaarden Log error, if not S_SUCCESS + // it's the "Open templates" item + Logger::info(L"Open templates folder"); + const std::filesystem::path template_folder_root = utilities::get_new_template_folder_location(); + const std::wstring verb_hardcoded_do_not_change = L"open"; + ShellExecute(nullptr, verb_hardcoded_do_not_change.c_str(), template_folder_root.c_str(), NULL, NULL, SW_SHOWNORMAL); + Trace::EventOpenTemplates(); } + trace.Flush(); + trace.UpdateState(false); + return hr; } -IFACEMETHODIMP shell_context_menu_win10::InvokeCommand(CMINVOKECOMMANDINFO* pici) +IFACEMETHODIMP shell_context_menu_win10::GetCommandString(UINT_PTR, UINT, UINT*, CHAR*, UINT) { return E_NOTIMPL; } +#pragma endregion -IFACEMETHODIMP shell_context_menu_win10::GetCommandString(UINT_PTR idCmd, UINT uType, UINT* pReserved, CHAR* pszName, UINT cchMax) +#pragma region IObjectWithSite +IFACEMETHODIMP shell_context_menu_win10::SetSite(_In_ IUnknown* site) noexcept { - return E_NOTIMPL; + if (site) + { + this->site_of_folder = site; + ComPtr service_provider; + site->QueryInterface(IID_PPV_ARGS(&service_provider)); + service_provider->QueryService(__uuidof(IFolderView), IID_PPV_ARGS(&target_folder_view)); + } + + return S_OK; +} +IFACEMETHODIMP shell_context_menu_win10::GetSite(_In_ REFIID riid, _COM_Outptr_ void** returned_site) noexcept +{ + return this->site_of_folder.CopyTo(riid, returned_site); } #pragma endregion - diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/shell_context_menu_win10.h b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/shell_context_menu_win10.h index 376d84febf95..468597b40f45 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/shell_context_menu_win10.h +++ b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/shell_context_menu_win10.h @@ -1,44 +1,42 @@ #pragma once #include "pch.h" +#include using namespace Microsoft::WRL; #define NEW_SHELL_EXTENSION_EXPLORER_COMMAND_WIN10_UUID_STR "FF90D477-E32A-4BE8-8CC5-A502A97F5401" // File Explorer context menu "New+" for Windows 10 -class __declspec(uuid(NEW_SHELL_EXTENSION_EXPLORER_COMMAND_WIN10_UUID_STR)) shell_context_menu_win10 final : +class __declspec(uuid(NEW_SHELL_EXTENSION_EXPLORER_COMMAND_WIN10_UUID_STR)) shell_context_menu_win10 : public RuntimeClass< RuntimeClassFlags, IShellExtInit, - IExplorerCommand, - IContextMenu> + IContextMenu, + IObjectWithSite> { public: + ~shell_context_menu_win10(); + #pragma region IShellExtInit - IFACEMETHODIMP Initialize(_In_opt_ PCIDLIST_ABSOLUTE, _In_ IDataObject* site, HKEY); + IFACEMETHODIMP Initialize(_In_opt_ PCIDLIST_ABSOLUTE, _In_ IDataObject*, HKEY); #pragma endregion -#pragma region IExplorerCommand - IFACEMETHODIMP GetTitle(_In_opt_ IShellItemArray*, _Outptr_result_nullonfailure_ PWSTR* returned_title); - IFACEMETHODIMP GetIcon(_In_opt_ IShellItemArray*, _Outptr_result_nullonfailure_ PWSTR* returned_icon); - IFACEMETHODIMP GetToolTip(_In_opt_ IShellItemArray*, _Outptr_result_nullonfailure_ PWSTR* returned_tool_tip); - IFACEMETHODIMP GetCanonicalName(_Out_ GUID* returned_id); - IFACEMETHODIMP GetState(_In_opt_ IShellItemArray*, _In_ BOOL, _Out_ EXPCMDSTATE* returned_state); - IFACEMETHODIMP Invoke(_In_opt_ IShellItemArray*, _In_opt_ IBindCtx*) noexcept; - IFACEMETHODIMP GetFlags(_Out_ EXPCMDFLAGS* returned_menu_item_flags); - IFACEMETHODIMP EnumSubCommands(_COM_Outptr_ IEnumExplorerCommand** returned_enum_commands); +#pragma region IContextMenu + IFACEMETHODIMP QueryContextMenu(HMENU menu_handle, UINT menu_index, UINT menu_first_cmd_id, UINT, UINT menu_flags); + IFACEMETHODIMP InvokeCommand(CMINVOKECOMMANDINFO* pici); + IFACEMETHODIMP GetCommandString(UINT_PTR, UINT, UINT*, CHAR*, UINT); #pragma endregion -#pragma region IContextMenu - IFACEMETHODIMP QueryContextMenu(HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags) override; - IFACEMETHODIMP InvokeCommand(CMINVOKECOMMANDINFO* pici) override; - IFACEMETHODIMP GetCommandString(UINT_PTR idCmd, UINT uType, UINT* pReserved, CHAR* pszName, UINT cchMax) override; +#pragma region IObjectWithSite + IFACEMETHODIMP SetSite(_In_ IUnknown* site) noexcept; + IFACEMETHODIMP GetSite(_In_ REFIID riid, _COM_Outptr_ void** site) noexcept; #pragma endregion protected: HINSTANCE instance_handle = 0; - HBITMAP icon_handle = nullptr; - - ComPtr site_of_folder; + ComPtr site_of_folder; + ComPtr target_folder_view; + newplus::template_folder* templates = nullptr; + std::vector bitmap_handles; }; diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu/new_utilities.h b/src/modules/NewPlus/NewShellExtensionContextMenu/new_utilities.h index 7ae46635a85e..c8e7039fc340 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu/new_utilities.h +++ b/src/modules/NewPlus/NewShellExtensionContextMenu/new_utilities.h @@ -39,6 +39,35 @@ namespace newplus::utilities return icon_resource; } + inline HICON get_explorer_icon_handle(std::filesystem::path path) + { + SHFILEINFO shell_file_info = { 0 }; + const std::wstring filepath = path.wstring(); + DWORD_PTR result = SHGetFileInfo(filepath.c_str(), 0, &shell_file_info, sizeof(shell_file_info), SHGFI_ICON); + if (shell_file_info.hIcon) + { + return shell_file_info.hIcon; + } + + +// cgaarden todo/Hack not tested!!! + WCHAR icon_resource_specifier[MAX_PATH] = { 0 }; + DWORD buffer_length = MAX_PATH; + const std::wstring extension = path.extension().wstring(); + const HRESULT hr = AssocQueryString(ASSOCF_INIT_IGNOREUNKNOWN, + ASSOCSTR_DEFAULTICON, + extension.c_str(), + NULL, + icon_resource_specifier, + &buffer_length); + const std::wstring icon_resource = icon_resource_specifier; + + const auto icon_x = GetSystemMetrics(SM_CXSMICON); + const auto icon_y = GetSystemMetrics(SM_CYSMICON); + HICON hIcon = static_cast(LoadImage(NULL, icon_resource.c_str(), IMAGE_ICON, icon_x, icon_y, LR_LOADFROMFILE)); + return hIcon; + } + inline bool is_hidden(const std::filesystem::path path) { const std::filesystem::path::string_type name = path.filename(); diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu/shell_context_menu.cpp b/src/modules/NewPlus/NewShellExtensionContextMenu/shell_context_menu.cpp index b3bf2992d5f1..3ed3011a5049 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu/shell_context_menu.cpp +++ b/src/modules/NewPlus/NewShellExtensionContextMenu/shell_context_menu.cpp @@ -69,7 +69,7 @@ IFACEMETHODIMP shell_context_menu::GetFlags(_Out_ EXPCMDFLAGS* returned_menu_ite IFACEMETHODIMP shell_context_menu::EnumSubCommands(_COM_Outptr_ IEnumExplorerCommand** returned_enum_commands) { - auto e = Make(site_of_folder); + auto e = Make(target_folder_view); return e->QueryInterface(IID_PPV_ARGS(returned_enum_commands)); } #pragma endregion @@ -77,7 +77,14 @@ IFACEMETHODIMP shell_context_menu::EnumSubCommands(_COM_Outptr_ IEnumExplorerCom #pragma region IObjectWithSite IFACEMETHODIMP shell_context_menu::SetSite(_In_ IUnknown* site) noexcept { - this->site_of_folder = site; + if (site) + { + this->site_of_folder = site; + ComPtr service_provider; + site->QueryInterface(IID_PPV_ARGS(&service_provider)); + service_provider->QueryService(__uuidof(IFolderView), IID_PPV_ARGS(&target_folder_view)); + } + return S_OK; } IFACEMETHODIMP shell_context_menu::GetSite(_In_ REFIID riid, _COM_Outptr_ void** returned_site) noexcept diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu/shell_context_menu.h b/src/modules/NewPlus/NewShellExtensionContextMenu/shell_context_menu.h index 564069254d37..e07c3e69aa9f 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu/shell_context_menu.h +++ b/src/modules/NewPlus/NewShellExtensionContextMenu/shell_context_menu.h @@ -27,11 +27,11 @@ class __declspec(uuid(NEW_SHELL_EXTENSION_EXPLORER_COMMAND_UUID_STR)) shell_cont #pragma region IObjectWithSite IFACEMETHODIMP SetSite(_In_ IUnknown* site) noexcept; - IFACEMETHODIMP GetSite(_In_ REFIID riid, _COM_Outptr_ void** site) noexcept; #pragma endregion protected: HINSTANCE instance_handle = 0; ComPtr site_of_folder; + ComPtr target_folder_view; }; diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu/shell_context_sub_menu.cpp b/src/modules/NewPlus/NewShellExtensionContextMenu/shell_context_sub_menu.cpp index 47f93beac757..2c528446b1a6 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu/shell_context_sub_menu.cpp +++ b/src/modules/NewPlus/NewShellExtensionContextMenu/shell_context_sub_menu.cpp @@ -5,7 +5,7 @@ using namespace Microsoft::WRL; // // Sub context menu command enumerator -shell_context_sub_menu::shell_context_sub_menu(const ComPtr site_of_folder) +shell_context_sub_menu::shell_context_sub_menu(const ComPtr target_folder_view) { trace.UpdateState(true); this->site_of_folder = site_of_folder; @@ -25,7 +25,7 @@ shell_context_sub_menu::shell_context_sub_menu(const ComPtr site_of_fo int index = 0; for (int i = 0; i < number_of_templates; i++) { - explorer_menu_item_commands.push_back(Make(templates->get_template_item(i), site_of_folder)); + explorer_menu_item_commands.push_back(Make(templates->get_template_item(i), target_folder_view)); } // Add separator to context menu diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu/shell_context_sub_menu.h b/src/modules/NewPlus/NewShellExtensionContextMenu/shell_context_sub_menu.h index 2fef78ed6348..3c354ce2e4aa 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu/shell_context_sub_menu.h +++ b/src/modules/NewPlus/NewShellExtensionContextMenu/shell_context_sub_menu.h @@ -13,7 +13,7 @@ using namespace newplus; class shell_context_sub_menu final : public RuntimeClass, IEnumExplorerCommand> { public: - shell_context_sub_menu(const ComPtr site_of_folder); + shell_context_sub_menu(const ComPtr target_folder_view); // IEnumExplorerCommand IFACEMETHODIMP Next(ULONG celt, __out_ecount_part(celt, *pceltFetched) IExplorerCommand** apUICommand, __out_opt ULONG* pceltFetched); @@ -26,4 +26,5 @@ class shell_context_sub_menu final : public RuntimeClass>::const_iterator current_command; template_folder* templates; ComPtr site_of_folder; + ComPtr target_folder_view; }; diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu/shell_context_sub_menu_item.cpp b/src/modules/NewPlus/NewShellExtensionContextMenu/shell_context_sub_menu_item.cpp index 12e5f9cf5c18..5e821f374d46 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu/shell_context_sub_menu_item.cpp +++ b/src/modules/NewPlus/NewShellExtensionContextMenu/shell_context_sub_menu_item.cpp @@ -12,10 +12,10 @@ shell_context_sub_menu_item::shell_context_sub_menu_item() this->template_entry = nullptr; } -shell_context_sub_menu_item::shell_context_sub_menu_item(const template_item* template_entry, const ComPtr site_of_folder) +shell_context_sub_menu_item::shell_context_sub_menu_item(const template_item* template_entry, const ComPtr target_folder_view) { this->template_entry = template_entry; - this->site_of_folder = site_of_folder; + this->target_folder_view = target_folder_view; } IFACEMETHODIMP shell_context_sub_menu_item::GetTitle(_In_opt_ IShellItemArray* items, _Outptr_result_nullonfailure_ PWSTR* title) @@ -69,14 +69,14 @@ IFACEMETHODIMP shell_context_sub_menu_item::Invoke(_In_opt_ IShellItemArray*, _I trace.UpdateState(true); // Determine target path of where context menu was displayed - const auto target_path_name = utilities::get_path_from_unknown_site(site_of_folder); + const auto target_path_name = utilities::get_path_from_unknown_site(target_folder_view); // Determine initial filename std::filesystem::path source_fullpath = template_entry->path; std::filesystem::path target_fullpath = std::wstring(target_path_name); // Only append name to target if source is not a directory - if (!utilities::is_directory(target_fullpath)) + if (!utilities::is_directory(source_fullpath)) { target_fullpath.append(this->template_entry->get_target_filename(!utilities::get_newplus_setting_hide_starting_digits())); } @@ -90,7 +90,7 @@ IFACEMETHODIMP shell_context_sub_menu_item::Invoke(_In_opt_ IShellItemArray*, _I SHChangeNotify(SHCNE_CREATE, SHCNF_PATH | SHCNF_FLUSH, target_final_fullpath.wstring().c_str(), NULL); // Enter rename mode - this->template_entry->enter_rename_mode(site_of_folder, target_final_fullpath); + this->template_entry->enter_rename_mode(target_folder_view, target_final_fullpath); Trace::EventCopyTemplateResult(S_OK); } diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu/shell_context_sub_menu_item.h b/src/modules/NewPlus/NewShellExtensionContextMenu/shell_context_sub_menu_item.h index 38d24973ede7..7a05001df4ff 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu/shell_context_sub_menu_item.h +++ b/src/modules/NewPlus/NewShellExtensionContextMenu/shell_context_sub_menu_item.h @@ -12,7 +12,7 @@ using namespace newplus; class shell_context_sub_menu_item : public RuntimeClass, IExplorerCommand> { public: - shell_context_sub_menu_item(const template_item* template_entry, const ComPtr site_of_folder); + shell_context_sub_menu_item(const template_item* template_entry, const ComPtr target_folder_view); // IExplorerCommand IFACEMETHODIMP GetTitle(_In_opt_ IShellItemArray* items, _Outptr_result_nullonfailure_ PWSTR* title); @@ -34,7 +34,7 @@ class shell_context_sub_menu_item : public RuntimeClass site_of_folder; + ComPtr target_folder_view; }; // Sub-context-menu separator between the list of templates menu-items and "Open templates" menu-item diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu/template_folder.cpp b/src/modules/NewPlus/NewShellExtensionContextMenu/template_folder.cpp index b4bfdf63f53a..e52a871e806b 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu/template_folder.cpp +++ b/src/modules/NewPlus/NewShellExtensionContextMenu/template_folder.cpp @@ -11,6 +11,11 @@ template_folder::template_folder(const std::filesystem::path newplus_template_fo this->template_folder_path = newplus_template_folder; } +template_folder::~template_folder() +{ + list_of_templates.clear(); +} + void template_folder::init() { rescan_template_folder(); diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu/template_folder.h b/src/modules/NewPlus/NewShellExtensionContextMenu/template_folder.h index fe644be2e913..4ff949981975 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu/template_folder.h +++ b/src/modules/NewPlus/NewShellExtensionContextMenu/template_folder.h @@ -13,6 +13,8 @@ namespace newplus { public: template_folder(const std::filesystem::path newplus_template_folder); + ~template_folder(); + void rescan_template_folder(); std::filesystem::path template_folder_path; diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu/template_item.cpp b/src/modules/NewPlus/NewShellExtensionContextMenu/template_item.cpp index e644df5c85bf..d8f0f23b5137 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu/template_item.cpp +++ b/src/modules/NewPlus/NewShellExtensionContextMenu/template_item.cpp @@ -63,6 +63,11 @@ std::wstring template_item::get_explorer_icon() const return utilities::get_explorer_icon(path); } +HICON template_item::get_explorer_icon_handle() const +{ + return utilities::get_explorer_icon_handle(path); +} + std::filesystem::path template_item::copy_object_to(const HWND window_handle, const std::filesystem::path destination) const { // SHFILEOPSTRUCT wants the from and to paths to be terminated with two NULLs, @@ -86,6 +91,14 @@ std::filesystem::path template_item::copy_object_to(const HWND window_handle, co if (!file_operation_params.hNameMappings) { // No file name collision on copy + if (utilities::is_directory(this->path)) + { + // Append dir for consistency on directory naming inclusion for with and without collision + std::filesystem::path with_dir = destination; + with_dir /= this->path.filename(); + return with_dir; + } + return destination; } @@ -104,43 +117,43 @@ std::filesystem::path template_item::copy_object_to(const HWND window_handle, co return final_path; } -void template_item::enter_rename_mode(const ComPtr site, const std::filesystem::path target_fullpath) const +void template_item::enter_rename_mode(const ComPtr target_folder_view, const std::filesystem::path target_fullpath) const { - std::thread thread_for_renaming_workaround(rename_on_other_thread_workaround, site, target_fullpath); + std::thread thread_for_renaming_workaround(rename_on_other_thread_workaround, target_folder_view, target_fullpath); thread_for_renaming_workaround.detach(); } -void template_item::rename_on_other_thread_workaround(const ComPtr site, const std::filesystem::path target_fullpath) +void template_item::rename_on_other_thread_workaround(const ComPtr target_folder_view, const std::filesystem::path target_fullpath) { // Have been unable to have Windows Explorer Shell enter rename mode from the main thread // Sleep for a bit to only enter rename mode when icon has been drawn. Not strictly needed. - const std::chrono::milliseconds approx_wait_for_icon_redraw_not_needed{ 350 }; + const std::chrono::milliseconds approx_wait_for_icon_redraw_not_needed{ 1200 }; std::this_thread::sleep_for(std::chrono::milliseconds(approx_wait_for_icon_redraw_not_needed)); const std::wstring filename = target_fullpath.filename(); - ComPtr service_provider; - site->QueryInterface(IID_PPV_ARGS(&service_provider)); - ComPtr folder_view; - service_provider->QueryService(__uuidof(IFolderView), IID_PPV_ARGS(&folder_view)); + if (target_folder_view == nullptr) + { + return; + } int count = 0; - folder_view->ItemCount(SVGIO_ALLVIEW, &count); + target_folder_view->ItemCount(SVGIO_ALLVIEW, &count); for (int i = 0; i < count; ++i) { std::wstring path_of_item(MAX_PATH, 0); - LPITEMIDLIST pidl; + LPITEMIDLIST shell_item_id_pointer; - folder_view->Item(i, &pidl); - SHGetPathFromIDList(pidl, &path_of_item[0]); - CoTaskMemFree(pidl); + target_folder_view->Item(i, &shell_item_id_pointer); + SHGetPathFromIDList(shell_item_id_pointer, &path_of_item[0]); + CoTaskMemFree(shell_item_id_pointer); std::wstring current_filename = std::filesystem::path(path_of_item.c_str()).filename(); if (utilities::wstring_same_when_comparing_ignore_case(filename, current_filename)) { - folder_view->SelectItem(i, SVSI_EDIT | SVSI_SELECT | SVSI_DESELECTOTHERS | SVSI_ENSUREVISIBLE | SVSI_FOCUSED); + target_folder_view->SelectItem(i, SVSI_EDIT | SVSI_SELECT | SVSI_DESELECTOTHERS | SVSI_ENSUREVISIBLE | SVSI_FOCUSED); break; } } diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu/template_item.h b/src/modules/NewPlus/NewShellExtensionContextMenu/template_item.h index ffb1e8839f11..bd6b591a8901 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu/template_item.h +++ b/src/modules/NewPlus/NewShellExtensionContextMenu/template_item.h @@ -20,15 +20,17 @@ namespace newplus std::wstring get_target_filename(const bool include_starting_digits) const; std::wstring get_explorer_icon() const; + + HICON get_explorer_icon_handle() const; std::filesystem::path copy_object_to(const HWND window_handle, const std::filesystem::path destination) const; - void enter_rename_mode(const ComPtr site, const std::filesystem::path target_folder) const; + void enter_rename_mode(const ComPtr target_folder_view, const std::filesystem::path target_fullpath) const; std::filesystem::path path; private: - static void rename_on_other_thread_workaround(const ComPtr site, const std::filesystem::path target_fullpath); + static void rename_on_other_thread_workaround(const ComPtr target_folder_view, const std::filesystem::path target_fullpath); std::wstring remove_starting_digits_from_filename(std::wstring filename) const; }; diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu/trace.cpp b/src/modules/NewPlus/NewShellExtensionContextMenu/trace.cpp index 3a2c8c8c91b7..d126c6dd024b 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu/trace.cpp +++ b/src/modules/NewPlus/NewShellExtensionContextMenu/trace.cpp @@ -58,3 +58,12 @@ void Trace::EventCopyTemplateResult(_In_ const HRESULT hr) noexcept TraceLoggingHResult(hr), TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE)); } + +void Trace::EventOpenTemplates() noexcept +{ + TraceLoggingWriteWrapper( + g_hProvider, + "NewPlus_EventOpenTemplates", + ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance), + TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE)); +} diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu/trace.h b/src/modules/NewPlus/NewShellExtensionContextMenu/trace.h index 7c21086642fc..1d0c2562855f 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu/trace.h +++ b/src/modules/NewPlus/NewShellExtensionContextMenu/trace.h @@ -12,4 +12,5 @@ class Trace : public telemetry::TraceBase static void EventShowTemplateItems(_In_ const size_t number_of_templates) noexcept; static void EventCopyTemplate(_In_ const std::wstring template_file_extension) noexcept; static void EventCopyTemplateResult(_In_ const HRESULT hr) noexcept; + static void EventOpenTemplates() noexcept; }; From 2f4203093b920f8091ca14a7b61697ace79ecd29 Mon Sep 17 00:00:00 2001 From: Christian Gaarden Gaardmark Date: Thu, 7 Nov 2024 20:27:45 -0800 Subject: [PATCH 08/24] Windows 10 provisional support wo/rename --- .../dll_main.cpp | 10 +- .../shell_context_menu_win10.cpp | 94 ++++++++++++------- .../shell_context_menu_win10.h | 6 +- .../new_utilities.h | 2 - .../template_item.cpp | 7 +- .../template_item.h | 2 + .../SettingsXAML/Views/NewPlusPage.xaml | 2 +- .../Settings.UI/Strings/en-us/Resources.resw | 4 +- 8 files changed, 76 insertions(+), 51 deletions(-) diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/dll_main.cpp b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/dll_main.cpp index edc46745ed52..877e8dfefda4 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/dll_main.cpp +++ b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/dll_main.cpp @@ -15,12 +15,12 @@ BOOL APIENTRY DllMain(HMODULE module_handle, DWORD ul_reason_for_call, LPVOID re { case DLL_PROCESS_ATTACH: module_instance_handle = module_handle; - //Trace::RegisterProvider(); - //newplus::utilities::init_logger(); + Trace::RegisterProvider(); + newplus::utilities::init_logger(); break; case DLL_PROCESS_DETACH: - //Trace::UnregisterProvider(); + Trace::UnregisterProvider(); break; } return TRUE; @@ -42,7 +42,3 @@ STDAPI DllGetClassObject(_In_ REFCLSID rclsid, _In_ REFIID riid, _Outptr_ LPVOID } CoCreatableClass(shell_context_menu_win10) - - -// cgaarden remove -CoCreatableClassWrlCreatorMapInclude(shell_context_menu_win10) diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/shell_context_menu_win10.cpp b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/shell_context_menu_win10.cpp index 57163ef8caac..4a2f6c82ca60 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/shell_context_menu_win10.cpp +++ b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/shell_context_menu_win10.cpp @@ -8,11 +8,7 @@ #include "trace.h" #include "Generated Files/resource.h" #include - -#include -#include -#pragma comment(lib, "gdiplus.lib") -using namespace Gdiplus; +#include using namespace Microsoft::WRL; using namespace newplus; @@ -25,25 +21,19 @@ shell_context_menu_win10::~shell_context_menu_win10() } } - #pragma region IShellExtInit IFACEMETHODIMP shell_context_menu_win10::Initialize(PCIDLIST_ABSOLUTE, IDataObject*, HKEY) { - // cgaarden HACK UPDATE- -- also check for whether win10 or not - if (!NewSettingsInstance().GetEnabled()) - { - return E_FAIL; - } - return S_OK; } #pragma endregion #pragma region IContextMenu -IFACEMETHODIMP shell_context_menu_win10::QueryContextMenu(HMENU menu_handle, UINT menu_index, UINT menu_first_cmd_id, UINT menu_last_cmd_id, UINT menu_flags) +IFACEMETHODIMP shell_context_menu_win10::QueryContextMenu(HMENU menu_handle, UINT menu_index, UINT menu_first_cmd_id, UINT, UINT menu_flags) { - // cgaarden Update to NOT show Win10 menu when on Windows 11++ - if (!NewSettingsInstance().GetEnabled()) + if (!NewSettingsInstance().GetEnabled() + || package::IsWin11OrGreater() + ) { return E_FAIL; } @@ -79,8 +69,10 @@ IFACEMETHODIMP shell_context_menu_win10::QueryContextMenu(HMENU menu_handle, UIN if (bitmap_handles.size() == 0) { - const std::wstring icon_file = utilities::get_new_icon_resource_filepath(module_instance_handle, ThemeHelpers::GetAppTheme()).c_str(); - HICON local_icon_handle = static_cast(LoadImage(NULL, icon_file.c_str(), IMAGE_ICON, icon_x, icon_y, LR_LOADFROMFILE)); + const std::wstring icon_file = utilities::get_new_icon_resource_filepath( + module_instance_handle, ThemeHelpers::GetAppTheme()).c_str(); + HICON local_icon_handle = static_cast( + LoadImage(NULL, icon_file.c_str(), IMAGE_ICON, icon_x, icon_y, LR_LOADFROMFILE)); if (local_icon_handle) { @@ -113,7 +105,9 @@ IFACEMETHODIMP shell_context_menu_win10::QueryContextMenu(HMENU menu_handle, UIN { const auto template_item = templates->get_template_item(index); wchar_t menu_name[256] = { 0 }; - wcscpy_s(menu_name, ARRAYSIZE(menu_name), template_item->get_menu_title(!utilities::get_newplus_setting_hide_extension(), !utilities::get_newplus_setting_hide_starting_digits()).c_str()); + wcscpy_s(menu_name, ARRAYSIZE(menu_name), template_item->get_menu_title( + !utilities::get_newplus_setting_hide_extension(), + !utilities::get_newplus_setting_hide_starting_digits()).c_str()); MENUITEMINFO newplus_menu_item_template; newplus_menu_item_template.cbSize = sizeof(MENUITEMINFO); newplus_menu_item_template.fMask = MIIM_STRING | MIIM_FTYPE | MIIM_ID | MIIM_DATA; @@ -141,7 +135,6 @@ IFACEMETHODIMP shell_context_menu_win10::QueryContextMenu(HMENU menu_handle, UIN sub_menu_index++; } - // Add separator to context menu MENUITEMINFO menu_item_separator; menu_item_separator.cbSize = sizeof(MENUITEMINFO); @@ -166,8 +159,10 @@ IFACEMETHODIMP shell_context_menu_win10::QueryContextMenu(HMENU menu_handle, UIN const auto open_templates_icon_index = index + 1; if (bitmap_handles.size() <= open_templates_icon_index) { - const std::wstring icon_file = utilities::get_open_templates_icon_resource_filepath(module_instance_handle, ThemeHelpers::GetAppTheme()).c_str(); - HICON open_template_icon_handle = static_cast(LoadImage(NULL, icon_file.c_str(), IMAGE_ICON, icon_x, icon_y, LR_LOADFROMFILE)); + const std::wstring icon_file = utilities::get_open_templates_icon_resource_filepath( + module_instance_handle, ThemeHelpers::GetAppTheme()).c_str(); + HICON open_template_icon_handle = static_cast( + LoadImage(NULL, icon_file.c_str(), IMAGE_ICON, icon_x, icon_y, LR_LOADFROMFILE)); if (open_template_icon_handle) { bitmap_handles.push_back(CreateBitmapFromIcon(open_template_icon_handle)); @@ -183,7 +178,6 @@ IFACEMETHODIMP shell_context_menu_win10::QueryContextMenu(HMENU menu_handle, UIN InsertMenuItem(sub_menu_of_templates, sub_menu_index, TRUE, &newplus_menu_item_open_templates); menu_id++; - // Log that context menu was shown and with how many items Trace::EventShowTemplateItems(number_of_templates); @@ -192,8 +186,8 @@ IFACEMETHODIMP shell_context_menu_win10::QueryContextMenu(HMENU menu_handle, UIN if (!InsertMenuItem(menu_handle, menu_index, TRUE, &newplus_menu_item)) { + Logger::error(L"QueryContextMenu() failed. {}", get_last_error_or_default(GetLastError())); return HRESULT_FROM_WIN32(GetLastError()); - // cgaarden Log error, if not S_SUCCESS } else { @@ -215,21 +209,20 @@ IFACEMETHODIMP shell_context_menu_win10::InvokeCommand(CMINVOKECOMMANDINFO* para return E_FAIL; } - trace.UpdateState(true); - HRESULT hr = S_OK; const auto number_of_templates = templates->list_of_templates.size(); const bool is_template_item = selected_menu_item_index < number_of_templates; if (is_template_item) { - // it's a template item + // It's a template menu item + const auto template_entry = templates->get_template_item(selected_menu_item_index); try { - Logger::info(L"Copying template"); + trace.UpdateState(true); - const auto template_entry = templates->get_template_item(selected_menu_item_index); + Logger::info(L"Copying template"); // Determine target path of where context menu was displayed const auto target_path_name = utilities::get_path_from_folder_view(target_folder_view); @@ -241,19 +234,22 @@ IFACEMETHODIMP shell_context_menu_win10::InvokeCommand(CMINVOKECOMMANDINFO* para // Only append name to target if source is not a directory if (!utilities::is_directory(source_fullpath)) { - target_fullpath.append(template_entry->get_target_filename(!utilities::get_newplus_setting_hide_starting_digits())); + target_fullpath.append(template_entry->get_target_filename( + !utilities::get_newplus_setting_hide_starting_digits())); } // Copy file and determine final filename - std::filesystem::path target_final_fullpath = template_entry->copy_object_to(GetActiveWindow(), target_fullpath); + std::filesystem::path target_final_fullpath = template_entry->copy_object_to( + GetActiveWindow(), target_fullpath); Trace::EventCopyTemplate(target_final_fullpath.extension().c_str()); - // Refresh folder items - SHChangeNotify(SHCNE_CREATE, SHCNF_PATH | SHCNF_FLUSH, target_final_fullpath.wstring().c_str(), NULL); + // Refresh folder item + template_entry->refresh_target(target_final_fullpath); // Enter rename mode - template_entry->enter_rename_mode(target_folder_view, target_final_fullpath); + // Removed for Windows 10 -- causes crash -- looking for possible different approaches, including SHChangeNotify + // template_entry->enter_rename_mode(target_folder_view, target_final_fullpath); Trace::EventCopyTemplateResult(S_OK); } @@ -267,8 +263,8 @@ IFACEMETHODIMP shell_context_menu_win10::InvokeCommand(CMINVOKECOMMANDINFO* para } else { - // it's the "Open templates" item - Logger::info(L"Open templates folder"); + // It's the "Open templates" menu item + Logger::info(L"Opening templates folder"); const std::filesystem::path template_folder_root = utilities::get_new_template_folder_location(); const std::wstring verb_hardcoded_do_not_change = L"open"; ShellExecute(nullptr, verb_hardcoded_do_not_change.c_str(), template_folder_root.c_str(), NULL, NULL, SW_SHOWNORMAL); @@ -297,6 +293,33 @@ IFACEMETHODIMP shell_context_menu_win10::SetSite(_In_ IUnknown* site) noexcept ComPtr service_provider; site->QueryInterface(IID_PPV_ARGS(&service_provider)); service_provider->QueryService(__uuidof(IFolderView), IID_PPV_ARGS(&target_folder_view)); + + + //ComPtr shell_browser; + //service_provider->QueryService(__uuidof(IShellBrowser), IID_PPV_ARGS(&shell_browser)); + //if (shell_browser) + //{ + // ComPtr shell_view; + // shell_browser->QueryActiveShellView(&shell_view); + // HRESULT hr; + // LPITEMIDLIST shell_item_id_pointer; + // target_folder_view->Item(1, &shell_item_id_pointer); + // hr = shell_view->SelectItem(shell_item_id_pointer, SVSI_EDIT | SVSI_SELECT | SVSI_DESELECTOTHERS | SVSI_ENSUREVISIBLE | SVSI_FOCUSED); + // CoTaskMemFree(shell_item_id_pointer); + //} + + + //ComPtr shell_browser; + //site->QueryInterface(IID_PPV_ARGS(&shell_browser)); + //if (shell_browser) + //{ + // ComPtr shell_view; + // shell_browser->QueryActiveShellView(&shell_view); + //} + +// Site.QueryInterface(IServiceProvider, ServiceProvider) // Site was received in IObjectWithSite.SetSite +// ServiceProvider.QueryService(SID_STopLevelBrowser, IShellBrowser, ShellBrowser) +// ShellBrowser.BrowseObject(ChildItem, SBSP_RELATIVE or SBSP_SAMEBROWSER) } return S_OK; @@ -306,3 +329,4 @@ IFACEMETHODIMP shell_context_menu_win10::GetSite(_In_ REFIID riid, _COM_Outptr_ return this->site_of_folder.CopyTo(riid, returned_site); } #pragma endregion + diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/shell_context_menu_win10.h b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/shell_context_menu_win10.h index 468597b40f45..18a70bb4cf83 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/shell_context_menu_win10.h +++ b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/shell_context_menu_win10.h @@ -5,10 +5,10 @@ using namespace Microsoft::WRL; -#define NEW_SHELL_EXTENSION_EXPLORER_COMMAND_WIN10_UUID_STR "FF90D477-E32A-4BE8-8CC5-A502A97F5401" +#define NEW_SHELL_EXTENSION_EXPLORER_COMMAND_WIN10_UUID "FF90D477-E32A-4BE8-8CC5-A502A97F5401" // File Explorer context menu "New+" for Windows 10 -class __declspec(uuid(NEW_SHELL_EXTENSION_EXPLORER_COMMAND_WIN10_UUID_STR)) shell_context_menu_win10 : +class __declspec(uuid(NEW_SHELL_EXTENSION_EXPLORER_COMMAND_WIN10_UUID)) shell_context_menu_win10 : public RuntimeClass< RuntimeClassFlags, IShellExtInit, @@ -32,7 +32,7 @@ class __declspec(uuid(NEW_SHELL_EXTENSION_EXPLORER_COMMAND_WIN10_UUID_STR)) shel IFACEMETHODIMP SetSite(_In_ IUnknown* site) noexcept; IFACEMETHODIMP GetSite(_In_ REFIID riid, _COM_Outptr_ void** site) noexcept; #pragma endregion - + protected: HINSTANCE instance_handle = 0; ComPtr site_of_folder; diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu/new_utilities.h b/src/modules/NewPlus/NewShellExtensionContextMenu/new_utilities.h index c8e7039fc340..7a015fcb2e6b 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu/new_utilities.h +++ b/src/modules/NewPlus/NewShellExtensionContextMenu/new_utilities.h @@ -49,8 +49,6 @@ namespace newplus::utilities return shell_file_info.hIcon; } - -// cgaarden todo/Hack not tested!!! WCHAR icon_resource_specifier[MAX_PATH] = { 0 }; DWORD buffer_length = MAX_PATH; const std::wstring extension = path.extension().wstring(); diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu/template_item.cpp b/src/modules/NewPlus/NewShellExtensionContextMenu/template_item.cpp index d8f0f23b5137..7e4118de0eec 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu/template_item.cpp +++ b/src/modules/NewPlus/NewShellExtensionContextMenu/template_item.cpp @@ -117,6 +117,11 @@ std::filesystem::path template_item::copy_object_to(const HWND window_handle, co return final_path; } +void template_item::refresh_target(const std::filesystem::path target_final_fullpath) const +{ + SHChangeNotify(SHCNE_CREATE, SHCNF_PATH | SHCNF_FLUSH, target_final_fullpath.wstring().c_str(), NULL); +} + void template_item::enter_rename_mode(const ComPtr target_folder_view, const std::filesystem::path target_fullpath) const { std::thread thread_for_renaming_workaround(rename_on_other_thread_workaround, target_folder_view, target_fullpath); @@ -127,7 +132,7 @@ void template_item::rename_on_other_thread_workaround(const ComPtr { // Have been unable to have Windows Explorer Shell enter rename mode from the main thread // Sleep for a bit to only enter rename mode when icon has been drawn. Not strictly needed. - const std::chrono::milliseconds approx_wait_for_icon_redraw_not_needed{ 1200 }; + const std::chrono::milliseconds approx_wait_for_icon_redraw_not_needed{ 350 }; std::this_thread::sleep_for(std::chrono::milliseconds(approx_wait_for_icon_redraw_not_needed)); const std::wstring filename = target_fullpath.filename(); diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu/template_item.h b/src/modules/NewPlus/NewShellExtensionContextMenu/template_item.h index bd6b591a8901..f93e65f1fa46 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu/template_item.h +++ b/src/modules/NewPlus/NewShellExtensionContextMenu/template_item.h @@ -25,6 +25,8 @@ namespace newplus std::filesystem::path copy_object_to(const HWND window_handle, const std::filesystem::path destination) const; + void refresh_target(const std::filesystem::path target_final_fullpath) const; + void enter_rename_mode(const ComPtr target_folder_view, const std::filesystem::path target_fullpath) const; std::filesystem::path path; diff --git a/src/settings-ui/Settings.UI/SettingsXAML/Views/NewPlusPage.xaml b/src/settings-ui/Settings.UI/SettingsXAML/Views/NewPlusPage.xaml index ef8b9c68e899..2867a89b48b3 100644 --- a/src/settings-ui/Settings.UI/SettingsXAML/Views/NewPlusPage.xaml +++ b/src/settings-ui/Settings.UI/SettingsXAML/Views/NewPlusPage.xaml @@ -24,7 +24,7 @@ Enable New+ Localize product name in accordance with Windows New - - New+ is not supported in Windows 10 and is not expected to work. + + New+ Windows 10 support is experimental. PowerToys "Backup and Restore" feature doesn't take templates into account at this moment. If you use that feature, templates will have to be copied manually. From 6e591c86a1827364022139d642083204deba55c2 Mon Sep 17 00:00:00 2001 From: Christian Gaarden Gaardmark Date: Thu, 7 Nov 2024 20:29:13 -0800 Subject: [PATCH 09/24] Update dll.def --- src/modules/NewPlus/NewShellExtensionContextMenu.win10/dll.def | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/dll.def b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/dll.def index 98766b8e2823..74de7c3181f3 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/dll.def +++ b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/dll.def @@ -3,4 +3,4 @@ LIBRARY EXPORTS DllGetClassObject PRIVATE DllCanUnloadNow PRIVATE - DllGetActivationFactory PRIVATE \ No newline at end of file + DllGetActivationFactory PRIVATE From 02608306c47c75ce52d0315925dc99e156eaaaa6 Mon Sep 17 00:00:00 2001 From: Christian Gaarden Gaardmark Date: Thu, 7 Nov 2024 20:44:09 -0800 Subject: [PATCH 10/24] Reducing diff --- .../NewShellExtensionContextMenu.win10/dll_main.h | 2 +- .../new.base.rc | 2 +- .../resource.base.h | 1 - .../shell_context_menu.cpp | 11 ++--------- .../shell_context_menu.h | 1 - .../shell_context_sub_menu.cpp | 4 ++-- .../shell_context_sub_menu.h | 3 +-- .../shell_context_sub_menu_item.cpp | 14 +++++++------- .../shell_context_sub_menu_item.h | 4 ++-- .../template_item.cpp | 15 +++++++-------- .../NewShellExtensionContextMenu/template_item.h | 4 ++-- 11 files changed, 25 insertions(+), 36 deletions(-) diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/dll_main.h b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/dll_main.h index 9e980caa0db5..c2d69eebfd39 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/dll_main.h +++ b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/dll_main.h @@ -3,4 +3,4 @@ #include extern HMODULE module_instance_handle; -extern Shared::Trace::ETWTrace trace; \ No newline at end of file +extern Shared::Trace::ETWTrace trace; diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/new.base.rc b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/new.base.rc index 90f26c856728..e5abd2223661 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/new.base.rc +++ b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/new.base.rc @@ -46,4 +46,4 @@ // Icon with lowest ID value placed first to ensure application icon // remains consistent on all systems. -IDI_NEWPLUS_ICON ICON "../NewShellExtensionContextMenu/Assets/NewPlus/New_light.ico" + diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/resource.base.h b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/resource.base.h index 113546d90960..25dc1f71b055 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/resource.base.h +++ b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/resource.base.h @@ -7,7 +7,6 @@ #define FILE_DESCRIPTION "PowerToys.New+" #define INTERNAL_NAME "PowerToys.New+" #define ORIGINAL_FILENAME "PowerToys.NewPlus.ShellExtension.win10.dll" -#define IDI_NEWPLUS_ICON 1001 // Non-localizable ////////////////////////////// diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu/shell_context_menu.cpp b/src/modules/NewPlus/NewShellExtensionContextMenu/shell_context_menu.cpp index 3ed3011a5049..b3bf2992d5f1 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu/shell_context_menu.cpp +++ b/src/modules/NewPlus/NewShellExtensionContextMenu/shell_context_menu.cpp @@ -69,7 +69,7 @@ IFACEMETHODIMP shell_context_menu::GetFlags(_Out_ EXPCMDFLAGS* returned_menu_ite IFACEMETHODIMP shell_context_menu::EnumSubCommands(_COM_Outptr_ IEnumExplorerCommand** returned_enum_commands) { - auto e = Make(target_folder_view); + auto e = Make(site_of_folder); return e->QueryInterface(IID_PPV_ARGS(returned_enum_commands)); } #pragma endregion @@ -77,14 +77,7 @@ IFACEMETHODIMP shell_context_menu::EnumSubCommands(_COM_Outptr_ IEnumExplorerCom #pragma region IObjectWithSite IFACEMETHODIMP shell_context_menu::SetSite(_In_ IUnknown* site) noexcept { - if (site) - { - this->site_of_folder = site; - ComPtr service_provider; - site->QueryInterface(IID_PPV_ARGS(&service_provider)); - service_provider->QueryService(__uuidof(IFolderView), IID_PPV_ARGS(&target_folder_view)); - } - + this->site_of_folder = site; return S_OK; } IFACEMETHODIMP shell_context_menu::GetSite(_In_ REFIID riid, _COM_Outptr_ void** returned_site) noexcept diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu/shell_context_menu.h b/src/modules/NewPlus/NewShellExtensionContextMenu/shell_context_menu.h index e07c3e69aa9f..6e74d9730de6 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu/shell_context_menu.h +++ b/src/modules/NewPlus/NewShellExtensionContextMenu/shell_context_menu.h @@ -33,5 +33,4 @@ class __declspec(uuid(NEW_SHELL_EXTENSION_EXPLORER_COMMAND_UUID_STR)) shell_cont protected: HINSTANCE instance_handle = 0; ComPtr site_of_folder; - ComPtr target_folder_view; }; diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu/shell_context_sub_menu.cpp b/src/modules/NewPlus/NewShellExtensionContextMenu/shell_context_sub_menu.cpp index 2c528446b1a6..47f93beac757 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu/shell_context_sub_menu.cpp +++ b/src/modules/NewPlus/NewShellExtensionContextMenu/shell_context_sub_menu.cpp @@ -5,7 +5,7 @@ using namespace Microsoft::WRL; // // Sub context menu command enumerator -shell_context_sub_menu::shell_context_sub_menu(const ComPtr target_folder_view) +shell_context_sub_menu::shell_context_sub_menu(const ComPtr site_of_folder) { trace.UpdateState(true); this->site_of_folder = site_of_folder; @@ -25,7 +25,7 @@ shell_context_sub_menu::shell_context_sub_menu(const ComPtr target_ int index = 0; for (int i = 0; i < number_of_templates; i++) { - explorer_menu_item_commands.push_back(Make(templates->get_template_item(i), target_folder_view)); + explorer_menu_item_commands.push_back(Make(templates->get_template_item(i), site_of_folder)); } // Add separator to context menu diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu/shell_context_sub_menu.h b/src/modules/NewPlus/NewShellExtensionContextMenu/shell_context_sub_menu.h index 3c354ce2e4aa..2fef78ed6348 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu/shell_context_sub_menu.h +++ b/src/modules/NewPlus/NewShellExtensionContextMenu/shell_context_sub_menu.h @@ -13,7 +13,7 @@ using namespace newplus; class shell_context_sub_menu final : public RuntimeClass, IEnumExplorerCommand> { public: - shell_context_sub_menu(const ComPtr target_folder_view); + shell_context_sub_menu(const ComPtr site_of_folder); // IEnumExplorerCommand IFACEMETHODIMP Next(ULONG celt, __out_ecount_part(celt, *pceltFetched) IExplorerCommand** apUICommand, __out_opt ULONG* pceltFetched); @@ -26,5 +26,4 @@ class shell_context_sub_menu final : public RuntimeClass>::const_iterator current_command; template_folder* templates; ComPtr site_of_folder; - ComPtr target_folder_view; }; diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu/shell_context_sub_menu_item.cpp b/src/modules/NewPlus/NewShellExtensionContextMenu/shell_context_sub_menu_item.cpp index 5e821f374d46..15c3ba6a15a3 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu/shell_context_sub_menu_item.cpp +++ b/src/modules/NewPlus/NewShellExtensionContextMenu/shell_context_sub_menu_item.cpp @@ -12,10 +12,10 @@ shell_context_sub_menu_item::shell_context_sub_menu_item() this->template_entry = nullptr; } -shell_context_sub_menu_item::shell_context_sub_menu_item(const template_item* template_entry, const ComPtr target_folder_view) +shell_context_sub_menu_item::shell_context_sub_menu_item(const template_item* template_entry, const ComPtr site_of_folder) { this->template_entry = template_entry; - this->target_folder_view = target_folder_view; + this->site_of_folder = site_of_folder; } IFACEMETHODIMP shell_context_sub_menu_item::GetTitle(_In_opt_ IShellItemArray* items, _Outptr_result_nullonfailure_ PWSTR* title) @@ -69,7 +69,7 @@ IFACEMETHODIMP shell_context_sub_menu_item::Invoke(_In_opt_ IShellItemArray*, _I trace.UpdateState(true); // Determine target path of where context menu was displayed - const auto target_path_name = utilities::get_path_from_unknown_site(target_folder_view); + const auto target_path_name = utilities::get_path_from_unknown_site(site_of_folder); // Determine initial filename std::filesystem::path source_fullpath = template_entry->path; @@ -78,19 +78,19 @@ IFACEMETHODIMP shell_context_sub_menu_item::Invoke(_In_opt_ IShellItemArray*, _I // Only append name to target if source is not a directory if (!utilities::is_directory(source_fullpath)) { - target_fullpath.append(this->template_entry->get_target_filename(!utilities::get_newplus_setting_hide_starting_digits())); + target_fullpath.append(template_entry->get_target_filename(!utilities::get_newplus_setting_hide_starting_digits())); } // Copy file and determine final filename - std::filesystem::path target_final_fullpath = this->template_entry->copy_object_to(GetActiveWindow(), target_fullpath); + std::filesystem::path target_final_fullpath = template_entry->copy_object_to(GetActiveWindow(), target_fullpath); Trace::EventCopyTemplate(target_final_fullpath.extension().c_str()); // Refresh folder items - SHChangeNotify(SHCNE_CREATE, SHCNF_PATH | SHCNF_FLUSH, target_final_fullpath.wstring().c_str(), NULL); + template_entry->refresh_target(target_final_fullpath); // Enter rename mode - this->template_entry->enter_rename_mode(target_folder_view, target_final_fullpath); + template_entry->enter_rename_mode(site_of_folder, target_final_fullpath); Trace::EventCopyTemplateResult(S_OK); } diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu/shell_context_sub_menu_item.h b/src/modules/NewPlus/NewShellExtensionContextMenu/shell_context_sub_menu_item.h index 7a05001df4ff..38d24973ede7 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu/shell_context_sub_menu_item.h +++ b/src/modules/NewPlus/NewShellExtensionContextMenu/shell_context_sub_menu_item.h @@ -12,7 +12,7 @@ using namespace newplus; class shell_context_sub_menu_item : public RuntimeClass, IExplorerCommand> { public: - shell_context_sub_menu_item(const template_item* template_entry, const ComPtr target_folder_view); + shell_context_sub_menu_item(const template_item* template_entry, const ComPtr site_of_folder); // IExplorerCommand IFACEMETHODIMP GetTitle(_In_opt_ IShellItemArray* items, _Outptr_result_nullonfailure_ PWSTR* title); @@ -34,7 +34,7 @@ class shell_context_sub_menu_item : public RuntimeClass target_folder_view; + ComPtr site_of_folder; }; // Sub-context-menu separator between the list of templates menu-items and "Open templates" menu-item diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu/template_item.cpp b/src/modules/NewPlus/NewShellExtensionContextMenu/template_item.cpp index 7e4118de0eec..75267b6a01d9 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu/template_item.cpp +++ b/src/modules/NewPlus/NewShellExtensionContextMenu/template_item.cpp @@ -122,13 +122,13 @@ void template_item::refresh_target(const std::filesystem::path target_final_full SHChangeNotify(SHCNE_CREATE, SHCNF_PATH | SHCNF_FLUSH, target_final_fullpath.wstring().c_str(), NULL); } -void template_item::enter_rename_mode(const ComPtr target_folder_view, const std::filesystem::path target_fullpath) const +void template_item::enter_rename_mode(const ComPtr site_of_folder, const std::filesystem::path target_fullpath) const { - std::thread thread_for_renaming_workaround(rename_on_other_thread_workaround, target_folder_view, target_fullpath); + std::thread thread_for_renaming_workaround(rename_on_other_thread_workaround, site_of_folder, target_fullpath); thread_for_renaming_workaround.detach(); } -void template_item::rename_on_other_thread_workaround(const ComPtr target_folder_view, const std::filesystem::path target_fullpath) +void template_item::rename_on_other_thread_workaround(const ComPtr site_of_folder, const std::filesystem::path target_fullpath) { // Have been unable to have Windows Explorer Shell enter rename mode from the main thread // Sleep for a bit to only enter rename mode when icon has been drawn. Not strictly needed. @@ -137,12 +137,11 @@ void template_item::rename_on_other_thread_workaround(const ComPtr const std::wstring filename = target_fullpath.filename(); - if (target_folder_view == nullptr) - { - return; - } - int count = 0; + ComPtr service_provider; + ComPtr target_folder_view; + site_of_folder->QueryInterface(IID_PPV_ARGS(&service_provider)); + service_provider->QueryService(__uuidof(IFolderView), IID_PPV_ARGS(&target_folder_view)); target_folder_view->ItemCount(SVGIO_ALLVIEW, &count); for (int i = 0; i < count; ++i) diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu/template_item.h b/src/modules/NewPlus/NewShellExtensionContextMenu/template_item.h index f93e65f1fa46..a843ac99e017 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu/template_item.h +++ b/src/modules/NewPlus/NewShellExtensionContextMenu/template_item.h @@ -27,12 +27,12 @@ namespace newplus void refresh_target(const std::filesystem::path target_final_fullpath) const; - void enter_rename_mode(const ComPtr target_folder_view, const std::filesystem::path target_fullpath) const; + void enter_rename_mode(const ComPtr site_of_folder, const std::filesystem::path target_fullpath) const; std::filesystem::path path; private: - static void rename_on_other_thread_workaround(const ComPtr target_folder_view, const std::filesystem::path target_fullpath); + static void rename_on_other_thread_workaround(const ComPtr site_of_folder, const std::filesystem::path target_fullpath); std::wstring remove_starting_digits_from_filename(std::wstring filename) const; }; From 381980d50221b7a0fc0b945586dd4cd13290aa32 Mon Sep 17 00:00:00 2001 From: Christian Gaarden Gaardmark Date: Thu, 7 Nov 2024 20:49:37 -0800 Subject: [PATCH 11/24] less delta --- .../template_item.cpp | 27 ++++++++++--------- .../template_item.h | 4 +-- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu/template_item.cpp b/src/modules/NewPlus/NewShellExtensionContextMenu/template_item.cpp index 75267b6a01d9..9eb41b31a951 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu/template_item.cpp +++ b/src/modules/NewPlus/NewShellExtensionContextMenu/template_item.cpp @@ -122,13 +122,13 @@ void template_item::refresh_target(const std::filesystem::path target_final_full SHChangeNotify(SHCNE_CREATE, SHCNF_PATH | SHCNF_FLUSH, target_final_fullpath.wstring().c_str(), NULL); } -void template_item::enter_rename_mode(const ComPtr site_of_folder, const std::filesystem::path target_fullpath) const +void template_item::enter_rename_mode(const ComPtr site, const std::filesystem::path target_fullpath) const { - std::thread thread_for_renaming_workaround(rename_on_other_thread_workaround, site_of_folder, target_fullpath); + std::thread thread_for_renaming_workaround(rename_on_other_thread_workaround, site, target_fullpath); thread_for_renaming_workaround.detach(); } -void template_item::rename_on_other_thread_workaround(const ComPtr site_of_folder, const std::filesystem::path target_fullpath) +void template_item::rename_on_other_thread_workaround(const ComPtr site, const std::filesystem::path target_fullpath) { // Have been unable to have Windows Explorer Shell enter rename mode from the main thread // Sleep for a bit to only enter rename mode when icon has been drawn. Not strictly needed. @@ -137,27 +137,28 @@ void template_item::rename_on_other_thread_workaround(const ComPtr sit const std::wstring filename = target_fullpath.filename(); - int count = 0; ComPtr service_provider; - ComPtr target_folder_view; - site_of_folder->QueryInterface(IID_PPV_ARGS(&service_provider)); - service_provider->QueryService(__uuidof(IFolderView), IID_PPV_ARGS(&target_folder_view)); - target_folder_view->ItemCount(SVGIO_ALLVIEW, &count); + site->QueryInterface(IID_PPV_ARGS(&service_provider)); + ComPtr folder_view; + service_provider->QueryService(__uuidof(IFolderView), IID_PPV_ARGS(&folder_view)); + + int count = 0; + folder_view->ItemCount(SVGIO_ALLVIEW, &count); for (int i = 0; i < count; ++i) { std::wstring path_of_item(MAX_PATH, 0); - LPITEMIDLIST shell_item_id_pointer; + LPITEMIDLIST pidl; - target_folder_view->Item(i, &shell_item_id_pointer); - SHGetPathFromIDList(shell_item_id_pointer, &path_of_item[0]); - CoTaskMemFree(shell_item_id_pointer); + folder_view->Item(i, &pidl); + SHGetPathFromIDList(pidl, &path_of_item[0]); + CoTaskMemFree(pidl); std::wstring current_filename = std::filesystem::path(path_of_item.c_str()).filename(); if (utilities::wstring_same_when_comparing_ignore_case(filename, current_filename)) { - target_folder_view->SelectItem(i, SVSI_EDIT | SVSI_SELECT | SVSI_DESELECTOTHERS | SVSI_ENSUREVISIBLE | SVSI_FOCUSED); + folder_view->SelectItem(i, SVSI_EDIT | SVSI_SELECT | SVSI_DESELECTOTHERS | SVSI_ENSUREVISIBLE | SVSI_FOCUSED); break; } } diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu/template_item.h b/src/modules/NewPlus/NewShellExtensionContextMenu/template_item.h index a843ac99e017..f9dd448185c1 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu/template_item.h +++ b/src/modules/NewPlus/NewShellExtensionContextMenu/template_item.h @@ -27,12 +27,12 @@ namespace newplus void refresh_target(const std::filesystem::path target_final_fullpath) const; - void enter_rename_mode(const ComPtr site_of_folder, const std::filesystem::path target_fullpath) const; + void enter_rename_mode(const ComPtr site, const std::filesystem::path target_fullpath) const; std::filesystem::path path; private: - static void rename_on_other_thread_workaround(const ComPtr site_of_folder, const std::filesystem::path target_fullpath); + static void rename_on_other_thread_workaround(const ComPtr site, const std::filesystem::path target_fullpath); std::wstring remove_starting_digits_from_filename(std::wstring filename) const; }; From 45239cb491f95c46e16ba12d1b53c3826bd136c1 Mon Sep 17 00:00:00 2001 From: Christian Gaarden Gaardmark Date: Fri, 8 Nov 2024 18:01:10 -0800 Subject: [PATCH 12/24] More clean up --- .../dll_main.cpp | 2 +- .../shell_context_menu_win10.cpp | 40 ++----------------- .../shell_context_menu_win10.h | 1 - 3 files changed, 5 insertions(+), 38 deletions(-) diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/dll_main.cpp b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/dll_main.cpp index 877e8dfefda4..c620e39f3293 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/dll_main.cpp +++ b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/dll_main.cpp @@ -7,7 +7,7 @@ #include HMODULE module_instance_handle = 0; -Shared::Trace::ETWTrace trace(L"NewPlusShellExtensionWin10"); +Shared::Trace::ETWTrace trace(L"NewPlusShellExtension_Win10"); BOOL APIENTRY DllMain(HMODULE module_handle, DWORD ul_reason_for_call, LPVOID reserved) { diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/shell_context_menu_win10.cpp b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/shell_context_menu_win10.cpp index 4a2f6c82ca60..b919381c44d9 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/shell_context_menu_win10.cpp +++ b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/shell_context_menu_win10.cpp @@ -225,7 +225,7 @@ IFACEMETHODIMP shell_context_menu_win10::InvokeCommand(CMINVOKECOMMANDINFO* para Logger::info(L"Copying template"); // Determine target path of where context menu was displayed - const auto target_path_name = utilities::get_path_from_folder_view(target_folder_view); + const auto target_path_name = utilities::get_path_from_unknown_site(site_of_folder); // Determine initial filename std::filesystem::path source_fullpath = template_entry->path; @@ -248,7 +248,8 @@ IFACEMETHODIMP shell_context_menu_win10::InvokeCommand(CMINVOKECOMMANDINFO* para template_entry->refresh_target(target_final_fullpath); // Enter rename mode - // Removed for Windows 10 -- causes crash -- looking for possible different approaches, including SHChangeNotify + // Removed for Windows 10 -- causes crash -- looking for possible different approaches, + // including SHChangeNotify // template_entry->enter_rename_mode(target_folder_view, target_final_fullpath); Trace::EventCopyTemplateResult(S_OK); @@ -287,40 +288,7 @@ IFACEMETHODIMP shell_context_menu_win10::GetCommandString(UINT_PTR, UINT, UINT*, #pragma region IObjectWithSite IFACEMETHODIMP shell_context_menu_win10::SetSite(_In_ IUnknown* site) noexcept { - if (site) - { - this->site_of_folder = site; - ComPtr service_provider; - site->QueryInterface(IID_PPV_ARGS(&service_provider)); - service_provider->QueryService(__uuidof(IFolderView), IID_PPV_ARGS(&target_folder_view)); - - - //ComPtr shell_browser; - //service_provider->QueryService(__uuidof(IShellBrowser), IID_PPV_ARGS(&shell_browser)); - //if (shell_browser) - //{ - // ComPtr shell_view; - // shell_browser->QueryActiveShellView(&shell_view); - // HRESULT hr; - // LPITEMIDLIST shell_item_id_pointer; - // target_folder_view->Item(1, &shell_item_id_pointer); - // hr = shell_view->SelectItem(shell_item_id_pointer, SVSI_EDIT | SVSI_SELECT | SVSI_DESELECTOTHERS | SVSI_ENSUREVISIBLE | SVSI_FOCUSED); - // CoTaskMemFree(shell_item_id_pointer); - //} - - - //ComPtr shell_browser; - //site->QueryInterface(IID_PPV_ARGS(&shell_browser)); - //if (shell_browser) - //{ - // ComPtr shell_view; - // shell_browser->QueryActiveShellView(&shell_view); - //} - -// Site.QueryInterface(IServiceProvider, ServiceProvider) // Site was received in IObjectWithSite.SetSite -// ServiceProvider.QueryService(SID_STopLevelBrowser, IShellBrowser, ShellBrowser) -// ShellBrowser.BrowseObject(ChildItem, SBSP_RELATIVE or SBSP_SAMEBROWSER) - } + this->site_of_folder = site; return S_OK; } diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/shell_context_menu_win10.h b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/shell_context_menu_win10.h index 18a70bb4cf83..ca45849daca6 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/shell_context_menu_win10.h +++ b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/shell_context_menu_win10.h @@ -36,7 +36,6 @@ class __declspec(uuid(NEW_SHELL_EXTENSION_EXPLORER_COMMAND_WIN10_UUID)) shell_co protected: HINSTANCE instance_handle = 0; ComPtr site_of_folder; - ComPtr target_folder_view; newplus::template_folder* templates = nullptr; std::vector bitmap_handles; }; From 07f0fe6cd7536af3f95bbc2f1c11601c89f18dd0 Mon Sep 17 00:00:00 2001 From: Christian Gaarden Gaardmark Date: Fri, 8 Nov 2024 19:48:49 -0800 Subject: [PATCH 13/24] Workaround for spellfix --- .../NewPlus/NewShellExtensionContextMenu.win10/dll_main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/dll_main.cpp b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/dll_main.cpp index c620e39f3293..b036eb2ed0e5 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/dll_main.cpp +++ b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/dll_main.cpp @@ -36,9 +36,9 @@ STDAPI DllCanUnloadNow() return Module::GetModule().GetObjectCount() == 0 ? S_OK : S_FALSE; } -STDAPI DllGetClassObject(_In_ REFCLSID rclsid, _In_ REFIID riid, _Outptr_ LPVOID FAR* ppv) +STDAPI DllGetClassObject(_In_ REFCLSID ref_class_id, _In_ REFIID ref_interface_id, _Outptr_ LPVOID FAR* object) { - return Module::GetModule().GetClassObject(rclsid, riid, ppv); + return Module::GetModule().GetClassObject(ref_class_id, ref_interface_id, object); } CoCreatableClass(shell_context_menu_win10) From 5d5af92ae94ba65f59fad3fc9b8bba26125ed689 Mon Sep 17 00:00:00 2001 From: Christian Gaarden Gaardmark Date: Fri, 8 Nov 2024 21:00:47 -0800 Subject: [PATCH 14/24] Update expect.txt Spell check... --- .github/actions/spell-check/expect.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/actions/spell-check/expect.txt b/.github/actions/spell-check/expect.txt index a6d3b032dbb7..47f4fcf0ff57 100644 --- a/.github/actions/spell-check/expect.txt +++ b/.github/actions/spell-check/expect.txt @@ -475,6 +475,7 @@ exsb exstyle EXTENDEDKEY EXTENDEDVERBS +Extensionwin EXTRINSICPROPERTIES eyetracker FANCYZONESDRAWLAYOUTTEST @@ -1003,6 +1004,7 @@ newitem newpath newplus NEWPLUSCONTEXTMENU +NEWPLUSSHELLEXTENSIONWIN newrow newsgroups NIF From 43e08725c48a905f10c3222d314a4dfcfa0ec9f1 Mon Sep 17 00:00:00 2001 From: Christian Gaarden Gaardmark Date: Sat, 9 Nov 2024 18:56:26 -0800 Subject: [PATCH 15/24] Renaming mode now working now across windows 10 and 11 --- .../shell_context_menu_win10.cpp | 4 +- .../new_utilities.h | 111 ++++++++++++++++++ .../shell_context_sub_menu_item.cpp | 2 +- .../template_item.cpp | 36 +----- .../template_item.h | 4 +- .../SettingsXAML/Views/NewPlusPage.xaml | 7 -- .../Settings.UI/Strings/en-us/Resources.resw | 3 - 7 files changed, 120 insertions(+), 47 deletions(-) diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/shell_context_menu_win10.cpp b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/shell_context_menu_win10.cpp index b919381c44d9..4cc34f8cd7bd 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/shell_context_menu_win10.cpp +++ b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/shell_context_menu_win10.cpp @@ -248,9 +248,7 @@ IFACEMETHODIMP shell_context_menu_win10::InvokeCommand(CMINVOKECOMMANDINFO* para template_entry->refresh_target(target_final_fullpath); // Enter rename mode - // Removed for Windows 10 -- causes crash -- looking for possible different approaches, - // including SHChangeNotify - // template_entry->enter_rename_mode(target_folder_view, target_final_fullpath); + template_entry->enter_rename_mode(target_final_fullpath); Trace::EventCopyTemplateResult(S_OK); } diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu/new_utilities.h b/src/modules/NewPlus/NewShellExtensionContextMenu/new_utilities.h index 7a015fcb2e6b..0182d97ac8d4 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu/new_utilities.h +++ b/src/modules/NewPlus/NewShellExtensionContextMenu/new_utilities.h @@ -207,4 +207,115 @@ namespace newplus::utilities return path; } + inline bool is_desktop_folder(const std::filesystem::path target_fullpath) + { + TCHAR desktopPath[MAX_PATH]; + if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_DESKTOP, NULL, 0, desktopPath))) + { + return StrCmpIW(target_fullpath.c_str(), desktopPath) == 0; + } + return false; + } + + + inline void explorer_enter_rename_mode(const std::filesystem::path target_fullpath_of_new_instance) + { + const std::filesystem::path path_without_new_file_or_dir = target_fullpath_of_new_instance.parent_path(); + const std::filesystem::path new_file_or_dir_without_path = target_fullpath_of_new_instance.filename(); + + ComPtr shell_windows; + + HRESULT hr; + if (FAILED(CoCreateInstance(CLSID_ShellWindows, NULL, CLSCTX_ALL, IID_PPV_ARGS(&shell_windows)))) + { + return; + } + + long window_handle; + ComPtr shell_window; + const bool object_created_on_desktop = is_desktop_folder(path_without_new_file_or_dir.c_str()); + if (object_created_on_desktop) + { + // Special handling for desktop folder + VARIANT empty_yet_needed_incl_init; + VariantInit(&empty_yet_needed_incl_init); + + if (FAILED(shell_windows->FindWindowSW(&empty_yet_needed_incl_init, &empty_yet_needed_incl_init, SWC_DESKTOP, &window_handle, SWFO_NEEDDISPATCH, &shell_window))) + { + return; + } + } + else + { + long count_of_shell_windows = 0; + shell_windows->get_Count(&count_of_shell_windows); + + for (long i = 0; i < count_of_shell_windows; ++i) + { + ComPtr web_browser_app; + VARIANT v; + V_VT(&v) = VT_I4; + V_I4(&v) = i; + hr = shell_windows->Item(v, &shell_window); + if (SUCCEEDED(hr) && shell_window) + { + hr = shell_window.As(&web_browser_app); + if (SUCCEEDED(hr)) + { + BSTR folder_view_location; + hr = web_browser_app->get_LocationURL(&folder_view_location); + if (SUCCEEDED(hr) && folder_view_location) + { + wchar_t path[MAX_PATH]; + DWORD pathLength = ARRAYSIZE(path); + hr = PathCreateFromUrl(folder_view_location, path, &pathLength, 0); + SysFreeString(folder_view_location); + if (SUCCEEDED(hr) && StrCmpIW(path_without_new_file_or_dir.c_str(), path) == 0) + { + break; + } + } + } + } + shell_window = nullptr; + } + } + + if (!shell_window) + { + return; + } + + ComPtr service_provider; + shell_window.As(&service_provider); + ComPtr shell_browser; + service_provider->QueryService(SID_STopLevelBrowser, IID_PPV_ARGS(&shell_browser)); + ComPtr shell_view; + shell_browser->QueryActiveShellView(&shell_view); + ComPtr folder_view; + shell_view.As(&folder_view); + + // Find the newly created object (file or folder) + // And put into edit mode (SVSI_EDIT) + int number_of_objects_in_view = 0; + folder_view->ItemCount(SVGIO_ALLVIEW, &number_of_objects_in_view); + for (int i = 0; i < number_of_objects_in_view; ++i) + { + std::wstring path_of_item(MAX_PATH, 0); + LPITEMIDLIST shell_item_ids; + + folder_view->Item(i, &shell_item_ids); + SHGetPathFromIDList(shell_item_ids, &path_of_item[0]); + CoTaskMemFree(shell_item_ids); + + std::wstring current_filename = std::filesystem::path(path_of_item.c_str()).filename(); + + //if (utilities::wstring_same_when_comparing_ignore_case(filename, current_filename)) + if (StrCmpIW(new_file_or_dir_without_path.c_str(), current_filename.c_str()) == 0) + { + folder_view->SelectItem(i, SVSI_EDIT | SVSI_SELECT | SVSI_DESELECTOTHERS | SVSI_ENSUREVISIBLE | SVSI_FOCUSED); + break; + } + } + } } diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu/shell_context_sub_menu_item.cpp b/src/modules/NewPlus/NewShellExtensionContextMenu/shell_context_sub_menu_item.cpp index 15c3ba6a15a3..d1bc2ba29575 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu/shell_context_sub_menu_item.cpp +++ b/src/modules/NewPlus/NewShellExtensionContextMenu/shell_context_sub_menu_item.cpp @@ -90,7 +90,7 @@ IFACEMETHODIMP shell_context_sub_menu_item::Invoke(_In_opt_ IShellItemArray*, _I template_entry->refresh_target(target_final_fullpath); // Enter rename mode - template_entry->enter_rename_mode(site_of_folder, target_final_fullpath); + template_entry->enter_rename_mode(target_final_fullpath); Trace::EventCopyTemplateResult(S_OK); } diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu/template_item.cpp b/src/modules/NewPlus/NewShellExtensionContextMenu/template_item.cpp index 9eb41b31a951..6fef157fda46 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu/template_item.cpp +++ b/src/modules/NewPlus/NewShellExtensionContextMenu/template_item.cpp @@ -122,44 +122,18 @@ void template_item::refresh_target(const std::filesystem::path target_final_full SHChangeNotify(SHCNE_CREATE, SHCNF_PATH | SHCNF_FLUSH, target_final_fullpath.wstring().c_str(), NULL); } -void template_item::enter_rename_mode(const ComPtr site, const std::filesystem::path target_fullpath) const +void template_item::enter_rename_mode(const std::filesystem::path target_fullpath) const { - std::thread thread_for_renaming_workaround(rename_on_other_thread_workaround, site, target_fullpath); + std::thread thread_for_renaming_workaround(rename_on_other_thread_workaround, target_fullpath); thread_for_renaming_workaround.detach(); } -void template_item::rename_on_other_thread_workaround(const ComPtr site, const std::filesystem::path target_fullpath) +void template_item::rename_on_other_thread_workaround(const std::filesystem::path target_fullpath) { // Have been unable to have Windows Explorer Shell enter rename mode from the main thread // Sleep for a bit to only enter rename mode when icon has been drawn. Not strictly needed. - const std::chrono::milliseconds approx_wait_for_icon_redraw_not_needed{ 350 }; + const std::chrono::milliseconds approx_wait_for_icon_redraw_not_needed{ 250 }; std::this_thread::sleep_for(std::chrono::milliseconds(approx_wait_for_icon_redraw_not_needed)); - const std::wstring filename = target_fullpath.filename(); - - ComPtr service_provider; - site->QueryInterface(IID_PPV_ARGS(&service_provider)); - ComPtr folder_view; - service_provider->QueryService(__uuidof(IFolderView), IID_PPV_ARGS(&folder_view)); - - int count = 0; - folder_view->ItemCount(SVGIO_ALLVIEW, &count); - - for (int i = 0; i < count; ++i) - { - std::wstring path_of_item(MAX_PATH, 0); - LPITEMIDLIST pidl; - - folder_view->Item(i, &pidl); - SHGetPathFromIDList(pidl, &path_of_item[0]); - CoTaskMemFree(pidl); - - std::wstring current_filename = std::filesystem::path(path_of_item.c_str()).filename(); - - if (utilities::wstring_same_when_comparing_ignore_case(filename, current_filename)) - { - folder_view->SelectItem(i, SVSI_EDIT | SVSI_SELECT | SVSI_DESELECTOTHERS | SVSI_ENSUREVISIBLE | SVSI_FOCUSED); - break; - } - } + newplus::utilities::explorer_enter_rename_mode(target_fullpath); } diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu/template_item.h b/src/modules/NewPlus/NewShellExtensionContextMenu/template_item.h index f9dd448185c1..7b8ba78aeefe 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu/template_item.h +++ b/src/modules/NewPlus/NewShellExtensionContextMenu/template_item.h @@ -27,12 +27,12 @@ namespace newplus void refresh_target(const std::filesystem::path target_final_fullpath) const; - void enter_rename_mode(const ComPtr site, const std::filesystem::path target_fullpath) const; + void enter_rename_mode(const std::filesystem::path target_fullpath) const; std::filesystem::path path; private: - static void rename_on_other_thread_workaround(const ComPtr site, const std::filesystem::path target_fullpath); + static void rename_on_other_thread_workaround(const std::filesystem::path target_fullpath); std::wstring remove_starting_digits_from_filename(std::wstring filename) const; }; diff --git a/src/settings-ui/Settings.UI/SettingsXAML/Views/NewPlusPage.xaml b/src/settings-ui/Settings.UI/SettingsXAML/Views/NewPlusPage.xaml index 2867a89b48b3..7f4e427d6531 100644 --- a/src/settings-ui/Settings.UI/SettingsXAML/Views/NewPlusPage.xaml +++ b/src/settings-ui/Settings.UI/SettingsXAML/Views/NewPlusPage.xaml @@ -23,13 +23,6 @@ - - Enable New+ Localize product name in accordance with Windows New - - New+ Windows 10 support is experimental. - PowerToys "Backup and Restore" feature doesn't take templates into account at this moment. If you use that feature, templates will have to be copied manually. From 64e81d801c00e0745f42ba28b99d5d883d6b8ae0 Mon Sep 17 00:00:00 2001 From: Christian Gaarden Gaardmark Date: Sat, 16 Nov 2024 15:31:58 -0800 Subject: [PATCH 16/24] Win10 refactored-light --- .../shell_context_menu_win10.cpp | 273 ++++++++---------- .../shell_context_menu_win10.h | 4 + .../new_utilities.h | 109 ++++++- .../shell_context_sub_menu_item.cpp | 50 +--- .../template_item.cpp | 4 +- .../NewShellExtensionContextMenu/trace.cpp | 10 + .../NewShellExtensionContextMenu/trace.h | 2 + 7 files changed, 244 insertions(+), 208 deletions(-) diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/shell_context_menu_win10.cpp b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/shell_context_menu_win10.cpp index 4cc34f8cd7bd..61d1ad05e134 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/shell_context_menu_win10.cpp +++ b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/shell_context_menu_win10.cpp @@ -32,7 +32,7 @@ IFACEMETHODIMP shell_context_menu_win10::Initialize(PCIDLIST_ABSOLUTE, IDataObje IFACEMETHODIMP shell_context_menu_win10::QueryContextMenu(HMENU menu_handle, UINT menu_index, UINT menu_first_cmd_id, UINT, UINT menu_flags) { if (!NewSettingsInstance().GetEnabled() - || package::IsWin11OrGreater() + || package::IsWin11OrGreater() ) { return E_FAIL; @@ -43,107 +43,105 @@ IFACEMETHODIMP shell_context_menu_win10::QueryContextMenu(HMENU menu_handle, UIN return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, 0); } - trace.UpdateState(true); - - const auto icon_x = GetSystemMetrics(SM_CXSMICON); - const auto icon_y = GetSystemMetrics(SM_CYSMICON); - - // Create the initial context popup menu containing the list of templates and open templates action - HMENU sub_menu_of_templates = CreatePopupMenu(); - int menu_id = menu_first_cmd_id; - int sub_menu_index = 0; - - // Create the New+ menu item and point to the initial context popup menu - static const std::wstring localized_context_menu_item = - GET_RESOURCE_STRING_FALLBACK(IDS_CONTEXT_MENU_ITEM_NEW, L"New+"); - wchar_t newplus_menu_name[20] = { 0 }; - wcscpy_s(newplus_menu_name, ARRAYSIZE(newplus_menu_name), localized_context_menu_item.c_str()); - MENUITEMINFO newplus_menu_item; - newplus_menu_item.cbSize = sizeof(MENUITEMINFO); - newplus_menu_item.fMask = MIIM_STRING | MIIM_FTYPE | MIIM_ID | MIIM_SUBMENU; - newplus_menu_item.wID = menu_id; - newplus_menu_item.fType = MFT_STRING; - newplus_menu_item.dwTypeData = (PWSTR)newplus_menu_name; - newplus_menu_item.hSubMenu = sub_menu_of_templates; - const auto newplus_icon_index = 0; - - if (bitmap_handles.size() == 0) - { - const std::wstring icon_file = utilities::get_new_icon_resource_filepath( - module_instance_handle, ThemeHelpers::GetAppTheme()).c_str(); - HICON local_icon_handle = static_cast( - LoadImage(NULL, icon_file.c_str(), IMAGE_ICON, icon_x, icon_y, LR_LOADFROMFILE)); + Trace trace_on; - if (local_icon_handle) - { - bitmap_handles.push_back(CreateBitmapFromIcon(local_icon_handle)); - DestroyIcon(local_icon_handle); - } - } - if (bitmap_handles.size() > newplus_icon_index && bitmap_handles[newplus_icon_index]) + try { - newplus_menu_item.fMask |= MIIM_BITMAP; - newplus_menu_item.hbmpItem = bitmap_handles[newplus_icon_index]; - } - - menu_id++; - - // Determine the New+ Template folder location - const std::filesystem::path template_folder_root = utilities::get_new_template_folder_location(); - - // Create the New+ Template folder location if it doesn't exist (very rare scenario) - utilities::create_folder_if_not_exist(template_folder_root); + // Create the initial context popup menu containing the list of templates and open templates action + int menu_id = menu_first_cmd_id; + MENUITEMINFO newplus_main_context_menu_item; + HMENU sub_menu_of_templates = CreatePopupMenu(); + int sub_menu_index = 0; - // Scan the folder for any files and folders (the templates) - templates = new template_folder(template_folder_root); - templates->rescan_template_folder(); + // Determine the New+ Template folder location + const std::filesystem::path template_folder_root = utilities::get_new_template_folder_location(); - // Add template items to context menu - const auto number_of_templates = templates->list_of_templates.size(); - int index = 0; - for (; index < number_of_templates; index++) - { - const auto template_item = templates->get_template_item(index); - wchar_t menu_name[256] = { 0 }; - wcscpy_s(menu_name, ARRAYSIZE(menu_name), template_item->get_menu_title( - !utilities::get_newplus_setting_hide_extension(), - !utilities::get_newplus_setting_hide_starting_digits()).c_str()); - MENUITEMINFO newplus_menu_item_template; - newplus_menu_item_template.cbSize = sizeof(MENUITEMINFO); - newplus_menu_item_template.fMask = MIIM_STRING | MIIM_FTYPE | MIIM_ID | MIIM_DATA; - newplus_menu_item_template.wID = menu_id; - newplus_menu_item_template.fType = MFT_STRING; - newplus_menu_item_template.dwTypeData = (PWSTR)menu_name; - const auto current_template_icon_index = index + 1; - if (bitmap_handles.size() <= current_template_icon_index) + // Create the New+ Template folder location if it doesn't exist (very rare scenario) + utilities::create_folder_if_not_exist(template_folder_root); + + // Scan the folder for any files and folders (the templates) + templates = new template_folder(template_folder_root); + templates->rescan_template_folder(); + const auto number_of_templates = templates->list_of_templates.size(); + + // Create the New+ menu item and point to the initial context popup menu + static const std::wstring localized_context_menu_item = + GET_RESOURCE_STRING_FALLBACK(IDS_CONTEXT_MENU_ITEM_NEW, L"New+"); + wchar_t newplus_menu_name[20] = { 0 }; + wcscpy_s(newplus_menu_name, ARRAYSIZE(newplus_menu_name), localized_context_menu_item.c_str()); + newplus_main_context_menu_item.cbSize = sizeof(MENUITEMINFOW); + newplus_main_context_menu_item.fMask = MIIM_STRING | MIIM_FTYPE | MIIM_ID | MIIM_SUBMENU; + newplus_main_context_menu_item.wID = menu_id; + newplus_main_context_menu_item.fType = MFT_STRING; + newplus_main_context_menu_item.dwTypeData = (PWSTR)newplus_menu_name; + newplus_main_context_menu_item.hSubMenu = sub_menu_of_templates; + const auto newplus_icon_index = 0; + + if (bitmap_handles.size() == 0) { - HICON template_icon_handle = template_item->get_explorer_icon_handle(); - if (template_icon_handle) + const std::wstring icon_file = utilities::get_new_icon_resource_filepath( + module_instance_handle, ThemeHelpers::GetAppTheme()) + .c_str(); + HICON local_icon_handle = static_cast( + LoadImage(NULL, icon_file.c_str(), IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_LOADFROMFILE)); + + if (local_icon_handle) { - bitmap_handles.push_back(CreateBitmapFromIcon(template_icon_handle)); - DestroyIcon(template_icon_handle); + bitmap_handles.push_back(CreateBitmapFromIcon(local_icon_handle)); + DestroyIcon(local_icon_handle); } } - if (bitmap_handles.size() > current_template_icon_index && bitmap_handles[current_template_icon_index]) + if (bitmap_handles.size() > newplus_icon_index && bitmap_handles[newplus_icon_index]) { - newplus_menu_item_template.fMask |= MIIM_BITMAP; - newplus_menu_item_template.hbmpItem = bitmap_handles[current_template_icon_index]; + newplus_main_context_menu_item.fMask |= MIIM_BITMAP; + newplus_main_context_menu_item.hbmpItem = bitmap_handles[newplus_icon_index]; } - InsertMenuItem(sub_menu_of_templates, sub_menu_index, TRUE, &newplus_menu_item_template); menu_id++; + + // Add template items to context menu + int index = 0; + for (; index < number_of_templates; index++) + { + const auto template_item = templates->get_template_item(index); + add_template_item_to_context_menu(sub_menu_of_templates, sub_menu_index, template_item, menu_id, index); + menu_id++; + sub_menu_index++; + } + + // Add separator to context menu + add_separator_to_context_menu(sub_menu_of_templates, sub_menu_index); sub_menu_index++; + + // Add "Open templates" item to context menu + add_open_templates_to_context_menu(sub_menu_of_templates, sub_menu_index, template_folder_root, menu_id, index); + menu_id++; + + if (!InsertMenuItem(menu_handle, menu_index, TRUE, &newplus_main_context_menu_item)) + { + Logger::error(L"QueryContextMenu() failed. {}", get_last_error_or_default(GetLastError())); + return HRESULT_FROM_WIN32(GetLastError()); + } + else + { + // Log that context menu was shown and with how many items + Trace::EventShowTemplateItems(number_of_templates); + + // Return the amount if entries inserted + const auto number_of_items_inserted = menu_id - menu_first_cmd_id; + return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, number_of_items_inserted); + } + } + catch (const std::exception& ex) + { + Logger::error(ex.what()); } - // Add separator to context menu - MENUITEMINFO menu_item_separator; - menu_item_separator.cbSize = sizeof(MENUITEMINFO); - menu_item_separator.fMask = MIIM_FTYPE; - menu_item_separator.fType = MFT_SEPARATOR; - InsertMenuItem(sub_menu_of_templates, sub_menu_index, TRUE, &menu_item_separator); - sub_menu_index++; + return E_FAIL; +} - // Add "Open templates" item to context menu +void shell_context_menu_win10::add_open_templates_to_context_menu(HMENU sub_menu_of_templates, int sub_menu_index, const std::filesystem::path& template_folder_root, int menu_id, int index) +{ static const std::wstring localized_context_menu_item_open_templates = GET_RESOURCE_STRING_FALLBACK(IDS_CONTEXT_MENU_ITEM_OPEN_TEMPLATES, L"Open templates"); wchar_t menu_name_open[256] = { 0 }; @@ -160,9 +158,10 @@ IFACEMETHODIMP shell_context_menu_win10::QueryContextMenu(HMENU menu_handle, UIN if (bitmap_handles.size() <= open_templates_icon_index) { const std::wstring icon_file = utilities::get_open_templates_icon_resource_filepath( - module_instance_handle, ThemeHelpers::GetAppTheme()).c_str(); + module_instance_handle, ThemeHelpers::GetAppTheme()) + .c_str(); HICON open_template_icon_handle = static_cast( - LoadImage(NULL, icon_file.c_str(), IMAGE_ICON, icon_x, icon_y, LR_LOADFROMFILE)); + LoadImage(NULL, icon_file.c_str(), IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_LOADFROMFILE)); if (open_template_icon_handle) { bitmap_handles.push_back(CreateBitmapFromIcon(open_template_icon_handle)); @@ -176,24 +175,44 @@ IFACEMETHODIMP shell_context_menu_win10::QueryContextMenu(HMENU menu_handle, UIN } InsertMenuItem(sub_menu_of_templates, sub_menu_index, TRUE, &newplus_menu_item_open_templates); - menu_id++; - - // Log that context menu was shown and with how many items - Trace::EventShowTemplateItems(number_of_templates); +} - trace.Flush(); - trace.UpdateState(false); +void shell_context_menu_win10::add_separator_to_context_menu(HMENU sub_menu_of_templates, int sub_menu_index) +{ + MENUITEMINFO menu_item_separator; + menu_item_separator.cbSize = sizeof(MENUITEMINFO); + menu_item_separator.fMask = MIIM_FTYPE; + menu_item_separator.fType = MFT_SEPARATOR; + InsertMenuItem(sub_menu_of_templates, sub_menu_index, TRUE, &menu_item_separator); +} - if (!InsertMenuItem(menu_handle, menu_index, TRUE, &newplus_menu_item)) +void shell_context_menu_win10::add_template_item_to_context_menu(HMENU sub_menu_of_templates, int sub_menu_index, newplus::template_item* const template_item, int menu_id, int index) +{ + wchar_t menu_name[256] = { 0 }; + wcscpy_s(menu_name, ARRAYSIZE(menu_name), template_item->get_menu_title(!utilities::get_newplus_setting_hide_extension(), !utilities::get_newplus_setting_hide_starting_digits()).c_str()); + MENUITEMINFO newplus_menu_item_template; + newplus_menu_item_template.cbSize = sizeof(MENUITEMINFO); + newplus_menu_item_template.fMask = MIIM_STRING | MIIM_FTYPE | MIIM_ID | MIIM_DATA; + newplus_menu_item_template.wID = menu_id; + newplus_menu_item_template.fType = MFT_STRING; + newplus_menu_item_template.dwTypeData = (PWSTR)menu_name; + const auto current_template_icon_index = index + 1; + if (bitmap_handles.size() <= current_template_icon_index) { - Logger::error(L"QueryContextMenu() failed. {}", get_last_error_or_default(GetLastError())); - return HRESULT_FROM_WIN32(GetLastError()); + HICON template_icon_handle = template_item->get_explorer_icon_handle(); + if (template_icon_handle) + { + bitmap_handles.push_back(CreateBitmapFromIcon(template_icon_handle)); + DestroyIcon(template_icon_handle); + } } - else + if (bitmap_handles.size() > current_template_icon_index && bitmap_handles[current_template_icon_index]) { - const auto number_of_items_inserted = menu_id - menu_first_cmd_id; - return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, number_of_items_inserted); + newplus_menu_item_template.fMask |= MIIM_BITMAP; + newplus_menu_item_template.hbmpItem = bitmap_handles[current_template_icon_index]; } + + InsertMenuItem(sub_menu_of_templates, sub_menu_index, TRUE, &newplus_menu_item_template); } IFACEMETHODIMP shell_context_menu_win10::InvokeCommand(CMINVOKECOMMANDINFO* params) @@ -203,13 +222,13 @@ IFACEMETHODIMP shell_context_menu_win10::InvokeCommand(CMINVOKECOMMANDINFO* para return E_FAIL; } + // Get selected menu item (a template or the "Open templates" item) const auto selected_menu_item_index = LOWORD(params->lpVerb) - 1; if (selected_menu_item_index < 0) { return E_FAIL; } - HRESULT hr = S_OK; const auto number_of_templates = templates->list_of_templates.size(); const bool is_template_item = selected_menu_item_index < number_of_templates; @@ -218,63 +237,17 @@ IFACEMETHODIMP shell_context_menu_win10::InvokeCommand(CMINVOKECOMMANDINFO* para // It's a template menu item const auto template_entry = templates->get_template_item(selected_menu_item_index); - try - { - trace.UpdateState(true); - - Logger::info(L"Copying template"); - - // Determine target path of where context menu was displayed - const auto target_path_name = utilities::get_path_from_unknown_site(site_of_folder); - - // Determine initial filename - std::filesystem::path source_fullpath = template_entry->path; - std::filesystem::path target_fullpath = std::wstring(target_path_name); - - // Only append name to target if source is not a directory - if (!utilities::is_directory(source_fullpath)) - { - target_fullpath.append(template_entry->get_target_filename( - !utilities::get_newplus_setting_hide_starting_digits())); - } - - // Copy file and determine final filename - std::filesystem::path target_final_fullpath = template_entry->copy_object_to( - GetActiveWindow(), target_fullpath); - - Trace::EventCopyTemplate(target_final_fullpath.extension().c_str()); - - // Refresh folder item - template_entry->refresh_target(target_final_fullpath); - - // Enter rename mode - template_entry->enter_rename_mode(target_final_fullpath); - - Trace::EventCopyTemplateResult(S_OK); - } - catch (const std::exception& ex) - { - Trace::EventCopyTemplateResult(S_FALSE); - Logger::error(ex.what()); - - hr = S_FALSE; - } + return newplus::utilities::copy_template(template_entry, site_of_folder); } else { // It's the "Open templates" menu item - Logger::info(L"Opening templates folder"); const std::filesystem::path template_folder_root = utilities::get_new_template_folder_location(); - const std::wstring verb_hardcoded_do_not_change = L"open"; - ShellExecute(nullptr, verb_hardcoded_do_not_change.c_str(), template_folder_root.c_str(), NULL, NULL, SW_SHOWNORMAL); - Trace::EventOpenTemplates(); + return newplus::utilities::open_template_folder(template_folder_root); } - trace.Flush(); - trace.UpdateState(false); - - return hr; + return E_FAIL; } IFACEMETHODIMP shell_context_menu_win10::GetCommandString(UINT_PTR, UINT, UINT*, CHAR*, UINT) diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/shell_context_menu_win10.h b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/shell_context_menu_win10.h index ca45849daca6..f69355cccb66 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/shell_context_menu_win10.h +++ b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/shell_context_menu_win10.h @@ -34,6 +34,10 @@ class __declspec(uuid(NEW_SHELL_EXTENSION_EXPLORER_COMMAND_WIN10_UUID)) shell_co #pragma endregion protected: + void add_open_templates_to_context_menu(HMENU sub_menu_of_templates, int sub_menu_index, const std::filesystem::path& template_folder_root, int menu_id, int index); + void add_separator_to_context_menu(HMENU sub_menu_of_templates, int sub_menu_index); + void add_template_item_to_context_menu(HMENU sub_menu_of_templates, int sub_menu_index, newplus::template_item* const template_item, int menu_id, int index); + HINSTANCE instance_handle = 0; ComPtr site_of_folder; newplus::template_folder* templates = nullptr; diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu/new_utilities.h b/src/modules/NewPlus/NewShellExtensionContextMenu/new_utilities.h index 0182d97ac8d4..e0c0a361c77e 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu/new_utilities.h +++ b/src/modules/NewPlus/NewShellExtensionContextMenu/new_utilities.h @@ -7,9 +7,13 @@ #include "constants.h" #include "settings.h" +#include "template_item.h" +#include "trace.h" #pragma comment(lib, "Shlwapi.lib") +using namespace newplus; + namespace newplus::utilities { @@ -217,7 +221,6 @@ namespace newplus::utilities return false; } - inline void explorer_enter_rename_mode(const std::filesystem::path target_fullpath_of_new_instance) { const std::filesystem::path path_without_new_file_or_dir = target_fullpath_of_new_instance.parent_path(); @@ -296,26 +299,116 @@ namespace newplus::utilities shell_view.As(&folder_view); // Find the newly created object (file or folder) - // And put into edit mode (SVSI_EDIT) + // And put object into edit mode (SVSI_EDIT) and if desktop also reposition int number_of_objects_in_view = 0; + bool done = false; folder_view->ItemCount(SVGIO_ALLVIEW, &number_of_objects_in_view); - for (int i = 0; i < number_of_objects_in_view; ++i) + for (int i = 0; i < number_of_objects_in_view && !done; ++i) { std::wstring path_of_item(MAX_PATH, 0); LPITEMIDLIST shell_item_ids; folder_view->Item(i, &shell_item_ids); SHGetPathFromIDList(shell_item_ids, &path_of_item[0]); + + const std::wstring current_filename = std::filesystem::path(path_of_item.c_str()).filename(); + + if (utilities::wstring_same_when_comparing_ignore_case(new_file_or_dir_without_path, current_filename)) + { + const DWORD common_select_flags = SVSI_EDIT | SVSI_SELECT | SVSI_DESELECTOTHERS | SVSI_ENSUREVISIBLE | SVSI_FOCUSED; + + if (object_created_on_desktop) + { + // Newly created object is on the desktop -- reposition under mouse and enter rename mode + LPCITEMIDLIST shell_item_to_select_and_position[] = { shell_item_ids }; + POINT mouse_position; + GetCursorPos(&mouse_position); + mouse_position.x -= GetSystemMetrics(SM_CXMENUSIZE); + mouse_position.x = max(mouse_position.x, 20); + mouse_position.y -= GetSystemMetrics(SM_CXMENUSIZE)/2; + mouse_position.y = max(mouse_position.y, 20); + POINT position[] = { mouse_position }; + folder_view->SelectAndPositionItems(1, shell_item_to_select_and_position, position, common_select_flags | SVSI_POSITIONITEM); + } + else + { + // Enter rename mode + folder_view->SelectItem(i, common_select_flags); + } + done = true; + } CoTaskMemFree(shell_item_ids); + } + } + + inline HRESULT copy_template(const template_item* template_entry, const ComPtr site_of_folder) + { + HRESULT hr = S_OK; + + Trace trace_on; - std::wstring current_filename = std::filesystem::path(path_of_item.c_str()).filename(); + try + { + Logger::info(L"Copying template"); + + // Determine target path of where context menu was displayed + const auto target_path_name = utilities::get_path_from_unknown_site(site_of_folder); + + // Determine initial filename + std::filesystem::path source_fullpath = template_entry->path; + std::filesystem::path target_fullpath = std::wstring(target_path_name); - //if (utilities::wstring_same_when_comparing_ignore_case(filename, current_filename)) - if (StrCmpIW(new_file_or_dir_without_path.c_str(), current_filename.c_str()) == 0) + // Only append name to target if source is not a directory + if (!utilities::is_directory(source_fullpath)) { - folder_view->SelectItem(i, SVSI_EDIT | SVSI_SELECT | SVSI_DESELECTOTHERS | SVSI_ENSUREVISIBLE | SVSI_FOCUSED); - break; + target_fullpath.append(template_entry->get_target_filename(!utilities::get_newplus_setting_hide_starting_digits())); } + + // Copy file and determine final filename + std::filesystem::path target_final_fullpath = template_entry->copy_object_to(GetActiveWindow(), target_fullpath); + + Trace::EventCopyTemplate(target_final_fullpath.extension().c_str()); + + // Refresh folder items + template_entry->refresh_target(target_final_fullpath); + + // Enter rename mode + template_entry->enter_rename_mode(target_final_fullpath); + } + catch (const std::exception& ex) + { + Logger::error(ex.what()); + + hr = S_FALSE; + } + + Trace::EventCopyTemplateResult(hr); + + return hr; + } + + inline HRESULT open_template_folder(const std::filesystem::path template_folder) + { + HRESULT hr = S_OK; + + Trace trace_on; + + try + { + Logger::info(L"Open templates folder"); + + const std::wstring verb_hardcoded_do_not_change = L"open"; + ShellExecute(nullptr, verb_hardcoded_do_not_change.c_str(), template_folder.c_str(), NULL, NULL, SW_SHOWNORMAL); + + Trace::EventOpenTemplates(); } + catch (const std::exception& ex) + { + Logger::error(ex.what()); + + hr = S_FALSE; + } + + return hr; } } diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu/shell_context_sub_menu_item.cpp b/src/modules/NewPlus/NewShellExtensionContextMenu/shell_context_sub_menu_item.cpp index d1bc2ba29575..2b1b940d65e6 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu/shell_context_sub_menu_item.cpp +++ b/src/modules/NewPlus/NewShellExtensionContextMenu/shell_context_sub_menu_item.cpp @@ -63,49 +63,7 @@ IFACEMETHODIMP shell_context_sub_menu_item::GetState(_In_opt_ IShellItemArray* s IFACEMETHODIMP shell_context_sub_menu_item::Invoke(_In_opt_ IShellItemArray*, _In_opt_ IBindCtx*) noexcept { - HRESULT hr = S_OK; - try - { - trace.UpdateState(true); - - // Determine target path of where context menu was displayed - const auto target_path_name = utilities::get_path_from_unknown_site(site_of_folder); - - // Determine initial filename - std::filesystem::path source_fullpath = template_entry->path; - std::filesystem::path target_fullpath = std::wstring(target_path_name); - - // Only append name to target if source is not a directory - if (!utilities::is_directory(source_fullpath)) - { - target_fullpath.append(template_entry->get_target_filename(!utilities::get_newplus_setting_hide_starting_digits())); - } - - // Copy file and determine final filename - std::filesystem::path target_final_fullpath = template_entry->copy_object_to(GetActiveWindow(), target_fullpath); - - Trace::EventCopyTemplate(target_final_fullpath.extension().c_str()); - - // Refresh folder items - template_entry->refresh_target(target_final_fullpath); - - // Enter rename mode - template_entry->enter_rename_mode(target_final_fullpath); - - Trace::EventCopyTemplateResult(S_OK); - } - catch (const std::exception& ex) - { - Trace::EventCopyTemplateResult(S_FALSE); - Logger::error(ex.what()); - - hr = S_FALSE; - } - - trace.Flush(); - trace.UpdateState(false); - - return hr; + return newplus::utilities::copy_template(template_entry, site_of_folder); } IFACEMETHODIMP shell_context_sub_menu_item::GetFlags(_Out_ EXPCMDFLAGS* returned_flags) @@ -162,9 +120,5 @@ IFACEMETHODIMP template_folder_context_menu_item::GetIcon(_In_opt_ IShellItemArr IFACEMETHODIMP template_folder_context_menu_item::Invoke(_In_opt_ IShellItemArray* selection, _In_opt_ IBindCtx*) noexcept { - Logger::info(L"Open templates folder"); - const std::wstring verb_hardcoded_do_not_change = L"open"; - ShellExecute(nullptr, verb_hardcoded_do_not_change.c_str(), shell_template_folder.c_str(), NULL, NULL, SW_SHOWNORMAL); - - return S_OK; + return newplus::utilities::open_template_folder(shell_template_folder); } diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu/template_item.cpp b/src/modules/NewPlus/NewShellExtensionContextMenu/template_item.cpp index 6fef157fda46..5de461beceee 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu/template_item.cpp +++ b/src/modules/NewPlus/NewShellExtensionContextMenu/template_item.cpp @@ -131,8 +131,8 @@ void template_item::enter_rename_mode(const std::filesystem::path target_fullpat void template_item::rename_on_other_thread_workaround(const std::filesystem::path target_fullpath) { // Have been unable to have Windows Explorer Shell enter rename mode from the main thread - // Sleep for a bit to only enter rename mode when icon has been drawn. Not strictly needed. - const std::chrono::milliseconds approx_wait_for_icon_redraw_not_needed{ 250 }; + // Sleep for a bit to only enter rename mode when icon has been drawn. + const std::chrono::milliseconds approx_wait_for_icon_redraw_not_needed{ 50 }; std::this_thread::sleep_for(std::chrono::milliseconds(approx_wait_for_icon_redraw_not_needed)); newplus::utilities::explorer_enter_rename_mode(target_fullpath); diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu/trace.cpp b/src/modules/NewPlus/NewShellExtensionContextMenu/trace.cpp index d126c6dd024b..df9a167e875f 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu/trace.cpp +++ b/src/modules/NewPlus/NewShellExtensionContextMenu/trace.cpp @@ -10,6 +10,16 @@ TRACELOGGING_DEFINE_PROVIDER( (0x38e8889b, 0x9731, 0x53f5, 0xe9, 0x01, 0xe8, 0xa7, 0xc1, 0x75, 0x30, 0x74), TraceLoggingOptionProjectTelemetry()); +Trace::Trace() +{ + trace.UpdateState(true); +} +Trace::~Trace() +{ + trace.Flush(); + trace.UpdateState(false); +} + void Trace::EventToggleOnOff(_In_ const bool enabled) noexcept { TraceLoggingWriteWrapper( diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu/trace.h b/src/modules/NewPlus/NewShellExtensionContextMenu/trace.h index 1d0c2562855f..2eeadfb80ef5 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu/trace.h +++ b/src/modules/NewPlus/NewShellExtensionContextMenu/trace.h @@ -7,6 +7,8 @@ class Trace : public telemetry::TraceBase { public: + Trace(); + ~Trace(); static void EventToggleOnOff(_In_ const bool new_enabled_state) noexcept; static void EventChangedTemplateLocation() noexcept; static void EventShowTemplateItems(_In_ const size_t number_of_templates) noexcept; From 789db3fed32a4f7fba8b474475e46f411ba1c1be Mon Sep 17 00:00:00 2001 From: Jaime Bernardo Date: Thu, 21 Nov 2024 09:19:50 +0000 Subject: [PATCH 17/24] Fix spellcheck --- .github/actions/spell-check/expect.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/actions/spell-check/expect.txt b/.github/actions/spell-check/expect.txt index 744d3f5fd5b0..f74d7bfbc509 100644 --- a/.github/actions/spell-check/expect.txt +++ b/.github/actions/spell-check/expect.txt @@ -1180,6 +1180,7 @@ pnid Pnp Popups POPUPWINDOW +POSITIONITEM POWERRENAMECONTEXTMENU powerrenameinput POWERRENAMETEST From a42cc349c586d94baa0c2f7a84e0b6ac287a213c Mon Sep 17 00:00:00 2001 From: Jaime Bernardo Date: Thu, 21 Nov 2024 08:42:36 +0000 Subject: [PATCH 18/24] [ci]Fix signing new Workspaces dll in Dart --- .pipelines/ESRPSigning_core.json | 1 + 1 file changed, 1 insertion(+) diff --git a/.pipelines/ESRPSigning_core.json b/.pipelines/ESRPSigning_core.json index 5319bdc55fd9..e1f0101fa240 100644 --- a/.pipelines/ESRPSigning_core.json +++ b/.pipelines/ESRPSigning_core.json @@ -201,6 +201,7 @@ "PowerToys.WorkspacesLauncherUI.exe", "PowerToys.WorkspacesLauncherUI.dll", "PowerToys.WorkspacesModuleInterface.dll", + "PowerToys.WorkspacesCsharpLibrary.dll", "WinUI3Apps\\PowerToys.RegistryPreviewExt.dll", "WinUI3Apps\\PowerToys.RegistryPreviewUILib.dll", From a5347ac0b2434203ead2ba0ed757ea44c7114b2f Mon Sep 17 00:00:00 2001 From: Jaime Bernardo Date: Thu, 21 Nov 2024 11:05:35 +0000 Subject: [PATCH 19/24] Refactor vcxproj --- .../NewPlus.ShellExtension.win10.vcxproj | 206 +----------------- 1 file changed, 10 insertions(+), 196 deletions(-) diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/NewPlus.ShellExtension.win10.vcxproj b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/NewPlus.ShellExtension.win10.vcxproj index 71d4c9355000..f99a77d16a02 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/NewPlus.ShellExtension.win10.vcxproj +++ b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/NewPlus.ShellExtension.win10.vcxproj @@ -4,32 +4,6 @@ - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - Debug - ARM64 - - - Release - ARM64 - - 17.0 Win32Proj @@ -38,151 +12,34 @@ 10.0.22621.0 - - DynamicLibrary - true - v143 - Unicode - - - DynamicLibrary - false - v143 - true - Unicode - - - DynamicLibrary - true - v143 - Unicode - - + DynamicLibrary - false v143 - true Unicode - - DynamicLibrary + true - v143 - Unicode - - DynamicLibrary + false - v143 true - Unicode - - - - - - - - - - - - - - - - + - - ..\..\..\..\$(Platform)\$(Configuration)\WinUI3Apps\ - PowerToys.NewPlus.ShellExtension.win10 - $(Platform)\$(Configuration)\ - - - - - ..\..\..\..\$(Platform)\$(Configuration)\WinUI3Apps\ - PowerToys.NewPlus.ShellExtension.win10 - $(Platform)\$(Configuration)\ - - - - - - PowerToys.NewPlus.ShellExtension.win10 - ..\..\..\..\$(Platform)\$(Configuration)\WinUI3Apps\ - $(Platform)\$(Configuration)\ - - - - - PowerToys.NewPlus.ShellExtension.win10 + ..\..\..\..\$(Platform)\$(Configuration)\WinUI3Apps\ - $(Platform)\$(Configuration)\ - - - - PowerToys.NewPlus.ShellExtension.win10 - ..\..\..\..\$(Platform)\$(Configuration)\WinUI3Apps\ - - - - PowerToys.NewPlus.ShellExtension.win10 - ..\..\..\..\$(Platform)\$(Configuration)\WinUI3Apps\ - - - Level3 - true - WIN32;_DEBUG;NEWPLUSSHELLEXTENSIONWIN10_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - true - Use - pch.h - stdcpplatest - ..\..\..\common\Telemetry;..\..\;..\..\..\;%(AdditionalIncludeDirectories);..\NewShellExtensionContextMenu - - - Windows - true - false - dll.def - runtimeobject.lib;$(CoreLibraryDependencies) - - - - - Level3 - true - true - true - WIN32;NDEBUG;NEWPLUSSHELLEXTENSIONWIN10_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - true - Use - ..\..\..\common\Telemetry;..\..\;..\..\..\;%(AdditionalIncludeDirectories);..\NewShellExtensionContextMenu - false - - - Windows - true - true - true - false - dll.def - runtimeobject.lib;$(CoreLibraryDependencies) - - - + Level3 true @@ -191,6 +48,7 @@ Use ..\..\..\common\Telemetry;..\..\;..\..\..\;%(AdditionalIncludeDirectories);..\NewShellExtensionContextMenu false + stdcpplatest Windows @@ -200,57 +58,18 @@ dll.def - + Level3 - true true - true - NDEBUG;NEWPLUSSHELLEXTENSIONWIN10_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - true - Use - ..\..\..\common\Telemetry;..\..\;..\..\..\;%(AdditionalIncludeDirectories);..\NewShellExtensionContextMenu - false - - - Windows - true - true - true - false - runtimeobject.lib;$(CoreLibraryDependencies) - dll.def - - - - - Level3 - true - _DEBUG;NEWPLUSSHELLEXTENSIONWIN10_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - true - Use - ..\..\..\common\Telemetry;..\..\;..\..\..\;%(AdditionalIncludeDirectories);..\NewShellExtensionContextMenu - false - - - Windows - true - false - runtimeobject.lib;$(CoreLibraryDependencies) - dll.def - - - - - Level3 true - true true NDEBUG;NEWPLUSSHELLEXTENSIONWIN10_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) true Use ..\..\..\common\Telemetry;..\..\;..\..\..\;%(AdditionalIncludeDirectories);..\NewShellExtensionContextMenu false + stdcpplatest Windows @@ -287,12 +106,7 @@ - Create - Create - Create - Create - Create - Create + Create From 8c16afcebabab1df33614387e1c20218d67641b4 Mon Sep 17 00:00:00 2001 From: Jaime Bernardo Date: Thu, 21 Nov 2024 11:19:36 +0000 Subject: [PATCH 20/24] Fix dll having no metadata --- .../new.base.rc | 71 ++++++++++--------- 1 file changed, 38 insertions(+), 33 deletions(-) diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/new.base.rc b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/new.base.rc index e5abd2223661..5a3589275100 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/new.base.rc +++ b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/new.base.rc @@ -1,43 +1,48 @@ #include #include "Generated Files/resource.h" -#include "../../../common/version/version.h" +#include "../../../../common/version/version.h" #define APSTUDIO_READONLY_SYMBOLS #include "winres.h" #undef APSTUDIO_READONLY_SYMBOLS -//1 VERSIONINFO -// FILEVERSION FILE_VERSION -// PRODUCTVERSION PRODUCT_VERSION -// FILEFLAGSMASK VS_FFI_FILEFLAGSMASK -//#ifdef _DEBUG -// FILEFLAGS VS_FF_DEBUG -//#else -// FILEFLAGS 0x0L -//#endif -// FILEOS VOS_NT_WINDOWS32 -// FILETYPE VFT_DLL -// FILESUBTYPE VFT2_UNKNOWN -//BEGIN -// BLOCK "StringFileInfo" -// BEGIN -// BLOCK "040904b0" -// BEGIN -// VALUE "CompanyName", COMPANY_NAME -// VALUE "FileDescription", FILE_DESCRIPTION -// VALUE "FileVersion", FILE_VERSION_STRING -// VALUE "InternalName", INTERNAL_NAME -// VALUE "LegalCopyright", COPYRIGHT_NOTE -// VALUE "OriginalFilename", ORIGINAL_FILENAME -// VALUE "ProductName", PRODUCT_NAME -// VALUE "ProductVersion", PRODUCT_VERSION_STRING -// END -// END -// BLOCK "VarFileInfo" -// BEGIN -// VALUE "Translation", 0x409, 1200 -// END -//END +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION FILE_VERSION + PRODUCTVERSION PRODUCT_VERSION + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", COMPANY_NAME + VALUE "FileDescription", FILE_DESCRIPTION + VALUE "FileVersion", FILE_VERSION_STRING + VALUE "InternalName", INTERNAL_NAME + VALUE "LegalCopyright", COPYRIGHT_NOTE + VALUE "OriginalFilename", ORIGINAL_FILENAME + VALUE "ProductName", PRODUCT_NAME + VALUE "ProductVersion", PRODUCT_VERSION_STRING + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END ///////////////////////////////////////////////////////////////////////////// // From f7b5f90771c1bc17167f6666b3b7d37700200d42 Mon Sep 17 00:00:00 2001 From: Jaime Bernardo Date: Thu, 21 Nov 2024 13:42:51 +0000 Subject: [PATCH 21/24] Add new dll to signing --- .pipelines/ESRPSigning_core.json | 1 + 1 file changed, 1 insertion(+) diff --git a/.pipelines/ESRPSigning_core.json b/.pipelines/ESRPSigning_core.json index e1f0101fa240..878716c7d76b 100644 --- a/.pipelines/ESRPSigning_core.json +++ b/.pipelines/ESRPSigning_core.json @@ -181,6 +181,7 @@ "WinUI3Apps\\PowerToys.NewPlus.ShellExtension.dll", "WinUI3Apps\\NewPlusPackage.msix", + "WinUI3Apps\\PowerToys.NewPlus.ShellExtension.win10.dll", "PowerAccent.Core.dll", "PowerToys.PowerAccent.dll", From 63112b48285bd5e187744330094a3248c72ed8f0 Mon Sep 17 00:00:00 2001 From: Jaime Bernardo Date: Fri, 22 Nov 2024 09:00:51 +0000 Subject: [PATCH 22/24] Remove unneeded spellcheck bit --- .github/actions/spell-check/expect.txt | 1 - .../NewPlus.ShellExtension.win10.vcxproj | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/actions/spell-check/expect.txt b/.github/actions/spell-check/expect.txt index 7cba4d8cb802..6ceee5cb7f69 100644 --- a/.github/actions/spell-check/expect.txt +++ b/.github/actions/spell-check/expect.txt @@ -477,7 +477,6 @@ exsb exstyle EXTENDEDKEY EXTENDEDVERBS -Extensionwin EXTRINSICPROPERTIES eyetracker FANCYZONESDRAWLAYOUTTEST diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/NewPlus.ShellExtension.win10.vcxproj b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/NewPlus.ShellExtension.win10.vcxproj index f99a77d16a02..e5dd2d5a4d31 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/NewPlus.ShellExtension.win10.vcxproj +++ b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/NewPlus.ShellExtension.win10.vcxproj @@ -8,7 +8,7 @@ 17.0 Win32Proj {0db0f63a-d2f8-4da3-a650-2d0b8724218e} - NewPlusShellExtensionwin10 + NewPlusShellExtensionWin10 10.0.22621.0 From 883e58b94eaa5c7eb7cff4d8b9ed3f5f74319d73 Mon Sep 17 00:00:00 2001 From: Jaime Bernardo Date: Fri, 22 Nov 2024 11:47:58 +0000 Subject: [PATCH 23/24] Reduce telemetry spam --- .../shell_context_menu_win10.cpp | 11 ++++++----- .../NewShellExtensionContextMenu/new_utilities.h | 13 +++++++++---- .../shell_context_sub_menu.cpp | 4 +++- .../NewPlus/NewShellExtensionContextMenu/trace.cpp | 10 ---------- .../NewPlus/NewShellExtensionContextMenu/trace.h | 2 -- 5 files changed, 18 insertions(+), 22 deletions(-) diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/shell_context_menu_win10.cpp b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/shell_context_menu_win10.cpp index 61d1ad05e134..e2130ca097c0 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/shell_context_menu_win10.cpp +++ b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/shell_context_menu_win10.cpp @@ -43,8 +43,6 @@ IFACEMETHODIMP shell_context_menu_win10::QueryContextMenu(HMENU menu_handle, UIN return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, 0); } - Trace trace_on; - try { // Create the initial context popup menu containing the list of templates and open templates action @@ -124,9 +122,6 @@ IFACEMETHODIMP shell_context_menu_win10::QueryContextMenu(HMENU menu_handle, UIN } else { - // Log that context menu was shown and with how many items - Trace::EventShowTemplateItems(number_of_templates); - // Return the amount if entries inserted const auto number_of_items_inserted = menu_id - menu_first_cmd_id; return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, number_of_items_inserted); @@ -232,6 +227,12 @@ IFACEMETHODIMP shell_context_menu_win10::InvokeCommand(CMINVOKECOMMANDINFO* para const auto number_of_templates = templates->list_of_templates.size(); const bool is_template_item = selected_menu_item_index < number_of_templates; + // Log that context menu was shown and with how many items + trace.UpdateState(true); + Trace::EventShowTemplateItems(number_of_templates); + trace.Flush(); + trace.UpdateState(false); + if (is_template_item) { // It's a template menu item diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu/new_utilities.h b/src/modules/NewPlus/NewShellExtensionContextMenu/new_utilities.h index e0c0a361c77e..2b084428994c 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu/new_utilities.h +++ b/src/modules/NewPlus/NewShellExtensionContextMenu/new_utilities.h @@ -345,8 +345,6 @@ namespace newplus::utilities { HRESULT hr = S_OK; - Trace trace_on; - try { Logger::info(L"Copying template"); @@ -367,7 +365,10 @@ namespace newplus::utilities // Copy file and determine final filename std::filesystem::path target_final_fullpath = template_entry->copy_object_to(GetActiveWindow(), target_fullpath); + trace.UpdateState(true); Trace::EventCopyTemplate(target_final_fullpath.extension().c_str()); + trace.Flush(); + trace.UpdateState(false); // Refresh folder items template_entry->refresh_target(target_final_fullpath); @@ -382,7 +383,10 @@ namespace newplus::utilities hr = S_FALSE; } + trace.UpdateState(true); Trace::EventCopyTemplateResult(hr); + trace.Flush(); + trace.UpdateState(false); return hr; } @@ -391,8 +395,6 @@ namespace newplus::utilities { HRESULT hr = S_OK; - Trace trace_on; - try { Logger::info(L"Open templates folder"); @@ -400,7 +402,10 @@ namespace newplus::utilities const std::wstring verb_hardcoded_do_not_change = L"open"; ShellExecute(nullptr, verb_hardcoded_do_not_change.c_str(), template_folder.c_str(), NULL, NULL, SW_SHOWNORMAL); + trace.UpdateState(true); Trace::EventOpenTemplates(); + trace.Flush(); + trace.UpdateState(false); } catch (const std::exception& ex) { diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu/shell_context_sub_menu.cpp b/src/modules/NewPlus/NewShellExtensionContextMenu/shell_context_sub_menu.cpp index 47f93beac757..3456cac7e3b4 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu/shell_context_sub_menu.cpp +++ b/src/modules/NewPlus/NewShellExtensionContextMenu/shell_context_sub_menu.cpp @@ -7,7 +7,6 @@ using namespace Microsoft::WRL; // // Sub context menu command enumerator shell_context_sub_menu::shell_context_sub_menu(const ComPtr site_of_folder) { - trace.UpdateState(true); this->site_of_folder = site_of_folder; // Determine the New+ Template folder location @@ -37,7 +36,10 @@ shell_context_sub_menu::shell_context_sub_menu(const ComPtr site_of_fo current_command = explorer_menu_item_commands.cbegin(); // Log that context menu was shown and with how many items + trace.UpdateState(true); Trace::EventShowTemplateItems(number_of_templates); + trace.Flush(); + trace.UpdateState(false); } // IEnumExplorerCommand diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu/trace.cpp b/src/modules/NewPlus/NewShellExtensionContextMenu/trace.cpp index df9a167e875f..d126c6dd024b 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu/trace.cpp +++ b/src/modules/NewPlus/NewShellExtensionContextMenu/trace.cpp @@ -10,16 +10,6 @@ TRACELOGGING_DEFINE_PROVIDER( (0x38e8889b, 0x9731, 0x53f5, 0xe9, 0x01, 0xe8, 0xa7, 0xc1, 0x75, 0x30, 0x74), TraceLoggingOptionProjectTelemetry()); -Trace::Trace() -{ - trace.UpdateState(true); -} -Trace::~Trace() -{ - trace.Flush(); - trace.UpdateState(false); -} - void Trace::EventToggleOnOff(_In_ const bool enabled) noexcept { TraceLoggingWriteWrapper( diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu/trace.h b/src/modules/NewPlus/NewShellExtensionContextMenu/trace.h index 2eeadfb80ef5..1d0c2562855f 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu/trace.h +++ b/src/modules/NewPlus/NewShellExtensionContextMenu/trace.h @@ -7,8 +7,6 @@ class Trace : public telemetry::TraceBase { public: - Trace(); - ~Trace(); static void EventToggleOnOff(_In_ const bool new_enabled_state) noexcept; static void EventChangedTemplateLocation() noexcept; static void EventShowTemplateItems(_In_ const size_t number_of_templates) noexcept; From a23235676de591c7e2eeb0c7efacbe505fa6f0d7 Mon Sep 17 00:00:00 2001 From: Jaime Bernardo Date: Tue, 26 Nov 2024 13:40:30 +0000 Subject: [PATCH 24/24] Reduce garralous telemetry calls --- .../NewPlus.ShellExtension.win10.vcxproj | 1 + ...wPlus.ShellExtension.win10.vcxproj.filters | 3 +++ .../shell_context_menu_win10.cpp | 8 +++----- .../NewShellExtensionContextMenu.vcxproj | 3 ++- ...wShellExtensionContextMenu.vcxproj.filters | 18 ++++++----------- .../new_utilities.cpp | 13 ++++++++++++ .../new_utilities.h | 20 +++++++++++++++++++ .../shell_context_sub_menu.cpp | 9 ++++----- 8 files changed, 52 insertions(+), 23 deletions(-) create mode 100644 src/modules/NewPlus/NewShellExtensionContextMenu/new_utilities.cpp diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/NewPlus.ShellExtension.win10.vcxproj b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/NewPlus.ShellExtension.win10.vcxproj index e5dd2d5a4d31..6d975b33262d 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/NewPlus.ShellExtension.win10.vcxproj +++ b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/NewPlus.ShellExtension.win10.vcxproj @@ -97,6 +97,7 @@ + diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/NewPlus.ShellExtension.win10.vcxproj.filters b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/NewPlus.ShellExtension.win10.vcxproj.filters index 1c737dac12c2..25399a81dc3d 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/NewPlus.ShellExtension.win10.vcxproj.filters +++ b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/NewPlus.ShellExtension.win10.vcxproj.filters @@ -89,6 +89,9 @@ Source Files + + Source Files + diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/shell_context_menu_win10.cpp b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/shell_context_menu_win10.cpp index e2130ca097c0..c54631df0925 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu.win10/shell_context_menu_win10.cpp +++ b/src/modules/NewPlus/NewShellExtensionContextMenu.win10/shell_context_menu_win10.cpp @@ -227,11 +227,9 @@ IFACEMETHODIMP shell_context_menu_win10::InvokeCommand(CMINVOKECOMMANDINFO* para const auto number_of_templates = templates->list_of_templates.size(); const bool is_template_item = selected_menu_item_index < number_of_templates; - // Log that context menu was shown and with how many items - trace.UpdateState(true); - Trace::EventShowTemplateItems(number_of_templates); - trace.Flush(); - trace.UpdateState(false); + // Save how many item templates we have so it can be sent later when we do something with New+. + // It will be sent when the user does something, similar to Windows 11 context menu. + newplus::utilities::set_saved_number_of_templates(static_cast(number_of_templates)); if (is_template_item) { diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu/NewShellExtensionContextMenu.vcxproj b/src/modules/NewPlus/NewShellExtensionContextMenu/NewShellExtensionContextMenu.vcxproj index 8d2e61757922..68b74d6ae14a 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu/NewShellExtensionContextMenu.vcxproj +++ b/src/modules/NewPlus/NewShellExtensionContextMenu/NewShellExtensionContextMenu.vcxproj @@ -128,6 +128,7 @@ MakeAppx.exe pack /d . /p $(OutDir)NewPlusPackage.msix /nv + @@ -227,7 +228,7 @@ MakeAppx.exe pack /d . /p $(OutDir)NewPlusPackage.msix /nv - + diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu/NewShellExtensionContextMenu.vcxproj.filters b/src/modules/NewPlus/NewShellExtensionContextMenu/NewShellExtensionContextMenu.vcxproj.filters index 2e8323a6f94d..de0cea201749 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu/NewShellExtensionContextMenu.vcxproj.filters +++ b/src/modules/NewPlus/NewShellExtensionContextMenu/NewShellExtensionContextMenu.vcxproj.filters @@ -31,6 +31,9 @@ Source Files + + Source Files + @@ -123,9 +126,6 @@ Source Files - - Asset Files - Asset Files @@ -190,14 +190,8 @@ - - Template Examples\Example folder - - - Template Examples\Example folder - - - Template Examples - + + + \ No newline at end of file diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu/new_utilities.cpp b/src/modules/NewPlus/NewShellExtensionContextMenu/new_utilities.cpp new file mode 100644 index 000000000000..d7c324e5afcf --- /dev/null +++ b/src/modules/NewPlus/NewShellExtensionContextMenu/new_utilities.cpp @@ -0,0 +1,13 @@ +#include "pch.h" +#include "new_utilities.h" + +// HACK: Store number of templates when generating the menu entries to send later. +size_t saved_number_of_templates = -1; +size_t newplus::utilities::get_saved_number_of_templates() +{ + return saved_number_of_templates; +} +void newplus::utilities::set_saved_number_of_templates(size_t templates) +{ + saved_number_of_templates = templates; +} diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu/new_utilities.h b/src/modules/NewPlus/NewShellExtensionContextMenu/new_utilities.h index 2b084428994c..adf186a50986 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu/new_utilities.h +++ b/src/modules/NewPlus/NewShellExtensionContextMenu/new_utilities.h @@ -16,6 +16,8 @@ using namespace newplus; namespace newplus::utilities { + size_t get_saved_number_of_templates(); + void set_saved_number_of_templates(size_t templates); inline std::wstring get_explorer_icon(std::filesystem::path path) { @@ -349,6 +351,15 @@ namespace newplus::utilities { Logger::info(L"Copying template"); + if (newplus::utilities::get_saved_number_of_templates() >= 0) + { + // Log that context menu was shown and with how many items + trace.UpdateState(true); + Trace::EventShowTemplateItems(newplus::utilities::get_saved_number_of_templates()); + trace.Flush(); + trace.UpdateState(false); + } + // Determine target path of where context menu was displayed const auto target_path_name = utilities::get_path_from_unknown_site(site_of_folder); @@ -399,6 +410,15 @@ namespace newplus::utilities { Logger::info(L"Open templates folder"); + if (newplus::utilities::get_saved_number_of_templates() >= 0) + { + // Log that context menu was shown and with how many items + trace.UpdateState(true); + Trace::EventShowTemplateItems(newplus::utilities::get_saved_number_of_templates()); + trace.Flush(); + trace.UpdateState(false); + } + const std::wstring verb_hardcoded_do_not_change = L"open"; ShellExecute(nullptr, verb_hardcoded_do_not_change.c_str(), template_folder.c_str(), NULL, NULL, SW_SHOWNORMAL); diff --git a/src/modules/NewPlus/NewShellExtensionContextMenu/shell_context_sub_menu.cpp b/src/modules/NewPlus/NewShellExtensionContextMenu/shell_context_sub_menu.cpp index 3456cac7e3b4..921130baa4f2 100644 --- a/src/modules/NewPlus/NewShellExtensionContextMenu/shell_context_sub_menu.cpp +++ b/src/modules/NewPlus/NewShellExtensionContextMenu/shell_context_sub_menu.cpp @@ -1,6 +1,7 @@ #include "pch.h" #include "shell_context_sub_menu.h" #include "trace.h" +#include "new_utilities.h" using namespace Microsoft::WRL; @@ -35,11 +36,9 @@ shell_context_sub_menu::shell_context_sub_menu(const ComPtr site_of_fo current_command = explorer_menu_item_commands.cbegin(); - // Log that context menu was shown and with how many items - trace.UpdateState(true); - Trace::EventShowTemplateItems(number_of_templates); - trace.Flush(); - trace.UpdateState(false); + // Save how many item templates we have so it can be sent later when we do something with New+. + // We don't send it here or it would send an event every time we open a context menu. + newplus::utilities::set_saved_number_of_templates(static_cast(number_of_templates)); } // IEnumExplorerCommand