今天教师节,唱个反调吧。我上高中时与班主任不对眼,她看不上我我也看不上她。当时很多人说:等十年后你就知道老师这么着是为你好了。但十年后的今天,我还是看不上她。也许又有人让我再等十年?好吧,我可以等,不过请不要低估未成年人的情商。卡扎菲都撒丫子跑路了,更何况你们那保守的教育方式呢。
获取特殊快捷方式的指向路径
在通常的情况下,为了获取一个快捷方式 (.lnk) 指向的路径,可以通过调用 IShellLink 接口的 GetPath 方法来实现。但是,某些特殊的快捷方式是无法取得指向路径的,比如 Office 系列的快捷方式,如下图。

首先你可以看到,普通快捷方式中用于显示路径信息的“目标”一栏已经被禁用掉了。而且,对其调用 IShellLink::GetPath,会得到类似这样的结果:
C:\Windows\Installer\{90120000-0012-0000-0000-0000000FF1CE}\wordicon.exe我的直觉告诉我,问题的真正答案就藏在 IShellLink 之中。不过,那正确的路是哪一条呢?MSDN 的优点是完备,缺点则是过于完备,我已经数次被淹没其中了。故不取之。
那么还是自己分析吧。我打开 Process Monitor,设置过滤器,如下图。

接下来使用快捷方式来启动 Word,可以看到系统的确访问了 wordicon.exe。
继续往下找,找到 WINWORD.EXE 的第一个现身处。
查看其调用堆栈,如下所示。
从堆栈中,可以得到两个有用的信息:
- WINWORD.EXE 真实路径的获取与 CShellLink::_Resolve 有关。而 IShellLink 之中,也存在一个名为 Resolve 的接口。
- WINWORD.EXE 真实路径的获取借助了 msi.dll (Microsoft Windows Installer) 的部分函数,而 IShellLink::Resolve 方法的 fFlags 参数恰有一个标志名为 SLR_INVOKE_MSI。
好了,现在已经猜出了那句最重要的代码,可以堆码一试了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | CComPtr<IShellLink> sl; sl.CoCreateInstance(CLSID_ShellLink); // Load the link file... TCHAR sz[MAX_PATH]; WIN32_FIND_DATA wfd; sl->Resolve(NULL, SLR_INVOKE_MSI); // C:\Windows\Installer\{90120000-0012-0000-0000-0000000FF1CE}\wordicon.exe sl->GetPath(sz, MAX_PATH, &wfd, SLGP_RAWPATH); // D:\Program Files\Microsoft Office\Office12\WINWORD.EXE LPITEMIDLIST pidl = NULL; sl->GetIDList(&pidl); SHGetPathFromIDList(pidl, sz); |
一句话(23)
我想借用鲁迅先生《社戏》的一段文字来评价《变形金刚 3》:“于是看小旦唱,看花旦唱,看老生唱,看不知什么角色唱,看一大班人乱打,看两三个人互打,从九点多到十点,从十点到十一点,从十一点到十一点半,从十一点半到十二点。”
一句话(21)
每当我调用 COM 接口的时候,都会暗暗赞叹下 COM 是个精妙的框架设计;每当我实现 COM 接口的时候,都会暗暗吐槽下抄写成员函数的工作是这个框架设计下十分蛋疼的副产品。


