提取快捷方式的圖標資源問題


問題點:獲取桌面上的快捷方式並提取出圖標資源。

問題點分析: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 。   

   


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM