基本的なフォルダオブジェクトインターフェースの実装
名前空間拡張を実装する手順は、他のインプロセス コンポーネント オブジェクト モデル (COM) オブジェクトの場合と同様です。 すべての拡張機能は、拡張機能のフォルダーをツリー ビューに表示するために必要な基本情報を Windows Explorer に提供する 3 つの主要なインターフェイスをサポートする必要があります。 ただし、Windows Explorer の機能を最大限に活用するには、拡張機能で、ショートカット メニューやドラッグ アンド ドロップなどのより高度な機能をサポートし、フォルダー ビューを提供する 1 つ以上のオプション インターフェイスも公開する必要があります。
このドキュメントでは、拡張機能のコンテンツに関する情報を取得するために Windows Explorer が呼び出すプライマリ インターフェイスとオプション インターフェイスを実装する方法について説明します。 フォルダー ビューを実装する方法と Windows Explorer をカスタマイズする方法については、「フォルダー ビューの実装」を参照してください。
基本的な実装と登録
インプロセス COM サーバーとして、DLL はいくつかの標準関数とインターフェイスを公開する必要があります。
これらの関数とインターフェイスは、他のほとんどの COM オブジェクトと同じ方法で実装されます。 詳細については、COM のドキュメントをご覧ください。
拡張機能の登録
すべての COM オブジェクトと同様に、拡張機能のクラス識別子 (CLSID) GUID を作成する必要があります。 拡張機能の CLSID にちなんで名付けられた HKEY_CLASSES_ROOT\CLSID のサブキーを作成して、オブジェクトを登録します。 DLL はインプロセス サーバーとして登録し、アパートメント スレッド モデルを指定する必要があります。 拡張機能の CLSID キーにさまざまなサブキーと値を追加することで、拡張機能のルート フォルダーの動作をカスタマイズできます。
これらの値のいくつかは、仮想ジャンクション ポイントを持つ拡張機能にのみ適用されます。 これらの値は、ジャンクション ポイントがファイル システム フォルダーである拡張機能には適用されません。 詳細については、「名前空間拡張の場所の指定」を参照してください。 仮想ジャンクション ポイントを持つ拡張機能の動作を変更するには、拡張機能の CLSID キーに次の値の 1 つ以上を追加します。
- WantsFORPARSING. 仮想ジャンクション ポイントを持つ拡張機能の解析名は、通常、::{GUID} の形式になります。 このタイプの拡張機能には通常、仮想アイテムが含まれます。 ただし、「マイ ドキュメント」などの一部の拡張子は、仮想ジャンクション ポイントがあっても、実際にはファイル システム フォルダーに対応します。 拡張機能がファイル システム オブジェクトをこのように表す場合は、WantsFORPARSING 値を設定できます。 次に、Windows Explorer は、フォルダー オブジェクトの IShellFolder::GetDisplayNameOf メソッドを呼び出して、ルート フォルダーの解析名を要求します。このとき、 uFlags は SHGDN_FORPARSING に設定され、 pidl はアイテム識別子リスト (PIDL) への単一の空のポインターに設定されます。 空の PIDL にはターミネータのみが含まれます。 メソッドはルート フォルダーの ::{GUID} 解析名を返す必要があります。
- HideFolderVerbs. HKEY_CLASSES_ROOT\Folder の下に登録された動詞は、通常、すべての拡張機能に関連付けられています。 これらは拡張機能のショートカット メニューに表示され、 ShellExecuteによって呼び出すことができます。 これらの動詞が拡張機能に関連付けられないようにするには、HideFolderVerbs 値を設定します。
- HideAsDelete. ユーザーが拡張機能を削除しようとすると、Windows Explorer は拡張機能を非表示にします。
- HideAsDeletePerUser. この値は HideAsDelete と同じ効果がありますが、ユーザーごとに異なります。 拡張機能は、それを削除しようとしたユーザーに対してのみ非表示になります。 拡張機能は他のすべてのユーザーに表示されます。
- QueryForOverlay. ルート フォルダーのアイコンにアイコン オーバーレイを表示できることを示すには、この値を設定します。 フォルダー オブジェクトは IShellIconOverlay インターフェイスをサポートする必要があります。 Windows Explorer は、ルート フォルダーのアイコンを表示する前に、 pidlItem を空の PIDL に設定して 2 つの IShellIconOverlay メソッドのいずれかを呼び出してオーバーレイ アイコンを要求します。
残りの値とサブキーはすべての拡張機能に適用されます。
- 拡張機能のジャンクション ポイント フォルダーの表示名を指定するには、拡張機能の CLSID サブキーの既定値を適切な文字列に設定します。
- カーソルをフォルダーの上に置くと、通常、フォルダーの内容を説明する情報ヒントが表示されます。 拡張機能のルート フォルダーに情報ヒントを提供するには、拡張機能の CLSID キーの InfoTip REG_SZ 値を作成し、適切な文字列に設定します。
- 拡張機能のルート フォルダーにカスタム アイコンを指定するには、拡張機能の CLSID サブキーの DefaultIcon という名前のサブキーを作成します。 DefaultIcon のデフォルト値を、アイコンを含むファイルの名前、その後にコンマ、マイナス記号、そのファイル内のアイコンのインデックスが続く REG_SZ 値に設定します。
- デフォルトでは、拡張機能のルート フォルダーのショートカット メニューには、 HKEY_CLASSES_ROOT\Folder で定義された項目が含まれます。 適切な SFGAO_XXX フラグを設定した場合、 削除、 名前変更、および プロパティ 項目が追加されます。 ファイル タイプ の場合と同様に、ルート フォルダーのショートカット メニューに他の項目を追加したり、既存の項目を上書きしたりできます。 拡張機能の CLSID キーの下に Shell サブキーを作成し、「ショートカット メニューの拡張」で説明されているようにコマンドを定義します。
- ルート フォルダーのショートカット メニューをより柔軟に処理する必要がある場合は、 ショートカット メニュー ハンドラー を実装できます。 ショートカット メニュー ハンドラーを登録するには、拡張機能の CLSID キーの下に ShellEx キーを作成します。 従来の シェル拡張ハンドラーの作成 と同様に、ハンドラーの CLSID を登録します。
- ルート フォルダーのプロパティ プロパティ シートにページを追加するには、フォルダーに SFGAO_HASPROPSHEET 属性を指定し、 プロパティ シート ハンドラー を実装します。 プロパティ シート ハンドラーを登録するには、拡張機能の CLSID キーの下に ShellEx キーを作成します。 従来の シェル拡張ハンドラーの作成 と同様に、ハンドラーの CLSID を登録します。
- ルート フォルダーの属性を指定するには、拡張機能の CLSID サブキーに ShellFolder サブキーを追加します。 属性値を作成し、それを SFGAO_XXX フラグの適切な組み合わせに設定します。
次の表に、ルート フォルダーでよく使用される属性の一部を示します。
フラグ | 値 | 説明 |
---|---|---|
SFGAO_FOLDER | 0x20000000 | 拡張機能のルート フォルダーには 1 つ以上の項目が含まれています。 |
SFGAO_HASSUBFOLDER | 0x80000000 | 拡張機能のルート フォルダーには、1 つ以上のサブフォルダーが含まれます。 Windows Explorer では、フォルダー アイコンの横にプラス記号 ( + ) が表示されます。 |
SFGAO_CANDELETE | 0x00000020 | 拡張機能のルート フォルダーはユーザーが削除できます。 フォルダーのショートカット メニューには、 削除 項目が表示されます。 このフラグは、 仮想フォルダーのいずれかの下に配置されたジャンクション ポイントに対して設定する必要があります。 |
SFGAO_CANRENAME | 0x00000010 | 拡張機能のルート フォルダーの名前はユーザーが変更できます。 フォルダーのショートカット メニューには、 名前の変更 項目が表示されます。 |
SFGAO_HASPROPSHEET | 0x00000040 | 拡張機能のルート フォルダーには、 Properties プロパティ シートがあります。 フォルダーのショートカット メニューには、 プロパティ 項目が表示されます。 プロパティ シートを提供するには、 プロパティ シート ハンドラーを実装する必要があります。 前述したように、拡張機能の CLSID キーの下にハンドラーを登録します。 |
次の例は、表示名が MyExtension である拡張機能の CLSID レジストリ エントリを示しています。 拡張機能には、拡張機能の DLL にインデックス 1 で含まれるカスタム アイコンがあります。 SFGAO_FOLDER、 SFGAO_HASSUBFOLDER、および SFGAO_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 Explorer は、ルート フォルダーに PIDL を割り当て、初期化中にその値を拡張機能に渡します。 拡張機能は、適切に構築された PIDL を各オブジェクトに割り当て、要求に応じてそれらの PIDL を Windows Explorer に提供する役割を担います。 シェルが PIDL を使用して拡張機能のオブジェクトの 1 つを識別する場合、拡張機能は PIDL を解釈して特定のオブジェクトを識別できる必要があります。 拡張機能では、各オブジェクトに 表示名 と 解析名 も割り当てる必要があります。 PIDL はほぼすべてのフォルダー インターフェイスで使用されるため、拡張機能では通常、これらすべてのタスクを処理するために単一の PIDL マネージャー を実装します。
PIDL という用語は、コンテキストに応じて、 ITEMIDLIST 構造体、またはそのような構造体へのポインターの略です。 宣言されているように、 ITEMIDLIST 構造体には、 SHITEMID 構造体という単一のメンバーがあります。 オブジェクトの ITEMIDLIST 構造は、実際には 2 つ以上の SHITEMID 構造のパックされた配列です。 これらの構造の順序は、c:\MyDirectory\MyFile がファイル システム内のパスを定義するのとほぼ同じように、名前空間内のパスを定義します。 通常、オブジェクトの PIDL は、名前空間パスを定義するフォルダーに対応する一連の SHITEMID 構造と、それに続くオブジェクトの SHITEMID 構造、そしてターミネータで構成されます。
ターミネータは SHITEMID 構造体で、 cb メンバーは NULL に設定されています。 オブジェクトの PIDL 内の SHITEMID 構造体の数は、Shell 名前空間内のオブジェクトの位置とパスの開始点によって異なるため、ターミネータが必要です。 さらに、さまざまな SHITEMID 構造のサイズは異なる場合があります。 PIDL を受け取った場合、そのサイズや SHITEMID 構造の合計数を確認する簡単な方法はありません。 代わりに、ターミネータに到達するまで、パックされた配列を構造ごとに「ウォーク」する必要があります。
PIDL を作成するには、アプリケーションで次の操作を行う必要があります。
SHITEMID構造の作成
オブジェクトの SHITEMID 構造は、フォルダー内のオブジェクトを一意に識別します。 実際、多くの IShellFolder メソッドで使用される PIDL のタイプは、オブジェクトの SHITEMID 構造とそれに続く終端文字のみで構成されます。 SHITEMID 構造の定義は次のとおりです。
typedef struct _SHITEMID {
USHORT cb;
BYTE abID[1];
} SHITEMID, * LPSHITEMID;
abID メンバーはオブジェクトの識別子です。 abID の長さは定義されておらず、変化する可能性があるため、 cb メンバーは SHITEMID 構造体のサイズ (バイト単位) に設定されます。
abID の長さも内容も標準化されていないため、任意のスキームを使用してオブジェクトに abID 値を割り当てることができます。 唯一の要件は、同じフォルダー内に同じ値を持つ 2 つのオブジェクトを置くことができないことです。 ただし、パフォーマンス上の理由から、 SHITEMID 構造は DWORDに揃える必要があります。 つまり、 cb が 4 の整数倍になるように abID 値を構築する必要があります。
通常、 abID は拡張機能で定義された構造を指します。 この構造は、オブジェクトの ID に加えて、オブジェクトのタイプや属性など、さまざまな関連情報を保持するためによく使用されます。 拡張機能のフォルダー オブジェクトは、クエリを実行する代わりに、PIDL から情報をすばやく抽出できます。
Note
PIDL のデータ構造を設計する上で最も重要な側面の 1 つは、構造を永続的かつ転送可能にすることです。 PIDL の文脈では、これらの用語の意味は次のとおりです。
- 永続的。 システムは、ショートカット ファイルなどのさまざまな種類の長期ストレージに PIDL を頻繁に配置します。 その後、システムの再起動後に、これらの PIDL をストレージから回復できます。 ストレージから回復された PIDL は、拡張機能に対して引き続き有効かつ意味のあるものでなければなりません。 この要件は、たとえば、PIDL 構造内でポインターやハンドルを使用しないことを意味します。 このタイプのデータを含む PIDL は、システムが後でストレージから回復するときには通常意味をなさなくなります。
- 持ち運び可能。 PIDL は、あるコンピューターから別のコンピューターに転送されるときにも意味を維持する必要があります。 たとえば、PIDL をショートカット ファイルに書き込んでフロッピー ディスクにコピーし、別のコンピューターに転送することができます。 その PIDL は、2 台目のコンピューターで実行されている拡張機能にとっても意味があるはずです。 たとえば、PIDL が移植可能であることを確認するには、ANSI または Unicode 文字のいずれかを明示的に使用します。 TCHAR や LPTSTR などのデータ型は避けてください。 これらのデータ型を使用すると、拡張機能の 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 メンバーにはオブジェクトの表示名が含まれます。 同じフォルダー内の 2 つの異なるオブジェクトに同じ表示名を割り当てることはできないため、表示名はオブジェクト ID としても機能します。 この例では、 SHITEMID 構造が DWORD に揃えられるように、 wszDisplayName は 40 文字に設定されています。 PIDL のサイズを制限するには、代わりに可変長文字配列を使用し、それに応じて cb の値を調整します。 構造体の DWORD の配置を維持するために、表示文字列に十分な '\0' 文字を埋め込みます。 構造体に入れると便利なその他のメンバーには、オブジェクトのサイズ、属性、解析名などがあります。
PIDLの構築
オブジェクトに対して SHITEMID 構造を定義したら、それを使用して PIDL を構築できます。 PIDL はさまざまな目的で構築できますが、ほとんどのタスクでは 2 種類の PIDL のいずれかが使用されます。 最も単純な単一レベルの PIDL は、親フォルダーを基準にしてオブジェクトを識別します。 このタイプの PIDL は、多くの IShellFolder メソッドで使用されます。 単一レベルの PIDL には、オブジェクトの SHITEMID 構造とそれに続く終端子が含まれます。 完全修飾 PIDL は、デスクトップからオブジェクトまでの名前空間階層を通るパスを定義します。 このタイプの PIDL はデスクトップから始まり、パス内の各フォルダーに対して 1 つの SHITEMID 構造が含まれ、その後にオブジェクトとターミネータが続きます。 完全修飾 PIDL は、Shell 名前空間全体内でオブジェクトを一意に識別します。
PIDL を構築する最も簡単な方法は、 ITEMIDLIST 構造自体を直接操作することです。 ITEMIDLIST 構造体を作成しますが、すべての SHITEMID 構造体を保持するのに十分なメモリを割り当てます。 この構造体のアドレスは、初期の SHITEMID 構造体を指します。 この初期構造体のメンバの値を定義し、適切な順序で必要な数の SHITEMID 構造体を追加します。 次の手順では、単一レベルの PIDL を作成する方法について説明します。 これには、2 つの SHITEMID 構造体 (MYPIDLDATA 構造体とそれに続く終端文字) が含まれています。
- PIDL にメモリを割り当てるには、 CoTaskMemAlloc 関数を使用します。 プライベート データ用に十分なメモリと、ターミネータ用の USHORT (2 バイト) を割り当てます。 結果を LPMYPIDLDATA にキャストします。
- 最初の MYPIDLDATA 構造体の cb メンバーをその構造体のサイズに設定します。 この例では、 cb を sizeof(MYPIDLDATA) に設定します。 可変長構造体を使用する場合は、 cb の値を計算する必要があります。
- プライベート データ メンバーに適切な値を割り当てます。
- 次の SHITEMID 構造体のアドレスを計算します。 現在の MYPIDLDATA 構造体のアドレスを LPBYTE にキャストし、その値を手順 3 で決定した cb の値に追加します。
- この場合、次の SHITEMID 構造がターミネータになります。 構造体の cb メンバーをゼロに設定します。
PIDL が長い場合は、十分なメモリを割り当て、追加の 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 構造が必要です。 シェルが IPersistFolder::Initialize を呼び出すと、拡張機能はルート フォルダーの完全修飾 PIDL を受け取ります。 オブジェクトの完全修飾 PIDL を構築するには、シェルがルート フォルダーに割り当てた PIDL を取得し、ルート フォルダーからオブジェクトに移動するために必要な SHITEMID 構造を追加します。
PIDL の解釈
シェルまたはアプリケーションが拡張機能のインターフェイスの 1 つを呼び出してオブジェクトに関する情報を要求する場合、通常は PIDL によってオブジェクトが識別されます。 IShellFolder::GetUIObjectOf などの一部のメソッドは、親フォルダーを基準とした PIDL を使用し、簡単に解釈できます。 ただし、拡張機能はおそらく完全に修飾された PIDL も受信することになります。 次に、PIDL マネージャーは、PIDL が参照しているオブジェクトを特定する必要があります。
オブジェクトを完全修飾 PIDL に関連付けるタスクが複雑になるのは、PIDL 内の最初の SHITEMID 構造の 1 つ以上が、シェル名前空間の拡張機能の外部にあるオブジェクトに属している可能性があるからです。 これらの構造体の abID メンバーの意味を解釈する方法はありません。 拡張機能が実行する必要があるのは、ルート フォルダーに対応する構造に到達するまで、 SHITEMID 構造のリストを「調べる」ことです。 それ以降は、 SHITEMID 構造内の情報をどのように解釈するかがわかります。
PIDL をウォークするには、最初の cb 値を取得し、それを PIDL のアドレスに追加して、ポインターを次の SHITEMID 構造の先頭に進めます。 次に、その構造体の cb メンバーを指すようになり、これを使用してポインターを次の SHITEMID 構造体の先頭に進めることができます。 ポインタを進めるたびに、 SHITEMID 構造を調べて、拡張機能の名前空間のルートに到達したかどうかを判断します。
主要なインターフェースの実装
すべての COM オブジェクトと同様に、拡張機能の実装は主にインターフェイスのコレクションを実装することになります。 このセクションでは、すべての拡張機能で実装する必要がある 3 つの主要なインターフェースについて説明します。 これらは初期化に使用され、拡張機能の内容に関する基本情報を Windows Explorer に提供します。 これらのインターフェースと フォルダー ビューが、機能拡張に必要なすべてです。 ただし、Windows Explorer の機能を最大限に活用するために、ほとんどの拡張機能では 1 つ以上のオプション インターフェイスも実装します。
IPersistFolder インターフェイス
IPersistFolder インターフェイスは、新しいフォルダー オブジェクトを初期化するために呼び出されます。 IPersistFolder::Initialize メソッドは、新しいオブジェクトに完全修飾 PIDL を割り当てます。 この PIDL を後で使用するために保存します。 たとえば、フォルダー オブジェクトは、この PIDL を使用して、オブジェクトの子に対して完全修飾 PIDL を構築する必要があります。 IPersistFolder::Initialize メソッドは、新しいオブジェクトに完全修飾 PIDL を割り当てます。
通常、フォルダー オブジェクトは、親フォルダーの IShellFolder::BindToObject メソッドによって作成および初期化されます。 ただし、ユーザーが拡張機能を参照すると、Windows Explorer は拡張機能のルート フォルダー オブジェクトを作成して初期化します。 ルート フォルダー オブジェクトが IPersistFolder::Initialize を通じて受信する PIDL には、拡張機能の完全修飾 PIDL を構築するために必要な、デスクトップからルート フォルダーまでのパスが含まれています。
IShellFolder インターフェイス
シェルは、拡張機能を階層的に順序付けられたフォルダー オブジェクトのコレクションとして扱います。 IShellFolder インターフェイスは、あらゆる拡張機能の実装の中核です。 これはフォルダー オブジェクトを表し、フォルダーの内容を表示するために必要な多くの情報を Windows Explorer に提供します。
IShellFolder は通常、 IPersistFolder 以外でフォルダー オブジェクトによって直接公開される唯一のフォルダー インターフェイスです。 Windows Explorer は、フォルダーの内容に関する情報を取得するためにさまざまな必須およびオプションのインターフェイスを使用しますが、それらのインターフェイスへのポインターは IShellFolderを通じて取得されます。
Windows Explorer は、さまざまな方法で拡張機能のルート フォルダーの CLSID を取得します。 詳細については、「名前空間拡張の場所の指定」または「名前空間拡張の自己完結型ビューの表示」を参照してください。 次に、Windows Explorer はその CLSID を使用してルート フォルダーのインスタンスを作成し、初期化し、IShellFolder インターフェイスを照会します。 拡張機能は、ルート フォルダーを表すフォルダー オブジェクトを作成し、オブジェクトの IShellFolder インターフェイスを返します。 拡張機能と Windows Explorer 間の残りのやり取りの多くは、 IShellFolder を通じて行われます。 Windows Explorer は IShellFolder を呼び出して次の操作を行います。
- ルート フォルダーの内容を列挙できるオブジェクトを要求します。
- ルート フォルダーの内容に関するさまざまな情報を取得します。
- オプションのインターフェースの 1 つを公開するオブジェクトを要求します。 これらのインターフェースに対して、アイコンやショートカット メニューなどの追加情報を照会できます。
- ルート フォルダーのサブフォルダーを表すフォルダー オブジェクトを要求します。
ユーザーがルート フォルダーのサブフォルダーを開くと、Windows Explorer は IShellFolder::BindToObject を呼び出します。 拡張機能は、サブフォルダーを表す新しいフォルダー オブジェクトを作成して初期化し、その IShellFolder インターフェイスを返します。 その後、Windows Explorer は、さまざまな種類の情報を取得するためにこのインターフェイスを呼び出します。これは、ユーザーがシェル名前空間内の別の場所に移動するか、Windows Explorer を閉じるまで続きます。
このセクションの残りの部分では、より重要な IShellFolder メソッドとその実装方法について簡単に説明します。
EnumObjects
ツリー ビューにフォルダーの内容を表示する前に、Windows Explorer はまず IShellFolder::EnumObjects メソッドを呼び出して、フォルダーに含まれる内容を特定する必要があります。 このメソッドは、 IEnumIDList インターフェイスを公開し、そのインターフェイス ポインターを返す標準 OLE 列挙オブジェクトを作成します。 IEnumIDList インターフェイスを使用すると、Windows Explorer はフォルダーに含まれるすべてのオブジェクトの PIDL を取得できます。 これらの PIDL は、フォルダーに含まれるオブジェクトに関する情報を取得するために使用されます。 詳細については、 IEnumIDList インターフェイスを参照してください。
Note
IEnumIDList::Next メソッドは、親フォルダーを基準とした PIDL のみを返す必要があります。 PIDL には、オブジェクトの SHITEMID 構造とそれに続く終端子のみが含まれている必要があります。
CreateViewObject
フォルダーの内容が表示される前に、Windows Explorer はこのメソッドを呼び出して、 IShellView インターフェイスへのポインターを要求します。 このインターフェイスは、Windows Explorer がフォルダー ビューを管理するために使用されます。 フォルダー ビュー オブジェクトを作成し、その IShellView インターフェイスを返します。
IShellFolder::CreateViewObject メソッドも呼び出され、フォルダー自体の IContextMenuなどのオプションのインターフェイスの 1 つを要求します。 このメソッドの実装では、要求されたインターフェイスを公開し、インターフェイス ポインターを返すオブジェクトを作成する必要があります。 Windows Explorer がフォルダーに含まれるオブジェクトの 1 つに対してオプションのインターフェイスを必要とする場合、 IShellFolder::GetUIObjectOf を呼び出します。
GetUIObjectOf
フォルダーの内容に関する基本情報は IShellFolder メソッドを通じて入手できますが、拡張機能によって Windows Explorer にさまざまな種類の追加情報を提供することもできます。 たとえば、フォルダーの内容やオブジェクトのショートカット メニューのアイコンを指定できます。 Windows Explorer は、 IShellFolder::GetUIObjectOf メソッドを呼び出して、フォルダーに含まれるオブジェクトに関する追加情報を取得しようとします。 Windows Explorer は、情報が必要なオブジェクトと、関連するインターフェイスの IID を指定します。 次に、フォルダー オブジェクトは、要求されたインターフェイスを公開し、インターフェイス ポインターを返すオブジェクトを作成します。
拡張機能によって、ユーザーがドラッグ アンド ドロップまたはクリップボードを使用してオブジェクトを転送できる場合、Windows Explorer は IShellFolder::GetUIObjectOf を呼び出して、 IDataObject または IDropTarget インターフェイスを要求します。 詳細については、「ドラッグアンドドロップとクリップボードを使用したシェル オブジェクトの転送」を参照してください。
Windows Explorer は、フォルダー自体に関する同じ種類の情報が必要な場合に、IShellFolder::CreateViewObject を呼び出します。
BindToObject
ユーザーが拡張機能のサブフォルダーの 1 つを開こうとすると、Windows Explorer は IShellFolder::BindToObject メソッドを呼び出します。 riid が IID_IShellFolder に設定されている場合、サブフォルダーを表すフォルダー オブジェクトを作成して初期化し、オブジェクトの IShellFolder インターフェイスを返す必要があります。
Note
現在、Windows Explorer は、 IShellFolder インターフェイスを要求するためにのみこのメソッドを呼び出します。 ただし、常にそうなるとは限りません。 続行する前に、必ず riid の値を確認してください。
GetDisplayNameOf
Windows Explorer は、 IShellFolder::GetDisplayNameOf メソッドを呼び出して、フォルダーのオブジェクトの 1 つの PIDL を名前に変換します。 その PIDL はオブジェクトの親フォルダーを基準にする必要があります。 つまり、単一の非NULL SHITEMID 構造を含める必要があります。 オブジェクトに名前を付ける方法は複数あるため、Windows Explorer は、 uFlags パラメータに 1 つ以上の SHGDNF フラグを設定することによって名前の種類を指定します。 名前をフォルダーに相対的にするかデスクトップに相対的にするかを指定するために、2 つの値 SHGDN_NORMAL または SHGDN_INFOLDER のいずれかが設定されます。 他の 3 つの値 SHGDN_FOREDITING、 SHGDN_FORADDRESSBAR、または SHGDN_FORPARSING のいずれかを設定して、名前の使用目的を指定できます。
名前は STREET 構造の形式で返す必要があります。 SHGDN_FOREDITING、 SHGDN_FORADDRESSBAR、および >SHGDN_FORPARSING が設定されていない場合は、オブジェクトの表示名を返します。 SHGDN_FORPARSING フラグが設定されている場合、Windows Explorer は解析名を要求しています。 解析名は、名前空間階層内の現在のフォルダーより 1 レベル以上下にある場合でも、オブジェクトの PIDL を取得するために >IShellFolder::ParseDisplayName に渡されます。 たとえば、ファイル システム オブジェクトの解析名はそのパスです。 ファイル システム内の任意のオブジェクトの完全修飾パスをデスクトップの IShellFolder::ParseDisplayName メソッドに渡すと、オブジェクトの完全修飾 PIDL が返されます。
解析名はテキスト文字列ですが、必ずしも表示名を含める必要はありません。 >IShellFolder::ParseDisplayName が呼び出されたときに最も効率的に機能するものに基づいて解析名を割り当てる必要があります。 たとえば、シェルの仮想フォルダーの多くはファイル システムの一部ではなく、完全修飾パスがありません。 代わりに、各フォルダーには GUID が割り当てられ、解析名は ::{GUID} の形式になります。 使用するスキームに関係なく、確実に「ラウンド トリップ」できる必要があります。たとえば、呼び出し元が解析名を IShellFolder::ParseDisplayName に渡してオブジェクトの PIDL を取得し、次にその PIDL を SHGDN_FORPARSING フラグを設定して IShellFolder::GetDisplayNameOf に渡す場合、呼び出し元は元の解析名を回復する必要があります。
GetAttributesOf
Windows Explorer は、 IShellFolder::GetAttributesOf メソッドを呼び出して、フォルダー オブジェクトに含まれる 1 つ以上の項目の属性を決定します。 cidl の値はクエリ内の項目の数を示し、 aPidl はそれらの PIDL のリストを指します。
一部の属性のテストには時間がかかることがあるため、Windows Explorer では通常、 rfgInOut に値を設定して、使用可能なフラグのサブセットにクエリを制限します。 メソッドでは、 rfgInOut でフラグが設定されている属性のみをテストする必要があります。 有効なフラグは設定したままにして、残りをクリアします。 クエリに複数の項目が含まれている場合は、すべての項目に適用されるフラグのみを設定します。
Note
アイテムを正しく表示するには、属性を適切に設定する必要があります。 たとえば、アイテムがサブフォルダーを含むフォルダーである場合は、 SFGAO_HASSUBFOLDER フラグを設定する必要があります。 そうしないと、Windows Explorer のツリー ビューで項目のアイコンの横に + が表示されません。
ParseDisplayName
IShellFolder::ParseDisplayName メソッドは、ある意味では IShellFolder::GetDisplayNameOf のミラー イメージです。 このメソッドの最も一般的な用途は、オブジェクトの解析名を関連する PIDL に変換することです。 解析名は、名前空間階層内のフォルダーの下にある任意のオブジェクトを参照できます。 返される PIDL は、メソッドを公開するフォルダー オブジェクトを基準としており、通常は完全修飾されていません。 つまり、PIDL には複数の SHITEMID 構造を含めることができますが、最初の構造はオブジェクト自体の構造か、フォルダーからオブジェクトへのパスの最初のサブフォルダーの構造のいずれかになります。 呼び出し元は、オブジェクトの完全修飾 PIDL を取得するために、この PIDL をフォルダーの完全修飾 PIDL に追加する必要があります。
IShellFolder::ParseDisplayName を呼び出してオブジェクトの属性を要求することもできます。 適用可能なすべての属性を決定するには時間がかかる可能性があるため、呼び出し元は、呼び出し元が関心のある情報を表す SFGAO_XXX フラグのみを設定します。 オブジェクトに対してどの属性が当てはまるかを判断し、残りのフラグをクリアする必要があります。
IEnumIDList インターフェイス
Windows Explorer は、フォルダーに含まれるオブジェクトを列挙する必要がある場合、 IShellFolder::EnumObjects を呼び出します。 フォルダー オブジェクトは、 IEnumIDList インターフェイスを公開する列挙オブジェクトを作成し、そのインターフェイス ポインターを返す必要があります。 Windows Explorer は通常、 IEnumIDList を使用して、フォルダーに含まれるすべてのオブジェクトの PIDL を列挙します。
IEnumIDList は標準の OLE 列挙インターフェイスであり、通常の方法で実装されます。 ただし、返される PIDL はフォルダーを基準とし、オブジェクトの SHITEMID 構造とターミネータのみを含む必要があることに注意してください。
オプションインターフェースの実装
拡張機能のフォルダー オブジェクトがサポートできるオプションの Shell インターフェイスがいくつかあります。 >IExtractIcon など、その多くを使用すると、ユーザーが拡張機能を表示する方法のさまざまな側面をカスタマイズできます。 IDataObject などの他のオブジェクトを使用すると、拡張機能でドラッグ アンド ドロップなどの機能をサポートできます。
オプションのインターフェースはいずれもフォルダー オブジェクトによって直接公開されません。 代わりに、Windows Explorer は、次の 2 つの IShellFolder メソッドのいずれかを呼び出してインターフェイスを要求します。
- Windows Explorer は、フォルダー オブジェクトの IShellFolder::GetUIObjectOf を呼び出して、フォルダーに含まれるオブジェクトの 1 つに対するインターフェイスを要求します。
- Windows Explorer は、フォルダー オブジェクトの IShellFolder::CreateViewObject を呼び出して、フォルダー自体のインターフェイスを要求します。
情報を提供するために、フォルダー オブジェクトは、要求されたインターフェイスを公開し、インターフェイス ポインターを返すオブジェクトを作成します。 その後、Windows Explorer はそのインターフェイスを呼び出して必要な情報を取得します。 このセクションでは、最も一般的に使用されるオプション インターフェースについて説明します。
IExtractIcon
Windows Explorer は、フォルダーの内容を表示する前に IExtractIcon インターフェイスを要求します。 このインターフェースを使用すると、拡張機能はフォルダーに含まれるオブジェクトのカスタム アイコンを指定できます。 それ以外の場合は、標準のファイルおよびフォルダー アイコンが使用されます。 カスタム アイコンを提供するには、 IExtractIcon を公開するアイコン抽出オブジェクトを作成し、そのインターフェイスへのポインターを返します。 詳細については、 IExtractIcon リファレンス ドキュメントまたは アイコン ハンドラーの作成を参照してください。
IContextMenu
ユーザーがオブジェクトを右クリックすると、Windows Explorer は IContextMenu インターフェイスを要求します。 オブジェクトにショートカット メニューを提供するには、メニュー ハンドラー オブジェクトを作成し、その IContextMenu インターフェイスを返します。
メニュー ハンドラー オブジェクトを作成する手順は、メニュー ハンドラー シェル拡張を作成する手順と非常に似ています。 詳細については、 コンテキスト メニュー ハンドラーの作成 または IContextMenu、IContextMenu2、または IContextMenu3 リファレンスを参照してください。
IQueryInfo
Windows Explorer は、情報ヒントのテキスト文字列を取得するために IQueryInfo インターフェイスを呼び出します。
IDataObject と IDropTarget
オブジェクトが Windows Explorer によって表示される場合、フォルダー オブジェクトには、ユーザーがオブジェクトの切り取り、コピー、またはドラッグを試みていることを直接知る方法がありません。 代わりに、Windows Explorer は IDataObject インターフェイスを要求します。 オブジェクトを転送できるようにするには、データ オブジェクトを作成し、その IDataObject インターフェイスへのポインターを返します。
同様に、ユーザーは、アイコンやアドレス バーのパスなど、オブジェクトの 1 つの Windows Explorer 表現にデータ オブジェクトをドロップしようとする場合があります。 次に、Windows Explorer は IDropTarget インターフェイスを要求します。 データ オブジェクトを削除できるようにするには、 IDropTarget インターフェイスを公開するオブジェクトを作成し、インターフェイス ポインターを返します。
データ転送の処理は、名前空間拡張を記述する際の難しい側面の 1 つです。 詳細については、「ドラッグ アンド ドロップとクリップボードを使用したシェル オブジェクトの転送」を参照してください。
デフォルトのシェル フォルダー ビュー実装の操作
デフォルトのシェル フォルダー ビュー オブジェクト (DefView) を使用するデータ ソースは、次のインターフェイスを実装する必要があります。
オプションで、 IPersistFolder3を実装することもできます。