501 lines
10 KiB
C++
501 lines
10 KiB
C++
#define _WIN32_IE 0x0500
|
|
#define _WIN32_WINNT 0x0500
|
|
|
|
#include "resource.h"
|
|
#include <stdio.h>
|
|
#include <windows.h>
|
|
#include "Scene.h"
|
|
|
|
#define _WIN32_IE 0x0500
|
|
#define _WIN32_WINNT 0x0500
|
|
|
|
#include "resource.h"
|
|
#include <stdio.h>
|
|
#include <windows.h>
|
|
#include "Scene.h"
|
|
|
|
const ULONG MAX_FORMATS = 100;
|
|
|
|
class DragDataObject : public IDataObject
|
|
{
|
|
public:
|
|
//
|
|
// IUnknown members
|
|
//
|
|
HRESULT __stdcall QueryInterface (REFIID iid, void ** ppvObject);
|
|
ULONG __stdcall AddRef (void);
|
|
ULONG __stdcall Release (void);
|
|
|
|
//
|
|
// IDataObject members
|
|
//
|
|
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 *pAdvSink, DWORD *pdwConnection);
|
|
HRESULT __stdcall DUnadvise (DWORD dwConnection);
|
|
HRESULT __stdcall EnumDAdvise (IEnumSTATDATA **ppEnumAdvise);
|
|
|
|
//
|
|
// Constructor / Destructor
|
|
//
|
|
DragDataObject(FORMATETC *fmt, STGMEDIUM *stgmed, int count);
|
|
~DragDataObject();
|
|
|
|
private:
|
|
|
|
int LookupFormatEtc(FORMATETC *pFormatEtc);
|
|
|
|
//
|
|
// any private members and functions
|
|
//
|
|
LONG m_lRefCount;
|
|
|
|
FORMATETC *m_pFormatEtc;
|
|
STGMEDIUM *m_pStgMedium;
|
|
LONG m_nNumFormats;
|
|
|
|
};
|
|
|
|
//
|
|
// Constructor
|
|
//
|
|
DragDataObject::DragDataObject(FORMATETC *fmtetc, STGMEDIUM *stgmed, int count)
|
|
{
|
|
m_lRefCount = 1;
|
|
m_nNumFormats = count;
|
|
|
|
m_pFormatEtc = new FORMATETC[count];
|
|
m_pStgMedium = new STGMEDIUM[count];
|
|
|
|
for(int i = 0; i < count; i++)
|
|
{
|
|
m_pFormatEtc[i] = fmtetc[i];
|
|
m_pStgMedium[i] = stgmed[i];
|
|
}
|
|
}
|
|
|
|
//
|
|
// Destructor
|
|
//
|
|
DragDataObject::~DragDataObject()
|
|
{
|
|
// cleanup
|
|
if(m_pFormatEtc) delete[] m_pFormatEtc;
|
|
if(m_pStgMedium) delete[] m_pStgMedium;
|
|
}
|
|
|
|
//
|
|
// IUnknown::AddRef
|
|
//
|
|
ULONG __stdcall DragDataObject::AddRef(void)
|
|
{
|
|
// increment object reference count
|
|
return InterlockedIncrement(&m_lRefCount);
|
|
}
|
|
|
|
//
|
|
// IUnknown::Release
|
|
//
|
|
ULONG __stdcall DragDataObject::Release(void)
|
|
{
|
|
// decrement object reference count
|
|
LONG count = InterlockedDecrement(&m_lRefCount);
|
|
|
|
if(count == 0)
|
|
{
|
|
delete this;
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
return count;
|
|
}
|
|
}
|
|
|
|
//
|
|
// IUnknown::QueryInterface
|
|
//
|
|
HRESULT __stdcall DragDataObject::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;
|
|
}
|
|
else
|
|
{
|
|
*ppvObject = 0;
|
|
return E_NOINTERFACE;
|
|
}
|
|
}
|
|
|
|
HGLOBAL DupMem(HGLOBAL hMem)
|
|
{
|
|
// lock the source memory object
|
|
DWORD len = GlobalSize(hMem);
|
|
PVOID source = GlobalLock(hMem);
|
|
|
|
// create a fixed "global" block - i.e. just
|
|
// a regular lump of our process heap
|
|
PVOID dest = GlobalAlloc(GMEM_FIXED, len);
|
|
|
|
memcpy(dest, source, len);
|
|
|
|
GlobalUnlock(hMem);
|
|
|
|
return dest;
|
|
}
|
|
|
|
int DragDataObject::LookupFormatEtc(FORMATETC *pFormatEtc)
|
|
{
|
|
for(int i = 0; i < m_nNumFormats; i++)
|
|
{
|
|
if((pFormatEtc->tymed & m_pFormatEtc[i].tymed) &&
|
|
pFormatEtc->cfFormat == m_pFormatEtc[i].cfFormat &&
|
|
pFormatEtc->dwAspect == m_pFormatEtc[i].dwAspect)
|
|
{
|
|
return i;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
//
|
|
// IDataObject::GetData
|
|
//
|
|
HRESULT __stdcall DragDataObject::GetData (FORMATETC *pFormatEtc, STGMEDIUM *pMedium)
|
|
{
|
|
int idx;
|
|
|
|
//
|
|
// try to match the requested FORMATETC with one of our supported formats
|
|
//
|
|
if((idx = LookupFormatEtc(pFormatEtc)) == -1)
|
|
{
|
|
return DV_E_FORMATETC;
|
|
}
|
|
|
|
//
|
|
// found a match! transfer the data into the supplied storage-medium
|
|
//
|
|
pMedium->tymed = m_pFormatEtc[idx].tymed;
|
|
pMedium->pUnkForRelease = 0;
|
|
|
|
switch(m_pFormatEtc[idx].tymed)
|
|
{
|
|
case TYMED_HGLOBAL:
|
|
|
|
pMedium->hGlobal = DupMem(m_pStgMedium[idx].hGlobal);
|
|
//return S_OK;
|
|
break;
|
|
|
|
default:
|
|
return DV_E_FORMATETC;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//
|
|
// IDataObject::GetDataHere
|
|
//
|
|
HRESULT __stdcall DragDataObject::GetDataHere (FORMATETC *pFormatEtc, STGMEDIUM *pMedium)
|
|
{
|
|
// GetDataHere is only required for IStream and IStorage mediums
|
|
// It is an error to call GetDataHere for things like HGLOBAL and other clipboard formats
|
|
//
|
|
// OleFlushClipboard
|
|
//
|
|
return DATA_E_FORMATETC;
|
|
}
|
|
|
|
//
|
|
// IDataObject::QueryGetData
|
|
//
|
|
// Called to see if the IDataObject supports the specified format of data
|
|
//
|
|
HRESULT __stdcall DragDataObject::QueryGetData (FORMATETC *pFormatEtc)
|
|
{
|
|
return (LookupFormatEtc(pFormatEtc) == -1) ? DV_E_FORMATETC : S_OK;
|
|
}
|
|
|
|
//
|
|
// IDataObject::GetCanonicalFormatEtc
|
|
//
|
|
HRESULT __stdcall DragDataObject::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;
|
|
}
|
|
|
|
//
|
|
// IDataObject::SetData
|
|
//
|
|
HRESULT __stdcall DragDataObject::SetData (FORMATETC *pFormatEtc, STGMEDIUM *pMedium, BOOL fRelease)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
//
|
|
// IDataObject::EnumFormatEtc
|
|
//
|
|
HRESULT __stdcall DragDataObject::EnumFormatEtc (DWORD dwDirection, IEnumFORMATETC **ppEnumFormatEtc)
|
|
{
|
|
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 SHCreateStdEnumFmtEtc(m_nNumFormats, m_pFormatEtc, ppEnumFormatEtc);
|
|
//return CreateEnumFormatEtc(m_nNumFormats, m_pFormatEtc, ppEnumFormatEtc);
|
|
}
|
|
else
|
|
{
|
|
// the direction specified is not support for drag+drop
|
|
return E_NOTIMPL;
|
|
}
|
|
}
|
|
|
|
//
|
|
// IDataObject::DAdvise
|
|
//
|
|
HRESULT __stdcall DragDataObject::DAdvise (FORMATETC *pFormatEtc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection)
|
|
{
|
|
return OLE_E_ADVISENOTSUPPORTED;
|
|
}
|
|
|
|
//
|
|
// IDataObject::DUnadvise
|
|
//
|
|
HRESULT __stdcall DragDataObject::DUnadvise (DWORD dwConnection)
|
|
{
|
|
return OLE_E_ADVISENOTSUPPORTED;
|
|
}
|
|
|
|
//
|
|
// IDataObject::EnumDAdvise
|
|
//
|
|
HRESULT __stdcall DragDataObject::EnumDAdvise (IEnumSTATDATA **ppEnumAdvise)
|
|
{
|
|
return OLE_E_ADVISENOTSUPPORTED;
|
|
}
|
|
|
|
HRESULT CreateDataObject(FORMATETC *fmtetc, STGMEDIUM *stgmeds, UINT count, IDataObject **ppDataObject)
|
|
{
|
|
if(ppDataObject == 0)
|
|
return E_INVALIDARG;
|
|
|
|
*ppDataObject = new DragDataObject(fmtetc, stgmeds, count);
|
|
return (*ppDataObject) ? S_OK : E_OUTOFMEMORY;
|
|
}
|
|
|
|
|
|
class DragDropSource : public IDropSource
|
|
{
|
|
public:
|
|
//
|
|
// IUnknown members
|
|
//
|
|
HRESULT __stdcall QueryInterface (REFIID iid, void ** ppvObject);
|
|
ULONG __stdcall AddRef (void);
|
|
ULONG __stdcall Release (void);
|
|
|
|
//
|
|
// IDropSource members
|
|
//
|
|
HRESULT __stdcall QueryContinueDrag (BOOL fEscapePressed, DWORD grfKeyState);
|
|
HRESULT __stdcall GiveFeedback (DWORD dwEffect);
|
|
|
|
//
|
|
// Constructor / Destructor
|
|
//
|
|
DragDropSource();
|
|
~DragDropSource();
|
|
|
|
private:
|
|
|
|
//
|
|
// private members and functions
|
|
//
|
|
LONG m_lRefCount;
|
|
};
|
|
|
|
//
|
|
// Constructor
|
|
//
|
|
DragDropSource::DragDropSource()
|
|
{
|
|
m_lRefCount = 1;
|
|
}
|
|
|
|
//
|
|
// Destructor
|
|
//
|
|
DragDropSource::~DragDropSource()
|
|
{
|
|
}
|
|
|
|
//
|
|
// IUnknown::AddRef
|
|
//
|
|
ULONG __stdcall DragDropSource::AddRef(void)
|
|
{
|
|
// increment object reference count
|
|
return InterlockedIncrement(&m_lRefCount);
|
|
}
|
|
|
|
//
|
|
// IUnknown::Release
|
|
//
|
|
ULONG __stdcall DragDropSource::Release(void)
|
|
{
|
|
// decrement object reference count
|
|
LONG count = InterlockedDecrement(&m_lRefCount);
|
|
|
|
if(count == 0)
|
|
{
|
|
delete this;
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
return count;
|
|
}
|
|
}
|
|
|
|
//
|
|
// IUnknown::QueryInterface
|
|
//
|
|
HRESULT __stdcall DragDropSource::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;
|
|
}
|
|
else
|
|
{
|
|
*ppvObject = 0;
|
|
return E_NOINTERFACE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// DragDropSource::QueryContinueDrag
|
|
//
|
|
// Called by OLE whenever Escape/Control/Shift/Mouse buttons have changed
|
|
//
|
|
HRESULT __stdcall DragDropSource::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;
|
|
}
|
|
|
|
//
|
|
// DragDropSource::GiveFeedback
|
|
//
|
|
// Return either S_OK, or DRAGDROP_S_USEDEFAULTCURSORS to instruct OLE to use the
|
|
// default mouse cursor images
|
|
//
|
|
HRESULT __stdcall DragDropSource::GiveFeedback(DWORD dwEffect)
|
|
{
|
|
return DRAGDROP_S_USEDEFAULTCURSORS;
|
|
}
|
|
|
|
//
|
|
// Helper routine to create an IDropSource object
|
|
//
|
|
HRESULT CreateDropSource(IDropSource **ppDropSource)
|
|
{
|
|
if(ppDropSource == 0)
|
|
return E_INVALIDARG;
|
|
|
|
*ppDropSource = new DragDropSource();
|
|
|
|
return (*ppDropSource) ? S_OK : E_OUTOFMEMORY;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int DragAndDrop(char *path, bool moveFiles)
|
|
{
|
|
DWORD dwEffect;
|
|
DWORD dwResult;
|
|
IDataObject *pDataObject;
|
|
IDropSource *pDropSource;
|
|
|
|
|
|
if (!OleInitialize(0) != S_OK)
|
|
return 0;
|
|
|
|
int so_hdrop = sizeof (DROPFILES);
|
|
int so_buff = so_hdrop + strlen (path) + 2; // 2 NULLS at end
|
|
HGLOBAL hglobal = GlobalAlloc (GMEM_SHARE | GHND | GMEM_ZEROINIT, so_buff);
|
|
DROPFILES *dropdat = (DROPFILES *) GlobalLock (hglobal);
|
|
dropdat->pFiles = sizeof(DROPFILES);
|
|
dropdat->fWide = 0;
|
|
|
|
char *cp = ((char *)dropdat) + so_hdrop;
|
|
strcpy (cp, path);
|
|
GlobalUnlock (hglobal);
|
|
|
|
FORMATETC format;
|
|
STGMEDIUM store;
|
|
|
|
memset(&format, 0, sizeof(format));
|
|
format.cfFormat = CF_HDROP;
|
|
format.dwAspect = DVASPECT_CONTENT;
|
|
format.lindex = -1;
|
|
format.tymed = TYMED_HGLOBAL;
|
|
|
|
memset(&store, 0, sizeof(store));
|
|
store.tymed = TYMED_HGLOBAL;
|
|
store.hGlobal = hglobal;
|
|
|
|
CreateDataObject(&format, &store, 1, &pDataObject);
|
|
CreateDropSource(&pDropSource);
|
|
|
|
int dragArgs = DROPEFFECT_COPY;
|
|
if (moveFiles) dragArgs |= DROPEFFECT_MOVE;
|
|
|
|
dwResult = DoDragDrop(pDataObject, pDropSource, dragArgs, &dwEffect);
|
|
|
|
GlobalFree ( hglobal );
|
|
|
|
OleUninitialize();
|
|
return 1;
|
|
}
|