基本的なフォルダー オブジェクト インターフェイスの実装

名前空間拡張機能を実装する手順は、他のインプロセス コンポーネント オブジェクト モデル (COM) オブジェクトの場合と似ています。 すべての拡張機能は、ツリー ビューに拡張機能のフォルダーを表示するために必要な基本情報を Windows エクスプローラーに提供する 3 つのプライマリ インターフェイスをサポートする必要があります。 ただし、Windows エクスプローラーの機能を最大限に活用するには、拡張機能で、ショートカット メニューやドラッグ アンド ドロップなどのより高度な機能をサポートする 1 つ以上のオプション インターフェイスを公開し、フォルダー ビューを提供する必要もあります。

このドキュメントでは、Windows エクスプローラーが拡張機能の内容に関する情報を呼び出すプライマリ インターフェイスと省略可能なインターフェイスを実装する方法について説明します。 フォルダー ビューを実装する方法と Windows エクスプローラーをカスタマイズする方法については、「フォルダー ビューの実装」を参照してください。

基本的な実装と登録

インプロセス COM サーバーとして、DLL でいくつかの標準関数とインターフェイスを公開する必要があります。

これらの関数とインターフェイスは、他のほとんどの COM オブジェクトと同じ方法で実装されます。 詳細については、 COM のドキュメントを参照してください

拡張機能の登録

すべての COM オブジェクトと同様に、拡張機能のクラス識別子 (CLSID) GUID を作成する必要があります。 拡張機能の CLSID に対して という名前 HKEY_CLASSES_ROOT\CLSID のサブキーを作成して、オブジェクトを登録します。 DLL はインプロセス サーバーとして登録する必要があり、アパートメント スレッド モデルを指定する必要があります。 拡張機能の CLSID キーにさまざまなサブキーと値を追加することで、拡張機能のルート フォルダーの動作をカスタマイズできます。

これらの値の一部は、仮想ジャンクション ポイントを持つ拡張機能にのみ適用されます。 これらの値は、ジャンクション ポイントがファイル システム フォルダーである拡張子には適用されません。 詳細については、「 名前空間拡張機能の場所の指定」を参照してください。 仮想ジャンクション ポイントを持つ拡張機能の動作を変更するには、拡張機能の CLSID キーに次の値の 1 つ以上を追加します。

  • WantsFORPARSING。 仮想ジャンクション ポイントを持つ拡張機能の解析名は、通常、::{GUID} という形式になります。 通常、この型の拡張機能には仮想アイテムが含まれます。 ただし、個人用ドキュメントなどの一部の拡張機能は、仮想ジャンクション ポイントがある場合でも、実際にはファイル システム フォルダーに対応しています。 拡張機能がこのようにファイル システム オブジェクトを表している場合は、WantsFORPARSING 値を設定できます。 その後、Windows エクスプローラー は、フォルダー オブジェクトの IShellFolder::GetDisplayNameOf メソッドを呼び出し、uFlagsSHGDN_FORPARSING に設定し、pidl を項目識別子リスト (PIDL) への 1 つの空のポインターに設定することで、ルート フォルダーの解析名を要求します。 空の PIDL にはターミネータのみが含まれます。 その後、メソッドはルート フォルダーの ::{GUID} 解析名を返す必要があります。
  • HideFolderVerbs。 HKEY_CLASSES_ROOT\フォルダーに登録されている動詞は、通常、すべての拡張機能に関連付けられます。 これらは拡張機能のショートカット メニューに表示され、 ShellExecute によって呼び出すことができます。 これらの動詞のいずれかが拡張機能に関連付けられるのを防ぐには、HideFolderVerbs 値を設定します。
  • HideAsDelete。 ユーザーが拡張機能を削除しようとすると、Windows エクスプローラーは代わりに拡張機能を非表示にします。
  • HideAsDeletePerUser。 この値は HideAsDelete と同じ効果を持ちますが、ユーザー単位です。 拡張機能は、削除を試みたユーザーに対してのみ非表示になります。 拡張機能は、他のすべてのユーザーに表示されます。
  • QueryForOverlay。 この値を設定して、ルート フォルダーのアイコンにアイコン オーバーレイを設定できることを示します。 フォルダー オブジェクトは 、IShellIconOverlay インターフェイスをサポートしている必要があります。 Windows エクスプローラーがルート フォルダーのアイコンを表示する前に、pidlItem が空の PIDL に設定されている 2 つの IShellIconOverlay メソッドのいずれかを呼び出してオーバーレイ アイコンを要求します。

