#define _WIN32_IE 0x0500 #define _WIN32_WINNT 0x0500 #include "resource.h" #include #include #include "Scene.h" #define _WIN32_IE 0x0500 #define _WIN32_WINNT 0x0500 #include "resource.h" #include #include #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 key has been pressed since the last call, cancel the drop if(fEscapePressed == TRUE) return DRAGDROP_S_CANCEL; // if the 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; }