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