残りの値とサブキーは、すべての拡張機能に適用されます。

  • 拡張機能のジャンクション ポイント フォルダーの表示名を指定するには、拡張機能の CLSID サブキーの既定値を適切な文字列に設定します。
  • カーソルがフォルダーの上に移動すると、通常、フォルダーの内容を説明するヒントが表示されます。 拡張機能のルート フォルダーのヒントを指定するには、拡張機能の CLSID キー のヒント REG_SZ 値を作成し、適切な文字列に設定します。
  • 拡張機能のルート フォルダーのカスタム アイコンを指定するには、 DefaultIcon という名前の拡張機能の CLSID サブキーのサブキーを作成します。 DefaultIcon の既定値を、アイコンを含むファイルの名前を含むREG_SZ値に設定し、その後にコンマ、マイナス記号、そのファイル内のアイコンのインデックスを続けます。
  • 既定では、拡張機能のルート フォルダーのショートカット メニューには、HKEY_CLASSES_ROOT\Folderで定義されている項目 含まれます。 適切なSFGAO_XXX フラグを設定すると、 DeleteRenameProperties の各項目が追加されます。 ルート フォルダーのショートカット メニューに他の項目を追加したり、 ファイルの種類と同じように既存の項目をオーバーライドしたりできます。 拡張機能の CLSID キーの下に シェル サブキーを作成し、「 ショートカット メニューの拡張」で説明されているようにコマンドを定義します。
  • ルート フォルダーのショートカット メニューをより柔軟に処理する方法が必要な場合は、 ショートカット メニュー ハンドラーを実装できます。 ショートカット メニュー ハンドラーを登録するには、拡張機能の CLSID キーの下に ShellEx キーを作成します。 従来のシェル拡張ハンドラーの作成と同様に 、ハンドラーの CLSID を登録します。
  • ルート フォルダーの Properties プロパティ シートにページを追加するには、フォルダーに SFGAO_HASPROPSHEET 属性を指定し、 プロパティ シート ハンドラーを実装します。 プロパティ シート ハンドラーを登録するには、拡張機能の CLSID キーの下に ShellEx キーを作成します。 従来のシェル拡張ハンドラーの作成と同様に 、ハンドラーの CLSID を登録します。
  • ルート フォルダーの属性を指定するには、拡張機能の CLSID サブキーに ShellFolder サブキーを追加します。 Attributes 値を作成し、 SFGAO_XXX フラグの 適切な組み合わせに設定します。

次の表に、ルート フォルダーでよく使用される属性の一覧を示します。

フラグ 説明
SFGAO_FOLDER 0x20000000 拡張機能のルート フォルダーには、1 つ以上の項目が含まれています。
SFGAO_HASSUBFOLDER 0x80000000 拡張機能のルート フォルダーには、1 つ以上のサブフォルダーが含まれています。 Windows エクスプローラーでは、フォルダー アイコンの横にプラス記号 ( + ) が配置されます。
SFGAO_CANDELETE 0x00000020 拡張機能のルート フォルダーは、ユーザーが削除できます。 フォルダーのショートカット メニューには 、[削除 ] 項目があります。 このフラグは、 いずれかの仮想フォルダーの下に配置されるジャンクション ポイントに対して設定する必要があります。
SFGAO_CANRENAME 0x00000010 拡張機能のルート フォルダーの名前は、ユーザーが変更できます。 フォルダーのショートカット メニューには、[ 名前の変更 ] 項目があります。
SFGAO_HASPROPSHEET 0x00000040 拡張機能のルート フォルダーには 、Properties プロパティ シートがあります。 フォルダーのショートカット メニューには 、[プロパティ ] 項目があります。 プロパティ シートを提供するには、 プロパティ シート ハンドラーを実装する必要があります。 前に説明したように、拡張機能の CLSID キーの下にハンドラーを登録します。

 

