Somthing confused with ole drag and drop implementation [closed]

元气小坏坏 提交于 2020-01-05 08:23:33

问题


I wish to finish a little demo to implement OLE drag and drop(drag a file from my application to windows explorer).

But here comes a problem:DoDragDrop return DRAGDROP_S_DROP which means the ole drag and drop operation has successfully done,but also get DROPEFFECT_NONE which means drop target cannot accept the data.

I debug into it but I get a mess with them,help me,please:(

Here is the gui:

Critical code comes: 1.MainWindow.h

#ifndef MainWindowH
#define MainWindowH
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
#include <Ole2.h>
#include "MyDataObject.h"
#include "MyDropSource.h"
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published:    // IDE-managed Components
    TLabel *Label1;
    void __fastcall Label1StartDrag(TObject *Sender, TDragObject *&DragObject);
    void __fastcall Label1EndDrag(TObject *Sender, TObject *Target, int X, int Y);
    void __fastcall FormCreate(TObject *Sender);
    void __fastcall FormDestroy(TObject *Sender);
private:    // User declarations
    //准备两个接口实例
    IDataObject *pDataObject;
    IDropSource *pDropSource;

    //
    STGMEDIUM stgmed;
    FORMATETC fmtetc;

public:     // User declarations
    __fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif

2.DoDragDrop invoke in MainWindow.cpp

   void __fastcall TForm1::Label1StartDrag(TObject *Sender, TDragObject *&DragObject)
{
    Label1->Caption = "Start drag";

    //Source file
    char tFileName[256] = "D:\\119.dat";

    //Prepare FOTMATETC
    fmtetc.cfFormat = CF_HDROP;
    fmtetc.dwAspect = DVASPECT_CONTENT;
    fmtetc.lindex = -1;
    fmtetc.ptd = (void*)0;
    fmtetc.tymed = TYMED_HGLOBAL;

    //Prepare DROPFILES
    DROPFILES* tDropFiles;
    //Fill the filename
    HGLOBAL hGblFiles;
    LPSTR lpData;
    stgmed.hGlobal = GlobalAlloc(GHND, sizeof(DROPFILES)+strlen(tFileName)+ 2);
    if(0 == stgmed.hGlobal)
        MessageBoxA(NULL, "OUT_OF_MEMORY!!!", "OUT_OF_MEMORY", 0);

    tDropFiles = (DROPFILES*)GlobalLock(stgmed.hGlobal);
    ZeroMemory(tDropFiles, sizeof(DROPFILES)+strlen(tFileName)+2);
    strcpy(((char*)tDropFiles)+sizeof(DROPFILES), tFileName);
    GlobalUnlock(stgmed.hGlobal);

    tDropFiles->fNC     = true;
    tDropFiles->fWide   = false;
    tDropFiles->pFiles  = sizeof(DROPFILES);
    tDropFiles->pt.x    = 0;
    tDropFiles->pt.y    = 0;

    //set hGlobal
    stgmed.tymed = TYMED_HGLOBAL;
    stgmed.hGlobal = tDropFiles;
    stgmed.pUnkForRelease = 0;

    //Create Instance of IDropSource and IDataObject
    pDropSource  = new MyDropSource();
    pDropSource->AddRef();
    pDataObject  = new MyDataObject();
    pDataObject->AddRef();

    //SetData
    pDataObject->SetData(&fmtetc, &stgmed, true);

    OleInitialize(0);

    //Invoke DoDragDrop
    DWORD dwEffect;
    HRESULT tResult = DoDragDrop((IDataObject*)pDataObject, (IDropSource*)pDropSource, DROPEFFECT_MOVE, &dwEffect);

    //Ckeck drag&drop result
    if(tResult != DRAGDROP_S_DROP)
        {
        if(tResult == DRAGDROP_S_CANCEL)
            MessageBoxA(NULL, "DRAGDROP_S_CANCEL!", "DRAGDROP_S_DROP", 0);
        else
            MessageBoxA(NULL, "E_UNSPEC!", "DRAGDROP_S_DROP", 0);
        return;
        }

    if((dwEffect & DROPEFFECT_MOVE) == DROPEFFECT_MOVE)
        MessageBoxA(NULL, "Ole drag&drop OK!!", "DRAGDROP_S_DROP", 0);
    else
        {
        if((dwEffect & DROPEFFECT_NONE) == DROPEFFECT_NONE)
            MessageBoxA(NULL, "DROPEFFECT_NONE!!", "DRAGDROP_S_DROP", 0);
        }

    //Clean
    pDropSource->Release();
    pDataObject->Release();

    OleUninitialize();

    return;
}

3.MyDataObject.h

#ifndef _MYDATAOBJECT_H_
#define _MYDATAOBJECT_H_

#include <stdio.h>
#include "IDragDemo.h"
#include "MyDropSource.h"

#ifndef SAFE_DELETE
#define SAFE_DELETE(p) { if(p){delete(p);  (p)=NULL;} }
#endif

HRESULT CreateEnumFormatEtc(UINT cfmt, FORMATETC *afmt, IEnumFORMATETC **ppEnumFormatEtc);

class MyDataObject : public IDataObject
{
public:
    //IUnknown implementation
    ULONG __stdcall AddRef();
    ULONG __stdcall Release();
    STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject);

    //IDataObject members
    STDMETHODIMP GetData               (FORMATETC *pformatetcIn, STGMEDIUM *pmedium);
    STDMETHODIMP GetDataHere           (FORMATETC *pformatetc,   STGMEDIUM *pmedium);
    STDMETHODIMP QueryGetData          (FORMATETC *pformatetc);
    STDMETHODIMP GetCanonicalFormatEtc (FORMATETC *pformatectIn, FORMATETC *pformatetcOut);
    STDMETHODIMP SetData               (FORMATETC *pformatetc,   STGMEDIUM *pmedium,  BOOL fRelease);
    STDMETHODIMP EnumFormatEtc         (DWORD     dwDirection,   IEnumFORMATETC **ppenumFormatEtc);
    STDMETHODIMP DAdvise               (FORMATETC *pformatetc,   DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection);
    STDMETHODIMP DUnadvise             (DWORD     dwConnection);
    STDMETHODIMP EnumDAdvise           (IEnumSTATDATA **ppenumAdvise);
public:
    MyDataObject();
    ~MyDataObject();
private:
    LONG refcount;

    FORMATETC* m_AcceptFormat;
    STGMEDIUM* m_StorageMedium;

    HGLOBAL DupGlobalMem(HGLOBAL hMem);

    //Helper function
    HRESULT CopyMedium(STGMEDIUM* pMedDest, STGMEDIUM* pMedSrc, FORMATETC* pFmtSrc);
    HRESULT SetBlob(CLIPFORMAT cf, const void *pvBlob, UINT cbBlob);

    LONG m_RefCount;
};
//----------------MyEnumFormatEtc-----------------------------------------------------------
class MyEnumFormatEtc : public IEnumFORMATETC
{
public:
    // IUnknown members
    HRESULT __stdcall  QueryInterface (REFIID iid, void ** ppv)
    {
        if((iid==IID_IUnknown)||(iid==IID_IEnumFORMATETC))
        {
            *ppv=this;
            AddRef();
            return S_OK;
        }
        else
        {
            *ppv=NULL;
            return E_NOINTERFACE;
        }
    }
    ULONG   __stdcall AddRef (void) { return ++_iRefCount; }
    ULONG   __stdcall Release (void)  { if(--_iRefCount==0){delete this;  return 0;} return _iRefCount; }

