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

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

在C#中,我们这样定义 IShellFolder 接口:


using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

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);

/// <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(1, out 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(1, out pidlSub, out celtFetched) == 0 && celtFetched == API.S_FALSE)
                {
                    string name = API.GetNameByPIDL(pidlSub);
                    lvFile.Items.Add(name, 0);
                }
            }

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

(C#)Windows Shell 外壳编程系列1 - 基础,浏览一个文件夹的更多相关文章

  1. (C#)Windows Shell 外壳编程系列2 - 解释,从“桌面”开始展开

    (本系列文章由柠檬的(lc_mtt)原创,转载请注明出处,谢谢-) 接上一篇:(C#)Windows Shell 外壳编程系列1 - 基础,浏览一个文件夹 让我们详细解释一下 Shell 编程中最基本 ...

  2. (C#)Windows Shell 外壳编程系列8 - 同后缀名不同图标?

    原文 (C#)Windows Shell 外壳编程系列8 - 同后缀名不同图标? (本系列文章由柠檬的(lc_mtt)原创,转载请注明出处,谢谢-) 接上一节:(C#)Windows Shell 外壳 ...

  3. (C#)Windows Shell 外壳编程系列9 - QueryInfo 扩展提示

    原文 (C#)Windows Shell 外壳编程系列9 - QueryInfo 扩展提示 (本系列文章由柠檬的(lc_mtt)原创,转载请注明出处,谢谢-) 接上一节:(C#)Windows She ...

  4. (C#)Windows Shell 外壳编程系列7 - ContextMenu 注册文件右键菜单

    原文 (C#)Windows Shell 外壳编程系列7 - ContextMenu 注册文件右键菜单 (本系列文章由柠檬的(lc_mtt)原创,转载请注明出处,谢谢-) 接上一节:(C#)Windo ...

  5. (C#)Windows Shell 外壳编程系列6 - 执行

    原文(C#)Windows Shell 外壳编程系列6 - 执行 (本系列文章由柠檬的(lc_mtt)原创,转载请注明出处,谢谢-) 接上一节:(C#)Windows Shell 外壳编程系列5 - ...

  6. (C#)Windows Shell 外壳编程系列5 - 获取图标

    (本系列文章由柠檬的(lc_mtt)原创,转载请注明出处,谢谢-) 接上一节:(C#)Windows Shell 外壳编程系列4 - 上下文菜单(iContextMenu)(二)嵌入菜单和执行命令 有 ...

  7. (C#)Windows Shell 外壳编程系列4 - 上下文菜单(iContextMenu)(二)嵌入菜单和执行命令

    (本系列文章由柠檬的(lc_mtt)原创,转载请注明出处,谢谢-) 接上一节:(C#)Windows Shell 外壳编程系列3 - 上下文菜单(iContextMenu)(一)右键菜单 上一节说到如 ...

  8. (C#)Windows Shell 外壳编程系列3 - 上下文菜单(iContextMenu)(一)右键菜单

    (本系列文章由柠檬的(lc_mtt)原创,转载请注明出处,谢谢-) 接上一节:(C#)Windows Shell 外壳编程系列2 - 解释,从“桌面”开始展开 这里解释上一节中获取名称的方法 GetD ...

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

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

随机推荐

  1. [Codeforces-div.1 55D] Beautiful numbers

    [Codeforces-div.1 55D] Beautiful numbers 试题分析 还是离散化...\(f_{i,j,k}\)表示i位,gcd为j,余数为k. #include<iost ...

  2. 【状压dp】互不侵犯KING

    互不侵犯KING Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 3866  Solved: 2264[Submit][Status][Discuss] ...

  3. Problem C: 零起点学算法82——数组中查找数

    #include<stdio.h> int main(void) { ],m; while(scanf("%d",&n)!=EOF) { ;i<n;i++ ...

  4. ES6的异步操作

    刚开始看书上的这一章的时候,没想到JavaScript还有异步操作,还有这种操作???果不其然,异步操作和java里面的异步操作同样,还是有点难.不过看了两三遍下来,似乎还是明白了一些. 废话不多说, ...

  5. [转] SSH配置之web.xml

    在项目中总会遇到一些关于加载的优先级问题, 首先可以肯定的是,加载顺序与它们在 web.xml 文件中的先后顺序无关.即不会因为 filter 写在 listener 的前面而会先加载 filter. ...

  6. Codeforces Round #127 (Div. 1) B. Guess That Car! 扫描线

    B. Guess That Car! 题目连接: http://codeforces.com/contest/201/problem/B Description A widely known amon ...

  7. CentOS中如何安装7ZIP

    7-zip以高压缩率著称,并且是一款免费开源的压缩软件.在常规的Linux发行版中,无法通过简单的yum命令来安装该软件.那么在CentOS中,如何安装7ZIP呢?有以下3种方法: 第一种,源码编译安 ...

  8. Phpstorm-php在线手册配置

    php在线手册配置 第一个是浏览器软件位置 第二个是php网站写法 第三个是工作路径 C:\Users\hasee\AppData\Local\Google\Chrome\Application\ch ...

  9. iOS- dispatch_semaphore和NSOperationQueue并发

    并发:同一个时间内运行多个任务.又叫共行性,是指处理多个同时性活动的能力. 并行:是指两个并发的任务同时发生. 并发不一定并行,并发不一定要同时发生. 举个例子: 有两个快递分别要送到目的地,有以下两 ...

  10. List 中的最大最小值

    以下实例演示了如何使用 Collections 类的 max() 和 min() 方法来获取List中最大最小值: /* author by w3cschool.cc Main.java */ imp ...