65.9K
CodeProject 正在变化。 阅读更多。
Home

当文件不是文件

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.77/5 (12投票s)

2016年11月14日

CPOL

2分钟阅读

viewsIcon

17334

downloadIcon

268

获取尚未存在的文件信息

引言

这段代码基于 MSDN 上一篇出色的文章,创建简单的 PIDL:对于你足够关心发送非常假的文件的那些时候[^],我将它的思想转换成了 C#。它描述了如何欺骗 Windows shell,使其相信某个文件存在,而实际上它并不存在。这对于发现 shell 将如何处理该文件很有用 - 它将显示什么图标?有哪些细节可用?

背景

我正在研究在写入文件时设置各种文件属性。我想在保存文件之前收集这些属性,所以我研究了获取特定文件类型可用的属性。虽然该系统并不能提供所有这些答案,但这是我在研究过程中走过的路径,我认为它值得一篇单独的文章。

工作原理

当 shell 获取文件信息时,它会在文件系统中查找它,接收一个 WIN32_FIND_DATA 结构,其中包含有关文件的基本详细信息。我们在这里所做的是将一个 IBindCtx 附加到 shell,告诉它不要费心查找这个特定的文件,而是要求我们的组件提供 WIN32_FIND_DATA。但是,我们传递给 shell 的结构不是真实的 - 我们只是凭空捏造的。然而,shell 仍然相信我们,并像它是一个真实文件一样使用我们伪造的数据。

在底层,这由我们的 IFileSystemBindData 实现处理,它会根据请求向 shell 提供 WIN32_FIND_DATA。一旦我们向 shell 提供了这些信息,我们就会要求它为我们的假文件生成一个 PIDL,这是一系列字节,用于将该项目标识给 shell。从这个标识符,我们可以向 shell 询问关于它所代表的文件的一切。所有这些都只需几行代码即可完成。

    void CreateBindCtx(out IBindCtx pbc) {
        System.Runtime.InteropServices.ComTypes.BIND_OPTS bo = 
                    new System.Runtime.InteropServices.ComTypes.BIND_OPTS() {
            cbStruct = Marshal.SizeOf(typeof(System.Runtime.InteropServices.ComTypes.BIND_OPTS)),
            dwTickCountDeadline = 0,
            grfFlags = 0,
            grfMode = STGM_CREATE
        };
        try {
            CreateBindCtx(0, out pbc);
            pbc.SetBindOptions(ref bo);
            pbc.RegisterObjectParam(STR_FILE_SYS_BIND_DATA, (IFileSystemBindData)this);
        }
        catch {
            pbc = null;
            throw;
        }
    }

    void CreateSimplePidl(string path) {
        IBindCtx pbc;
        uint sfgao;
        CreateBindCtx(out pbc);
        SHParseDisplayName(path, pbc, out _ppidl, 0, out sfgao);
    }

Using the Code

创建 PIDL 后,它可以在许多 shell 函数和对象中使用。在这个例子中,我公开了两种方法 - 一种用于创建 IShellItem 对象,它提供对假文件本身信息的访问,另一种用于创建 IShellFolder 对象,以提供有关包含此假文件的文件夹的信息,以及它将如何显示它。在演示中,我使用这些对象来获取有关文件的基本属性(IShellItem2.GetPropertyStore),以及获取文件的图标(IShellFolder.GetUIObjectOf)。Shell 文档提供了更多可以实现的功能。

© . All rights reserved.