    // IEnumFormatEtc members
    HRESULT __stdcall  Next  (ULONG celt, FORMATETC * rgelt, ULONG * pceltFetched);
    HRESULT __stdcall  Skip  (ULONG celt)
    {
        _nIndex += celt;
        return (_nIndex <= _nNumFormats) ? S_OK : S_FALSE;
    }
    HRESULT __stdcall  Reset (void)
    {
        _nIndex = 0;
        return S_OK;
    }
    HRESULT __stdcall  Clone (IEnumFORMATETC ** ppEnumFormatEtc)
    {
        HRESULT hResult;
        hResult = CreateEnumFormatEtc(_nNumFormats, _pFormatEtc, ppEnumFormatEtc);
        if(hResult == S_OK)
        {
            ((MyEnumFormatEtc *)*ppEnumFormatEtc)->_nIndex = _nIndex;
        }
        return hResult;
    }

    // Construction / Destruction
    MyEnumFormatEtc(FORMATETC *pFormatEtc, ULONG nNumFormats);
    ~MyEnumFormatEtc();

private:
    LONG        _iRefCount;        
    ULONG       _nIndex;        
    ULONG       _nNumFormats;      
    FORMATETC * _pFormatEtc; 
};
//---------------------------------------------------------------------------

#endif

4.MyDataObject.cpp

 #include "MyDataObject.h"
 #include "MyDropSource.h"
 #include <Urlmon.h>


MyDataObject::MyDataObject(MyDropSource* vDropSource)
{
    m_RefCount = 0;
    m_DropSource = vDropSource;
}