次の例は、表示名が MyExtension の拡張機能の CLSID レジストリ エントリを示しています。 拡張機能には、インデックスが 1 の拡張機能の DLL に含まれるカスタム アイコンがあります。 SFGAO_FOLDERSFGAO_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 の処理

シェル名前空間内のすべての項目には、一意の PIDL が必要です。 Windows エクスプローラーは、PIDL をルート フォルダーに割り当て、初期化中に拡張機能に値を渡します。 その後、拡張機能は、適切に構築された PIDL を各オブジェクトに割り当て、要求に応じて Windows エクスプローラーにそれらの PIDL を提供する役割を担います。 シェルが PIDL を使用して拡張機能のオブジェクトの 1 つを識別する場合、拡張機能は PIDL を解釈し、特定のオブジェクトを識別できる必要があります。 また、拡張機能では、 表示名解析名を 各オブジェクトに割り当てる必要があります。 PIDL は事実上すべてのフォルダー インターフェイスで使用されるため、拡張機能では通常、これらすべてのタスクを処理する単一 の PIDL マネージャー が実装されます。

PIDL という用語は、コンテキストに応じて 、ITEMIDLIST 構造体またはこのような構造体へのポインターの略です。 宣言されているように、 ITEMIDLIST 構造体には、1 つのメンバー である SHITEMID 構造体があります。 オブジェクトの ITEMIDLIST 構造体は、実際には 2 つ以上の SHITEMID 構造体のパックされた配列です。 これらの構造体の順序は、c:\MyDirectory\MyFile がファイル システム経由のパスを定義するのとほぼ同じ方法で、名前空間を通るパスを定義します。 通常、オブジェクトの PIDL は、名前空間パスを定義するフォルダーに対応する一連の SHITEMID 構造体と、オブジェクトの SHITEMID 構造体の後にターミネータで構成されます。

ターミネータは、CB メンバーが NULL に設定された、SHITEMID 構造体です。 オブジェクトの PIDL 内の 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 値をオブジェクトに割り当てる任意のスキームを使用できます。 唯一の要件は、同じ値を持つ同じフォルダーに 2 つのオブジェクトを含めることはできません。 ただし、パフォーマンス上の理由から、 SHITEMID 構造体は DWORD に合わせて配置する必要があります。 言い換えると、cb が 4 の整数倍数になるように abID 値を構築する必要があります。

通常、 abID は拡張定義構造体を指します。 この構造体は、オブジェクトの ID に加えて、オブジェクトの型や属性など、さまざまな関連情報を保持するためによく使用されます。 拡張機能のフォルダー オブジェクトを使用すると、PIDL に対してクエリを実行する必要なく、情報をすばやく抽出できます。

注意

