Patch by Dmitriy Mazovka:

add drag'n drop support in ecore_win32 (reworked) (missing files)


SVN revision: 37890
This commit is contained in:
Vincent Torri 2008-12-01 22:43:04 +00:00
parent 6a06a92ac8
commit 1a897239c7
9 changed files with 1005 additions and 0 deletions

View File

@ -0,0 +1,133 @@
/*
* vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <windows.h>
#include "Ecore_Win32.h"
#include "ecore_win32_private.h"
static int _ecore_win32_dnd_init_count = 0;
static HANDLE DataToHandle(const char *data, int size)
{
char *ptr;
ptr = (char *)GlobalAlloc(GMEM_FIXED, size);
memcpy(ptr, data, size);
return ptr;
}
int
ecore_win32_dnd_init()
{
if (_ecore_win32_dnd_init_count > 0)
{
_ecore_win32_dnd_init_count++;
return _ecore_win32_dnd_init_count;
}
if (OleInitialize(NULL) != S_OK)
return 0;
_ecore_win32_dnd_init_count++;
return _ecore_win32_dnd_init_count;
}
int ecore_win32_dnd_shutdown()
{
_ecore_win32_dnd_init_count--;
if (_ecore_win32_dnd_init_count > 0) return _ecore_win32_dnd_init_count;
OleUninitialize();
if (_ecore_win32_dnd_init_count < 0) _ecore_win32_dnd_init_count = 0;
return _ecore_win32_dnd_init_count;
}
int ecore_win32_dnd_begin(const char *data,
int size)
{
if (data == NULL)
return 0;
if (size < 0)
size = strlen(data) + 1;
IDataObject *pDataObject = NULL;
IDropSource *pDropSource = NULL;
FORMATETC fmtetc = { CF_TEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
STGMEDIUM stgmed = { TYMED_HGLOBAL, { 0 }, 0 };
stgmed.hGlobal = DataToHandle(data, size);
int res = 0;
// create the data object
pDataObject = (IDataObject *)_ecore_win32_dnd_data_object_new((void *)&fmtetc,
(void *)&stgmed,
1);
pDropSource = (IDropSource *)_ecore_win32_dnd_drop_source_new();
if (pDataObject && pDropSource)
{
DWORD dwResult;
DWORD dwEffect = DROPEFFECT_COPY;
// do the drag-drop!
dwResult = DoDragDrop(pDataObject, pDropSource, DROPEFFECT_COPY, &dwEffect);
// finished. Check the return values to see if we need to do anything else
if (dwResult == DRAGDROP_S_DROP)
{
//printf(">>> \"%s\" Dropped <<<\n", str);
if(dwEffect == DROPEFFECT_MOVE)
{
// remove the data we just dropped from active document
}
}
//else if (dwResult == DRAGDROP_S_CANCEL)
// printf("DND cancelled\n");
//else
// printf("DND error\n");
res = 1;
}
_ecore_win32_dnd_data_object_free(pDataObject);
_ecore_win32_dnd_drop_source_free(pDropSource);
// cleanup
ReleaseStgMedium(&stgmed);
return (int)res;
}
int ecore_win32_dnd_register_drop_target(Ecore_Win32_Window *window,
Ecore_Win32_Dnd_DropTarget_Callback callback)
{
if (window == NULL)
return 0;
struct _Ecore_Win32_Window *wnd = (struct _Ecore_Win32_Window *)window;
wnd->dnd_drop_target = _ecore_win32_dnd_register_drop_window(wnd->window,
callback,
(void *)wnd);
return (int)(wnd->dnd_drop_target != NULL);
}
void ecore_win32_dnd_unregister_drop_target(Ecore_Win32_Window *window)
{
if (window == NULL)
return;
struct _Ecore_Win32_Window *wnd = (struct _Ecore_Win32_Window *)window;
if (wnd->dnd_drop_target != NULL)
_ecore_win32_dnd_unregister_drop_window(wnd->window, wnd->dnd_drop_target);
}

View File

@ -0,0 +1,209 @@
/*
* vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <assert.h>
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#undef WIN32_LEAN_AND_MEAN
#include <ole2.h>
#include "Ecore_Win32.h"
#include "ecore_win32_private.h"
#include "ecore_win32_dnd_enumformatetc.h"
#include "ecore_win32_dnd_data_object.h"
static HGLOBAL DupGlobalMem(HGLOBAL hMem)
{
DWORD len = (DWORD)GlobalSize(hMem);
PVOID source = GlobalLock(hMem);
PVOID dest = GlobalAlloc(GMEM_FIXED, len);
memcpy(dest, source, len);
GlobalUnlock(hMem);
return dest;
}
// structors
DataObject::DataObject(FORMATETC *fmtetc, STGMEDIUM *stgmed, int count)
{
assert(fmtetc != NULL);
assert(stgmed != NULL);
assert(count > 0);
// reference count must ALWAYS start at 1
ref_count_ = 1;
formats_num_ = count;
format_etc_ = new FORMATETC[count];
stg_medium_ = new STGMEDIUM[count];
for(int i = 0; i < count; i++)
{
format_etc_[i] = fmtetc[i];
stg_medium_[i] = stgmed[i];
}
}
DataObject::~DataObject()
{
delete[] format_etc_;
delete[] stg_medium_;
}
// IUnknown
HRESULT DataObject::QueryInterface(REFIID iid, void **ppvObject)
{
// check to see what interface has been requested
if ((iid == IID_IDataObject) || (iid == IID_IUnknown))
{
AddRef();
*ppvObject = this;
return S_OK;
}
*ppvObject = 0;
return E_NOINTERFACE;
}
ULONG DataObject::AddRef()
{
return InterlockedIncrement(&ref_count_);
}
ULONG DataObject::Release()
{
LONG count = InterlockedDecrement(&ref_count_);
if(count == 0)
{
delete this;
return 0;
}
return count;
}
// IDataObject
HRESULT DataObject::GetData(FORMATETC *pFormatEtc, STGMEDIUM *pMedium)
{
assert(pMedium != NULL);
int idx;
// try to match the specified FORMATETC with one of our supported formats
if((idx = lookup_format_etc(pFormatEtc)) == -1)
return DV_E_FORMATETC;
// found a match - transfer data into supplied storage medium
pMedium->tymed = format_etc_[idx].tymed;
pMedium->pUnkForRelease = 0;
// copy the data into the caller's storage medium
switch(format_etc_[idx].tymed)
{
case TYMED_HGLOBAL:
pMedium->hGlobal = DupGlobalMem(stg_medium_[idx].hGlobal);
break;
default:
return DV_E_FORMATETC;
}
return S_OK;
}
HRESULT DataObject::GetDataHere(FORMATETC *pFormatEtc, STGMEDIUM *pmedium)
{
return DATA_E_FORMATETC;
}
HRESULT DataObject::QueryGetData(FORMATETC *pFormatEtc)
{
return (lookup_format_etc(pFormatEtc) == -1) ? DV_E_FORMATETC : S_OK;
}
HRESULT DataObject::GetCanonicalFormatEtc(FORMATETC *pFormatEct, FORMATETC *pFormatEtcOut)
{
// Apparently we have to set this field to NULL even though we don't do anything else
pFormatEtcOut->ptd = NULL;
return E_NOTIMPL;
}
HRESULT DataObject::SetData(FORMATETC *pFormatEtc, STGMEDIUM *pMedium, BOOL fRelease)
{
return E_NOTIMPL;
}
HRESULT DataObject::EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC **ppEnumFormatEtc)
{
// only the get direction is supported for OLE
if(dwDirection == DATADIR_GET)
{
// for Win2k+ you can use the SHCreateStdEnumFmtEtc API call, however
// to support all Windows platforms we need to implement IEnumFormatEtc ourselves.
return CreateEnumFormatEtc(formats_num_, format_etc_, ppEnumFormatEtc);
}
else
{
// the direction specified is not supported for drag+drop
return E_NOTIMPL;
}
}
HRESULT DataObject::DAdvise(FORMATETC *pFormatEtc, DWORD advf, IAdviseSink *, DWORD *)
{
return OLE_E_ADVISENOTSUPPORTED;
}
HRESULT DataObject::DUnadvise(DWORD dwConnection)
{
return OLE_E_ADVISENOTSUPPORTED;
}
HRESULT DataObject::EnumDAdvise(IEnumSTATDATA **ppEnumAdvise)
{
return OLE_E_ADVISENOTSUPPORTED;
}
// internal helper function
int DataObject::lookup_format_etc(FORMATETC *pFormatEtc)
{
// check each of our formats in turn to see if one matches
for(int i = 0; i < formats_num_; i++)
{
if((format_etc_[i].tymed & pFormatEtc->tymed) &&
(format_etc_[i].cfFormat == pFormatEtc->cfFormat) &&
(format_etc_[i].dwAspect == pFormatEtc->dwAspect))
{
// return index of stored format
return i;
}
}
// error, format not found
return -1;
}
void *_ecore_win32_dnd_data_object_new(void *fmtetc, void *stgmeds, int count)
{
IDataObject *object = new DataObject((FORMATETC *)fmtetc, (STGMEDIUM *)stgmeds, (UINT)count);
assert(object != NULL);
return object;
}
void _ecore_win32_dnd_data_object_free(void *data_object)
{
if (!data_object)
return;
IDataObject *object = (IDataObject *)data_object;
object->Release();
}

View File

@ -0,0 +1,49 @@
#ifndef __ECORE_WIN32_DND_DATA_OBJECT_H__
#define __ECORE_WIN32_DND_DATA_OBJECT_H__
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#undef WIN32_LEAN_AND_MEAN
#include <objbase.h>
class DataObject : public IDataObject
{
private:
LONG ref_count_;
int formats_num_;
FORMATETC *format_etc_;
STGMEDIUM *stg_medium_;
private: // internal helper function
int lookup_format_etc(FORMATETC *format_etc);
public: // structors
DataObject(FORMATETC *fmtetc, STGMEDIUM *stgmed, int count);
~DataObject();
public: // IUnknown
HRESULT __stdcall QueryInterface(REFIID iid, void **ppvObject);
ULONG __stdcall AddRef();
ULONG __stdcall Release();
public: // IDataObject
HRESULT __stdcall GetData(FORMATETC *pFormatEtc, STGMEDIUM *pmedium);
HRESULT __stdcall GetDataHere(FORMATETC *pFormatEtc, STGMEDIUM *pmedium);
HRESULT __stdcall QueryGetData(FORMATETC *pFormatEtc);
HRESULT __stdcall GetCanonicalFormatEtc(FORMATETC *pFormatEct, FORMATETC *pFormatEtcOut);
HRESULT __stdcall SetData(FORMATETC *pFormatEtc, STGMEDIUM *pMedium, BOOL fRelease);
HRESULT __stdcall EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC **ppEnumFormatEtc);
HRESULT __stdcall DAdvise(FORMATETC *pFormatEtc, DWORD advf, IAdviseSink *, DWORD *);
HRESULT __stdcall DUnadvise(DWORD dwConnection);
HRESULT __stdcall EnumDAdvise(IEnumSTATDATA **ppEnumAdvise);
};
#endif /* __ECORE_WIN32_DND_DATA_OBJECT_H__ */