MyDataObject::~MyDataObject()
{
    refcount = 0;

    SAFE_DELETE(m_StorageMedium);
    SAFE_DELETE(m_AcceptFormat);
}


ULONG __stdcall MyDataObject::AddRef()
{
    return InterlockedIncrement(&m_RefCount);
}

ULONG __stdcall MyDataObject::Release()
{
    ULONG nRefCount = InterlockedDecrement(&m_RefCount);

    if (nRefCount == 0)
        delete this;

    return nRefCount;
}

STDMETHODIMP MyDataObject::QueryInterface(REFIID riid, void **ppvObject) {

if (!ppvObject)
        return E_POINTER;

    if (riid == IID_IDataObject)
        *ppvObject = (IDataObject*)this;
    else if (riid == IID_IUnknown)
        *ppvObject = (IUnknown*)this;
    else
    {
        *ppvObject = 0;
        return E_NOINTERFACE;
    }

    AddRef();
    return S_OK;


}


STDMETHODIMP MyDataObject::GetData(FORMATETC *pformatetcIn, STGMEDIUM *pmedium)
{

    if ( (NULL == pformatetcIn) || (NULL == pmedium) )
    {
        return E_INVALIDARG;
    }

    pmedium->hGlobal = NULL;

    if( (pformatetcIn->tymed & m_AcceptFormat->tymed) &&
        (pformatetcIn->dwAspect == m_AcceptFormat->dwAspect) &&
        (pformatetcIn->cfFormat == m_AcceptFormat->cfFormat) )
        {
            return CopyMedium(pmedium, m_StorageMedium, m_AcceptFormat);
        }

    return DV_E_FORMATETC;
}

STDMETHODIMP MyDataObject::GetDataHere(FORMATETC *pformatetc, STGMEDIUM *pmedium)
{
    return E_NOTIMPL;
}

STDMETHODIMP MyDataObject::QueryGetData(FORMATETC *pformatetc)
{
    if(NULL == pformatetc )
    {
        return E_INVALIDARG;
    }
    if(!(DVASPECT_CONTENT & pformatetc->dwAspect))
    {
        return DV_E_DVASPECT;
    }
    HRESULT hr = DV_E_TYMED;

    if(m_AcceptFormat->tymed & pformatetc->tymed )
        {
        if(m_AcceptFormat->cfFormat == pformatetc->cfFormat )
            {
            return S_OK;
            }
        else
            {
            hr = DV_E_CLIPFORMAT;
            }
        }
    else
        {
            hr = DV_E_TYMED;
        }
    return hr;
}

STDMETHODIMP MyDataObject::GetCanonicalFormatEtc(FORMATETC *pformatectIn, FORMATETC *pformatetcOut)
{
    pformatetcOut->ptd = NULL;
    return E_NOTIMPL;
}

STDMETHODIMP MyDataObject::SetData(FORMATETC *pformatetc, STGMEDIUM *pmedium, BOOL fRelease)
{
    if ( (NULL == pformatetc) || (NULL == pmedium) )
        return E_INVALIDARG;


    if ( pformatetc->tymed != pmedium->tymed )
        return E_FAIL;

    m_AcceptFormat = new FORMATETC;
    m_StorageMedium = new STGMEDIUM;
    ZeroMemory(m_AcceptFormat, sizeof(FORMATETC));
    ZeroMemory(m_StorageMedium, sizeof(STGMEDIUM));

    if ( TRUE == fRelease )
    {
        *m_StorageMedium = *pmedium;
    }
    else
    {
        CopyMedium(m_StorageMedium, pmedium, pformatetc);
    }

    return S_OK;
}

STDMETHODIMP MyDataObject::EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC **ppenumFormatEtc)
{
    if(NULL == ppenumFormatEtc)
    {
        return E_INVALIDARG;
    }
    *ppenumFormatEtc = NULL;
    HRESULT hr = E_NOTIMPL;
    if (DATADIR_GET == dwDirection )
    {
        FORMATETC rgfmtetc[] =
        {
            { CF_HDROP, NULL, DVASPECT_CONTENT, 0, TYMED_HGLOBAL },
        };
        hr = CreateEnumFormatEtc(ARRAYSIZE(rgfmtetc), rgfmtetc, ppenumFormatEtc);
    }
    return hr;
}
//Advises:OLE_E_ADVISENOTSUPPORTED
STDMETHODIMP MyDataObject::DAdvise(FORMATETC *pformatetc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection)
{
    UNREFERENCED_PARAMETER(pformatetc);
    UNREFERENCED_PARAMETER(advf);
    UNREFERENCED_PARAMETER(pAdvSink);
    UNREFERENCED_PARAMETER(pdwConnection);
    return E_NOTIMPL;
}

