(C#)Windows Shell 编程系列1 - 基础,浏览一个文件夹

简介: 原文 (C#)Windows Shell 编程系列1 - 基础,浏览一个文件夹  (本系列文章由柠檬的(lc_mtt)原创,转载请注明出处,谢谢~)Windows Shell 编程,即 Windows 外壳编程。

原文 (C#)Windows Shell 编程系列1 - 基础,浏览一个文件夹 

(本系列文章由柠檬的(lc_mtt)原创,转载请注明出处,谢谢~)

Windows Shell 编程,即 Windows 外壳编程。我们所看到的资源管理器以及整个桌面,都是一个 Shell。

关于 Windows 外壳的基本概念,我这里不做详细介绍,不了解的朋友,可以看看 姜伟华 的 Windows外壳名字空间的浏览
好,现在让我们从基础学起,早日做出一个强大的资源管理器软件。(偶也是初学者,多多指教)

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

我们知道,在win32中是以外壳名字空间的形式来组织文件系统的,在外壳名字空间里的每一个对象(注)都实现了一个IShellFolder的接口,通过这个接口我们可以直接查询或间接得到其他相关的接口。 (注:这里的对象指的是外壳名字空间中的一个节点,对象有可能是一个文件夹,有可能是一个文件,也有可能是一个虚拟文件夹,例如:我的电脑,网上邻居,控制面板等)
在C#中,我们这样定义 IShellFolder 接口:

 

当然,这个接口还没有列出细节函数。我们要做的仅仅是从最基础开始。
首先我们必须了解,在外壳编程中,要使用 PIDL 路径代替普通路径(如果对 PIDL 不熟悉,请看Windows外壳名字空间的浏览)。
“桌面”是最顶级的文件夹,外壳名字空间中其他各项都可以用从“桌面”开始的 PIDL 加以表示。
如何获取“桌面”的 PIDL 和其 IShellFolder 接口呢,可以通过 API SHGetDesktopFolder:

[DllImport( " shell32.dll " )]          public   static   extern  Int32 SHGetDesktopFolder( out  IntPtr ppshf); /// <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); 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;              // 获取子文件夹              if  (Root.EnumObjects( this .Handle, SHCONTF.FOLDERS  |  SHCONTF.INCLUDEHIDDEN,  out  fileEnumPtr)  ==  API.S_OK)              {                 fileEnum = (IEnumIDList)Marshal.GetObjectForIUnknown(fileEnumPtr);                 while (fileEnum.Next(1out pidlSub, out celtFetched) == 0 && celtFetched == API.S_FALSE)                 {                     //获取显示名称                     string name = API.GetNameByPIDL(pidlSub);                     lvFile.Items.Add(name, 1);                 }             }              // 获取子文件              if  (Root.EnumObjects( this .Handle, SHCONTF.NONFOLDERS  |  SHCONTF.INCLUDEHIDDEN,  out  folderEnumPtr)  ==  API.S_OK)              {                 folderEnum = (IEnumIDList)Marshal.GetObjectForIUnknown(folderEnumPtr);                 while (folderEnum.Next(1out pidlSub, out celtFetched) == 0 && celtFetched == API.S_FALSE)                 {                     string name = API.GetNameByPIDL(pidlSub);                     lvFile.Items.Add(name, 0);                 }             }


事实上,代码到此结束。然而我发现有太多的结构体和枚举没有介绍(以后会有更多),有兴趣的朋友可以自己查 MSDN ,否则就等待我下一节再介绍了。

最后把图和代码贴上,下一节再详细介绍。



源代码:/Files/lemony/WinShell.rar

目录
相关文章
|
7月前
|
XML 前端开发 C#
C#编程实践:解析HTML文档并执行元素匹配
通过上述步骤,可以在C#中有效地解析HTML文档并执行元素匹配。HtmlAgilityPack提供了一个强大而灵活的工具集,可以处理各种HTML解析任务。
340 19
|
C# 开发者
C# 一分钟浅谈:Code Contracts 与契约编程
【10月更文挑战第26天】本文介绍了 C# 中的 Code Contracts,这是一个强大的工具,用于通过契约编程增强代码的健壮性和可维护性。文章从基本概念入手,详细讲解了前置条件、后置条件和对象不变量的使用方法,并通过具体代码示例进行了说明。同时,文章还探讨了常见的问题和易错点,如忘记启用静态检查、过度依赖契约和性能影响,并提供了相应的解决建议。希望读者能通过本文更好地理解和应用 Code Contracts。
388 3
|
8月前
|
监控 算法 C#
C#与Halcon联合编程实现鼠标控制图像缩放、拖动及ROI绘制
C#与Halcon联合编程实现鼠标控制图像缩放、拖动及ROI绘制
1714 0
|
存储 安全 编译器
学懂C#编程:属性(Property)的概念定义及使用详解
通过深入理解和使用C#的属性,可以编写更清晰、简洁和高效的代码,为开发高质量的应用程序奠定基础。
1306 12
|
设计模式 C# 图形学
Unity 游戏引擎 C# 编程:一分钟浅谈
本文介绍了在 Unity 游戏开发中使用 C# 的基础知识和常见问题。从 `MonoBehavior` 类的基础用法,到变量和属性的管理,再到空引用异常、资源管理和性能优化等常见问题的解决方法。文章还探讨了单例模式、事件系统和数据持久化等高级话题,旨在帮助开发者避免常见错误,提升游戏开发效率。
672 4
|
运维 监控 Shell
深入理解Linux系统下的Shell脚本编程
【10月更文挑战第24天】本文将深入浅出地介绍Linux系统中Shell脚本的基础知识和实用技巧,帮助读者从零开始学习编写Shell脚本。通过本文的学习,你将能够掌握Shell脚本的基本语法、变量使用、流程控制以及函数定义等核心概念,并学会如何将这些知识应用于实际问题解决中。文章还将展示几个实用的Shell脚本例子,以加深对知识点的理解和应用。无论你是运维人员还是软件开发者,这篇文章都将为你提供强大的Linux自动化工具。
|
Shell
Shell编程(下)
Shell编程(下)
231 1
|
安全 C# 数据安全/隐私保护
实现C#编程文件夹加锁保护
【10月更文挑战第16天】本文介绍了两种用 C# 实现文件夹保护的方法:一是通过设置文件系统权限,阻止普通用户访问;二是使用加密技术,对文件夹中的文件进行加密,防止未授权访问。提供了示例代码和使用方法,适用于不同安全需求的场景。
733 0
|
C# 区块链 API
【C#】WindowsAPICodePack-Shell使用教程
原文:【C#】WindowsAPICodePack-Shell使用教程 1.首先在项目中添加WindowsAPICodePack的Nuget包。
2293 0
|
7月前
|
存储 安全 Unix
七、Linux Shell 与脚本基础
别再一遍遍地敲重复的命令了,把它们写进Shell脚本,就能一键搞定。脚本本质上就是个存着一堆命令的文本文件,但要让它“活”起来,有几个关键点:文件开头最好用#!/usr/bin/env bash来指定解释器,并用chmod +x给它执行权限。执行时也有讲究:./script.sh是在一个新“房间”(子Shell)里跑,不影响你;而source script.sh是在当前“房间”里跑,适合用来加载环境变量和配置文件。
653 9