(C#)Windows Shell 外壳编程系列1 - 基础,浏览一个文件夹
1 - 基础,浏览一个文件夹
我们知道,在win32中是以外壳名字空间的形式来组织文件系统的,在外壳名字空间里的每一个对象(注)都实现了一个IShellFolder的接口,通过这个接口我们可以直接查询或间接得到其他相关的接口。
(注:这里的对象指的是外壳名字空间中的一个节点,对象有可能是一个文件夹,有可能是一个文件,也有可能是一个虚拟文件夹,例如:我的电脑,网上邻居,控制面板等)
在C#中,我们这样定义 IShellFolder 接口:
Windows Shell 外壳编程系列1 - 基础,浏览一个文件夹 - 柠檬的 - 博客园_files/ExpandedBlockStart.gif)
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;Windows Shell 外壳编程系列1 - 基础,浏览一个文件夹 - 柠檬的 - 博客园_files/None.gif)
namespace WinShell
{
[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("000214E6-0000-0000-C000-000000000046")]
public interface IShellFolder
{
}
}当然,这个接口还没有列出细节函数。我们要做的仅仅是从最基础开始。
首先我们必须了解,在外壳编程中,要使用 PIDL 路径代替普通路径(如果对 PIDL 不熟悉,请看Windows外壳名字空间的浏览)。
“桌面”是最顶级的文件夹,外壳名字空间中其他各项都可以用从“桌面”开始的 PIDL 加以表示。
如何获取“桌面”的 PIDL 和其 IShellFolder 接口呢,可以通过 API SHGetDesktopFolder:
[DllImport("shell32.dll")]
public static extern Int32 SHGetDesktopFolder(out IntPtr ppshf);Windows Shell 外壳编程系列1 - 基础,浏览一个文件夹 - 柠檬的 - 博客园_files/None.gif)
/// <summary>
/// 获得桌面 Shell
/// </summary>
public static IShellFolder GetDesktopFolder(out IntPtr ppshf)
{
SHGetDesktopFolder(out ppshf);
Object obj = Marshal.GetObjectForIUnknown(ppshf);
return (IShellFolder)obj;
}
//获得桌面 PIDL
IntPtr desktopPtr;
IShellFolder desktop = API.GetDesktopFolder(out desktopPtr);好的,我们取得“桌面”的 IShellFolder 接口,就已经成功了一半。现在我需要通过“桌面”,来获取“C:\”这个路径的 PIDL 和 IShellFolder 接口,可以通过 IShellFolder 的 ParseDisplayName 和 BindToObject 函数来实现:
void ParseDisplayName(
IntPtr hwnd,
IntPtr pbc,
[MarshalAs(UnmanagedType.LPWStr)] string pszDisplayName,
out uint pchEaten,
out IntPtr ppidl,
ref uint pdwAttributes);Windows Shell 外壳编程系列1 - 基础,浏览一个文件夹 - 柠檬的 - 博客园_files/None.gif)
void BindToObject(
IntPtr pidl,
IntPtr pbc,
[In()] ref Guid riid,
out IShellFolder ppv);
//获取 C 盘的 PIDL
string FolderPath = @"C:\";
IntPtr Pidl = IntPtr.Zero;
IShellFolder Root;
uint i, j = 0;
desktop.ParseDisplayName(Handle, IntPtr.Zero, FolderPath, out i, out Pidl, ref j);
desktop.BindToObject(Pidl, IntPtr.Zero, ref Guids.IID_IShellFolder, out Root);前提是你应该保证路径存在,因为我没有做任何出错控制。这样我们就获得了一个 Root,它表示C盘。通过这个Root,我们可以用 EnumObjects 来循环获取其子项(子文件和子文件夹):
[PreserveSig]
int EnumObjects(IntPtr hWnd, SHCONTF flags, out IntPtr enumIDList);
//循环查找 C 盘下面的文件/文件夹的 PIDL
IEnumIDList fileEnum = null;
IEnumIDList folderEnum = null;
IntPtr fileEnumPtr = IntPtr.Zero;
IntPtr folderEnumPtr = IntPtr.Zero;
IntPtr pidlSub;
int celtFetched;Windows Shell 外壳编程系列1 - 基础,浏览一个文件夹 - 柠檬的 - 博客园_files/None.gif)
//获取子文件夹
if (Root.EnumObjects(this.Handle, SHCONTF.FOLDERS | SHCONTF.INCLUDEHIDDEN, out fileEnumPtr) == API.S_OK)
{
fileEnum = (IEnumIDList)Marshal.GetObjectForIUnknown(fileEnumPtr);
while (fileEnum.Next(1, out pidlSub, out celtFetched) == 0 && celtFetched == API.S_FALSE)
{
//获取显示名称
string name = API.GetNameByPIDL(pidlSub);
lvFile.Items.Add(name, 1);
}
}Windows Shell 外壳编程系列1 - 基础,浏览一个文件夹 - 柠檬的 - 博客园_files/None.gif)
//获取子文件
if (Root.EnumObjects(this.Handle, SHCONTF.NONFOLDERS | SHCONTF.INCLUDEHIDDEN, out folderEnumPtr) == API.S_OK)
{
folderEnum = (IEnumIDList)Marshal.GetObjectForIUnknown(folderEnumPtr);
while (folderEnum.Next(1, out pidlSub, out celtFetched) == 0 && celtFetched == API.S_FALSE)
{
string name = API.GetNameByPIDL(pidlSub);
lvFile.Items.Add(name, 0);
}
}事实上,代码到此结束。然而我发现有太多的结构体和枚举没有介绍(以后会有更多),有兴趣的朋友可以等待我下一节介绍
(C#)Windows Shell 外壳编程系列1 - 基础,浏览一个文件夹的更多相关文章
- (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 外壳编程系列7 - ContextMenu 注册文件右键菜单
原文 (C#)Windows Shell 外壳编程系列7 - ContextMenu 注册文件右键菜单 (本系列文章由柠檬的(lc_mtt)原创,转载请注明出处,谢谢-) 接上一节:(C#)Windo ...
- (C#)Windows Shell 外壳编程系列6 - 执行
原文(C#)Windows Shell 外壳编程系列6 - 执行 (本系列文章由柠檬的(lc_mtt)原创,转载请注明出处,谢谢-) 接上一节:(C#)Windows Shell 外壳编程系列5 - ...
- (C#)Windows Shell 外壳编程系列5 - 获取图标
(本系列文章由柠檬的(lc_mtt)原创,转载请注明出处,谢谢-) 接上一节:(C#)Windows Shell 外壳编程系列4 - 上下文菜单(iContextMenu)(二)嵌入菜单和执行命令 有 ...
- (C#)Windows Shell 外壳编程系列4 - 上下文菜单(iContextMenu)(二)嵌入菜单和执行命令
(本系列文章由柠檬的(lc_mtt)原创,转载请注明出处,谢谢-) 接上一节:(C#)Windows Shell 外壳编程系列3 - 上下文菜单(iContextMenu)(一)右键菜单 上一节说到如 ...
- (C#)Windows Shell 外壳编程系列3 - 上下文菜单(iContextMenu)(一)右键菜单
(本系列文章由柠檬的(lc_mtt)原创,转载请注明出处,谢谢-) 接上一节:(C#)Windows Shell 外壳编程系列2 - 解释,从“桌面”开始展开 这里解释上一节中获取名称的方法 GetD ...
- (C#)Windows Shell 编程系列1 - 基础,浏览一个文件夹
原文 (C#)Windows Shell 编程系列1 - 基础,浏览一个文件夹 (本系列文章由柠檬的(lc_mtt)原创,转载请注明出处,谢谢-) Windows Shell 编程,即 Windows ...
随机推荐
- BZOJ 1305 [CQOI2009]dance跳舞(二分+网络流)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1305 [题目大意] 一次舞会有n个男孩和n个女孩. 每首曲子开始时,所有男孩和女孩恰好 ...
- 【计算几何】【圆反演】计蒜客17314 2017 ACM-ICPC 亚洲区(南宁赛区)网络赛 G. Finding the Radius for an Inserted Circle
题意:给你三个半径相同的圆,它们切在一起,然后让你往缝里一个一个地塞圆,问你塞到第k个的半径是多少. 就把上面那两个圆的切点当成反演中心,然后会反演成这个样子,两个平行直线和一个圆. 然后就是往那个圆 ...
- bash中的快捷键使用
移动 ctrl + xx 光标在行首.位移动 ctrl + 方向左键 光标移动到前一个单词的开始 ctrl + 方向右键 光标移动到后一个单词的开始 ...
- 小程序把图片转换成base64
1.首先需要到upng.js,然后upng.js需要pako.js,先一并下载了 2.然后就可以直接用了,具体代码如下: <!--pages/base/base.wxml--> <c ...
- 每天5分钟玩转Docker
总结的这个八爪鱼图,不懂的时候随时翻翻书.....
- git log --oneline --graph的读法
星号表明这个提交所在的分支: 最左边的直线表示当前分支的历史状态,从图看,当前分支HEAD是master分支 :提交历史是:8cfbb25<--d486463<--a88c595<- ...
- ylbtech-LanguageSamples-OperatorOverLoading(运算符重载)
ylbtech-Microsoft-CSharpSamples:ylbtech-LanguageSamples-OperatorOverLoading(运算符重载) 1.A,示例(Sample) 返回 ...
- 在Ubuntu Server上源码安装OpenERP 8.0,并配置wsgi和nginx运行环境
原文: How to install OpenERP 8.0 Alpha on a fresh Debian / Ubuntu server. OpenERP的安装,可以有多种方式,通过添加源,到 h ...
- TensorFlow------读取二进制文件实例
TensorFlow------读取二进制文件实例: class CifarRead(object): ''' 完成读取二进制文件,写进tfrecords,读取tfrecords :param obj ...
- 线程局部存储(TLS)
线程局部存储(TLS) 2011-10-11 09:59:28| 分类: Win32---API | 标签:tls |举报 |字号 订阅 什么是线程局部存储 众所周知,线程是执行的单元,同 ...