提取快捷方式的图标资源问题

大兔子大兔子 提交于 2019-11-28 01:48:15

问题点:获取桌面上的快捷方式并提取出图标资源。

问题点分析: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库,转换方便,且可以将图标资源转换为其他格式。

 

参考:

1、https://docs.microsoft.com/en-us/windows/win32/api/shlobj_core/nf-shlobj_core-shgetspecialfolderpatha

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

6、https://stackoverflow.com/questions/16330403/get-hbitmaps-for-all-sizes-and-depths-of-a-file-type-icon-c

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 。   

   

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!