ドロップターゲットのC++による実装の例
ドロップターゲットをC++で実装する例
ドロップを抽象化するクラス。
動的生成で管理するならinitの内容をコンストラクターに移動するのもありだろう。
class TDropTarget; class TMyDrop { friend TDropTarget; private: HWND FHwnd; TDropTarget* FDropTarget; void release_target(); public: TDragAndDrop() : FHwnd(0), FDropTarget(NULL) {} virtual ~TDragAndDrop(); void init( HWND hwnd ); }; //------------------------------------------------------ TMyDrop::~TDragAndDrop() { if( FDropTarget ) release_target(); ::RevokeDragDrop( FHwnd ); ::OleUninitialize(); } //------------------------------------------------------ void TMyDrop::init( HWND hwnd ) { if( !FHwnd ) { ::OleInitialize( NULL ); } if( FDropTarget ) delete FDropTarget; FDropTarget = new TDropTarget( this, hwnd ); if( S_OK != ::RegisterDragDrop( FHwnd, FDropTarget ) ) { release_target(); ::OleUninitialize(); return; } FHwnd = hwnd; } //------------------------------------------------------ void TMyDrop::release_target() { if( FDropTarget ) { delete FDropTarget; FDropTarget = NULL; } } //------------------------------------------------------
IDropTargetを実装するクラス。
DropEffectは、MOVE、COPY、LINKがある。この辺は目的に沿って実装する。
もちろん、必要とするフォーマットによりFORMATETCあたりの定義は変更する。
class TDropTarget : public IDropTarget { private: TDragAndDrop* FParent; LONG FRef; HWND FHwnd; DWORD FEffect; void make_formatetc( FORMATETC &formatetc ); public: TDropTarget( TDragAndDrop *parent, HWND hwnd ) : FParent(parent), FRef(1), FHwnd(hwnd), FEffect(DROPEFFECT_NONE) {} virtual ~TDropTarget() {} STDMETHODIMP QueryInterface( REFIID ref_iid, void **ppObj ); STDMETHODIMP_(ULONG) AddRef(); STDMETHODIMP_(ULONG) Release(); STDMETHODIMP DragEnter( IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect ); STDMETHODIMP DragOver( DWORD grfKeyState, POINTL pt, DWORD *pdwEffect ); STDMETHODIMP DragLeave(); STDMETHODIMP Drop( IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect ); }; //------------------------------------------------------ void TDropTarget::make_formatetc( FORMATETC &formatetc ) { formatetc.cfFormat = CF_HDROP; formatetc.ptd = NULL; formatetc.dwAspect = DVASPECT_CONTENT; formatetc.lindex = -1; formatetc.tymed = TYMED_HGLOBAL; } //------------------------------------------------------ STDMETHODIMP TDropTarget::QueryInterface( REFIID ref_iid, void **ppObj ) { (*ppObj) = NULL; if( IsEqualIID( ref_iid, IID_IUnknown ) || IsEqualIID( ref_iid, IID_IDropTarget ) ) (*ppObj) = dynamic_cast<IDropTarget*>(this); else return E_NOINTERFACE; AddRef(); return S_OK; } //------------------------------------------------------ STDMETHODIMP_(ULONG) TDropTarget::AddRef() { return InterlockedIncrement( &FRef ); } //------------------------------------------------------ STDMETHODIMP_(ULONG) TDropTarget::Release() { if( 0 == InterlockedDecrement( &FRef ) ) { FParent->release_target(); return 0; } return FRef; } //------------------------------------------------------ STDMETHODIMP TDropTarget::DragEnter( IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect ) { FORMATETC formatetc; make_formatetc( formatetc ); if( S_OK == pDataObj->QueryGetData( &formatetc ) ) { *pdwEffect = FEffect = DROPEFFECT_COPY|DROPEFFECT_LINK; return S_OK; } else { *pdwEffect = FEffect = DROPEFFECT_NONE; return DRAGDROP_S_CANCEL; } } //------------------------------------------------------ STDMETHODIMP TDropTarget::DragOver( DWORD grfKeyState, POINTL pt, DWORD *pdwEffect ) { *pdwEffect = FEffect; return S_OK; } //------------------------------------------------------ STDMETHODIMP TDropTarget::DragLeave() { return S_OK; } //------------------------------------------------------ STDMETHODIMP TDropTarget::Drop(IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) { FORMATETC formatetc; make_formatetc( formatetc ); *pdwEffect = DROPEFFECT_NONE; STGMEDIUM medium; if( S_OK != pDataObj->GetData( &formatetc, &medium ) ) { return E_FAIL; } *pdwEffect = FEffect; // それぞれの処理 ::ReleaseStgMedium(&medium); return S_OK; } //------------------------------------------------------