LoginSignup
0
0

More than 5 years have passed since last update.

IDropTarget を実装する

Last updated at Posted at 2012-11-19

""

参考リンク:
IDropTargetを実装する
7.IDropTargetとOLEドラッグ&ドロップ - COM研究室

まずは定型

#include <shlobj.h>

class TDropTargetBase : public IDropTarget
{
protected:
    unsigned int refCount;

    TDropTargetBase();
    ~TDropTargetBase();

    virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv);
    virtual ULONG __stdcall AddRef();
    virtual ULONG __stdcall Release();

};

TDropTargetBase::TDropTargetBase() {
    refCount = 0;
};

TDropTargetBase::~TDropTargetBase() {
};

HRESULT TDropTargetBase::QueryInterface(const IID& iid, void** ppv){
    if (IsEqualIID(iid, IID_IUnknown) || IsEqualIID(iid, IID_IDropTarget))
        *ppv = static_cast<IDropTarget *>(this);
    else
    {
        *ppv = NULL;
        return E_NOINTERFACE;
    }

    AddRef();

    return S_OK;
}

ULONG TDropTargetBase::AddRef(){
    refCount++;
    return refCount;
}

ULONG TDropTargetBase::Release(){
    refCount--;
    if (refCount == 0) {
        delete this;
    }
    return refCount;
}

IDropTarget::DragEnter, DragOver, DragLeave, Drop を実装する。

//  TDropTargetBase は、この説明で定型の部分を分離したかっただけで、本当はクラス分けする必要性は皆無。

class TDropTarget : public TDropTargetBase
{
public:
    static void CreateInstance(IDropTarget **);
private:
    virtual HRESULT __stdcall DragEnter(IDataObject* pDataObj, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect);
    virtual HRESULT __stdcall DragOver(DWORD grfKeyState, POINTL pt, DWORD* pdwEffect);
    virtual HRESULT __stdcall DragLeave();
    virtual HRESULT __stdcall Drop(IDataObject* pDataObj, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect);
};

void TDropTarget::CreateInstance(IDropTarget **pp) {
    if (pp != NULL) {
        TDropTarget *p = new TDropTarget();
        p->QueryInterface(IID_IDropTarget, (void **)pp);
    }
}

#include <tchar.h>
#include <string>
typedef std::basic_string<TCHAR> tstring;

static void OutputDebugEffectString(DWORD *pdwEffect) {
    tstring sz;
    sz += TEXT("DROPEFFECT_");
    if (*pdwEffect == DROPEFFECT_NONE) {
        sz += TEXT("NONE");
    }
    else {
        if (*pdwEffect & DROPEFFECT_COPY) {
            sz += TEXT("COPY/");
        }
        if (*pdwEffect & DROPEFFECT_MOVE) {
            sz += TEXT("MOVE/");
        }
        if (*pdwEffect & DROPEFFECT_LINK) {
            sz += TEXT("LINK/");
        }
        if (*pdwEffect & DROPEFFECT_LINK) {
            sz += TEXT("SCROLL/");
        }
        sz.pop_back();
    }

    OutputDebugString(sz.data());
}

HRESULT TDropTarget::DragEnter(IDataObject* pDataObj, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect){
    OutputDebugString(TEXT("DragOver"));
    OutputDebugEffectString(pdwEffect);
    OutputDebugString(TEXT("\r\n"));
    return S_OK;
}

HRESULT TDropTarget::DragOver(DWORD keyState, POINTL pt, DWORD* effect){
    OutputDebugString(TEXT("DragOver"));
    OutputDebugString(TEXT("\r\n"));
    return S_OK;
}

HRESULT TDropTarget::DragLeave(){
    OutputDebugString(TEXT("DragLeave"));
    OutputDebugString(TEXT("\r\n"));
    return S_OK;
}

HRESULT TDropTarget::Drop(IDataObject* pDataObj, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect){
    OutputDebugString(TEXT("Drop"));
    OutputDebugEffectString(pdwEffect);
    OutputDebugString(TEXT("\r\n"));
    return S_OK;
}

