注:本文仅说明流程,具体的分析涉及太多东西
在Win7及以前,解析快捷方式目标程序和参数等信息,可以使用IShellLink。创建对应的COM实例,加载lnk文件,通过GetPath、GetArguments读取。但对于Win10 UWP程序创建的快捷方式,获取不到任何信息。
UWP快捷方式(或磁贴,将开始桌面的磁贴拖入到窗口)的解析,需要使用Vista系统之后提供的IShellItem2::GetProperty,属于Windows Property System的内容(里面东西很多,以后再慢慢了解)。
IShellItem2::GetProperty接口需要两个参数:
REFPROPERTYKEY结构
在propkey.h头文件中预定了大量的结构,包括与快捷方式相关的PKEY_Link开头的结构。PROPVARIANT指针
存储GetProperty的结果,需要使用PropVariantClear来释放动态申请的空间,比如字符串。
大概流程如下:
得到快捷方式或磁铁的PCIDLIST_ABSOLUTE结构,也就是一个ITEMIDLIST结构
对于拖放操作,文件(包括快捷方式)、开始桌面磁贴,这些数据存在于Shell IDList Array格式中,这个结构比较复杂,是多个文件ITEMIDLIST合并后的复合结构。ITEMIDLIST有绝对和相对之分,类似文件的绝对和相对路径。需要通过以下方式转换:
//data是保存Shell IDList Arra结构的字节序列指针 //第一个4字节宽度保存了文件数量count,紧接着4字节是拖放多个文件的父文件夹的ITEMIDLIST在data中的偏移量 //后面count个4字节是各文件的ITEMIDLIST在data中的偏移量,与父文件夹的ITEMIDLIST合并得到PCIDLIST_ABSOLUTE int count = *(const int *)(data); int offset = sizeof(unsigned); int idlist_offset = *(int *)(data + offset); LPCITEMIDLIST parent_id = LPCITEMIDLIST(data + idlist_offset); for (int i = 0; i < count; ++i) { offset += sizeof(unsigned); idlist_offset = *(int *)(data + offset); LPCITEMIDLIST child = LPCITEMIDLIST(data + idlist_offset); LPITEMIDLIST abspidl = ILCombine(parent_id, child); }
对于已经有了快捷方式的绝对路径字符串,IShellLink::GetIDList 也可以获取,不过获取的ITEMIDLIST已经是目标程序。或者使用其他通用的转换方式。
调用SHCreateItemFromIDList创建一个IShellItem2实例,针对不同类型数据使用不同的Property Key。
IShellItem2 *shell_item = NULL; SHCreateItemFromIDList(abspidl, IID_PPV_ARGS(&shell_item)); if (shell_item) { PROPVARIANT var{ 0 }; shell_item->GetProperty(PKEY_AppUserModel_ID, &var); if (var.vt == VT_LPWSTR) { OutputDebugString(var.pwszVal); } PropVariantClear(&var); shell_item->Release(); }
以下是对常见的拖放做了测试,可能需要通过结果区分不同类型(有些文件快捷方式,如VS,也存在AppUserModelID属性):
类型 Property Key 结果 文件 PKEY_ParsingPath 文件绝对路径 PKEY_ParsingName、PKEY_FileName 文件名 PKEY_FileExtension 文件后缀 文件的快捷方式(非UWP) PKEY_Link_TargetParsingPath 目标文件路径 PKEY_Link_Arguments 快捷方式参数 网页的快捷方式 PKEY_Link_TargetParsingPath、PKEY_Link_TargetUrl 网址 UWP快捷方式 PKEY_Link_TargetParsingPath UWP程序的AppUserModelID UWP磁贴 PKEY_AppUserModel_ID、PKEY_ParsingName、PKEY_ParsingPath UWP程序的AppUserModelID 我的电脑、回收站等 PKEY_NamespaceCLSID CLSID(GUID)指针,可以使用StringFromCLSID转换到字符串