zoukankan      html  css  js  c++  java
  • 提取快捷方式的图标资源问题

    一、背景

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

    二、问题点分析

    1. 如何获取桌面上的快捷方式?
    2. 如果通过快捷方式路径提取到图标资源?

    三、获取桌面上的快捷方式

      Windows桌面上的文件保存在两个文件夹下,分别是:公共桌面文件夹和用户桌面文件夹。一般对于的系统路径是为系统盘下,例如:C:UserssmartDesktop(用户)和C:UsersPublicDesktop(公共)。然后对这两个文件夹下的文件遍历筛选出扩展名为lnk的快捷方式.

      对于实际编程中,桌面的文件路径是一种系统特殊文件夹路径,不能规定死了。而且如果使用过桌面文件迁移软件对桌面迁移过,桌面文件夹的目录也会发生变化。不过,微软为我们提供了一些API获取特殊文件路径

    1 BOOL SHGetSpecialFolderPath( HWND hwnd,  //保留,设置为NULL
    2 
    3                    LPSTR pszPath, //特殊文件夹路径
    4 
    5                       int csidl,              //需要获取的特殊文件夹类型,如果是虚拟文件夹,获取失败
    6 
    7                    BOOL fCreate    //如果文件夹不存在,是否创建
    8 
    9                    );

      该函数在以后可能不在受支持,可以采用新的API。

     1 SHFOLDERAPI SHGetFolderPath( HWND hwnd, //保留,设置为NULL
     2 
     3                        int csidl,          //需要获取的特殊文件夹类型,如果是虚拟文件夹,获取失败
     4 
     5                      HANDLE hToken, //访问令牌,一般设置为NULL,也可以传入当前登录用户的令牌.
     6 
     7                                                                        DWORD dwFlags, //指定要返回的路径的标志
     8 
     9                                                                         LPSTR pszPath //特殊文件夹路径
    10 
    11                      );

      从Windows Vista开始,该函数只是SHGetKnownFolderPath的包装器。

    1 HRESULT SHGetKnownFolderPath( REFKNOWNFOLDERID rfid,  //获取特殊文件夹路径类型
    2 
    3                     DWORD dwFlags, //指定特殊检索选项的标志,可以为0
    4 
    5                     HANDLE hToken, //访问令牌, 一般为空,如果为空,则该函数请求当前用户的已知文件夹,否则请求特定用户的已知文件夹
    6 
    7                     PWSTR *ppszPath //特殊文件夹路径 调用进程负责通过CoTaskMemFree调用释放不再需要的资源
    8 
    9                     );

      对该函数封装一个获取系统特殊文件夹路径的类,方便使用。

      获取到桌面文件目录后,我们就可以对文件夹下的文件进行枚举,通过文件扩展名筛选出快捷方式的文件。可以使用c++14标准库中的filesystem::path进行枚举,这里主要使用微软提供的API函数:

     1 HANDLE FindFirstFile( LPCSTR lpFileName, //查询的文件目录或路径
     2 
     3               LPWIN32_FIND_DATAA lpFindFileData //接收有关找到的文件或目录的信息
     4 
     5                );
     6 
     7 BOOL FindNextFile( HANDLE hFindFile,  //通过FindFirstFile返回的文件句柄
     8 
     9              LPWIN32_FIND_DATAA lpFindFileData //接收有关找到的文件或目录的信息
    10 
    11               );

      通过这两个函数就可以对指定文件目录下的文件进行查询,获取文件相关信息。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
    2 
    3                 LPCSTR pszExeFileName, //可执行文件,DLL或图标文件的名称
    4 
    5                                                      UINT nIconIndex               //要检索的图标的从零开始的索引 0:表示从第一个开始,-1:获取图标总数
    6 
    7               );

      该函数和ExtractIconEx(提取大图标和小图标)一般提取16*16 和32*32像素的图标.使用完图标资源后,调用DestoryIcon是否资源。

      如果需要提取一些像素更大的图标资源,上面的API就无法实现了,需要使用其他API获取。

     1 DWORD_PTR SHGetFileInfoW( LPCWSTR pszPath,          //提取图标资源的文件路径
     2 
     3                   DWORD dwFileAttributes, //文件属性标志位
     4 
     5                   SHFILEINFOW *psfi,         //接收文件信息
     6 
     7                   UINT cbFileInfo,               //指向SHFILEINFO结构体大小
     8 
     9                   UINT uFlags                    //要检索的文件信息的标志
    10 
    11                   );

      在调用SHGetFileInfo之前, 必须初始化组件对象模型(COM)

    1 SHSTDAPI SHGetImageList( int iImageList,
    2 
    3                  REFIID riid,
    4 
    5                     void **ppvObj
    6 
    7                 );

      如果提取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 。   

       

  • 相关阅读:
    oracel 备份导出报错 EXP-00091: Exporting questionable statistics
    将多张图片快速制作成一个PDF文件
    自连接表:M可能无下级,可能有下级
    STL迭代器失效总结
    DNS劫持和DNS污染的区别
    snprintf函数用法(转)
    sql查询面试题
    linux获取主机信息
    linux网络通信中的地址形式转换
    printf函数编程小技巧
  • 原文地址:https://www.cnblogs.com/smartNeo/p/11386109.html
Copyright © 2011-2022 走看看