]> git.saurik.com Git - wxWidgets.git/blob - src/msw/ole/dataobj.cpp
48e999239ac263727661a26fec9d9be1a4c6cd36
[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 wxChar *format)
141 {
142 m_format = (wxDataFormat::NativeFormat)::RegisterClipboardFormat(format);
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, size_t* size,
690 const wxDataFormat& format )
691 {
692 // hack: the third parameter is declared non-const in Wine's headers so
693 // cast away the const
694 size_t realsz = ::HeapSize(::GetProcessHeap(), 0,
695 wx_const_cast(void*, buffer));
696 if ( realsz == (size_t)-1 )
697 {
698 // note that HeapSize() does not set last error
699 wxLogApiError(wxT("HeapSize"), 0);
700 return NULL;
701 }
702
703 *size = realsz;
704
705 // check if this data has its size prepended (as it was by default for wx
706 // programs prior 2.6.3):
707 size_t *p = (size_t *)buffer;
708 if ( *p == realsz )
709 {
710 if ( NeedsVerbatimData(format) )
711 wxLogDebug(wxT("Apparent data format mismatch: size not needed"));
712
713 p++; // this data has its size prepended; skip first DWORD
714 }
715
716 return p;
717 }
718
719 void* wxDataObject::SetSizeInBuffer( void* buffer, size_t size,
720 const wxDataFormat& format )
721 {
722 size_t* p = (size_t *)buffer;
723 if ( !NeedsVerbatimData(format) )
724 {
725 // prepend the size to the data and skip it
726 *p++ = size;
727 }
728
729 return p;
730 }
731
732 #ifdef __WXDEBUG__
733
734 const wxChar *wxDataObject::GetFormatName(wxDataFormat format)
735 {
736 // case 'xxx' is not a valid value for switch of enum 'wxDataFormat'
737 #ifdef __VISUALC__
738 #pragma warning(disable:4063)
739 #endif // VC++
740
741 static wxChar s_szBuf[256];
742 switch ( format ) {
743 case CF_TEXT: return wxT("CF_TEXT");
744 case CF_BITMAP: return wxT("CF_BITMAP");
745 case CF_SYLK: return wxT("CF_SYLK");
746 case CF_DIF: return wxT("CF_DIF");
747 case CF_TIFF: return wxT("CF_TIFF");
748 case CF_OEMTEXT: return wxT("CF_OEMTEXT");
749 case CF_DIB: return wxT("CF_DIB");
750 case CF_PALETTE: return wxT("CF_PALETTE");
751 case CF_PENDATA: return wxT("CF_PENDATA");
752 case CF_RIFF: return wxT("CF_RIFF");
753 case CF_WAVE: return wxT("CF_WAVE");
754 case CF_UNICODETEXT: return wxT("CF_UNICODETEXT");
755 #ifndef __WXWINCE__
756 case CF_METAFILEPICT: return wxT("CF_METAFILEPICT");
757 case CF_ENHMETAFILE: return wxT("CF_ENHMETAFILE");
758 case CF_LOCALE: return wxT("CF_LOCALE");
759 case CF_HDROP: return wxT("CF_HDROP");
760 #endif
761
762 default:
763 if ( !::GetClipboardFormatName(format, s_szBuf, WXSIZEOF(s_szBuf)) )
764 {
765 // it must be a new predefined format we don't know the name of
766 wxSprintf(s_szBuf, wxT("unknown CF (0x%04x)"), format.GetFormatId());
767 }
768
769 return s_szBuf;
770 }
771
772 #ifdef __VISUALC__
773 #pragma warning(default:4063)
774 #endif // VC++
775 }
776
777 #endif // Debug
778
779 // ----------------------------------------------------------------------------
780 // wxBitmapDataObject supports CF_DIB format
781 // ----------------------------------------------------------------------------
782
783 // TODO: support CF_DIB under Windows CE as well
784
785 size_t wxBitmapDataObject::GetDataSize() const
786 {
787 #if wxUSE_WXDIB && !defined(__WXWINCE__)
788 return wxDIB::ConvertFromBitmap(NULL, GetHbitmapOf(GetBitmap()));
789 #else
790 return 0;
791 #endif
792 }
793
794 bool wxBitmapDataObject::GetDataHere(void *buf) const
795 {
796 #if wxUSE_WXDIB && !defined(__WXWINCE__)
797 BITMAPINFO * const pbi = (BITMAPINFO *)buf;
798
799 return wxDIB::ConvertFromBitmap(pbi, GetHbitmapOf(GetBitmap())) != 0;
800 #else
801 wxUnusedVar(buf);
802 return false;
803 #endif
804 }
805
806 bool wxBitmapDataObject::SetData(size_t WXUNUSED(len), const void *buf)
807 {
808 #if wxUSE_WXDIB && !defined(__WXWINCE__)
809 const BITMAPINFO * const pbmi = (const BITMAPINFO *)buf;
810
811 HBITMAP hbmp = wxDIB::ConvertToBitmap(pbmi);
812
813 wxCHECK_MSG( hbmp, FALSE, wxT("pasting/dropping invalid bitmap") );
814
815 const BITMAPINFOHEADER * const pbmih = &pbmi->bmiHeader;
816 wxBitmap bitmap(pbmih->biWidth, pbmih->biHeight, pbmih->biBitCount);
817 bitmap.SetHBITMAP((WXHBITMAP)hbmp);
818
819 // TODO: create wxPalette if the bitmap has any
820
821 SetBitmap(bitmap);
822
823 return true;
824 #else
825 wxUnusedVar(buf);
826 return false;
827 #endif
828 }
829
830 // ----------------------------------------------------------------------------
831 // wxBitmapDataObject2 supports CF_BITMAP format
832 // ----------------------------------------------------------------------------
833
834 // the bitmaps aren't passed by value as other types of data (i.e. by copying
835 // the data into a global memory chunk and passing it to the clipboard or
836 // another application or whatever), but by handle, so these generic functions
837 // don't make much sense to them.
838
839 size_t wxBitmapDataObject2::GetDataSize() const
840 {
841 return 0;
842 }
843
844 bool wxBitmapDataObject2::GetDataHere(void *pBuf) const
845 {
846 // we put a bitmap handle into pBuf
847 *(WXHBITMAP *)pBuf = GetBitmap().GetHBITMAP();
848
849 return true;
850 }
851
852 bool wxBitmapDataObject2::SetData(size_t WXUNUSED(len), const void *pBuf)
853 {
854 HBITMAP hbmp = *(HBITMAP *)pBuf;
855
856 BITMAP bmp;
857 if ( !GetObject(hbmp, sizeof(BITMAP), &bmp) )
858 {
859 wxLogLastError(wxT("GetObject(HBITMAP)"));
860 }
861
862 wxBitmap bitmap(bmp.bmWidth, bmp.bmHeight, bmp.bmPlanes);
863 bitmap.SetHBITMAP((WXHBITMAP)hbmp);
864
865 if ( !bitmap.Ok() ) {
866 wxFAIL_MSG(wxT("pasting/dropping invalid bitmap"));
867
868 return false;
869 }
870
871 SetBitmap(bitmap);
872
873 return true;
874 }
875
876 #if 0
877
878 size_t wxBitmapDataObject::GetDataSize(const wxDataFormat& format) const
879 {
880 if ( format.GetFormatId() == CF_DIB )
881 {
882 // create the DIB
883 ScreenHDC hdc;
884
885 // shouldn't be selected into a DC or GetDIBits() would fail
886 wxASSERT_MSG( !m_bitmap.GetSelectedInto(),
887 wxT("can't copy bitmap selected into wxMemoryDC") );
888
889 // first get the info
890 BITMAPINFO bi;
891 if ( !GetDIBits(hdc, (HBITMAP)m_bitmap.GetHBITMAP(), 0, 0,
892 NULL, &bi, DIB_RGB_COLORS) )
893 {
894 wxLogLastError(wxT("GetDIBits(NULL)"));
895
896 return 0;
897 }
898
899 return sizeof(BITMAPINFO) + bi.bmiHeader.biSizeImage;
900 }
901 else // CF_BITMAP
902 {
903 // no data to copy - we don't pass HBITMAP via global memory
904 return 0;
905 }
906 }
907
908 bool wxBitmapDataObject::GetDataHere(const wxDataFormat& format,
909 void *pBuf) const
910 {
911 wxASSERT_MSG( m_bitmap.Ok(), wxT("copying invalid bitmap") );
912
913 HBITMAP hbmp = (HBITMAP)m_bitmap.GetHBITMAP();
914 if ( format.GetFormatId() == CF_DIB )
915 {
916 // create the DIB
917 ScreenHDC hdc;
918
919 // shouldn't be selected into a DC or GetDIBits() would fail
920 wxASSERT_MSG( !m_bitmap.GetSelectedInto(),
921 wxT("can't copy bitmap selected into wxMemoryDC") );
922
923 // first get the info
924 BITMAPINFO *pbi = (BITMAPINFO *)pBuf;
925 if ( !GetDIBits(hdc, hbmp, 0, 0, NULL, pbi, DIB_RGB_COLORS) )
926 {
927 wxLogLastError(wxT("GetDIBits(NULL)"));
928
929 return 0;
930 }
931
932 // and now copy the bits
933 if ( !GetDIBits(hdc, hbmp, 0, pbi->bmiHeader.biHeight, pbi + 1,
934 pbi, DIB_RGB_COLORS) )
935 {
936 wxLogLastError(wxT("GetDIBits"));
937
938 return false;
939 }
940 }
941 else // CF_BITMAP
942 {
943 // we put a bitmap handle into pBuf
944 *(HBITMAP *)pBuf = hbmp;
945 }
946
947 return true;
948 }
949
950 bool wxBitmapDataObject::SetData(const wxDataFormat& format,
951 size_t size, const void *pBuf)
952 {
953 HBITMAP hbmp;
954 if ( format.GetFormatId() == CF_DIB )
955 {
956 // here we get BITMAPINFO struct followed by the actual bitmap bits and
957 // BITMAPINFO starts with BITMAPINFOHEADER followed by colour info
958 ScreenHDC hdc;
959
960 BITMAPINFO *pbmi = (BITMAPINFO *)pBuf;
961 BITMAPINFOHEADER *pbmih = &pbmi->bmiHeader;
962 hbmp = CreateDIBitmap(hdc, pbmih, CBM_INIT,
963 pbmi + 1, pbmi, DIB_RGB_COLORS);
964 if ( !hbmp )
965 {
966 wxLogLastError(wxT("CreateDIBitmap"));
967 }
968
969 m_bitmap.SetWidth(pbmih->biWidth);
970 m_bitmap.SetHeight(pbmih->biHeight);
971 }
972 else // CF_BITMAP
973 {
974 // it's easy with bitmaps: we pass them by handle
975 hbmp = *(HBITMAP *)pBuf;
976
977 BITMAP bmp;
978 if ( !GetObject(hbmp, sizeof(BITMAP), &bmp) )
979 {
980 wxLogLastError(wxT("GetObject(HBITMAP)"));
981 }
982
983 m_bitmap.SetWidth(bmp.bmWidth);
984 m_bitmap.SetHeight(bmp.bmHeight);
985 m_bitmap.SetDepth(bmp.bmPlanes);
986 }
987
988 m_bitmap.SetHBITMAP((WXHBITMAP)hbmp);
989
990 wxASSERT_MSG( m_bitmap.Ok(), wxT("pasting invalid bitmap") );
991
992 return true;
993 }
994
995 #endif // 0
996
997 // ----------------------------------------------------------------------------
998 // wxFileDataObject
999 // ----------------------------------------------------------------------------
1000
1001 bool wxFileDataObject::SetData(size_t WXUNUSED(size),
1002 const void *WXUNUSED_IN_WINCE(pData))
1003 {
1004 #ifndef __WXWINCE__
1005 m_filenames.Empty();
1006
1007 // the documentation states that the first member of DROPFILES structure is
1008 // a "DWORD offset of double NUL terminated file list". What they mean by
1009 // this (I wonder if you see it immediately) is that the list starts at
1010 // ((char *)&(pDropFiles.pFiles)) + pDropFiles.pFiles. We're also advised
1011 // to use DragQueryFile to work with this structure, but not told where and
1012 // how to get HDROP.
1013 HDROP hdrop = (HDROP)pData; // NB: it works, but I'm not sure about it
1014
1015 // get number of files (magic value -1)
1016 UINT nFiles = ::DragQueryFile(hdrop, (unsigned)-1, NULL, 0u);
1017
1018 wxCHECK_MSG ( nFiles != (UINT)-1, FALSE, wxT("wrong HDROP handle") );
1019
1020 // for each file get the length, allocate memory and then get the name
1021 wxString str;
1022 UINT len, n;
1023 for ( n = 0; n < nFiles; n++ ) {
1024 // +1 for terminating NUL
1025 len = ::DragQueryFile(hdrop, n, NULL, 0) + 1;
1026
1027 UINT len2 = ::DragQueryFile(hdrop, n, wxStringBuffer(str, len), len);
1028 m_filenames.Add(str);
1029
1030 if ( len2 != len - 1 ) {
1031 wxLogDebug(wxT("In wxFileDropTarget::OnDrop DragQueryFile returned\
1032 %d characters, %d expected."), len2, len - 1);
1033 }
1034 }
1035
1036 return true;
1037 #else
1038 return false;
1039 #endif
1040 }
1041
1042 void wxFileDataObject::AddFile(const wxString& file)
1043 {
1044 // just add file to filenames array
1045 // all useful data (such as DROPFILES struct) will be
1046 // created later as necessary
1047 m_filenames.Add(file);
1048 }
1049
1050 size_t wxFileDataObject::GetDataSize() const
1051 {
1052 #ifndef __WXWINCE__
1053 // size returned will be the size of the DROPFILES structure, plus the list
1054 // of filesnames (null byte separated), plus a double null at the end
1055
1056 // if no filenames in list, size is 0
1057 if ( m_filenames.empty() )
1058 return 0;
1059
1060 #if wxUSE_UNICODE_MSLU
1061 size_t sizeOfChar;
1062 if ( wxGetOsVersion() == wxOS_WINDOWS_9X )
1063 {
1064 // Win9x always uses ANSI file names and MSLU doesn't help with this
1065 sizeOfChar = sizeof(char);
1066 }
1067 else
1068 {
1069 sizeOfChar = sizeof(wxChar);
1070 }
1071 #else // !wxUSE_UNICODE_MSLU
1072 static const size_t sizeOfChar = sizeof(wxChar);
1073 #endif // wxUSE_UNICODE_MSLU/!wxUSE_UNICODE_MSLU
1074
1075 // inital size of DROPFILES struct + null byte
1076 size_t sz = sizeof(DROPFILES) + sizeOfChar;
1077
1078 const size_t count = m_filenames.size();
1079 for ( size_t i = 0; i < count; i++ )
1080 {
1081 // add filename length plus null byte
1082 size_t len;
1083 #if wxUSE_UNICODE_MSLU
1084 if ( sizeOfChar == sizeof(char) )
1085 len = strlen(wxConvFileName->cWC2MB(m_filenames[i]));
1086 else
1087 #endif // wxUSE_UNICODE_MSLU
1088 len = m_filenames[i].length();
1089
1090 sz += (len + 1) * sizeOfChar;
1091 }
1092
1093 return sz;
1094 #else
1095 return 0;
1096 #endif
1097 }
1098
1099 bool wxFileDataObject::GetDataHere(void *WXUNUSED_IN_WINCE(pData)) const
1100 {
1101 #ifndef __WXWINCE__
1102 // pData points to an externally allocated memory block
1103 // created using the size returned by GetDataSize()
1104
1105 // if pData is NULL, or there are no files, return
1106 if ( !pData || m_filenames.empty() )
1107 return false;
1108
1109 // convert data pointer to a DROPFILES struct pointer
1110 LPDROPFILES pDrop = (LPDROPFILES) pData;
1111
1112 // initialize DROPFILES struct
1113 pDrop->pFiles = sizeof(DROPFILES);
1114 pDrop->fNC = FALSE; // not non-client coords
1115 #if wxUSE_UNICODE_MSLU
1116 pDrop->fWide = wxGetOsVersion() != wxOS_WINDOWS_9X ? TRUE : FALSE;
1117 #else
1118 pDrop->fWide = wxUSE_UNICODE;
1119 #endif
1120
1121 const size_t sizeOfChar = pDrop->fWide ? sizeof(wchar_t) : sizeof(char);
1122
1123 // set start of filenames list (null separated)
1124 BYTE *pbuf = (BYTE *)(pDrop + 1);
1125
1126 const size_t count = m_filenames.size();
1127 for ( size_t i = 0; i < count; i++ )
1128 {
1129 // copy filename to pbuf and add null terminator
1130 size_t len;
1131 #if wxUSE_UNICODE_MSLU
1132 if ( sizeOfChar == sizeof(char) )
1133 {
1134 wxCharBuffer buf(wxConvFileName->cWC2MB(m_filenames[i]));
1135 len = strlen(buf);
1136 memcpy(pbuf, buf, len*sizeOfChar);
1137 }
1138 else
1139 #endif // wxUSE_UNICODE_MSLU
1140 {
1141 len = m_filenames[i].length();
1142 memcpy(pbuf, m_filenames[i].c_str(), len*sizeOfChar);
1143 }
1144
1145 pbuf += len*sizeOfChar;
1146
1147 memset(pbuf, 0, sizeOfChar);
1148 pbuf += sizeOfChar;
1149 }
1150
1151 // add final null terminator
1152 memset(pbuf, 0, sizeOfChar);
1153
1154 return true;
1155 #else
1156 return false;
1157 #endif
1158 }
1159
1160 // ----------------------------------------------------------------------------
1161 // wxURLDataObject
1162 // ----------------------------------------------------------------------------
1163
1164 // Work around bug in Wine headers
1165 #if defined(__WINE__) && defined(CFSTR_SHELLURL) && wxUSE_UNICODE
1166 #undef CFSTR_SHELLURL
1167 #define CFSTR_SHELLURL _T("CFSTR_SHELLURL")
1168 #endif
1169
1170 class CFSTR_SHELLURLDataObject : public wxCustomDataObject
1171 {
1172 public:
1173 CFSTR_SHELLURLDataObject() : wxCustomDataObject(CFSTR_SHELLURL) {}
1174
1175 virtual size_t GetBufferOffset( const wxDataFormat& WXUNUSED(format) )
1176 {
1177 return 0;
1178 }
1179
1180 virtual const void* GetSizeFromBuffer( const void* buffer, size_t* size,
1181 const wxDataFormat& WXUNUSED(format) )
1182 {
1183 // CFSTR_SHELLURL is _always_ ANSI text
1184 *size = strlen( (const char*)buffer );
1185
1186 return buffer;
1187 }
1188
1189 virtual void* SetSizeInBuffer( void* buffer, size_t WXUNUSED(size),
1190 const wxDataFormat& WXUNUSED(format) )
1191 {
1192 return buffer;
1193 }
1194
1195 #if wxUSE_UNICODE
1196 virtual bool GetDataHere( void* buffer ) const
1197 {
1198 // CFSTR_SHELLURL is _always_ ANSI!
1199 wxCharBuffer char_buffer( GetDataSize() );
1200 wxCustomDataObject::GetDataHere( (void*)char_buffer.data() );
1201 wxString unicode_buffer( char_buffer, wxConvLibc );
1202 memcpy( buffer, unicode_buffer.c_str(),
1203 ( unicode_buffer.length() + 1 ) * sizeof(wxChar) );
1204
1205 return true;
1206 }
1207 virtual bool GetDataHere(const wxDataFormat& WXUNUSED(format),
1208 void *buf) const
1209 { return GetDataHere(buf); }
1210 #endif
1211
1212 DECLARE_NO_COPY_CLASS(CFSTR_SHELLURLDataObject)
1213 };
1214
1215
1216
1217 wxURLDataObject::wxURLDataObject(const wxString& url)
1218 {
1219 // we support CF_TEXT and CFSTR_SHELLURL formats which are basicly the same
1220 // but it seems that some browsers only provide one of them so we have to
1221 // support both
1222 Add(new wxTextDataObject);
1223 Add(new CFSTR_SHELLURLDataObject());
1224
1225 // we don't have any data yet
1226 m_dataObjectLast = NULL;
1227
1228 if ( !url.empty() )
1229 SetURL(url);
1230 }
1231
1232 bool wxURLDataObject::SetData(const wxDataFormat& format,
1233 size_t len,
1234 const void *buf)
1235 {
1236 m_dataObjectLast = GetObject(format);
1237
1238 wxCHECK_MSG( m_dataObjectLast, FALSE,
1239 wxT("unsupported format in wxURLDataObject"));
1240
1241 return m_dataObjectLast->SetData(len, buf);
1242 }
1243
1244 wxString wxURLDataObject::GetURL() const
1245 {
1246 wxString url;
1247 wxCHECK_MSG( m_dataObjectLast, url, _T("no data in wxURLDataObject") );
1248
1249 size_t len = m_dataObjectLast->GetDataSize();
1250
1251 m_dataObjectLast->GetDataHere(wxStringBuffer(url, len));
1252
1253 return url;
1254 }
1255
1256 void wxURLDataObject::SetURL(const wxString& url)
1257 {
1258 SetData(wxDataFormat(wxUSE_UNICODE ? wxDF_UNICODETEXT : wxDF_TEXT),
1259 url.Length()+1, url.c_str());
1260
1261 // CFSTR_SHELLURL is always supposed to be ANSI...
1262 wxWX2MBbuf urlA = (wxWX2MBbuf)url.mbc_str();
1263 size_t len = strlen(urlA);
1264 SetData(wxDataFormat(CFSTR_SHELLURL), len+1, (const char*)urlA);
1265 }
1266
1267 // ----------------------------------------------------------------------------
1268 // private functions
1269 // ----------------------------------------------------------------------------
1270
1271 #ifdef __WXDEBUG__
1272
1273 static const wxChar *GetTymedName(DWORD tymed)
1274 {
1275 static wxChar s_szBuf[128];
1276 switch ( tymed ) {
1277 case TYMED_HGLOBAL: return wxT("TYMED_HGLOBAL");
1278 case TYMED_FILE: return wxT("TYMED_FILE");
1279 case TYMED_ISTREAM: return wxT("TYMED_ISTREAM");
1280 case TYMED_ISTORAGE: return wxT("TYMED_ISTORAGE");
1281 case TYMED_GDI: return wxT("TYMED_GDI");
1282 case TYMED_MFPICT: return wxT("TYMED_MFPICT");
1283 case TYMED_ENHMF: return wxT("TYMED_ENHMF");
1284 default:
1285 wxSprintf(s_szBuf, wxT("type of media format %ld (unknown)"), tymed);
1286 return s_szBuf;
1287 }
1288 }
1289
1290 #endif // Debug
1291
1292 #else // not using OLE at all
1293
1294 // ----------------------------------------------------------------------------
1295 // wxDataObject
1296 // ----------------------------------------------------------------------------
1297
1298 #if wxUSE_DATAOBJ
1299
1300 wxDataObject::wxDataObject()
1301 {
1302 }
1303
1304 wxDataObject::~wxDataObject()
1305 {
1306 }
1307
1308 void wxDataObject::SetAutoDelete()
1309 {
1310 }
1311
1312 #ifdef __WXDEBUG__
1313 const wxChar *wxDataObject::GetFormatName(wxDataFormat WXUNUSED(format))
1314 {
1315 return NULL;
1316 }
1317 #endif // __WXDEBUG__
1318
1319 #endif // wxUSE_DATAOBJ
1320
1321 #endif // wxUSE_OLE/!wxUSE_OLE
1322
1323