View File

@ -0,0 +1,92 @@
/*
* vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <assert.h>
#include "ecore_win32_dnd_drop_source.h"
#include "ecore_win32_private.h"
// structors
// reference count must ALWAYS start at 1
DropSource::DropSource() : ref_count_(1)
{ }
// IUnknown
HRESULT DropSource::QueryInterface(REFIID iid, void **ppvObject)
{
// check to see what interface has been requested
if (iid == IID_IDropSource || iid == IID_IUnknown)
{
AddRef();
*ppvObject = this;
return S_OK;
}
*ppvObject = 0;
return E_NOINTERFACE;
}
ULONG DropSource::AddRef()
{
return InterlockedIncrement(&ref_count_);
}
ULONG DropSource::Release()
{
LONG count = InterlockedDecrement(&ref_count_);
if(count == 0)
{
delete this;
return 0;
}
return count;
}
// IDropSource
HRESULT DropSource::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState)
{
// if the Escape key has been pressed since the last call, cancel the drop
if(fEscapePressed == TRUE)
return DRAGDROP_S_CANCEL;
// if the LeftMouse button has been released, then do the drop!
if((grfKeyState & MK_LBUTTON) == 0)
return DRAGDROP_S_DROP;
// continue with the drag-drop
return S_OK;
}
HRESULT DropSource::GiveFeedback(DWORD dwEffect)
{
return DRAGDROP_S_USEDEFAULTCURSORS;
}
// ecore_win32 private functions
void *_ecore_win32_dnd_drop_source_new()
{
IDropSource *object = new DropSource();
assert(object != NULL);
return object;
}
void _ecore_win32_dnd_drop_source_free(void *drop_source)
{
if (!drop_source)
return;
IDropSource *object = (IDropSource *)drop_source;
object->Release();
}

View File

@ -0,0 +1,36 @@
#ifndef __ECORE_WIN32_DND_DROP_SOURCE_H__
#define __ECORE_WIN32_DND_DROP_SOURCE_H__
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#undef WIN32_LEAN_AND_MEAN
#include <ole2.h>
#include "Ecore_Win32.h"
class DropSource : public IDropSource
{
private:
LONG ref_count_;
public: // structors
DropSource();
public: // IUnknown
HRESULT __stdcall QueryInterface(REFIID iid, void ** ppvObject);
ULONG __stdcall AddRef();
ULONG __stdcall Release();
public: // IDropSource
HRESULT __stdcall QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState);
HRESULT __stdcall GiveFeedback(DWORD dwEffect);
};
#endif /* __ECORE_WIN32_DND_DROP_SOURCE_H__ */

