取得資料夾內容的相關資訊
取得 資料夾識別碼 一節討論了取得命名空間物件指標至專案識別碼清單 (PIDL) 的兩種方法。 一個明顯的問題是:一旦您有 PIDL,就可以用它做什麼? 相關問題是:如果方法都無法運作,或不適合您的應用程式,該怎麼辦? 這兩個問題的解答需要進一步瞭解命名空間的實作方式。 金鑰是 IShellFolder 介面。
本檔稍早,命名空間資料夾稱為 物件。 雖然在這一點上,這個詞在鬆散的意義上被使用,但實際上在嚴格的意義上也是真的。 每個命名空間資料夾都會以元件物件模型 (COM) 物件表示。 每個資料夾物件都會公開許多介面,這些介面可用於各種不同的工作。 某些選擇性的介面可能不會由所有資料夾公開。 不過,所有資料夾都必須公開基本介面 IShellFolder 。
使用資料夾物件的第一個步驟是擷取其 IShellFolder 介面的 指標。 除了提供物件其他介面的存取權之外, IShellFolder 也會公開一組處理一些常見工作的方法,本節會討論其中幾個工作。
若要擷取命名空間物件的 IShellFolder 介面指標,您必須先呼叫 SHGetDesktopFolder 。 此函式會傳回命名空間根目錄桌面之 IShellFolder 介面的指標 。 一旦您擁有桌面的 IShellFolder 介面,有各種不同的方式可以繼續進行。
例如,如果您已經有您感興趣的資料夾 PIDL,例如呼叫 SHGetFolderLocation ,您可以呼叫桌面的 IShellFolder::BindToObject 方法來擷取其 IShellFolder 介面。 如果您有檔案系統物件的路徑,您必須先呼叫桌面的 IShellFolder::P arseDisplayName 方法,然後呼叫 IShellFolder::BindToObject 來取得其 PIDL。 如果這兩種方法都不適用,您可以使用其他 IShellFolder 方法來巡覽命名空間。 如需詳細資訊,請參閱 流覽命名空間 。
您通常想要使用資料夾做的第一件事是找出其包含的內容。 您必須先呼叫資料夾的 IShellFolder::EnumObjects 方法。 資料夾會建立標準 OLE 列舉物件,並傳回其 IEnumIDList 介面。 此介面會公開四個標準方法: Clone 、 Next 、 Reset 和 Skip ,可用來列舉資料夾的內容。
列舉資料夾內容的基本程式為:
- 呼叫資料夾 IShellFolder::EnumObjects 方法來擷取列舉物件的 IEnumIDList 介面指標。
- 將未配置的 PIDL 傳遞至 IEnumIDList::Next 。 接下來 會負責配置 PIDL,但應用程式在不再需要時必須解除配置。 當 Next 傳回時 ,PIDL 只會包含物件的專案識別碼和終止 的 Null 字元。 換句話說,它是相對於資料夾的單一層級 PIDL,而不是完整 PIDL。
- 重複步驟 2,直到 Next 傳回S_FALSE,以指出所有專案都已列舉。
- 呼叫 IEnumIDList::Release 以釋放列舉物件。
注意
請務必追蹤您使用的是完整或相對 PIDL。 某些函式和方法會接受其中一種,但其他函式只會接受其中一個或另一個函式。
如果您需要重複列舉資料夾,其餘三 個 IEnumIDList 方法( Reset 、 Skip 和 Clone )會很有用。 它們可讓您重設列舉、略過一或多個物件,並建立列舉物件的複本來保留其狀態。
列舉資料夾所包含的所有 PIDL 之後,您就可以找出它們所代表的物件類型。 IShellFolder 介面提供一些實用的方法,其中兩個會在這裡討論。 稍後會討論其他 IShellFolder 方法和其他 Shell 資料夾介面。
其中一個最有用的屬性是物件的顯示名稱。 若要擷取物件的顯示名稱,請將其 PIDL 傳遞至 IShellFolder::GetDisplayNameOf 。 雖然物件可以位於命名空間中父資料夾下方的任何位置,但其 PIDL 必須相對於資料夾。
IShellFolder::GetDisplayNameOf 會傳回顯示名稱做為 STRRET 結構的一 部分。 因為從 STRRET 結構擷取顯示名稱可能有點棘手,殼層會提供兩個 函式來為您執行作業: StrRetToStr 和 StrRetToBuf。 這兩個函式都會 採用 STRRET 結構,並將顯示名稱傳回為一般字串。 它們只會在字串的配置方式上有所不同。
除了其顯示名稱之外,物件還可以有數個屬性,例如是否為資料夾或是否可以移動。 您可以將物件的 PIDL 傳遞至 IShellFolder::GetAttributesOf ,以擷取物件的屬性。 屬性的完整清單相當大,因此您應該會看到參考以取得詳細資料。 請注意,您傳遞給 GetAttributesOf 的 PIDL 必須是單一層級。 特別是 IShellFolder ::GetAttributesOf 會接受 IEnumIDList::Next 所 傳回的 PIDL。 您可以傳入 PIDL 陣列,而 GetAttributesOf 會傳回陣列中所有物件通用的屬性。
如果您有物件的完整路徑或 PIDL,SHGetFileInfo 會提供簡單的方法來擷取物件的相關資訊,該物件足以供許多用途使用。 SHGetFileInfo 會採用完整的路徑或 PIDL,並傳回物件的各種資訊,包括:
- 物件的顯示名稱
- 物件的屬性
- 物件的圖示控制碼
- 系統映射清單的控制碼
- 包含物件圖示的檔案路徑
您可以呼叫 IShellFolder::GetAttributesOf 來判斷資料夾是否包含任何子資料夾,並檢查是否已設定SFGAO_FOLDER旗標。 如果物件是資料夾,您可以系結至該資料夾,以提供其 IShellFolder 介面的指標。
若要系結至子資料夾,請呼叫父資料夾的 IShellFolder::BindToObject 方法。 這個方法會採用子資料夾的 PIDL,並傳回其 IShellFolder 介面的指標。 擁有此指標之後,您可以使用 IShellFolder 方法來列舉子資料夾內容、判斷其屬性等等。
如果您有物件的 PIDL,您可能需要其父資料夾所公開其中一個介面的控制碼。 例如,如果您想要使用 IShellFolder::GetDisplayNameOf 來判斷與 PIDL 相關聯的顯示名稱,您必須先擷取 物件的父代 IShellFolder 介面。 使用上一節所討論的技術,可以執行這項操作。 不過,更簡單的方法就是使用 Shell 函 式 SHBindToParent 。 此函式會取得物件的完整 PIDL,並在父資料夾上傳回指定的介面指標。 或者,它也會傳回專案的單一層級 PIDL,以用於 IShellFolder::GetAttributesOf 等 方法。
下列範例主控台應用程式會擷取 System 特殊資料夾的 PIDL,並傳回其顯示名稱。
#include <shlobj.h>
#include <shlwapi.h>
#include <iostream.h>
#include <objbase.h>
int main()
{
IShellFolder *psfParent = NULL;
LPITEMIDLIST pidlSystem = NULL;
LPCITEMIDLIST pidlRelative = NULL;
STRRET strDispName;
TCHAR szDisplayName[MAX_PATH];
HRESULT hr;
hr = SHGetFolderLocation(NULL, CSIDL_SYSTEM, NULL, NULL, &pidlSystem);
hr = SHBindToParent(pidlSystem, IID_IShellFolder, (void **) &psfParent, &pidlRelative);
if(SUCCEEDED(hr))
{
hr = psfParent->GetDisplayNameOf(pidlRelative, SHGDN_NORMAL, &strDispName);
hr = StrRetToBuf(&strDispName, pidlSystem, szDisplayName, sizeof(szDisplayName));
cout << "SHGDN_NORMAL - " <<szDisplayName << '\n';
}
psfParent->Release();
CoTaskMemFree(pidlSystem);
return 0;
}
應用程式會先使用 SHGetFolderLocation 來擷取 System 資料夾的 PIDL。 然後它會呼叫 SHBindToParent ,它會傳回父資料夾 IShellFolder 介面的指標,以及相對於其父資料夾的 PIDL。 然後,它會使用父資料夾的 IShellFolder::GetDisplayNameOf 方法來擷取 System 資料夾的顯示名稱。 因為 GetDisplayNameOf 會傳 回 STRRET 結構, 因此 StrRetToBuf 會用來將顯示名稱轉換成一般字串。 顯示顯示名稱之後,會釋放介面指標,並釋放系統 PIDL。 請注意,您不得釋放 SHBindToParent 所 傳回的相對 PIDL。