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