STDMETHODIMP MyDataObject::DUnadvise(DWORD dwConnection)
{
    UNREFERENCED_PARAMETER(dwConnection);
    return E_NOTIMPL;
}

STDMETHODIMP MyDataObject::EnumDAdvise(IEnumSTATDATA **ppenumAdvise)
{
    UNREFERENCED_PARAMETER(ppenumAdvise);
    return E_NOTIMPL;
}
//Advises:OLE_E_ADVISENOTSUPPORTED

HGLOBAL MyDataObject::DupGlobalMem(HGLOBAL hMem)
{
    DWORD   len    = GlobalSize(hMem);
    PVOID   source = GlobalLock(hMem);
    PVOID   dest   = GlobalAlloc(GMEM_ZEROINIT | GMEM_MOVEABLE | GMEM_DDESHARE, len);

    memcpy(dest, source, len);
    GlobalUnlock(hMem);
    return dest;
}

HRESULT MyDataObject::CopyMedium(STGMEDIUM* pMedDest, STGMEDIUM* pMedSrc, FORMATETC* pFmtSrc)
{
    if ( (NULL == pMedDest) || (NULL ==pMedSrc) || (NULL == pFmtSrc) )
    {
        return E_INVALIDARG;
    }
    switch(pMedSrc->tymed)
    {
    case TYMED_HGLOBAL:
        pMedDest->hGlobal = (HGLOBAL)OleDuplicateData(pMedSrc->hGlobal, pFmtSrc->cfFormat, NULL);
        break;
    case TYMED_GDI:
        pMedDest->hBitmap = (HBITMAP)OleDuplicateData(pMedSrc->hBitmap, pFmtSrc->cfFormat, NULL);
        break;
    case TYMED_MFPICT:
        pMedDest->hMetaFilePict = (HMETAFILEPICT)OleDuplicateData(pMedSrc->hMetaFilePict, pFmtSrc->cfFormat, NULL);
        break;
    case TYMED_ENHMF:
        pMedDest->hEnhMetaFile = (HENHMETAFILE)OleDuplicateData(pMedSrc->hEnhMetaFile, pFmtSrc->cfFormat, NULL);
        break;
    case TYMED_FILE:
        pMedSrc->lpszFileName = (LPOLESTR)OleDuplicateData(pMedSrc->lpszFileName, pFmtSrc->cfFormat, NULL);
        break;
    case TYMED_ISTREAM:
        pMedDest->pstm = pMedSrc->pstm;
        pMedSrc->pstm->AddRef();
        break;
    case TYMED_ISTORAGE:
        pMedDest->pstg = pMedSrc->pstg;
        pMedSrc->pstg->AddRef();
        break;
    case TYMED_NULL:
    default:
        break;
    }
    pMedDest->tymed = pMedSrc->tymed;
    pMedDest->pUnkForRelease = NULL;
    if(pMedSrc->pUnkForRelease != NULL)
    {
        pMedDest->pUnkForRelease = pMedSrc->pUnkForRelease;
        pMedSrc->pUnkForRelease->AddRef();
    }
    return S_OK;
}
HRESULT MyDataObject::SetBlob(CLIPFORMAT cf, const void *pvBlob, UINT cbBlob)
{
    void *pv = GlobalAlloc(GPTR, cbBlob);
    HRESULT hr = pv ? S_OK : E_OUTOFMEMORY;
    if ( SUCCEEDED(hr) )
    {
        CopyMemory(pv, pvBlob, cbBlob);
        FORMATETC fmte = {cf, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
        STGMEDIUM medium = {};
        medium.tymed = TYMED_HGLOBAL;
        medium.hGlobal = pv;
        hr = this->SetData(&fmte, &medium, TRUE);
        if (FAILED(hr))
        {
            GlobalFree(pv);
        }
    }
    return hr;
}

HRESULT CreateEnumFormatEtc(UINT cfmt, FORMATETC *afmt, IEnumFORMATETC **ppEnumFormatEtc)
{
    if (cfmt == 0 || afmt == 0 || ppEnumFormatEtc == 0)
        return E_INVALIDARG;

    *ppEnumFormatEtc = new MyEnumFormatEtc(afmt, cfmt);
    return (*ppEnumFormatEtc) ? S_OK: E_OUTOFMEMORY;
}

void DeepCopyFormatEtc(FORMATETC *dest, FORMATETC *source)
{
    *dest = *source;
    if(source->ptd)
    {
        dest->ptd = (DVTARGETDEVICE*)CoTaskMemAlloc(sizeof(DVTARGETDEVICE));
        *(dest->ptd) = *(source->ptd);
    }
}

MyEnumFormatEtc::MyEnumFormatEtc(FORMATETC *pFormatEtc, ULONG nNumFormats)
    :_iRefCount(1),_nIndex(0),_nNumFormats(nNumFormats)
{
    _pFormatEtc  = new FORMATETC[nNumFormats];
    // make a new copy of each FORMATETC structure
    for(ULONG i = 0; i < nNumFormats; i++)
    {
        DeepCopyFormatEtc (&_pFormatEtc[i], &pFormatEtc[i]);
    }
}
MyEnumFormatEtc::~MyEnumFormatEtc()
{
    // first free any DVTARGETDEVICE structures
    for(ULONG i = 0; i < _nNumFormats; i++)
    {
        if(_pFormatEtc[i].ptd)
            CoTaskMemFree(_pFormatEtc[i].ptd);
    }
    // now free the main array
    delete[] _pFormatEtc;
}

HRESULT __stdcall MyEnumFormatEtc::Next(ULONG celt, FORMATETC *pFormatEtc, ULONG *pceltFetched)
{
    ULONG copied = 0;
    // copy the FORMATETC structures into the caller's buffer
    while (_nIndex < _nNumFormats && copied < celt)
    {
        DeepCopyFormatEtc (&pFormatEtc [copied], &_pFormatEtc [_nIndex]);
        copied++;
        _nIndex++;
    }
    // store result
    if(pceltFetched != 0)
        *pceltFetched = copied;
    // did we copy all that was requested?
    return (copied == celt) ? S_OK : S_FALSE;
}

5.MyDropSource.h

#ifndef _MYDROPSOURCE_H_
#define _MYDROPSOURCE_H_

#include <stdio.h>
#include "IDragDemo.h"

class MyDropSource : public IDropSource
{
public:

    //IUnknown implementation
    ULONG __stdcall AddRef();
    ULONG __stdcall Release();
    STDMETHODIMP    QueryInterface(REFIID riid, void **ppvObject);

    //IDropSource members
    STDMETHODIMP QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState);
    STDMETHODIMP GiveFeedback(DWORD dwEffect);

    //Cons/Destructors
    MyDropSource();
    ~MyDropSource();
private:
    LONG refcount;
};
#endif

