1 ///////////////////////////////////////////////////////////////////////////////
2 // Name:        src/msw/ole/dataobj.cpp
3 // Purpose:     implementation of wx[I]DataObject class
4 // Author:      Vadim Zeitlin
5 // Modified by:
6 // Created:     10.05.98
7 // Copyright:   (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
8 // Licence:     wxWindows licence
9 ///////////////////////////////////////////////////////////////////////////////
10 
11 // ============================================================================
12 // declarations
13 // ============================================================================
14 
15 // ----------------------------------------------------------------------------
16 // headers
17 // ----------------------------------------------------------------------------
18 
19 // For compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
21 
22 #if defined(__BORLANDC__)
23     #pragma hdrstop
24 #endif
25 
26 #ifndef WX_PRECOMP
27     #include "wx/intl.h"
28     #include "wx/log.h"
29     #include "wx/utils.h"
30     #include "wx/wxcrtvararg.h"
31 #endif
32 
33 #include "wx/dataobj.h"
34 
35 #if wxUSE_OLE && defined(__WIN32__) && !defined(__GNUWIN32_OLD__)
36 
37 #include "wx/scopedarray.h"
38 #include "wx/vector.h"
39 #include "wx/msw/private.h"         // includes <windows.h>
40 
41 #ifdef __WXWINCE__
42 #include <winreg.h>
43 #endif
44 
45 // for some compilers, the entire ole2.h must be included, not only oleauto.h
46 #if wxUSE_NORLANDER_HEADERS || defined(__WATCOMC__) || defined(__WXWINCE__)
47   #include <ole2.h>
48 #endif
49 
50 #include <oleauto.h>
51 #include "wx/msw/wrapshl.h"
52 
53 #include "wx/msw/ole/oleutils.h"
54 
55 #include "wx/msw/dib.h"
56 
57 #ifndef CFSTR_SHELLURL
58 #define CFSTR_SHELLURL wxT("UniformResourceLocator")
59 #endif
60 
61 // ----------------------------------------------------------------------------
62 // functions
63 // ----------------------------------------------------------------------------
64 
65 #if wxDEBUG_LEVEL
66     static const wxChar *GetTymedName(DWORD tymed);
67 #else // !wxDEBUG_LEVEL
68     #define GetTymedName(tymed) wxEmptyString
69 #endif // wxDEBUG_LEVEL/!wxDEBUG_LEVEL
70 
71 namespace
72 {
73 
HtmlFormatFixup(wxDataFormat format)74 wxDataFormat HtmlFormatFixup(wxDataFormat format)
75 {
76     // Since the HTML format is dynamically registered, the wxDF_HTML
77     // format does not match the native constant in the way other formats do,
78     // so for the format checks below to work, we must change the native
79     // id to the wxDF_HTML constant.
80     //
81     // But skip this for the standard constants which are never going to match
82     // wxDF_HTML anyhow.
83     if ( !format.IsStandard() )
84     {
85         wxChar szBuf[256];
86         if ( ::GetClipboardFormatName(format, szBuf, WXSIZEOF(szBuf)) )
87         {
88             if ( wxStrcmp(szBuf, wxT("HTML Format")) == 0 )
89                 format = wxDF_HTML;
90         }
91     }
92 
93     return format;
94 }
95 
96 // helper function for wxCopyStgMedium()
wxGlobalClone(HGLOBAL hglobIn)97 HGLOBAL wxGlobalClone(HGLOBAL hglobIn)
98 {
99     HGLOBAL hglobOut = NULL;
100 
101     LPVOID pvIn = GlobalLock(hglobIn);
102     if (pvIn)
103     {
104         SIZE_T cb = GlobalSize(hglobIn);
105         hglobOut = GlobalAlloc(GMEM_FIXED, cb);
106         if (hglobOut)
107         {
108             CopyMemory(hglobOut, pvIn, cb);
109         }
110         GlobalUnlock(hglobIn);
111     }
112 
113     return hglobOut;
114 }
115 
116 // Copies the given STGMEDIUM structure.
117 //
118 // This is an local implementation of the function with the same name in
119 // urlmon.lib but to use that function would require linking with urlmon.lib
120 // and we don't want to require it, so simple reimplement it here.
wxCopyStgMedium(const STGMEDIUM * pmediumIn,STGMEDIUM * pmediumOut)121 HRESULT wxCopyStgMedium(const STGMEDIUM *pmediumIn, STGMEDIUM *pmediumOut)
122 {
123     HRESULT hres = S_OK;
124     STGMEDIUM stgmOut = *pmediumIn;
125 
126     if (pmediumIn->pUnkForRelease == NULL &&
127         !(pmediumIn->tymed & (TYMED_ISTREAM | TYMED_ISTORAGE)))
128     {
129         // Object needs to be cloned.
130         if (pmediumIn->tymed == TYMED_HGLOBAL)
131         {
132             stgmOut.hGlobal = wxGlobalClone(pmediumIn->hGlobal);
133             if (!stgmOut.hGlobal)
134             {
135                 hres = E_OUTOFMEMORY;
136             }
137         }
138         else
139         {
140             hres = DV_E_TYMED; // Don't know how to clone GDI objects.
141         }
142     }
143 
144     if ( SUCCEEDED(hres) )
145     {
146         switch ( stgmOut.tymed )
147         {
148             case TYMED_ISTREAM:
149                 stgmOut.pstm->AddRef();
150                 break;
151 
152             case TYMED_ISTORAGE:
153                 stgmOut.pstg->AddRef();
154                 break;
155         }
156 
157         if ( stgmOut.pUnkForRelease )
158             stgmOut.pUnkForRelease->AddRef();
159 
160         *pmediumOut = stgmOut;
161     }
162 
163     return hres;
164 }
165 
166 } // anonymous namespace
167 
168 // ----------------------------------------------------------------------------
169 // wxIEnumFORMATETC interface implementation
170 // ----------------------------------------------------------------------------
171 
172 class wxIEnumFORMATETC : public IEnumFORMATETC
173 {
174 public:
175     wxIEnumFORMATETC(const wxDataFormat* formats, ULONG nCount);
~wxIEnumFORMATETC()176     virtual ~wxIEnumFORMATETC() { delete [] m_formats; }
177 
178     // IEnumFORMATETC
179     STDMETHODIMP Next(ULONG celt, FORMATETC *rgelt, ULONG *pceltFetched);
180     STDMETHODIMP Skip(ULONG celt);
181     STDMETHODIMP Reset();
182     STDMETHODIMP Clone(IEnumFORMATETC **ppenum);
183 
184     DECLARE_IUNKNOWN_METHODS;
185 
186 private:
187     CLIPFORMAT *m_formats;  // formats we can provide data in
188     ULONG       m_nCount,   // number of formats we support
189                 m_nCurrent; // current enum position
190 
191     wxDECLARE_NO_COPY_CLASS(wxIEnumFORMATETC);
192 };
193 
194 // ----------------------------------------------------------------------------
195 // wxIDataObject implementation of IDataObject interface
196 // ----------------------------------------------------------------------------
197 
198 class wxIDataObject : public IDataObject
199 {
200 public:
201     wxIDataObject(wxDataObject *pDataObject);
202     virtual ~wxIDataObject();
203 
204     // normally, wxDataObject controls our lifetime (i.e. we're deleted when it
205     // is), but in some cases, the situation is reversed, that is we delete it
206     // when this object is deleted - setting this flag enables such logic
SetDeleteFlag()207     void SetDeleteFlag() { m_mustDelete = true; }
208 
209     // IDataObject
210     STDMETHODIMP GetData(FORMATETC *pformatetcIn, STGMEDIUM *pmedium);
211     STDMETHODIMP GetDataHere(FORMATETC *pformatetc, STGMEDIUM *pmedium);
212     STDMETHODIMP QueryGetData(FORMATETC *pformatetc);
213     STDMETHODIMP GetCanonicalFormatEtc(FORMATETC *In, FORMATETC *pOut);
214     STDMETHODIMP SetData(FORMATETC *pfetc, STGMEDIUM *pmedium, BOOL fRelease);
215     STDMETHODIMP EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC **ppenumFEtc);
216     STDMETHODIMP DAdvise(FORMATETC *pfetc, DWORD ad, IAdviseSink *p, DWORD *pdw);
217     STDMETHODIMP DUnadvise(DWORD dwConnection);
218     STDMETHODIMP EnumDAdvise(IEnumSTATDATA **ppenumAdvise);
219 
220     DECLARE_IUNKNOWN_METHODS;
221 
222 private:
223     wxDataObject *m_pDataObject;      // pointer to C++ class we belong to
224 
225     bool m_mustDelete;
226 
227     wxDECLARE_NO_COPY_CLASS(wxIDataObject);
228 
229     // The following code is need to be able to store system data the operating
230     // system is using for it own purposes, e.g. drag images.
231 
232     class SystemDataEntry
233     {
234     public:
235         // Ctor takes ownership of the pointers.
SystemDataEntry(FORMATETC * pformatetc,STGMEDIUM * pmedium)236         SystemDataEntry(FORMATETC *pformatetc, STGMEDIUM *pmedium)
237             : pformatetc(pformatetc), pmedium(pmedium)
238         {
239         }
240 
~SystemDataEntry()241         ~SystemDataEntry()
242         {
243             delete pformatetc;
244             delete pmedium;
245         }
246 
247         FORMATETC *pformatetc;
248         STGMEDIUM *pmedium;
249     };
250     typedef wxVector<SystemDataEntry*> SystemData;
251 
252     // get system data specified by the given format
253     bool GetSystemData(wxDataFormat format, STGMEDIUM*) const;
254 
255     // determines if the data object contains system data specified by the given format.
256     bool HasSystemData(wxDataFormat format) const;
257 
258     // save system data
259     HRESULT SaveSystemData(FORMATETC*, STGMEDIUM*, BOOL fRelease);
260 
261     // container for system data
262     SystemData m_systemData;
263 };
264 
265 bool
GetSystemData(wxDataFormat format,STGMEDIUM * pmedium) const266 wxIDataObject::GetSystemData(wxDataFormat format, STGMEDIUM *pmedium) const
267 {
268     for ( SystemData::const_iterator it = m_systemData.begin();
269           it != m_systemData.end();
270           ++it )
271     {
272         FORMATETC* formatEtc = (*it)->pformatetc;
273         if ( formatEtc->cfFormat == format )
274         {
275             wxCopyStgMedium((*it)->pmedium, pmedium);
276             return true;
277         }
278     }
279 
280     return false;
281 }
282 
283 bool
HasSystemData(wxDataFormat format) const284 wxIDataObject::HasSystemData(wxDataFormat format) const
285 {
286     for ( SystemData::const_iterator it = m_systemData.begin();
287           it != m_systemData.end();
288           ++it )
289     {
290         FORMATETC* formatEtc = (*it)->pformatetc;
291         if ( formatEtc->cfFormat == format )
292             return true;
293     }
294 
295     return false;
296 }
297 
298 // save system data
299 HRESULT
SaveSystemData(FORMATETC * pformatetc,STGMEDIUM * pmedium,BOOL fRelease)300 wxIDataObject::SaveSystemData(FORMATETC *pformatetc,
301                                  STGMEDIUM *pmedium,
302                                  BOOL fRelease)
303 {
304     if ( pformatetc == NULL || pmedium == NULL )
305         return E_INVALIDARG;
306 
307     // remove entry if already available
308     for ( SystemData::iterator it = m_systemData.begin();
309           it != m_systemData.end();
310           ++it )
311     {
312         if ( pformatetc->tymed & (*it)->pformatetc->tymed &&
313              pformatetc->dwAspect == (*it)->pformatetc->dwAspect &&
314              pformatetc->cfFormat == (*it)->pformatetc->cfFormat )
315         {
316             delete (*it);
317             m_systemData.erase(it);
318             break;
319         }
320     }
321 
322     // create new format/medium
323     FORMATETC* pnewformatEtc = new FORMATETC;
324     STGMEDIUM* pnewmedium = new STGMEDIUM;
325 
326     wxZeroMemory(*pnewformatEtc);
327     wxZeroMemory(*pnewmedium);
328 
329     // copy format
330     *pnewformatEtc = *pformatetc;
331 
332     // copy or take ownerschip of medium
333     if ( fRelease )
334         *pnewmedium = *pmedium;
335     else
336         wxCopyStgMedium(pmedium, pnewmedium);
337 
338     // save entry
339     m_systemData.push_back(new SystemDataEntry(pnewformatEtc, pnewmedium));
340 
341     return S_OK;
342 }
343 
344 // ============================================================================
345 // implementation
346 // ============================================================================
347 
348 // ----------------------------------------------------------------------------
349 // wxDataFormat
350 // ----------------------------------------------------------------------------
351 
operator ==(wxDataFormatId format) const352 bool wxDataFormat::operator==(wxDataFormatId format) const
353 {
354     return HtmlFormatFixup(*this).m_format == (NativeFormat)format;
355 }
356 
operator !=(wxDataFormatId format) const357 bool wxDataFormat::operator!=(wxDataFormatId format) const
358 {
359     return !(*this == format);
360 }
361 
operator ==(const wxDataFormat & format) const362 bool wxDataFormat::operator==(const wxDataFormat& format) const
363 {
364     return HtmlFormatFixup(*this).m_format == HtmlFormatFixup(format).m_format;
365 }
366 
operator !=(const wxDataFormat & format) const367 bool wxDataFormat::operator!=(const wxDataFormat& format) const
368 {
369     return !(*this == format);
370 }
371 
SetId(const wxString & format)372 void wxDataFormat::SetId(const wxString& format)
373 {
374     m_format = (wxDataFormat::NativeFormat)::RegisterClipboardFormat(format.t_str());
375     if ( !m_format )
376     {
377         wxLogError(_("Couldn't register clipboard format '%s'."), format);
378     }
379 }
380 
GetId() const381 wxString wxDataFormat::GetId() const
382 {
383     static const int max = 256;
384 
385     wxString s;
386 
387     wxCHECK_MSG( !IsStandard(), s,
388                  wxT("name of predefined format cannot be retrieved") );
389 
390     int len = ::GetClipboardFormatName(m_format, wxStringBuffer(s, max), max);
391 
392     if ( !len )
393     {
394         wxLogError(_("The clipboard format '%d' doesn't exist."), m_format);
395         return wxEmptyString;
396     }
397 
398     return s;
399 }
400 
401 // ----------------------------------------------------------------------------
402 // wxIEnumFORMATETC
403 // ----------------------------------------------------------------------------
404 
405 BEGIN_IID_TABLE(wxIEnumFORMATETC)
406     ADD_IID(Unknown)
407     ADD_IID(EnumFORMATETC)
408 END_IID_TABLE;
409 
IMPLEMENT_IUNKNOWN_METHODS(wxIEnumFORMATETC)410 IMPLEMENT_IUNKNOWN_METHODS(wxIEnumFORMATETC)
411 
412 wxIEnumFORMATETC::wxIEnumFORMATETC(const wxDataFormat *formats, ULONG nCount)
413 {
414     m_nCurrent = 0;
415     m_nCount = nCount;
416     m_formats = new CLIPFORMAT[nCount];
417     for ( ULONG n = 0; n < nCount; n++ ) {
418         if (formats[n].GetFormatId() != wxDF_HTML)
419             m_formats[n] = formats[n].GetFormatId();
420         else
421             m_formats[n] = ::RegisterClipboardFormat(wxT("HTML Format"));
422     }
423 }
424 
Next(ULONG celt,FORMATETC * rgelt,ULONG * pceltFetched)425 STDMETHODIMP wxIEnumFORMATETC::Next(ULONG      celt,
426                                     FORMATETC *rgelt,
427                                     ULONG     *pceltFetched)
428 {
429     wxLogTrace(wxTRACE_OleCalls, wxT("wxIEnumFORMATETC::Next"));
430 
431     ULONG numFetched = 0;
432     while (m_nCurrent < m_nCount && numFetched < celt) {
433         FORMATETC format;
434         format.cfFormat = m_formats[m_nCurrent++];
435         format.ptd      = NULL;
436         format.dwAspect = DVASPECT_CONTENT;
437         format.lindex   = -1;
438         format.tymed    = TYMED_HGLOBAL;
439 
440         *rgelt++ = format;
441         numFetched++;
442     }
443 
444     if (pceltFetched)
445         *pceltFetched = numFetched;
446 
447     return numFetched == celt ? S_OK : S_FALSE;
448 }
449 
Skip(ULONG celt)450 STDMETHODIMP wxIEnumFORMATETC::Skip(ULONG celt)
451 {
452     wxLogTrace(wxTRACE_OleCalls, wxT("wxIEnumFORMATETC::Skip"));
453 
454     m_nCurrent += celt;
455     if ( m_nCurrent < m_nCount )
456         return S_OK;
457 
458     // no, can't skip this many elements
459     m_nCurrent -= celt;
460 
461     return S_FALSE;
462 }
463 
Reset()464 STDMETHODIMP wxIEnumFORMATETC::Reset()
465 {
466     wxLogTrace(wxTRACE_OleCalls, wxT("wxIEnumFORMATETC::Reset"));
467 
468     m_nCurrent = 0;
469 
470     return S_OK;
471 }
472 
Clone(IEnumFORMATETC ** ppenum)473 STDMETHODIMP wxIEnumFORMATETC::Clone(IEnumFORMATETC **ppenum)
474 {
475     wxLogTrace(wxTRACE_OleCalls, wxT("wxIEnumFORMATETC::Clone"));
476 
477     // unfortunately, we can't reuse the code in ctor - types are different
478     wxIEnumFORMATETC *pNew = new wxIEnumFORMATETC(NULL, 0);
479     pNew->m_nCount = m_nCount;
480     pNew->m_formats = new CLIPFORMAT[m_nCount];
481     for ( ULONG n = 0; n < m_nCount; n++ ) {
482         pNew->m_formats[n] = m_formats[n];
483     }
484     pNew->AddRef();
485     *ppenum = pNew;
486 
487     return S_OK;
488 }
489 
490 // ----------------------------------------------------------------------------
491 // wxIDataObject
492 // ----------------------------------------------------------------------------
493 
494 BEGIN_IID_TABLE(wxIDataObject)
495     ADD_IID(Unknown)
496     ADD_IID(DataObject)
497 END_IID_TABLE;
498 
IMPLEMENT_IUNKNOWN_METHODS(wxIDataObject)499 IMPLEMENT_IUNKNOWN_METHODS(wxIDataObject)
500 
501 wxIDataObject::wxIDataObject(wxDataObject *pDataObject)
502 {
503     m_pDataObject = pDataObject;
504     m_mustDelete = false;
505 }
506 
~wxIDataObject()507 wxIDataObject::~wxIDataObject()
508 {
509     // delete system data
510     for ( SystemData::iterator it = m_systemData.begin();
511           it != m_systemData.end();
512           ++it )
513     {
514         delete (*it);
515     }
516 
517     if ( m_mustDelete )
518     {
519         delete m_pDataObject;
520     }
521 }
522 
523 // get data functions
GetData(FORMATETC * pformatetcIn,STGMEDIUM * pmedium)524 STDMETHODIMP wxIDataObject::GetData(FORMATETC *pformatetcIn, STGMEDIUM *pmedium)
525 {
526     wxLogTrace(wxTRACE_OleCalls, wxT("wxIDataObject::GetData"));
527 
528     // is data is in our format?
529     HRESULT hr = QueryGetData(pformatetcIn);
530     if ( FAILED(hr) )
531         return hr;
532 
533     // for the bitmaps and metafiles we use the handles instead of global memory
534     // to pass the data
535     wxDataFormat format = (wxDataFormat::NativeFormat)pformatetcIn->cfFormat;
536     format = HtmlFormatFixup(format);
537 
538     // is this system data?
539     if ( GetSystemData(format, pmedium) )
540     {
541         // pmedium is already filled with corresponding data, so we're ready.
542         return S_OK;
543     }
544 
545     switch ( format )
546     {
547         case wxDF_BITMAP:
548             pmedium->tymed = TYMED_GDI;
549             break;
550 
551         case wxDF_ENHMETAFILE:
552             pmedium->tymed = TYMED_ENHMF;
553             break;
554 
555 #ifndef __WXWINCE__
556         case wxDF_METAFILE:
557             pmedium->hGlobal = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE,
558                                            sizeof(METAFILEPICT));
559             if ( !pmedium->hGlobal ) {
560                 wxLogLastError(wxT("GlobalAlloc"));
561                 return E_OUTOFMEMORY;
562             }
563             pmedium->tymed = TYMED_MFPICT;
564             break;
565 #endif
566         default:
567             // alloc memory
568             size_t size = m_pDataObject->GetDataSize(format);
569             if ( !size ) {
570                 // it probably means that the method is just not implemented
571                 wxLogDebug(wxT("Invalid data size - can't be 0"));
572 
573                 return DV_E_FORMATETC;
574             }
575 
576             // we may need extra space for the buffer size
577             size += m_pDataObject->GetBufferOffset( format );
578 
579             HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, size);
580             if ( hGlobal == NULL ) {
581                 wxLogLastError(wxT("GlobalAlloc"));
582                 return E_OUTOFMEMORY;
583             }
584 
585             // copy data
586             pmedium->tymed   = TYMED_HGLOBAL;
587             pmedium->hGlobal = hGlobal;
588     }
589 
590     pmedium->pUnkForRelease = NULL;
591 
592     // do copy the data
593     hr = GetDataHere(pformatetcIn, pmedium);
594     if ( FAILED(hr) ) {
595         // free resources we allocated
596         if ( pmedium->tymed & (TYMED_HGLOBAL | TYMED_MFPICT) ) {
597             GlobalFree(pmedium->hGlobal);
598         }
599 
600         return hr;
601     }
602 
603     return S_OK;
604 }
605 
GetDataHere(FORMATETC * pformatetc,STGMEDIUM * pmedium)606 STDMETHODIMP wxIDataObject::GetDataHere(FORMATETC *pformatetc,
607                                         STGMEDIUM *pmedium)
608 {
609     wxLogTrace(wxTRACE_OleCalls, wxT("wxIDataObject::GetDataHere"));
610 
611     // put data in caller provided medium
612     switch ( pmedium->tymed )
613     {
614         case TYMED_GDI:
615             if ( !m_pDataObject->GetDataHere(wxDF_BITMAP, &pmedium->hBitmap) )
616                 return E_UNEXPECTED;
617             break;
618 
619         case TYMED_ENHMF:
620             if ( !m_pDataObject->GetDataHere(wxDF_ENHMETAFILE,
621                                              &pmedium->hEnhMetaFile) )
622                 return E_UNEXPECTED;
623             break;
624 
625         case TYMED_MFPICT:
626             // fall through - we pass METAFILEPICT through HGLOBAL
627 
628         case TYMED_HGLOBAL:
629             {
630                 // copy data
631                 HGLOBAL hGlobal = pmedium->hGlobal;
632                 void *pBuf = GlobalLock(hGlobal);
633                 if ( pBuf == NULL ) {
634                     wxLogLastError(wxT("GlobalLock"));
635                     return E_OUTOFMEMORY;
636                 }
637 
638                 wxDataFormat format = pformatetc->cfFormat;
639 
640                 // possibly put the size in the beginning of the buffer
641                 pBuf = m_pDataObject->SetSizeInBuffer
642                                       (
643                                         pBuf,
644                                         ::GlobalSize(hGlobal),
645                                         format
646                                       );
647 
648                 if ( !m_pDataObject->GetDataHere(format, pBuf) )
649                     return E_UNEXPECTED;
650 
651                 GlobalUnlock(hGlobal);
652             }
653             break;
654 
655         default:
656             return DV_E_TYMED;
657     }
658 
659     return S_OK;
660 }
661 
662 
663 // set data functions
SetData(FORMATETC * pformatetc,STGMEDIUM * pmedium,BOOL fRelease)664 STDMETHODIMP wxIDataObject::SetData(FORMATETC *pformatetc,
665                                     STGMEDIUM *pmedium,
666                                     BOOL       fRelease)
667 {
668     wxLogTrace(wxTRACE_OleCalls, wxT("wxIDataObject::SetData"));
669 
670     switch ( pmedium->tymed )
671     {
672         case TYMED_GDI:
673             m_pDataObject->SetData(wxDF_BITMAP, 0, &pmedium->hBitmap);
674             break;
675 
676         case TYMED_ENHMF:
677             m_pDataObject->SetData(wxDF_ENHMETAFILE, 0, &pmedium->hEnhMetaFile);
678             break;
679 
680         case TYMED_ISTREAM:
681             // check if this format is supported
682             if ( !m_pDataObject->IsSupported(pformatetc->cfFormat,
683                                              wxDataObject::Set) )
684             {
685                 // As this is not a supported format (content data), assume it
686                 // is system data and save it.
687                 return SaveSystemData(pformatetc, pmedium, fRelease);
688             }
689             break;
690 
691         case TYMED_MFPICT:
692             // fall through - we pass METAFILEPICT through HGLOBAL
693         case TYMED_HGLOBAL:
694             {
695                 wxDataFormat format = pformatetc->cfFormat;
696 
697                 format = HtmlFormatFixup(format);
698 
699                 // check if this format is supported
700                 if ( !m_pDataObject->IsSupported(format, wxDataObject::Set) ) {
701                     // As above, assume that unsupported format must be system
702                     // data and just save it.
703                     return SaveSystemData(pformatetc, pmedium, fRelease);
704                 }
705 
706                 // copy data
707                 const void *pBuf = GlobalLock(pmedium->hGlobal);
708                 if ( pBuf == NULL ) {
709                     wxLogLastError(wxT("GlobalLock"));
710 
711                     return E_OUTOFMEMORY;
712                 }
713 
714                 // we've got a problem with SetData() here because the base
715                 // class version requires the size parameter which we don't
716                 // have anywhere in OLE data transfer - so we need to
717                 // synthetise it for known formats and we suppose that all data
718                 // in custom formats starts with a DWORD containing the size
719                 size_t size;
720                 switch ( format )
721                 {
722                     case wxDF_HTML:
723                     case CF_TEXT:
724                     case CF_OEMTEXT:
725                         size = strlen((const char *)pBuf);
726                         break;
727 #if !(defined(__BORLANDC__) && (__BORLANDC__ < 0x500))
728                     case CF_UNICODETEXT:
729 #if ( defined(__BORLANDC__) && (__BORLANDC__ > 0x530) )
730                         size = std::wcslen((const wchar_t *)pBuf) * sizeof(wchar_t);
731 #else
732                         size = wxWcslen((const wchar_t *)pBuf) * sizeof(wchar_t);
733 #endif
734                         break;
735 #endif
736                     case CF_BITMAP:
737 #ifndef __WXWINCE__
738                     case CF_HDROP:
739                         // these formats don't use size at all, anyhow (but
740                         // pass data by handle, which is always a single DWORD)
741                         size = 0;
742                         break;
743 #endif
744 
745                     case CF_DIB:
746                         // the handler will calculate size itself (it's too
747                         // complicated to do it here)
748                         size = 0;
749                         break;
750 
751 #ifndef __WXWINCE__
752                     case CF_METAFILEPICT:
753                         size = sizeof(METAFILEPICT);
754                         break;
755 #endif
756                     default:
757                         pBuf = m_pDataObject->
758                                     GetSizeFromBuffer(pBuf, &size, format);
759                         size -= m_pDataObject->GetBufferOffset(format);
760                 }
761 
762                 bool ok = m_pDataObject->SetData(format, size, pBuf);
763 
764                 GlobalUnlock(pmedium->hGlobal);
765 
766                 if ( !ok ) {
767                     return E_UNEXPECTED;
768                 }
769             }
770             break;
771 
772         default:
773             return DV_E_TYMED;
774     }
775 
776     if ( fRelease ) {
777         // we own the medium, so we must release it - but do *not* free any
778         // data we pass by handle because we have copied it elsewhere
779         switch ( pmedium->tymed )
780         {
781             case TYMED_GDI:
782                 pmedium->hBitmap = 0;
783                 break;
784 
785             case TYMED_MFPICT:
786                 pmedium->hMetaFilePict = 0;
787                 break;
788 
789             case TYMED_ENHMF:
790                 pmedium->hEnhMetaFile = 0;
791                 break;
792         }
793 
794         ReleaseStgMedium(pmedium);
795     }
796 
797     return S_OK;
798 }
799 
800 // information functions
QueryGetData(FORMATETC * pformatetc)801 STDMETHODIMP wxIDataObject::QueryGetData(FORMATETC *pformatetc)
802 {
803     // do we accept data in this format?
804     if ( pformatetc == NULL ) {
805         wxLogTrace(wxTRACE_OleCalls,
806                    wxT("wxIDataObject::QueryGetData: invalid ptr."));
807 
808         return E_INVALIDARG;
809     }
810 
811     // the only one allowed by current COM implementation
812     if ( pformatetc->lindex != -1 ) {
813         wxLogTrace(wxTRACE_OleCalls,
814                    wxT("wxIDataObject::QueryGetData: bad lindex %ld"),
815                    pformatetc->lindex);
816 
817         return DV_E_LINDEX;
818     }
819 
820     // we don't support anything other (THUMBNAIL, ICON, DOCPRINT...)
821     if ( pformatetc->dwAspect != DVASPECT_CONTENT ) {
822         wxLogTrace(wxTRACE_OleCalls,
823                    wxT("wxIDataObject::QueryGetData: bad dwAspect %ld"),
824                    pformatetc->dwAspect);
825 
826         return DV_E_DVASPECT;
827     }
828 
829     // and now check the type of data requested
830     wxDataFormat format = pformatetc->cfFormat;
831     format = HtmlFormatFixup(format);
832 
833     if ( m_pDataObject->IsSupportedFormat(format) ) {
834         wxLogTrace(wxTRACE_OleCalls, wxT("wxIDataObject::QueryGetData: %s ok"),
835                    wxGetFormatName(format));
836     }
837     else if ( HasSystemData(format) )
838     {
839         wxLogTrace(wxTRACE_OleCalls, wxT("wxIDataObject::QueryGetData: %s ok (system data)"),
840                    wxGetFormatName(format));
841         // this is system data, so no further checks needed.
842         return S_OK;
843     }
844     else {
845         wxLogTrace(wxTRACE_OleCalls,
846                    wxT("wxIDataObject::QueryGetData: %s unsupported"),
847                    wxGetFormatName(format));
848 
849         return DV_E_FORMATETC;
850     }
851 
852     // we only transfer data by global memory, except for some particular cases
853     DWORD tymed = pformatetc->tymed;
854     if ( (format == wxDF_BITMAP && !(tymed & TYMED_GDI)) &&
855          !(tymed & TYMED_HGLOBAL) ) {
856         // it's not what we're waiting for
857         wxLogTrace(wxTRACE_OleCalls,
858                    wxT("wxIDataObject::QueryGetData: %s != %s"),
859                    GetTymedName(tymed),
860                    GetTymedName(format == wxDF_BITMAP ? TYMED_GDI
861                                                       : TYMED_HGLOBAL));
862 
863         return DV_E_TYMED;
864     }
865 
866     return S_OK;
867 }
868 
GetCanonicalFormatEtc(FORMATETC * WXUNUSED (pFormatetcIn),FORMATETC * pFormatetcOut)869 STDMETHODIMP wxIDataObject::GetCanonicalFormatEtc(FORMATETC *WXUNUSED(pFormatetcIn),
870                                                   FORMATETC *pFormatetcOut)
871 {
872     wxLogTrace(wxTRACE_OleCalls, wxT("wxIDataObject::GetCanonicalFormatEtc"));
873 
874     // TODO we might want something better than this trivial implementation here
875     if ( pFormatetcOut != NULL )
876         pFormatetcOut->ptd = NULL;
877 
878     return DATA_S_SAMEFORMATETC;
879 }
880 
EnumFormatEtc(DWORD dwDir,IEnumFORMATETC ** ppenumFormatEtc)881 STDMETHODIMP wxIDataObject::EnumFormatEtc(DWORD dwDir,
882                                           IEnumFORMATETC **ppenumFormatEtc)
883 {
884     wxLogTrace(wxTRACE_OleCalls, wxT("wxIDataObject::EnumFormatEtc"));
885 
886     wxDataObject::Direction dir = dwDir == DATADIR_GET ? wxDataObject::Get
887                                                        : wxDataObject::Set;
888 
889     // format count is total of user specified and system formats.
890     const size_t ourFormatCount = m_pDataObject->GetFormatCount(dir);
891     const size_t sysFormatCount = m_systemData.size();
892 
893     const ULONG
894         nFormatCount = wx_truncate_cast(ULONG, ourFormatCount + sysFormatCount);
895 
896     // fill format array with formats ...
897     wxScopedArray<wxDataFormat> formats(new wxDataFormat[nFormatCount]);
898 
899     // ... from content data (supported formats)
900     m_pDataObject->GetAllFormats(formats.get(), dir);
901 
902     // ... from system data
903     for ( size_t j = 0; j < sysFormatCount; j++ )
904     {
905         SystemDataEntry* entry = m_systemData[j];
906         wxDataFormat& format = formats[ourFormatCount + j];
907         format = entry->pformatetc->cfFormat;
908     }
909 
910     wxIEnumFORMATETC *pEnum = new wxIEnumFORMATETC(formats.get(), nFormatCount);
911     pEnum->AddRef();
912     *ppenumFormatEtc = pEnum;
913 
914     return S_OK;
915 }
916 
917 // ----------------------------------------------------------------------------
918 // advise sink functions (not implemented)
919 // ----------------------------------------------------------------------------
920 
DAdvise(FORMATETC * WXUNUSED (pformatetc),DWORD WXUNUSED (advf),IAdviseSink * WXUNUSED (pAdvSink),DWORD * WXUNUSED (pdwConnection))921 STDMETHODIMP wxIDataObject::DAdvise(FORMATETC   *WXUNUSED(pformatetc),
922                                     DWORD        WXUNUSED(advf),
923                                     IAdviseSink *WXUNUSED(pAdvSink),
924                                     DWORD       *WXUNUSED(pdwConnection))
925 {
926   return OLE_E_ADVISENOTSUPPORTED;
927 }
928 
DUnadvise(DWORD WXUNUSED (dwConnection))929 STDMETHODIMP wxIDataObject::DUnadvise(DWORD WXUNUSED(dwConnection))
930 {
931   return OLE_E_ADVISENOTSUPPORTED;
932 }
933 
EnumDAdvise(IEnumSTATDATA ** WXUNUSED (ppenumAdvise))934 STDMETHODIMP wxIDataObject::EnumDAdvise(IEnumSTATDATA **WXUNUSED(ppenumAdvise))
935 {
936   return OLE_E_ADVISENOTSUPPORTED;
937 }
938 
939 // ----------------------------------------------------------------------------
940 // wxDataObject
941 // ----------------------------------------------------------------------------
942 
wxDataObject()943 wxDataObject::wxDataObject()
944 {
945     m_pIDataObject = new wxIDataObject(this);
946     m_pIDataObject->AddRef();
947 }
948 
~wxDataObject()949 wxDataObject::~wxDataObject()
950 {
951     ReleaseInterface(m_pIDataObject);
952 }
953 
SetAutoDelete()954 void wxDataObject::SetAutoDelete()
955 {
956     ((wxIDataObject *)m_pIDataObject)->SetDeleteFlag();
957     m_pIDataObject->Release();
958 
959     // so that the dtor doesn't crash
960     m_pIDataObject = NULL;
961 }
962 
GetBufferOffset(const wxDataFormat & format)963 size_t wxDataObject::GetBufferOffset(const wxDataFormat& format )
964 {
965     // if we prepend the size of the data to the buffer itself, account for it
966     return NeedsVerbatimData(format) ? 0 : sizeof(size_t);
967 }
968 
GetSizeFromBuffer(const void * buffer,size_t * size,const wxDataFormat & WXUNUSED (format))969 const void *wxDataObject::GetSizeFromBuffer(const void *buffer,
970                                             size_t *size,
971                                             const wxDataFormat& WXUNUSED(format))
972 {
973     // hack: the third parameter is declared non-const in Wine's headers so
974     // cast away the const
975     const size_t realsz = ::HeapSize(::GetProcessHeap(), 0,
976                                      const_cast<void*>(buffer));
977     if ( realsz == (size_t)-1 )
978     {
979         // note that HeapSize() does not set last error
980         wxLogApiError(wxT("HeapSize"), 0);
981         return NULL;
982     }
983 
984     *size = realsz;
985 
986     return buffer;
987 }
988 
SetSizeInBuffer(void * buffer,size_t size,const wxDataFormat & format)989 void* wxDataObject::SetSizeInBuffer( void* buffer, size_t size,
990                                       const wxDataFormat& format )
991 {
992     size_t* p = (size_t *)buffer;
993     if ( !NeedsVerbatimData(format) )
994     {
995         // prepend the size to the data and skip it
996         *p++ = size;
997     }
998 
999     return p;
1000 }
1001 
1002 #if wxDEBUG_LEVEL
1003 
GetFormatName(wxDataFormat format)1004 const wxChar *wxDataObject::GetFormatName(wxDataFormat format)
1005 {
1006     // case 'xxx' is not a valid value for switch of enum 'wxDataFormat'
1007     #ifdef __VISUALC__
1008         #pragma warning(disable:4063)
1009     #endif // VC++
1010 
1011     static wxChar s_szBuf[256];
1012     switch ( format ) {
1013         case CF_TEXT:         return wxT("CF_TEXT");
1014         case CF_BITMAP:       return wxT("CF_BITMAP");
1015         case CF_SYLK:         return wxT("CF_SYLK");
1016         case CF_DIF:          return wxT("CF_DIF");
1017         case CF_TIFF:         return wxT("CF_TIFF");
1018         case CF_OEMTEXT:      return wxT("CF_OEMTEXT");
1019         case CF_DIB:          return wxT("CF_DIB");
1020         case CF_PALETTE:      return wxT("CF_PALETTE");
1021         case CF_PENDATA:      return wxT("CF_PENDATA");
1022         case CF_RIFF:         return wxT("CF_RIFF");
1023         case CF_WAVE:         return wxT("CF_WAVE");
1024         case CF_UNICODETEXT:  return wxT("CF_UNICODETEXT");
1025 #ifndef __WXWINCE__
1026         case CF_METAFILEPICT: return wxT("CF_METAFILEPICT");
1027         case CF_ENHMETAFILE:  return wxT("CF_ENHMETAFILE");
1028         case CF_LOCALE:       return wxT("CF_LOCALE");
1029         case CF_HDROP:        return wxT("CF_HDROP");
1030 #endif
1031 
1032         default:
1033             if ( !::GetClipboardFormatName(format, s_szBuf, WXSIZEOF(s_szBuf)) )
1034             {
1035                 // it must be a new predefined format we don't know the name of
1036                 wxSprintf(s_szBuf, wxT("unknown CF (0x%04x)"), format.GetFormatId());
1037             }
1038 
1039             return s_szBuf;
1040     }
1041 
1042     #ifdef __VISUALC__
1043         #pragma warning(default:4063)
1044     #endif // VC++
1045 }
1046 
1047 #endif // wxDEBUG_LEVEL
1048 
1049 // ----------------------------------------------------------------------------
1050 // wxBitmapDataObject supports CF_DIB format
1051 // ----------------------------------------------------------------------------
1052 
1053 // TODO: support CF_DIB under Windows CE as well
1054 
GetDataSize() const1055 size_t wxBitmapDataObject::GetDataSize() const
1056 {
1057 #if wxUSE_WXDIB && !defined(__WXWINCE__)
1058     return wxDIB::ConvertFromBitmap(NULL, GetHbitmapOf(GetBitmap()));
1059 #else
1060     return 0;
1061 #endif
1062 }
1063 
GetDataHere(void * buf) const1064 bool wxBitmapDataObject::GetDataHere(void *buf) const
1065 {
1066 #if wxUSE_WXDIB && !defined(__WXWINCE__)
1067     BITMAPINFO * const pbi = (BITMAPINFO *)buf;
1068 
1069     return wxDIB::ConvertFromBitmap(pbi, GetHbitmapOf(GetBitmap())) != 0;
1070 #else
1071     wxUnusedVar(buf);
1072     return false;
1073 #endif
1074 }
1075 
SetData(size_t WXUNUSED (len),const void * buf)1076 bool wxBitmapDataObject::SetData(size_t WXUNUSED(len), const void *buf)
1077 {
1078 #if wxUSE_WXDIB && !defined(__WXWINCE__)
1079     const BITMAPINFO * const pbmi = (const BITMAPINFO *)buf;
1080 
1081     HBITMAP hbmp = wxDIB::ConvertToBitmap(pbmi);
1082 
1083     wxCHECK_MSG( hbmp, FALSE, wxT("pasting/dropping invalid bitmap") );
1084 
1085     const BITMAPINFOHEADER * const pbmih = &pbmi->bmiHeader;
1086     wxBitmap bitmap(pbmih->biWidth, pbmih->biHeight, pbmih->biBitCount);
1087     bitmap.SetHBITMAP((WXHBITMAP)hbmp);
1088 
1089     // TODO: create wxPalette if the bitmap has any
1090 
1091     SetBitmap(bitmap);
1092 
1093     return true;
1094 #else
1095     wxUnusedVar(buf);
1096     return false;
1097 #endif
1098 }
1099 
1100 // ----------------------------------------------------------------------------
1101 // wxBitmapDataObject2 supports CF_BITMAP format
1102 // ----------------------------------------------------------------------------
1103 
1104 // the bitmaps aren't passed by value as other types of data (i.e. by copying
1105 // the data into a global memory chunk and passing it to the clipboard or
1106 // another application or whatever), but by handle, so these generic functions
1107 // don't make much sense to them.
1108 
GetDataSize() const1109 size_t wxBitmapDataObject2::GetDataSize() const
1110 {
1111     return 0;
1112 }
1113 
GetDataHere(void * pBuf) const1114 bool wxBitmapDataObject2::GetDataHere(void *pBuf) const
1115 {
1116     // we put a bitmap handle into pBuf
1117     *(WXHBITMAP *)pBuf = GetBitmap().GetHBITMAP();
1118 
1119     return true;
1120 }
1121 
SetData(size_t WXUNUSED (len),const void * pBuf)1122 bool wxBitmapDataObject2::SetData(size_t WXUNUSED(len), const void *pBuf)
1123 {
1124     HBITMAP hbmp = *(HBITMAP *)pBuf;
1125 
1126     BITMAP bmp;
1127     if ( !GetObject(hbmp, sizeof(BITMAP), &bmp) )
1128     {
1129         wxLogLastError(wxT("GetObject(HBITMAP)"));
1130     }
1131 
1132     wxBitmap bitmap(bmp.bmWidth, bmp.bmHeight, bmp.bmPlanes);
1133     bitmap.SetHBITMAP((WXHBITMAP)hbmp);
1134 
1135     if ( !bitmap.IsOk() ) {
1136         wxFAIL_MSG(wxT("pasting/dropping invalid bitmap"));
1137 
1138         return false;
1139     }
1140 
1141     SetBitmap(bitmap);
1142 
1143     return true;
1144 }
1145 
1146 #if 0
1147 
1148 size_t wxBitmapDataObject::GetDataSize(const wxDataFormat& format) const
1149 {
1150     if ( format.GetFormatId() == CF_DIB )
1151     {
1152         // create the DIB
1153         ScreenHDC hdc;
1154 
1155         // shouldn't be selected into a DC or GetDIBits() would fail
1156         wxASSERT_MSG( !m_bitmap.GetSelectedInto(),
1157                       wxT("can't copy bitmap selected into wxMemoryDC") );
1158 
1159         // first get the info
1160         BITMAPINFO bi;
1161         if ( !GetDIBits(hdc, (HBITMAP)m_bitmap.GetHBITMAP(), 0, 0,
1162                         NULL, &bi, DIB_RGB_COLORS) )
1163         {
1164             wxLogLastError(wxT("GetDIBits(NULL)"));
1165 
1166             return 0;
1167         }
1168 
1169         return sizeof(BITMAPINFO) + bi.bmiHeader.biSizeImage;
1170     }
1171     else // CF_BITMAP
1172     {
1173         // no data to copy - we don't pass HBITMAP via global memory
1174         return 0;
1175     }
1176 }
1177 
1178 bool wxBitmapDataObject::GetDataHere(const wxDataFormat& format,
1179                                      void *pBuf) const
1180 {
1181     wxASSERT_MSG( m_bitmap.IsOk(), wxT("copying invalid bitmap") );
1182 
1183     HBITMAP hbmp = (HBITMAP)m_bitmap.GetHBITMAP();
1184     if ( format.GetFormatId() == CF_DIB )
1185     {
1186         // create the DIB
1187         ScreenHDC hdc;
1188 
1189         // shouldn't be selected into a DC or GetDIBits() would fail
1190         wxASSERT_MSG( !m_bitmap.GetSelectedInto(),
1191                       wxT("can't copy bitmap selected into wxMemoryDC") );
1192 
1193         // first get the info
1194         BITMAPINFO *pbi = (BITMAPINFO *)pBuf;
1195         if ( !GetDIBits(hdc, hbmp, 0, 0, NULL, pbi, DIB_RGB_COLORS) )
1196         {
1197             wxLogLastError(wxT("GetDIBits(NULL)"));
1198 
1199             return 0;
1200         }
1201 
1202         // and now copy the bits
1203         if ( !GetDIBits(hdc, hbmp, 0, pbi->bmiHeader.biHeight, pbi + 1,
1204                         pbi, DIB_RGB_COLORS) )
1205         {
1206             wxLogLastError(wxT("GetDIBits"));
1207 
1208             return false;
1209         }
1210     }
1211     else // CF_BITMAP
1212     {
1213         // we put a bitmap handle into pBuf
1214         *(HBITMAP *)pBuf = hbmp;
1215     }
1216 
1217     return true;
1218 }
1219 
1220 bool wxBitmapDataObject::SetData(const wxDataFormat& format,
1221                                  size_t size, const void *pBuf)
1222 {
1223     HBITMAP hbmp;
1224     if ( format.GetFormatId() == CF_DIB )
1225     {
1226         // here we get BITMAPINFO struct followed by the actual bitmap bits and
1227         // BITMAPINFO starts with BITMAPINFOHEADER followed by colour info
1228         ScreenHDC hdc;
1229 
1230         BITMAPINFO *pbmi = (BITMAPINFO *)pBuf;
1231         BITMAPINFOHEADER *pbmih = &pbmi->bmiHeader;
1232         hbmp = CreateDIBitmap(hdc, pbmih, CBM_INIT,
1233                               pbmi + 1, pbmi, DIB_RGB_COLORS);
1234         if ( !hbmp )
1235         {
1236             wxLogLastError(wxT("CreateDIBitmap"));
1237         }
1238 
1239         m_bitmap.SetWidth(pbmih->biWidth);
1240         m_bitmap.SetHeight(pbmih->biHeight);
1241     }
1242     else // CF_BITMAP
1243     {
1244         // it's easy with bitmaps: we pass them by handle
1245         hbmp = *(HBITMAP *)pBuf;
1246 
1247         BITMAP bmp;
1248         if ( !GetObject(hbmp, sizeof(BITMAP), &bmp) )
1249         {
1250             wxLogLastError(wxT("GetObject(HBITMAP)"));
1251         }
1252 
1253         m_bitmap.SetWidth(bmp.bmWidth);
1254         m_bitmap.SetHeight(bmp.bmHeight);
1255         m_bitmap.SetDepth(bmp.bmPlanes);
1256     }
1257 
1258     m_bitmap.SetHBITMAP((WXHBITMAP)hbmp);
1259 
1260     wxASSERT_MSG( m_bitmap.IsOk(), wxT("pasting invalid bitmap") );
1261 
1262     return true;
1263 }
1264 
1265 #endif // 0
1266 
1267 // ----------------------------------------------------------------------------
1268 // wxFileDataObject
1269 // ----------------------------------------------------------------------------
1270 
SetData(size_t WXUNUSED (size),const void * WXUNUSED_IN_WINCE (pData))1271 bool wxFileDataObject::SetData(size_t WXUNUSED(size),
1272                                const void *WXUNUSED_IN_WINCE(pData))
1273 {
1274 #ifndef __WXWINCE__
1275     m_filenames.Empty();
1276 
1277     // the documentation states that the first member of DROPFILES structure is
1278     // a "DWORD offset of double NUL terminated file list". What they mean by
1279     // this (I wonder if you see it immediately) is that the list starts at
1280     // ((char *)&(pDropFiles.pFiles)) + pDropFiles.pFiles. We're also advised
1281     // to use DragQueryFile to work with this structure, but not told where and
1282     // how to get HDROP.
1283     HDROP hdrop = (HDROP)pData;   // NB: it works, but I'm not sure about it
1284 
1285     // get number of files (magic value -1)
1286     UINT nFiles = ::DragQueryFile(hdrop, (unsigned)-1, NULL, 0u);
1287 
1288     wxCHECK_MSG ( nFiles != (UINT)-1, FALSE, wxT("wrong HDROP handle") );
1289 
1290     // for each file get the length, allocate memory and then get the name
1291     wxString str;
1292     UINT len, n;
1293     for ( n = 0; n < nFiles; n++ ) {
1294         // +1 for terminating NUL
1295         len = ::DragQueryFile(hdrop, n, NULL, 0) + 1;
1296 
1297         UINT len2 = ::DragQueryFile(hdrop, n, wxStringBuffer(str, len), len);
1298         m_filenames.Add(str);
1299 
1300         if ( len2 != len - 1 ) {
1301             wxLogDebug(wxT("In wxFileDropTarget::OnDrop DragQueryFile returned\
1302  %d characters, %d expected."), len2, len - 1);
1303         }
1304     }
1305 
1306     return true;
1307 #else
1308     return false;
1309 #endif
1310 }
1311 
AddFile(const wxString & file)1312 void wxFileDataObject::AddFile(const wxString& file)
1313 {
1314     // just add file to filenames array
1315     // all useful data (such as DROPFILES struct) will be
1316     // created later as necessary
1317     m_filenames.Add(file);
1318 }
1319 
GetDataSize() const1320 size_t wxFileDataObject::GetDataSize() const
1321 {
1322 #ifndef __WXWINCE__
1323     // size returned will be the size of the DROPFILES structure, plus the list
1324     // of filesnames (null byte separated), plus a double null at the end
1325 
1326     // if no filenames in list, size is 0
1327     if ( m_filenames.empty() )
1328         return 0;
1329 
1330 #if wxUSE_UNICODE_MSLU
1331     size_t sizeOfChar;
1332     if ( wxGetOsVersion() == wxOS_WINDOWS_9X )
1333     {
1334         // Win9x always uses ANSI file names and MSLU doesn't help with this
1335         sizeOfChar = 1;
1336     }
1337     else
1338     {
1339         sizeOfChar = sizeof(wxChar);
1340     }
1341 #else // !wxUSE_UNICODE_MSLU
1342     static const size_t sizeOfChar = sizeof(wxChar);
1343 #endif // wxUSE_UNICODE_MSLU/!wxUSE_UNICODE_MSLU
1344 
1345     // initial size of DROPFILES struct + null byte
1346     size_t sz = sizeof(DROPFILES) + sizeOfChar;
1347 
1348     const size_t count = m_filenames.size();
1349     for ( size_t i = 0; i < count; i++ )
1350     {
1351         // add filename length plus null byte
1352         size_t len;
1353 #if wxUSE_UNICODE_MSLU
1354         if ( sizeOfChar == 1 )
1355             len = strlen(m_filenames[i].mb_str(*wxConvFileName));
1356         else
1357 #endif // wxUSE_UNICODE_MSLU
1358             len = m_filenames[i].length();
1359 
1360         sz += (len + 1) * sizeOfChar;
1361     }
1362 
1363     return sz;
1364 #else
1365     return 0;
1366 #endif
1367 }
1368 
GetDataHere(void * WXUNUSED_IN_WINCE (pData)) const1369 bool wxFileDataObject::GetDataHere(void *WXUNUSED_IN_WINCE(pData)) const
1370 {
1371 #ifndef __WXWINCE__
1372     // pData points to an externally allocated memory block
1373     // created using the size returned by GetDataSize()
1374 
1375     // if pData is NULL, or there are no files, return
1376     if ( !pData || m_filenames.empty() )
1377         return false;
1378 
1379     // convert data pointer to a DROPFILES struct pointer
1380     LPDROPFILES pDrop = (LPDROPFILES) pData;
1381 
1382     // initialize DROPFILES struct
1383     pDrop->pFiles = sizeof(DROPFILES);
1384     pDrop->fNC = FALSE;                 // not non-client coords
1385 #if wxUSE_UNICODE_MSLU
1386     pDrop->fWide = wxGetOsVersion() != wxOS_WINDOWS_9X ? TRUE : FALSE;
1387 #else
1388     pDrop->fWide = wxUSE_UNICODE;
1389 #endif
1390 
1391     const size_t sizeOfChar = pDrop->fWide ? sizeof(wchar_t) : 1;
1392 
1393     // set start of filenames list (null separated)
1394     BYTE *pbuf = (BYTE *)(pDrop + 1);
1395 
1396     const size_t count = m_filenames.size();
1397     for ( size_t i = 0; i < count; i++ )
1398     {
1399         // copy filename to pbuf and add null terminator
1400         size_t len;
1401 #if wxUSE_UNICODE_MSLU
1402         if ( sizeOfChar == 1 )
1403         {
1404             wxCharBuffer buf(m_filenames[i].mb_str(*wxConvFileName));
1405             len = strlen(buf);
1406             memcpy(pbuf, buf, len*sizeOfChar);
1407         }
1408         else
1409 #endif // wxUSE_UNICODE_MSLU
1410         {
1411             len = m_filenames[i].length();
1412             memcpy(pbuf, m_filenames[i].t_str(), len*sizeOfChar);
1413         }
1414 
1415         pbuf += len*sizeOfChar;
1416 
1417         memset(pbuf, 0, sizeOfChar);
1418         pbuf += sizeOfChar;
1419     }
1420 
1421     // add final null terminator
1422     memset(pbuf, 0, sizeOfChar);
1423 
1424     return true;
1425 #else
1426     return false;
1427 #endif
1428 }
1429 
1430 // ----------------------------------------------------------------------------
1431 // wxURLDataObject
1432 // ----------------------------------------------------------------------------
1433 
1434 // Work around bug in Wine headers
1435 #if defined(__WINE__) && defined(CFSTR_SHELLURL) && wxUSE_UNICODE
1436 #undef CFSTR_SHELLURL
1437 #define CFSTR_SHELLURL wxT("CFSTR_SHELLURL")
1438 #endif
1439 
1440 class CFSTR_SHELLURLDataObject : public wxCustomDataObject
1441 {
1442 public:
CFSTR_SHELLURLDataObject()1443     CFSTR_SHELLURLDataObject() : wxCustomDataObject(CFSTR_SHELLURL) {}
1444 
GetBufferOffset(const wxDataFormat & WXUNUSED (format))1445     virtual size_t GetBufferOffset( const wxDataFormat& WXUNUSED(format) )
1446     {
1447         return 0;
1448     }
1449 
GetSizeFromBuffer(const void * buffer,size_t * size,const wxDataFormat & WXUNUSED (format))1450     virtual const void* GetSizeFromBuffer( const void* buffer, size_t* size,
1451                                            const wxDataFormat& WXUNUSED(format) )
1452     {
1453         // CFSTR_SHELLURL is _always_ ANSI text
1454         *size = strlen( (const char*)buffer );
1455 
1456         return buffer;
1457     }
1458 
SetSizeInBuffer(void * buffer,size_t WXUNUSED (size),const wxDataFormat & WXUNUSED (format))1459     virtual void* SetSizeInBuffer( void* buffer, size_t WXUNUSED(size),
1460                                    const wxDataFormat& WXUNUSED(format) )
1461     {
1462         return buffer;
1463     }
1464 
1465     wxDECLARE_NO_COPY_CLASS(CFSTR_SHELLURLDataObject);
1466 };
1467 
1468 
1469 
wxURLDataObject(const wxString & url)1470 wxURLDataObject::wxURLDataObject(const wxString& url)
1471 {
1472     // we support CF_TEXT and CFSTR_SHELLURL formats which are basically the
1473     // same but it seems that some browsers only provide one of them so we have
1474     // to support both
1475     Add(new wxTextDataObject);
1476     Add(new CFSTR_SHELLURLDataObject());
1477 
1478     // we don't have any data yet
1479     m_dataObjectLast = NULL;
1480 
1481     if ( !url.empty() )
1482         SetURL(url);
1483 }
1484 
SetData(const wxDataFormat & format,size_t len,const void * buf)1485 bool wxURLDataObject::SetData(const wxDataFormat& format,
1486                               size_t len,
1487                               const void *buf)
1488 {
1489     m_dataObjectLast = GetObject(format);
1490 
1491     wxCHECK_MSG( m_dataObjectLast, FALSE,
1492                  wxT("unsupported format in wxURLDataObject"));
1493 
1494     return m_dataObjectLast->SetData(len, buf);
1495 }
1496 
GetURL() const1497 wxString wxURLDataObject::GetURL() const
1498 {
1499     wxString url;
1500     wxCHECK_MSG( m_dataObjectLast, url, wxT("no data in wxURLDataObject") );
1501 
1502     if ( m_dataObjectLast->GetPreferredFormat() == CFSTR_SHELLURL )
1503     {
1504         const size_t len = m_dataObjectLast->GetDataSize();
1505         if ( !len )
1506             return wxString();
1507 
1508         // CFSTR_SHELLURL is always ANSI so we need to convert it from it in
1509         // Unicode build
1510 #if wxUSE_UNICODE
1511         wxCharBuffer buf(len);
1512 
1513         if ( m_dataObjectLast->GetDataHere(buf.data()) )
1514             url = buf;
1515 #else // !wxUSE_UNICODE
1516         // in ANSI build no conversion is necessary
1517         m_dataObjectLast->GetDataHere(wxStringBuffer(url, len));
1518 #endif // wxUSE_UNICODE/!wxUSE_UNICODE
1519     }
1520     else // must be wxTextDataObject
1521     {
1522         url = static_cast<wxTextDataObject *>(m_dataObjectLast)->GetText();
1523     }
1524 
1525     return url;
1526 }
1527 
SetURL(const wxString & url)1528 void wxURLDataObject::SetURL(const wxString& url)
1529 {
1530     wxCharBuffer urlMB(url.mb_str());
1531     if ( urlMB )
1532     {
1533         const size_t len = strlen(urlMB);
1534 
1535 #if !wxUSE_UNICODE
1536         // wxTextDataObject takes the number of characters in the string, not
1537         // the size of the buffer (which would be len+1)
1538         SetData(wxDF_TEXT, len, urlMB);
1539 #endif // !wxUSE_UNICODE
1540 
1541         // however CFSTR_SHELLURLDataObject doesn't append NUL automatically
1542         // but we probably still want to have it on the clipboard (just to be
1543         // safe), so do append it
1544         SetData(wxDataFormat(CFSTR_SHELLURL), len + 1, urlMB);
1545     }
1546 
1547 #if wxUSE_UNICODE
1548     SetData(wxDF_UNICODETEXT, url.length()*sizeof(wxChar), url.wc_str());
1549 #endif
1550 }
1551 
1552 // ----------------------------------------------------------------------------
1553 // private functions
1554 // ----------------------------------------------------------------------------
1555 
1556 #if wxDEBUG_LEVEL
1557 
GetTymedName(DWORD tymed)1558 static const wxChar *GetTymedName(DWORD tymed)
1559 {
1560     static wxChar s_szBuf[128];
1561     switch ( tymed ) {
1562         case TYMED_HGLOBAL:   return wxT("TYMED_HGLOBAL");
1563         case TYMED_FILE:      return wxT("TYMED_FILE");
1564         case TYMED_ISTREAM:   return wxT("TYMED_ISTREAM");
1565         case TYMED_ISTORAGE:  return wxT("TYMED_ISTORAGE");
1566         case TYMED_GDI:       return wxT("TYMED_GDI");
1567         case TYMED_MFPICT:    return wxT("TYMED_MFPICT");
1568         case TYMED_ENHMF:     return wxT("TYMED_ENHMF");
1569         default:
1570             wxSprintf(s_szBuf, wxT("type of media format %ld (unknown)"), tymed);
1571             return s_szBuf;
1572     }
1573 }
1574 
1575 #endif // Debug
1576 
1577 #else // not using OLE at all
1578 
1579 // ----------------------------------------------------------------------------
1580 // wxDataObject
1581 // ----------------------------------------------------------------------------
1582 
1583 #if wxUSE_DATAOBJ
1584 
wxDataObject()1585 wxDataObject::wxDataObject()
1586 {
1587 }
1588 
~wxDataObject()1589 wxDataObject::~wxDataObject()
1590 {
1591 }
1592 
SetAutoDelete()1593 void wxDataObject::SetAutoDelete()
1594 {
1595 }
1596 
GetFormatName(wxDataFormat WXUNUSED (format))1597 const wxChar *wxDataObject::GetFormatName(wxDataFormat WXUNUSED(format))
1598 {
1599     return NULL;
1600 }
1601 
1602 #endif // wxUSE_DATAOBJ
1603 
1604 #endif // wxUSE_OLE/!wxUSE_OLE
1605 
1606 
1607