[New+]Windows 10 support (#35832)

This commit is contained in:
Christian Gaarden Gaardmark
2024-11-27 06:22:05 -08:00
committed by GitHub
parent 08fe8089b8
commit 084402a2bd
32 changed files with 1246 additions and 109 deletions

View File

@@ -0,0 +1,152 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props')" />
<Target Name="GenerateResourceFiles" BeforeTargets="PrepareForBuild">
<Exec Command="powershell -NonInteractive -executionpolicy Unrestricted $(SolutionDir)tools\build\convert-resx-to-rc.ps1 $(MSBuildThisFileDirectory) resource.base.h resource.h new.base.rc new.rc" />
</Target>
<PropertyGroup Label="Globals">
<VCProjectVersion>17.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{0db0f63a-d2f8-4da3-a650-2d0b8724218e}</ProjectGuid>
<RootNamespace>NewPlusShellExtensionWin10</RootNamespace>
<WindowsTargetPlatformVersion>10.0.22621.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
<UseDebugLibraries>true</UseDebugLibraries>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<OutDir>..\..\..\..\$(Platform)\$(Configuration)\WinUI3Apps\</OutDir>
<TargetName>PowerToys.NewPlus.ShellExtension.win10</TargetName>
<LinkIncremental />
<IgnoreImportLibrary />
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;NEWPLUSSHELLEXTENSIONWIN10_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>Use</PrecompiledHeader>
<AdditionalIncludeDirectories>..\..\..\common\Telemetry;..\..\;..\..\..\;%(AdditionalIncludeDirectories);..\NewShellExtensionContextMenu</AdditionalIncludeDirectories>
<CompileAsWinRT>false</CompileAsWinRT>
<LanguageStandard>stdcpplatest</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
<AdditionalDependencies>runtimeobject.lib;$(CoreLibraryDependencies)</AdditionalDependencies>
<ModuleDefinitionFile>dll.def</ModuleDefinitionFile>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<IntrinsicFunctions>true</IntrinsicFunctions>
<FunctionLevelLinking>true</FunctionLevelLinking>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;NEWPLUSSHELLEXTENSIONWIN10_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>Use</PrecompiledHeader>
<AdditionalIncludeDirectories>..\..\..\common\Telemetry;..\..\;..\..\..\;%(AdditionalIncludeDirectories);..\NewShellExtensionContextMenu</AdditionalIncludeDirectories>
<CompileAsWinRT>false</CompileAsWinRT>
<LanguageStandard>stdcpplatest</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
<AdditionalDependencies>runtimeobject.lib;$(CoreLibraryDependencies)</AdditionalDependencies>
<ModuleDefinitionFile>dll.def</ModuleDefinitionFile>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="..\NewShellExtensionContextMenu\constants.h" />
<ClInclude Include="..\NewShellExtensionContextMenu\new_utilities.h" />
<ClInclude Include="..\NewShellExtensionContextMenu\settings.h" />
<ClInclude Include="..\NewShellExtensionContextMenu\shell_context_sub_menu.h" />
<ClInclude Include="..\NewShellExtensionContextMenu\shell_context_sub_menu_item.h" />
<ClInclude Include="..\NewShellExtensionContextMenu\template_folder.h" />
<ClInclude Include="..\NewShellExtensionContextMenu\template_item.h" />
<ClInclude Include="..\NewShellExtensionContextMenu\trace.h" />
<ClInclude Include="dll_main.h" />
<ClInclude Include="Generated Files\resource.h" />
<ClInclude Include="pch.h" />
<ClInclude Include="resource.base.h" />
<ClInclude Include="shell_context_menu_win10.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\NewShellExtensionContextMenu\new_utilities.cpp" />
<ClCompile Include="..\NewShellExtensionContextMenu\powertoys_module.cpp" />
<ClCompile Include="..\NewShellExtensionContextMenu\settings.cpp" />
<ClCompile Include="..\NewShellExtensionContextMenu\shell_context_sub_menu.cpp" />
<ClCompile Include="..\NewShellExtensionContextMenu\shell_context_sub_menu_item.cpp" />
<ClCompile Include="..\NewShellExtensionContextMenu\template_folder.cpp" />
<ClCompile Include="..\NewShellExtensionContextMenu\template_item.cpp" />
<ClCompile Include="..\NewShellExtensionContextMenu\trace.cpp" />
<ClCompile Include="dll_main.cpp" />
<ClCompile Include="pch.cpp">
<PrecompiledHeader>Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="shell_context_menu_win10.cpp" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="Generated Files\new.rc" />
<None Include="new.base.rc" />
</ItemGroup>
<ItemGroup>
<None Include="resources.resx">
<SubType>Designer</SubType>
</None>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\common\SettingsAPI\SettingsAPI.vcxproj">
<Project>{6955446d-23f7-4023-9bb3-8657f904af99}</Project>
</ProjectReference>
<ProjectReference Include="..\..\..\common\Telemetry\EtwTrace\EtwTrace.vcxproj">
<Project>{8f021b46-362b-485c-bfba-ccf83e820cbd}</Project>
</ProjectReference>
<ProjectReference Include="..\..\..\common\Themes\Themes.vcxproj">
<Project>{98537082-0fdb-40de-abd8-0dc5a4269bab}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="dll.def" />
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<Import Project="..\..\..\..\deps\spdlog.props" />
<ImportGroup Label="ExtensionTargets">
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets')" />
<Import Project="..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.231216.1\build\native\Microsoft.Windows.ImplementationLibrary.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.231216.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" />
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>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}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets'))" />
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.231216.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.ImplementationLibrary.1.0.231216.1\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" />
</Target>
</Project>