6.MyDropSource.cpp

#include "MyDataObject.h"
 #include "MyDropSource.h"
 #include <Urlmon.h>

//Constructors
MyDataObject::MyDataObject(MyDropSource* vDropSource)
{
    m_RefCount = 0;
    m_DropSource = vDropSource;
}

//Destructors
MyDataObject::~MyDataObject()
{
    refcount = 0;

    SAFE_DELETE(m_StorageMedium);
    SAFE_DELETE(m_AcceptFormat);
}

//IUnkown implementation
ULONG __stdcall MyDataObject::AddRef()
{
    return InterlockedIncrement(&m_RefCount);
}

ULONG __stdcall MyDataObject::Release()
{
    ULONG nRefCount = InterlockedDecrement(&m_RefCount);

    if (nRefCount == 0)
        delete this;

    return nRefCount;
}

STDMETHODIMP MyDataObject::QueryInterface(REFIID riid, void **ppvObject) {
    if (!ppvObject)
    return E_POINTER;

if (riid == IID_IDataObject)
    *ppvObject = (IDataObject*)this;
else if (riid == IID_IUnknown)
    *ppvObject = (IUnknown*)this;
else
{
    *ppvObject = 0;
    return E_NOINTERFACE;
}

AddRef();
return S_OK;
}

STDMETHODIMP MyDataObject::GetData(FORMATETC *pformatetcIn, STGMEDIUM *pmedium)
{
    //入参检查
    if ( (NULL == pformatetcIn) || (NULL == pmedium) )
    {
        return E_INVALIDARG;
    }

    pmedium->hGlobal = NULL;

    if( (pformatetcIn->tymed & m_AcceptFormat->tymed) &&
        (pformatetcIn->dwAspect == m_AcceptFormat->dwAspect) &&
        (pformatetcIn->cfFormat == m_AcceptFormat->cfFormat) )
        {
            return CopyMedium(pmedium, m_StorageMedium, m_AcceptFormat);
        }

    return DV_E_FORMATETC;
}

