天天看點

(C#)Windows Shell 外殼程式設計系列4 - 上下文菜單(iContextMenu)(二)嵌入菜單和執行指令

(本系列文章由檸檬的(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#中也實作這樣的效果哦。希望大家多多支援^_^。