View File

@@ -0,0 +1,116 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
<Filter Include="Generated Files">
<UniqueIdentifier>{4cea4fff-ccef-4b62-9e46-f33da2b9a0cc}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="pch.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="shell_context_menu_win10.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="resource.base.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Generated Files\resource.h">
<Filter>Generated Files</Filter>
</ClInclude>
<ClInclude Include="..\NewShellExtensionContextMenu\new_utilities.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\NewShellExtensionContextMenu\shell_context_sub_menu.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\NewShellExtensionContextMenu\shell_context_sub_menu_item.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\NewShellExtensionContextMenu\template_folder.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\NewShellExtensionContextMenu\template_item.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\NewShellExtensionContextMenu\trace.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\NewShellExtensionContextMenu\constants.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="dll_main.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\NewShellExtensionContextMenu\settings.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="pch.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="dll_main.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="shell_context_menu_win10.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\NewShellExtensionContextMenu\template_item.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\NewShellExtensionContextMenu\template_folder.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\NewShellExtensionContextMenu\shell_context_sub_menu.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\NewShellExtensionContextMenu\shell_context_sub_menu_item.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\NewShellExtensionContextMenu\powertoys_module.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\NewShellExtensionContextMenu\settings.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\NewShellExtensionContextMenu\trace.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\NewShellExtensionContextMenu\new_utilities.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="Generated Files\new.rc">
<Filter>Generated Files</Filter>
</ResourceCompile>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
<None Include="dll.def">
<Filter>Source Files</Filter>
</None>
<None Include="new.base.rc">
<Filter>Resource Files</Filter>
</None>
<None Include="resources.resx">
<Filter>Resource Files</Filter>
</None>
</ItemGroup>
<ItemGroup>
<Natvis Include="$(MSBuildThisFileDirectory)..\..\natvis\wil.natvis" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,6 @@
LIBRARY
EXPORTS
DllGetClassObject PRIVATE
DllCanUnloadNow PRIVATE
DllGetActivationFactory PRIVATE

View File