STDMETHODIMP MyDataObject::GetDataHere(FORMATETC *pformatetc, STGMEDIUM *pmedium)
{
    return E_NOTIMPL;
}

STDMETHODIMP MyDataObject::QueryGetData(FORMATETC *pformatetc)
{
    if(NULL == pformatetc )
    {
        return E_INVALIDARG;
    }
    if(!(DVASPECT_CONTENT & pformatetc->dwAspect))
    {
        return DV_E_DVASPECT;
    }
    HRESULT hr = DV_E_TYMED;

    if(m_AcceptFormat->tymed & pformatetc->tymed )
        {
        if(m_AcceptFormat->cfFormat == pformatetc->cfFormat )
            {
            return S_OK;
            }
        else
            {
            hr = DV_E_CLIPFORMAT;
            }
        }
    else
        {
            hr = DV_E_TYMED;
        }
    return hr;
}

STDMETHODIMP MyDataObject::GetCanonicalFormatEtc(FORMATETC *pformatectIn, FORMATETC *pformatetcOut)
{
    pformatetcOut->ptd = NULL;
    return E_NOTIMPL;
}

STDMETHODIMP MyDataObject::SetData(FORMATETC *pformatetc, STGMEDIUM *pmedium, BOOL fRelease)
{
    if ( (NULL == pformatetc) || (NULL == pmedium) )
        return E_INVALIDARG;


    if ( pformatetc->tymed != pmedium->tymed )
        return E_FAIL;

    m_AcceptFormat = new FORMATETC;
    m_StorageMedium = new STGMEDIUM;
    ZeroMemory(m_AcceptFormat, sizeof(FORMATETC));
    ZeroMemory(m_StorageMedium, sizeof(STGMEDIUM));

    if ( TRUE == fRelease )
    {
        *m_StorageMedium = *pmedium;
    }
    else
    {
        CopyMedium(m_StorageMedium, pmedium, pformatetc);
    }

    return S_OK;
}

STDMETHODIMP MyDataObject::EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC **ppenumFormatEtc)
{
    if(NULL == ppenumFormatEtc)
    {
        return E_INVALIDARG;
    }
    *ppenumFormatEtc = NULL;
    HRESULT hr = E_NOTIMPL;
    if (DATADIR_GET == dwDirection )
    {
        FORMATETC rgfmtetc[] =
        {
            { CF_HDROP, NULL, DVASPECT_CONTENT, 0, TYMED_HGLOBAL },
        };
        hr = CreateEnumFormatEtc(ARRAYSIZE(rgfmtetc), rgfmtetc, ppenumFormatEtc);
    }
    return hr;
}
//Advises:OLE_E_ADVISENOTSUPPORTED
STDMETHODIMP MyDataObject::DAdvise(FORMATETC *pformatetc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection)
{
    UNREFERENCED_PARAMETER(pformatetc);
    UNREFERENCED_PARAMETER(advf);
    UNREFERENCED_PARAMETER(pAdvSink);
    UNREFERENCED_PARAMETER(pdwConnection);
    return E_NOTIMPL;
}

STDMETHODIMP MyDataObject::DUnadvise(DWORD dwConnection)
{
    UNREFERENCED_PARAMETER(dwConnection);
    return E_NOTIMPL;
}

STDMETHODIMP MyDataObject::EnumDAdvise(IEnumSTATDATA **ppenumAdvise)
{
    UNREFERENCED_PARAMETER(ppenumAdvise);
    return E_NOTIMPL;
}
//Advises:OLE_E_ADVISENOTSUPPORTED

HGLOBAL MyDataObject::DupGlobalMem(HGLOBAL hMem)
{
    DWORD   len    = GlobalSize(hMem);
    PVOID   source = GlobalLock(hMem);
    PVOID   dest   = GlobalAlloc(GMEM_ZEROINIT | GMEM_MOVEABLE | GMEM_DDESHARE, len);

    memcpy(dest, source, len);
    GlobalUnlock(hMem);
    return dest;
}

