[New+]Windows 10 support (#35832)
This commit is contained in:
Родитель
08fe8089b8
Коммит
084402a2bd
|
@ -997,6 +997,7 @@ newitem
|
|||
newpath
|
||||
newplus
|
||||
NEWPLUSCONTEXTMENU
|
||||
NEWPLUSSHELLEXTENSIONWIN
|
||||
newrow
|
||||
newsgroups
|
||||
NIF
|
||||
|
@ -1168,6 +1169,7 @@ pnid
|
|||
Pnp
|
||||
Popups
|
||||
POPUPWINDOW
|
||||
POSITIONITEM
|
||||
POWERRENAMECONTEXTMENU
|
||||
powerrenameinput
|
||||
POWERRENAMETEST
|
||||
|
|
|
@ -181,6 +181,7 @@
|
|||
|
||||
"WinUI3Apps\\PowerToys.NewPlus.ShellExtension.dll",
|
||||
"WinUI3Apps\\NewPlusPackage.msix",
|
||||
"WinUI3Apps\\PowerToys.NewPlus.ShellExtension.win10.dll",
|
||||
|
||||
"PowerAccent.Core.dll",
|
||||
"PowerToys.PowerAccent.dll",
|
||||
|
|
|
@ -632,6 +632,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MouseWithoutBorders.UnitTes
|
|||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WorkspacesCsharpLibrary", "src\modules\Workspaces\WorkspacesCsharpLibrary\WorkspacesCsharpLibrary.csproj", "{89D0E199-B17A-418C-B2F8-7375B6708357}"
|
||||
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
|
||||
|
@ -2792,6 +2794,18 @@ Global
|
|||
{89D0E199-B17A-418C-B2F8-7375B6708357}.Release|x64.Build.0 = Release|x64
|
||||
{89D0E199-B17A-418C-B2F8-7375B6708357}.Release|x86.ActiveCfg = Release|x64
|
||||
{89D0E199-B17A-418C-B2F8-7375B6708357}.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|x64
|
||||
{0DB0F63A-D2F8-4DA3-A650-2D0B8724218E}.Debug|x86.Build.0 = Debug|x64
|
||||
{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|x64
|
||||
{0DB0F63A-D2F8-4DA3-A650-2D0B8724218E}.Release|x86.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
@ -3024,6 +3038,7 @@ Global
|
|||
{8F021B46-362B-485C-BFBA-CCF83E820CBD} = {8F62026A-294B-41C6-8839-87463613F216}
|
||||
{66614C26-314C-4B91-9071-76133422CFEF} = {B6C42F16-73EB-477E-8B0D-4E6CF6C20AAC}
|
||||
{89D0E199-B17A-418C-B2F8-7375B6708357} = {A2221D7E-55E7-4BEA-90D1-4F162D670BBF}
|
||||
{0DB0F63A-D2F8-4DA3-A650-2D0B8724218E} = {CA716AE6-FE5C-40AC-BB8F-2C87912687AC}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {C3A2F9D1-7930-4EF4-A6FC-7EE0A99821D0}
|
||||
|
|
|
@ -18,6 +18,19 @@
|
|||
<DirectoryRef Id="NewPlusAssetsInstallFolder" FileSource="$(var.NewPlusAssetsFilesPath)">
|
||||
<!-- Generated by generateFileComponents.ps1 -->
|
||||
<!--NewPlusAssetsFiles_Component_Def-->
|
||||
|
||||
<!-- NewPlus Shell Extension for Win10 registration -->
|
||||
<Component Id="NewPlus_ShellExtension_win10" Guid="D5456D4A-6EEC-4B85-944D-6A6A4A74FFA6" Win64="yes">
|
||||
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\CLSID\{FF90D477-E32A-4BE8-8CC5-A502A97F5401}">
|
||||
<RegistryValue Type="string" Value="NewPlus Shell Extension Win10" />
|
||||
<RegistryValue Type="string" Name="ContextMenuOptIn" Value="" />
|
||||
<RegistryValue Type="string" Key="InprocServer32" Value="[WinUI3AppsInstallFolder]PowerToys.NewPlus.ShellExtension.win10.dll" />
|
||||
<RegistryValue Type="string" Key="InprocServer32" Name="ThreadingModel" Value="Apartment" />
|
||||
</RegistryKey>
|
||||
<RegistryKey Root="$(var.RegistryScope)" Key="SOFTWARE\Classes\Directory\background\ShellEx\ContextMenuHandlers\NewPlusShellExtensionWin10">
|
||||
<RegistryValue Type="string" Value="{FF90D477-E32A-4BE8-8CC5-A502A97F5401}"/>
|
||||
</RegistryKey>
|
||||
</Component>
|
||||
</DirectoryRef>
|
||||
|
||||
<ComponentGroup Id="NewPlusComponentGroup">
|
||||
|
@ -27,6 +40,7 @@
|
|||
</RegistryKey>
|
||||
<RemoveFolder Id="RemoveFolderNewPlusAssetsFolder" Directory="NewPlusAssetsInstallFolder" On="uninstall"/>
|
||||
</Component>
|
||||
<ComponentRef Id="NewPlus_ShellExtension_win10" />
|
||||
</ComponentGroup>
|
||||
|
||||
|
||||
|
|
|
@ -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>
|
|
@ -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>
|
|
@ -0,0 +1,6 @@
|
|||
LIBRARY
|
||||
|
||||
EXPORTS
|
||||
DllGetClassObject PRIVATE
|
||||
DllCanUnloadNow PRIVATE
|
||||
DllGetActivationFactory PRIVATE
|
|
@ -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)
|
|
@ -0,0 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <common/Telemetry/EtwTrace/EtwTrace.h>
|
||||
|
||||
extern HMODULE module_instance_handle;
|
||||
extern Shared::Trace::ETWTrace trace;
|
|
@ -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.
|
||||
|
|
@ -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>
|
|
@ -0,0 +1,3 @@
|
|||
// pch.cpp: source file corresponding to the pre-compiled header
|
||||
|
||||
#include "pch.h"
|
|
@ -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"
|
|
@ -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
|
||||
//////////////////////////////
|
|
@ -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>
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
};
|
|
@ -128,6 +128,7 @@ MakeAppx.exe pack /d . /p $(OutDir)NewPlusPackage.msix /nv</Command>
|
|||
<ClInclude Include="template_item.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="new_utilities.cpp" />
|
||||
<ClCompile Include="shell_context_menu.cpp" />
|
||||
<ClCompile Include="shell_context_sub_menu.cpp" />
|
||||
<ClCompile Include="shell_context_sub_menu_item.cpp" />
|
||||
|
@ -227,7 +228,7 @@ MakeAppx.exe pack /d . /p $(OutDir)NewPlusPackage.msix /nv</Command>
|
|||
<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.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')" />
|
||||
</ImportGroup>
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
|
|
|
@ -31,6 +31,9 @@
|
|||
<ClCompile Include="trace.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="new_utilities.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="template_folder.h">
|
||||
|
@ -123,9 +126,6 @@
|
|||
<None Include="AppxManifest.xml">
|
||||
<Filter>Source Files</Filter>
|
||||
</None>
|
||||
<None Include="Assets\NewPlus\New.ico">
|
||||
<Filter>Asset Files</Filter>
|
||||
</None>
|
||||
<None Include="Assets\NewPlus\SmallTile.png">
|
||||
<Filter>Asset Files</Filter>
|
||||
</None>
|
||||
|
@ -190,14 +190,8 @@
|
|||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Text Include="TemplateExamples\Example folder\Another example txt file.txt">
|
||||
<Filter>Template Examples\Example folder</Filter>
|
||||
</Text>
|
||||
<Text Include="TemplateExamples\Example folder\Example txt file.txt">
|
||||
<Filter>Template Examples\Example folder</Filter>
|
||||
</Text>
|
||||
<Text Include="TemplateExamples\Any files or folders placed in the template folder are available via New+.txt">
|
||||
<Filter>Template Examples</Filter>
|
||||
</Text>
|
||||
<CopyFileToFolders Include="TemplateExamples\Any files or folders placed in the template folder are available via New+.txt" />
|
||||
<CopyFileToFolders Include="TemplateExamples\Example folder\Example txt file.txt" />
|
||||
<CopyFileToFolders Include="TemplateExamples\Example folder\Another example txt file.txt" />
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -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;
|
||||
}
|
|
@ -7,11 +7,17 @@
|
|||
|
||||
#include "constants.h"
|
||||
#include "settings.h"
|
||||
#include "template_item.h"
|
||||
#include "trace.h"
|
||||
|
||||
#pragma comment(lib, "Shlwapi.lib")
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -39,6 +45,33 @@ 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;
|
||||
}
|
||||
|
||||
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<HICON>(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();
|
||||
|
@ -180,4 +213,227 @@ 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<IShellWindows> shell_windows;
|
||||
|
||||
HRESULT hr;
|
||||
if (FAILED(CoCreateInstance(CLSID_ShellWindows, NULL, CLSCTX_ALL, IID_PPV_ARGS(&shell_windows))))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
long window_handle;
|
||||
ComPtr<IDispatch> 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<IWebBrowserApp> 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<IServiceProvider> service_provider;
|
||||
shell_window.As(&service_provider);
|
||||
ComPtr<IShellBrowser> shell_browser;
|
||||
service_provider->QueryService(SID_STopLevelBrowser, IID_PPV_ARGS(&shell_browser));
|
||||
ComPtr<IShellView> shell_view;
|
||||
shell_browser->QueryActiveShellView(&shell_view);
|
||||
ComPtr<IFolderView> folder_view;
|
||||
shell_view.As(&folder_view);
|
||||
|
||||
// Find the newly created object (file or folder)
|
||||
// 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 && !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<IUnknown> site_of_folder)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
try
|
||||
{
|
||||
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);
|
||||
|
||||
// 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.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);
|
||||
|
||||
// Enter rename mode
|
||||
template_entry->enter_rename_mode(target_final_fullpath);
|
||||
}
|
||||
catch (const std::exception& ex)
|
||||
{
|
||||
Logger::error(ex.what());
|
||||
|
||||
hr = S_FALSE;
|
||||
}
|
||||
|
||||
trace.UpdateState(true);
|
||||
Trace::EventCopyTemplateResult(hr);
|
||||
trace.Flush();
|
||||
trace.UpdateState(false);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
inline HRESULT open_template_folder(const std::filesystem::path template_folder)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
try
|
||||
{
|
||||
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);
|
||||
|
||||
trace.UpdateState(true);
|
||||
Trace::EventOpenTemplates();
|
||||
trace.Flush();
|
||||
trace.UpdateState(false);
|
||||
}
|
||||
catch (const std::exception& ex)
|
||||
{
|
||||
Logger::error(ex.what());
|
||||
|
||||
hr = S_FALSE;
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,7 +27,6 @@ public:
|
|||
|
||||
#pragma region IObjectWithSite
|
||||
IFACEMETHODIMP SetSite(_In_ IUnknown* site) noexcept;
|
||||
|
||||
IFACEMETHODIMP GetSite(_In_ REFIID riid, _COM_Outptr_ void** site) noexcept;
|
||||
#pragma endregion
|
||||
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
#include "pch.h"
|
||||
#include "shell_context_sub_menu.h"
|
||||
#include "trace.h"
|
||||
#include "new_utilities.h"
|
||||
|
||||
using namespace Microsoft::WRL;
|
||||
|
||||
// // Sub context menu command enumerator
|
||||
shell_context_sub_menu::shell_context_sub_menu(const ComPtr<IUnknown> site_of_folder)
|
||||
{
|
||||
trace.UpdateState(true);
|
||||
this->site_of_folder = site_of_folder;
|
||||
|
||||
// Determine the New+ Template folder location
|
||||
|
@ -36,8 +36,9 @@ shell_context_sub_menu::shell_context_sub_menu(const ComPtr<IUnknown> site_of_fo
|
|||
|
||||
current_command = explorer_menu_item_commands.cbegin();
|
||||
|
||||
// Log that context menu was shown and with how many items
|
||||
Trace::EventShowTemplateItems(number_of_templates);
|
||||
// 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<size_t>(number_of_templates));
|
||||
}
|
||||
|
||||
// IEnumExplorerCommand
|
||||
|
|
|
@ -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(target_fullpath))
|
||||
{
|
||||
target_fullpath.append(this->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);
|
||||
|
||||
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
|
||||
this->template_entry->enter_rename_mode(site_of_folder, 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);
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,44 +117,23 @@ std::filesystem::path template_item::copy_object_to(const HWND window_handle, co
|
|||
return final_path;
|
||||
}
|
||||
|
||||
void template_item::enter_rename_mode(const ComPtr<IUnknown> site, const std::filesystem::path target_fullpath) const
|
||||
void template_item::refresh_target(const std::filesystem::path target_final_fullpath) const
|
||||
{
|
||||
std::thread thread_for_renaming_workaround(rename_on_other_thread_workaround, site, target_fullpath);
|
||||
SHChangeNotify(SHCNE_CREATE, SHCNF_PATH | SHCNF_FLUSH, target_final_fullpath.wstring().c_str(), NULL);
|
||||
}
|
||||
|
||||
void template_item::enter_rename_mode(const std::filesystem::path target_fullpath) const
|
||||
{
|
||||
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<IUnknown> 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 };
|
||||
// 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));
|
||||
|
||||
const std::wstring filename = target_fullpath.filename();
|
||||
|
||||
ComPtr<IServiceProvider> service_provider;
|
||||
site->QueryInterface(IID_PPV_ARGS(&service_provider));
|
||||
ComPtr<IFolderView> 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);
|
||||
}
|
||||
|
|
|
@ -20,15 +20,19 @@ 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<IUnknown> site, const std::filesystem::path target_folder) const;
|
||||
void refresh_target(const std::filesystem::path target_final_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<IUnknown> 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;
|
||||
};
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -12,4 +12,5 @@ public:
|
|||
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;
|
||||
};
|
||||
|
|
|
@ -23,13 +23,6 @@
|
|||
<ToggleSwitch x:Uid="ToggleSwitch" IsOn="{x:Bind ViewModel.IsEnabled, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
|
||||
<InfoBar
|
||||
x:Uid="NewPlus_NoWindows10SupportWarning"
|
||||
IsClosable="False"
|
||||
IsOpen="{x:Bind ViewModel.IsWin10OrLower, Mode=OneWay}"
|
||||
IsTabStop="{x:Bind ViewModel.IsWin10OrLower, Mode=OneWay}"
|
||||
Severity="Warning" />
|
||||
|
||||
<InfoBar
|
||||
x:Uid="GPO_SettingIsManaged"
|
||||
IsClosable="False"
|
||||
|
|
|
@ -4498,9 +4498,6 @@ Activate by holding the key for the character you want to add an accent to, then
|
|||
<value>Enable New+</value>
|
||||
<comment>Localize product name in accordance with Windows New</comment>
|
||||
</data>
|
||||
<data name="NewPlus_NoWindows10SupportWarning.Title" xml:space="preserve">
|
||||
<value>New+ is not supported in Windows 10 and is not expected to work.</value>
|
||||
</data>
|
||||
<data name="NewPlus_TemplatesNotBackupAndRestoreWarning.Title" xml:space="preserve">
|
||||
<value>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.</value>
|
||||
</data>
|
||||
|
|
Загрузка…
Ссылка в новой задаче