@@ -0,0 +1,44 @@
#include "pch.h"
#include "shell_context_menu_win10.h"
#include "dll_main.h"
#include "trace.h"
#include <common/Telemetry/EtwTrace/EtwTrace.h>
HMODULE module_instance_handle = 0;
Shared::Trace::ETWTrace trace(L"NewPlusShellExtension_Win10");
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<ModuleType::InProc>::GetModule().GetActivationFactory(activatableClassId, factory);
}
STDAPI DllCanUnloadNow()
{
return Module<InProc>::GetModule().GetObjectCount() == 0 ? S_OK : S_FALSE;
}
STDAPI DllGetClassObject(_In_ REFCLSID ref_class_id, _In_ REFIID ref_interface_id, _Outptr_ LPVOID FAR* object)
{
return Module<InProc>::GetModule().GetClassObject(ref_class_id, ref_interface_id, object);
}
CoCreatableClass(shell_context_menu_win10)

View File

@@ -0,0 +1,6 @@
#pragma once
#include <common/Telemetry/EtwTrace/EtwTrace.h>
extern HMODULE module_instance_handle;
extern Shared::Trace::ETWTrace trace;

View File

@@ -0,0 +1,54 @@
#include <windows.h>
#include "Generated Files/resource.h"
#include "../../../../common/version/version.h"
#define APSTUDIO_READONLY_SYMBOLS
#include "winres.h"
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// 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
/////////////////////////////////////////////////////////////////////////////
//
// Icon
//
// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Windows.CppWinRT" version="2.0.240111.5" targetFramework="native" />
<package id="Microsoft.Windows.ImplementationLibrary" version="1.0.231216.1" targetFramework="native" />
</packages>

View File

@@ -0,0 +1,3 @@
// pch.cpp: source file corresponding to the pre-compiled header
#include "pch.h"

View File

@@ -0,0 +1,39 @@
// Precompiled header file.
#pragma once
#define WIN32_LEAN_AND_MEAN
#define NOMCX
#define NOHELP
#define NOCOMM
// Windows and STL
#include <Shobjidl.h>
#include <shlwapi.h>
#include <shellapi.h>
#include <Windows.h>
#include <shlobj.h>
#include <vector>
#include <system_error>
#include <memory>
#include <iostream>
#include <atlbase.h>
#include <wrl.h>
#include <wrl/module.h>
#include <wrl/client.h>
#include <unknwn.h>
using namespace Microsoft::WRL;
// PowerToys project common
#include <ProjectTelemetry.h>
#include <common/utils/resources.h>
#include <common/logger/logger.h>
#include <common/logger/logger_settings.h>
#include <common/utils/logger_helper.h>
#include <common/Themes/theme_helpers.h>
// New project specific
#include "dll_main.h"
#include "template_folder.h"
#include "settings.h"
#include "new_utilities.h"

View File

@@ -0,0 +1,12 @@
//{{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.win10.dll"
// Non-localizable
//////////////////////////////

View File

@@ -0,0 +1,132 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="context_menu_item_new" xml:space="preserve">
<value>New+</value>
<comment>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+</comment>
</data>
<data name="context_menu_item_open_templates" xml:space="preserve">
<value>Open templates</value>
<comment>The menu item in the context menu that enables user to open the folder that contains their templates.</comment>
</data>
<data name="default_template_sub_folder_name_where_templates_are_stored" xml:space="preserve">
<value>Templates</value>
<comment>Default subfolder name where templates are stored.</comment>
</data>
</root>

View File