HRESULT MyDataObject::CopyMedium(STGMEDIUM* pMedDest, STGMEDIUM* pMedSrc, FORMATETC* pFmtSrc)
{
    if ( (NULL == pMedDest) || (NULL ==pMedSrc) || (NULL == pFmtSrc) )
    {
        return E_INVALIDARG;
    }
    switch(pMedSrc->tymed)
    {
    case TYMED_HGLOBAL:
        pMedDest->hGlobal = (HGLOBAL)OleDuplicateData(pMedSrc->hGlobal, pFmtSrc->cfFormat, NULL);
        break;
    case TYMED_GDI:
        pMedDest->hBitmap = (HBITMAP)OleDuplicateData(pMedSrc->hBitmap, pFmtSrc->cfFormat, NULL);
        break;
    case TYMED_MFPICT:
        pMedDest->hMetaFilePict = (HMETAFILEPICT)OleDuplicateData(pMedSrc->hMetaFilePict, pFmtSrc->cfFormat, NULL);
        break;
    case TYMED_ENHMF:
        pMedDest->hEnhMetaFile = (HENHMETAFILE)OleDuplicateData(pMedSrc->hEnhMetaFile, pFmtSrc->cfFormat, NULL);
        break;
    case TYMED_FILE:
        pMedSrc->lpszFileName = (LPOLESTR)OleDuplicateData(pMedSrc->lpszFileName, pFmtSrc->cfFormat, NULL);
        break;
    case TYMED_ISTREAM:
        pMedDest->pstm = pMedSrc->pstm;
        pMedSrc->pstm->AddRef();
        break;
    case TYMED_ISTORAGE:
        pMedDest->pstg = pMedSrc->pstg;
        pMedSrc->pstg->AddRef();
        break;
    case TYMED_NULL:
    default:
        break;
    }
    pMedDest->tymed = pMedSrc->tymed;
    pMedDest->pUnkForRelease = NULL;
    if(pMedSrc->pUnkForRelease != NULL)
    {
        pMedDest->pUnkForRelease = pMedSrc->pUnkForRelease;
        pMedSrc->pUnkForRelease->AddRef();
    }
    return S_OK;
}
HRESULT MyDataObject::SetBlob(CLIPFORMAT cf, const void *pvBlob, UINT cbBlob)
{
    void *pv = GlobalAlloc(GPTR, cbBlob);
    HRESULT hr = pv ? S_OK : E_OUTOFMEMORY;
    if ( SUCCEEDED(hr) )
    {
        CopyMemory(pv, pvBlob, cbBlob);
        FORMATETC fmte = {cf, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
        STGMEDIUM medium = {};
        medium.tymed = TYMED_HGLOBAL;
        medium.hGlobal = pv;
        hr = this->SetData(&fmte, &medium, TRUE);
        if (FAILED(hr))
        {
            GlobalFree(pv);
        }
    }
    return hr;
}

HRESULT CreateEnumFormatEtc(UINT cfmt, FORMATETC *afmt, IEnumFORMATETC **ppEnumFormatEtc)
{
    if (cfmt == 0 || afmt == 0 || ppEnumFormatEtc == 0)
        return E_INVALIDARG;

    *ppEnumFormatEtc = new MyEnumFormatEtc(afmt, cfmt);
    return (*ppEnumFormatEtc) ? S_OK: E_OUTOFMEMORY;
}

void DeepCopyFormatEtc(FORMATETC *dest, FORMATETC *source)
{
    // copy the source FORMATETC into dest
    *dest = *source;
    if(source->ptd)
    {
        // allocate memory for the DVTARGETDEVICE if necessary
        dest->ptd = (DVTARGETDEVICE*)CoTaskMemAlloc(sizeof(DVTARGETDEVICE));
        // copy the contents of the source DVTARGETDEVICE into dest->ptd
        *(dest->ptd) = *(source->ptd);
    }
}

MyEnumFormatEtc::MyEnumFormatEtc(FORMATETC *pFormatEtc, ULONG nNumFormats)
    :_iRefCount(1),_nIndex(0),_nNumFormats(nNumFormats)
{
    _pFormatEtc  = new FORMATETC[nNumFormats];
    // make a new copy of each FORMATETC structure
    for(ULONG i = 0; i < nNumFormats; i++)
    {
        DeepCopyFormatEtc (&_pFormatEtc[i], &pFormatEtc[i]);
    }
}
MyEnumFormatEtc::~MyEnumFormatEtc()
{
    // first free any DVTARGETDEVICE structures
    for(ULONG i = 0; i < _nNumFormats; i++)
    {
        if(_pFormatEtc[i].ptd)
            CoTaskMemFree(_pFormatEtc[i].ptd);
    }
    // now free the main array
    delete[] _pFormatEtc;
}

HRESULT __stdcall MyEnumFormatEtc::Next(ULONG celt, FORMATETC *pFormatEtc, ULONG *pceltFetched)
{
    ULONG copied = 0;
    // copy the FORMATETC structures into the caller's buffer
    while (_nIndex < _nNumFormats && copied < celt)
    {
        DeepCopyFormatEtc (&pFormatEtc [copied], &_pFormatEtc [_nIndex]);
        copied++;
        _nIndex++;
    }
    // store result
    if(pceltFetched != 0)
        *pceltFetched = copied;
    // did we copy all that was requested?
    return (copied == celt) ? S_OK : S_FALSE;
}

7.IDragDemo.h

#ifndef _DRAGDROP_H_
#define _DRAGDROP_H_
#include <windows.h>
#include <ole2.h>
#include <Shlobj.h>
#endif //_DRAGDROP_H_

Complete Code can be get here:https://github.com/cyfingm/cb_ole_dragdrop


回答1:


OleIsCurrentClipboard() is returning S_FALSE because you are calling OleFlushClipboard() beforehand. Read the documentation:

OleFlushClipboard function

Carries out the clipboard shutdown sequence. It also releases the IDataObject pointer that was placed on the clipboard by the OleSetClipboard function.

...

OleFlushClipboard renders the data from a data object onto the clipboard and releases the IDataObject pointer to the data object.

...

Before calling OleFlushClipboard, you can easily determine if your data is still on the clipboard with a call to the OleIsCurrentClipboard function.

Basically, once you call OleFlushClipboard(), the clipboard no longer contains a pointer to your IDataObject. The CF_HDROP data gets copied directly onto the clipboard, and the IDataObject is removed.

Why are you involving the clipboard at all? You do not need to put the IDataObject on the clipboard in order to use DoDragDrop(), so stop doing that. You pass the IDataObject directly to DoDragDrop(), that is all you need to do.

There are other problems with this code as well.

This line is wrong:

strcpy((char*)(tDropFiles+sizeof(DROPFILES)), tFileName);

It should be this instead:

strcpy(((char*)tDropFiles)+sizeof(DROPFILES), tFileName);

Or this:

strcpy((char*)(tDropFiles+1), tFileName);

You are also not maintaining the IDataObject and IDropSource reference counts correctly. When you create those objects, their reference counts are 0. OleSetClipboard() will increment the IDataObject reference count, then OleFlushClipboard() will decrement it, freeing that object before DoDragDrop() is called. Label1EndDrag() needs to call AddRef() on both objects after creating them (it has a reference to them, afterall), and then call Release() when it is done using them.

pDropSource  = new MyDropSource();
pDropSource->AddRef();

pDataObject  = new MyDataObject((MyDropSource*)pDropSource);//(&fmtetc, &stgmed, 1);
pDataObject->AddRef();

...

pDropSource->Release();
pDataObject->Release();

Also, this will not work:

(MyDropSource*)pDropSource

You cannot create a MyDropSource instance, assign it to an IDropSource* pointer, and then type-cast it back to MyDropSource*. And besides, there is no good reason to have MyDataObject contain a pointer to MyDropSource (especially since it is not actually using it for anything, nor is it incrementing/decrementing the reference count), so you need to remove that altogether.

Lastly, your QueryInterface() implementations are not returning the correct output pointer address. It is not taking polymorphic vtables into account correctly. The implementation need to look more like this instead:

STDMETHODIMP MyDataObject::QueryInterface(REFIID riid, void **ppvObject)
{
    if (!ppvObject)
        return E_POINTER;

    if (riid == IID_IDataObject)
        *ppvObject = (IDataObject*)this;
    else if (riid == IID_IUnknown)
        *ppvObject = (IUnknown*)this;
    else
    {
        *ppvObject = 0;
        return E_NOINTERFACE;
    }

    AddRef();
    return S_OK;
}

I'm sure there are other flaws and leaks in this code, but I stopped reviewing after seeing these big flaws. It is not a very clean implementation in general.

Update: DROPEFFECT_NONE is defined as 0, so the statement

if((dwEffect & DROPEFFECT_NONE) == DROPEFFECT_NONE)

Will always evaluate as true, regardless of the value of dwEffect. Don't use the bitwise & operator to test for DROPEFFECT_NONE, use the == operator instead. Use & for all other values.

if(dwEffect == DROPEFFECT_NONE)
    MessageBoxA(NULL, "Ole data not accepted!!", "DRAGDROP_S_DROP", 0);
else if((dwEffect & DROPEFFECT_MOVE) == DROPEFFECT_MOVE)
    MessageBoxA(NULL, "Ole data moved!!", "DRAGDROP_S_DROP", 0);
else if((dwEffect & DROPEFFECT_COPY) == DROPEFFECT_COPY)
    MessageBoxA(NULL, "Ole data copied!!", "DRAGDROP_S_DROP", 0);
...


来源:https://stackoverflow.com/questions/28513635/somthing-confused-with-ole-drag-and-drop-implementation

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!