--- /dev/null
+///////////////////////////////////////////////////////////////////////////////
+// Name: msw/ole/dataobj.cpp
+// Purpose: implementation of wx[I]DataObject class
+// Author: Vadim Zeitlin
+// Modified by:
+// Created: 10.05.98
+// RCS-ID: $Id$
+// Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
+// Licence: wxWindows license
+///////////////////////////////////////////////////////////////////////////////
+
+// ============================================================================
+// declarations
+// ============================================================================
+
+// ----------------------------------------------------------------------------
+// headers
+// ----------------------------------------------------------------------------
+
+#ifdef __GNUG__
+ #pragma implementation "dataobj.h"
+#endif
+
+// For compilers that support precompilation, includes "wx.h".
+#include "wx/wxprec.h"
+
+#if defined(__BORLANDC__)
+ #pragma hdrstop
+#endif
+
+#include <wx/log.h>
+#include <wx/msw/ole/oleutils.h>
+#include <wx/msw/ole/dataobj.h>
+
+#ifndef __WIN32__
+ #include <ole2.h>
+ #include <olestd.h>
+#endif
+
+// ----------------------------------------------------------------------------
+// functions
+// ----------------------------------------------------------------------------
+
+#ifdef __DEBUG__
+ static const char *GetTymedName(DWORD tymed);
+#else
+ #define GetTymedName(tymed) ""
+#endif
+
+// ----------------------------------------------------------------------------
+// wxIEnumFORMATETC interface implementation
+// ----------------------------------------------------------------------------
+class wxIEnumFORMATETC : public IEnumFORMATETC
+{
+public:
+ wxIEnumFORMATETC(CLIPFORMAT cf);
+
+ DECLARE_IUNKNOWN_METHODS;
+
+ // IEnumFORMATETC
+ STDMETHODIMP Next(ULONG celt, FORMATETC *rgelt, ULONG *pceltFetched);
+ STDMETHODIMP Skip(ULONG celt);
+ STDMETHODIMP Reset();
+ STDMETHODIMP Clone(IEnumFORMATETC **ppenum);
+
+private:
+ FORMATETC m_format; // (unique @@@) format we can provide data in
+ ULONG m_nCurrent; // current enum position (currently either 0 or 1)
+};
+
+// ----------------------------------------------------------------------------
+// wxIDataObject implementation of IDataObject interface
+// ----------------------------------------------------------------------------
+class wxIDataObject : public IDataObject
+{
+public:
+ wxIDataObject(wxDataObject *pDataObject);
+
+ DECLARE_IUNKNOWN_METHODS;
+
+ // IDataObject
+ STDMETHODIMP GetData(FORMATETC *pformatetcIn, STGMEDIUM *pmedium);
+ STDMETHODIMP GetDataHere(FORMATETC *pformatetc, STGMEDIUM *pmedium);
+ STDMETHODIMP QueryGetData(FORMATETC *pformatetc);
+ STDMETHODIMP GetCanonicalFormatEtc(FORMATETC *In, FORMATETC *pOut);
+ STDMETHODIMP SetData(FORMATETC *pfetc, STGMEDIUM *pmedium, BOOL fRelease);
+ STDMETHODIMP EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC **ppenumFEtc);
+ STDMETHODIMP DAdvise(FORMATETC *pfetc, DWORD ad, IAdviseSink *p, DWORD *pdw);
+ STDMETHODIMP DUnadvise(DWORD dwConnection);
+ STDMETHODIMP EnumDAdvise(IEnumSTATDATA **ppenumAdvise);
+
+private:
+ wxDataObject *m_pDataObject; // pointer to C++ class we belong to
+};
+
+// ============================================================================
+// implementation
+// ============================================================================
+
+// ----------------------------------------------------------------------------
+// wxIEnumFORMATETC
+// ----------------------------------------------------------------------------
+
+BEGIN_IID_TABLE(wxIEnumFORMATETC)
+ ADD_IID(Unknown)
+ ADD_IID(EnumFORMATETC)
+END_IID_TABLE;
+
+IMPLEMENT_IUNKNOWN_METHODS(wxIEnumFORMATETC)
+
+wxIEnumFORMATETC::wxIEnumFORMATETC(CLIPFORMAT cf)
+{
+ m_format.cfFormat = cf;
+ m_format.ptd = NULL;
+ m_format.dwAspect = DVASPECT_CONTENT;
+ m_format.lindex = -1;
+ m_format.tymed = TYMED_HGLOBAL;
+ m_cRef = 0;
+ m_nCurrent = 0;
+}
+
+STDMETHODIMP wxIEnumFORMATETC::Next(ULONG celt,
+ FORMATETC *rgelt,
+ ULONG *pceltFetched)
+{
+ wxLogTrace("wxIEnumFORMATETC::Next");
+
+ if ( celt > 1 )
+ return S_FALSE;
+
+ if ( m_nCurrent == 0 ) {
+ *rgelt = m_format;
+ m_nCurrent++;
+
+ return S_OK;
+ }
+ else
+ return S_FALSE;
+}
+
+STDMETHODIMP wxIEnumFORMATETC::Skip(ULONG celt)
+{
+ wxLogTrace("wxIEnumFORMATETC::Skip");
+
+ if ( m_nCurrent == 0 )
+ m_nCurrent++;
+
+ return S_FALSE;
+}
+
+STDMETHODIMP wxIEnumFORMATETC::Reset()
+{
+ wxLogTrace("wxIEnumFORMATETC::Reset");
+
+ m_nCurrent = 0;
+
+ return S_OK;
+}
+
+STDMETHODIMP wxIEnumFORMATETC::Clone(IEnumFORMATETC **ppenum)
+{
+ wxLogTrace("wxIEnumFORMATETC::Clone");
+
+ wxIEnumFORMATETC *pNew = new wxIEnumFORMATETC(m_format.cfFormat);
+ pNew->AddRef();
+ *ppenum = pNew;
+
+ return S_OK;
+}
+
+// ----------------------------------------------------------------------------
+// wxIDataObject
+// ----------------------------------------------------------------------------
+
+BEGIN_IID_TABLE(wxIDataObject)
+ ADD_IID(Unknown)
+ ADD_IID(DataObject)
+END_IID_TABLE;
+
+IMPLEMENT_IUNKNOWN_METHODS(wxIDataObject)
+
+wxIDataObject::wxIDataObject(wxDataObject *pDataObject)
+{
+ m_cRef = 0;
+ m_pDataObject = pDataObject;
+}
+
+// get data functions
+STDMETHODIMP wxIDataObject::GetData(FORMATETC *pformatetcIn, STGMEDIUM *pmedium)
+{
+ wxLogTrace("wxIDataObject::GetData");
+
+ // is data is in our format?
+ HRESULT hr = QueryGetData(pformatetcIn);
+ if ( FAILED(hr) )
+ return hr;
+
+ // alloc memory
+ HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE,
+ m_pDataObject->GetDataSize());
+ if ( hGlobal == NULL ) {
+ wxLogLastError("GlobalAlloc");
+ return E_OUTOFMEMORY;
+ }
+
+ // copy data
+ pmedium->tymed = TYMED_HGLOBAL;
+ pmedium->hGlobal = hGlobal;
+ pmedium->pUnkForRelease = NULL;
+
+ hr = GetDataHere(pformatetcIn, pmedium);
+ if ( FAILED(hr) ) {
+ GlobalFree(hGlobal);
+ return hr;
+ }
+
+ return S_OK;
+}
+
+STDMETHODIMP wxIDataObject::GetDataHere(FORMATETC *pformatetc,
+ STGMEDIUM *pmedium)
+{
+ wxLogTrace("wxIDataObject::GetDataHere");
+
+ // put data in caller provided medium
+ if ( pmedium->tymed != TYMED_HGLOBAL )
+ return DV_E_TYMED;
+
+ // copy data
+ void *pBuf = GlobalLock(pmedium->hGlobal);
+ if ( pBuf == NULL ) {
+ wxLogLastError("GlobalLock");
+ return E_OUTOFMEMORY;
+ }
+
+ m_pDataObject->GetDataHere(pBuf);
+
+ GlobalUnlock(pmedium->hGlobal);
+
+ return S_OK;
+}
+
+// set data functions (not implemented)
+STDMETHODIMP wxIDataObject::SetData(FORMATETC *pformatetc,
+ STGMEDIUM *pmedium,
+ BOOL fRelease)
+{
+ wxLogTrace("wxIDataObject::SetData");
+ return E_NOTIMPL;
+}
+
+// information functions
+STDMETHODIMP wxIDataObject::QueryGetData(FORMATETC *pformatetc)
+{
+ // do we accept data in this format?
+ if ( pformatetc == NULL ) {
+ wxLogTrace("wxIDataObject::QueryGetData: invalid ptr.");
+ return E_INVALIDARG;
+ }
+
+ // the only one allowed by current COM implementation
+ if ( pformatetc->lindex != -1 ) {
+ wxLogTrace("wxIDataObject::QueryGetData: bad lindex %d",
+ pformatetc->lindex);
+ return DV_E_LINDEX;
+ }
+
+ // we don't support anything other (THUMBNAIL, ICON, DOCPRINT...)
+ if ( pformatetc->dwAspect != DVASPECT_CONTENT ) {
+ wxLogTrace("wxIDataObject::QueryGetData: bad dwAspect %d",
+ pformatetc->dwAspect);
+ return DV_E_DVASPECT;
+ }
+
+ // @@ we only transfer data by global memory (bad for large amounts of it!)
+ if ( !(pformatetc->tymed & TYMED_HGLOBAL) ) {
+ wxLogTrace("wxIDataObject::QueryGetData: %s != TYMED_HGLOBAL.",
+ GetTymedName(pformatetc->tymed));
+ return DV_E_TYMED;
+ }
+
+ // and now check the type of data requested
+ if ( m_pDataObject->IsSupportedFormat(pformatetc->cfFormat) ) {
+ wxLogTrace("wxIDataObject::QueryGetData: %s ok",
+ wxDataObject::GetFormatName(pformatetc->cfFormat));
+ return S_OK;
+ }
+ else {
+ wxLogTrace("wxIDataObject::QueryGetData: %s unsupported",
+ wxDataObject::GetFormatName(pformatetc->cfFormat));
+ return DV_E_FORMATETC;
+ }
+}
+
+STDMETHODIMP wxIDataObject::GetCanonicalFormatEtc(FORMATETC *pFormatetcIn,
+ FORMATETC *pFormatetcOut)
+{
+ wxLogTrace("wxIDataObject::GetCanonicalFormatEtc");
+
+ // @@ implementation is trivial, we might want something better here
+ if ( pFormatetcOut != NULL )
+ pFormatetcOut->ptd = NULL;
+ return DATA_S_SAMEFORMATETC;
+}
+
+STDMETHODIMP wxIDataObject::EnumFormatEtc(DWORD dwDirection,
+ IEnumFORMATETC **ppenumFormatEtc)
+{
+ wxLogTrace("wxIDataObject::EnumFormatEtc");
+
+ if ( dwDirection == DATADIR_SET ) {
+ // we don't allow setting of data anyhow
+ return E_NOTIMPL;
+ }
+
+ wxIEnumFORMATETC *pEnum =
+ new wxIEnumFORMATETC(m_pDataObject->GetPreferredFormat());
+ pEnum->AddRef();
+ *ppenumFormatEtc = pEnum;
+
+ return S_OK;
+}
+
+// advise sink functions (not implemented)
+STDMETHODIMP wxIDataObject::DAdvise(FORMATETC *pformatetc,
+ DWORD advf,
+ IAdviseSink *pAdvSink,
+ DWORD *pdwConnection)
+{
+ return OLE_E_ADVISENOTSUPPORTED;
+}
+
+STDMETHODIMP wxIDataObject::DUnadvise(DWORD dwConnection)
+{
+ return OLE_E_ADVISENOTSUPPORTED;
+}
+
+STDMETHODIMP wxIDataObject::EnumDAdvise(IEnumSTATDATA **ppenumAdvise)
+{
+ return OLE_E_ADVISENOTSUPPORTED;
+}
+
+// ----------------------------------------------------------------------------
+// wxDataObject
+// ----------------------------------------------------------------------------
+
+wxDataObject::wxDataObject()
+{
+ m_pIDataObject = new wxIDataObject(this);
+ m_pIDataObject->AddRef();
+}
+
+wxDataObject::~wxDataObject()
+{
+ m_pIDataObject->Release();
+}
+
+#ifdef __DEBUG__
+
+const char *wxDataObject::GetFormatName(wxDataFormat format)
+{
+ static char s_szBuf[128];
+ switch ( format ) {
+ case CF_TEXT: return "CF_TEXT";
+ case CF_BITMAP: return "CF_BITMAP";
+ case CF_METAFILEPICT: return "CF_METAFILEPICT";
+ case CF_SYLK: return "CF_SYLK";
+ case CF_DIF: return "CF_DIF";
+ case CF_TIFF: return "CF_TIFF";
+ case CF_OEMTEXT: return "CF_OEMTEXT";
+ case CF_DIB: return "CF_DIB";
+ case CF_PALETTE: return "CF_PALETTE";
+ case CF_PENDATA: return "CF_PENDATA";
+ case CF_RIFF: return "CF_RIFF";
+ case CF_WAVE: return "CF_WAVE";
+ case CF_UNICODETEXT: return "CF_UNICODETEXT";
+ case CF_ENHMETAFILE: return "CF_ENHMETAFILE";
+ case CF_HDROP: return "CF_HDROP";
+ case CF_LOCALE: return "CF_LOCALE";
+ default:
+ sprintf(s_szBuf, "clipboard format %d (unknown)", format);
+ return s_szBuf;
+ }
+}
+
+// ----------------------------------------------------------------------------
+// private functions
+// ----------------------------------------------------------------------------
+static const char *GetTymedName(DWORD tymed)
+{
+ static char s_szBuf[128];
+ switch ( tymed ) {
+ case TYMED_HGLOBAL: return "TYMED_HGLOBAL";
+ case TYMED_FILE: return "TYMED_FILE";
+ case TYMED_ISTREAM: return "TYMED_ISTREAM";
+ case TYMED_ISTORAGE: return "TYMED_ISTORAGE";
+ case TYMED_GDI: return "TYMED_GDI";
+ case TYMED_MFPICT: return "TYMED_MFPICT";
+ case TYMED_ENHMF: return "TYMED_ENHMF";
+ default:
+ sprintf(s_szBuf, "type of media format %d (unknown)", tymed);
+ return s_szBuf;
+ }
+}
+
+#endif //DEBUG
\ No newline at end of file
--- /dev/null
+///////////////////////////////////////////////////////////////////////////////
+// Name: msw/ole/dropsrc.cpp
+// Purpose: implementation of wxIDropSource and wxDropSource
+// Author: Vadim Zeitlin
+// Modified by:
+// Created: 10.05.98
+// RCS-ID: $Id$
+// Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
+// Licence: wxWindows license
+///////////////////////////////////////////////////////////////////////////////
+
+// ============================================================================
+// declarations
+// ============================================================================
+
+// ----------------------------------------------------------------------------
+// headers
+// ----------------------------------------------------------------------------
+
+#ifdef __GNUG__
+ #pragma implementation "dropsrc.h"
+#endif
+
+// For compilers that support precompilation, includes "wx.h".
+#include "wx/wxprec.h"
+
+#if defined(__BORLANDC__)
+ #pragma hdrstop
+#endif
+
+#include <wx/setup.h>
+
+#if USE_DRAG_AND_DROP
+
+#include <wx/log.h>
+#include <wx/msw/ole/oleutils.h>
+#include <wx/msw/ole/dataobj.h>
+#include <wx/msw/ole/dropsrc.h>
+
+#ifndef __WIN32__
+ #include <ole2.h>
+ #include <olestd.h>
+#endif
+
+// ----------------------------------------------------------------------------
+// wxIDropSource implementation of IDropSource interface
+// ----------------------------------------------------------------------------
+
+class wxIDropSource : public IDropSource
+{
+public:
+ wxIDropSource(wxDropSource *pDropSource);
+
+ DECLARE_IUNKNOWN_METHODS;
+
+ // IDropSource
+ STDMETHODIMP QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState);
+ STDMETHODIMP GiveFeedback(DWORD dwEffect);
+
+private:
+ DWORD m_grfInitKeyState; // button which started the d&d operation
+ wxDropSource *m_pDropSource; // pointer to C++ class we belong to
+};
+
+// ============================================================================
+// Implementation
+// ============================================================================
+
+// ----------------------------------------------------------------------------
+// wxIDropSource implementation
+// ----------------------------------------------------------------------------
+BEGIN_IID_TABLE(wxIDropSource)
+ ADD_IID(Unknown)
+ ADD_IID(DropSource)
+END_IID_TABLE;
+
+IMPLEMENT_IUNKNOWN_METHODS(wxIDropSource)
+
+wxIDropSource::wxIDropSource(wxDropSource *pDropSource)
+{
+ wxASSERT( pDropSource != NULL );
+
+ m_pDropSource = pDropSource;
+ m_grfInitKeyState = 0;
+ m_cRef = 0;
+}
+
+// Name : wxIDropSource::QueryContinueDrag
+// Purpose : decide if drag operation must be continued or not
+// Returns : HRESULT: S_OK if we should continue
+// DRAGDROP_S_DROP to drop right now
+// DRAGDROP_S_CANCEL to cancel everything
+// Params : [in] BOOL fEscapePressed <Esc> pressed since last call?
+// [in] DWORD grfKeyState mask containing state of kbd keys
+// Notes : as there is no reasonably simple portable way to implement this
+// function, we currently don't give the possibility to override the
+// default behaviour implemented here
+STDMETHODIMP wxIDropSource::QueryContinueDrag(BOOL fEscapePressed,
+ DWORD grfKeyState)
+{
+ if ( fEscapePressed )
+ return DRAGDROP_S_CANCEL;
+
+ // initialize ourself with the drag begin button
+ if ( m_grfInitKeyState == 0 ) {
+ m_grfInitKeyState = grfKeyState & (MK_LBUTTON | MK_RBUTTON | MK_MBUTTON);
+ }
+
+ if ( !(grfKeyState & m_grfInitKeyState) ) {
+ // button which started d&d released, go!
+ return DRAGDROP_S_DROP;
+ }
+
+ return S_OK;
+}
+
+// Name : wxIDropSource::GiveFeedback
+// Purpose : give UI feedback according to current state of operation
+// Returns : STDMETHODIMP
+// Params : [in] DWORD dwEffect - what would happen if we dropped now
+// Notes : default implementation is ok in more than 99% of cases
+STDMETHODIMP wxIDropSource::GiveFeedback(DWORD dwEffect)
+{
+ wxDropSource::DragResult effect;
+ if ( dwEffect & DROPEFFECT_COPY )
+ effect = wxDropSource::Copy;
+ else if ( dwEffect & DROPEFFECT_MOVE )
+ effect = wxDropSource::Move;
+ else
+ effect = wxDropSource::None;
+
+ if ( m_pDropSource->GiveFeedback(effect,
+ (dwEffect & DROPEFFECT_SCROLL) != 0 ) )
+ return S_OK;
+
+ return DRAGDROP_S_USEDEFAULTCURSORS;
+}
+
+// ----------------------------------------------------------------------------
+// wxDropSource implementation
+// ----------------------------------------------------------------------------
+
+// ctors
+
+// common part of all ctors
+void wxDropSource::Init()
+{
+ m_pIDropSource = new wxIDropSource(this);
+ m_pIDropSource->AddRef();
+}
+
+wxDropSource::wxDropSource()
+{
+ Init();
+ m_pData = NULL;
+}
+
+wxDropSource::wxDropSource(wxDataObject& data)
+{
+ Init();
+ SetData(data);
+}
+
+void wxDropSource::SetData(wxDataObject& data)
+{
+ m_pData = &data;
+}
+
+wxDropSource::~wxDropSource()
+{
+ m_pIDropSource->Release();
+}
+
+// Name : DoDragDrop
+// Purpose : start drag and drop operation
+// Returns : DragResult - the code of performed operation
+// Params : [in] bool bAllowMove: if false, only copy is allowed
+// Notes : you must call SetData() before if you had used def ctor
+wxDropSource::DragResult wxDropSource::DoDragDrop(bool bAllowMove)
+{
+ wxCHECK_RET( m_pData != NULL, None );
+
+ DWORD dwEffect;
+ HRESULT hr = ::DoDragDrop(m_pData->GetInterface(),
+ m_pIDropSource,
+ bAllowMove ? DROPEFFECT_COPY | DROPEFFECT_MOVE
+ : DROPEFFECT_COPY,
+ &dwEffect);
+
+ if ( hr == DRAGDROP_S_CANCEL ) {
+ return Cancel;
+ }
+ else if ( hr == DRAGDROP_S_DROP ) {
+ if ( dwEffect & DROPEFFECT_COPY ) {
+ return Copy;
+ }
+ else if ( dwEffect & DROPEFFECT_MOVE ) {
+ // consistency check: normally, we shouldn't get "move" at all
+ // here if !bAllowMove, but in practice it does happen quite often
+ if ( bAllowMove )
+ return Move;
+ else
+ return Copy;
+ }
+ else {
+ // not copy or move
+ return None;
+ }
+ }
+ else {
+ if ( FAILED(hr) ) {
+ wxLogApiError("DoDragDrop", hr);
+ wxLogError("Drag & drop operation failed.");
+ }
+ else {
+ wxLogDebug("Unexpected success return code %08lx from DoDragDrop.", hr);
+ }
+
+ return Error;
+ }
+}
+
+// Name : wxDropSource::GiveFeedback
+// Purpose : visually inform the user about d&d operation state
+// Returns : bool: true if we do all ourselves or false for default feedback
+// Params : [in] DragResult effect - what would happen if we dropped now
+// [in] bool bScrolling - true if target is scrolling
+// Notes : here we just leave this stuff for default implementation
+bool wxDropSource::GiveFeedback(DragResult effect, bool bScrolling)
+{
+ return false;
+}
+
+#endif //USE_DRAG_AND_DROP
\ No newline at end of file