我希望完成一个小的演示来实现OLE拖放(将文件从我的应用程序拖到Windows资源管理器中)。
但是出现了一个问题:DoDragDrop返回DRAGDROP_S_DROP,这意味着ole拖放操作已成功完成,但也获得了DROPEFFECT_NONE,这意味着drop target无法接受数据。
我调试了它,但我弄得一团糟,请帮帮我,(
这是gui:
关键代码来了: 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中调用
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_
答案 0 :(得分:1)
OleIsCurrentClipboard()
正在返回S_FALSE
,因为您事先正在调用OleFlushClipboard()
。阅读文档:
执行剪贴板关闭序列。 它还会释放由OleSetClipboard函数放置在剪贴板上的IDataObject指针。
...
OleFlushClipboard将数据对象中的数据呈现到剪贴板,并释放指向数据对象的IDataObject指针。
...
在调用OleFlushClipboard之前,您可以通过调用OleIsCurrentClipboard函数轻松确定数据是否仍在剪贴板上。
基本上,一旦您拨打OleFlushClipboard()
,剪贴板就不再包含指向IDataObject
的指针。 <{1}}数据会直接复制到剪贴板上,并删除CF_HDROP
。
你为什么要涉及剪贴板?您无需将IDataObject
放在剪贴板上即可使用IDataObject
,因此请停止这样做。您将DoDragDrop()
直接传递给IDataObject
,这就是您需要做的一切。
此代码还存在其他问题。
这一行错了:
DoDragDrop()
应该是这样:
strcpy((char*)(tDropFiles+sizeof(DROPFILES)), tFileName);
或者这个:
strcpy(((char*)tDropFiles)+sizeof(DROPFILES), tFileName);
您也没有正确维护strcpy((char*)(tDropFiles+1), tFileName);
和IDataObject
引用计数。创建这些对象时,它们的引用计数为0. IDropSource
将增加OleSetClipboard()
引用计数,然后IDataObject
将减少它,在调用OleFlushClipboard()
之前释放该对象。 DoDragDrop()
需要在创建它们之后在两个对象上调用Label1EndDrag()
(它具有对它们的引用,毕竟),然后在使用它们时调用AddRef()
。
Release()
此外,这不起作用:
pDropSource = new MyDropSource();
pDropSource->AddRef();
pDataObject = new MyDataObject((MyDropSource*)pDropSource);//(&fmtetc, &stgmed, 1);
pDataObject->AddRef();
...
pDropSource->Release();
pDataObject->Release();
您无法创建(MyDropSource*)pDropSource
实例,将其分配给MyDropSource
指针,然后将其强制转换回IDropSource*
。此外,没有充分的理由让MyDropSource*
包含指向MyDataObject
的指针(特别是因为它实际上并没有将它用于任何事情,也没有递增/递减引用计数),所以你需要完全删除它。
最后,您的MyDropSource
实现没有返回正确的输出指针地址。它没有正确考虑多态vtable。实现需要看起来更像这样:
QueryInterface()
我确定此代码中还有其他漏洞和漏洞,但在看到这些大漏洞后我停止了审核。一般来说,它不是一个非常干净的实现。
更新: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;
}
定义为0,因此语句
DROPEFFECT_NONE
无论if((dwEffect & DROPEFFECT_NONE) == DROPEFFECT_NONE)
的值如何,始终评估为 true 。不要使用按位dwEffect
运算符来测试&
,而是使用DROPEFFECT_NONE
运算符。对所有其他值使用==
。
&