问题
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