PIDL のデータ構造を設計する際の最も重要な側面の 1 つは、構造を永続化および転送可能にすることです。 PIDL のコンテキストでは、これらの用語の意味は次のとおりです。

  • 永続。 システムは、ショートカット ファイルなど、さまざまな種類の長期ストレージに PID を配置する場合が多いです。 その後、システムの再起動後に、これらの PID を後でストレージから回復できます。 ストレージから回復された PIDL は、引き続き有効であり、拡張機能にとって意味のあるものでなければなりません。 この要件は、たとえば、PIDL 構造体でポインターやハンドルを使用しないことを意味します。 この種類のデータを含む PIDL は、システムが後でストレージから回復する場合、通常は意味がありません。
  • トランス。 PIDL は、あるコンピューターから別のコンピューターに転送される場合に意味を持つ必要があります。 たとえば、PIDL をショートカット ファイルに書き込み、フロッピー ディスクにコピーして、別のコンピューターに転送することができます。 その PIDL は、2 台目のコンピューターで実行されている拡張機能にとって意味があるはずです。 たとえば、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 メンバーは、オブジェクトの種類を示す拡張定義値です。 この例では、 フォルダーの場合は dwTypeTRUE 、それ以外の場合は FALSE に設定されています。 このメンバーを使用すると、たとえば、オブジェクトがフォルダーであるかどうかを迅速に判断できます。 wszDisplayName メンバーには、オブジェクトの表示名が含まれています。 同じフォルダー内の 2 つの異なるオブジェクトに同じ表示名を割り当てないため、表示名もオブジェクト ID として機能します。 この例では、 WSzDisplayName を 40 文字に設定して 、SHITEMID 構造体が DWORD にアラインされることを保証します。 PIDL のサイズを制限するには、代わりに可変長文字配列を使用し、それに応じて cb の値を調整します。 構造体の DWORD アラインメントを維持するのに十分な '\0' 文字で表示文字列を埋め込みます。 構造体に配置するのに役立つその他のメンバーには、オブジェクトのサイズ、属性、または解析名が含まれます。

PIDL の構築

オブジェクトに対して SHITEMID 構造体を定義したら、それらを使用して PIDL を構築できます。 PIDL はさまざまな目的で構築できますが、ほとんどのタスクでは 2 種類の PIDL のいずれかを使用します。 最も単純な単一レベルの PIDL は、親フォルダーを基準にしてオブジェクトを識別します。 この種類の PIDL は、 多くの IShellFolder メソッドで使用されます。 単一レベルの PIDL には、オブジェクトの SHITEMID 構造体の後にターミネータが含まれます。 完全修飾 PIDL は、デスクトップからオブジェクトへの名前空間階層のパスを定義します。 この種類の PIDL はデスクトップから始まり、パス内の各フォルダーに 1 つの SHITEMID 構造体が含まれており、その後に オブジェクトとターミネータが続きます。 完全修飾 PIDL は、シェル名前空間全体内のオブジェクトを一意に識別します。

PIDL を構築する最も簡単な方法は、 ITEMIDLIST 構造体自体を直接操作することです。 ITEMIDLIST 構造体を作成しますが、すべての SHITEMID 構造体を保持するのに十分なメモリを割り当てます。 この構造体のアドレスは、最初の SHITEMID 構造体を指します。 この初期構造体のメンバーの値を定義し、必要な数の 追加の SHITEMID 構造体を適切な順序で追加します。 次の手順では、単一レベルの PIDL を作成する方法について説明します。 これには、MYPIDLDATA 構造体の後にターミネータが続く 2 つの SHITEMID 構造体が含まれています。

  1. COTaskMemAlloc 関数を使用して、PIDL のメモリを割り当てます。 プライベート データに十分なメモリと、ターミネータ用の USHORT (2 バイト) を割り当てます。 結果を LPMYPIDLDATA にキャストします。
  2. 最初の MYPIDLDATA 構造体の cb メンバーを、その構造体のサイズに設定します。 この例では、 cb を sizeof(MYPIDLDATA) に設定します。 可変長構造体を使用する場合は、cb の値を計算する必要 があります
  3. プライベート データ メンバーに適切な値を割り当てます。
  4. 次の SHITEMID 構造体のアドレスを計算します。 現在の MYPIDLDATA 構造体のアドレスを LPBYTE にキャストし、手順 3 で決定した cb の値にその値を追加します。
  5. この場合、次の SHITEMID 構造体はターミネータです。 構造体の cb メンバーを 0 に設定します。

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 内の最初の 1 つ以上の SHITEMID 構造体が、Shell 名前空間の拡張機能の外部にあるオブジェクトに属している可能性があるということです。 これらの構造体の abID メンバーの意味を解釈する方法はありません。 拡張機能で行う必要がある操作は、ルート フォルダーに対応する構造体に到達するまで、 SHITEMID 構造体の一覧を "ウォーク" することです。 それ以降は、 SHITEMID 構造体内の情報を解釈する方法がわかります。

