开发者社区> 杰克.陈> 正文

(C#)Windows Shell 编程系列4 - 上下文菜单(iContextMenu)(二)嵌入菜单和执行命令

简介: 原文(C#)Windows Shell 编程系列4 - 上下文菜单(iContextMenu)(二)嵌入菜单和执行命令 (本系列文章由柠檬的(lc_mtt)原创,转载请注明出处,谢谢~)接上一节:(C#)Windows Shell 编程系列3 - 上下文菜单(iContextMenu)(一)右键菜单上 一节说到如何弹出 IShellFolder 的上下文菜单,也就是 IContextMenu。
+关注继续查看

原文(C#)Windows Shell 编程系列4 - 上下文菜单(iContextMenu)(二)嵌入菜单和执行命令

(本系列文章由柠檬的(lc_mtt)原创,转载请注明出处,谢谢~)

接上一节:(C#)Windows Shell 编程系列3 - 上下文菜单(iContextMenu)(一)右键菜单

上 一节说到如何弹出 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, 0true);
/////////////////////////
这里我们用到了 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 : uint
{
    GRAYED 
= 0x00000003,
    DISABLED 
= 0x00000003,
    CHECKED 
= 0x00000008,
    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#中也实现这样的效果哦。希望大家多多支持^_^。 

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
MaxCompute客户端(odpscmd)在windows命令行下查询中文乱码问题处理实践
MaxCompute客户端工具是阿里云大数据计算服务MaxCompue产品官方客户端工具,通过客户端工具可以连接MaxCompute项目,完成包括数据管理、数据上下传、作业执行、用户及授权管理等各项操作。
5679 0
Python学习(28)--tkinter图形界面编程1
Python学习(28)--tkinter图形界面编程1 这一节我们将介绍Python内置的图形界面编程模块tkinter,tkinter是Python标准的GUI编程接口,可以良好的运行在大多数的系统平台中,只需要安装好Python就可以导入tkinter模块并使用,无需安装第三方库。
1719 0
【Windows10 IoT开发系列】Powershell命令行实用程序
原文:【Windows10 IoT开发系列】Powershell命令行实用程序 更新帐户密码: 强烈建议你更新默认的管理员帐户密码。若要更新帐户密码,你可以发出以下命令: net user Administrator [new password]​ (其中 [new password] 表示你选择的强密码)。
1190 0
+关注
杰克.陈
一个安静的程序猿~
10427
文章
2
问答
文章排行榜
最热
最新
相关电子书
更多
OceanBase 入门到实战教程
立即下载
阿里云图数据库GDB,加速开启“图智”未来.ppt
立即下载
实时数仓Hologres技术实战一本通2.0版(下)
立即下载