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 000000000..14aaf5440 Binary files /dev/null and b/PowerEditor/src/tools/NppModernShell/Packaging/Square150x150Logo.png differ diff --git a/PowerEditor/src/tools/NppModernShell/Packaging/Square44x44Logo.png b/PowerEditor/src/tools/NppModernShell/Packaging/Square44x44Logo.png new file mode 100644 index 000000000..488dcdf47 Binary files /dev/null and b/PowerEditor/src/tools/NppModernShell/Packaging/Square44x44Logo.png differ diff --git a/PowerEditor/src/tools/NppModernShell/Packaging/StoreLogo.png b/PowerEditor/src/tools/NppModernShell/Packaging/StoreLogo.png new file mode 100644 index 000000000..dcab10a55 Binary files /dev/null and b/PowerEditor/src/tools/NppModernShell/Packaging/StoreLogo.png differ 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