Shell Drag/Drop Helper オブジェクト
第 1 部 : IDropTargetHelper
Raymond Chen
Microsoft Corporation
February 2000
日本語版最終更新日 2000年5月10日
要約 : MicrosoftR WindowsR 2000 シェルには、新しいオブジェクトである shell drag/drop helper オブジェクトが用意されています。このオブジェクトを使用すると、ドラッグ イメージやアルファ ブレンディングなどの機能をはじめとする shell drag/drop ユーザー インターフェイスを利用できます。この記事は、アプリケーションで shell drag/drop helper オブジェクトを使ってユーザーの操作性を高める方法を解説した 2 部構成の記事の第 1 部です。
内容
IDropTargetHelper インターフェイスにアクセスする
IDropTargetHelper インターフェイスを使用する
ドラッグ ループ内で描画する
折り返し地点
図 1 : shell drag/drop helper オブジェクトを使用した
ドラッグ/ドロップ フィードバックの描画例
IDropTargetHelper インターフェイスにアクセスする
IDropTargetHelper インターフェイスを使用すると、ユーザーがドロップ ターゲット上にシェル オブジェクト (または、shell drag/drop helper オブジェクトを使用するほかの任意のオブジェクト) をドラッグしたときに、より有意義なフィードバックを返すことができます。このインターフェイスの使用法は非常に簡単です。ただ 1 つ、 IDropTargetHelper::Show メソッドの扱いには、注意が多少必要ですが、これについては後で説明します。
最初に、 CoCreateInstance 関数を使って shell drag/drop helper オブジェクトを作成します。この関数には、IID_IdropTargetHelper をインターフェイスとして指定します。それぞれのドロップ ターゲットごとに、(通常は、メンバ変数として) ヘルパ オブジェクトを作成する必要がある点に注意してください。
ここでは、記事のスペースに制約があるので、参照カウント操作や NULL ポインタのチェックといった問題を効率よく処理するために ATL スマート ポインタを使用しています。
class CDropTarget : public IDropTarget {
...
CDropTarget(HWND hwnd);
~CDropTarget();
private:
CComPtr<IDropTargetHelper> m_spdth;
CComPtr<IDataObject> m_spdtoDragging; /* ドラッグされるオブジェクト */
HWND m_hwnd; /* ウィンドウのハンドル */
};
CDropTarget::CDropTarget(HWND hwnd) /* コンストラクタ */
{
/* この呼び出しに失敗した場合は、OLE によって m_pdth が NULL に設定される */
CoCreateInstance(CLSID_DragDropHelper, NULL, CLSCTX_INPROC_SERVER,
IID_IDropTargetHelper, (LPVOID*)&m_pdth);
m_hwnd = hwnd;
RegisterDragDrop(m_hwnd, this);
/* コンストラクタ関連のその他のコードをここに挿入する... */
}
CDropTarget::~CDropTarget() /* デストラクタ */
{
// 破棄されたときには ATL スマート ポインタによって自動的に解放される
RevokeDragDrop(m_hwnd);
}
以前のバージョンの Microsoft Windows には shell drag/drop helper オブジェクトが実装されていなかったため、 CoCreateInstance 関数の呼び出しに失敗することがあります。この関数を使用するときには、事前に m_pdth メンバが NULL でないことを必ず確認してください (ダミー オブジェクトを使って、別の方法でこの問題を回避する方法も考えられます)。
IDropTargetHelper インターフェイスを使用する
すでに述べたように、shell drag/drop helper オブジェクトの使用法は非常に簡単です。対応する IDropTarget メソッドから適切な IDropTargetHelper メソッドを単に呼び出すだけで、ドラッグされたオブジェクトの描画と消去に関するすべての操作が drag/drop helper オブジェクトによって実行されます。
たとえば、サンプルのドロップ ターゲットを使用すると、以下のようなコードを作成できます (このプログラムの実行時の画面ショットは図 1 です)。
HRESULT CDropTarget::DragEnter(IDataObject *pdto, DWORD grfKeyState, POINTL ptl, DWORD *pdwEffect)
{
if (m_spdth) { /* ヘルパーがある場合は使用する */
POINT pt = { ptl.x, ptl.y };
m_spdth->DragEnter(m_hwnd, pdto, &pt, *pdwEffect);
}
m_spdtoDragging = pdto; /* ドラッグされている対象を記憶する */
/* 標準的なドロップ ターゲット処理をここに挿入する... */
return S_OK;
}
HRESULT CDropTarget::DragLeave()
{
if (m_spdth) { /* ヘルパーがある場合は使用する */
m_spdth->DragLeave();
}
m_spdtoDragging->Release(); /* 何もドラッグされていない */
/* 標準的なドロップ ターゲット操作をここに挿入する... */
return S_OK;
}
HRESULT CDropTarget::DragOver(DWORD grfKeyState, POINTL ptl, DWORD *pdwEffect)
{
if (m_spdth) { /* ヘルパーがある場合は使用する */
POINT pt = { ptl.x, ptl.y };
m_spdth->DragOver(&pt, *pdwEffect);
}
/* 標準的なドロップ ターゲット操作をここに挿入する... */
return S_OK;
}
HRESULT CDropTarget::Drop(IDataObject *pdto, DWORD grfKeyState, POINTL ptl, DWORD *pdwEffect)
{
if (m_spdth) { /* ヘルパーがある場合は使用する */
POINT pt = { ptl.x, ptl.y };
m_spdth->Drop(pdto, &pt, *pdwEffect);
}
m_spdtoDragging->Release(); /* 何もドラッグされていない */
// 標準的なドロップ ターゲット操作をここに挿入する... このサンプルでは単に
// "nothing happened"と表示する
*pdwEffect = DROPEFFECT_NONE;
return S_OK;
}
それぞれのメソッドの最初で drag/drop helper オブジェクトを呼び出しているほかに、ドラッグされているデータ オブジェクトを常に記憶していることに気付くと思います。実は、このちょっとした記憶の操作によって、すぐ後に出てくる潜在的な問題を解消しています。
ドラッグ ループ内で描画する
今のままでは、ユーザーがウィンドウ上にオブジェクトをドラッグしたときに、ドロップ ターゲット ウィンドウを描画しようとして失敗することがあります。これは、ドラッグ ループ内でドロップ ターゲット ウィンドウを動かそうとする場合に問題になります。たとえば、エクスプローラ ウィンドウの端にオブジェクトをドラッグすると、その端の方向へウィンドウがスクロールし、エクスプローラ ウィンドウ内のアイテム上にオブジェクトをドラッグすると、そのアイテムがドロップのターゲットであることを示すためにアイテムが特別な色で描画されます。
この問題を解決するために、IDropTargetHelper インターフェイスのその他のメソッドを使用します。
// WM_PAINT ハンドラ...
if (m_spdtoDragging && m_spdth) {
m_spdth->Show(FALSE);
}
// 通常の描画コードをここに挿入する
if (m_spdtoDragging && m_spdth) {
m_spdth->Show(TRUE);
}
IDropTargetHelper::Show メソッドでは、ドラッグ イメージの非表示/表示を明示的に指定することができます。システム構成によっては、ドラッグ イメージが表示されているときに描画を試みると、無視されることがあります。そこで、描画するときには、ドラッグ イメージを非表示にして描画を実行し、描画の終了後にイメージを再び表示する必要があります。
折り返し地点
これまでの説明でわかるように、IDropTargetHelper インターフェイスの使い方は非常に簡単です。ほんの数行のコードを記述するだけで、動作方法を知らなくても、Windows 2000 のグラフィックス機能をアプリケーションで利用することができます。さらに、シェルが進化を続けても、shell drag/drop helper オブジェクトによって、shell drag/drop UI へのアクセスが従来どおり提供されることになります。この記事の 第 2 部では、ドラッグ/ドロップのもう一方の当事者であるドラッグ 側のソースについて説明します。