@@ -0,0 +1,270 @@
#include "pch.h"
#include "shell_context_menu_win10.h"
#include "shell_context_sub_menu.h"
#include "shell_context_sub_menu_item.h"
#include "new_utilities.h"
#include "settings.h"
#include "trace.h"
#include "Generated Files/resource.h"
#include <common/Themes/icon_helpers.h>
#include <common/utils/winapi_error.h>
using namespace Microsoft::WRL;
using namespace newplus;
shell_context_menu_win10::~shell_context_menu_win10()
{
for (const auto& handle : bitmap_handles)
{
DeleteObject(handle);
}
}
#pragma region IShellExtInit
IFACEMETHODIMP shell_context_menu_win10::Initialize(PCIDLIST_ABSOLUTE, IDataObject*, HKEY)
{
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, UINT menu_flags)
{
if (!NewSettingsInstance().GetEnabled()
|| package::IsWin11OrGreater()
)
{
return E_FAIL;
}
if (menu_flags & CMF_DEFAULTONLY)
{
return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, 0);
}
try
{
// 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;
// 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);
// 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)
{
const std::wstring icon_file = utilities::get_new_icon_resource_filepath(
module_instance_handle, ThemeHelpers::GetAppTheme())
.c_str();
HICON local_icon_handle = static_cast<HICON>(
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(local_icon_handle));
DestroyIcon(local_icon_handle);
}
}
if (bitmap_handles.size() > newplus_icon_index && bitmap_handles[newplus_icon_index])
{
newplus_main_context_menu_item.fMask |= MIIM_BITMAP;
newplus_main_context_menu_item.hbmpItem = bitmap_handles[newplus_icon_index];
}
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
{
// 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());
}
return E_FAIL;
}
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 };
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_context_menu_item>(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<HICON>(
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));
DestroyIcon(open_template_icon_handle);
}
}
if (bitmap_handles.size() > open_templates_icon_index && bitmap_handles[open_templates_icon_index])
{
newplus_menu_item_open_templates.fMask |= MIIM_BITMAP;
newplus_menu_item_open_templates.hbmpItem = bitmap_handles[open_templates_icon_index];
}
InsertMenuItem(sub_menu_of_templates, sub_menu_index, TRUE, &newplus_menu_item_open_templates);
}
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);
}
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)
{
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);
}
IFACEMETHODIMP shell_context_menu_win10::InvokeCommand(CMINVOKECOMMANDINFO* params)
{
if (!params)
{
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;
}
const auto number_of_templates = templates->list_of_templates.size();
const bool is_template_item = selected_menu_item_index < number_of_templates;
// 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<size_t>(number_of_templates));
if (is_template_item)
{
// It's a template menu item
const auto template_entry = templates->get_template_item(selected_menu_item_index);
return newplus::utilities::copy_template(template_entry, site_of_folder);
}
else
{
// It's the "Open templates" menu item
const std::filesystem::path template_folder_root = utilities::get_new_template_folder_location();
return newplus::utilities::open_template_folder(template_folder_root);
}
return E_FAIL;
}
IFACEMETHODIMP shell_context_menu_win10::GetCommandString(UINT_PTR, UINT, UINT*, CHAR*, UINT)
{
return E_NOTIMPL;
}
#pragma endregion
#pragma region IObjectWithSite
IFACEMETHODIMP shell_context_menu_win10::SetSite(_In_ IUnknown* site) noexcept
{
this->site_of_folder = site;
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

View File

@@ -0,0 +1,45 @@
#pragma once
#include "pch.h"
#include <template_folder.h>
using namespace Microsoft::WRL;
#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)) shell_context_menu_win10 :
public RuntimeClass<
RuntimeClassFlags<ClassicCom>,
IShellExtInit,
IContextMenu,
IObjectWithSite>
{
public:
~shell_context_menu_win10();
#pragma region IShellExtInit
IFACEMETHODIMP Initialize(_In_opt_ PCIDLIST_ABSOLUTE, _In_ IDataObject*, HKEY);
#pragma endregion
#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 IObjectWithSite
IFACEMETHODIMP SetSite(_In_ IUnknown* site) noexcept;
IFACEMETHODIMP GetSite(_In_ REFIID riid, _COM_Outptr_ void** site) noexcept;
#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<IUnknown> site_of_folder;
newplus::template_folder* templates = nullptr;
std::vector<HBITMAP> bitmap_handles;
};