一、前言win11更新后微软对右键菜单进行了重新设计分为了新版右键菜单(简化菜单/快捷菜单)和旧版菜单(win10菜单)。而新版菜单和旧版菜单的设计有巨大差别无法按照原本旧版菜单的方法(包括注册表直接改写、shellex程序等方式)。二、简述win11新版菜单需要两组项目需要实现IExplorerCommand接口的组件并将其编写msix的Package.appxmanifest使其注册对应的到右键菜单上并进行打包安装实现IExplorerCommand接口的右键拓展组件通过VS的 使用 Visual Studio 从源代码打包桌面应用 - MSIX | Microsoft Learn 或 MSIX 打包工具概述 - MSIX | Microsoft Learn 将组件添加入安装资源并改写其中的Package.appxmanifest 文件使其正确被注册(msix的虚拟注册表)并添加到合适的Type中。打包成对应的MSIX安装包进行安装(建议虚拟机/沙盒环境测试不合格将自动闪退)。而对于旧版win10菜单首先实现IContextMenu的右键拓展程序组件之后可以regsvr32程序直接注册(msix项目不建议)到注册表中的file_extension Key (包括HKCR下的‘*’ 和 各后缀名、文件、文件夹及背景等)的指定位置。也可以类似win11使用Package.appxmanifest 文件FileExplorerClassicContextMenuHandler标签(要求高版本)将组件注册到虚拟注册表中。两者配合实现新旧菜单同时使用。开发要求对于win11右键菜单- 开发环境推荐使用windows系统环境下使用VisualStudio2022的IDE- VisualStudio负载C的桌面开发、.NET桌面开发- 开发项目模板ATL项目支持包括IExplorerCommand接口在内的win32程序开发、windows应用程序打包项目、空项目(用于处理应用程序打包项目的入口程序(可选))对于win10右键菜单- 开发环境推荐使用windows系统环境下使用VisualStudio2017的IDE- VisualStudio负载C的桌面开发- 开发项目模板ATL项目三、开发指南1、准备项目需要创建一个空白解决方案用来收拢子项目再依次创建ATL项目和windows应用程序打包项目、空项目(如果没有exe程序需求可以直接int main(){return 0;}。1、空白解决方案2、创建子项目3、创建ATL项目配置新项目细节可参考 windows ATL项目简介-CSDN博客4、创建windows应用程序打包项目配置版本细节可参考 Windows 10中有什么不同 - Windows UWP applications | Microsoft Learn2、配置ATL项目创建ATL项目后需要创建ATL模块来专门为接口实现注册等在添加新项中选择ATL-ATL简单对象命名后确认下一步一般无需改动直接下一步到完成其他细节可参考 windows ATL项目简介-CSDN博客IContextMenu和IExplorerCommand具体实现后文陈述。3、配置windows应用程序打包项目添加资源直接在 解决方案资源管理器内右键-添加-现有项 将上文的dll等资源(成品)添加入项目中。添加入口程序右击依赖项项目引用 将exe程序(可以是前面的空项目做的简单程序)引入必须存在否则打包程序无法运行。配置Package.appxmanifest 文件可参考应用包清单 - Windows UWP applications | Microsoft Learn 此为示例其中com命名空间用来注册组件本身、FileExplorerContextMenus用来注册到新版快捷菜单、FileExplorerClassicContextMenuHandler来支持旧版菜单(需求版本高低版本应直接调用regsvr32注册程序)以下为示例(有瑕疵需根据情况修正)?xml version1.0 encodingutf-8? Package xmlnshttp://schemas.microsoft.com/appx/manifest/foundation/windows10 xmlns:comhttp://schemas.microsoft.com/appx/manifest/com/windows10 xmlns:desktop4http://schemas.microsoft.com/appx/manifest/desktop/windows10/4 xmlns:desktop9http://schemas.microsoft.com/appx/manifest/desktop/windows10/9 xmlns:desktop10http://schemas.microsoft.com/appx/manifest/desktop/windows10/10 xmlns:uaphttp://schemas.microsoft.com/appx/manifest/uap/windows10 xmlns:rescaphttp://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities xmlns:uap18http://schemas.microsoft.com/appx/manifest/uap/windows10/18 IgnorableNamespacesuap rescap desktop4 desktop9 uap18 com Identity Name9ae0e8eb-306d-4b54-bb9c-fd987a602a57 PublisherCNdevptx Version1.0.13.0 / Properties DisplayNameWapProjTemplate1/DisplayName PublisherDisplayNameDallas/PublisherDisplayName LogoImages\StoreLogo.png/Logo /Properties Dependencies TargetDeviceFamily NameWindows.Universal MinVersion10.0.0.0 MaxVersionTested10.0.0.0 / TargetDeviceFamily NameWindows.Desktop MinVersion10.0.14393.0 MaxVersionTested10.0.14393.0 / /Dependencies Resources Resource Languagex-generate/ /Resources Applications Application IdApp Executable$targetnametoken$.exe EntryPoint$targetentrypoint$ uap18:RuntimeBehaviorwin32App uap:VisualElements DisplayNameWapProjTemplate1 DescriptionWapProjTemplate1 BackgroundColortransparent Square150x150LogoImages\Square150x150Logo.png Square44x44LogoImages\Square44x44Logo.png uap:DefaultTile Wide310x150LogoImages\Wide310x150Logo.png / uap:SplashScreen ImageImages\SplashScreen.png / /uap:VisualElements Extensions com:Extension Categorywindows.comServer com:ComServer com:SurrogateServer DisplayNameDllReg Extensions com:Class Id9dd00a4a-9701-4c02-813c-2fd842b33587 PathDllRegExt.dll ThreadingModelSTA / com:Class Id6f3d9fe2-7d96-4910-9d34-e7e57378bc64 PathSample.dll ThreadingModelSTA / /com:SurrogateServer /com:ComServer /com:Extension desktop4:Extension Categorywindows.fileExplorerContextMenus desktop4:FileExplorerContextMenus desktop4:ItemType Type* desktop4:Verb Idregs Clsid9dd00a4a-9701-4c02-813c-2fd842b33587 / desktop4:Verb IdtestATL Clsid6f3d9fe2-7d96-4910-9d34-e7e57378bc64 / /desktop4:ItemType /desktop4:FileExplorerContextMenus /desktop4:Extension desktop9:Extension Categorywindows.fileExplorerClassicContextMenuHandler desktop9:FileExplorerClassicContextMenuHandler desktop9:ExtensionHandler Type* Clsid9dd00a4a-9701-4c02-813c-2fd842b33587 / !--desktop9:ExtensionHandler Type* Clsid6f3d9fe2-7d96-4910-9d34-e7e57378bc64 /-- /desktop9:FileExplorerClassicContextMenuHandler /desktop9:Extension /Extensions /Application /Applications Capabilities rescap:Capability NamerunFullTrust / /Capabilities /Package四、实现上下文菜单扩展具体参考案例可参考lan2405/staticcontextmenu参考代码ATLSimpleObject.h// ATLSimpleObject.h: CATLSimpleObject 的声明 #pragma once #include resource.h // 主符号 #include ShObjIdl_core.h #include string #include Sample_i.h #if defined(_WIN32_WCE) !defined(_CE_DCOM) !defined(_CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA) #error Windows CE 平台(如不提供完全 DCOM 支持的 Windows Mobile 平台)上无法正确支持单线程 COM 对象。定义 _CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA 可强制 ATL 支持创建单线程 COM 对象实现并允许使用其单线程 COM 对象实现。rgs 文件中的线程模型已被设置为“Free”原因是该模型是非 DCOM Windows CE 平台支持的唯一线程模型。 #endif using namespace ATL; // CATLSimpleObject class ATL_NO_VTABLE CATLSimpleObject : public CComObjectRootExCComSingleThreadModel, public CComCoClassCATLSimpleObject, CLSID_ATLSimpleObject, public IDispatchImplIATLSimpleObject, IID_IATLSimpleObject, LIBID_SampleLib, /*wMajor */ 1, /*wMinor */ 0, public IShellExtInit, public IContextMenu, public IExplorerCommand { public: CATLSimpleObject() { } DECLARE_REGISTRY_RESOURCEID(106) BEGIN_COM_MAP(CATLSimpleObject) COM_INTERFACE_ENTRY(IATLSimpleObject) COM_INTERFACE_ENTRY(IDispatch) COM_INTERFACE_ENTRY(IShellExtInit) COM_INTERFACE_ENTRY(IContextMenu) COM_INTERFACE_ENTRY(IExplorerCommand) END_COM_MAP() DECLARE_PROTECT_FINAL_CONSTRUCT() HRESULT FinalConstruct() { return S_OK; } void FinalRelease() { } public: // IShellExtInit STDMETHOD(Initialize)(_In_ LPCITEMIDLIST pidlFolder, _In_ IDataObject* pdtobj, _In_ HKEY hkeyProgID) override; // IContextMenu STDMETHOD(QueryContextMenu)(_In_ HMENU hMenu, _In_ UINT indexMenu, _In_ UINT idCmdFirst, _In_ UINT idCmdLast, _In_ UINT uFlags) override; STDMETHOD(InvokeCommand)(_In_ LPCMINVOKECOMMANDINFO pici) override; STDMETHOD(GetCommandString)(_In_ UINT_PTR idCmd, _In_ UINT uFlags, _Out_opt_ UINT* pwReserved, _Out_writes_opt_(cchOut) LPSTR pszName, _In_ UINT cchOut) { return S_OK; }; // IExplorerCommand STDMETHOD(EnumSubCommands)(_Out_ IEnumExplorerCommand** ppEnum) override; STDMETHOD(GetCanonicalName)(_Out_ GUID* pguidCommandName) override; STDMETHOD(GetFlags)(_Out_ EXPCMDFLAGS* pFlags) override; STDMETHOD(GetIcon)(_In_ IShellItemArray* psiItemArray, _Out_ LPWSTR* ppszIcon) override; STDMETHOD(GetState)(_In_ IShellItemArray* psiItemArray, _In_ BOOL fOkToBeSlow, _Out_ EXPCMDSTATE* pCmdState) override; STDMETHOD(GetTitle)(_In_ IShellItemArray* psiItemArray, _Out_ LPWSTR* ppszName) override; STDMETHOD(GetToolTip)(_In_ IShellItemArray* psiItemArray, _Out_ LPWSTR* ppszInfotip) override; STDMETHOD(Invoke)(_In_ IShellItemArray* psiItemArray, _Out_ IBindCtx* pbc) override; }; OBJECT_ENTRY_AUTO(__uuidof(ATLSimpleObject), CATLSimpleObject)ATLSimpleObject.cpp// ATLSimpleObject.cpp: CATLSimpleObject 的实现 #include pch.h #include ATLSimpleObject.h // CATLSimpleObject // IShellExtInit STDMETHODIMP_(HRESULT __stdcall) CATLSimpleObject::Initialize(LPCITEMIDLIST pidlFolder, IDataObject* pdtobj, HKEY hkeyProgID) { return S_OK; } // IContextMenu STDMETHODIMP_(HRESULT __stdcall) CATLSimpleObject::QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags) { HMENU uhmenu CreatePopupMenu(); MENUITEMINFO hmenu_lpmi{ sizeof(MENUITEMINFO),MIIM_TYPE | MIIM_STATE | MIIM_SUBMENU,MFT_STRING,MFS_ENABLED }; hmenu_lpmi.cch idCmdFirst; hmenu_lpmi.hSubMenu uhmenu; hmenu_lpmi.dwTypeData _T(注册dlltest); MENUITEMINFO uhmenu_lpmi0{ sizeof(MENUITEMINFO),MIIM_TYPE | MIIM_STATE | MIIM_ID ,MFT_STRING,MFS_ENABLED ,idCmdFirst 1 }; MENUITEMINFO uhmenu_lpmi1{ sizeof(MENUITEMINFO),MIIM_TYPE | MIIM_STATE | MIIM_ID ,MFT_STRING,MFS_ENABLED, idCmdFirst 2 }; uhmenu_lpmi0.dwTypeData _T(注册test); uhmenu_lpmi1.dwTypeData _T(注销test); InsertMenuItem(uhmenu, idCmdFirst 1, TRUE, (LPCMENUITEMINFO)uhmenu_lpmi0); InsertMenuItem(uhmenu, idCmdFirst 2, TRUE, (LPCMENUITEMINFO)uhmenu_lpmi1); InsertMenuItem(hMenu, indexMenu, TRUE, (LPCMENUITEMINFO)hmenu_lpmi); return MAKE_HRESULT(SEVERITY_SUCCESS, 0, 2); } STDMETHODIMP_(HRESULT __stdcall) CATLSimpleObject::InvokeCommand(LPCMINVOKECOMMANDINFO pici) { return E_NOTIMPL; } //STDMETHODIMP_(HRESULT __stdcall) CATLSimpleObject::GetCommandString(UINT_PTR idCmd, UINT uFlags, UINT* pwReserved, LPSTR pszName, UINT cchOut) //{ // return E_NOTIMPL; //} // IExplorerCommand STDMETHODIMP_(HRESULT __stdcall) CATLSimpleObject::EnumSubCommands(_Out_ IEnumExplorerCommand** ppEnum) { *ppEnum nullptr; return E_NOTIMPL; } STDMETHODIMP_(HRESULT __stdcall) CATLSimpleObject::GetCanonicalName(_Out_ GUID* pguidCommandName) { *pguidCommandName GetObjectCLSID(); return S_OK; } STDMETHODIMP_(HRESULT __stdcall) CATLSimpleObject::GetFlags(_Out_ EXPCMDFLAGS* pFlags) { *pFlags ECF_DEFAULT; return S_OK; } STDMETHODIMP_(HRESULT __stdcall) CATLSimpleObject::GetIcon(IShellItemArray* psiItemArray, _Out_ LPWSTR* ppszIcon) { return E_NOTIMPL; } STDMETHODIMP_(HRESULT __stdcall) CATLSimpleObject::GetState(IShellItemArray* psiItemArray, BOOL fOkToBeSlow, _Out_ EXPCMDSTATE* pCmdState) { *pCmdState ECS_ENABLED; return S_OK; } STDMETHODIMP_(HRESULT __stdcall) CATLSimpleObject::GetTitle(IShellItemArray* psiItemArray, _Out_ LPWSTR* ppszName) { std::wstring titlename _T( test); return SHStrDup(titlename.c_str(), ppszName); } STDMETHODIMP_(HRESULT __stdcall) CATLSimpleObject::GetToolTip(IShellItemArray* psiItemArray, _Out_ LPWSTR* ppszInfotip) { *ppszInfotip nullptr; return E_NOTIMPL; } STDMETHODIMP_(HRESULT __stdcall) CATLSimpleObject::Invoke(IShellItemArray* psiItemArray, _Out_ IBindCtx* pbc) { return E_NOTIMPL; }多级菜单与Package.appxmanifest 相关:com:Extension Categorywindows.comServer com:ComServer com:SurrogateServer DisplayNameDllReg Extensions com:Class Id9dd00a4a-9701-4c02-813c-2fd842b33587 PathDllRegExt.dll ThreadingModelSTA / com:Class Id6f3d9fe2-7d96-4910-9d34-e7e57378bc64 PathSample.dll ThreadingModelSTA / /com:SurrogateServer /com:ComServer /com:Extension desktop4:Extension Categorywindows.fileExplorerContextMenus desktop4:FileExplorerContextMenus desktop4:ItemType Type* desktop4:Verb Idregs Clsid9dd00a4a-9701-4c02-813c-2fd842b33587 / desktop4:Verb IdtestATL Clsid6f3d9fe2-7d96-4910-9d34-e7e57378bc64 / /desktop4:ItemType /desktop4:FileExplorerContextMenus /desktop4:Extension代表id为regs和testATL(与菜单显示文字无关实际内容由其IExplorerCommand决定)两个子菜单并存生成MSIX程序包右键打包项目-发布-创建应用程序包配置后即可创建ps.为了能够在其他环境中能正常测试建议直接使用个人测试证书(可直接生成)微软商店发布不需要证书此外渠道自主发布需要签名证书如阿里云EV证书(1000r)六、测试生成后在项目文件夹的\WapProjTemplate1\AppPackages存储生成的安装包 执行Add-AppDevPackage.ps1脚本按照测试证书安装(自动安装测试证书)。注意事项1、 使用个人测试证书需要主动开启开发人员模式2、报错cannot be loaded because running scripts is disabled on this system.Windows PowerShell 默认的安全策略禁止运行脚本需要执行Set-ExecutionPolicy RemoteSigned -Scope CurrentUser参考资料微软文档-快捷菜单上下文菜单和快捷菜单处理程序 - Win32 apps | Microsoft Learn微软文档-Windows应用程序开发 - 最佳做法 - Windows apps | Microsoft Learn微软文档-[应用程序打包项目](使用 Visual Studio 从源代码打包桌面应用 - MSIX | Microsoft Learn)微软文档-[MSIX Packaging Tool](MSIX 打包工具概述 - MSIX | Microsoft Learn)微软文档-Windows 10中有什么不同 - Windows UWP applications | Microsoft Learn微软文档-IExplorerCommand (shobjidl_core.h) - Win32 apps | Microsoft Learn微软文档-打包应用 - UWP applications | Microsoft Learn微软文档-desktop4:FileExplorerContextMenus - Windows UWP applications | Microsoft Learn微软文档-应用包清单 - Windows UWP applications | Microsoft Learn CSDN-注册表常见位置以及COM注册表项架构详解_右键菜单注册表-CSDN博客CSDN-windows ATL项目简介-CSDN博客