当文件不是文件
获取尚未存在的文件信息
引言
这段代码基于 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 文档提供了更多可以实现的功能。