PIDL をウォークするには、最初の cb 値を取得し、PIDL のアドレスに追加して、ポインターを次の SHITEMID 構造体の先頭に進めます。 その後、その構造体の cb メンバーを指します。これを使用して、ポインターを次の SHITEMID 構造体の先頭に進めることができます。などです。 ポインターを進めるたびに、 SHITEMID 構造体を調べて、拡張機能の名前空間のルートに到達したかどうかを判断します。

プライマリ インターフェイスの実装

すべての COM オブジェクトと同様に、拡張機能の実装は、主にインターフェイスのコレクションを実装する問題です。 このセクションでは、すべての拡張機能で実装する必要がある 3 つの主要なインターフェイスについて説明します。 これらは初期化に使用され、Windows エクスプローラーに拡張機能の内容に関する基本情報を提供するために使用されます。 これらのインターフェイスと フォルダー ビューは、機能拡張に必要なすべてです。 ただし、Windows エクスプローラーの機能を完全に活用するために、ほとんどの拡張機能では、1 つ以上のオプション インターフェイスも実装されます。

IPersistFolder インターフェイス

IPersistFolder インターフェイスは、新しいフォルダー オブジェクトを初期化するために呼び出されます。 IPersistFolder::Initialize メソッドは、新しいオブジェクトに完全修飾 PIDL を割り当てます。 後で使用するために、この PIDL を格納します。 たとえば、フォルダー オブジェクトは、この PIDL を使用して、オブジェクトの子の完全修飾 PIDL を構築する必要があります。 フォルダー オブジェクトの作成者は 、IPersist::GetClassID を呼び出して、オブジェクトの CLSID を要求することもできます。

通常、フォルダー オブジェクトは、親フォルダーの IShellFolder::BindToObject メソッドによって作成および初期化されます。 ただし、ユーザーが拡張機能を参照すると、Windows エクスプローラーは拡張機能のルート フォルダー オブジェクトを作成して初期化します。 ルート フォルダー オブジェクトが IPersistFolder::Initialize を介して受け取る PIDL には、デスクトップからルート フォルダーへのパスが含まれており、拡張機能の完全修飾 PIDL を構築する必要があります。

IShellFolder インターフェイス

シェルは、拡張機能をフォルダー オブジェクトの階層順のコレクションとして扱います。 IShellFolder インターフェイスは、拡張機能の実装の中核です。 フォルダー オブジェクトを表し、フォルダーの内容を表示するために必要な情報の多くを Windows エクスプローラーに提供します。

通常、IShellFolder は、フォルダー オブジェクトによって直接公開される IPersistFolder 以外の唯一のフォルダー インターフェイスです。 Windows エクスプローラーでは、さまざまな必須インターフェイスと省略可能なインターフェイスを使用してフォルダーの内容に関する情報を取得しますが、IShellFolder を使用してこれらのインターフェイスへのポインターを取得します。

Windows エクスプローラーは、拡張機能のルート フォルダーの CLSID をさまざまな方法で取得します。 詳細については、「名前空間拡張機能の場所を指定する」または「名前空間拡張機能のSelf-Contained ビューを表示する」を参照してください。 Windows エクスプローラーでは、その CLSID を使用してルート フォルダーのインスタンスを作成および初期化し、IShellFolder インターフェイスのクエリを実行します。 拡張機能は、ルート フォルダーを表すフォルダー オブジェクトを作成し、オブジェクトの IShellFolder インターフェイスを 返します。 拡張機能と Windows エクスプローラー間の相互作用の残りの多くは、IShellFolder を介して行われます。 Windows エクスプローラーは IShellFolder を呼び出して次の処理を行います。

  • ルート フォルダーの内容を列挙できるオブジェクトを要求します。
  • ルート フォルダーの内容に関するさまざまな種類の情報を取得します。
  • 省略可能なインターフェイスのいずれかを公開する オブジェクトを要求します。 その後、これらのインターフェイスに対して、アイコンやショートカット メニューなどの追加情報を照会できます。
  • ルート フォルダーのサブフォルダーを表すフォルダー オブジェクトを要求します。

