]> git.saurik.com Git - wxWidgets.git/blob - src/msw/ole/dataobj.cpp
14ae6ed6a880334eb1101f26f169ffa63e1e0166
[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 license
10 ///////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 #ifdef __GNUG__
21 #pragma implementation "dataobj.h"
22 #endif
23
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
26
27 #if defined(__BORLANDC__)
28 #pragma hdrstop
29 #endif
30 #ifndef WX_PRECOMP
31 #include "wx/intl.h"
32 #endif
33 #include "wx/defs.h"
34
35 #if defined(__WIN32__) && !defined(__GNUWIN32__) || defined(wxUSE_NORLANDER_HEADERS)
36
37 #include "wx/log.h"
38 #include "wx/dataobj.h"
39
40 #include <windows.h>
41 #ifdef wxUSE_NORLANDER_HEADERS
42 #include <ole2.h>
43 #endif
44 #include <oleauto.h>
45
46 #ifndef __WIN32__
47 #include <ole2.h>
48 #include <olestd.h>
49 #endif
50
51 #include "wx/msw/ole/oleutils.h"
52
53 // ----------------------------------------------------------------------------
54 // functions
55 // ----------------------------------------------------------------------------
56
57 #ifdef __WXDEBUG__
58 static const wxChar *GetTymedName(DWORD tymed);
59 #endif // Debug
60
61 // ----------------------------------------------------------------------------
62 // wxIEnumFORMATETC interface implementation
63 // ----------------------------------------------------------------------------
64
65 class wxIEnumFORMATETC : public IEnumFORMATETC
66 {
67 public:
68 wxIEnumFORMATETC(const wxDataFormat* formats, ULONG nCount);
69 ~wxIEnumFORMATETC() { delete [] m_formats; }
70
71 DECLARE_IUNKNOWN_METHODS;
72
73 // IEnumFORMATETC
74 STDMETHODIMP Next(ULONG celt, FORMATETC *rgelt, ULONG *pceltFetched);
75 STDMETHODIMP Skip(ULONG celt);
76 STDMETHODIMP Reset();
77 STDMETHODIMP Clone(IEnumFORMATETC **ppenum);
78
79 private:
80 CLIPFORMAT *m_formats; // formats we can provide data in
81 ULONG m_nCount, // number of formats we support
82 m_nCurrent; // current enum position
83 };
84
85 // ----------------------------------------------------------------------------
86 // wxIDataObject implementation of IDataObject interface
87 // ----------------------------------------------------------------------------
88
89 class wxIDataObject : public IDataObject
90 {
91 public:
92 wxIDataObject(wxDataObject *pDataObject);
93 ~wxIDataObject();
94
95 // normally, wxDataObject controls our lifetime (i.e. we're deleted when it
96 // is), but in some cases, the situation is inversed, that is we delete it
97 // when this object is deleted - setting this flag enables such logic
98 void SetDeleteFlag() { m_mustDelete = TRUE; }
99
100 DECLARE_IUNKNOWN_METHODS;
101
102 // IDataObject
103 STDMETHODIMP GetData(FORMATETC *pformatetcIn, STGMEDIUM *pmedium);
104 STDMETHODIMP GetDataHere(FORMATETC *pformatetc, STGMEDIUM *pmedium);
105 STDMETHODIMP QueryGetData(FORMATETC *pformatetc);
106 STDMETHODIMP GetCanonicalFormatEtc(FORMATETC *In, FORMATETC *pOut);
107 STDMETHODIMP SetData(FORMATETC *pfetc, STGMEDIUM *pmedium, BOOL fRelease);
108 STDMETHODIMP EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC **ppenumFEtc);
109 STDMETHODIMP DAdvise(FORMATETC *pfetc, DWORD ad, IAdviseSink *p, DWORD *pdw);
110 STDMETHODIMP DUnadvise(DWORD dwConnection);
111 STDMETHODIMP EnumDAdvise(IEnumSTATDATA **ppenumAdvise);
112
113 private:
114 wxDataObject *m_pDataObject; // pointer to C++ class we belong to
115
116 bool m_mustDelete;
117 };
118
119 // ----------------------------------------------------------------------------
120 // small helper class for getting screen DC (we're working with bitmaps and
121 // DIBs here)
122 // ----------------------------------------------------------------------------
123
124 class ScreenHDC
125 {
126 public:
127 ScreenHDC() { m_hdc = GetDC(NULL); }
128 ~ScreenHDC() { ReleaseDC(NULL, m_hdc); }
129 operator HDC() const { return m_hdc; }
130
131 private:
132 HDC m_hdc;
133 };
134
135 // ============================================================================
136 // implementation
137 // ============================================================================
138
139 // ----------------------------------------------------------------------------
140 // wxDataFormat
141 // ----------------------------------------------------------------------------
142
143 void wxDataFormat::SetId(const wxChar *format)
144 {
145 m_format = ::RegisterClipboardFormat(format);
146 if ( !m_format )
147 {
148 wxLogError(_("Couldn't register clipboard format '%s'."), format);
149 }
150 }
151
152 wxString wxDataFormat::GetId() const
153 {
154 static const int max = 256;
155
156 wxString s;
157
158 wxCHECK_MSG( !IsStandard(), s,
159 wxT("name of predefined format cannot be retrieved") );
160
161 int len = ::GetClipboardFormatName(m_format, s.GetWriteBuf(max), max);
162 s.UngetWriteBuf();
163
164 if ( !len )
165 {
166 wxLogError(_("The clipboard format '%d' doesn't exist."), m_format);
167 }
168
169 return s;
170 }
171
172 // ----------------------------------------------------------------------------
173 // wxIEnumFORMATETC
174 // ----------------------------------------------------------------------------
175
176 BEGIN_IID_TABLE(wxIEnumFORMATETC)
177 ADD_IID(Unknown)
178 ADD_IID(EnumFORMATETC)
179 END_IID_TABLE;
180
181 IMPLEMENT_IUNKNOWN_METHODS(wxIEnumFORMATETC)
182
183 wxIEnumFORMATETC::wxIEnumFORMATETC(const wxDataFormat *formats, ULONG nCount)
184 {
185 m_cRef = 0;
186 m_nCurrent = 0;
187 m_nCount = nCount;
188 m_formats = new CLIPFORMAT[nCount];
189 for ( ULONG n = 0; n < nCount; n++ ) {
190 m_formats[n] = formats[n].GetFormatId();
191 }
192 }
193
194 STDMETHODIMP wxIEnumFORMATETC::Next(ULONG celt,
195 FORMATETC *rgelt,
196 ULONG *pceltFetched)
197 {
198 wxLogTrace(wxTRACE_OleCalls, wxT("wxIEnumFORMATETC::Next"));
199
200 if ( celt > 1 ) {
201 // we only return 1 element at a time - mainly because I'm too lazy to
202 // implement something which you're never asked for anyhow
203 return S_FALSE;
204 }
205
206 if ( m_nCurrent < m_nCount ) {
207 FORMATETC format;
208 format.cfFormat = m_formats[m_nCurrent++];
209 format.ptd = NULL;
210 format.dwAspect = DVASPECT_CONTENT;
211 format.lindex = -1;
212 format.tymed = TYMED_HGLOBAL;
213 *rgelt = format;
214
215 return S_OK;
216 }
217 else {
218 // bad index
219 return S_FALSE;
220 }
221 }
222
223 STDMETHODIMP wxIEnumFORMATETC::Skip(ULONG celt)
224 {
225 wxLogTrace(wxTRACE_OleCalls, wxT("wxIEnumFORMATETC::Skip"));
226
227 m_nCurrent += celt;
228 if ( m_nCurrent < m_nCount )
229 return S_OK;
230
231 // no, can't skip this many elements
232 m_nCurrent -= celt;
233
234 return S_FALSE;
235 }
236
237 STDMETHODIMP wxIEnumFORMATETC::Reset()
238 {
239 wxLogTrace(wxTRACE_OleCalls, wxT("wxIEnumFORMATETC::Reset"));
240
241 m_nCurrent = 0;
242
243 return S_OK;
244 }
245
246 STDMETHODIMP wxIEnumFORMATETC::Clone(IEnumFORMATETC **ppenum)
247 {
248 wxLogTrace(wxTRACE_OleCalls, wxT("wxIEnumFORMATETC::Clone"));
249
250 // unfortunately, we can't reuse the code in ctor - types are different
251 wxIEnumFORMATETC *pNew = new wxIEnumFORMATETC(NULL, 0);
252 pNew->m_nCount = m_nCount;
253 pNew->m_formats = new CLIPFORMAT[m_nCount];
254 for ( ULONG n = 0; n < m_nCount; n++ ) {
255 pNew->m_formats[n] = m_formats[n];
256 }
257 pNew->AddRef();
258 *ppenum = pNew;
259
260 return S_OK;
261 }
262
263 // ----------------------------------------------------------------------------
264 // wxIDataObject
265 // ----------------------------------------------------------------------------
266
267 BEGIN_IID_TABLE(wxIDataObject)
268 ADD_IID(Unknown)
269 ADD_IID(DataObject)
270 END_IID_TABLE;
271
272 IMPLEMENT_IUNKNOWN_METHODS(wxIDataObject)
273
274 wxIDataObject::wxIDataObject(wxDataObject *pDataObject)
275 {
276 m_cRef = 0;
277 m_pDataObject = pDataObject;
278 m_mustDelete = FALSE;
279 }
280
281 wxIDataObject::~wxIDataObject()
282 {
283 if ( m_mustDelete )
284 {
285 delete m_pDataObject;
286 }
287 }
288
289 // get data functions
290 STDMETHODIMP wxIDataObject::GetData(FORMATETC *pformatetcIn, STGMEDIUM *pmedium)
291 {
292 wxLogTrace(wxTRACE_OleCalls, wxT("wxIDataObject::GetData"));
293
294 // is data is in our format?
295 HRESULT hr = QueryGetData(pformatetcIn);
296 if ( FAILED(hr) )
297 return hr;
298
299 // for the bitmaps and metafiles we use the handles instead of global memory
300 // to pass the data
301 wxDataFormat format = (wxDataFormatId)pformatetcIn->cfFormat;
302
303 switch ( format )
304 {
305 case wxDF_BITMAP:
306 pmedium->tymed = TYMED_GDI;
307 break;
308
309 case wxDF_METAFILE:
310 pmedium->tymed = TYMED_MFPICT;
311 break;
312
313 default:
314 // alloc memory
315 size_t size = m_pDataObject->GetDataSize(format);
316 if ( !size ) {
317 // it probably means that the method is just not implemented
318 wxLogDebug(wxT("Invalid data size - can't be 0"));
319
320 return DV_E_FORMATETC;
321 }
322
323 HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, size);
324 if ( hGlobal == NULL ) {
325 wxLogLastError("GlobalAlloc");
326 return E_OUTOFMEMORY;
327 }
328
329 // copy data
330 pmedium->tymed = TYMED_HGLOBAL;
331 pmedium->hGlobal = hGlobal;
332 }
333
334 pmedium->pUnkForRelease = NULL;
335
336 // do copy the data
337 hr = GetDataHere(pformatetcIn, pmedium);
338 if ( FAILED(hr) ) {
339 // free resources we allocated
340 if ( pmedium->tymed == TYMED_HGLOBAL ) {
341 GlobalFree(pmedium->hGlobal);
342 }
343
344 return hr;
345 }
346
347 return S_OK;
348 }
349
350 STDMETHODIMP wxIDataObject::GetDataHere(FORMATETC *pformatetc,
351 STGMEDIUM *pmedium)
352 {
353 wxLogTrace(wxTRACE_OleCalls, wxT("wxIDataObject::GetDataHere"));
354
355 // put data in caller provided medium
356 switch ( pmedium->tymed )
357 {
358 case TYMED_GDI:
359 if ( !m_pDataObject->GetDataHere(wxDF_BITMAP, &pmedium->hBitmap) )
360 return E_UNEXPECTED;
361 break;
362
363 case TYMED_MFPICT:
364 // this should be copied on bitmaps - but I don't have time for
365 // this now
366 wxFAIL_MSG(wxT("TODO - no support for metafiles in wxDataObject"));
367 break;
368
369 case TYMED_HGLOBAL:
370 {
371 // copy data
372 void *pBuf = GlobalLock(pmedium->hGlobal);
373 if ( pBuf == NULL ) {
374 wxLogLastError(wxT("GlobalLock"));
375 return E_OUTOFMEMORY;
376 }
377
378 wxDataFormat format = (wxDataFormatId)pformatetc->cfFormat;
379 if ( !m_pDataObject->GetDataHere(format, pBuf) )
380 return E_UNEXPECTED;
381
382 GlobalUnlock(pmedium->hGlobal);
383 }
384 break;
385
386 default:
387 return DV_E_TYMED;
388 }
389
390 return S_OK;
391 }
392
393 // set data functions (not implemented)
394 STDMETHODIMP wxIDataObject::SetData(FORMATETC *pformatetc,
395 STGMEDIUM *pmedium,
396 BOOL fRelease)
397 {
398 wxLogTrace(wxTRACE_OleCalls, wxT("wxIDataObject::SetData"));
399
400 switch ( pmedium->tymed )
401 {
402 case TYMED_GDI:
403 m_pDataObject->SetData(wxDF_BITMAP, &pmedium->hBitmap);
404 break;
405
406 case TYMED_MFPICT:
407 // this should be copied on bitmaps - but I don't have time for
408 // this now
409 wxFAIL_MSG(wxT("TODO - no support for metafiles in wxDataObject"));
410 break;
411
412 case TYMED_HGLOBAL:
413 {
414 // copy data
415 void *pBuf = GlobalLock(pmedium->hGlobal);
416 if ( pBuf == NULL ) {
417 wxLogLastError("GlobalLock");
418
419 return E_OUTOFMEMORY;
420 }
421
422 wxDataFormat format = (wxDataFormatId)pformatetc->cfFormat;
423 m_pDataObject->SetData(format, pBuf);
424
425 GlobalUnlock(pmedium->hGlobal);
426 }
427 break;
428
429 default:
430 return DV_E_TYMED;
431 }
432
433 if ( fRelease ) {
434 // we own the medium, so we must release it - but do *not* free the
435 // bitmap handle fi we have it because we have copied it elsewhere
436 if ( pmedium->tymed == TYMED_GDI )
437 {
438 pmedium->hBitmap = 0;
439 }
440
441 ReleaseStgMedium(pmedium);
442 }
443
444 return S_OK;
445 }
446
447 // information functions
448 STDMETHODIMP wxIDataObject::QueryGetData(FORMATETC *pformatetc)
449 {
450 // do we accept data in this format?
451 if ( pformatetc == NULL ) {
452 wxLogTrace(wxTRACE_OleCalls,
453 wxT("wxIDataObject::QueryGetData: invalid ptr."));
454
455 return E_INVALIDARG;
456 }
457
458 // the only one allowed by current COM implementation
459 if ( pformatetc->lindex != -1 ) {
460 wxLogTrace(wxTRACE_OleCalls,
461 wxT("wxIDataObject::QueryGetData: bad lindex %d"),
462 pformatetc->lindex);
463
464 return DV_E_LINDEX;
465 }
466
467 // we don't support anything other (THUMBNAIL, ICON, DOCPRINT...)
468 if ( pformatetc->dwAspect != DVASPECT_CONTENT ) {
469 wxLogTrace(wxTRACE_OleCalls,
470 wxT("wxIDataObject::QueryGetData: bad dwAspect %d"),
471 pformatetc->dwAspect);
472
473 return DV_E_DVASPECT;
474 }
475
476 // and now check the type of data requested
477 wxDataFormat format = (wxDataFormatId)pformatetc->cfFormat;
478 if ( m_pDataObject->IsSupportedFormat(format) ) {
479 #ifdef __WXDEBUG__
480 wxLogTrace(wxTRACE_OleCalls, wxT("wxIDataObject::QueryGetData: %s ok"),
481 wxDataObject::GetFormatName(format));
482 #endif // Debug
483 }
484 else {
485 #ifdef __WXDEBUG__
486 wxLogTrace(wxTRACE_OleCalls,
487 wxT("wxIDataObject::QueryGetData: %s unsupported"),
488 wxDataObject::GetFormatName(format));
489 #endif
490 return DV_E_FORMATETC;
491 }
492
493 // we only transfer data by global memory, except for some particular cases
494 DWORD tymed = pformatetc->tymed;
495 if ( (format == wxDF_BITMAP && !(tymed & TYMED_GDI)) &&
496 !(tymed & TYMED_HGLOBAL) ) {
497 // it's not what we're waiting for
498 #ifdef __WXDEBUG__
499 wxLogTrace(wxTRACE_OleCalls,
500 wxT("wxIDataObject::QueryGetData: %s != %s"),
501 GetTymedName(tymed),
502 GetTymedName(format == wxDF_BITMAP ? TYMED_GDI
503 : TYMED_HGLOBAL));
504 #endif // Debug
505
506 return DV_E_TYMED;
507 }
508
509 return S_OK;
510 }
511
512 STDMETHODIMP wxIDataObject::GetCanonicalFormatEtc(FORMATETC *pFormatetcIn,
513 FORMATETC *pFormatetcOut)
514 {
515 wxLogTrace(wxTRACE_OleCalls, wxT("wxIDataObject::GetCanonicalFormatEtc"));
516
517 // TODO we might want something better than this trivial implementation here
518 if ( pFormatetcOut != NULL )
519 pFormatetcOut->ptd = NULL;
520
521 return DATA_S_SAMEFORMATETC;
522 }
523
524 STDMETHODIMP wxIDataObject::EnumFormatEtc(DWORD dwDirection,
525 IEnumFORMATETC **ppenumFormatEtc)
526 {
527 wxLogTrace(wxTRACE_OleCalls, wxT("wxIDataObject::EnumFormatEtc"));
528
529 bool allowOutputOnly = dwDirection == DATADIR_GET;
530
531 size_t nFormatCount = m_pDataObject->GetFormatCount(allowOutputOnly);
532 wxDataFormat format, *formats;
533 if ( nFormatCount == 1 ) {
534 // this is the most common case, this is why we consider it separately
535 formats = &format;
536 format = m_pDataObject->GetPreferredFormat();
537 }
538 else {
539 // bad luck, build the array with all formats
540 formats = new wxDataFormat[nFormatCount];
541 m_pDataObject->GetAllFormats(formats, allowOutputOnly);
542 }
543
544 wxIEnumFORMATETC *pEnum = new wxIEnumFORMATETC(formats, nFormatCount);
545 pEnum->AddRef();
546 *ppenumFormatEtc = pEnum;
547
548 if ( formats != &format ) {
549 delete [] formats;
550 }
551
552 return S_OK;
553 }
554
555 // advise sink functions (not implemented)
556 STDMETHODIMP wxIDataObject::DAdvise(FORMATETC *pformatetc,
557 DWORD advf,
558 IAdviseSink *pAdvSink,
559 DWORD *pdwConnection)
560 {
561 return OLE_E_ADVISENOTSUPPORTED;
562 }
563
564 STDMETHODIMP wxIDataObject::DUnadvise(DWORD dwConnection)
565 {
566 return OLE_E_ADVISENOTSUPPORTED;
567 }
568
569 STDMETHODIMP wxIDataObject::EnumDAdvise(IEnumSTATDATA **ppenumAdvise)
570 {
571 return OLE_E_ADVISENOTSUPPORTED;
572 }
573
574 // ----------------------------------------------------------------------------
575 // wxDataObject
576 // ----------------------------------------------------------------------------
577
578 wxDataObject::wxDataObject()
579 {
580 m_pIDataObject = new wxIDataObject(this);
581 m_pIDataObject->AddRef();
582 }
583
584 wxDataObject::~wxDataObject()
585 {
586 ReleaseInterface(m_pIDataObject);
587 }
588
589 void wxDataObject::SetAutoDelete()
590 {
591 ((wxIDataObject *)m_pIDataObject)->SetDeleteFlag();
592 m_pIDataObject->Release();
593
594 // so that the dtor doesnt' crash
595 m_pIDataObject = NULL;
596 }
597
598 bool wxDataObject::IsSupportedFormat(const wxDataFormat& format) const
599 {
600 size_t nFormatCount = GetFormatCount();
601 if ( nFormatCount == 1 ) {
602 return format == GetPreferredFormat();
603 }
604 else {
605 wxDataFormat *formats = new wxDataFormat[nFormatCount];
606 GetAllFormats(formats);
607
608 size_t n;
609 for ( n = 0; n < nFormatCount; n++ ) {
610 if ( formats[n] == format )
611 break;
612 }
613
614 delete [] formats;
615
616 // found?
617 return n < nFormatCount;
618 }
619 }
620
621 #ifdef __WXDEBUG__
622 const char *wxDataObject::GetFormatName(wxDataFormat format)
623 {
624 // case 'xxx' is not a valid value for switch of enum 'wxDataFormat'
625 #ifdef __VISUALC__
626 #pragma warning(disable:4063)
627 #endif // VC++
628
629 static char s_szBuf[128];
630 switch ( format ) {
631 case CF_TEXT: return "CF_TEXT";
632 case CF_BITMAP: return "CF_BITMAP";
633 case CF_METAFILEPICT: return "CF_METAFILEPICT";
634 case CF_SYLK: return "CF_SYLK";
635 case CF_DIF: return "CF_DIF";
636 case CF_TIFF: return "CF_TIFF";
637 case CF_OEMTEXT: return "CF_OEMTEXT";
638 case CF_DIB: return "CF_DIB";
639 case CF_PALETTE: return "CF_PALETTE";
640 case CF_PENDATA: return "CF_PENDATA";
641 case CF_RIFF: return "CF_RIFF";
642 case CF_WAVE: return "CF_WAVE";
643 case CF_UNICODETEXT: return "CF_UNICODETEXT";
644 case CF_ENHMETAFILE: return "CF_ENHMETAFILE";
645 case CF_HDROP: return "CF_HDROP";
646 case CF_LOCALE: return "CF_LOCALE";
647 default:
648 sprintf(s_szBuf, "clipboard format 0x%x (unknown)", format);
649 return s_szBuf;
650 }
651
652 #ifdef __VISUALC__
653 #pragma warning(default:4063)
654 #endif // VC++
655 }
656 #endif // Debug
657
658 // ----------------------------------------------------------------------------
659 // wxPrivateDataObject
660 // ----------------------------------------------------------------------------
661
662 wxPrivateDataObject::wxPrivateDataObject()
663 {
664 m_size = 0;
665 m_data = NULL;
666 }
667
668 void wxPrivateDataObject::Free()
669 {
670 if ( m_data )
671 free(m_data);
672 }
673
674 void wxPrivateDataObject::SetData( const void *data, size_t size )
675 {
676 Free();
677
678 m_size = size;
679 m_data = malloc(size);
680
681 memcpy( m_data, data, size );
682 }
683
684 void wxPrivateDataObject::WriteData( void *dest ) const
685 {
686 WriteData( m_data, dest );
687 }
688
689 size_t wxPrivateDataObject::GetSize() const
690 {
691 return m_size;
692 }
693
694 void wxPrivateDataObject::WriteData( const void *data, void *dest ) const
695 {
696 memcpy( dest, data, GetSize() );
697 }
698
699 // ----------------------------------------------------------------------------
700 // wxBitmapDataObject: it supports standard CF_BITMAP and CF_DIB formats
701 // ----------------------------------------------------------------------------
702
703 size_t wxBitmapDataObject::GetFormatCount(bool outputOnlyToo) const
704 {
705 return 2;
706 }
707
708 void wxBitmapDataObject::GetAllFormats(wxDataFormat *formats,
709 bool outputOnlyToo) const
710 {
711 formats[0] = CF_BITMAP;
712 formats[1] = CF_DIB;
713 }
714
715 // the bitmaps aren't passed by value as other types of data (i.e. by copyign
716 // the data into a global memory chunk and passing it to the clipboard or
717 // another application or whatever), but by handle, so these generic functions
718 // don't make much sense to them.
719
720 size_t wxBitmapDataObject::GetDataSize(const wxDataFormat& format) const
721 {
722 if ( format.GetFormatId() == CF_DIB )
723 {
724 // create the DIB
725 ScreenHDC hdc;
726
727 // shouldn't be selected into a DC or GetDIBits() would fail
728 wxASSERT_MSG( !m_bitmap.GetSelectedInto(),
729 wxT("can't copy bitmap selected into wxMemoryDC") );
730
731 // first get the info
732 BITMAPINFO bi;
733 if ( !GetDIBits(hdc, (HBITMAP)m_bitmap.GetHBITMAP(), 0, 0,
734 NULL, &bi, DIB_RGB_COLORS) )
735 {
736 wxLogLastError("GetDIBits(NULL)");
737
738 return 0;
739 }
740
741 return sizeof(BITMAPINFO) + bi.bmiHeader.biSizeImage;
742 }
743 else // CF_BITMAP
744 {
745 // no data to copy - we don't pass HBITMAP via global memory
746 return 0;
747 }
748 }
749
750 bool wxBitmapDataObject::GetDataHere(const wxDataFormat& format,
751 void *pBuf) const
752 {
753 wxASSERT_MSG( m_bitmap.Ok(), wxT("copying invalid bitmap") );
754
755 HBITMAP hbmp = (HBITMAP)m_bitmap.GetHBITMAP();
756 if ( format.GetFormatId() == CF_DIB )
757 {
758 // create the DIB
759 ScreenHDC hdc;
760
761 // shouldn't be selected into a DC or GetDIBits() would fail
762 wxASSERT_MSG( !m_bitmap.GetSelectedInto(),
763 wxT("can't copy bitmap selected into wxMemoryDC") );
764
765 // first get the info
766 BITMAPINFO *pbi = (BITMAPINFO *)pBuf;
767 if ( !GetDIBits(hdc, hbmp, 0, 0, NULL, pbi, DIB_RGB_COLORS) )
768 {
769 wxLogLastError("GetDIBits(NULL)");
770
771 return 0;
772 }
773
774 // and now copy the bits
775 if ( !GetDIBits(hdc, hbmp, 0, pbi->bmiHeader.biHeight, pbi + 1,
776 pbi, DIB_RGB_COLORS) )
777 {
778 wxLogLastError("GetDIBits");
779
780 return FALSE;
781 }
782 }
783 else // CF_BITMAP
784 {
785 // we put a bitmap handle into pBuf
786 *(HBITMAP *)pBuf = hbmp;
787 }
788
789 return TRUE;
790 }
791
792 bool wxBitmapDataObject::SetData(const wxDataFormat& format, const void *pBuf)
793 {
794 HBITMAP hbmp;
795 if ( format.GetFormatId() == CF_DIB )
796 {
797 // here we get BITMAPINFO struct followed by the actual bitmap bits and
798 // BITMAPINFO starts with BITMAPINFOHEADER followed by colour info
799 ScreenHDC hdc;
800
801 BITMAPINFO *pbmi = (BITMAPINFO *)pBuf;
802 BITMAPINFOHEADER *pbmih = &pbmi->bmiHeader;
803 hbmp = CreateDIBitmap(hdc, pbmih, CBM_INIT,
804 pbmi + 1, pbmi, DIB_RGB_COLORS);
805 if ( !hbmp )
806 {
807 wxLogLastError("CreateDIBitmap");
808 }
809
810 m_bitmap.SetWidth(pbmih->biWidth);
811 m_bitmap.SetHeight(pbmih->biHeight);
812 }
813 else // CF_BITMAP
814 {
815 // it's easy with bitmaps: we pass them by handle
816 hbmp = *(HBITMAP *)pBuf;
817
818 BITMAP bmp;
819 if ( !GetObject(hbmp, sizeof(BITMAP), &bmp) )
820 {
821 wxLogLastError("GetObject(HBITMAP)");
822 }
823
824 m_bitmap.SetWidth(bmp.bmWidth);
825 m_bitmap.SetHeight(bmp.bmHeight);
826 m_bitmap.SetDepth(bmp.bmPlanes);
827 }
828
829 m_bitmap.SetHBITMAP((WXHBITMAP)hbmp);
830
831 wxASSERT_MSG( m_bitmap.Ok(), wxT("pasting invalid bitmap") );
832
833 return TRUE;
834 }
835
836 // ----------------------------------------------------------------------------
837 // private functions
838 // ----------------------------------------------------------------------------
839
840 #ifdef __WXDEBUG__
841
842 static const wxChar *GetTymedName(DWORD tymed)
843 {
844 static wxChar s_szBuf[128];
845 switch ( tymed ) {
846 case TYMED_HGLOBAL: return wxT("TYMED_HGLOBAL");
847 case TYMED_FILE: return wxT("TYMED_FILE");
848 case TYMED_ISTREAM: return wxT("TYMED_ISTREAM");
849 case TYMED_ISTORAGE: return wxT("TYMED_ISTORAGE");
850 case TYMED_GDI: return wxT("TYMED_GDI");
851 case TYMED_MFPICT: return wxT("TYMED_MFPICT");
852 case TYMED_ENHMF: return wxT("TYMED_ENHMF");
853 default:
854 wxSprintf(s_szBuf, wxT("type of media format %d (unknown)"), tymed);
855 return s_szBuf;
856 }
857 }
858
859 #endif // Debug
860
861 #endif // not using OLE at all
862