View File

@ -0,0 +1,232 @@
/*
* vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "ecore_win32_dnd_drop_target.h"
#include "ecore_win32_private.h"
// structors
DropTarget::DropTarget(HWND window, Ecore_Win32_Dnd_DropTarget_Callback callback, void *window_obj_ptr)
: ref_count_(1)
, window_(window)
, allow_drop_(false)
, drop_callback_(callback)
,drop_callback_ptr_(window_obj_ptr)
{ }
// IUnknown
HRESULT DropTarget::QueryInterface(REFIID iid, void **ppvObject)
{
// check to see what interface has been requested
if (iid == IID_IDropTarget || iid == IID_IUnknown)
{
AddRef();
*ppvObject = this;
return S_OK;
}
*ppvObject = 0;
return E_NOINTERFACE;
}
ULONG DropTarget::AddRef()
{
return InterlockedIncrement(&ref_count_);
}
ULONG DropTarget::Release()
{
LONG count = InterlockedDecrement(&ref_count_);
if (count == 0)
{
delete this;
return 0;
}
return count;
}
// IDropTarget
HRESULT DropTarget::DragEnter(IDataObject *pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
{
// does the dataobject contain data we want?
allow_drop_ = QueryDataObject(pDataObject) &&
(drop_callback_ == NULL ||
(drop_callback_(drop_callback_ptr_, ECORE_WIN32_DND_EVENT_DRAG_ENTER, pt.x, pt.y, NULL, 0) != 0));
if (allow_drop_)
{
// get the dropeffect based on keyboard state
*pdwEffect = DropEffect(grfKeyState, pt, *pdwEffect);
SetFocus(window_);
//PositionCursor(_hwnd, pt);
}
else
*pdwEffect = DROPEFFECT_NONE;
return S_OK;
}
HRESULT DropTarget::DragOver(DWORD grfKeyState, POINTL pt, DWORD * pdwEffect)
{
allow_drop_ =
(drop_callback_ == NULL) ||
(drop_callback_(drop_callback_ptr_, ECORE_WIN32_DND_EVENT_DRAG_OVER, pt.x, pt.y, NULL, 0) != 0);
if (allow_drop_)
{
*pdwEffect = DropEffect(grfKeyState, pt, *pdwEffect);
//PositionCursor(m_hWnd, pt);
}
else
{
*pdwEffect = DROPEFFECT_NONE;
}
return S_OK;
}
HRESULT DropTarget::DragLeave()
{
POINT pt;
GetCursorPos(&pt);
if (drop_callback_ != NULL)
drop_callback_(drop_callback_ptr_, ECORE_WIN32_DND_EVENT_DRAG_LEAVE, pt.x, pt.y, NULL, 0);
return S_OK;
}
HRESULT DropTarget::Drop(IDataObject *pDataObject, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
{
if (allow_drop_)
{
// construct a FORMATETC object
FORMATETC fmtetc = { CF_TEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
STGMEDIUM stgmed;
// See if the dataobject contains any TEXT stored as a HGLOBAL
if (pDataObject->QueryGetData(&fmtetc) == S_OK)
{
// Yippie! the data is there, so go get it!
if (pDataObject->GetData(&fmtetc, &stgmed) == S_OK)
{
// we asked for the data as a HGLOBAL, so access it appropriately
PVOID data = GlobalLock(stgmed.hGlobal);
UINT size = GlobalSize(stgmed.hGlobal);
if (drop_callback_ != NULL)
{
drop_callback_(drop_callback_ptr_,
ECORE_WIN32_DND_EVENT_DROP,
pt.x, pt.y,
data, size);
}
GlobalUnlock(stgmed.hGlobal);
// release the data using the COM API
ReleaseStgMedium(&stgmed);
}
}
*pdwEffect = DropEffect(grfKeyState, pt, *pdwEffect);
}
else
{
*pdwEffect = DROPEFFECT_NONE;
}
return S_OK;
}
// internal helper function
DWORD DropTarget::DropEffect(DWORD grfKeyState, POINTL pt, DWORD dwAllowed)
{
DWORD dwEffect = 0;
// 1. check "pt" -> do we allow a drop at the specified coordinates?
// 2. work out that the drop-effect should be based on grfKeyState
if (grfKeyState & MK_CONTROL)
{
dwEffect = dwAllowed & DROPEFFECT_COPY;
}
else if (grfKeyState & MK_SHIFT)
{
dwEffect = dwAllowed & DROPEFFECT_MOVE;
}
// 3. no key-modifiers were specified (or drop effect not allowed), so
// base the effect on those allowed by the dropsource
if (dwEffect == 0)
{
if (dwAllowed & DROPEFFECT_COPY) dwEffect = DROPEFFECT_COPY;
if (dwAllowed & DROPEFFECT_MOVE) dwEffect = DROPEFFECT_MOVE;
}
return dwEffect;
}
bool DropTarget::QueryDataObject(IDataObject *pDataObject)
{
FORMATETC fmtetc = { CF_TEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
// does the data object support CF_TEXT using a HGLOBAL?
return pDataObject->QueryGetData(&fmtetc) == S_OK;
}
// ecore_win32 private functions
void *_ecore_win32_dnd_register_drop_window(HWND hwnd, Ecore_Win32_Dnd_DropTarget_Callback callback, void *ptr)
{
DropTarget *pDropTarget = new DropTarget(hwnd, callback, ptr);
if (pDropTarget == NULL)
return NULL;
// acquire a strong lock
if (FAILED(CoLockObjectExternal(pDropTarget, TRUE, FALSE)))
{
delete pDropTarget;
return NULL;
}
// tell OLE that the window is a drop target
if (FAILED(RegisterDragDrop(hwnd, pDropTarget)))
{
delete pDropTarget;
return NULL;
}
return pDropTarget;
}
void _ecore_win32_dnd_unregister_drop_window(HWND hwnd, void *drop_target)
{
IDropTarget *pDropTarget = (IDropTarget *)drop_target;
if (drop_target == NULL)
return;
// remove drag+drop
RevokeDragDrop(hwnd);
// remove the strong lock
CoLockObjectExternal(pDropTarget, FALSE, TRUE);
// release our own reference
pDropTarget->Release();
}

View File

@ -0,0 +1,47 @@
#ifndef __ECORE_WIN32_DND_DROP_TARGET_H__
#define __ECORE_WIN32_DND_DROP_TARGET_H__
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#undef WIN32_LEAN_AND_MEAN
#include <ole2.h>
#include "Ecore_Win32.h"
class DropTarget : public IDropTarget
{
private:
LONG ref_count_;
HWND window_;
bool allow_drop_;
Ecore_Win32_Dnd_DropTarget_Callback drop_callback_;
void *drop_callback_ptr_;
private: // internal helper function
DWORD DropEffect(DWORD grfKeyState, POINTL pt, DWORD dwAllowed);
bool QueryDataObject(IDataObject *pDataObject);
public: // structors
DropTarget(HWND hwnd, Ecore_Win32_Dnd_DropTarget_Callback callback, void *window_obj_ptr);
public: // IUnknown
HRESULT __stdcall QueryInterface(REFIID iid, void ** ppvObject);
ULONG __stdcall AddRef();
ULONG __stdcall Release();
public: // IDropTarget
HRESULT __stdcall DragEnter(IDataObject * pDataObject, DWORD grfKeyState, POINTL pt, DWORD * pdwEffect);
HRESULT __stdcall DragOver(DWORD grfKeyState, POINTL pt, DWORD * pdwEffect);
HRESULT __stdcall DragLeave();
HRESULT __stdcall Drop(IDataObject * pDataObject, DWORD grfKeyState, POINTL pt, DWORD * pdwEffect);
};
#endif /* __ECORE_WIN32_DND_DROP_TARGET_H__ */

