(C#)Windows Shell 编程系列3 - 上下文菜单(iContextMenu)(一)右键菜单
原文 (C#)Windows Shell 编程系列3 - 上下文菜单(iContextMenu)(一)右键菜单
接上一节:(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没有设定,就返回外壳对象的显示名称。
具体实现方法:
);
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();
}
public enum SHGNO
{
NORMAL = 0x0,
INFOLDER = 0x1,
FOREDITING = 0x1000,
FORADDRESSBAR = 0x4000,
FORPARSING = 0x8000,
}事实上,只要修改 SHGNO ,就可以获取其绝对路径:
;
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);

public enum ShellSpecialFolders
{
DESKTOP = 0x0000, // <desktop>
INTERNET = 0x0001,
PROGRAMS = 0x0002, // Start Menu/Programs
CONTROLS = 0x0003, // My Computer/Control Panel
PRINTERS = 0x0004, // My Computer/Printers
PERSONAL = 0x0005, // My Documents
FAVORITES = 0x0006, // <user name>/Favorites
STARTUP = 0x0007, // Start Menu/Programs/Startup
RECENT = 0x0008, // <user name>/Recent
SENDTO = 0x0009, // <user name>/SendTo
BITBUCKET = 0x000a, // <desktop>/Recycle Bin
STARTMENU = 0x000b, // <user name>/Start Menu
MYDOCUMENTS = 0x000c, // logical "My Documents" desktop icon
MYMUSIC = 0x000d, // "My Music" folder
MYVIDEO = 0x000e, // "My Videos" folder
DESKTOPDIRECTORY = 0x0010, // <user name>/Desktop
DRIVES = 0x0011, // My Computer
NETWORK = 0x0012, // Network Neighborhood (My Network Places)
NETHOOD = 0x0013, // <user name>/nethood
FONTS = 0x0014, // windows/fonts
TEMPLATES = 0x0015,
COMMON_STARTMENU = 0x0016, // All Users/Start Menu
COMMON_PROGRAMS = 0X0017, // All Users/Start Menu/Programs
COMMON_STARTUP = 0x0018, // All Users/Startup
COMMON_DESKTOPDIRECTORY = 0x0019, // All Users/Desktop
APPDATA = 0x001a, // <user name>/Application Data
PRINTHOOD = 0x001b, // <user name>/PrintHood
LOCAL_APPDATA = 0x001c, // <user name>/Local Settings/Applicaiton Data (non roaming)
ALTSTARTUP = 0x001d, // non localized startup
COMMON_ALTSTARTUP = 0x001e, // non localized common startup
COMMON_FAVORITES = 0x001f,
INTERNET_CACHE = 0x0020,
COOKIES = 0x0021,
HISTORY = 0x0022,
COMMON_APPDATA = 0x0023, // All Users/Application Data
WINDOWS = 0x0024, // GetWindowsDirectory()
SYSTEM = 0x0025, // GetSystemDirectory()
PROGRAM_FILES = 0x0026, // C:/Program Files
MYPICTURES = 0x0027, // C:/Program Files/My Pictures
PROFILE = 0x0028, // USERPROFILE
SYSTEMX86 = 0x0029, // x86 system directory on RISC
PROGRAM_FILESX86 = 0x002a, // x86 C:/Program Files on RISC
PROGRAM_FILES_COMMON = 0x002b, // C:/Program Files/Common
PROGRAM_FILES_COMMONX86 = 0x002c, // x86 Program Files/Common on RISC
COMMON_TEMPLATES = 0x002d, // All Users/Templates
COMMON_DOCUMENTS = 0x002e, // All Users/Documents
COMMON_ADMINTOOLS = 0x002f, // All Users/Start Menu/Programs/Administrative Tools
ADMINTOOLS = 0x0030, // <user name>/Start Menu/Programs/Administrative Tools
CONNECTIONS = 0x0031, // Network and Dial-up Connections
COMMON_MUSIC = 0x0035, // All Users/My Music
COMMON_PICTURES = 0x0036, // All Users/My Pictures
COMMON_VIDEO = 0x0037, // All Users/My Video
RESOURCES = 0x0038, // Resource Direcotry
RESOURCES_LOCALIZED = 0x0039, // Localized Resource Direcotry
COMMON_OLINKS = 0x003a, // Links to All Users OEM specific apps
CDBURN_AREA = 0x003b, // USERPROFILE/Local Settings/Application Data/Microsoft/CD Burning
COMPUTERSNEARME = 0x003d, // Computers Near Me (computered from Workgroup membership)
FLAG_CREATE = 0x8000, // combine with value to force folder creation in SHGetFolderPath()
FLAG_DONT_VERIFY = 0x4000, // combine with value to return an unverified folder path
FLAG_NO_ALIAS = 0x1000, // combine with value to insure non-alias versions of the pidl
FLAG_PER_USER_INIT = 0x0800, // combine with value to indicate per-user init (eg. upgrade)
FLAG_MASK = 0xFF00, // mask for all possible flag values
}
/// <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 的数组:
] = PIDL;没错,我们的确要用到 PIDL 数组。可以理解,你在资源管理器中选择了多个文件/文件夹,再点击右键,弹出的上下文菜单将有所不同。你可以根据需要,把同一级的多个 PIDL 放到数组里面,实现这个效果。由于我们在例2的树中弹出菜单,所以只存放一个节点的 PIDL。
IContextMenu 是一个接口,我们这样定义:
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
namespace WinShell
{
[ComImport(), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), GuidAttribute("000214e4-0000-0000-c000-000000000046")]
public interface IContextMenu
{
[PreserveSig()]
Int32 QueryContextMenu(
IntPtr hmenu,
uint iMenu,
uint idCmdFirst,
uint idCmdLast,
CMF uFlags);
[PreserveSig()]
Int32 InvokeCommand(
ref CMINVOKECOMMANDINFOEX info);
[PreserveSig()]
void GetCommandString(
int idcmd,
GetCommandStringInformations uflags,
int reserved,
StringBuilder commandstring,
int cch);
}
} 
然后,通过 IParent 的 GetUIObjectOf 方法我们可以得到该节点的一个或多个指定子节点的 IContextMenu 接口:
IntPtr GetUIObjectOf(
IntPtr hwndOwner,
uint cidl,
[MarshalAs(UnmanagedType.LPArray)] IntPtr[] apidl,
[In()] ref Guid riid,
out IntPtr rgfReserved);
//得到 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,如果该方法执行成功的话,会在我们的菜单里加入相应的菜单项。
,
API.CMD_FIRST, API.CMD_LAST, CMF.NORMAL | CMF.EXPLORE);有了菜单项,我们就可以弹出该菜单了,我们用 TPM_RETURNCMD 标志指定 TrackPopupMenu 必须返回用户所选菜单项的 ID,以便稍后通过IContextMenu.InvokeCommand 来执行菜单命令:
;
iContextMenu.InvokeCommand(ref invoke);
}惯例附上图片和源代码:
源代码:/Files/lemony/WinShell3.rar
下一节深入讲述 iContextMenu,让我们可以插入自己的菜单,或者直接调用菜单命令。
(C#)Windows Shell 编程系列3 - 上下文菜单(iContextMenu)(一)右键菜单的更多相关文章
- (C#)Windows Shell 编程系列4 - 上下文菜单(iContextMenu)(二)嵌入菜单和执行命令
原文(C#)Windows Shell 编程系列4 - 上下文菜单(iContextMenu)(二)嵌入菜单和执行命令 (本系列文章由柠檬的(lc_mtt)原创,转载请注明出处,谢谢-) 接上一节:( ...
- C#)Windows Shell 编程系列5 - 获取图标
原文 C#)Windows Shell 编程系列5 - 获取图标 (本系列文章由柠檬的(lc_mtt)原创,转载请注明出处,谢谢-) 接上一节:(C#)Windows Shell 编程系列4 - 上下 ...
- (C#)Windows Shell 编程系列2 - 解释,从“桌面”开始展开
原文 (C#)Windows Shell 编程系列2 - 解释,从“桌面”开始展开 (本系列文章由柠檬的(lc_mtt)原创,转载请注明出处,谢谢-) 接上一篇:(C#)Windows Shell 编 ...
- (C#)Windows Shell 编程系列1 - 基础,浏览一个文件夹
原文 (C#)Windows Shell 编程系列1 - 基础,浏览一个文件夹 (本系列文章由柠檬的(lc_mtt)原创,转载请注明出处,谢谢-) Windows Shell 编程,即 Windows ...
- (C#)Windows Shell 外壳编程系列4 - 上下文菜单(iContextMenu)(二)嵌入菜单和执行命令
(本系列文章由柠檬的(lc_mtt)原创,转载请注明出处,谢谢-) 接上一节:(C#)Windows Shell 外壳编程系列3 - 上下文菜单(iContextMenu)(一)右键菜单 上一节说到如 ...
- [转]Windows Shell 编程 第二章 【来源:http://blog.csdn.net/wangqiulin123456/article/details/7987893】
第二章Shell的结构 “Shell 编程”的大伞之下有大量的API函数和COM接口.这个种类繁多的‘命令’集允许你用不同的方法对Windows Shell进行编程.函数和接口并不是两种提供相同功能 ...
- shell编程系列25--shell操作数据库实战之备份MySQL数据,并通过FTP将其传输到远端主机
shell编程系列25--shell操作数据库实战之备份MySQL数据,并通过FTP将其传输到远端主机 备份mysql中的库或者表 mysqldump 常用参数详解: -u 用户名 -p 密码 -h ...
- shell编程系列10--文本处理三剑客之sed利用sed查询特定内容
shell编程系列10--文本处理三剑客之sed利用sed查询特定内容 利用sed查找文件内容: pattern种类: .8p .,10p .,+5p ./regexp/p .,/regexp/p . ...
- Windows Shell Extension 系列文章
Windows Shell Extension 系列文章 http://www.codeproject.com/Articles/512956/NET-Shell-Extensions-Shell-C ...
随机推荐
- md笔记——微信JS接口
微信js接口 隐藏微信中网页右上角按钮 document.addEventListener('WeixinJSBridgeReady', function onBridgeReady() { Weix ...
- JavaScript之Style属性学习
当CSS使用伪类开始侵入DOM和JavaSCript所控制着的行为层时,DOM和JavaScript也使用他们的一系列样式去控制表现层,这篇随笔主要说的就是利用JavaScript去控制元素的表现形式 ...
- AppDelegate关于应用程序挂起、复原与终止的代理方法
AppDelegate关于应用程序挂起.复原与终止的代理方法: 首次运行: - (BOOL)application:(UIApplication *)application didFinishLaun ...
- rownum(转载)
对于 Oracle 的 rownum 问题,很多资料都说不支持>,>=,=,between...and,只能用以上符号(<.<=.!=),并非说用>,>=,=,be ...
- C++链接库
静态链接库在程序编译链接过程中就导入lib文件并且包含在生成的exe文件里,而动态链接库DLL是在程序运行中由程序加载和卸载的,也就是说它是动态的,当然动态链接库DLL也可以静态加载当做静态来用: 静 ...
- MFC的资源切换AFX_MANAGE_STATE(AfxGetStaticModuleState()
转载自:http://blog.chinaunix.net/uid-20532101-id-1931929.html 以前写MFC的DLL的时候,总会在自动生成的代码框架里看到提示,需要在每一个输出的 ...
- R与数据分析旧笔记(六)多元线性分析 下
逐步回归 向前引入法:从一元回归开始,逐步加快变量,使指标值达到最优为止 向后剔除法:从全变量回归方程开始,逐步删去某个变量,使指标值达到最优为止 逐步筛选法:综合上述两种方法 多元线性回归的核心问题 ...
- hdu 1524 A Chess Game 博弈
题目链接 给出一个有向无环图, 上面放有一些棋子, 两个人轮流移动棋子, 当一个人无法移动时, 算输. 求出每一个点的sg值, 异或就可以.出度为0的点sg值为0. #include<bits/ ...
- Java的序列化
1.为啥需要序列化 在Java编程时,一个类被实例化以后,Java虚拟机使得对象处理生存状态,但是当虚拟机关闭后,对象就不复存在了,所以一个对象的生存期不会超过JVM的工作时间,那么如何才能让对象持续 ...
- 应用AXIS开始Web服务之旅(soap web services)——使用三种不同的语言访问创建的Web服务,分别是JAVA、VB、VC
一. 介绍 本文并不是想介绍Web服务的原理.系统架构等,我们假设您已经了解了关于Web服务的一些基本的概念.原理等知识.本文主要是针对那些已经了解Web服务概念,但是还没有亲身体会Web服务所带来令 ...