共用方式為


實作基本資料夾物件介面

實作命名空間延伸的程式類似於任何其他同進程元件物件模型 (COM) 物件的程式。 所有擴充功能都必須支援三個主要介面,以提供 Windows 檔案總管在樹視圖中顯示延伸模組資料夾所需的基本資訊。 不過,若要充分利用 Windows 檔案總管的功能,您的延伸模組也必須公開一或多個選擇性介面,以支援更複雜的功能,例如快捷功能表或拖放功能,並提供資料夾檢視。

本文件討論如何實作 Windows Explorer 呼叫的主要和選擇性介面,以取得擴充功能內容的相關信息。 如需如何實作資料夾檢視以及如何自定義 Windows 檔案總管的討論,請參閱 實作資料夾檢視

基本實作和註冊

作為同進程 COM 伺服器,您的 DLL 必須公開數個標準函式和介面:

這些函式和介面的實作方式與大部分其他 COM 物件相同。 如需詳細資訊,請參閱 COM 檔

註冊延伸模組

如同所有 COM 物件,您必須為延伸模組建立類別識別碼 (CLSID) GUID。 藉由為擴充功能的CLSID建立名為 HKEY_CLASSES_ROOT\CLSID 的子機碼來註冊物件。 DLL 應該註冊為同進程伺服器,而且應該指定 Apartment 線程模型。 您可以將各種子機碼和值新增至延伸模組的 CLSID 索引鍵,以自定義延伸模組根資料夾的行為。

其中數個值僅適用於具有虛擬連接點的延伸模組。 這些值不適用於其連接點為檔案系統資料夾的延伸模組。 如需進一步的討論,請參閱 指定命名空間延伸模組的位置。 若要修改具有虛擬連接點的延伸模組行為,請將下列一或多個值新增至延伸模組的 CLSID 索引鍵:

  • WantsFORPARSING。 具有虛擬連接點之延伸模組的剖析名稱通常會有格式 ::{GUID}。 此類型的擴充功能通常包含虛擬專案。 不過,有些延伸模組,例如「我的檔」,實際上會對應至文件系統資料夾,即使它們具有虛擬連接點也一樣。 如果您的延伸模組以這種方式代表文件系統物件,您可以設定 WantsFORPARSING 值。 接著,Windows 檔案總管會呼叫資料夾物件的 IShellFolder::GetDisplayNameOf 方法 ,並將 uFlags 設定為 SHGDN_FORPARSING ,並將 pidl 設定為專案標識符清單的單一空白指標來要求根資料夾的剖析名稱。 空的 PIDL 只包含終止符。 然後,您的方法應該會傳回根資料夾的 ::{GUID} 剖析名稱。
  • HideFolderVerbs。 在 HKEY_CLASSES_ROOT Folder 底下註冊的\動詞通常與所有延伸模塊相關聯。 它們會出現在延伸模組的快捷方式功能表上,而且可由ShellExecute叫用 若要防止這些動詞命令與您的擴充功能產生關聯,請設定HideFolderVerbs值。
  • HideAsDelete。 如果使用者嘗試刪除您的延伸模組,Windows 檔案總管會改為隱藏延伸模組。
  • HideAsDeletePerUser。 這個值的效果與HideAsDelete相同,但以每個用戶為基礎。 只有嘗試刪除延伸模組的使用者才會隱藏。 所有其他使用者都可以看到延伸模組。
  • QueryForOverlay。 將此值設定為表示根資料夾的圖示可以有圖示重疊。 資料夾對象必須支援 IShellIconOverlay 介面。 在 Windows 檔案總管顯示根資料夾的圖示之前,它會呼叫兩 個 IShellIconOverlay 方法 之一,並將 pidlItem 設定為空白 PIDL,以要求重迭圖示。