View File

@ -0,0 +1,157 @@
#include <ole2.h>
#include "ecore_win32_dnd_enumformatetc.h"
// structors
CEnumFormatEtc::CEnumFormatEtc(FORMATETC *format_etc, int formats_num)
: ref_count_(1)
, index_(0)
, formats_num_(formats_num)
, format_etc_(new FORMATETC[formats_num])
{
// make a new copy of each FORMATETC structure
for (unsigned int i = 0; i < formats_num_; i++)
{
DeepCopyFormatEtc(&format_etc_[i], &format_etc[i]);
}
}
CEnumFormatEtc::~CEnumFormatEtc()
{
if (format_etc_)
{
// first free any DVTARGETDEVICE structures
for (ULONG i = 0; i < formats_num_; i++)
{
if (format_etc_[i].ptd)
CoTaskMemFree(format_etc_[i].ptd);
}
// now free the main array
delete[] format_etc_;
}
}
// IUnknown
ULONG __stdcall CEnumFormatEtc::AddRef(void)
{
// increment object reference count
return InterlockedIncrement(&ref_count_);
}
ULONG __stdcall CEnumFormatEtc::Release(void)
{
// decrement object reference count
LONG count = InterlockedDecrement(&ref_count_);
if (count == 0)
{
delete this;
return 0;
}
else
{
return count;
}
}
HRESULT __stdcall CEnumFormatEtc::QueryInterface(REFIID iid, void **ppvObject)
{
// check to see what interface has been requested
if ((iid == IID_IEnumFORMATETC) || (iid == IID_IUnknown))
{
AddRef();
*ppvObject = this;
return S_OK;
}
else
{
*ppvObject = 0;
return E_NOINTERFACE;
}
}
// IEnumFormatEtc
HRESULT CEnumFormatEtc::Reset(void)
{
index_ = 0;
return S_OK;
}
HRESULT CEnumFormatEtc::Skip(ULONG celt)
{
index_ += celt;
return (index_ <= formats_num_) ? S_OK : S_FALSE;
}
HRESULT CEnumFormatEtc::Clone(IEnumFORMATETC **ppEnumFormatEtc)
{
HRESULT hResult;
// make a duplicate enumerator
hResult = CreateEnumFormatEtc(formats_num_, format_etc_, ppEnumFormatEtc);
if (hResult == S_OK)
{
// manually set the index state
((CEnumFormatEtc *)*ppEnumFormatEtc)->index_ = index_;
}
return hResult;
}
HRESULT CEnumFormatEtc::Next(ULONG celt, FORMATETC *pFormatEtc, ULONG *pceltFetched)
{
ULONG copied = 0;
// validate arguments
if ((celt == 0) || (pFormatEtc == 0))
return E_INVALIDARG;
// copy the FORMATETC structures into the caller's buffer
while (index_ < formats_num_ && copied < celt)
{
DeepCopyFormatEtc(&pFormatEtc[copied], &format_etc_[index_]);
copied++;
index_++;
}
// store result
if (pceltFetched != 0)
*pceltFetched = copied;
// did we copy all that was requested?
return (copied == celt) ? S_OK : S_FALSE;
}
// external functions
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);
}
}
HRESULT CreateEnumFormatEtc(UINT cfmt, FORMATETC *afmt, IEnumFORMATETC **ppEnumFormatEtc)
{
if((cfmt == 0) || (afmt == 0) || (ppEnumFormatEtc == 0))
return E_INVALIDARG;
*ppEnumFormatEtc = new CEnumFormatEtc(afmt, cfmt);
return (*ppEnumFormatEtc) ? S_OK : E_OUTOFMEMORY;
}

