ドロップターゲットの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;
}
//------------------------------------------------------