(C#)Windows Shell 外壳编程系列3 - 上下文菜单(iContextMenu)(一)右键菜单
(本系列文章由柠檬的(lc_mtt)原创,转载请注明出处,谢谢~)
接上一节:(C#)Windows Shell 外壳编程系列2 - 解释,从“桌面”开始展开
这里解释上一节中获取名称的方法
GetDisplayNameOf 定义:
void GetDisplayNameOf(
IntPtr pidl,
SHGNO uFlags,
IntPtr lpName);该方法是用来转换PIDL成为可显示的名称字符串。PIDL必须是相对于对象的父目录的。换句话说,它必须包含一个非空的SHITEMID 结构。因为有多种命名对象的方式,资源管理器通过在uFlags参数中定义SHGNO标识的组合来表示名称类型。SHGDN_NORMAL或SHGDN_INFOLDER将被用来指定名称是相对于文件夹的还是相对于桌面的。其他三个值SHGDN_FOREDITING、SHGDN_FORADDRESSBAR和SHGDN_FORPARSING可以用来指定名称的用途。 名称必须按STRRET的结构形式返回,如果SHGDN_FOREDITING、SHGDN_FORADDRESSBAR和 SHGDN_FORPARSING没有设定,就返回外壳对象的显示名称。
具体实现方法:
/// <summary>
/// 获取显示名称
/// </summary>
public static string GetNameByIShell(IShellFolder Root, IntPtr pidlSub)
{
IntPtr strr = Marshal.AllocCoTaskMem(MAX_PATH * 2 + 4);
Marshal.WriteInt32(strr, 0, 0);
StringBuilder buf = new StringBuilder(MAX_PATH);
Root.GetDisplayNameOf(pidlSub, SHGNO.INFOLDER, strr);
API.StrRetToBuf(strr, pidlSub, buf, MAX_PATH);
Marshal.FreeCoTaskMem(strr);
return buf.ToString();
}
SHGNO事实上,只要修改 SHGNO ,就可以获取其绝对路径:
/// <summary>
/// 根据路径获取 IShellFolder 和 PIDL
/// </summary>
public static IShellFolder GetShellFolder(IShellFolder desktop, string path, out IntPtr Pidl)
{
IShellFolder IFolder;
uint i, j = 0;
desktop.ParseDisplayName(IntPtr.Zero, IntPtr.Zero, path, out i, out Pidl, ref j);
desktop.BindToObject(Pidl, IntPtr.Zero, ref Guids.IID_IShellFolder, out IFolder);
return IFolder;
}但我们还关心类似“桌面”、“我的文档”这种既是普通文件夹又是特殊对象的绝对路径如何获得,这里就要用到 SHGetSpecialFolderPath API 了。
[DllImport("Shell32.Dll")]
private static extern bool SHGetSpecialFolderPath(
IntPtr hwndOwner,
StringBuilder lpszPath,
ShellSpecialFolders nFolder,
bool fCreate);

ShellSpecialFolders
/// <summary>
/// 获取特殊文件夹的路径
/// </summary>
public static string GetSpecialFolderPath(IntPtr hwnd, ShellSpecialFolders nFolder)
{
StringBuilder sb = new StringBuilder(MAX_PATH);
SHGetSpecialFolderPath(hwnd, sb, nFolder, false);
return sb.ToString();
}上下文菜单
对象的上下文菜单相关的接口是IContextMenu,通过对象的父文件夹的IShellFolder.GetUIObjectOf方法可得到该接口。得到该接口后,可以用IContextMenu.QueryContextMenu方法来生成上下文菜单的菜单项,用IContextMenu.InvokeCommand调用相应的命令。
好,让我们一步一步来实现 IShellFolder 对象的上下文菜单弹出。
首先假设我们已经获得某个 IShellFolder 对象的 PIDL 和其上级 IShellFolder 对象:
IntPtr PIDL;
IShellFolder IParent;然后我们定义一个存放 PIDL 的数组:
IntPtr[] pidls = new IntPtr[1];
pidls[0] = PIDL;没错,我们的确要用到 PIDL 数组。可以理解,你在资源管理器中选择了多个文件/文件夹,再点击右键,弹出的上下文菜单将有所不同。你可以根据需要,把同一级的多个 PIDL 放到数组里面,实现这个效果。由于我们在例2的树中弹出菜单,所以只存放一个节点的 PIDL。
IContextMenu 是一个接口,我们这样定义:
IContextMenu.cs然后,通过 IParent 的 GetUIObjectOf 方法我们可以得到该节点的一个或多个指定子节点的 IContextMenu 接口:
GetUIObjectOf
//得到 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);得到 IContextMenu 后我们需要提供一个弹出式菜单的句柄,并把他传给 IContextMenu.QueryContextMenu,如果该方法执行成功的话,会在我们的菜单里加入相应的菜单项。
//提供一个弹出式菜单的句柄
IntPtr contextMenu = API.CreatePopupMenu();
iContextMenu.QueryContextMenu(contextMenu, 0,
API.CMD_FIRST, API.CMD_LAST, CMF.NORMAL | CMF.EXPLORE);有了菜单项,我们就可以弹出该菜单了,我们用 TPM_RETURNCMD 标志指定 TrackPopupMenu 必须返回用户所选菜单项的 ID,以便稍后通过IContextMenu.InvokeCommand 来执行菜单命令:
//弹出菜单
uint cmd = API.TrackPopupMenuEx(contextMenu,TPM.RETURNCMD,
MousePosition.X, MousePosition.Y, this.Handle, IntPtr.Zero);
//获取命令序号,执行菜单命令
if (cmd >= API.CMD_FIRST)
{
CMINVOKECOMMANDINFOEX invoke = new CMINVOKECOMMANDINFOEX();
invoke.cbSize = Marshal.SizeOf(typeof(CMINVOKECOMMANDINFOEX));
invoke.lpVerb = (IntPtr)(cmd - 1);
invoke.lpDirectory = string.Empty;
invoke.fMask = 0;
invoke.ptInvoke = new POINT(MousePosition.X, MousePosition.Y);
invoke.nShow = 1;
iContextMenu.InvokeCommand(ref invoke);
}惯例附上图片和源代码:

源代码:/Files/lemony/WinShell3.rar
下一节深入讲述 iContextMenu,让我们可以插入自己的菜单,或者直接调用菜单命令。
(C#)Windows Shell 外壳编程系列3 - 上下文菜单(iContextMenu)(一)右键菜单的更多相关文章
- (C#)Windows Shell 外壳编程系列4 - 上下文菜单(iContextMenu)(二)嵌入菜单和执行命令
(本系列文章由柠檬的(lc_mtt)原创,转载请注明出处,谢谢-) 接上一节:(C#)Windows Shell 外壳编程系列3 - 上下文菜单(iContextMenu)(一)右键菜单 上一节说到如 ...
- (C#)Windows Shell 外壳编程系列5 - 获取图标
(本系列文章由柠檬的(lc_mtt)原创,转载请注明出处,谢谢-) 接上一节:(C#)Windows Shell 外壳编程系列4 - 上下文菜单(iContextMenu)(二)嵌入菜单和执行命令 有 ...
- (C#)Windows Shell 外壳编程系列7 - ContextMenu 注册文件右键菜单
原文 (C#)Windows Shell 外壳编程系列7 - ContextMenu 注册文件右键菜单 (本系列文章由柠檬的(lc_mtt)原创,转载请注明出处,谢谢-) 接上一节:(C#)Windo ...
- (C#)Windows Shell 外壳编程系列2 - 解释,从“桌面”开始展开
(本系列文章由柠檬的(lc_mtt)原创,转载请注明出处,谢谢-) 接上一篇:(C#)Windows Shell 外壳编程系列1 - 基础,浏览一个文件夹 让我们详细解释一下 Shell 编程中最基本 ...
- (C#)Windows Shell 外壳编程系列8 - 同后缀名不同图标?
原文 (C#)Windows Shell 外壳编程系列8 - 同后缀名不同图标? (本系列文章由柠檬的(lc_mtt)原创,转载请注明出处,谢谢-) 接上一节:(C#)Windows Shell 外壳 ...
- (C#)Windows Shell 外壳编程系列9 - QueryInfo 扩展提示
原文 (C#)Windows Shell 外壳编程系列9 - QueryInfo 扩展提示 (本系列文章由柠檬的(lc_mtt)原创,转载请注明出处,谢谢-) 接上一节:(C#)Windows She ...
- (C#)Windows Shell 外壳编程系列6 - 执行
原文(C#)Windows Shell 外壳编程系列6 - 执行 (本系列文章由柠檬的(lc_mtt)原创,转载请注明出处,谢谢-) 接上一节:(C#)Windows Shell 外壳编程系列5 - ...
- (C#)Windows Shell 外壳编程系列1 - 基础,浏览一个文件夹
1 - 基础,浏览一个文件夹 我们知道,在win32中是以外壳名字空间的形式来组织文件系统的,在外壳名字空间里的每一个对象(注)都实现了一个IShellFolder的接口,通过这个接口我们可以直接查询 ...
- (C#)Windows Shell 编程系列3 - 上下文菜单(iContextMenu)(一)右键菜单
原文 (C#)Windows Shell 编程系列3 - 上下文菜单(iContextMenu)(一)右键菜单 接上一节:(C#)Windows Shell 编程系列2 - 解释,从“桌面”开始展开这 ...
随机推荐
- 【转载】格式化存储装置成为 Ext2/Ext3/Ext4 档案系统
格式化 用系统管理员帐户 (即 root) 身份打「mkfs -t ext2|ext3|ext4 储存装置」: mkfs -t ext3 /dev/sdb5 要格式化档案系统为 Ext2,亦可以直接使 ...
- 嵌入式Qt程序启动参数-qws 不需要X11桌面系统
1 背景 通过串口终端启动arm开发板(linux系统)的Qt应用程序,提示: [root@FORLINX6410]# /opt/qt-4.7.1/demos/textedit/textedit s3 ...
- 【Flask】ORM 关系一对一
### 一对一的关系:在sqlalchemy中,如果想要将两个模型映射成一对一的关系,那么应该在父模型中,指定引用的时候,要传递一个`uselist=False`这个参数进去.就是告诉父模型,以后引用 ...
- com.android.dex.DexIndexOverflowException: Cannot merge new index 66299 into a non-jumbo instruction
打包时控制台输出: Error:Execution failed for task ':app:transformClassesWithDexForAll32Release'. > com.an ...
- python 运行报错 Process finished with exit code -1073741819 (0xC0000005)
发现是由于openpyxl模块导致的,去掉这个模块的内容就能运行,import openpyxl就运行不起来, 将openpyxl卸载了重装, 以及更换了不同的openpyxl版本,都不行,还是运行不 ...
- Hearbeat 工作原理
Hearbeat 原理 heartbeat (Linux-HA)的工作原理:heartbeat最核心的包括两个部分,心跳监测部分和资源接管部分,心跳监测可以通过网络链路和串口进行,而且支持冗 余链路, ...
- PHP扩展模块Pecl、Pear以及Perl的区别
一.简短总结:pear:一个书写的比较规范,国外较流行的工具箱代码集pecl:php扩展包,但不属于php基本扩展范围perl:一种早于php出现的脚本级语言,php借鉴了他的正则表达式部分 二.Pe ...
- kafka笔记(一)
1.kafka应用场景 基于流数据的发布订阅消息系统.实时流数据的高效异步通信.基于流数据的高可用分布式存储! 不同的系统之间实时流数据管道; 2.官方一句话概括 kafka是一个分布式流数据平台:可 ...
- Spark性能优化指南--基础篇
前言 开发调优 调优概述 原则一:避免创建重复的RDD 原则二:尽可能复用同一个RDD 原则三:对多次使用的RDD进行持久化 原则四:尽量避免使用shuffle类算子 原则五:使用map-side预聚 ...
- ReverseInteger
public class ReverseInteger { public static int reverse(int x) { long ret = 0; //如果是个位数,直接返回. if(x/1 ...