ユーザーがルート フォルダーのサブフォルダーを開くと、Windows エクスプローラーは IShellFolder::BindToObject を呼び出します。 拡張機能は、サブフォルダーを表す新しいフォルダー オブジェクトを作成して初期化し、その IShellFolder インターフェイスを返します。 その後、Windows エクスプローラーは、シェル名前空間内の他の場所に移動するか、Windows エクスプローラーを閉じるかをユーザーが決定するまで、さまざまな種類の情報に対してこのインターフェイスを呼び出します。

このセクションの残りの部分では、より重要な IShellFolder メソッドとその実装方法について簡単に説明します。

EnumObjects

ツリー ビューにフォルダーの内容を表示する前に、Windows エクスプローラーはまず、IShellFolder::EnumObjects メソッドを呼び出して、フォルダーに含まれるものを特定する必要があります。 このメソッドは、 IEnumIDList インターフェイスを公開し、そのインターフェイス ポインターを返す標準の OLE 列挙オブジェクトを作成します。 IEnumIDList インターフェイスを使用すると、Windows エクスプローラーは フォルダーに含まれるすべてのオブジェクトの PIDL を取得できます。 これらの PID は、フォルダーに含まれるオブジェクトに関する情報を取得するために使用されます。 詳細については、「 IEnumIDList インターフェイス」を参照してください。

注意

IEnumIDList::Next メソッドは、親フォルダーを基準とした PIDL のみを返す必要があります。 PIDL には、オブジェクトの SHITEMID 構造体とターミネータのみが含まれている必要があります。

 

CreateViewObject

フォルダーの内容が表示される前に、Windows エクスプローラーはこのメソッドを呼び出して、IShellView インターフェイスへのポインターを要求します。 このインターフェイスは、フォルダー ビューを管理するために Windows エクスプローラーによって使用されます。 フォルダー ビュー オブジェクトを作成し、その IShellView インターフェイスを返します。

IShellFolder::CreateViewObject メソッドは、フォルダー自体に対して IContextMenu などの省略可能なインターフェイスの 1 つを要求するためにも呼び出されます。 このメソッドの実装では、要求されたインターフェイスを公開し、インターフェイス ポインターを返す オブジェクトを作成する必要があります。 Windows エクスプローラーフォルダーに含まれるオブジェクトの 1 つに対してオプションのインターフェイスが必要な場合は、IShellFolder::GetUIObjectOf を呼び出します。

GetUIObjectOf

フォルダーの内容に関する基本情報は IShellFolder メソッドを通じて入手できますが、拡張機能ではさまざまな種類の追加情報を Windows エクスプローラーに提供することもできます。 たとえば、フォルダーまたはオブジェクトのショートカット メニューの内容のアイコンを指定できます。 Windows エクスプローラーは IShellFolder::GetUIObjectOf メソッドを呼び出して、フォルダーに含まれるオブジェクトに関する追加情報の取得を試みます。 Windows エクスプローラーは、情報を必要とするオブジェクトと、関連するインターフェイスの IID を指定します。 フォルダー オブジェクトは、要求されたインターフェイスを公開し、インターフェイス ポインターを返す オブジェクトを作成します。

拡張機能でユーザーがドラッグ アンド ドロップまたはクリップボードを使用してオブジェクトを転送できる場合、Windows エクスプローラーは IShellFolder::GetUIObjectOf を呼び出して IDataObject または IDropTarget インターフェイスを要求します。 詳細については、「 ドラッグ アンド ドロップとクリップボードを使用したシェル オブジェクトの転送」を参照してください

