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