(C#)Windows Shell 外壳编程系列总结

http://www.cnblogs.com/lemony/category/88555.html

原文见上面链接中的1-9系列

1、基础,浏览一个文件夹

win32中是以外壳名字空间的形式来组织文件系统的,在外壳名字空间里的每一个对象(注)都实现了一个IShellFolder的接口,通过这个接口我们可以直接查询或间接得到其他相关的接口。

(注:这里的对象指的是外壳名字空间中的一个节点,对象有可能是一个文件夹,有可能是一个文件,也有可能是一个虚拟文件夹,例如:我的电脑,网上邻居,控制面板等)

首先我们必须了解,在外壳编程中,要使用 PIDL 路径代替普通路径(如果对 PIDL 不熟悉,请看Windows外壳名字空间的浏览)。
“桌面”是最顶级的文件夹,外壳名字空间中其他各项都可以用从“桌面”开始的 PIDL 加以表示

如何获取“桌面”的 PIDL 和其 IShellFolder 接口呢,可以通过 API SHGetDesktopFolder:

首先是桌面的Ishellfolder 通过这个我们找我们自己目标路径的PIDL[IshellFolder可以通过 IShellFolder 的 ParseDisplayName 和 BindToObject 函数来实现:]

void Ishellfolder .GetDisplayNameOf( ntPtr pidl, SHGNO uFlags, IntPtr lpName)为ParseDisplayName 的逆函数,两者实现从文件名到pidl和从pidl到文件名的一个抓换

拿到了我们自己目标路径的ishellFolder  就可以通过EnumObjects 获得IEnumIDList进而通过循环获取其子项(子文件和子文件夹)的pidl:

获取到了pidl通过SHGetFileInfo来获取对应的文件或文件夹信息


2 - 解释,从“桌面”开始展开

对1的类似递归的利用,展开所有的文件夹及文件信息

类似“桌面”、“我的文档”这种既是普通文件夹又是特殊对象的绝对路径如何获得,这里就要用到 SHGetSpecialFolderPath API 了


3 - 上下文菜单(iContextMenu)(一)右键菜单

对象的上下文菜单相关的接口是IContextMenu,通过对象的父文件夹的IShellFolder.GetUIObjectOf方法可得到该接口。得到该接口后,可以用IContextMenu.QueryContextMenu方法来生成上下文菜单的菜单项,用IContextMenu.InvokeCommand调用相应的命令。

首先假设我们已经获得某个 IShellFolder 对象的 PIDL 和其上级 IShellFolder 对象:

IntPtr PIDL;
IShellFolder IParent;

然后我们定义一个存放 PIDL 的数组:

IntPtr[] pidls  =   new  IntPtr[ 1 ];
pidls[
0 =  PIDL;

没错,我们的确要用到 PIDL 数组。可以理解,你在资源管理器中选择了多个文件/文件夹,再点击右键,弹出的上下文菜单将有所不同。你可以根据需要,把同一级的多个 PIDL 放到数组里面,实现这个效果。由于我们在例2的树中弹出菜单,所以只存放一个节点的 PIDL。

然后,通过 IParent 的 GetUIObjectOf 方法我们可以得到该节点的一个或多个指定子节点的 IContextMenu 接口:

得到 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;
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值