問題點:獲取桌面上的快捷方式並提取出圖標資源。
問題點分析: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 。