一些事情与ole拖放实现混淆 [英] Somthing confused with ole drag and drop implementation

查看:359
本文介绍了一些事情与ole拖放实现混淆的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我希望完成一个实现OLE拖放的演示(将文件从我的应用程序拖到Windows资源管理器)。

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

但是这里有一个问题:DoDragDrop返回DRAGDROP_S_DROP,这意味着拖拽操作已经成功完成,但也可以获取DROPEFFECT_NONE,这意味着删除目标无法接受数据。

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:(

这是gui:

Here is the gui:

关键代码来自:
1.MainWindow.h

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在MainWindow.cpp中调用

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

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

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

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

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

7.IDragDemo.h

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

完整代码可以在这里: https://github.com/cyfingm/cb_ole_dragdrop

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

推荐答案

OleIsCurrentClipboard()正在返回 S_FALSE ,因为您正在调用 OleFlushClipboard()事先。阅读文档:

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

OleFlushClipboard功能


执行剪贴板关闭顺序。 它还释放由OleSetClipboard函数放在剪贴板上的IDataObject指针。

...

OleFlushClipboard将数据对象的数据从数据对象呈现到剪贴板上,并释放IDataObject指向数据对象的指针。

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

...

之前调用OleFlushClipboard,您可以轻松确定您的数据是否仍在剪贴板上,并调用OleIsCurrentClipboard函数。 / p>

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

基本上,一旦你调用了 OleFlushClipboard(),剪贴板就不再包含指向您的 IDataObject 。 The CF_HDROP data gets copied directly onto the clipboard, and the IDataObject is removed.

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.

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.

There are other problems with this code as well.

This line is wrong:

This line is wrong:

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

It should be this instead:

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.

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:

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.

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:

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.

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

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.

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);
...

这篇关于一些事情与ole拖放实现混淆的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