シェル データ オブジェクト
データ オブジェクトは、すべてのシェル データ転送の中心です。 これは主に、転送されたデータを保持するコンテナーです。 ただし、ターゲットはデータ オブジェクトと通信して、最適化された移動などの特殊な種類のシェル データ転送を容易にすることもできます。 このトピックでは、シェル データ オブジェクトの動作方法、ソースによって構築される方法、およびそれらがターゲットによってどのように処理されるかについて一般的に説明します。 データ オブジェクトを使用してさまざまな種類のシェル データを転送する方法の詳細については、「シェル データ転送シナリオの処理」を参照してください。
- データ オブジェクトの動作 の
- ソースがデータ オブジェクト を作成する方法を する
- グローバル メモリ オブジェクトをデータ オブジェクト に追加する方法
- IDataObject の実装の
- IDropSource の実装の
-
ターゲットがデータ オブジェクト を処理する方法
- データ オブジェクト からシェル データを抽出する
- IDropTarget の実装の
- ドラッグ アンド ドロップ ヘルパー オブジェクト を使用した
データ オブジェクトのしくみ
データ オブジェクトは、ターゲットにデータを転送するためにデータ ソースによって作成されるコンポーネント オブジェクト モデル (COM) オブジェクトです。 通常、複数の項目のデータが含まれます。 この方法には 2 つの理由があります。
- データ オブジェクトを使用してほぼすべての種類のデータを転送できますが、ソースは通常、ターゲットが受け入れ可能なデータの種類を認識しません。 たとえば、データは書式設定されたテキスト ドキュメントの一部である可能性があります。 ターゲットは複雑な書式設定情報を処理できる場合もありますが、ANSI テキストのみを受け入れることもできます。 このため、多くの場合、データ オブジェクトには複数の異なる形式の同じデータが含まれます。 ターゲットは、処理できる形式でデータを抽出できます。
- データ オブジェクトには、ソース データのバージョンではない補助データ項目を含めることもできます。 この種類のデータ項目は、通常、データ転送操作に関する追加情報を提供します。 たとえば、シェルは補助データ項目を使用して、ファイルをコピーまたは移動するかどうかを示します。
クリップボードの形式
データ オブジェクト内のデータの各項目には、通常、クリップボード形式と呼ばれる、関連付けられた形式があります。 Winuser.h で宣言された、一般的に使用されるデータ型に対応する標準のクリップボード形式がいくつかあります。 クリップボード形式は整数ですが、通常、XXXCF_形式を持つ同等の名前で参照されます。 たとえば、ANSI テキストのクリップボード形式はCF_TEXT。
アプリケーションでは、プライベート形式を定義することで、使用可能なクリップボード形式の範囲を拡張できます。 プライベート形式を定義するために、アプリケーションは形式を識別する文字列 RegisterClipboardFormat を呼び出します。 関数が返す符号なし整数は、標準のクリップボード形式と同様に使用できる有効な書式値です。 ただし、使用するには、ソースとターゲットの両方で形式を登録する必要があります。 1 つの例外 (CF_HDROP) では、シェル データの転送に使用されるクリップボード形式はプライベート形式として定義されます。 使用するには、ソースとターゲットによって登録されている必要があります。 使用可能なシェル クリップボード形式の詳細については、「シェル クリップボードの形式」を参照してください。
一部の例外がありますが、通常、データ オブジェクトには、サポートされているクリップボード形式ごとに 1 つのデータ項目のみが含まれます。 この形式とデータの 1 対 1 の相関関係により、関連付けられたデータ項目の識別子として書式値を使用できます。 実際、データ オブジェクトの内容について説明する場合、データの特定の項目は通常、"書式" と呼ばれ、その形式名で参照されます。 たとえば、「CF_TEXT形式を抽出する...」などの語句です。は、通常、データ オブジェクトの ANSI テキスト データ項目について説明するときに使用されます。
ドロップ ターゲットがデータ オブジェクトへのポインターを受け取ると、ドロップ ターゲットは使用可能な形式を列挙して、使用可能なデータの種類を決定します。 次に、使用可能な形式の 1 つ以上を要求し、データを抽出します。 ターゲットがデータ オブジェクトからシェル データを抽出する具体的な方法は、形式によって異なります。これについては、ターゲットがデータ オブジェクト を処理する方法で詳しく説明します。
単純なクリップボード データ転送では、データはグローバル メモリ オブジェクトに配置されます。 そのオブジェクトのアドレスは、その形式と共にクリップボードに配置されます。 クリップボード形式は、関連付けられているアドレスで検索されるデータの種類をターゲットに通知します。 簡単なクリップボード転送は簡単に実装できます。
- データ オブジェクトは、データを転送するはるかに柔軟な方法を提供します。
- データ オブジェクトは、大量のデータを転送する場合に適しています。
- ドラッグ アンド ドロップ操作でデータを転送するには、データ オブジェクトを使用する必要があります。
このような理由から、すべてのシェル データ転送ではデータ オブジェクトが使用されます。 データ オブジェクトでは、クリップボード形式は直接使用されません。 代わりに、データ項目はクリップボード形式の一般化、FORMATETC 構造体で識別されます。
FORMATETC 構造体
FORMATETC 構造体は、クリップボード形式の拡張バージョンです。 シェル データ転送に使用される FORMATETC 構造体には、次の特性があります。
データ項目は、cfFormat メンバーのクリップボード形式で引き続き識別されます。
データ転送は、グローバル メモリ オブジェクトに限定されません。 タイミングされた メンバーは、関連付けられた STGMEDIUM構造体に含まれるデータ転送メカニズム示すために使用されます。 TYMED_XXX 値のいずれかに設定されます。
シェルは、lIndex メンバーとその CFSTR_FILECONTENTS 形式を使用して、データ オブジェクトに 1 つの形式ごとに複数のデータ項目を格納できるようにします。 この形式の使用方法については、「シェル データ転送シナリオの処理」の「CFSTR_FILECONTENTS形式を使用してファイルからデータを抽出する 」セクション を参照してください。
dwAspect メンバーは通常、DVASPECT_CONTENTに設定されます。 ただし、Shlobj.h には、シェル データ転送に使用できる 3 つの値が定義されています。
価値 形容 DVASPECT_COPY 形式がデータのコピーを表していることを示すために使用されます。 DVASPECT_LINK 形式がデータへのショートカットを表していることを示すために使用されます。 DVASPECT_SHORTNAME CF_HDROP形式で使用され、名前が 8.3 形式に短縮されたファイル パスを要求します。 ptd メンバーはシェルデータ転送には使用されず、通常は NULL に設定されます。
STGMEDIUM 構造体
STGMEDIUM 構造体は、転送されるデータへのアクセスを提供します。 シェル データでは、次の 3 つのデータ転送メカニズムがサポートされています。
STGMEDIUM 構造体の タイミングされた メンバーは、データ転送メカニズムを識別する TYMED_XXX 値です。 2 番目のメンバーは、ターゲットがデータを抽出するために使用するポインターです。 ポインターは、の 値に応じて、さまざまな型のいずれかになります。 シェル データ転送に使用される 3 つの タイミングされた 値と、対応する STGMEDIUM メンバー名を次の表にまとめます。
tymed 値 | メンバー名 | 形容 |
---|---|---|
TYMED_HGLOBAL | hGlobal の | グローバル メモリ オブジェクトへのポインター。 このポインター型は、通常、少量のデータを転送するために使用されます。 たとえば、シェルはグローバル メモリ オブジェクトを使用して、ファイル名や URL などの短いテキスト文字列を転送します。 |
TYMED_ISTREAM | pstm を する | IStream インターフェイスへのポインター。 このポインター型は、TYMED_HGLOBALと比較して比較的少ないメモリを必要とするため、ほとんどのシェル データ転送に適しています。 また、TYMED_ISTREAMデータ転送メカニズムでは、ソースが特定の方法でデータを格納する必要はありません。 |
TYMED_ISTORAGE | pstg を する | IStorage インターフェイスへのポインター。 ターゲットは、インターフェイス メソッドを呼び出してデータを抽出します。 TYMED_ISTREAMと同様に、このポインター型は比較的少ないメモリを必要とします。 ただし、TYMED_ISTORAGEはTYMED_ISTREAMよりも柔軟性が低いため、一般的には使用されません。 |
ソースがデータ オブジェクトを作成する方法
ユーザーがシェル データ転送を開始すると、ソースはデータ オブジェクトを作成し、データと共に読み込む役割を担います。 プロセスの概要を次に示します。
- RegisterClipboardFormat 呼び出して、データ オブジェクトに含まれるシェル形式ごとに有効なクリップボード形式の値を取得します。 CF_HDROP は既に有効なクリップボード形式であり、登録する必要はありません。
- 転送する各形式について、関連付けられたデータをグローバル メモリ オブジェクトに配置するか、IStream または IStorageインターフェイスを介してそのデータへのアクセスを提供するオブジェクト作成します。 IStream および IStorage インターフェイスは、標準の COM 手法を使用して作成されます。 グローバル メモリ オブジェクトの処理方法については、「グローバル メモリ オブジェクトをデータ オブジェクトに追加する方法」を参照してください。
- FORMATETC作成し、各形式の STGMEDIUM構造体をします。
- データ オブジェクトをインスタンス化します。
- サポートされている各形式に対して IDataObject::SetData メソッドを呼び出し、形式の FORMATETC と STGMEDIUM構造体を渡して、データ オブジェクトにデータ読み込みます。
- クリップボードのデータ転送では、OleSetClipboard呼び出して、データ オブジェクトの IDataObject インターフェイスへのポインターをクリップボードに配置します。 ドラッグ アンド ドロップ転送の場合は、DoDragDrop呼び出して、ドラッグ ループ を開始します。 IDataObject ポインターは、データがドロップされたときにドロップ 先に渡され、ドラッグ ループが終了します。
これで、データ オブジェクトをターゲットに転送する準備ができました。 クリップボードのデータ転送の場合、オブジェクトは、OleGetClipboard呼び出すことによって、ターゲットが要求するまで保持されます。 データ転送をドラッグ アンド ドロップする場合、データ オブジェクトは、データを表すアイコンを作成し、ユーザーがカーソルを移動すると移動します。 オブジェクトがドラッグ ループ内にある間、ソースは IDropSourceインターフェイスを介して状態情報を受け取ります。 詳細については、「IDropSourceの実装」を参照してください。
データ オブジェクトがターゲットによってクリップボードから取得された場合、ソースは通知を受け取らなくなります。 ドラッグ アンド ドロップ操作によってオブジェクトがターゲットにドロップされると、ドラッグ ループを開始するために呼び出された doDragDrop関数が返されます。
データ オブジェクトにグローバル メモリ オブジェクトを追加する方法
シェルのデータ形式の多くは、グローバル メモリ オブジェクトの形式です。 グローバル メモリ オブジェクトを含む形式を作成し、データ オブジェクトに読み込むには、次の手順に従います。
- FORMATETC 構造体を作成します。 cfFormat メンバーを適切なクリップボード形式の値に設定し、の メンバーをTYMED_HGLOBALに設定します。
- STGMEDIUM 構造体を作成します。 の メンバーをTYMED_HGLOBALに設定します。
- GlobalAlloc呼び出して、適切なサイズのメモリ ブロックを割り当てることで、グローバル メモリ オブジェクトを作成します。
- GlobalAllocによって返されるアドレスに転送するデータブロック割り当てます。
- グローバル メモリ オブジェクトのアドレスを、STGMEDIUM 構造体の hGlobal メンバーに割り当てます。
- IDataObject::SetData呼び出し、前の手順で作成した FORMATETC を渡し、STGMEDIUM構造体をして、データ オブジェクトに形式を読み込みます。
次のサンプル関数は、DWORD 値を含むグローバル メモリ オブジェクトを作成し、データ オブジェクトに読み込みます。 pdtobj パラメーターは、データ オブジェクトの IDataObject インターフェイスへのポインターです。cf はクリップボード形式の値、dw はデータ値です。
STDAPI DataObj_SetDWORD(IDataObject *pdtobj, UINT cf, DWORD dw)
{
FORMATETC fmte = {(CLIPFORMAT) cf,
NULL,
DVASPECT_CONTENT,
-1,
TYMED_HGLOBAL};
STGMEDIUM medium;
HRESULT hres = E_OUTOFMEMORY;
DWORD *pdw = (DWORD *)GlobalAlloc(GPTR, sizeof(DWORD));
if (pdw)
{
*pdw = dw;
medium.tymed = TYMED_HGLOBAL;
medium.hGlobal = pdw;
medium.pUnkForRelease = NULL;
hres = pdtobj->SetData(&fmte, &medium, TRUE);
if (FAILED(hres))
GlobalFree((HGLOBAL)pdw);
}
return hres;
}
IDataObject の実装
IDataObject は、データ オブジェクトのプライマリ インターフェイスです。 すべてのデータ オブジェクトで実装する必要があります。 ソースとターゲットの両方で、次のようなさまざまな目的で使用されます。
- データ オブジェクトへのデータの読み込み。
- データ オブジェクトからデータを抽出する。
- データ オブジェクトに含まれるデータの種類の決定。
- データ転送の結果に関するフィードバックをデータ オブジェクトに提供する。
IDataObject では、さまざまなメソッドがサポートされています。 このセクションでは、シェル データ オブジェクト、SetData 、EnumFormatEtc、GetData の 3 つの最も重要なメソッドを実装する方法について説明します。 その他のメソッドの詳細については、IDataObject リファレンスを参照してください。
SetData メソッド
IDataObject::SetData メソッドの主な機能は、ソースがデータ オブジェクトにデータを読み込むようにすることです。 ソースは、含める各形式に対して、形式を識別する FORMATETC 構造体と、データへのポインターを保持する STGMEDIUM 構造体を作成します。 次に、ソースはオブジェクトの IDataObject::SetData メソッドを呼び出し、形式の FORMATETC と STGMEDIUM 構造体 渡します。 メソッドは、ターゲットが IDataObject::GetData を呼び出してオブジェクトからデータを抽出するときに使用できるように、この情報を格納する必要があります。
ただし、ファイルを転送する場合、シェルは、転送する各ファイルの情報を個別の CFSTR_FILECONTENTS 形式に格納することがよくあります。 異なるファイルを区別するために、各ファイルの FORMATETC 構造体の lIndex メンバーは、特定のファイルを識別するインデックス値に設定されます。 IDataObject::SetData 実装では、lIndex メンバーによってのみ異なる複数のCFSTR_FILECONTENTS形式を格納できる必要があります。
カーソルがターゲット ウィンドウの上にある間、ターゲットは ドラッグ アンド ドロップ ヘルパー オブジェクト を使用してドラッグ イメージを指定できます。 ドラッグ アンド ドロップ ヘルパー オブジェクト IDataObject::SetData を呼び出して、プロセス間のサポートに使用されるデータ オブジェクトにプライベート形式を読み込みます。 ドラッグ アンド ドロップ ヘルパー オブジェクトをサポートするには、IDataObject::SetData 実装で任意のプライベート形式を受け入れて格納できる必要があります。
データが削除された後、一部の種類のシェル データ転送では、ターゲットが IDataObject::SetData呼び出して、ドロップ操作の結果に関する情報をデータ オブジェクトに提供する必要があります。 たとえば、最適化された移動操作でファイルを移動する場合、ターゲットは通常、元のファイルを削除しますが、削除する必要はありません。 ターゲットは、CFSTR_LOGICALPERFORMEDDROPEFFECT 形式で IDataObject::SetData 呼び出して、ファイルを削除したかどうかをデータ オブジェクトに通知します。 他にも、データ オブジェクトに情報を渡すためにターゲットによって使用されるシェル クリップボード形式 がいくつかあります。 IDataObject::SetData 実装では、これらの形式を認識し、適切に応答できる必要があります。 詳細については、「シェル データ転送シナリオの処理」を参照してください。
EnumFormatEtc メソッド
ターゲットは、データ オブジェクトを受け取ると、一般的に FORMATETC呼び出して、オブジェクトに含まれる形式を決定します。 このメソッドは OLE 列挙オブジェクトを作成し、オブジェクトの IEnumFORMATETC インターフェイスへのポインターを返します。 次に、ターゲットはインターフェイスを使用して使用可能な形式を列挙します。
列挙オブジェクトは常に、最適な形式から順に使用可能な形式を列挙する必要があります。 形式の相対的な品質は、ドロップ ソースによって定義されます。 一般に、最高品質の形式には、最も豊富で最も完全なデータが含まれています。 たとえば、通常、24 ビットカラー イメージは、そのイメージのグレースケール バージョンよりも高品質と見なされます。 形式を品質順に列挙する理由は、通常、ターゲットがサポートする形式になるまで列挙し、その形式を使用してデータを抽出するためです。 この手順で、ターゲットがサポートできる最適な形式を生成するには、形式を品質の順に列挙する必要があります。
シェル データの列挙オブジェクトは、他の種類のデータ転送の場合とほぼ同じ方法で実装され、1 つの注目すべき例外があります。 通常、データ オブジェクトには形式ごとに 1 つのデータ項目しか含めないため、通常、IDataObject::SetDataに渡されるすべての形式を列挙します。 ただし、「SetData メソッドの」セクションで説明されているように、シェル データ オブジェクトには複数の CFSTR_FILECONTENTS 形式を含めることができます。
IDataObject::EnumFormatEtcの目的は、ターゲットが存在するデータの種類を判断できるようにすることであるため、複数の CFSTR_FILECONTENTS 形式を列挙する必要はありません。 ターゲットがデータ オブジェクトに含まれているこれらの形式の数を把握する必要がある場合、ターゲットは、付属のCFSTR_FILEDESCRIPTOR形式からその情報を取得できます。 IDataObject::EnumFormatEtcを実装する方法の詳細については、メソッドのリファレンス ドキュメントを参照してください。
GetData メソッド
ターゲットは IDataObject::GetData呼び出して、特定のデータ形式を抽出します。 ターゲットは、適切な FORMATETC 構造体を渡すことによって、形式を指定します。 IDataObject::GetData は、形式の STGMEDIUM 構造体を返します。
ターゲットは、FORMATETC 構造体の の メンバーを特定のTYMED_XXX 値に設定して、データの抽出に使用するデータ転送メカニズムを指定できます。 ただし、ターゲットは、より汎用的な要求を行い、データ オブジェクトが決定できるようにすることもできます。 データ転送メカニズムの選択をデータ オブジェクトに求めるために、ターゲットは、サポートされているすべてのTYMED_XXX 値を設定します。 IDataObject::GetData は、これらのデータ転送メカニズムのいずれかを選択し、適切な STGMEDIUM 構造体を返します。 たとえば、通常、の は TYMED_HGLOBAL | に設定されます。TYMED_ISTREAM |TYMED_ISTORAGE、3 つのシェル データ転送メカニズムのいずれかを要求します。
手記
複数の CFSTR_FILECONTENTS 形式が存在する可能性があるため、FORMATETC 構造体の cfFormat メンバーと タイミングされた メンバーでは、IDataObject::GetDataSTGMEDIUM構造体を示すには不十分です。 CFSTR_FILECONTENTS形式の場合、IDataObject::GetData は、正しい STGMEDIUM 構造体を返すために、FORMATETC 構造体の lIndex メンバーも調べる必要があります。
CFSTR_INDRAGLOOP 形式はデータ オブジェクトに配置され、ターゲットはドラッグ アンド ドロップ ループの状態を確認しながら、オブジェクトのデータのメモリ負荷の高いレンダリングを回避できます。 形式のデータは、DWORD 値であり、データ オブジェクトがドラッグ ループ内にある場合は 0 以外の値に設定されます。 データが削除された場合、形式のデータ値は 0 に設定されます。 ターゲットがこの形式を要求し、ソースによって読み込まれていない場合、IDataObject::GetData は、ソースが値 0 の形式を読み込んだかのように応答する必要があります。
カーソルがターゲット ウィンドウの上にある間、ターゲットは ドラッグ アンド ドロップ ヘルパー オブジェクト を使用してドラッグ イメージを指定できます。 ドラッグ アンド ドロップ ヘルパー オブジェクト IDataObject::SetData を呼び出して、プロセス間のサポートに使用されるデータ オブジェクトにプライベート形式を読み込みます。 後で IDataObject::GetData呼び出して取得します。 ドラッグ アンド ドロップ ヘルパー オブジェクトをサポートするには、シェル データ オブジェクトの実装で、要求されたときに任意のプライベート形式を返すことができる必要があります。
IDropSource の実装
ソースは、IDropSource インターフェイスを公開するオブジェクトを作成する必要があります。 このインターフェイスを使用すると、ソースはカーソルの現在位置を示す ドラッグ イメージ を更新し、ドラッグ アンド ドロップ操作を終了する方法についてシステムにフィードバックを提供できます。 IDropSource には、GiveFeedbackと QueryContinueDragの 2 つの方法があります。
GiveFeedback メソッド
ドラッグ ループでは、ドロップ ソースがカーソル位置を追跡し、適切なドラッグ 画像を表示します。 ただし、ドラッグ 先のウィンドウ上にある場合は、ドラッグ イメージの外観を変更する必要がある場合があります。
カーソルがターゲット ウィンドウに入ったり、移動中にターゲット ウィンドウを移動したりすると、システムはターゲットの IDropTarget インターフェイスを定期的に呼び出します。 ターゲットは、GiveFeedback メソッドを介してソースに転送される DROPEFFECT 値で応答します。 必要に応じて、ソースは、DROPEFFECT 値に基づいてカーソルの外観を変更できます。 詳細については、GiveFeedback と DoDragDropリファレンス参照してください。
QueryContinueDrag メソッド
このメソッドは、データ オブジェクトがドラッグ ループ内にある間にマウス ボタンまたはキーボードの状態が変化した場合に呼び出されます。 ESC キーが押されたかどうかをソースに通知し、Ctrl キーや Shift キーなどのキーボード修飾子キーの現在の状態を提供します。 QueryContinueDrag メソッドの戻り値は、次の 3 つのアクションのいずれかを指定します。
- S_OK。 ドラッグ操作を続行する
- DRAGDROP_S_DROP。 データを削除します。 その後、システムはターゲットの IDropTarget::D rop メソッドを呼び出します。
- DRAGDROP_S_CANCEL。 データをドロップせずにドラッグ ループを終了します。 この値は通常、ESCAPE キーが押された場合に返されます。
詳細については、QueryContinueDrag と DoDragDrop参照参照してください。
ターゲットがデータ オブジェクトを処理する方法
ターゲットは、クリップボードからデータ オブジェクトを取得するか、ユーザーがターゲット ウィンドウにドロップしたときに、データ オブジェクトを受け取ります。 ターゲットは、データ オブジェクトからデータを抽出できます。 必要に応じて、ターゲットは操作の結果をデータ オブジェクトに通知することもできます。 シェル データ転送の前に、ドロップ ターゲットは操作用に自身を準備する必要があります。
- データ オブジェクト 含まれる可能性のあるすべてのシェル形式 (CF_HDROP以外) の有効なクリップボード形式の値を取得するには、ターゲットが RegisterClipboardFormat を呼び出す必要があります。 CF_HDROPは既に有効なクリップボード形式であり、登録する必要はありません。
- ドラッグ アンド ドロップ操作をサポートするには、ターゲットが IDropTargetインターフェイス実装し、ターゲット ウィンドウを登録する必要があります。 ターゲット ウィンドウを登録するために、ターゲットは RegisterDragDrop呼び出し、ウィンドウのハンドルと IDropTarget インターフェイス ポインターを渡します。
クリップボード転送の場合、ターゲットはデータ オブジェクトがクリップボードに配置されたことを示す通知を受け取りません。 通常、アプリケーションは、アプリケーションのツール バーの [貼り付け] ボタンをクリックするなど、ユーザー アクションによってオブジェクトがクリップボードに表示されることを通知します。 次に、OleGetClipboardを呼び出して、データ オブジェクトの IDataObject ポインター取得します。 ドラッグ アンド ドロップデータ転送の場合、システムはターゲットの IDropTarget インターフェイスを使用して、データ転送の進行状況に関する情報をターゲットに提供します。
- カーソルがターゲット ウィンドウ 入ると、システムは IDropTarget::D ragEnter を呼び出します。
- システムは、IDropTarget::D ragOver を定期的に呼び出して、カーソルがターゲット ウィンドウを通過すると、ターゲットに現在のカーソル位置を与えます。
- カーソルがターゲット ウィンドウから離れると、システムは IDropTarget::D ragLeaveを呼び出します。
- ユーザーがターゲット ウィンドウ データ オブジェクトを削除すると、システムは IDropTarget::D rop を呼び出します。
これらのメソッドを実装する方法の詳細については、「IDropTargetを参照してください。
データが削除されると、IDropTarget::D ropは、データ オブジェクトの IDataObject インターフェイスへのポインターをターゲットに提供します。 その後、ターゲットはこのインターフェイスを使用してデータ オブジェクトからデータを抽出します。
データ オブジェクトからのシェル データの抽出
データ オブジェクトがクリップボードから削除または取得されると、ターゲットは必要なデータを抽出できます。 抽出プロセスの最初の手順は、通常、データ オブジェクトに含まれる形式を列挙することです。
- IDataObject::EnumFormatEtc呼び出します。 データ オブジェクトは、標準の OLE 列挙オブジェクトを作成し、その IEnumFORMATETC インターフェイスへのポインターを返します。
- IEnumFORMATETC メソッドを使用して、データ オブジェクトに含まれる形式を列挙します。 この操作は、通常、オブジェクトに含まれる形式ごとに 1 つの FORMATETC 構造体を取得します。 ただし、通常、列挙オブジェクトは、データ オブジェクトに含まれる形式 の数に関係なく、CFSTR_FILECONTENTS 形式の FORMATETC 構造体を 1 つだけ返します。
- 抽出する 1 つ以上の形式を選択し、FORMATETC構造体格納します。
特定の形式を取得するには、関連付けられている FORMATETC 構造体を IDataObject::GetData渡します。 このメソッドは、データへのアクセスを提供する STGMEDIUM 構造体を返します。 特定のデータ転送メカニズムを指定するには、FORMATETC 構造体の の 値を、対応するTYMED_XXX 値に設定します。 データ転送メカニズムの選択をデータ オブジェクトに求めるために、ターゲットは、ターゲットが処理できるすべてのデータ転送メカニズムのTYMED_XXX 値を設定します。 データ オブジェクトは、これらのデータ転送メカニズムのいずれかを選択し、STGMEDIUM 構造体 適切な値を返します。
ほとんどの形式では、ターゲットは、使用可能な形式を列挙したときに受け取った FORMATETC 構造体を渡すことによって、データを取得できます。 このルールの 1 つの例外は CFSTR_FILECONTENTSです。 データ オブジェクトには、この形式の複数のインスタンスを含めることができるため、列挙子によって返される FORMATETC 構造体は、抽出する特定の形式に対応していない可能性があります。 cfFormat および の メンバーを指定するだけでなく、lIndex メンバーをファイルのインデックス値に設定する必要もあります。 詳細については、「シェルデータ転送シナリオの処理」の「CFSTR_FILECONTENTS形式を使用してファイル からデータを抽出する」セクション 参照
データ抽出プロセスは、STGMEDIUM構造体で返されるに含まれるポインターの種類によって異なります。 構造体に IStream へのポインターまたは IStorageインターフェイスが含まれている場合は、インターフェイス メソッドを使用してデータを抽出します。 グローバル メモリ オブジェクトからデータを抽出するプロセスについては、次のセクションで説明します。
データ オブジェクトからグローバル メモリ オブジェクトを抽出する
シェルのデータ形式の多くは、グローバル メモリ オブジェクトの形式です。 データ オブジェクトからグローバル メモリ オブジェクトを含む形式を抽出し、そのデータをローカル変数に割り当てるには、次の手順に従います。
FORMATETC 構造体を作成します。 cfFormat メンバーを適切なクリップボード形式の値に設定し、の メンバーをTYMED_HGLOBALに設定します。
STGMEDIUM構造体空を作成します。
IDataObject::GetData呼び出し、FORMATETC へのポインターを渡し、STGMEDIUM構造体をします。
IDataObject::GetData戻ると、STGMEDIUM 構造体には、データを含むグローバル メモリ オブジェクトへのポインターが含まれます。
GlobalLock呼び出し、STGMEDIUM 構造体の hGlobal メンバーを渡すことによって、ローカル変数にデータを割り当てます。
手記
GlobalFreeではなく、ReleaseStgMediumを使用してグローバル メモリ オブジェクトを解放する必要があります。
次の例は、グローバル メモリ オブジェクトとして格納されている DWORD 値をデータ オブジェクトから抽出する方法を示しています。 pdtobj パラメーターは、データ オブジェクトの IDataObject インターフェイスへのポインターです。cf は目的のデータを識別するクリップボード形式であり、pdwOut 使用してデータ値を返します。
STDAPI DataObj_GetDWORD(IDataObject *pdtobj, UINT cf, DWORD *pdwOut)
{ STGMEDIUM medium;
FORMATETC fmte = {(CLIPFORMAT) cf, NULL, DVASPECT_CONTENT, -1,
TYMED_HGLOBAL};
HRESULT hres = pdtobj->GetData(&fmte, &medium);
if (SUCCEEDED(hres))
{
DWORD *pdw = (DWORD *)GlobalLock(medium.hGlobal);
if (pdw)
{
*pdwOut = *pdw;
GlobalUnlock(medium.hGlobal);
}
else
{
hres = E_UNEXPECTED;
}
ReleaseStgMedium(&medium);
}
return hres;
}
IDropTarget の実装
システムは、IDropTarget インターフェイスを使用して、カーソルがターゲット ウィンドウの上にある間にターゲットと通信します。 ターゲットの応答は、IDropSource インターフェイスを介してソースに転送されます。 応答に応じて、ソースはデータを表すアイコンを変更できます。 ドロップ ターゲットでデータ アイコンを指定する必要がある場合は、ドラッグ アンド ドロップ ヘルパー オブジェクトを作成。
従来のドラッグ アンド ドロップ操作では、IDropTarget::D ropの pdwEffect パラメーターを適切なDROPEFFECT 値に設定することで、操作の結果をデータ オブジェクトに通知します。 シェル データ オブジェクトでは、ターゲットで IDataObject::SetData呼び出す必要がある場合もあります。 さまざまなデータ転送シナリオに対するターゲットの対応方法については、「シェルデータ転送シナリオの処理」を参照してください。
以降のセクションでは、IDropTarget::D ragEnter 、IDropTarget::D ragOver、および IDropTarget::D ropメソッド実装する方法について簡単に説明します。 詳細については、リファレンス ドキュメントを参照してください。
DragEnter メソッド
カーソルがターゲット ウィンドウに入ると、システムは IDropTarget::D ragEnter メソッドを呼び出します。 そのパラメーターは、カーソルの位置、Ctrl キーなどのキーボード修飾子キーの状態、およびデータ オブジェクトの IDataObjectインターフェイスへのポインターをターゲット提供します。 ターゲットは、そのインターフェイスを使用して、データ オブジェクトに含まれるいずれかの形式を受け入れられるかどうかを判断する役割を担います。 可能な場合は、通常、pdwEffect 値 変更されません。 データ オブジェクトからデータを受け取ることができない場合は、pdwEffect パラメーターをDROPEFFECT_NONEに設定します。 システムは、このパラメーターの値をデータ オブジェクトの IDropSource インターフェイスに渡して、適切なドラッグ イメージを表示できるようにします。
ターゲットは、IDataObject::GetData メソッドを使用してシェル データを削除する前にレンダリングしないでください。 このような発生ごとにオブジェクトのデータを完全にレンダリングすると、ドラッグ カーソルがストールする可能性があります。 この問題を回避するために、一部のシェル オブジェクトには CFSTR_INDRAGLOOP 形式が含まれています。 この形式を抽出することで、ターゲットは、オブジェクトのデータのメモリ負荷の高いレンダリングを回避しながら、ドラッグ ループの状態を確認できます。 形式のデータ値は、DWORD であり、データ オブジェクトがドラッグ ループ内にある場合は 0 以外の値に設定されます。 データが削除された場合、形式のデータ値は 0 に設定されます。
ターゲットがデータ オブジェクトからのデータを受け入れる場合は、grfKeyState 調べて、通常のドロップ動作を変更するために修飾子キーが押されているかどうかを判断する必要があります。 たとえば、既定の操作は通常は移動ですが、Ctrl キーを押すと通常はコピー操作が示されます。
カーソルがターゲット ウィンドウの上にある間、ターゲットは ドラッグ アンド ドロップ ヘルパー オブジェクト を使用して、データ オブジェクトのドラッグ イメージを独自のドラッグ イメージに置き換えることができます。 その場合、IDropTarget::D ragEnterIDropTargetHelper::D ragEnter呼び出して、DragEnter パラメーターに含まれる情報をドラッグ アンド ドロップ ヘルパー オブジェクトに渡す必要があります。
DragOver メソッド
カーソルがターゲット ウィンドウ内で移動すると、システムは定期的に IDropTarget::D ragOver メソッドを呼び出します。 そのパラメーターは、カーソルの位置と、Ctrl キーなどのキーボード修飾子キーの状態をターゲットに提供します。 IDropTarget::D ragOver は、IDropTarget::D ragEnterとほぼ同じ役割を果たしており、実装は通常よく似ています。
ターゲットがドラッグ アンド ドロップ ヘルパー オブジェクトを使用している場合、IDropTarget::D ragOverIDropTargetHelper::D ragOver を呼び出して、DragOver パラメーターに含まれる情報をドラッグ アンド ドロップ ヘルパー オブジェクトに転送する必要があります。
Drop メソッド
システムは、IDropTarget::D rop メソッドを呼び出して、ユーザーがデータを削除したことをターゲットに通知します。通常はマウス ボタンを離します。 IDropTarget::D rop には、IDropTarget::D ragEnterと同じパラメーターがあります。 ターゲットは通常、データ オブジェクトから 1 つ以上の形式を抽出することによって応答します。 完了したら、ターゲットは、pdwEffect パラメーターを、操作の結果を示す DROPEFFECT 値に設定する必要があります。 一部の種類のシェル データ転送の場合、ターゲットは IDataObject::SetData を呼び出して、操作の結果に関する追加情報を含む形式をデータ オブジェクトに渡す必要があります。 詳細については、「シェル データ転送シナリオの処理」を参照してください。
ターゲットがドラッグ アンド ドロップ ヘルパー オブジェクトを使用している場合、IDropTarget::D ropIDropTargetHelper::D rop を呼び出して、IDropTargetHelper::D ragOver パラメーターに含まれる情報をドラッグ アンド ドロップ ヘルパー オブジェクトに転送する必要があります。
ドラッグ アンド ドロップ ヘルパー オブジェクトの使用
ドラッグ アンド ドロップ ヘルパー オブジェクト (CLSID_DragDropHelper) はシェルによってエクスポートされ、ターゲットがターゲット ウィンドウ上にある間にドラッグ イメージを指定できます。 ドラッグ アンド ドロップ ヘルパー オブジェクトを使用するには、CLSID_DragDropHelperのクラス識別子 (CLSID) を使用 CoCreateInstance を呼び出して、インプロセス サーバー オブジェクトを作成します。 ドラッグ アンド ドロップ ヘルパー オブジェクトは、次の方法で使用される 2 つのインターフェイスを公開します。
- IDragSourceHelper インターフェイスを使用すると、ドロップ ターゲットでデータ オブジェクトを表すアイコンを指定できます。
- IDropTargetHelper インターフェイスを使用すると、ドロップ ターゲットはカーソル位置をドラッグ アンド ドロップ ヘルパー オブジェクトに通知し、データ アイコンの表示と非表示を切り替えます。
IDragSourceHelper インターフェイスの使用
IDragSourceHelper インターフェイスは、ドラッグ アンド ドロップ ヘルパー オブジェクトによって公開され、カーソルがターゲット ウィンドウの上にある間に表示されるイメージをドロップ ターゲットが提供できるようにします。 IDragSourceHelper には、ドラッグイメージとして使用するビットマップを指定する 2 つの代替方法が用意されています。
- ウィンドウを持つターゲットをドロップするには、IDragSourceHelper::InitializeFromWindowを使用してドラッグ アンド ドロップ ヘルパー オブジェクト初期化することで、DI_GETDRAGIMAGE ウィンドウ メッセージを登録できます。 ターゲットがDI_GETDRAGIMAGEメッセージを受信すると、ハンドラーは、メッセージの lParam 値として渡される SHDRAGIMAGE 構造体にドラッグ イメージ ビットマップ情報を配置します。
- ウィンドウレス ドロップ ターゲットは、IDragSourceHelper::InitializeFromBitmapを使用してドラッグ アンド ドロップ ヘルパー オブジェクト初期化するときにビットマップを指定します。
IDropTargetHelper インターフェイスの使用
このインターフェイスを使用すると、カーソルがターゲットに入ったり離れたりしたときに、ドロップ ターゲットがドラッグ アンド ドロップ ヘルパー オブジェクトに通知されます。 カーソルがターゲット ウィンドウの上にある間、IDropTargetHelper、ターゲットは、IDropTarget インターフェイスを介してターゲットが受け取る情報をドラッグ アンド ドロップ ヘルパー オブジェクトに提供できます。
IDropTargetHelper メソッドのうち、IDropTargetHelper::D ragEnter、IDropTargetHelper::D ragLeave、IDropTargetHelper::D ragOver、および IDropTargetHelper::D ropは、同じ名前の IDropTarget メソッドに関連付けられます。 ドラッグ アンド ドロップ ヘルパー オブジェクトを使用するには、各 IDropTarget メソッドは、対応する IDropTargetHelper メソッドを呼び出して、ドラッグ アンド ドロップ ヘルパー オブジェクトに情報を転送する必要があります。 5 番目の IDropTargetHelper メソッド IDropTargetHelper::Showは、ドラッグ イメージを表示または非表示にするドラッグ アンド ドロップ ヘルパー オブジェクトに通知します。 このメソッドは、色深度の低いビデオ モードでターゲット ウィンドウ上をドラッグするときに使用されます。 これにより、ウィンドウの描画中にターゲットがドラッグイメージを非表示にすることができます。