(本系列文章由檸檬的(lc_mtt)原創,轉載請注明出處,謝謝~)
上一節說到如何彈出 IShellFolder 的上下文菜單,也就是 IContextMenu。有時候我們需要在這個菜單上面,加入一些屬于自己的菜單項。舉個例子,你打開資料總管,檢視左邊目錄樹的右鍵菜單,會發現頂層多了一個折疊/展開的菜單項。好,我們也動手來加入這個菜單項。
修改例子3,我們找到 QueryContextMenu 處,這時候提供了一個菜單句柄:
(C#)Windows Shell 外殼程式設計系列4 - 上下文菜單(iContextMenu)(二)嵌入菜單和執行指令 //提供一個彈出式菜單的句柄
(C#)Windows Shell 外殼程式設計系列4 - 上下文菜單(iContextMenu)(二)嵌入菜單和執行指令 IntPtr contextMenu = API.CreatePopupMenu();
(C#)Windows Shell 外殼程式設計系列4 - 上下文菜單(iContextMenu)(二)嵌入菜單和執行指令 iContextMenu.QueryContextMenu(contextMenu, 0,
(C#)Windows Shell 外殼程式設計系列4 - 上下文菜單(iContextMenu)(二)嵌入菜單和執行指令 API.CMD_FIRST, API.CMD_LAST, CMF.NORMAL | CMF.EXPLORE);
然後增加以下代碼:
(C#)Windows Shell 外殼程式設計系列4 - 上下文菜單(iContextMenu)(二)嵌入菜單和執行指令 /////////////////////////增加一個自定義菜單
(C#)Windows Shell 外殼程式設計系列4 - 上下文菜單(iContextMenu)(二)嵌入菜單和執行指令 string topInvoke = Tree1.SelectedNode.IsExpanded ? "折疊(&A)" : "展開(&A)";
(C#)Windows Shell 外殼程式設計系列4 - 上下文菜單(iContextMenu)(二)嵌入菜單和執行指令 MFT extraFlag = (Tree1.SelectedNode.Nodes.Count > 0) ? 0 : MFT.GRAYED;
(C#)Windows Shell 外殼程式設計系列4 - 上下文菜單(iContextMenu)(二)嵌入菜單和執行指令 API.InsertMenu(contextMenu, 0, MFT.BYPOSITION | extraFlag,
(C#)Windows Shell 外殼程式設計系列4 - 上下文菜單(iContextMenu)(二)嵌入菜單和執行指令 (int)(API.CMD_LAST+1), topInvoke);
(C#)Windows Shell 外殼程式設計系列4 - 上下文菜單(iContextMenu)(二)嵌入菜單和執行指令 //增加分隔線
(C#)Windows Shell 外殼程式設計系列4 - 上下文菜單(iContextMenu)(二)嵌入菜單和執行指令 API.InsertMenu(contextMenu, 1, MFT.BYPOSITION | MFT.SEPARATOR, 0, "-");
(C#)Windows Shell 外殼程式設計系列4 - 上下文菜單(iContextMenu)(二)嵌入菜單和執行指令 //把第一項菜單設定為預設菜單,也就是加粗
(C#)Windows Shell 外殼程式設計系列4 - 上下文菜單(iContextMenu)(二)嵌入菜單和執行指令 API.SetMenuDefaultItem(contextMenu, 0, true);
(C#)Windows Shell 外殼程式設計系列4 - 上下文菜單(iContextMenu)(二)嵌入菜單和執行指令 /////////////////////////
這裡我們用到了 InsertMenu 這個 API:
(C#)Windows Shell 外殼程式設計系列4 - 上下文菜單(iContextMenu)(二)嵌入菜單和執行指令 [DllImport("user32",
(C#)Windows Shell 外殼程式設計系列4 - 上下文菜單(iContextMenu)(二)嵌入菜單和執行指令 SetLastError = true,
(C#)Windows Shell 外殼程式設計系列4 - 上下文菜單(iContextMenu)(二)嵌入菜單和執行指令 CharSet = CharSet.Auto)]
(C#)Windows Shell 外殼程式設計系列4 - 上下文菜單(iContextMenu)(二)嵌入菜單和執行指令 public static extern bool InsertMenu(
(C#)Windows Shell 外殼程式設計系列4 - 上下文菜單(iContextMenu)(二)嵌入菜單和執行指令 IntPtr hmenu,
(C#)Windows Shell 外殼程式設計系列4 - 上下文菜單(iContextMenu)(二)嵌入菜單和執行指令 uint uPosition,
(C#)Windows Shell 外殼程式設計系列4 - 上下文菜單(iContextMenu)(二)嵌入菜單和執行指令 MFT uflags,
(C#)Windows Shell 外殼程式設計系列4 - 上下文菜單(iContextMenu)(二)嵌入菜單和執行指令 uint uIDNewItem,
(C#)Windows Shell 外殼程式設計系列4 - 上下文菜單(iContextMenu)(二)嵌入菜單和執行指令 [MarshalAs(UnmanagedType.LPTStr)]
(C#)Windows Shell 外殼程式設計系列4 - 上下文菜單(iContextMenu)(二)嵌入菜單和執行指令 string lpNewItem);
參數2表示增加菜單項的位置,從0開始。
參數3表示flag,這裡提供了菜單狀态,以及位置的計算方法,它是一個枚舉:
(C#)Windows Shell 外殼程式設計系列4 - 上下文菜單(iContextMenu)(二)嵌入菜單和執行指令 public enum MFT
MF_BYPOSITION 表示位置的計算方法是使用索引項,第一個菜單就是0,第二個菜單就是1,如此類推...
參數4表示指令值。我們可以根據這個指令值來執行對應的功能。
然後就可以彈出菜單了:
(C#)Windows Shell 外殼程式設計系列4 - 上下文菜單(iContextMenu)(二)嵌入菜單和執行指令 //彈出菜單
(C#)Windows Shell 外殼程式設計系列4 - 上下文菜單(iContextMenu)(二)嵌入菜單和執行指令 uint cmd = API.TrackPopupMenuEx(contextMenu,TPM.RETURNCMD,
(C#)Windows Shell 外殼程式設計系列4 - 上下文菜單(iContextMenu)(二)嵌入菜單和執行指令 MousePosition.X, MousePosition.Y, this.Handle, IntPtr.Zero);
可以看到彈出菜單的效果。當然,我們還必須做點事情來響應這個菜單的執行:
(C#)Windows Shell 外殼程式設計系列4 - 上下文菜單(iContextMenu)(二)嵌入菜單和執行指令 //擷取指令序号,執行菜單指令
(C#)Windows Shell 外殼程式設計系列4 - 上下文菜單(iContextMenu)(二)嵌入菜單和執行指令 if (cmd >= API.CMD_FIRST)
(C#)Windows Shell 外殼程式設計系列4 - 上下文菜單(iContextMenu)(二)嵌入菜單和執行指令 {
(C#)Windows Shell 外殼程式設計系列4 - 上下文菜單(iContextMenu)(二)嵌入菜單和執行指令
(C#)Windows Shell 外殼程式設計系列4 - 上下文菜單(iContextMenu)(二)嵌入菜單和執行指令
(C#)Windows Shell 外殼程式設計系列4 - 上下文菜單(iContextMenu)(二)嵌入菜單和執行指令
(C#)Windows Shell 外殼程式設計系列4 - 上下文菜單(iContextMenu)(二)嵌入菜單和執行指令 //自定義菜單指令
(C#)Windows Shell 外殼程式設計系列4 - 上下文菜單(iContextMenu)(二)嵌入菜單和執行指令 if (cmd == API.CMD_LAST + 1)
(C#)Windows Shell 外殼程式設計系列4 - 上下文菜單(iContextMenu)(二)嵌入菜單和執行指令 {
(C#)Windows Shell 外殼程式設計系列4 - 上下文菜單(iContextMenu)(二)嵌入菜單和執行指令 if (Tree1.SelectedNode.IsExpanded)
(C#)Windows Shell 外殼程式設計系列4 - 上下文菜單(iContextMenu)(二)嵌入菜單和執行指令 Tree1.SelectedNode.Collapse();
(C#)Windows Shell 外殼程式設計系列4 - 上下文菜單(iContextMenu)(二)嵌入菜單和執行指令 else
(C#)Windows Shell 外殼程式設計系列4 - 上下文菜單(iContextMenu)(二)嵌入菜單和執行指令 Tree1.SelectedNode.Expand();
(C#)Windows Shell 外殼程式設計系列4 - 上下文菜單(iContextMenu)(二)嵌入菜單和執行指令 }
(C#)Windows Shell 外殼程式設計系列4 - 上下文菜單(iContextMenu)(二)嵌入菜單和執行指令 }
如圖:
執行菜單指令
能不能不彈出菜單直接調用菜單項相應的指令?答案是肯定的。
大家還記得怎麼顯示一個檔案或檔案夾的屬性對話框嗎?
Yes,用ShellExecuteEx并指定SHELLEXECUTEINFO的lpVerb域為properties就可,但是這種方法隻能檢視一個檔案的屬性,怎麼同時檢視多個的?
要知道ShellExecuteEx檢視檔案屬性最終也是靠IContextMenu幫忙的,是以答案還是在IContextMenu上,我們隻要在調用GetUIObjectOf時把想檢視的檔案或檔案件的PIDL做為參數傳進去,然後直接調用InvokeCommand方法就OK啦。
當然,我們做的例子,還是彈出一個對象的屬性,靠你自己修改了。
我們必須先得到 IContextMenu 接口:
(C#)Windows Shell 外殼程式設計系列4 - 上下文菜單(iContextMenu)(二)嵌入菜單和執行指令 //得到 IContextMenu 接口
(C#)Windows Shell 外殼程式設計系列4 - 上下文菜單(iContextMenu)(二)嵌入菜單和執行指令 IntPtr iContextMenuPtr = IntPtr.Zero;
(C#)Windows Shell 外殼程式設計系列4 - 上下文菜單(iContextMenu)(二)嵌入菜單和執行指令 iContextMenuPtr = IParent.GetUIObjectOf(IntPtr.Zero, (uint)pidls.Length,
(C#)Windows Shell 外殼程式設計系列4 - 上下文菜單(iContextMenu)(二)嵌入菜單和執行指令 pidls, ref Guids.IID_IContextMenu, out iContextMenuPtr);
(C#)Windows Shell 外殼程式設計系列4 - 上下文菜單(iContextMenu)(二)嵌入菜單和執行指令 IContextMenu iContextMenu = (IContextMenu)Marshal.GetObjectForIUnknown(iContextMenuPtr);
但我們不彈出這個菜單,僅僅是調用 InvokeCommand 來執行指令而已:
(C#)Windows Shell 外殼程式設計系列4 - 上下文菜單(iContextMenu)(二)嵌入菜單和執行指令 //直接執行指令
(C#)Windows Shell 外殼程式設計系列4 - 上下文菜單(iContextMenu)(二)嵌入菜單和執行指令 CMINVOKECOMMANDINFOEX invoke = new CMINVOKECOMMANDINFOEX();
(C#)Windows Shell 外殼程式設計系列4 - 上下文菜單(iContextMenu)(二)嵌入菜單和執行指令 invoke.cbSize = Marshal.SizeOf(typeof(CMINVOKECOMMANDINFOEX));
(C#)Windows Shell 外殼程式設計系列4 - 上下文菜單(iContextMenu)(二)嵌入菜單和執行指令 invoke.lpVerb = Marshal.StringToHGlobalAnsi("properties");
(C#)Windows Shell 外殼程式設計系列4 - 上下文菜單(iContextMenu)(二)嵌入菜單和執行指令 invoke.lpDirectory = string.Empty;
(C#)Windows Shell 外殼程式設計系列4 - 上下文菜單(iContextMenu)(二)嵌入菜單和執行指令 invoke.fMask = 0;
(C#)Windows Shell 外殼程式設計系列4 - 上下文菜單(iContextMenu)(二)嵌入菜單和執行指令 invoke.nShow = 1;
(C#)Windows Shell 外殼程式設計系列4 - 上下文菜單(iContextMenu)(二)嵌入菜單和執行指令 iContextMenu.InvokeCommand(ref invoke);
關于verb的更多資訊請參考MSDN。我這裡做的是執行“屬性”,如果你要執行其他指令,或者按照索引來執行,也是可以的。這裡不做深入研究。
我正在考慮下一節是講圖示,還是繼續講iContextMenu。大家也知道,某個檔案的右鍵菜單裡面,往往會有幾個 winrar 的選項,還帶着可愛的圖示。
很有可能下一節就講述如何在C#中也實作這樣的效果哦。希望大家多多支援^_^。