From ce4d374a4782185f2e0dbaa2e6527ba7f8b9ad39 Mon Sep 17 00:00:00 2001 From: Bjarke Istrup Pedersen Date: Sat, 11 Mar 2023 11:17:27 +0100 Subject: [PATCH] Add Windows 11 context menu entry "Edit with Notepad++" This commit implements the Windows 11 context menu using the correct way of having a DLL file and a sparse package. Fix #13320, close #13330 --- PowerEditor/src/notepad++.exe.manifest | 5 + .../src/tools/NppModernShell/.gitignore | 2 + .../NppModernShell/CommandHandlerFactory.cpp | 35 ++++ .../NppModernShell/CommandHandlerFactory.h | 12 ++ .../EditWithNppExplorerCommandHandler.cpp | 78 +++++++ .../EditWithNppExplorerCommandHandler.h | 20 ++ .../NppModernShell/ExplorerCommandBase.cpp | 68 ++++++ .../NppModernShell/ExplorerCommandBase.h | 24 +++ .../src/tools/NppModernShell/Helpers.cpp | 27 +++ .../src/tools/NppModernShell/Helpers.h | 9 + .../src/tools/NppModernShell/Installer.cpp | 72 +++++++ .../src/tools/NppModernShell/Installer.h | 10 + .../tools/NppModernShell/NppModernShell.sln | 39 ++++ .../NppModernShell/NppModernShell.vcxproj | 198 ++++++++++++++++++ .../NppModernShell.vcxproj.filters | 55 +++++ .../NppModernShell/Packaging/AppxManifest.xml | 50 +++++ .../Packaging/Square150x150Logo.png | Bin 0 -> 38542 bytes .../Packaging/Square44x44Logo.png | Bin 0 -> 4643 bytes .../NppModernShell/Packaging/StoreLogo.png | Bin 0 -> 5034 bytes .../src/tools/NppModernShell/README.md | 68 ++++++ .../src/tools/NppModernShell/dllmain.cpp | 62 ++++++ .../src/tools/NppModernShell/framework.h | 16 ++ .../src/tools/NppModernShell/packages.config | 4 + PowerEditor/src/tools/NppModernShell/pch.cpp | 5 + PowerEditor/src/tools/NppModernShell/pch.h | 15 ++ .../src/tools/NppModernShell/source.def | 6 + 26 files changed, 880 insertions(+) create mode 100644 PowerEditor/src/tools/NppModernShell/.gitignore create mode 100644 PowerEditor/src/tools/NppModernShell/CommandHandlerFactory.cpp create mode 100644 PowerEditor/src/tools/NppModernShell/CommandHandlerFactory.h create mode 100644 PowerEditor/src/tools/NppModernShell/EditWithNppExplorerCommandHandler.cpp create mode 100644 PowerEditor/src/tools/NppModernShell/EditWithNppExplorerCommandHandler.h create mode 100644 PowerEditor/src/tools/NppModernShell/ExplorerCommandBase.cpp create mode 100644 PowerEditor/src/tools/NppModernShell/ExplorerCommandBase.h create mode 100644 PowerEditor/src/tools/NppModernShell/Helpers.cpp create mode 100644 PowerEditor/src/tools/NppModernShell/Helpers.h create mode 100644 PowerEditor/src/tools/NppModernShell/Installer.cpp create mode 100644 PowerEditor/src/tools/NppModernShell/Installer.h create mode 100644 PowerEditor/src/tools/NppModernShell/NppModernShell.sln create mode 100644 PowerEditor/src/tools/NppModernShell/NppModernShell.vcxproj create mode 100644 PowerEditor/src/tools/NppModernShell/NppModernShell.vcxproj.filters create mode 100644 PowerEditor/src/tools/NppModernShell/Packaging/AppxManifest.xml create mode 100644 PowerEditor/src/tools/NppModernShell/Packaging/Square150x150Logo.png create mode 100644 PowerEditor/src/tools/NppModernShell/Packaging/Square44x44Logo.png create mode 100644 PowerEditor/src/tools/NppModernShell/Packaging/StoreLogo.png create mode 100644 PowerEditor/src/tools/NppModernShell/README.md create mode 100644 PowerEditor/src/tools/NppModernShell/dllmain.cpp create mode 100644 PowerEditor/src/tools/NppModernShell/framework.h create mode 100644 PowerEditor/src/tools/NppModernShell/packages.config create mode 100644 PowerEditor/src/tools/NppModernShell/pch.cpp create mode 100644 PowerEditor/src/tools/NppModernShell/pch.h create mode 100644 PowerEditor/src/tools/NppModernShell/source.def diff --git a/PowerEditor/src/notepad++.exe.manifest b/PowerEditor/src/notepad++.exe.manifest index b78fd9175..8dca871b4 100644 --- a/PowerEditor/src/notepad++.exe.manifest +++ b/PowerEditor/src/notepad++.exe.manifest @@ -7,6 +7,11 @@ name="Notepad++" type="win32" /> + Notepad++ diff --git a/PowerEditor/src/tools/NppModernShell/.gitignore b/PowerEditor/src/tools/NppModernShell/.gitignore new file mode 100644 index 000000000..a41d7220a --- /dev/null +++ b/PowerEditor/src/tools/NppModernShell/.gitignore @@ -0,0 +1,2 @@ +packages +Packaging/NppModernShell.msix \ No newline at end of file diff --git a/PowerEditor/src/tools/NppModernShell/CommandHandlerFactory.cpp b/PowerEditor/src/tools/NppModernShell/CommandHandlerFactory.cpp new file mode 100644 index 000000000..defd9e508 --- /dev/null +++ b/PowerEditor/src/tools/NppModernShell/CommandHandlerFactory.cpp @@ -0,0 +1,35 @@ +#include "pch.h" +#include "CommandHandlerFactory.h" + +#include "EditWithNppExplorerCommandHandler.h" + +using namespace NppModernShell::CommandHandlers; +using namespace NppModernShell::Factories; + +IFACEMETHODIMP CommandHandlerFactory::CreateInstance(_In_opt_ IUnknown* pUnkOuter, _In_ REFIID riid, _COM_Outptr_ void** ppvObject) noexcept +{ + UNREFERENCED_PARAMETER(pUnkOuter); + + try + { + return winrt::make()->QueryInterface(riid, ppvObject); + } + catch (...) + { + return winrt::to_hresult(); + } +} + +IFACEMETHODIMP CommandHandlerFactory::LockServer(_In_ BOOL fLock) noexcept +{ + if (fLock) + { + ++winrt::get_module_lock(); + } + else + { + --winrt::get_module_lock(); + } + + return S_OK; +} \ No newline at end of file diff --git a/PowerEditor/src/tools/NppModernShell/CommandHandlerFactory.h b/PowerEditor/src/tools/NppModernShell/CommandHandlerFactory.h new file mode 100644 index 000000000..786835a57 --- /dev/null +++ b/PowerEditor/src/tools/NppModernShell/CommandHandlerFactory.h @@ -0,0 +1,12 @@ +#pragma once +#include "pch.h" + +namespace NppModernShell::Factories +{ + class __declspec(uuid("4EACAA14-3B43-4595-A44C-FBA8F0848620")) CommandHandlerFactory : public winrt::implements + { + public: + IFACEMETHODIMP CreateInstance(_In_opt_ IUnknown* pUnkOuter, _In_ REFIID riid, _COM_Outptr_ void** ppvObject) noexcept override; + IFACEMETHODIMP LockServer(_In_ BOOL fLock) noexcept override; + }; +} \ No newline at end of file diff --git a/PowerEditor/src/tools/NppModernShell/EditWithNppExplorerCommandHandler.cpp b/PowerEditor/src/tools/NppModernShell/EditWithNppExplorerCommandHandler.cpp new file mode 100644 index 000000000..82bd82427 --- /dev/null +++ b/PowerEditor/src/tools/NppModernShell/EditWithNppExplorerCommandHandler.cpp @@ -0,0 +1,78 @@ +#include "pch.h" +#include "EditWithNppExplorerCommandHandler.h" + +#include "Helpers.h" + +using namespace NppModernShell::CommandHandlers; +using namespace NppModernShell::Helpers; + +const wstring EditWithNppExplorerCommandHandler::GetNppExecutableFullPath() +{ + const wstring path = GetInstallationPath(); + const wstring fileName = L"\\notepad++.exe"; + + return L"\"" + path + fileName + L"\""; +} + +const wstring EditWithNppExplorerCommandHandler::Title() +{ + return L"Edit with Notepad++"; +} + +const wstring EditWithNppExplorerCommandHandler::Icon() +{ + const wstring fileName = GetNppExecutableFullPath(); + + return fileName; +} + +const wstring EditWithNppExplorerCommandHandler::GetCommandLine() +{ + const wstring fileName = GetNppExecutableFullPath(); + const wstring parameters = L"\"%1\""; + + return fileName + L" " + parameters; +} + +IFACEMETHODIMP EditWithNppExplorerCommandHandler::Invoke(_In_opt_ IShellItemArray* selection, _In_opt_ IBindCtx*) noexcept try +{ + if (!selection) + { + return S_OK; + } + + DWORD count; + RETURN_IF_FAILED(selection->GetCount(&count)); + + IShellItem* psi; + LPWSTR itemName; + + for (DWORD i = 0; i < count; ++i) + { + selection->GetItemAt(i, &psi); + RETURN_IF_FAILED(psi->GetDisplayName(SIGDN_FILESYSPATH, &itemName)); + + std::wstring cmdline = this->GetCommandLine(); + cmdline = cmdline.replace(cmdline.find(L"%1"), 2, itemName); + + STARTUPINFO si; + PROCESS_INFORMATION pi; + + ZeroMemory(&si, sizeof(si)); + si.cb = sizeof(si); + ZeroMemory(&pi, sizeof(pi)); + + wchar_t* command = (LPWSTR)cmdline.c_str(); + + if (!CreateProcess(nullptr, command, nullptr, nullptr, false, CREATE_NEW_PROCESS_GROUP, nullptr, nullptr, &si, &pi)) + { + return S_OK; + } + + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + } + + return S_OK; +} +CATCH_RETURN(); \ No newline at end of file diff --git a/PowerEditor/src/tools/NppModernShell/EditWithNppExplorerCommandHandler.h b/PowerEditor/src/tools/NppModernShell/EditWithNppExplorerCommandHandler.h new file mode 100644 index 000000000..0da41c934 --- /dev/null +++ b/PowerEditor/src/tools/NppModernShell/EditWithNppExplorerCommandHandler.h @@ -0,0 +1,20 @@ +#pragma once +#include "pch.h" + +#include "ExplorerCommandBase.h" + +namespace NppModernShell::CommandHandlers +{ + class EditWithNppExplorerCommandHandler : public ExplorerCommandBase + { + public: + const wstring Title() override; + const wstring Icon() override; + + IFACEMETHODIMP Invoke(_In_opt_ IShellItemArray* selection, _In_opt_ IBindCtx*) noexcept override; + + private: + const wstring GetNppExecutableFullPath(); + const wstring GetCommandLine(); + }; +} \ No newline at end of file diff --git a/PowerEditor/src/tools/NppModernShell/ExplorerCommandBase.cpp b/PowerEditor/src/tools/NppModernShell/ExplorerCommandBase.cpp new file mode 100644 index 000000000..d2b8017f8 --- /dev/null +++ b/PowerEditor/src/tools/NppModernShell/ExplorerCommandBase.cpp @@ -0,0 +1,68 @@ +#include "pch.h" +#include "ExplorerCommandBase.h" + +using namespace NppModernShell::CommandHandlers; + +const EXPCMDFLAGS ExplorerCommandBase::Flags() +{ + return ECF_DEFAULT; +} + +const EXPCMDSTATE ExplorerCommandBase::State(_In_opt_ IShellItemArray* selection) +{ + UNREFERENCED_PARAMETER(selection); + + return ECS_ENABLED; +} + +IFACEMETHODIMP ExplorerCommandBase::GetTitle(_In_opt_ IShellItemArray* items, _Outptr_result_nullonfailure_ PWSTR* name) +{ + UNREFERENCED_PARAMETER(items); + + *name = nullptr; + auto str = wil::make_cotaskmem_string_nothrow(Title().c_str()); + RETURN_IF_NULL_ALLOC(str); + *name = str.release(); + return S_OK; +} + +IFACEMETHODIMP ExplorerCommandBase::GetIcon(_In_opt_ IShellItemArray*, _Outptr_result_nullonfailure_ PWSTR* icon) +{ + *icon = nullptr; + auto str = wil::make_cotaskmem_string_nothrow(Icon().c_str()); + RETURN_IF_NULL_ALLOC(str); + *icon = str.release(); + return S_OK; +} + +IFACEMETHODIMP ExplorerCommandBase::GetToolTip(_In_opt_ IShellItemArray*, _Outptr_result_nullonfailure_ PWSTR* infoTip) +{ + *infoTip = nullptr; + return E_NOTIMPL; +} + +IFACEMETHODIMP ExplorerCommandBase::GetState(_In_opt_ IShellItemArray* selection, _In_ BOOL okToBeSlow, _Out_ EXPCMDSTATE* cmdState) +{ + UNREFERENCED_PARAMETER(okToBeSlow); + + *cmdState = State(selection); + return S_OK; +} + +IFACEMETHODIMP ExplorerCommandBase::GetFlags(_Out_ EXPCMDFLAGS* flags) +{ + *flags = Flags(); + return S_OK; +} + +IFACEMETHODIMP ExplorerCommandBase::GetCanonicalName(_Out_ GUID* guidCommandName) +{ + *guidCommandName = GUID_NULL; + return E_NOTIMPL; +} + +IFACEMETHODIMP ExplorerCommandBase::EnumSubCommands(_COM_Outptr_ IEnumExplorerCommand** enumCommands) +{ + *enumCommands = nullptr; + return E_NOTIMPL; +} \ No newline at end of file diff --git a/PowerEditor/src/tools/NppModernShell/ExplorerCommandBase.h b/PowerEditor/src/tools/NppModernShell/ExplorerCommandBase.h new file mode 100644 index 000000000..c3cbb5b22 --- /dev/null +++ b/PowerEditor/src/tools/NppModernShell/ExplorerCommandBase.h @@ -0,0 +1,24 @@ +#pragma once +#include "pch.h" + +namespace NppModernShell::CommandHandlers +{ + class ExplorerCommandBase : public winrt::implements + { + public: + virtual const wstring Title() = 0; + virtual const wstring Icon() = 0; + virtual const EXPCMDFLAGS Flags(); + virtual const EXPCMDSTATE State(_In_opt_ IShellItemArray* selection); + + IFACEMETHODIMP GetTitle(_In_opt_ IShellItemArray* items, _Outptr_result_nullonfailure_ PWSTR* name); + IFACEMETHODIMP GetIcon(_In_opt_ IShellItemArray*, _Outptr_result_nullonfailure_ PWSTR* icon); + IFACEMETHODIMP GetToolTip(_In_opt_ IShellItemArray*, _Outptr_result_nullonfailure_ PWSTR* infoTip); + IFACEMETHODIMP GetState(_In_opt_ IShellItemArray* selection, _In_ BOOL okToBeSlow, _Out_ EXPCMDSTATE* cmdState); + IFACEMETHODIMP GetFlags(_Out_ EXPCMDFLAGS* flags); + IFACEMETHODIMP GetCanonicalName(_Out_ GUID* guidCommandName); + IFACEMETHODIMP EnumSubCommands(_COM_Outptr_ IEnumExplorerCommand** enumCommands); + + virtual IFACEMETHODIMP Invoke(_In_opt_ IShellItemArray* selection, _In_opt_ IBindCtx*) noexcept = 0; + }; +} \ No newline at end of file diff --git a/PowerEditor/src/tools/NppModernShell/Helpers.cpp b/PowerEditor/src/tools/NppModernShell/Helpers.cpp new file mode 100644 index 000000000..97cbb661b --- /dev/null +++ b/PowerEditor/src/tools/NppModernShell/Helpers.cpp @@ -0,0 +1,27 @@ +#include "pch.h" +#include "Helpers.h" + +using namespace NppModernShell::Helpers; + +const HMODULE GetThisModule() +{ + HMODULE hm = NULL; + + BOOL result = GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (LPCWSTR)&GetInstallationPath, &hm); + + if (result == FALSE) + { + throw "Failed to locate current module, unable to proceed"; + } + + return hm; +} + +const wstring NppModernShell::Helpers::GetInstallationPath() +{ + HMODULE thisModule = GetThisModule(); + + wchar_t path[FILENAME_MAX] = { 0 }; + GetModuleFileName(thisModule, path, FILENAME_MAX); + return std::filesystem::path(path).parent_path().wstring(); +} \ No newline at end of file diff --git a/PowerEditor/src/tools/NppModernShell/Helpers.h b/PowerEditor/src/tools/NppModernShell/Helpers.h new file mode 100644 index 000000000..2bc82490d --- /dev/null +++ b/PowerEditor/src/tools/NppModernShell/Helpers.h @@ -0,0 +1,9 @@ +#pragma once +#include "pch.h" + +#include + +namespace NppModernShell::Helpers +{ + const wstring GetInstallationPath(); +} \ No newline at end of file diff --git a/PowerEditor/src/tools/NppModernShell/Installer.cpp b/PowerEditor/src/tools/NppModernShell/Installer.cpp new file mode 100644 index 000000000..8b23e911d --- /dev/null +++ b/PowerEditor/src/tools/NppModernShell/Installer.cpp @@ -0,0 +1,72 @@ +#include "pch.h" +#include "Installer.h" + +using namespace winrt::Windows::ApplicationModel; +using namespace winrt::Windows::Foundation; +using namespace winrt::Windows::Foundation::Collections; +using namespace winrt::Windows::Management::Deployment; + +using namespace NppModernShell::Helpers; +using namespace NppModernShell::Installer; + +const wstring SparsePackageName = L"NotepadPlusPlus"; + +STDAPI NppModernShell::Installer::RegisterSparsePackage() +{ + PackageManager packageManager; + AddPackageOptions options; + + const wstring externalLocation = GetInstallationPath(); + const wstring sparsePkgPath = externalLocation + L"\\NppModernShell.msix"; + + Uri externalUri(externalLocation); + Uri packageUri(sparsePkgPath); + + options.ExternalLocationUri(externalUri); + + auto deploymentOperation = packageManager.AddPackageByUriAsync(packageUri, options); + auto deployResult = deploymentOperation.get(); + + if (!SUCCEEDED(deployResult.ExtendedErrorCode())) + { + return deployResult.ExtendedErrorCode(); + } + + return S_OK; +} + +STDAPI NppModernShell::Installer::UnregisterSparsePackage() +{ + PackageManager packageManager; + IIterable packages; + + try + { + packages = packageManager.FindPackagesForUser(L""); + } + catch (winrt::hresult_error const& ex) + { + return ex.code(); + } + + for (const Package& package : packages) + { + if (package.Id().Name() != SparsePackageName) + { + continue; + } + + winrt::hstring fullName = package.Id().FullName(); + auto deploymentOperation = packageManager.RemovePackageAsync(fullName, RemovalOptions::None); + auto deployResult = deploymentOperation.get(); + + if (!SUCCEEDED(deployResult.ExtendedErrorCode())) + { + return deployResult.ExtendedErrorCode(); + } + + break; + } + + return S_OK; +} \ No newline at end of file diff --git a/PowerEditor/src/tools/NppModernShell/Installer.h b/PowerEditor/src/tools/NppModernShell/Installer.h new file mode 100644 index 000000000..ac566f7d0 --- /dev/null +++ b/PowerEditor/src/tools/NppModernShell/Installer.h @@ -0,0 +1,10 @@ +#pragma once +#include "pch.h" + +#include "Helpers.h" + +namespace NppModernShell::Installer +{ + STDAPI RegisterSparsePackage(); + STDAPI UnregisterSparsePackage(); +} \ No newline at end of file diff --git a/PowerEditor/src/tools/NppModernShell/NppModernShell.sln b/PowerEditor/src/tools/NppModernShell/NppModernShell.sln new file mode 100644 index 000000000..d28cc4acb --- /dev/null +++ b/PowerEditor/src/tools/NppModernShell/NppModernShell.sln @@ -0,0 +1,39 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.5.33414.496 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NppModernShell", "NppModernShell.vcxproj", "{E7539F55-2932-47D0-82B8-46ED5AFCA1C0}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Packaging", "Packaging", "{B9E2DBFF-8940-482F-9D07-BA9C4EAE7620}" + ProjectSection(SolutionItems) = preProject + Packaging\AppxManifest.xml = Packaging\AppxManifest.xml + Packaging\Square150x150Logo.png = Packaging\Square150x150Logo.png + Packaging\Square44x44Logo.png = Packaging\Square44x44Logo.png + Packaging\StoreLogo.png = Packaging\StoreLogo.png + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|ARM64 = Debug|ARM64 + Debug|x64 = Debug|x64 + Release|ARM64 = Release|ARM64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E7539F55-2932-47D0-82B8-46ED5AFCA1C0}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {E7539F55-2932-47D0-82B8-46ED5AFCA1C0}.Debug|ARM64.Build.0 = Debug|ARM64 + {E7539F55-2932-47D0-82B8-46ED5AFCA1C0}.Debug|x64.ActiveCfg = Debug|x64 + {E7539F55-2932-47D0-82B8-46ED5AFCA1C0}.Debug|x64.Build.0 = Debug|x64 + {E7539F55-2932-47D0-82B8-46ED5AFCA1C0}.Release|ARM64.ActiveCfg = Release|ARM64 + {E7539F55-2932-47D0-82B8-46ED5AFCA1C0}.Release|ARM64.Build.0 = Release|ARM64 + {E7539F55-2932-47D0-82B8-46ED5AFCA1C0}.Release|x64.ActiveCfg = Release|x64 + {E7539F55-2932-47D0-82B8-46ED5AFCA1C0}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {EAA0AA08-253D-435A-929E-9214D1E358CB} + EndGlobalSection +EndGlobal diff --git a/PowerEditor/src/tools/NppModernShell/NppModernShell.vcxproj b/PowerEditor/src/tools/NppModernShell/NppModernShell.vcxproj new file mode 100644 index 000000000..02e86dfdf --- /dev/null +++ b/PowerEditor/src/tools/NppModernShell/NppModernShell.vcxproj @@ -0,0 +1,198 @@ + + + + + Debug + ARM64 + + + Debug + x64 + + + Release + ARM64 + + + Release + x64 + + + + 16.0 + Win32Proj + {e7539f55-2932-47d0-82b8-46ed5afca1c0} + NppModernShell + 10.0 + + + + DynamicLibrary + true + v143 + Unicode + + + DynamicLibrary + true + v143 + Unicode + + + DynamicLibrary + false + v143 + true + Unicode + + + DynamicLibrary + false + v143 + true + Unicode + + + + + + + + + + + + + + + + + + + + + + Level4 + true + _DEBUG;NPPMODERNSHELL_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + Use + pch.h + stdcpp20 + MultiThreadedDebug + true + + + Windows + true + false + shlwapi.lib;runtimeobject.lib;%(AdditionalDependencies) + source.def + + + + + Level4 + true + _DEBUG;NPPMODERNSHELL_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + Use + pch.h + stdcpp20 + MultiThreadedDebug + true + + + Windows + true + false + shlwapi.lib;runtimeobject.lib;%(AdditionalDependencies) + source.def + + + + + Level4 + true + true + true + NDEBUG;NPPMODERNSHELL_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + Use + pch.h + stdcpp20 + MultiThreaded + true + + + Windows + true + true + true + false + shlwapi.lib;runtimeobject.lib;%(AdditionalDependencies) + source.def + + + + + Level4 + true + true + true + NDEBUG;NPPMODERNSHELL_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + Use + pch.h + stdcpp20 + MultiThreaded + true + + + Windows + true + true + true + false + shlwapi.lib;runtimeobject.lib;%(AdditionalDependencies) + source.def + + + + + + + + + + + + + + + + + + + + Create + Create + Create + Create + + + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + \ No newline at end of file diff --git a/PowerEditor/src/tools/NppModernShell/NppModernShell.vcxproj.filters b/PowerEditor/src/tools/NppModernShell/NppModernShell.vcxproj.filters new file mode 100644 index 000000000..164737779 --- /dev/null +++ b/PowerEditor/src/tools/NppModernShell/NppModernShell.vcxproj.filters @@ -0,0 +1,55 @@ + + + + + {ff31b0d8-bf03-4a28-945d-cfae6eb365fa} + + + {3ce00d49-8c93-43bf-8d92-00c9b7087776} + + + {ca898efe-24d8-4317-99c9-769e8e80c3aa} + + + + + CommandHandlers + + + CommandHandlers + + + Installer + + + Factories + + + + + + + + CommandHandlers + + + CommandHandlers + + + Installer + + + + + + Factories + + + + + + + + + + \ No newline at end of file diff --git a/PowerEditor/src/tools/NppModernShell/Packaging/AppxManifest.xml b/PowerEditor/src/tools/NppModernShell/Packaging/AppxManifest.xml new file mode 100644 index 000000000..28ffaa987 --- /dev/null +++ b/PowerEditor/src/tools/NppModernShell/Packaging/AppxManifest.xml @@ -0,0 +1,50 @@ + + + + + Notepad++ + Notepad++ + StoreLogo.png + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/PowerEditor/src/tools/NppModernShell/Packaging/Square150x150Logo.png b/PowerEditor/src/tools/NppModernShell/Packaging/Square150x150Logo.png new file mode 100644 index 0000000000000000000000000000000000000000..14aaf5440d3f0d93c5d3cc9d6ecce6a91df1274a GIT binary patch literal 38542 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 AUjP6A literal 0 HcmV?d00001 diff --git a/PowerEditor/src/tools/NppModernShell/README.md b/PowerEditor/src/tools/NppModernShell/README.md new file mode 100644 index 000000000..a34ff8f2a --- /dev/null +++ b/PowerEditor/src/tools/NppModernShell/README.md @@ -0,0 +1,68 @@ +# Windows 11 Modern UI Context Menu integration + +The purpose of this project is to allow Notepad++ to integrate into the new Windows 11 right-click context menu. +Doing this requires two new things. + +* A dll library with some COM objects that the shell can communicate with. +* A Sparse Package containing the metadata for the COM server. + +To build this, the following steps needs to be taken: + +1. Build a Release dll file (NppModernShell.dll) +2. Generate a Sparse Package (NppModernShell.msix) +3. Sign both of these with signtool.exe +4. Make sure they are included in the installer, so they are deployed next to the notepad++.exe program. +5. The installer should, upon installation, install the package. +6. The installer should, upon uninstallation, uninstall the package. + +## Prerequisites + +To be able to build this project, the following is needed: + +* [Visual Studio 2022](https://visualstudio.microsoft.com/vs) +* [Windows 11 SDK](https://developer.microsoft.com/en-us/windows/downloads/windows-sdk) + +## Build a Release dll file (NppModernShell.dll) +Just open the NppModernShell.sln Visual Studio solution, select Release as the build type, and do a Rebuild of the solution. + +## Generate a Sparse Package (NppModernShell.msix) +To generate a Sparse Package, you need to have the makeappx.exe tool in your PATH, the easiest way to do this is to run the `Developer Command Prompt for VS 2022` command prompt, since it sets up the path. +Once inside the NppModernShell folder, run the following command to generate the Sparse Package: +``` +makeappx pack /d .\Packaging /p .\NppModernShell.msix /nv +``` +This takes the content of the Packaging directory, and packages them up into the msix file. + +## Sign both of these with signtool.exe +Now we have both the `NppModernShell.dll` and `NppModernShell.msix` files, we need to sign them with a valid certificate. +To do this, once again run the `Developer Command Prompt for VS 2022` command prompt and change to the NppModernShell folder. +The following command expects the following: +* The pfx certificate is called MyCert.pfx +* The password for the pfx certificate is: `Test1234` + +Make the needed changes to match the real certificate. +``` +SignTool.exe sign /fd SHA256 /tr http://timestamp.digicert.com /td sha256 /a /f .\MyCert.pfx /p Test1234 /d "Notepad++" /du https://notepad-plus-plus.org/ NppModernShell.msix +SignTool.exe sign /fd SHA256 /tr http://timestamp.digicert.com /td sha256 /a /f .\MyCert.pfx /p Test1234 /d "Notepad++" /du https://notepad-plus-plus.org/ x64\Release\NppModernShell.dll +``` +Now both files has been signed, and can be used. + +## Make sure they are included in the installer, so they are deployed next to the notepad++.exe program. +The installer needs to deploy the two files into the same directory as notepad++.exe . +They need to be there, since the DLL is looking for notepad++.exe in the same directory as it is located itself. + +## The installer should, upon installation, install the package. +When the installer is running, after all the files has been copied into the program files directory, the follow command should be be run to run the register function to register the package: +``` +rundll32.exe .\NppModernShell.dll,RegisterSparsePackage +``` + +Remember to wait for the rundll32 process to exit before continuing. + +## The installer should, upon uninstallation, uninstall the package. +When the uninstaller is running, it should run this command to unregister the package: +``` +rundll32.exe .\NppModernShell.dll,UnregisterSparsePackage +``` + +Here we need to wait for rundll32 to finish, since if it isn't finished, the dll file will be locked by explorer. \ No newline at end of file diff --git a/PowerEditor/src/tools/NppModernShell/dllmain.cpp b/PowerEditor/src/tools/NppModernShell/dllmain.cpp new file mode 100644 index 000000000..20045ba31 --- /dev/null +++ b/PowerEditor/src/tools/NppModernShell/dllmain.cpp @@ -0,0 +1,62 @@ +#include "pch.h" + +#include "CommandHandlerFactory.h" + +using namespace NppModernShell::Factories; + +BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) +{ + UNREFERENCED_PARAMETER(hModule); + UNREFERENCED_PARAMETER(lpReserved); + + switch (ul_reason_for_call) + { + case DLL_PROCESS_ATTACH: + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + case DLL_PROCESS_DETACH: + break; + } + + return TRUE; +} + +__control_entrypoint(DllExport) +STDAPI DllCanUnloadNow(void) +{ + if (winrt::get_module_lock()) + { + return S_FALSE; + } + + winrt::clear_factory_cache(); + return S_OK; +} + +_Check_return_ +STDAPI DllGetClassObject(_In_ REFCLSID rclsid, _In_ REFIID riid, _Outptr_ LPVOID FAR* ppv) +{ + if (!ppv) + { + return E_POINTER; + } + + if (riid != IID_IClassFactory && riid != IID_IUnknown) + { + return E_NOINTERFACE; + } + + if (rclsid != __uuidof(CommandHandlerFactory)) + { + return E_INVALIDARG; + } + + try + { + return winrt::make()->QueryInterface(riid, ppv); + } + catch (...) + { + return winrt::to_hresult(); + } +} \ No newline at end of file diff --git a/PowerEditor/src/tools/NppModernShell/framework.h b/PowerEditor/src/tools/NppModernShell/framework.h new file mode 100644 index 000000000..6ad3bcca9 --- /dev/null +++ b/PowerEditor/src/tools/NppModernShell/framework.h @@ -0,0 +1,16 @@ +#pragma once + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +// Windows Header Files +#include +#include +#include + +// WinRT Header Files +#include +#include +#include +#include + +// Windows Implementation Library Header Files +#include "wil\winrt.h" \ No newline at end of file diff --git a/PowerEditor/src/tools/NppModernShell/packages.config b/PowerEditor/src/tools/NppModernShell/packages.config new file mode 100644 index 000000000..22819475c --- /dev/null +++ b/PowerEditor/src/tools/NppModernShell/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/PowerEditor/src/tools/NppModernShell/pch.cpp b/PowerEditor/src/tools/NppModernShell/pch.cpp new file mode 100644 index 000000000..64b7eef6d --- /dev/null +++ b/PowerEditor/src/tools/NppModernShell/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/PowerEditor/src/tools/NppModernShell/pch.h b/PowerEditor/src/tools/NppModernShell/pch.h new file mode 100644 index 000000000..1581b7622 --- /dev/null +++ b/PowerEditor/src/tools/NppModernShell/pch.h @@ -0,0 +1,15 @@ +// pch.h: This is a precompiled header file. +// Files listed below are compiled only once, improving build performance for future builds. +// This also affects IntelliSense performance, including code completion and many code browsing features. +// However, files listed here are ALL re-compiled if any one of them is updated between builds. +// Do not add files here that you will be updating frequently as this negates the performance advantage. + +#ifndef PCH_H +#define PCH_H + +// add headers that you want to pre-compile here +#include "framework.h" + +using namespace std; + +#endif //PCH_H diff --git a/PowerEditor/src/tools/NppModernShell/source.def b/PowerEditor/src/tools/NppModernShell/source.def new file mode 100644 index 000000000..80f5f9896 --- /dev/null +++ b/PowerEditor/src/tools/NppModernShell/source.def @@ -0,0 +1,6 @@ +LIBRARY +EXPORTS +DllCanUnloadNow PRIVATE +DllGetClassObject PRIVATE +RegisterSparsePackage +UnregisterSparsePackage \ No newline at end of file