其餘值和子機碼會套用至所有延伸模組:

  • 若要指定延伸模組連接點資料夾的顯示名稱,請將延伸模組 CLSID 子機碼的預設值設定為適當的字串。
  • 當游標停留在資料夾上方時,通常會顯示描述資料夾內容的資訊提示。 若要提供延伸模組根資料夾的資訊提示,請為延伸模組的 CLSID 索引鍵建立 InfoTip REG_SZ 值,並將其設定為適當的字串。
  • 若要指定延伸模組根資料夾的自定義圖示,請建立名為 DefaultIcon之延伸模組 CLSID 子機碼的子機碼。 將 DefaultIcon預設值設定為REG_SZ值,其中包含包含圖示的檔名,後面接著逗號,後面接著減號,後面接著該檔案中圖標的索引。
  • 根據預設,延伸模組根資料夾的快捷方式功能表會包含定義於 HKEY_CLASSES_ROOT\Folder 底下的專案。 如果您已設定適當的SFGAO_XXX旗標,則會新增 [刪除]、[重新命名] 和 [屬性] 專案。 您可以將其他專案新增至根資料夾的快捷方式功能表,或覆寫現有的專案,就像檔類型一樣。 在延伸模組的 CLSID 索引鍵下建立 Shell 子機碼,並定義命令,如擴充快捷方式功能表中所述
  • 如果您需要更有彈性的方式來處理根資料夾的快捷方式功能表,您可以實 作快捷方式選單處理程式。 若要註冊快捷方式功能表處理程式,請在延伸模組的CLSID機碼下建立 ShellEx 機碼。 註冊處理程式的 CLSID,就像傳統建立殼層擴充處理程式樣。
  • 若要將頁面新增至根資料夾的 Properties 屬性表,請為資料夾 提供SFGAO_HASPROPSHEET 屬性並實作 屬性表處理程式。 若要註冊屬性表處理程式,請在延伸模組的 CLSID 索引鍵下建立 ShellEx 索引鍵。 註冊處理程式的 CLSID,就像傳統建立殼層擴充處理程式樣。
  • 若要指定根資料夾的屬性,請將ShellFolder子機碼新增至延伸模組的CLSID子機碼。 建立 Attributes 值,並將它設定為適當的SFGAO_XXX旗標組合

下表列出根資料夾的一些常用屬性。

旗標 Description
SFGAO_FOLDER 0x20000000 延伸模組的根資料夾包含一或多個專案。
SFGAO_HASSUBFOLDER 0x80000000 延伸模組的根資料夾包含一或多個子資料夾。 Windows 檔案總管會在資料夾圖示旁邊加上加號 (+)。
SFGAO_CANDELETE 0x00000020 用戶可以刪除延伸模組的根資料夾。 資料夾的快捷方式選單將會有 [刪除] 專案。 這個旗標應該針對置於其中 一個虛擬資料夾下的連接點設定。
SFGAO_CANRENAME 0x00000010 延伸模組的根資料夾可由使用者重新命名。 資料夾的快捷方式選單將會有 [重新命名] 專案。
SFGAO_HASPROPSHEET 0x00000040 延伸模組的根資料夾具有 Properties 屬性表。 資料夾的快捷方式選單將會有 [屬性] 專案。 若要提供屬性表,您必須實 作屬性表處理程式。 如先前所述,在延伸模組的CLSID金鑰下註冊處理程式。

 

下列範例顯示擴展名的CLSID登錄專案,其顯示名稱為 MyExtension。 此延伸模組具有自定義圖示,其包含在擴充功能的 DLL 中,其索引為 1。 會 設定SFGAO_FOLDERSFGAO_HASSUBFOLDERSFGAO_CANDELETE 屬性。

HKEY_CLASSES_ROOT
   CLSID
      {Extension CLSID}
         (Default) = MyExtension
         InfoTip = Some appropriate text
      DefaultIcon
         (Default) = c:\MyDir\MyExtension.dll,-1
      InProcServer32
         (Default) = c:\MyDir\MyExtension.dll
         ThreadingModel = Apartment
      ShellFolder
         Attributes = 0xA00000020

處理 PIDL

Shell 命名空間中的每個項目都必須有唯一的 PIDL。 Windows 檔案總管會將 PIDL 指派給根資料夾,並在初始化期間將值傳遞至延伸模組。 接著,您的擴充功能會負責將正確建構的 PIDL 指派給每個物件,並依要求將這些 PIDL 提供給 Windows 檔案總管。 當殼層使用 PIDL 來識別其中一個延伸模組的物件時,您的延伸模組必須能夠解譯 PIDL 並識別特定物件。 您的延伸模組也必須將顯示名稱和剖析名稱指派給每個物件。 因為幾乎每個資料夾介面都會使用 PIDL,擴充功能通常會實作單 一 PIDL 管理員 來處理所有這些工作。