Windows エクスプローラーは、フォルダー自体に関する同じ種類の情報が必要な場合に IShellFolder::CreateViewObject を呼び出します。

BindToObject

Windows エクスプローラーは、ユーザーが拡張機能のサブフォルダーのいずれかを開こうとしたときに、IShellFolder::BindToObject メソッドを呼び出します。 riid が IID_IShellFolder に設定されている場合は、サブフォルダーを表すフォルダー オブジェクトを作成して初期化し、オブジェクトの IShellFolder インターフェイスを返す必要があります。

注意

現時点では、Windows エクスプローラーはこのメソッドを呼び出して IShellFolder インターフェイスを要求するだけです。 ただし、これが常に当てはまるとは想定しないでください。 続行する前に、常に riid の値をチェックする必要があります。

 

GetDisplayNameOf

Windows エクスプローラーは IShellFolder::GetDisplayNameOf メソッドを呼び出して、フォルダーのオブジェクトの 1 つの PIDL を名前に変換します。 その PIDL は、オブジェクトの親フォルダーに対する相対パスである必要があります。 つまり、NULL 以外の 1 つの SHITEMID 構造体を含む必要があります。 オブジェクトに名前を付ける方法は複数あるため、Windows エクスプローラー では、uFlags パラメーターに 1 つ以上の SHGDNF フラグを設定して名前の種類を指定します。 SHGDN_NORMALまたはSHGDN_INFOLDERの 2 つの値のいずれかを設定して、名前をフォルダーに対して相対的にするか、デスクトップに対する相対値にするかを指定します。 他の 3 つの値 ( SHGDN_FOREDITINGSHGDN_FORADDRESSBARまたはSHGDN_FORPARSING) のいずれかを設定して、名前の用途を指定できます。

名前は STRRET 構造体の形式で返す必要があります。 SHGDN_FOREDITINGSHGDN_FORADDRESSBARSHGDN_FORPARSINGが設定されていない場合は、オブジェクトの表示名を返します。 SHGDN_FORPARSING フラグが設定されている場合、Windows エクスプローラーは解析名を要求しています。 解析名は IShellFolder::P arseDisplayName に渡され、オブジェクトの PIDL が取得されます。ただし、名前空間階層内の現在のフォルダーの下に 1 つ以上のレベルが配置されている可能性があります。 たとえば、ファイル システム オブジェクトの解析名はそのパスです。 ファイル システム内の任意のオブジェクトの完全修飾パスをデスクトップの IShellFolder::P arseDisplayName メソッドに渡すと、オブジェクトの完全修飾 PIDL が返されます。

名前の解析はテキスト文字列ですが、必ずしも表示名を含める必要はありません。 IShellFolder::P arseDisplayName が呼び出されたときに最も効率的に動作するものに基づいて、解析名を割り当てる必要があります。 たとえば、シェルの仮想フォルダーの多くはファイル システムの一部ではなく、完全修飾パスを持っていません。 代わりに、各フォルダーには GUID が割り当てられ、解析名は ::{GUID} という形式になります。 使用するスキームに関係なく、確実に "ラウンド トリップ" できる必要があります。たとえば、呼び出し元が IShellFolder::P arseDisplayName に解析名を渡してオブジェクトの PIDL を取得し、その PIDL を SHGDN_FORPARSING フラグが設定された IShellFolder::GetDisplayNameOf に渡した場合、呼び出し元は元の解析名を回復する必要があります。

GetAttributesOf

Windows エクスプローラーは IShellFolder::GetAttributesOf メソッドを呼び出して、フォルダー オブジェクトに含まれる 1 つ以上のアイテムの属性を決定します。 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 構造体とターミネータのみを含んでいる必要があります。

省略可能なインターフェイスの実装

