大家應該都知道,微軟在 Windows 11 中對右鍵選單進行了一番大改造,從 XP 時代就開始的經典設計被換成了全新的操作模式和樣式。這種突如其來的變化讓不少人感到不適應,甚至有些人試圖透過修改機碼的方式,把舊版的右鍵選單找回來。但今天我想跟大家分享的不是如何恢復舊版選單,而是如何在新版的右鍵選單中添加自定義選項。
要完成這項任務,我們將會涉及到 C++ 語言的使用。我得坦白說,我本人並沒有寫過 C++,所以這次的範例大多是參考了 Notepad++ 的 NppShell.dll 的開源碼,然後再透過 ChatGPT 一點一滴的學習和調整,所以可能有些許的錯誤就請多多包涵。
NppShell Github 專案:
NppShell Github 專案
如何實現 Windows 11 自定義選單
要在 Windows 11 中實現自定義右鍵選單,根據微軟在開發者部落格的介紹,我們可以使用以下兩種方式實現:- 利用 IExplorerCommand 介面:IExplorerCommand 介面是 Windows Shell 擴展的一部分,專門用於定義和控制檔案總管中的右鍵選單命令。
- 使用 Sparse Package 技術:在早期的 Windows 版本中,傳統 Win32 應用程式是主要的應用程式類型,它們通常不包含對操作系統深度整合功能的存取,例如:「背景任務」、「通知」、「動態磚」、「分享」等。而這些功能主要是針對 UWP(通用 Windows 平台)應用程式設計的,它們具有更深層次的操作系統整合。所以在 Windows 新一點的版本中,微軟試圖縮小傳統 Win32 應用程式與這些新 Windows API 和功能之間的差距,因而引入Sparse Package技術。它允許這些傳統應用程式維持它們現有的檔案布局和部署方式,同時獲得對新 Windows API 的存取能力。
關於完整的 Sparse Package 介紹可以參考微軟的開發者部落格:
實作 IEnumExplorerCommand 儲存子菜單
完成 IExplorerCommand 接口的基礎實作之後,下一步是實作 IEnumExplorerCommand,它也是 Windows Shell 擴展的一部分,它允許開發者枚舉(列出)在檔案總管的右鍵選單中應該顯示的命令。這個接口對於管理多個自定義命令,特別是當你想在右鍵選單中添加多個選項時,變得尤為重要。和 IExplorerCommand 一樣,需要實做一些必要的方法:
以上就是使用 C++ 實現 IExplorerCommand 自定義選單的建置和開發過程。接下我們只需要編譯專案產生出 DLL 後,透過 Sparse Package 打包並使用 regsver32 註冊該 DLL 就可以完成 Windows 11 自定義的右鍵選單安裝,不過由於 Sparse Package 的實作和註冊 DLL 涉及多個步驟,我們將在下一篇文章中進行更詳細的介紹。
準備工具
首先我們需要準備 Visual Studio 2022 並且需要安裝 C++ 的工具。接著還需要安裝 Windows 11 的 SDK(軟體開發套件)。透過這個連結【點我前往】去下載並安裝。SDK 是開發 Windows 應用時必備的一套工具和庫,它讓我們可以更方便地存取系統功能。安裝完 SDK 之後可以到此路徑中「C:\Program Files (x86)\Windows Kits\10\bin\10.0.22621.0\x64」找到兩個稍後(Sparse Package 實作中會介紹)會用到的工具:「makeappx.exe」和「signtool.exe」這些工具將幫助我們在開發過程中打包和簽署應用。
安裝 NuGet 套件和專案設定
在 Visual Studio 2022 中,你需要建立一個新的 DLL 專案。選擇 C++ 作為開發語言。DLL(Dynamic Link Library)專案將允許我們創建可由 Windows 操作系統加載和執行的程式庫文件。