ウィンドウに割り当てる。

(ウィンドウプロシージャ内部)
    case WM_CREATE:
        ...
        {
            IDropTarget *pDropTarget;
            TDropTarget::CreateInstance(&pDropTarget);
            RegisterDragDrop(hwnd, pDropTarget);    // OLE機能にIDropTargetを登録
            pDropTarget->Release();
        }
        ...
        break;
    case WM_CLOSE:
        ...
        RevokeDragDrop(hwnd);
        ...
        break;

この時点で、もうファイルやテキストのドロップなどができる状態。

DragEnter, Drop をちゃんと実装する。

HRESULT TDropTarget::DragEnter(IDataObject* pDataObj, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect){
    HRESULT    hr;
    FORMATETC  formatetc;

    // ドロップされようとしてるデータが CF_HDROP フォーマットをサポートしているかどうかを調べる
    formatetc.cfFormat = CF_HDROP;
    formatetc.ptd      = NULL;
    formatetc.dwAspect = DVASPECT_CONTENT;
    formatetc.lindex   = -1;
    formatetc.tymed    = TYMED_HGLOBAL;

    hr = pDataObj->QueryGetData(&formatetc);
    if(hr != S_OK){
        *pdwEffect = DROPEFFECT_NONE;
    }else{
        *pdwEffect = DROPEFFECT_COPY;
    }

    return (*pdwEffect == DROPEFFECT_NONE) ? DRAGDROP_S_CANCEL:
        S_OK;
    // ちゃんと DRAGDROP_S_CANCEL を返してやらないと、DROPEFFECT_NONE にも関わらず
    // Drop できてしまう。
}


static HRESULT GetDroppedFiles(IDataObject *pDataObj, std::list<tstring> *pDroppedFiles) {
    HRESULT hr;

    FORMATETC  formatetc;
    formatetc.cfFormat = CF_HDROP;
    formatetc.ptd      = NULL;
    formatetc.dwAspect = DVASPECT_CONTENT;
    formatetc.lindex   = -1;
    formatetc.tymed    = TYMED_HGLOBAL;

    hr = pDataObj->QueryGetData(&formatetc);
    if (FAILED(hr)) {
        goto fail;
    }

    STGMEDIUM medium;
    hr = pDataObj->GetData(&formatetc, &medium);
    if (FAILED(hr)) {
        goto fail;
    }

    HDROP p = (HDROP)GlobalLock(medium.hGlobal);

    int num = DragQueryFile(p, 0xFFFFFFFF, NULL, 0);
    for (int iFile = 0; iFile < num; iFile++) {
        int size = DragQueryFile(p, iFile, NULL, 0);

        TCHAR * buf = new TCHAR[size + 1];

        // assert(size == 
            DragQueryFile(p, iFile, buf, size + 1)
        // )
            ;

        pDroppedFiles->push_back(tstring(buf));
        delete[] buf;
    }

    GlobalUnlock(medium.hGlobal);
    ReleaseStgMedium(&medium);
fail:
    return hr;
}

HRESULT TDropTarget::Drop(IDataObject* pDataObj, DWORD /*grfKeyState*/, POINTL /*pt*/, DWORD* pdwEffect) {
    HRESULT rc;

    OutputDebugString(TEXT("Drop : "));
    OutputDebugEffectString(pdwEffect);
    OutputDebugString(TEXT("\r\n"));

    std::list<tstring> droppedFiles;

    HRESULT hr = GetDroppedFiles(pDataObj, &droppedFiles);
    if (SUCCEEDED(hr) == false)
    {
        goto fail;
    }
    else
    {
        tstring debugString;

        for(std::list<tstring>::iterator ite = droppedFiles.begin();
            ite != droppedFiles.end();
            ite++) 
        {
            debugString += *ite;
            debugString += TEXT("\r\n");
        }

        OutputDebugString(debugString.data());
    }

    rc = S_OK;
    goto cleanUp;
fail:
    rc = E_FAIL;
    OutputDebugString(TEXT("Something wrong."));
cleanUp:
    return rc;
}

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0