【发布时间】:2019-10-13 09:26:21
【问题描述】:
我注意到,如果快捷方式的目标指向特殊文件夹(如“我的电脑”或控制面板小程序),IShellLinkW::GetPath 方法会返回一个空字符串。
示例代码
' CLSID_ShellLink from ShlGuid.h
Dim cShellLink As New CShellLink()
' https://msdn.microsoft.com/en-us/library/windows/desktop/ms687223%28v=vs.85%29.aspx
Dim persistFile As IPersistFile = DirectCast(cShellLink, IPersistFile)
persistFile.Load(lnkFilePath, 0)
Dim target As New StringBuilder(260)
' https://docs.microsoft.com/en-us/windows/desktop/api/shobjidl_core/nn-shobjidl_core-ishelllinkw
Dim lnkW As IShellLinkW = DirectCast(cShellLink, IShellLinkW)
lnkW.GetPath(target, target.Capacity, Nothing, IShellLinkGetPathFlags.RawPath)
(抱歉,这里分享的 P/Invokes 太多,但您可以在 this 存储库中找到它们。)
上面的代码可以正确检索任何指向文件或目录的 .lnk 文件的目标。它无法检索指向特殊项目/虚拟文件夹的目标。
我的问题是:
这是设计使然吗?如果没有,我错过了什么或做错了什么? (也许我的定义是错误的?)。为了检索特殊目标,我必须做什么?请注意,我想检索目标以将其显示在 PropertyGrid 中,并创建一个具有特殊目标克隆的新目标。
请注意,我开发此代码所使用的编程语言无关紧要,因为我首先要求的是方向,而且我接受任何用 C# 编写的解决方案。
【问题讨论】:
-
路径仅适用于文件系统对象。您必须熟悉 PIDL,IShellLinkW::GetIDList() 会返回它们。不推荐。
-
见SHGetPathFromIDList,SHGetFileInfo(注意它接受
LPCWSTR,但也接受pidl),SHGetSpecialFolderLocation。IShellLinkW接口还提供了一个可能派上用场的.Resolve()方法。在同一个shell对象上使用,然后得到GetIDList()返回的out地址 -
感谢 cmets,但如果我调用 IShellLinkW.GetIDList,然后获得(有效,非零)PIDL 的 SHGetPathFromIDListW,我总是得到一个空字符串,并且函数返回 false 但最后一个 win32 错误代码为零(SetLastError 设置为 true)。为什么?。我尝试了各种签名,还有来自 pinvoke.net 网站的签名。
-
另外,我不明白使用 SHGetFileInfo 有什么意义,因为我似乎只能获取文件名 (SHGFI_DISPLAYNAME) 和文件类型描述 (SHGFI_TYPENAME)。顺便说一句,这个函数接受我用 IShellLinkW.GetIDList 获得的 PIDL,但正如我提到的,我似乎无法用这个函数检索“原始”lnk 目标字符串......只是文件名或文件类型的描述。
-
在十六进制编辑器中分析这些 lnk 文件,它们具有目标的 CLSID(例如 ::{F02C1A0D-BE21-4350-88B0-7367FC96EF3C} 指向我的电脑),并且如果我在创建调用 SetPath 的快捷方式时使用该 CLSID(没有弄乱 SetIDList 和任何琐碎的事情),它会按预期工作。这个发现似乎使问题更容易解决,因为我想我可以从 PIDL 获得 CLSID。 PIDL 是一个我根本没有读过的概念,所以如果我说的是愚蠢的话,请原谅。但我仍然会通过可用的 win32 函数进行调查以获取 CLSID 值...