View File

@ -0,0 +1,50 @@
#ifndef __ECORE_WIN32_DND_ENUMFORMATETC_H__
#define __ECORE_WIN32_DND_ENUMFORMATETC_H__
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#undef WIN32_LEAN_AND_MEAN
#include <objbase.h>
class CEnumFormatEtc : public IEnumFORMATETC
{
private:
LONG ref_count_; // Reference count for this COM interface
ULONG index_; // current enumerator index
ULONG formats_num_; // number of FORMATETC members
FORMATETC *format_etc_; // array of FORMATETC objects
public: // structors
CEnumFormatEtc(FORMATETC *pFormatEtc, int nNumFormats);
~CEnumFormatEtc();
public: // IUnknown
HRESULT __stdcall QueryInterface (REFIID iid, void ** ppvObject);
ULONG __stdcall AddRef (void);
ULONG __stdcall Release (void);
public: // IEnumFormatEtc
HRESULT __stdcall Next (ULONG celt, FORMATETC * rgelt, ULONG * pceltFetched);
HRESULT __stdcall Skip (ULONG celt);
HRESULT __stdcall Reset (void);
HRESULT __stdcall Clone (IEnumFORMATETC ** ppEnumFormatEtc);
};
void DeepCopyFormatEtc(FORMATETC *dest, FORMATETC *source);
HRESULT CreateEnumFormatEtc(UINT cfmt, FORMATETC *afmt, IEnumFORMATETC **ppEnumFormatEtc);
#endif /* __ECORE_WIN32_DND_ENUMFORMATETC_H__ */