專案建立完成後,需要安裝以下兩個 NuGet 套件:
- Microsoft.Windows.CppWinRT:這個套件提供了 C++/WinRT 的支援,使用符合標準的 C++17 編譯器,用於 Windows Runtime(WinRT)API。這讓我們能夠更容易地在 C++ 中調用 WinRT API。
- Microsoft.Windows.ImplementationLibrary:這個套件則提供了實現 Windows API 程式庫的工具,幫助我們在專案中更加方便地實現 Windows 功能。
實作 IExplorerCommand 右鍵選單
接下來的重點就是實作自定義的右鍵選單。要成功地在 Windows 11 中添加自己的選單項目,我們需要利用 Windows 的 IExplorerCommand 接口來實現這個功能。它是 Windows Shell 擴展的一部分,它允許開發者定義和控制在檔案總管的上下文選單(也就是右鍵選單)中出現的命令。在這個類別中,你需要實做一些必要的方法:- GetTitle:用於獲取選單項目的標題。
- GetIcon:設定選單圖標。
- GetFlags:設定選單是的旗標。💡 這個用於設定是否為普通選單或是包含子項目的選單。
- EnumSubCommands:這個方法負責創建和管理子選單。
- Invoke:定義選擇該選單項目時執行的指令動作。
不論是主選單還是子選單,我們都會利用實現 IExplorerCommand 介面的方式來建立各種選項。為了提高開發效率和維護的方便性,因此我創建的是一個 BaseExplorerCommand 的基礎類別,這樣就能夠方便地通過繼承來實作所需的主選單(Main)和子選單(Sub)。
在主選單中,不需要執行任何命令,因此不需要實作「Invoke」。但是需要實作「GetFlags」和「EnumSubCommands」來實現子選單。
💡 記得!主選單一定要設定一組 UUID 供延伸模組做識別。
在子選單中,只需要實作「Invoke」。這裡為了方便展示,執行一個簡單的 cmd 命令:
💡 子選單點擊後會觸發 Invoke 方法。該方法簡單的執行一個 cmd 並顯示 Hello World by Sub1Win11ContextMenu 字串。
實作 IEnumExplorerCommand 儲存子菜單
完成 IExplorerCommand 接口的基礎實作之後,下一步是實作 IEnumExplorerCommand,它也是 Windows Shell 擴展的一部分,它允許開發者枚舉(列出)在檔案總管的右鍵選單中應該顯示的命令。這個接口對於管理多個自定義命令,特別是當你想在右鍵選單中添加多個選項時,變得尤為重要。和 IExplorerCommand 一樣,需要實做一些必要的方法:完成了 IEnumExplorerCommand 接口的基本實作後,我們的下一步是在主選單類別的「EnumSubCommands」方法中創建子選單並將其加入到 IEnumExplorerCommand 中:
為了讓系統識別主選單包含子選單,我們需要適當地調整主選單類別中的「GetFlags」方法。當使用者互動時,系統才能正確地顯示子選單。可以通過返回「ECF_HASSUBCOMMANDS」的標誌值來實現:
以上就是自定義右鍵選單的主選單和子選單的建置方法。篇幅的關係,部分的程式碼實作就請到我的 Github 上參考囉。
註冊選單和安裝 Sparse package
完成右鍵選單的建置之後,為了讓這些自定義功能能夠在 Windows 11 中順利運作,我們還需要透過程式碼來註冊選單和安裝 Sparse Package。
- 註冊 Windows 舊右鍵選單:雖然我們的主要目標是實現 Windows 11 的新右鍵選單,但為了向後兼容,我們也需要考慮在舊版本的 Windows 中如何展示我們的自定義選單。
- 安裝 Sparse Package 以支援 Windows 11 的新選單:目前我知道在 Windows 11 中添加自定義選單,必須透過 Sparse Package 來實現,因此如果是 Windows 11 系統就必須多執行這一步。
然後我們只需要確保「InstallContextMenu」和「UnInstallContextMenu」能夠在註冊 DLL 和註銷 DLL 時正確執行,即可在程式碼中完成選單的安裝和解除安裝。
💡 相關的 InstallContextMenu 和 UnInstallContextMenu 的實作,可以參考 Github 程式碼。
建置 DLLMain
最後為了讓 Windows Shell 能夠順利地獲取並使用我們的自定義右鍵選單,我們需要建置 DLLMain 函數並實作幾個關鍵的對外接口。這些接口是 Windows Shell 用來與 DLL 互動的橋樑,對於確保我們自定義功能的正常。以下為 DLLMain 的程式碼:
- DLLMain:是 DLL 的主要入口點。它在 DLL 被加載、註銷,或者執行緒創建和終止時被調用。
- DllRegisterServer和DllUnregisterServer:用於註冊或註銷 DLL時執行。為了讓系統能夠識別並使用我們的自定義選單,需要在這兩個方法中分別呼叫剛才建立的「InstallContextMenu」和「UnInstallContextMenu」進行選單的安裝和解除安裝。
- DllGetClassObject:它負責返回一個用於創建 COM 元件的 IClassFactory 工廠對象。我們需要檢查傳入的參數是否符合我們主選單所設定的 UUID。如果檢查通過,則回傳一個 IClassFactory 對象,該對象為我們自定義的主選單。💡 IClassFactory 的主要作用是創建 COM 元件。在 COM 編程模型中,元件的創建通常是透過工廠對象來完成。
- DllCanUnloadNow:用於確定 DLL 是否可以被安全註銷,確保在不再需要時,DLL 可以被正確且安全地註銷。
0 Comments
張貼留言