project64/Source/Project64/UserInterface/WTLControls/ClistCtrl/DragDrop.h

826 lines
22 KiB
C++

#pragma once
#include <shlobj.h>
#include <vector>
using namespace std;
class CEnumFormatEtc : public IEnumFORMATETC
{
public:
CEnumFormatEtc(const vector<FORMATETC> & vFormatEtc)
{
m_nRefCount = 0;
m_nIndex = 0;
m_vFormatEtc = vFormatEtc;
}
protected:
vector<FORMATETC> m_vFormatEtc;
int m_nRefCount;
int m_nIndex;
public:
// IUnknown members
STDMETHOD(QueryInterface)
(REFIID refiid, void FAR * FAR * ppvObject)
{
*ppvObject = (refiid == IID_IUnknown || refiid == IID_IEnumFORMATETC) ? this : nullptr;
if (*ppvObject != nullptr)
((LPUNKNOWN)*ppvObject)->AddRef();
return *ppvObject == nullptr ? E_NOINTERFACE : S_OK;
}
STDMETHOD_(ULONG, AddRef)
(void)
{
return ++m_nRefCount;
}
STDMETHOD_(ULONG, Release)
(void)
{
int nRefCount = --m_nRefCount;
if (nRefCount == 0)
delete this;
return nRefCount;
}
// IEnumFORMATETC members
STDMETHOD(Next)
(ULONG celt, LPFORMATETC lpFormatEtc, ULONG FAR * pceltFetched)
{
if (pceltFetched != nullptr)
*pceltFetched = 0;
ULONG cReturn = celt;
if (celt <= 0 || lpFormatEtc == nullptr || m_nIndex >= (int)m_vFormatEtc.size())
return S_FALSE;
if (pceltFetched == nullptr && celt != 1) // pceltFetched can be nullptr only for 1 item request
return S_FALSE;
while (m_nIndex < (int)m_vFormatEtc.size() && cReturn > 0)
{
*lpFormatEtc++ = m_vFormatEtc[m_nIndex++];
cReturn--;
}
if (pceltFetched != nullptr)
*pceltFetched = celt - cReturn;
return cReturn == 0 ? S_OK : S_FALSE;
}
STDMETHOD(Skip)
(ULONG celt)
{
if ((m_nIndex + (int)celt) >= (int)m_vFormatEtc.size())
return S_FALSE;
m_nIndex += celt;
return S_OK;
}
STDMETHOD(Reset)
(void)
{
m_nIndex = 0;
return S_OK;
}
STDMETHOD(Clone)
(IEnumFORMATETC FAR * FAR * ppCloneEnumFormatEtc)
{
if (ppCloneEnumFormatEtc == nullptr)
return E_POINTER;
*ppCloneEnumFormatEtc = new CEnumFormatEtc(m_vFormatEtc);
((CEnumFormatEtc *)*ppCloneEnumFormatEtc)->AddRef();
((CEnumFormatEtc *)*ppCloneEnumFormatEtc)->m_nIndex = m_nIndex;
return S_OK;
}
};
class CDropSource : public IDropSource
{
public:
CDropSource()
{
m_nRefCount = 0;
}
protected:
int m_nRefCount;
public:
// IUnknown members
STDMETHOD(QueryInterface)
(REFIID refiid, void FAR * FAR * ppvObject)
{
*ppvObject = (refiid == IID_IUnknown || refiid == IID_IDropSource) ? this : nullptr;
if (*ppvObject != nullptr)
((LPUNKNOWN)*ppvObject)->AddRef();
return *ppvObject == nullptr ? E_NOINTERFACE : S_OK;
}
STDMETHOD_(ULONG, AddRef)
(void)
{
return ++m_nRefCount;
}
STDMETHOD_(ULONG, Release)
(void)
{
int nRefCount = --m_nRefCount;
if (nRefCount == 0)
delete this;
return nRefCount;
}
// IDropSource members
STDMETHOD(QueryContinueDrag)
(BOOL bEscapePressed, DWORD dwKeyState)
{
if (bEscapePressed)
return DRAGDROP_S_CANCEL;
if (!(dwKeyState & (MK_LBUTTON | MK_RBUTTON)))
return DRAGDROP_S_DROP;
return S_OK;
}
STDMETHOD(GiveFeedback)
(DWORD /*dwEffect*/)
{
return DRAGDROP_S_USEDEFAULTCURSORS;
}
};
class CDataObject : public IDataObject
{
public:
CDataObject(CDropSource * pDropSource)
{
m_nRefCount = 0;
m_pDropSource = pDropSource;
m_bSwappedButtons = GetSystemMetrics(SM_SWAPBUTTON);
}
virtual ~CDataObject()
{
for (vector<STGMEDIUM>::iterator posStgMedium = m_vStgMedium.begin(); posStgMedium != m_vStgMedium.end(); posStgMedium++)
ReleaseStgMedium(&(*posStgMedium));
}
protected:
CDropSource * m_pDropSource;
int m_nRefCount;
BOOL m_bSwappedButtons;
vector<FORMATETC> m_vFormatEtc;
vector<STGMEDIUM> m_vStgMedium;
public:
// IUnknown members
STDMETHOD(QueryInterface)
(REFIID refiid, void FAR * FAR * ppvObject)
{
*ppvObject = (refiid == IID_IUnknown || refiid == IID_IDataObject) ? this : nullptr;
if (*ppvObject != nullptr)
((LPUNKNOWN)*ppvObject)->AddRef();
return *ppvObject == nullptr ? E_NOINTERFACE : S_OK;
}
STDMETHOD_(ULONG, AddRef)
(void)
{
return ++m_nRefCount;
}
STDMETHOD_(ULONG, Release)
(void)
{
int nRefCount = --m_nRefCount;
if (nRefCount == 0)
delete this;
return nRefCount;
}
// IDataObject members
STDMETHOD(GetData)
(FORMATETC __RPC_FAR * pformatetcIn, STGMEDIUM __RPC_FAR * pmedium)
{
if (pformatetcIn == nullptr || pmedium == nullptr)
return E_INVALIDARG;
ZeroMemory(pmedium, sizeof(STGMEDIUM));
for (int nFormatEtc = 0; nFormatEtc < (int)m_vFormatEtc.size(); nFormatEtc++)
{
if (pformatetcIn->tymed & m_vFormatEtc[nFormatEtc].tymed && pformatetcIn->dwAspect == m_vFormatEtc[nFormatEtc].dwAspect && pformatetcIn->cfFormat == m_vFormatEtc[nFormatEtc].cfFormat)
{
if (m_vStgMedium[nFormatEtc].tymed == TYMED_NULL)
return OnRenderData(m_vFormatEtc[nFormatEtc], pmedium, (GetAsyncKeyState(m_bSwappedButtons ? VK_RBUTTON : VK_LBUTTON) >= 0)) ? S_OK : DV_E_FORMATETC;
CopyMedium(pmedium, m_vStgMedium[nFormatEtc], m_vFormatEtc[nFormatEtc]);
return S_OK;
}
}
return DV_E_FORMATETC;
}
STDMETHOD(GetDataHere)
(FORMATETC __RPC_FAR * /*pformatetc*/, STGMEDIUM __RPC_FAR * /*pmedium*/)
{
return E_NOTIMPL;
}
STDMETHOD(QueryGetData)
(FORMATETC __RPC_FAR * pformatetc)
{
if (pformatetc == nullptr)
return E_INVALIDARG;
if (!(pformatetc->dwAspect & DVASPECT_CONTENT))
return DV_E_DVASPECT;
HRESULT hResult = DV_E_TYMED;
for (int nFormatEtc = 0; nFormatEtc < (int)m_vFormatEtc.size(); nFormatEtc++)
{
if (!(pformatetc->tymed & m_vFormatEtc[nFormatEtc].tymed))
{
hResult = DV_E_TYMED;
continue;
}
if (pformatetc->cfFormat == m_vFormatEtc[nFormatEtc].cfFormat)
return S_OK;
hResult = DV_E_CLIPFORMAT;
}
return hResult;
}
STDMETHOD(GetCanonicalFormatEtc)
(FORMATETC __RPC_FAR * /*pformatectIn*/, FORMATETC __RPC_FAR * pformatetcOut)
{
return pformatetcOut == nullptr ? E_INVALIDARG : DATA_S_SAMEFORMATETC;
}
STDMETHOD(SetData)
(FORMATETC __RPC_FAR * pformatetc, STGMEDIUM __RPC_FAR * pmedium, BOOL bRelease)
{
if (pformatetc == nullptr || pmedium == nullptr)
return E_INVALIDARG;
m_vFormatEtc.push_back(*pformatetc);
STGMEDIUM StgMedium = *pmedium;
if (!bRelease)
CopyMedium(&StgMedium, *pmedium, *pformatetc);
m_vStgMedium.push_back(StgMedium);
return S_OK;
}
STDMETHOD(EnumFormatEtc)
(DWORD dwDirection, IEnumFORMATETC __RPC_FAR * __RPC_FAR * ppenumFormatEtc)
{
if (ppenumFormatEtc == nullptr)
return E_POINTER;
switch (dwDirection)
{
case DATADIR_GET:
*ppenumFormatEtc = new CEnumFormatEtc(m_vFormatEtc);
((CEnumFormatEtc *)*ppenumFormatEtc)->AddRef();
return S_OK;
default:
*ppenumFormatEtc = nullptr;
return E_NOTIMPL;
}
}
STDMETHOD(DAdvise)
(FORMATETC __RPC_FAR * /*pformatetc*/, DWORD /*advf*/, IAdviseSink __RPC_FAR * /*pAdvSink*/, DWORD __RPC_FAR * /*pdwConnection*/)
{
return OLE_E_ADVISENOTSUPPORTED;
}
STDMETHOD(DUnadvise)
(DWORD /*dwConnection*/)
{
return E_NOTIMPL;
}
STDMETHOD(EnumDAdvise)
(IEnumSTATDATA __RPC_FAR * __RPC_FAR * /*ppenumAdvise*/)
{
return OLE_E_ADVISENOTSUPPORTED;
}
void CopyMedium(STGMEDIUM * pMedDest, STGMEDIUM & MedSrc, FORMATETC & FmtSrc)
{
switch (MedSrc.tymed)
{
case TYMED_HGLOBAL:
pMedDest->hGlobal = (HGLOBAL)OleDuplicateData(MedSrc.hGlobal, FmtSrc.cfFormat, NULL);
break;
case TYMED_GDI:
pMedDest->hBitmap = (HBITMAP)OleDuplicateData(MedSrc.hBitmap, FmtSrc.cfFormat, NULL);
break;
case TYMED_MFPICT:
pMedDest->hMetaFilePict = (HMETAFILEPICT)OleDuplicateData(MedSrc.hMetaFilePict, FmtSrc.cfFormat, NULL);
break;
case TYMED_ENHMF:
pMedDest->hEnhMetaFile = (HENHMETAFILE)OleDuplicateData(MedSrc.hEnhMetaFile, FmtSrc.cfFormat, NULL);
break;
case TYMED_FILE:
pMedDest->lpszFileName = (LPOLESTR)OleDuplicateData(MedSrc.lpszFileName, FmtSrc.cfFormat, NULL);
break;
case TYMED_ISTREAM:
pMedDest->pstm = MedSrc.pstm;
MedSrc.pstm->AddRef();
break;
case TYMED_ISTORAGE:
pMedDest->pstg = MedSrc.pstg;
MedSrc.pstg->AddRef();
break;
}
pMedDest->tymed = MedSrc.tymed;
pMedDest->pUnkForRelease = nullptr;
if (MedSrc.pUnkForRelease != nullptr)
{
pMedDest->pUnkForRelease = MedSrc.pUnkForRelease;
MedSrc.pUnkForRelease->AddRef();
}
}
virtual BOOL OnRenderData(FORMATETC & /*FormatEtc*/, STGMEDIUM * /*pStgMedium*/, BOOL /*bDropComplete*/)
{
return FALSE;
}
};
class CDropTarget : public IDropTarget
{
public:
CDropTarget(HWND hTargetWnd)
{
m_hTargetWnd = hTargetWnd;
m_nRefCount = 0;
m_bAllowDrop = FALSE;
m_pDropTargetHelper = nullptr;
ZeroMemory(&m_FormatEtc, sizeof(FORMATETC));
ZeroMemory(&m_StgMedium, sizeof(STGMEDIUM));
if (FAILED(CoCreateInstance(CLSID_DragDropHelper, nullptr, CLSCTX_INPROC_SERVER, IID_IDropTargetHelper, (LPVOID *)&m_pDropTargetHelper)))
m_pDropTargetHelper = nullptr;
}
virtual ~CDropTarget()
{
if (m_pDropTargetHelper != nullptr)
{
m_pDropTargetHelper->Release();
m_pDropTargetHelper = nullptr;
}
}
protected:
HWND m_hTargetWnd;
int m_nRefCount;
struct IDropTargetHelper * m_pDropTargetHelper;
vector<FORMATETC> m_vFormatEtc;
BOOL m_bAllowDrop;
FORMATETC m_FormatEtc;
STGMEDIUM m_StgMedium;
public:
// IUnknown members
STDMETHOD(QueryInterface)
(REFIID refiid, void FAR * FAR * ppvObject)
{
*ppvObject = (refiid == IID_IUnknown || refiid == IID_IDropTarget) ? this : nullptr;
if (*ppvObject != nullptr)
((LPUNKNOWN)*ppvObject)->AddRef();
return *ppvObject == nullptr ? E_NOINTERFACE : S_OK;
}
STDMETHOD_(ULONG, AddRef)
(void)
{
return ++m_nRefCount;
}
STDMETHOD_(ULONG, Release)
(void)
{
int nRefCount = --m_nRefCount;
if (nRefCount == 0)
delete this;
return nRefCount;
}
STDMETHOD(DragEnter)
(IDataObject __RPC_FAR * pDataObject, DWORD dwKeyState, POINTL pt, DWORD __RPC_FAR * pdwEffect)
{
if (pDataObject == nullptr)
return E_INVALIDARG;
if (m_pDropTargetHelper != nullptr)
m_pDropTargetHelper->DragEnter(m_hTargetWnd, pDataObject, (LPPOINT)&pt, *pdwEffect);
ZeroMemory(&m_FormatEtc, sizeof(FORMATETC));
if (m_StgMedium.tymed != TYMED_NULL)
ReleaseStgMedium(&m_StgMedium);
ZeroMemory(&m_StgMedium, sizeof(STGMEDIUM));
for (int nFormatEtc = 0; nFormatEtc < (int)m_vFormatEtc.size(); nFormatEtc++)
{
STGMEDIUM StgMedium;
m_bAllowDrop = (pDataObject->GetData(&m_vFormatEtc[nFormatEtc], &StgMedium) == S_OK);
if (m_bAllowDrop)
{
// Store drag data for later use in DragOver
m_FormatEtc = m_vFormatEtc[nFormatEtc];
m_StgMedium = StgMedium;
// Get client cursor position
CWindow hWnd(m_hTargetWnd);
CPoint point(pt.x, pt.y);
hWnd.ScreenToClient(&point);
*pdwEffect = OnDragEnter(m_FormatEtc, m_StgMedium, dwKeyState, point);
break;
}
}
QueryDrop(dwKeyState, pdwEffect);
return S_OK;
}
STDMETHOD(DragOver)
(DWORD dwKeyState, POINTL pt, DWORD __RPC_FAR * pdwEffect)
{
if (m_pDropTargetHelper)
m_pDropTargetHelper->DragOver((LPPOINT)&pt, *pdwEffect);
if (m_bAllowDrop && m_FormatEtc.cfFormat != CF_NULL && m_StgMedium.tymed != TYMED_NULL)
{
// Get client cursor position
CWindow hWnd(m_hTargetWnd);
CPoint point(pt.x, pt.y);
hWnd.ScreenToClient(&point);
*pdwEffect = OnDragOver(m_FormatEtc, m_StgMedium, dwKeyState, point);
}
QueryDrop(dwKeyState, pdwEffect);
return S_OK;
}
STDMETHOD(DragLeave)
(void)
{
if (m_pDropTargetHelper)
m_pDropTargetHelper->DragLeave();
OnDragLeave();
m_bAllowDrop = FALSE;
ZeroMemory(&m_FormatEtc, sizeof(FORMATETC));
if (m_StgMedium.tymed != TYMED_NULL)
ReleaseStgMedium(&m_StgMedium);
ZeroMemory(&m_StgMedium, sizeof(STGMEDIUM));
return S_OK;
}
STDMETHOD(Drop)
(IDataObject __RPC_FAR * pDataObject, DWORD dwKeyState, POINTL pt, DWORD __RPC_FAR * pdwEffect)
{
if (pDataObject == nullptr)
return E_INVALIDARG;
if (m_pDropTargetHelper)
m_pDropTargetHelper->Drop(pDataObject, (LPPOINT)&pt, *pdwEffect);
if (m_bAllowDrop && m_FormatEtc.cfFormat != CF_NULL && QueryDrop(dwKeyState, pdwEffect))
{
STGMEDIUM StgMedium;
if (pDataObject->GetData(&m_FormatEtc, &StgMedium) == S_OK)
{
// Get client cursor position
CWindow hWnd(m_hTargetWnd);
CPoint point(pt.x, pt.y);
hWnd.ScreenToClient(&point);
if (!OnDrop(m_FormatEtc, StgMedium, *pdwEffect, point))
*pdwEffect = DROPEFFECT_NONE;
ReleaseStgMedium(&StgMedium);
}
}
m_bAllowDrop = FALSE;
ZeroMemory(&m_FormatEtc, sizeof(FORMATETC));
if (m_StgMedium.tymed != TYMED_NULL)
ReleaseStgMedium(&m_StgMedium);
ZeroMemory(&m_StgMedium, sizeof(STGMEDIUM));
return S_OK;
}
void AddSupportedFormat(FORMATETC & FormatEtc)
{
m_vFormatEtc.push_back(FormatEtc);
}
void AddSupportedFormat(CLIPFORMAT cfFormat)
{
FORMATETC FormatEtc;
ZeroMemory(&FormatEtc, sizeof(FORMATETC));
FormatEtc.cfFormat = cfFormat;
FormatEtc.dwAspect = DVASPECT_CONTENT;
FormatEtc.lindex = -1;
FormatEtc.tymed = TYMED_HGLOBAL;
AddSupportedFormat(FormatEtc);
}
BOOL QueryDrop(DWORD dwKeyState, LPDWORD pdwEffect)
{
DWORD dwEffects = *pdwEffect;
if (!m_bAllowDrop)
{
*pdwEffect = DROPEFFECT_NONE;
return FALSE;
}
*pdwEffect = (dwKeyState & MK_CONTROL) ? ((dwKeyState & MK_SHIFT) ? DROPEFFECT_LINK : DROPEFFECT_COPY) : ((dwKeyState & MK_SHIFT) ? DROPEFFECT_MOVE : 0);
if (*pdwEffect == 0)
{
if (dwEffects & DROPEFFECT_COPY)
*pdwEffect = DROPEFFECT_COPY;
else if (dwEffects & DROPEFFECT_MOVE)
*pdwEffect = DROPEFFECT_MOVE;
else if (dwEffects & DROPEFFECT_LINK)
*pdwEffect = DROPEFFECT_LINK;
else
*pdwEffect = DROPEFFECT_NONE;
}
else if (!(*pdwEffect & dwEffects))
*pdwEffect = DROPEFFECT_NONE;
return (*pdwEffect != DROPEFFECT_NONE);
}
virtual DWORD OnDragEnter(FORMATETC & /*FormatEtc*/, STGMEDIUM & /*StgMedium*/, DWORD /*dwKeyState*/, CPoint /*point*/)
{
return FALSE;
}
virtual DWORD OnDragOver(FORMATETC & /*FormatEtc*/, STGMEDIUM & /*StgMedium*/, DWORD /*dwKeyState*/, CPoint /*point*/)
{
return FALSE;
}
virtual BOOL OnDrop(FORMATETC & /*FormatEtc*/, STGMEDIUM & /*StgMedium*/, DWORD /*dwEffect*/, CPoint /*point*/)
{
return FALSE;
}
virtual void OnDragLeave()
{
}
};
template <class T>
class CDropTargetT : public CDropTarget
{
public:
CDropTargetT(HWND hTargetWnd) :
CDropTarget(hTargetWnd)
{
m_pDelegate = nullptr;
}
protected:
T * m_pDelegate;
public:
BOOL Register(T * pDelegate)
{
m_pDelegate = pDelegate;
return TRUE;
}
virtual DWORD OnDragEnter(FORMATETC & FormatEtc, STGMEDIUM & StgMedium, DWORD dwKeyState, CPoint point)
{
return m_pDelegate == nullptr ? DROPEFFECT_NONE : m_pDelegate->OnDragEnter(FormatEtc, StgMedium, dwKeyState, point);
}
virtual DWORD OnDragOver(FORMATETC & FormatEtc, STGMEDIUM & StgMedium, DWORD dwKeyState, CPoint point)
{
return m_pDelegate == nullptr ? DROPEFFECT_NONE : m_pDelegate->OnDragOver(FormatEtc, StgMedium, dwKeyState, point);
}
virtual BOOL OnDrop(FORMATETC & FormatEtc, STGMEDIUM & StgMedium, DWORD dwEffect, CPoint point)
{
return m_pDelegate == nullptr ? FALSE : m_pDelegate->OnDrop(FormatEtc, StgMedium, dwEffect, point);
}
virtual void OnDragLeave()
{
if (m_pDelegate != nullptr)
m_pDelegate->OnDragLeave();
}
};
template <class T>
class CDataObjectT : public CDataObject
{
public:
CDataObjectT(CDropSource * pDropSource) :
CDataObject(pDropSource)
{
m_pDelegate = FALSE;
}
protected:
T * m_pDelegate;
public:
BOOL Register(T * pDelegate)
{
m_pDelegate = pDelegate;
return TRUE;
}
virtual BOOL OnRenderData(FORMATETC & FormatEtc, STGMEDIUM * pStgMedium, BOOL bDropComplete)
{
return m_pDelegate == nullptr ? FALSE : m_pDelegate->OnRenderData(FormatEtc, pStgMedium, bDropComplete);
}
};
template <class T>
class CDragDrop
{
public:
CDragDrop()
{
m_pDropSource = nullptr;
m_pDataObject = nullptr;
m_pDropTarget = nullptr;
m_hTargetWnd = nullptr;
}
virtual ~CDragDrop()
{
if (m_pDropSource != nullptr)
m_pDropSource->Release();
if (m_pDataObject != nullptr)
m_pDataObject->Release();
}
protected:
CDropSource * m_pDropSource;
CDataObjectT<T> * m_pDataObject;
CDropTargetT<T> * m_pDropTarget;
HWND m_hTargetWnd;
public:
BOOL Register(T * pDelegate, BOOL bDropSource = TRUE)
{
m_hTargetWnd = pDelegate->m_hWnd;
// Instantiate new drop target object
m_pDropTarget = new CDropTargetT<T>(m_hTargetWnd);
m_pDropTarget->Register(pDelegate);
// Register drop target
if (FAILED(RegisterDragDrop(m_hTargetWnd, m_pDropTarget)))
{
delete m_pDropTarget;
m_pDropTarget = nullptr;
return FALSE;
}
// Is this a drop target only?
if (!bDropSource)
return TRUE;
// Instantiate new drop source object
m_pDropSource = new CDropSource;
m_pDropSource->AddRef();
m_pDataObject = new CDataObjectT<T>(m_pDropSource);
m_pDataObject->AddRef();
// Register drop source delegate for data render
return m_pDataObject->Register(pDelegate);
}
BOOL Revoke()
{
m_pDropTarget = nullptr;
return (RevokeDragDrop(m_hTargetWnd) == S_OK);
}
BOOL AddTargetFormat(CLIPFORMAT cfFormat)
{
if (m_pDropTarget == nullptr)
return FALSE;
m_pDropTarget->AddSupportedFormat(cfFormat);
return TRUE;
}
BOOL AddSourceFormat(CLIPFORMAT cfFormat)
{
if (m_pDataObject == nullptr)
return FALSE;
FORMATETC FormatEtc;
ZeroMemory(&FormatEtc, sizeof(FORMATETC));
FormatEtc.cfFormat = cfFormat;
FormatEtc.dwAspect = DVASPECT_CONTENT;
FormatEtc.lindex = -1;
FormatEtc.tymed = TYMED_HGLOBAL;
STGMEDIUM StgMedium;
ZeroMemory(&StgMedium, sizeof(STGMEDIUM));
return SUCCEEDED(m_pDataObject->SetData(&FormatEtc, &StgMedium, TRUE));
}
BOOL SetClipboard(FORMATETC & FormatEtc, STGMEDIUM & StgMedium)
{
if (m_pDataObject == nullptr)
return DROPEFFECT_NONE;
if (FAILED(m_pDataObject->SetData(&FormatEtc, &StgMedium, TRUE)))
return DROPEFFECT_NONE;
return (OleSetClipboard(m_pDataObject) == S_OK);
}
BOOL FlushClipboard()
{
return (OleFlushClipboard() == S_OK);
}
DWORD DoDragDrop(SHDRAGIMAGE * pDragImage = nullptr, DWORD dwValidEffects = DROPEFFECT_COPY | DROPEFFECT_MOVE | DROPEFFECT_LINK)
{
if (m_pDataObject == nullptr)
return DROPEFFECT_NONE;
IDragSourceHelper * pDragSourceHelper = nullptr;
// Instantiate drag source helper object
if (pDragImage != nullptr)
{
if (FAILED(CoCreateInstance(CLSID_DragDropHelper, nullptr, CLSCTX_INPROC_SERVER, IID_IDragSourceHelper, (LPVOID *)&pDragSourceHelper)))
pDragSourceHelper = nullptr;
if (pDragSourceHelper != nullptr)
pDragSourceHelper->InitializeFromBitmap(pDragImage, m_pDataObject);
}
DWORD dwEffects = DROPEFFECT_NONE;
dwEffects = ::DoDragDrop(m_pDataObject, m_pDropSource, dwValidEffects, &dwEffects) == DRAGDROP_S_DROP ? DROPEFFECT_NONE : dwEffects;
// Destroy drag source helper object
if (pDragSourceHelper != nullptr)
pDragSourceHelper->Release();
return dwEffects;
}
};