(C#)Windows Shell 外殼編程系列4 – 操作功能表(iContextMenu)(二)嵌入菜單和執行命令

來源:互聯網
上載者:User

(本系列文章由檸檬的(lc_mtt)原創,轉載請註明出處,謝謝~)

上一節說到如何彈出 IShellFolder 的操作功能表,也就是 IContextMenu。有時候我們需要在這個菜單上面,加入一些屬於自己的功能表項目。舉個例子,你開啟資源管理員,查看左邊分類樹的右鍵菜單,會發現頂層多了一個摺疊/展開的功能表項目。好,我們也動手來加入這個功能表項目。
修改例子3,我們找到 QueryContextMenu 處,這時候提供了一個菜單控制代碼:

//提供一個彈出式菜單的控制代碼
IntPtr contextMenu = API.CreatePopupMenu();
iContextMenu.QueryContextMenu(contextMenu, 0,
    API.CMD_FIRST, API.CMD_LAST, CMF.NORMAL | CMF.EXPLORE);

然後增加以下代碼:

/**//////////////////////////增加一個自訂菜單
string topInvoke = Tree1.SelectedNode.IsExpanded ? "摺疊(&A)" : "展開(&A)";
MFT extraFlag = (Tree1.SelectedNode.Nodes.Count > 0) ? 0 : MFT.GRAYED;
API.InsertMenu(contextMenu, 0, MFT.BYPOSITION | extraFlag,
    (int)(API.CMD_LAST+1), topInvoke);
//增加分隔線
API.InsertMenu(contextMenu, 1, MFT.BYPOSITION | MFT.SEPARATOR, 0, "-");
//把第一項菜單設定為預設菜單,也就是加粗
API.SetMenuDefaultItem(contextMenu, 0, true);
/**//////////////////////////

這裡我們用到了 InsertMenu 這個 API:

[DllImport("user32",
            SetLastError = true,
            CharSet = CharSet.Auto)]
public static extern bool InsertMenu(
            IntPtr hmenu,
uint uPosition,
            MFT uflags,
uint uIDNewItem,
            [MarshalAs(UnmanagedType.LPTStr)]
string lpNewItem);

參數2表示增加功能表項目的位置,從0開始。
參數3表示flag,這裡提供了菜單狀態,以及位置的計算方法,它是一個枚舉:

public enum MFT
public enum MFT : uint
{
    GRAYED = 0x00000003,
   x00000003,
   x00000008,
    SEPARATOR = 0x00000800,
    RADIOCHECK = 0x00000200,
    BITMAP = 0x00000004,
    OWNERDRAW = 0x00000100,
    MENUBARBREAK = 0x00000020,
    MENUBREAK = 0x00000040,
    RIGHTORDER = 0x00002000,
    BYCOMMAND = 0x00000000,
    BYPOSITION = 0x00000400,
    POPUP = 0x00000010
}

MF_BYPOSITION 表示位置的計算方法是使用索引項目,第一個菜單就是0,第二個菜單就是1,如此類推...
參數4表示命令值。我們可以根據這個命令值來執行對應的功能。
然後就可以快顯功能表了:

//快顯功能表
uint cmd = API.TrackPopupMenuEx(contextMenu,TPM.RETURNCMD,
MousePosition.X, MousePosition.Y, this.Handle, IntPtr.Zero);

可以看到快顯功能表的效果。當然,我們還必須做點事情來響應這個菜單的執行:

//擷取命令序號,執行功能表命令
if (cmd >= API.CMD_FIRST)
{

//自訂功能表命令
if (cmd == API.CMD_LAST + 1)
{
if (Tree1.SelectedNode.IsExpanded)
            Tree1.SelectedNode.Collapse();
else
            Tree1.SelectedNode.Expand();
    }
}



執行功能表命令
能不能不快顯功能表直接調用功能表項目相應的命令?答案是肯定的。

大家還記得怎麼顯示一個檔案或檔案夾的屬性對話方塊嗎?

Yes,用ShellExecuteEx並指定SHELLEXECUTEINFO的lpVerb域為properties就可,但是這種方法只能查看一個檔案的屬性,怎麼同時查看多個的?

要知道ShellExecuteEx查看檔案屬性最終也是靠IContextMenu幫忙的,所以答案還是在IContextMenu上,我們只要在調用GetUIObjectOf時把想查看的檔案或檔案件的PIDL做為參數傳進去,然後直接調用InvokeCommand方法就OK啦。

當然,我們做的例子,還是彈出一個對象的屬性,靠你自己修改了。

我們必須先得到 IContextMenu 介面:

//得到 IContextMenu 介面
IntPtr iContextMenuPtr = IntPtr.Zero;
iContextMenuPtr = IParent.GetUIObjectOf(IntPtr.Zero, (uint)pidls.Length,
    pidls, ref Guids.IID_IContextMenu, out iContextMenuPtr);
IContextMenu iContextMenu = (IContextMenu)Marshal.GetObjectForIUnknown(iContextMenuPtr);

但我們不彈出這個菜單,僅僅是調用 InvokeCommand 來執行命令而已:

//直接執行命令
CMINVOKECOMMANDINFOEX invoke = new CMINVOKECOMMANDINFOEX();
invoke.cbSize = Marshal.SizeOf(typeof(CMINVOKECOMMANDINFOEX));
invoke.lpVerb = Marshal.StringToHGlobalAnsi("properties");
invoke.lpDirectory = string.Empty;
invoke.fMask = 0;
invoke.nShow = 1;
iContextMenu.InvokeCommand(ref invoke);

關於verb的更多資訊請參考MSDN。我這裡做的是執行“屬性”,如果你要執行其他命令,或者按照索引來執行,也是可以的。這裡不做深入研究。

原始碼:/Files/lemony/WinShell4.rar
我正在考慮下一節是講表徵圖,還是繼續講iContextMenu。大家也知道,某個檔案的右鍵菜單裡面,往往會有幾個 winrar 的選項,還帶著可愛的表徵圖。

很有可能下一節就講述如何在C#中也實現這樣的效果哦。希望大家多多支援^_^。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.