翻譯自MSDN 2005 -> Win32 和 COM 開發(fā) -> User Interface -> Windows User Experience -> Windows Shell -> Shell Programmer's Guide -> Shell Basics -> Shell Basics: Programming the Shell -> Getting a Folder's ID
在使用Shell對象前,需要有一種標識它的方法,,也就是要獲取其PIDL,,或者對于文件系統(tǒng)對象,獲取其路徑,。本文介紹兩種較簡單的獲取對象ID的方法,。
還有一種更強大的適合任何文件夾的方法,就是使用IShellFolder接口,,詳情見Getting Information About the Contents of a Folder,。
SHBrowseForFolder對話框
要讓用戶可以瀏覽名字空間然后選擇一個文件夾,可以簡單地調(diào)用SHBrowseForFolder。調(diào)用這個函數(shù)會顯示一個對話框,,其界面跟通用的打開或者另存為對話框相似,。
用戶選擇某文件夾后,函數(shù)會返回其全限定PIDL和顯示名,。如果選定的文件夾位于文件系統(tǒng)中,,可以用SHGetPathFromIDList把PIDL轉換成文件夾路徑。SHBrowseForFolder也可以指定根文件夾,,以限制用戶可以選取文件夾的范圍,,因為只有指定的根文件夾下層的文件夾才顯示在對話框中。下圖是一個根文件夾設置為Program Files的SHBrowseForFolder對話框,。
本文后面會提供一個關于如何使用SHBrowseForFolder的簡單例子,。
特殊文件夾和CSIDL
系統(tǒng)中一些常用的文件夾經(jīng)過了特殊設計。這些文件夾具有良好定義的用途,,并且其中大部分在所有系統(tǒng)中都存在,。即使有些文件夾當前不存在,其名字和位置還是定義了的,,可以在未來增加,。這些特殊文件夾包括所有的系統(tǒng)標準虛擬文件夾,像打印機,、我的文檔、網(wǎng)上鄰居等,。當然也包括一些標準的文件系統(tǒng)文件夾,,如程序(Program Files)和系統(tǒng)(System)文件夾。
雖然這些文件夾是系統(tǒng)的標準組件,,但它們的名稱和在名字空間中的位置卻可能不同,。比如說,系統(tǒng)文件夾在某些系統(tǒng)上是C:\Winnt\System32,,在另一些系統(tǒng)上卻是C:\Windows\System32,。過去是用環(huán)境變量來確定特殊文件夾的名字和位置的,現(xiàn)在Shell提供了更健壯和靈活的方法來標識這些特殊文件夾,,即CSIDL?,F(xiàn)在應該使用CSIDL了,而不是環(huán)境變量,。
CSIDL提供了標識和定位特殊文件夾的統(tǒng)一方法,。與環(huán)境變量不同的是,CSIDL不僅可以用于文件系統(tǒng)文件夾,,還可以用于虛擬文件夾,。每個特殊文件夾都分配了一個唯一的CSIDL,比如說,分配給程序文件夾的是CSIDL_PROGRAM_FILES,,分配給網(wǎng)上鄰居的是CSIDL_NETWORK,。
CSIDL與一些Shell函數(shù)結合使用可以獲取特殊文件夾的PIDL,或者其路徑,。如果請求的特殊文件夾在系統(tǒng)中還不存在,,可以結合CSIDL_FLAG_CREATE標志來創(chuàng)建它。CSIDL可以傳給下列函數(shù):
- SHGetFolderLocation 獲取某個特殊文件夾的PIDL
- SHGetFolderPath 獲取某文件系統(tǒng)特殊文件夾的路徑
這兩個函數(shù)在5.0版的Shell中引入,,取代了原來的SHGetSpecialFolderLocation和SHGetSpecialFolderPath函數(shù),。要在5.0版以前的Shell中使用這兩個函數(shù),需要包含可重新發(fā)布的DLL: ShFolder.dll,。
使用CSIDL和SHBrowseForFolder的簡單例子
下面的示例函數(shù)PidlBrowse展示了如何獲取Shell分配器IMalloc接口,,如何使用CSIDL獲取文件夾的PIDL,如何用SHBrowseForFolder讓用戶選擇一個文件夾,,函數(shù)返回選定文件夾的PIDL和顯示名,。
LPITEMIDLIST PidlBrowse(HWND hwnd, int nCSIDL, LPSTR pszDisplayName) { LPITEMIDLIST pidlRoot = NULL; LPITEMIDLIST pidlSelected = NULL; BROWSEINFO bi = {0}; LPMALLOC pMalloc = NULL;
SHGetMalloc(&pMalloc);
if(nCSIDL) { SHGetFolderLocation(hwnd, nCSIDL, NULL, NULL, &pidlRoot); }
else { pidlRoot = NULL; }
bi.hwndOwner = hwnd; bi.pidlRoot = pidlRoot; bi.pszDisplayName = pszDisplayName; bi.lpszTitle = "Choose a folder"; bi.ulFlags = 0; bi.lpfn = NULL; bi.lParam = 0;
pidlSelected = SHBrowseForFolder(&bi);
if(pidlRoot) { pMalloc->Free(pidlRoot); } pMalloc->Release(); return pidlSelected; } |
調(diào)用者傳入一個窗口句柄,這是SHBrowseForFolder需要的,;nCSIDL參數(shù)是可選的,,它用于指定根文件夾,只有層次結構中根文件夾以下的文件夾才會顯示,。本文前面的那幅圖片就是以CSIDL_PROGRAM_FILES作為nCSIDL參數(shù)值調(diào)用函數(shù)時產(chǎn)生的,。調(diào)用者還需要傳入由pszDisplayName參數(shù)指定的字符串緩沖區(qū),用于在函數(shù)返回時保存選定文件夾的顯示名,。
PidlBrowse首先調(diào)用SHGetMalloc來獲取Shell分配器接口指針,。雖然PidlBrowse本身沒有分配PIDL,但隨后需要用IMalloc接口來釋放(別處分配的)PIDL,。如果調(diào)用者用CSIDL指定了某根文件夾,,PidlBrowse會調(diào)用SHGetFolderLocation獲取文件夾的PIDL。然后PidlBrowse會為BROWSEINFO結構體各成員指定合適的值,,并調(diào)用SHBrowseForFolder,。
用戶選擇某文件夾后,SHBrowseForFolder會返回其PIDL,。選定文件夾的顯示名在BROWSEINFO結構體的pszDisplayName成員中返回,,然后通過PidlBrowse函數(shù)的pszDisplayName參數(shù)返回給調(diào)用者。最后,,PidlBrowse釋放根PIDL,,釋放IMalloc接口,返回選定文件夾的PIDL給調(diào)用者,。