PIDL 一詞適用於 ITEMIDLIST 結構或這類結構的指標,視內容而定。 如宣告,ITEMIDLIST 結構具有單一成員 SHITEMID 結構。 物件的 ITEMIDLIST 結構實際上是兩個或多個 SHITEMID 結構的封裝數位。 這些結構的順序會透過命名空間定義路徑,與 c:\MyDirectory\MyFile 透過文件系統定義路徑的方式大致相同。 一般而言,物件的 PIDL 將包含一系列的 SHITEMID 結構,這些結構會對應至定義命名空間路徑的資料夾,後面接著物件的 SHITEMID 結構,後面接著終止符。

終止符是 SHITEMID 結構,cb 成員設定為 NULL 終止符是必要的,因為物件 PIDL 中的 SHITEMID 結構數目取決於 Shell 命名空間中物件的位置,以及路徑的起點。 此外,各種 SHITEMID 結構的大小可能會有所不同。 當您收到 PIDL 時,您沒有任何簡單的方法來判斷其大小,甚至是 SHITEMID 結構的總數。 相反地,您必須依結構來「逐步執行」包裝的陣列,直到到達終止符為止。

若要建立 PIDL,您的應用程式必須:

  1. 為每個物件建立 SHITEMID 結構。
  2. 將相關的 SHITEMID 結構組合成 PIDL。

建立 SHITEMID 結構

物件的 SHITEMID 結構可唯一識別其資料夾中的物件。 事實上,許多 IShellFolder 方法所使用的 PIDL 類型只包含物件的 SHITEMID 結構,後面接著終止符。 SHITEMID 結構的定義是:

typedef struct _SHITEMID { 
    USHORT cb; 
    BYTE   abID[1]; 
} SHITEMID, * LPSHITEMID;

abID 成員是對象的標識碼。 由於abID的長度未定義且可能會有所不同,因此 cb 成員會以位元組為單位設定為 SHITEMID 結構的大小。

因為abID的長度和內容都未標準化,因此您可以使用任何您想要將abID值指派給物件的配置。 唯一的需求是,您不能在相同資料夾中有兩個具有相同值的物件。 不過,基於效能考慮,您的 SHITEMID 結構應對齊 DWORD 換句話說,您應該建構 abID 值,讓 cb 是 4 的整數倍數。

一般而言, abID 會指向延伸模組定義的結構。 除了對象的識別碼,此結構通常用來保存各種相關信息,例如對象的類型或屬性。 然後,延伸模組的資料夾物件可以快速地從 PIDL 擷取資訊,而不必查詢資訊。

注意

設計 PIDL 數據結構最重要的層面之一是讓結構可保存且可傳輸。 在 PIDL 的內容中,這些詞彙的意義如下:

  • 可保存。 系統經常將 PIDL 放在各種類型的長期記憶體中,例如快捷方式檔案。 然後,它可以稍後從記憶體復原這些 PIDL,可能是在系統重新啟動之後。 從記憶體復原的 PIDL 仍然對擴充功能有效且有意義。 例如,這項需求表示您不應該在 PIDL 結構中使用指標或句柄。 當系統稍後從記憶體復原這些數據時,包含此數據類型的 PIDL 通常毫無意義。
  • 運輸。 從一部計算機傳輸到另一部計算機時,PIDL 必須保持有意義。 例如,PIDL 可以寫入快捷方式檔案、複製到磁碟片,並傳輸至另一部計算機。 該 PIDL 仍然應該對在第二部計算機上執行的擴充功能有意義。 例如,若要確保您的 PIDL 可傳輸,請明確使用 ANSI 或 Unicode 字元。 避免數據類型,例如 TCHARLPTSTR。 如果您使用這些數據類型,在執行延伸模組 Unicode 版本的電腦上建立的 PIDL 將無法由在不同電腦上執行之該延伸模組的 ANSI 版本讀取。

 

下列宣告顯示數據結構的簡單範例。

