(C#)Windows Shell 外壳编程系列4 - 上下文菜单(iContextMenu)(二)嵌入菜单和执行命令
(本系列文章由柠檬的(lc_mtt)原创,转载请注明出处,谢谢~)接上一节:(C#)Windows Shell 外壳编程系列3 - 上下文菜单(iContextMenu)(一)右键菜单上一节说到如何弹出 IShellFolder 的上下文菜单,也就是 IContextMenu。有时候我们需要在这个菜单上面,加入一些属于自己的菜单项。举个例子,你打开资源管理器,查看左边目录树的右键菜单,会发现顶层多了一个折叠/展开的菜单项。好,我们也动手来加入这个菜单项。修改例子3,我们找到 QueryContextMenu 处,这时候提供了一个菜单句柄: //提供一个弹出式菜单的句柄 IntPtrcontextMenu=API.CreatePopupMenu(); iContextMenu.QueryContextMenu(contextMenu,0, API.CMD_FIRST,API.CMD_LAST,CMF.NORMAL|CMF.EXPLORE); 然后增加以下代码: /////////////////////////增加一个自定义菜单stringtopInvoke=Tree1.SelectedNode.IsExpanded?"折叠(&A)":"展开(&A)";MFTextraFlag=(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)] publicstaticexternboolInsertMenu( IntPtrhmenu, uintuPosition, MFTuflags, uintuIDNewItem, [MarshalAs(UnmanagedType.LPTStr)] stringlpNewItem); 参数2表示增加菜单项的位置,从0开始。参数3表示flag,这里提供了菜单状态,以及位置的计算方法,它是一个枚举: public enum MFT MF_BYPOSITION 表示位置的计算方法是使用索引项,第一个菜单就是0,第二个菜单就是1,如此类推...参数4表示命令值。我们可以根据这个命令值来执行对应的功能。然后就可以弹出菜单了: //弹出菜单 uintcmd=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();elseTree1.SelectedNode.Expand();}} 如图:执行菜单命令能不能不弹出菜单直接调用菜单项相应的命令?答案是肯定的。 大家还记得怎么显示一个文件或文件夹的属性对话框吗? Yes,用ShellExecuteEx并指定SHELLEXECUTEINFO的lpVerb域为properties就可,但是这种方法只能查看一个文件的属性,怎么同时查看多个的? 要知道ShellExecuteEx查看文件属性最终也是靠IContextMenu帮忙的,所以答案还是在IContextMenu上,我们只要在调用GetUIObjectOf时把想查看的文件或文件件的PIDL做为参数传进去,然后直接调用InvokeCommand方法就OK啦。 当然,我们做的例子,还是弹出一个对象的属性,靠你自己修改了。 我们必须先得到 IContextMenu 接口: //得到IContextMenu接口 IntPtriContextMenuPtr=IntPtr.Zero; iContextMenuPtr=IParent.GetUIObjectOf(IntPtr.Zero,(uint)pidls.Length, pidls,refGuids.IID_IContextMenu,outiContextMenuPtr); IContextMenuiContextMenu=(IContextMenu)Marshal.GetObjectForIUnknown(iContextMenuPtr); 但我们不弹出这个菜单,仅仅是调用 InvokeCommand 来执行命令而已: //直接执行命令 CMINVOKECOMMANDINFOEXinvoke=newCMINVOKECOMMANDINFOEX(); invoke.cbSize=Marshal.SizeOf(typeof(CMINVOKECOMMANDINFOEX)); invoke.lpVerb=Marshal.StringToHGlobalAnsi("properties"); invoke.lpDirectory=string.Empty; invoke.fMask=0; invoke.nShow=1; iContextMenu.InvokeCommand(refinvoke); 关于verb的更多信息请参考MSDN。我这里做的是执行“属性”,如果你要执行其他命令,或者按照索引来执行,也是可以的。这里不做深入研究。源代码:/Files/lemony/WinShell4.rar我正在考虑下一节是讲图标,还是继续讲iContextMenu。大家也知道,某个文件的右键菜单里面,往往会有几个 winrar 的选项,还带着可爱的图标。很有可能下一节就讲述如何在C#中也实现这样的效果哦。希望大家多多支持^_^。