问题描述
我希望完成一个实现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_
完整代码可以在这里:
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将数据对象的数据从数据对象呈现到剪贴板上,并释放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拖放实现混淆的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!