typedef struct tagMYPIDLDATA {
  USHORT cb;
  DWORD dwType;
  WCHAR wszDisplayName[40];
} MYPIDLDATA, *LPMYPIDLDATA;

cb 成員會設定為 MYPIDLDATA 結構的大小。 這個成員會使 MYPIDLDATA 成為本身的有效 SHITEMID 結構。 其餘成員相當於 SHITEMID 結構的 abID 成員,並保存私人數據。 dwType 成員是一個擴充定義的值,表示對象的類型。 在此範例中, dwType 會針對資料夾設定為 TRUE否則為 FALSE 。 例如,這個成員可讓您快速判斷物件是否為資料夾。 wszDisplayName 成員包含對象的顯示名稱。 由於您不會將相同的顯示名稱指派給相同資料夾中的兩個不同的物件,因此顯示名稱也會做為物件識別碼。 在此範例中, wszDisplayName 設定為 40 個字元,以確保 SHITEMID 結構會對 齊 DWORD。 若要限制 PIDL 的大小,您可以改用可變長度字元陣列,並據以調整 cb 的值。 以足夠的 『\0』 字元填補顯示字串,以維持結構的 DWORD 對齊方式。 在結構中放置可能很有用的其他成員包括物件的大小、屬性或剖析名稱。

建構 PIDL

定義物件的 SHITEMID 結構之後,您就可以使用這些結構來建構 PIDL。 PIDL 可以針對各種用途建構,但大部分的工作都使用兩種 PIDL 類型的其中一種。 最簡單的單一層級 PIDL 會識別相對於其父資料夾的物件。 許多 IShellFolder 方法都使用這種類型的 PIDL。 單一層級 PIDL 包含物件的 SHITEMID 結構,後面接著終止符。 完整 PIDL 會定義從桌面到 物件之命名空間階層的路徑。 這種類型的 PIDL 會從桌面開始,並針對路徑中的每個資料夾包含一個 SHITEMID 結構,後面接著 對象和終止符。 完整 PIDL 可唯一識別整個 Shell 命名空間內的 物件。

建構 PIDL 最簡單的方式是直接使用 ITEMIDLIST 結構本身。 建立 ITEMIDLIST 結構,但配置足夠的記憶體來保存所有 SHITEMID 結構。 此結構的位址會指向初始 SHITEMID 結構。 定義這個初始結構的成員值,然後依適當順序附加許多額外的 SHITEMID 結構。 下列程式概述如何建立單一層級 PIDL。 它包含兩SHITEMID 結構:MYPIDLDATA 結構,後面接著終止符:

  1. 使用 CoTaskMemAlloc 函式來配置 PIDL 的記憶體。 為私人數據配置足夠的記憶體,再加上 終止符的 USHORT (兩個字節)。 將結果轉換成 LPMYPIDLDATA。
  2. 將第一個 MYPIDLDATA 結構的 cb 成員設定為該結構的大小。 在此範例中,您會將 cb 設定為 sizeof(MYPIDLDATA)。 如果您想要使用可變長度結構,則必須計算 cb 的值
  3. 將適當的值指派給私人數據成員。
  4. 計算下一個 SHITEMID 結構的位址。 將目前 MYPIDLDATA 結構的位址轉換為 LPBYTE,並將該值新增至步驟 3 中決定的 cb 值。
  5. 在此情況下,下一個 SHITEMID 結構是終止符。 將結構的 cb 成員設定為零。

針對較長的 PIN,請配置足夠的記憶體,並針對每個額外的 SHITEMID 結構重複步驟 3-5。

下列範例函式會採用物件的類型和顯示名稱,並傳回物件的單一層級 PIDL。 函式假設顯示名稱,包括其終止的 Null 字元,不會超過為 MYPIDLDATA 結構宣告的字元數目。 如果該假設被證明是錯誤的, StringCbCopyW 函式將會截斷顯示名稱。 g_pMalloc變數是在其他地方建立並儲存在全域變數中的 IMalloc 指標。