拡張機能のフォルダー オブジェクトでサポートできるオプションのシェル インターフェイスがいくつかあります。 IExtractIcon などの多くは、ユーザーが拡張機能を表示する方法のさまざまな側面をカスタマイズできます。 IDataObject などのその他の機能を使用すると、拡張機能でドラッグ アンド ドロップなどの機能をサポートできます。

省略可能なインターフェイスは、フォルダー オブジェクトによって直接公開されません。 代わりに、Windows エクスプローラーは 2 つの IShellFolder メソッドのいずれかを呼び出してインターフェイスを要求します。

  • Windows エクスプローラー は、フォルダー オブジェクトの IShellFolder::GetUIObjectOf を呼び出して、フォルダーに含まれるオブジェクトの 1 つに対するインターフェイスを要求します。
  • Windows エクスプローラーは、フォルダー オブジェクトの IShellFolder::CreateViewObject を呼び出して、フォルダー自体のインターフェイスを要求します。

情報を提供するために、フォルダー オブジェクトは、要求されたインターフェイスを公開し、インターフェイス ポインターを返す オブジェクトを作成します。 Windows エクスプローラーそのインターフェイスを呼び出して、必要な情報を取得します。 このセクションでは、最もよく使用される省略可能なインターフェイスについて説明します。

IExtractIcon

Windows エクスプローラーは、フォルダーの内容を表示する前に IExtractIcon インターフェイスを要求します。 インターフェイスを使用すると、拡張機能で、 フォルダーに含まれるオブジェクトのカスタム アイコンを指定できます。 それ以外の場合は、標準のファイルとフォルダーのアイコンが使用されます。 カスタム アイコンを提供するには、 IExtractIcon を公開し、そのインターフェイスへのポインターを返すアイコン抽出オブジェクトを作成します。 詳細については、 IExtractIcon リファレンス ドキュメントまたは アイコン ハンドラーの作成に関するページを参照してください。

IContextMenu

ユーザーがオブジェクトを右クリックすると、Windows エクスプローラーは IContextMenu インターフェイスを要求します。 オブジェクトのショートカット メニューを提供するには、メニュー ハンドラー オブジェクトを作成し、その IContextMenu インターフェイスを 返します。

メニュー ハンドラー オブジェクトを作成する手順は、メニュー ハンドラーシェル拡張機能の作成に使用されるものとよく似ています。 詳細については、「コンテキスト メニュー ハンドラーの作成」または「IContextMenu、IContextMenu2、または IContextMenu3 リファレンス」を参照してください。

IQueryInfo

Windows エクスプローラー は、IQueryInfo インターフェイスを呼び出してヒント テキスト文字列を取得します。

IDataObject と IDropTarget

Windows エクスプローラーによってオブジェクトが表示される場合、フォルダー オブジェクトには、ユーザーがオブジェクトの切り取り、コピー、またはドラッグを試みている場合を知る直接的な方法はありません。 代わりに、Windows エクスプローラーは IDataObject インターフェイスを要求します。 オブジェクトを転送できるようにするには、データ オブジェクトを作成し、その IDataObject インターフェイスへのポインターを返します。

同様に、ユーザーは、アイコンやアドレス バーのパスなど、オブジェクトの 1 つを表エクスプローラーデータ オブジェクトを Windows にドロップしようとする場合があります。 その後、Windows エクスプローラーは IDropTarget インターフェイスを要求します。 データ オブジェクトを削除できるようにするには、 IDropTarget インターフェイスを公開する オブジェクトを作成し、インターフェイス ポインターを返します。

データ転送の処理は、名前空間拡張機能を記述する場合の複雑な側面の 1 つです。 詳細については、「 ドラッグ アンド ドロップとクリップボードを使用したシェル オブジェクトの転送」を参照してください

既定のシェル フォルダー ビューの実装の操作

既定のシェル フォルダー ビュー オブジェクト (DefView) を使用するデータ ソースでは、次のインターフェイスを実装する必要があります。

必要に応じて、 IPersistFolder3 を実装することもできます。