问题点:获取桌面上的快捷方式并提取出图标资源。
问题点分析:1、如何获取桌面上的快捷方式?2、如果通过快捷方式路径提取到图标资源?
问题一:获取桌面上的快捷方式:
Windows桌面上的文件保存在两个文件夹下,分别是:公共桌面文件夹和用户桌面文件夹。一般对于的系统路径是为系统盘下,例如:C:\Users\smart\Desktop(用户)和C:\Users\Public\Desktop(公共)。然后对这两个文件夹下的文件遍历筛选出扩展名为lnk的快捷方式.
对于实际编程中,桌面的文件路径是一种系统特殊文件夹路径,不能规定死了。而且如果使用过桌面文件迁移软件对桌面迁移过,桌面文件夹的目录也会发生变化。不过,微软为我们提供了一些API获取特殊文件路径。
1、BOOL SHGetSpecialFolderPath( HWND hwnd, //保留,设置为NULL
LPSTR pszPath, //特殊文件夹路径
int csidl, //需要获取的特殊文件夹类型,如果是虚拟文件夹,获取失败
BOOL fCreate //如果文件夹不存在,是否创建
);
该函数在以后可能不在受支持,可以采用新的API。
2、SHFOLDERAPI SHGetFolderPath( HWND hwnd, //保留,设置为NULL
int csidl, //需要获取的特殊文件夹类型,如果是虚拟文件夹,获取失败
HANDLE hToken, //访问令牌,一般设置为NULL,也可以传入当前登录用户的令牌.
DWORD dwFlags, //指定要返回的路径的标志
LPSTR pszPath //特殊文件夹路径
);
从Windows Vista开始,该函数只是SHGetKnownFolderPath的包装器。
3、HRESULT SHGetKnownFolderPath( REFKNOWNFOLDERID rfid, //获取特殊文件夹路径类型
DWORD dwFlags, //指定特殊检索选项的标志,可以为0
HANDLE hToken, //访问令牌, 一般为空,如果为空,则该函数请求当前用户的已知文件夹,否则请求特定用户的已知文件夹
PWSTR *ppszPath //特殊文件夹路径 调用进程负责通过CoTaskMemFree调用释放不再需要的资源
);
对该函数封装一个获取系统特殊文件夹路径的类,方便使用。
获取到桌面文件目录后,我们就可以对文件夹下的文件进行枚举,通过文件扩展名筛选出快捷方式的文件。可以使用c++14标准库中的filesystem::path进行枚举,这里主要使用微软提供的API函数:
1、HANDLE FindFirstFile( LPCSTR lpFileName, //查询的文件目录或路径
LPWIN32_FIND_DATAA lpFindFileData //接收有关找到的文件或目录的信息
);
2、BOOL FindNextFile( HANDLE hFindFile, //通过FindFirstFile返回的文件句柄
LPWIN32_FIND_DATAA lpFindFileData //接收有关找到的文件或目录的信息
);
通过这两个函数就可以对指定文件目录下的文件进行查询,获取文件相关信息。FindFirstFileEx函数是FindFirstFile扩展函数,如果需要获取其他文件属性,使用该函数。
问题二:通过快捷方式路径提取图标资源:
当我们获取到快捷方式的路径后,还需要进一步处理才能提取到图标资源。通过快捷方式提取信息需要用到windows提供的COM接口:IShellLink。是由COM接口之前,都需要初始化COM。然后创建IShellLink的接口实例,其中通过GetIconLocation接口函数获取到制定快捷方式的图标路径,但是如果该快捷方式图标资源不是.ico,则获取的图标路径为空。我们可以通过右键快捷方式属性查看到图标资源是否使用的是.ico文件.
但很多快捷方式并不是直接使用.ico资源文件,而是.exe中编译时编译成二进制的icon资源。
对于这种快捷方式指向的资源路径为可执行路径时,可以通过其他方式从执行文件或dll文件中提取图标句柄,将图标句柄转换为图标资源。IShellLink::GetPath可以获取到快捷方式的目标文件路径,即可执行路径(并不一定是是.exe文件)。微软为我们提供了一些API获取图标资源句柄:
1、HICON ExtractIconA( HINSTANCE hInst, //调用该函数的实例句柄 一般为NULL
LPCSTR pszExeFileName, //可执行文件,DLL或图标文件的名称
UINT nIconIndex //要检索的图标的从零开始的索引 0:表示从第一个开始,-1:获取图标总数
);
该函数和ExtractIconEx(提取大图标和小图标)一般提取16*16 和32*32像素的图标.使用完图标资源后,调用DestoryIcon是否资源。
如果需要提取一些像素更大的图标资源,上面的API就无法实现了,需要使用其他API获取。
1、DWORD_PTR SHGetFileInfoW( LPCWSTR pszPath, //提取图标资源的文件路径
DWORD dwFileAttributes, //文件属性标志位
SHFILEINFOW *psfi, //接收文件信息
UINT cbFileInfo, //指向SHFILEINFO结构体大小
UINT uFlags //要检索的文件信息的标志
);
在调用SHGetFileInfo之前, 必须初始化组件对象模型(COM).
2、SHSTDAPI SHGetImageList( int iImageList,
REFIID riid,
void **ppvObj
);
如果提取48*48或256*256像素大小的图标,需要使用该函数获取。Windows系统标准图标大小分别为:小(16 *16) 大(32 * 32)超大(48 *48)和巨型(256 *256).所以通过API获取的一般是系统标准大小的图标,但是有些应用存在其他大小的不同,例如:64 * 64 128 *128等像素大小的图标,可以同过PE格式提取等方式,具体方式,目前还为找到。
关于如何将HICON图标句柄资源保存到本地,可以使用GDI接口将HICON保存为bmp格式的图片文件,但是bmp占用空间大,压缩比较差,使用GDI比较麻烦,如果感兴趣的同学,可以使用微软封装的gdiplus库,转换方便,且可以将图标资源转换为其他格式。
参考:
2、https://www.cnblogs.com/aspring/archive/2005/03/12/117337.html;
3、https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-findfirstfilea;
4、https://docs.microsoft.com/en-us/windows/win32/api/shobjidl_core/nn-shobjidl_core-ishelllinka;
5、https://docs.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-extracticona;
7、https://docs.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shgetfileinfow;
8、https://docs.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shgetimagelist 。