LPITEMIDLIST CreatePIDL(DWORD dwType, LPCWSTR pwszDisplayName)
{
    LPMYPIDLDATA   pidlOut;
    USHORT         uSize;

    pidlOut = NULL;

    //Calculate the size of the MYPIDLDATA structure.
    uSize = sizeof(MYPIDLDATA);

    // Allocate enough memory for the PIDL to hold a MYPIDLDATA structure 
    // plus the terminator
    pidlOut = (LPMYPIDLDATA)m_pMalloc->Alloc(uSize + sizeof(USHORT));

    if(pidlOut)
    {
       //Assign values to the members of the MYPIDLDATA structure
       //that is the PIDL's first SHITEMID structure
       pidlOut->cb = uSize;
       pidlOut->dwType = dwType;
       hr = StringCbCopyW(pidlOut->wszDisplayName, 
                          sizeof(pidlOut->wszDisplayName), pwszDisplayName);
       
       // TODO: Add error handling here to verify the HRESULT returned 
       // by StringCbCopyW.

       //Advance the pointer to the start of the next SHITEMID structure.
       pidlOut = (LPMYPIDLDATA)((LPBYTE)pidlOut + pidlOut->cb);

       //Create the terminating null character by setting cb to 0.
       pidlOut->cb = 0;
    }

    return pidlOut;

完整的 PIDL 必須具有 從桌面到物件之每個物件的 SHITEMID 結構。 當 Shell 呼叫 IPersistFolder::Initialize 時,您的延伸模組會收到根資料夾的完整 PIDL。 若要建構物件的完整 PIDL,請取得Shell指派給根資料夾的PIDL,並將從根資料夾帶您到物件的 SHITEMID 結構附加

解譯 PIDL

當殼層或應用程式呼叫其中一個擴充功能的介面來要求對象的相關信息時,它通常會由 PIDL 識別物件。 某些方法,例如 IShellFolder::GetUIObjectOf,使用相對於父資料夾的 PIDLs,而且很容易解譯。 不過,您的延伸模組可能也會收到完整的 PIDL。 然後,您的 PIDL 管理員必須判斷 PIDL 所參考的物件。

使物件與完整 PIDL 產生關聯的工作複雜,在於 PIDL 中一或多個初始 SHITEMID 結構可能屬於位於 Shell 命名空間中延伸模組外部的物件。 您無法解譯這些結構之 abID 成員的意義。 延伸模組必須執行的動作是「逐步執行」SHITEMID 結構清單,直到到達對應至根資料夾的結構為止。 接著,您將瞭解如何解譯 SHITEMID 結構中的資訊。

若要逐步執行 PIDL,請取得第一個 cb 值,並將它新增至 PIDL 的位址,以將指標前進到下一個 SHITEMID 結構的開頭。 然後,它會指向該結構的 cb 成員,您可以使用該成員將指標前進到下一個 SHITEMID 結構的開頭等等。 每次推進指標時,請檢查 SHITEMID 結構,以判斷您是否已到達延伸模組命名空間的根目錄。

實作主要介面

與所有 COM 對象一樣,實作擴充功能主要是實作介面集合的問題。 本節討論所有延伸模組必須實作的三個主要介面。 它們用於初始化,並提供 Windows 檔案總管與擴充功能內容的基本資訊。 這些介面加上 資料夾檢視,都是功能延伸模組所需的所有介面。 不過,為了完全利用 Windows 檔案總管的功能,大部分的擴充功能也會實作一或多個選擇性介面。

IPersistFolder 介面

呼叫 IPersistFolder 介面來初始化新的資料夾物件。 IPersistFolder::Initialize 方法會將完整 PIDL 指派給新的 物件。 儲存此 PIDL 以供稍後使用。 例如,資料夾對象必須使用這個 PIDL 來建構物件子系的完整 PIDL。 資料夾物件的建立者也可以呼叫 IPersist::GetClassID 來要求物件的 CLSID。

一般而言,資料夾物件是由其父資料夾的 IShellFolder::BindToObject 方法所建立和初始化。 不過,當使用者流覽至延伸模組時,Windows 檔案總管會建立並初始化延伸模組的根資料夾物件。 根資料夾物件透過 IPersistFolder::Initialize 接收的 PIDL 包含從桌面到根資料夾的路徑,您必須為延伸模組建構完整的 PIDL。

IShellFolder 介面

Shell 會將延伸模組視為資料夾物件的階層式排序集合。 IShellFolder 介面是任何擴充實作的核心。 它代表資料夾物件,並提供 Windows 檔案總管顯示資料夾內容所需的大部分資訊。

IShellFolder 通常是直接由資料夾物件公開的 IPersistFolder 以外的唯一資料夾介面。 雖然 Windows 檔案總管使用各種不同的必要和選擇性介面來取得資料夾內容的相關信息,但它會透過 IShellFolder 取得這些介面的指標。

Windows 檔案總管會以各種方式取得延伸模組根資料夾的 CLSID。 如需詳細資訊,請參閱 指定命名空間延伸模組的位置顯示命名空間延伸模組的獨立檢視。 Windows 檔案總管接著會使用該 CLSID 來建立和初始化根資料夾的實例,並查詢 IShellFolder 介面。 您的延伸模組會建立資料夾物件來代表根資料夾,並傳回物件的 IShellFolder 介面。 擴充功能和 Windows 檔案總管之間的大部分互動,接著會透過 IShellFolder 進行。 Windows 檔案總管會呼叫 IShellFolder 以:

  • 要求可以列舉根資料夾內容的物件。
  • 取得根資料夾內容的各種類型資訊。
  • 要求公開其中一個選擇性介面的物件。 接著可以查詢這些介面以取得其他資訊,例如圖示或快捷功能表。
  • 要求代表根資料夾子資料夾的資料夾物件。

當用戶開啟根資料夾的子資料夾時,Windows 檔案總管會呼叫 IShellFolder::BindToObject 您的延伸模組會建立並初始化新的資料夾物件來表示子資料夾,並傳回其 IShellFolder 介面。 Windows 檔案總管接著會呼叫此介面以取得各種類型的資訊,等等,直到使用者決定在Shell命名空間中的其他位置巡覽,或關閉 Windows 檔案總管為止。

本節的其餘部分簡短討論更重要 的 IShellFolder 方法,以及如何實作它們。

EnumObjects

在樹視圖中顯示資料夾的內容之前,Windows 檔案總管必須先呼叫 IShellFolder::EnumObjects 方法來判斷資料夾包含的內容。 這個方法會建立標準 OLE 列舉物件,該物件會公開 IEnumIDList 介面,並傳回該介面指標。 IEnumIDList 介面可讓 Windows 檔案總管取得資料夾包含之所有物件的 PIDL。 然後,這些 PIDL 會用來取得資料夾所包含之物件的相關信息。 如需進一步的詳細數據,請參閱 IEnumIDList 介面

注意

IEnumIDList::Next 方法應該只傳回相對於父資料夾的 PIDL。 PIDL 應該只包含物件的 SHITEMID 結構,後面接著終止符。

 

CreateViewObject

在顯示資料夾的內容之前,Windows 檔案總管會呼叫此方法來要求 IShellView 介面的指標。 Windows 檔案總管會使用此介面來管理資料夾檢視。 建立資料夾檢視物件,並傳回其 IShellView 介面。

也會呼叫 IShellFolder::CreateViewObject 方法,要求資料夾本身的其中一個選擇性介面,例如 IContextMenu 這個方法的實作應該建立對象來公開要求的介面,並傳回介面指標。 如果 Windows 檔案總管需要資料夾所包含的其中一個對象的選擇性介面,它會呼叫 IShellFolder::GetUIObjectOf

GetUIObjectOf

雖然資料夾內容的基本資訊可透過 IShellFolder 方法取得,但您的延伸模組也可以提供 Windows 檔案總管各種其他資訊。 例如,您可以指定資料夾或物件快捷方式功能表內容的圖示。 Windows 檔案總管會 呼叫 IShellFolder::GetUIObjectOf 方法,嘗試擷取資料夾所包含之物件的其他資訊。 Windows 檔案總管會指定它想要信息的物件,以及相關介面的 IID。 資料夾對象接著會建立物件,該物件會公開要求的介面,並傳回介面指標。

如果您的延伸模組允許使用者使用拖放或剪貼簿傳送物件,Windows 檔案總管會呼叫 IShellFolder::GetUIObjectOf 來要求 IDataObject IDropTarget 介面。 如需詳細資訊,請參閱 使用拖放和剪貼簿傳輸殼層物件。

當 Windows Explorer 想要與資料夾本身相同的資訊時,會呼叫 IShellFolder::CreateViewObject

BindToObject

當使用者嘗試開啟其中一個延伸模組的子資料夾時,Windows 檔案總管會呼叫 IShellFolder::BindToObject 方法。 如果 riid 設定為 IID_IShellFolder,您應該建立並初始化代表子資料夾的資料夾物件,並傳回物件的 IShellFolder 介面。

注意

目前,Windows 檔案總管只會呼叫此方法來要求 IShellFolder 介面。 不過,請勿假設這一律會是這種情況。 在繼續之前,您應該一律檢查 riid 的值

 

GetDisplayNameOf

Windows Explorer 會 呼叫 IShellFolder::GetDisplayNameOf 方法,將其中一個資料夾物件的 PIDL 轉換成名稱。 該 PIDL 必須與物件的父資料夾相對。 換句話說,它必須包含單一非 NULL SHITEMID 結構。 因為命名物件的方法不止一種,Windows 檔案總管會藉由在 uFlags 參數中設定一或多個 SHGDNF 旗標來指定名稱類型。 其中一個值 ,SHGDN_NORMALSHGDN_INFOLDER,將設定為指定名稱應該相對於資料夾或相對於桌面。 另外三個值 之一,SHGDN_FOREDITINGSHGDN_FORADDRESSBARSHGDN_FORPARSING,可以設定為指定將用於的名稱。

您必須以 STRRET 結構的形式傳回名稱。 如果未 設定SHGDN_FOREDITINGSHGDN_FORADDRESSBARSHGDN_FORPARSING ,則傳回對象的顯示名稱。 如果已 設定SHGDN_FORPARSING 旗標,Windows 檔案總管會要求剖析名稱。 剖析名稱會傳遞至 IShellFolder::P arseDisplayName 以取得物件的 PIDL,即使它可能位於命名空間階層中目前資料夾下方的一或多個層級。 例如,檔案系統物件的剖析名稱是其路徑。 您可以將文件系統中任何物件的完整路徑傳遞至桌面的 IShellFolder::P arseDisplayName 方法,並傳回該物件的完整 PIDL。

雖然剖析名稱是文字字串,但它們不一定必須包含顯示名稱。 您應該根據呼叫 IShellFolder::P arseDisplayName,最有效率地指派剖析名稱。 例如,許多Shell的虛擬資料夾不是文件系統的一部分,而且沒有完整的路徑。 相反地,每個資料夾都會指派 GUID,剖析名稱的格式為 ::{GUID}。 無論您使用何種配置,它都應該能夠可靠地「往返」。例如,如果呼叫端將剖析名稱傳遞至 IShellFolder::P arseDisplayName 以擷取物件的 PIDL,然後將該 PIDL 傳遞給 IShellFolder::GetDisplayNameOf設定SHGDN_FORPARSING旗標,呼叫端應該復原原始剖析名稱。

GetAttributesOf

Windows 檔案總管會 呼叫 IShellFolder::GetAttributesOf 方法,以判斷資料夾物件所包含的一或多個項目屬性。 cidl 的值會提供查詢中的項目數,而 aPidl 會指向其 PIDL 清單。

由於測試某些屬性可能很耗時,因此 Windows 檔案總管通常會藉由在 rfgInOut 中設定其值,將查詢限制為可用旗標的子集。 您的方法應該只測試那些旗標是在 rfgInOut設定的屬性。 讓有效的旗標保持設定,並清除其餘部分。 如果查詢中包含一個以上的專案,請只設定套用至所有專案的旗標。

注意

必須正確設定屬性,才能正確顯示專案。 例如,如果專案是包含子資料夾的資料夾,您必須設定 SFGAO_HASSUBFOLDER 旗標。 否則,Windows 檔案總管將不會在樹檢視中顯示項目圖示旁的 + 。

 

ParseDisplayName

IShellFolder::P arseDisplayName 方法在某種程度上是 IShellFolder::GetDisplayNameOf鏡像影像。 這個方法最常見的用法是將物件的剖析名稱轉換成相關聯的 PIDL。 剖析名稱可以參考命名空間階層中資料夾下方的任何物件。 傳回的 PIDL 相對於公開 方法的資料夾物件,而且通常不是完整。 換句話說,雖然 PIDL 可以包含數 個 SHITEMID 結構,但第一個結構會是物件本身或路徑中從資料夾到物件的第一個子資料夾。 呼叫端必須將此 PIDL 附加至資料夾的完整 PIDL,才能取得物件的完整 PIDL。

您也可以呼叫 IShellFolder::P arseDisplayName 來要求對象的屬性。 因為判斷所有適用的屬性可能很耗時,因此呼叫端只會設定代表 呼叫者感興趣的資訊SFGAO_XXX 旗標。 您應該判斷物件有哪些屬性為 true,並清除其餘旗標。

IEnumIDList 介面

當 Windows 檔案總管需要列舉資料夾所包含的物件時,它會呼叫 IShellFolder::EnumObjects 資料夾對象必須建立列舉對象來公開 IEnumIDList 介面,並傳回該介面指標。 然後,Windows 檔案總管通常會使用 IEnumIDList 列舉資料夾包含之所有物件的 PIDL。

IEnumIDList 是標準 OLE 列舉介面,並以一般方式實作。 不過,請記住,您傳回的 PIDL 必須相對於資料夾,且只包含物件的 SHITEMID 結構和終止符。

實作選擇性介面

擴充功能的資料夾物件可支援許多選擇性Shell介面。 其中許多專案,例如 IExtractIcon,可讓您自定義用戶檢視延伸模組的各種層面。 其他專案,例如 IDataObject,可讓您的延伸模組支援拖放等功能。

任何選擇性介面都不會由資料夾物件直接公開。 相反地,Windows Explorer 會呼叫兩 個 IShellFolder 方法的其中一個來要求介面:

為了提供資訊,資料夾物件會建立對象來公開要求的介面,並傳回介面指標。 然後,Windows 檔案總管會呼叫該介面來擷取所需的資訊。 本節討論最常用的選擇性介面。

IExtractIcon

Windows 檔案總管會先要求 IExtractIcon 介面,再顯示資料夾的內容。 介面可讓您的延伸模組指定資料夾所包含物件的自訂圖示。 否則,將會使用標準檔案和資料夾圖示。 若要提供自定義圖示,請建立圖示擷取物件,以公開 IExtractIcon 並傳回該介面的指標。 如需進一步的討論,請參閱 IExtractIcon 參考檔或建立圖示處理程式

IContextMenu

當使用者以滑鼠右鍵按兩下物件時,Windows 檔案總管會要求 IContextMenu 介面。 若要提供物件的快捷功能表,請建立功能表處理程式物件並傳回其 IContextMenu 介面。

建立功能表處理程式物件的程式與用來建立功能表處理程式殼層延伸模組的程式非常類似。 如需詳細資訊,請參閱建立操作功能表處理程式IContextMenuIContextMenu2 IContextMenu3 參考。

IQueryInfo

Windows 檔案總管會 呼叫 IQueryInfo 介面來擷取資訊提示文字字串。

IDataObject 和 IDropTarget

當 Windows 檔案總管顯示您的物件時,資料夾物件無法直接知道使用者何時嘗試剪下、複製或拖曳物件。 相反地,Windows 檔案總管會要求 IDataObject 介面。 若要允許傳送物件,請建立數據物件,並傳回其 IDataObject 介面的指標。

同樣地,使用者可能會嘗試在其中一個物件的 Windows 檔案總管表示法上卸除數據物件,例如圖示或網址列路徑。 Windows 檔案總管接著會要求 IDropTarget 介面。 若要允許卸除數據物件,請建立可公開 IDropTarget 介面並傳回介面指標的物件。

處理數據傳輸是寫入命名空間延伸模組的其中一個棘手層面。 如需詳細討論,請參閱 使用拖放和剪貼簿傳輸殼層物件。

使用預設殼層資料夾檢視實作

使用預設 Shell 資料夾檢視物件 (DefView) 的資料來源必須實作這些介面:

或者,他們也可以實作 IPersistFolder3