]> git.saurik.com Git - wxWidgets.git/blob - src/msw/ole/dataobj.cpp
Size the notebook page when it is added to the notebook.
[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 wxLogTrace(wxTRACE_OleCalls,
486 wxT("wxIDataObject::QueryGetData: %s unsupported"),
487 wxDataObject::GetFormatName(format));
488
489 return DV_E_FORMATETC;
490 }
491
492 // we only transfer data by global memory, except for some particular cases
493 DWORD tymed = pformatetc->tymed;
494 if ( (format == wxDF_BITMAP && !(tymed & TYMED_GDI)) &&
495 !(tymed & TYMED_HGLOBAL) ) {
496 // it's not what we're waiting for
497 #ifdef __WXDEBUG__
498 wxLogTrace(wxTRACE_OleCalls,
499 wxT("wxIDataObject::QueryGetData: %s != %s"),
500 GetTymedName(tymed),
501 GetTymedName(format == wxDF_BITMAP ? TYMED_GDI
502 : TYMED_HGLOBAL));
503 #endif // Debug
504
505 return DV_E_TYMED;
506 }
507
508 return S_OK;
509 }
510
511 STDMETHODIMP wxIDataObject::GetCanonicalFormatEtc(FORMATETC *pFormatetcIn,
512 FORMATETC *pFormatetcOut)
513 {
514 wxLogTrace(wxTRACE_OleCalls, wxT("wxIDataObject::GetCanonicalFormatEtc"));
515
516 // TODO we might want something better than this trivial implementation here
517 if ( pFormatetcOut != NULL )
518 pFormatetcOut->ptd = NULL;
519
520 return DATA_S_SAMEFORMATETC;
521 }
522
523 STDMETHODIMP wxIDataObject::EnumFormatEtc(DWORD dwDirection,
524 IEnumFORMATETC **ppenumFormatEtc)
525 {
526 wxLogTrace(wxTRACE_OleCalls, wxT("wxIDataObject::EnumFormatEtc"));
527
528 bool allowOutputOnly = dwDirection == DATADIR_GET;
529
530 size_t nFormatCount = m_pDataObject->GetFormatCount(allowOutputOnly);
531 wxDataFormat format, *formats;
532 if ( nFormatCount == 1 ) {
533 // this is the most common case, this is why we consider it separately
534 formats = &format;
535 format = m_pDataObject->GetPreferredFormat();
536 }
537 else {
538 // bad luck, build the array with all formats
539 formats = new wxDataFormat[nFormatCount];
540 m_pDataObject->GetAllFormats(formats, allowOutputOnly);
541 }
542
543 wxIEnumFORMATETC *pEnum = new wxIEnumFORMATETC(formats, nFormatCount);
544 pEnum->AddRef();
545 *ppenumFormatEtc = pEnum;
546
547 if ( formats != &format ) {
548 delete [] formats;
549 }
550
551 return S_OK;
552 }
553
554 // advise sink functions (not implemented)
555 STDMETHODIMP wxIDataObject::DAdvise(FORMATETC *pformatetc,
556 DWORD advf,
557 IAdviseSink *pAdvSink,
558 DWORD *pdwConnection)
559 {
560 return OLE_E_ADVISENOTSUPPORTED;
561 }
562
563 STDMETHODIMP wxIDataObject::DUnadvise(DWORD dwConnection)
564 {
565 return OLE_E_ADVISENOTSUPPORTED;
566 }
567
568 STDMETHODIMP wxIDataObject::EnumDAdvise(IEnumSTATDATA **ppenumAdvise)
569 {
570 return OLE_E_ADVISENOTSUPPORTED;
571 }
572
573 // ----------------------------------------------------------------------------
574 // wxDataObject
575 // ----------------------------------------------------------------------------
576
577 wxDataObject::wxDataObject()
578 {
579 m_pIDataObject = new wxIDataObject(this);
580 m_pIDataObject->AddRef();
581 }
582
583 wxDataObject::~wxDataObject()
584 {
585 ReleaseInterface(m_pIDataObject);
586 }
587
588 void wxDataObject::SetAutoDelete()
589 {
590 ((wxIDataObject *)m_pIDataObject)->SetDeleteFlag();
591 m_pIDataObject->Release();
592
593 // so that the dtor doesnt' crash
594 m_pIDataObject = NULL;
595 }
596
597 bool wxDataObject::IsSupportedFormat(const wxDataFormat& format) const
598 {
599 size_t nFormatCount = GetFormatCount();
600 if ( nFormatCount == 1 ) {
601 return format == GetPreferredFormat();
602 }
603 else {
604 wxDataFormat *formats = new wxDataFormat[nFormatCount];
605 GetAllFormats(formats);
606
607 size_t n;
608 for ( n = 0; n < nFormatCount; n++ ) {
609 if ( formats[n] == format )
610 break;
611 }
612
613 delete [] formats;
614
615 // found?
616 return n < nFormatCount;
617 }
618 }
619
620 #ifdef __WXDEBUG__
621 const char *wxDataObject::GetFormatName(wxDataFormat format)
622 {
623 // case 'xxx' is not a valid value for switch of enum 'wxDataFormat'
624 #ifdef __VISUALC__
625 #pragma warning(disable:4063)
626 #endif // VC++
627
628 static char s_szBuf[128];
629 switch ( format ) {
630 case CF_TEXT: return "CF_TEXT";
631 case CF_BITMAP: return "CF_BITMAP";
632 case CF_METAFILEPICT: return "CF_METAFILEPICT";
633 case CF_SYLK: return "CF_SYLK";
634 case CF_DIF: return "CF_DIF";
635 case CF_TIFF: return "CF_TIFF";
636 case CF_OEMTEXT: return "CF_OEMTEXT";
637 case CF_DIB: return "CF_DIB";
638 case CF_PALETTE: return "CF_PALETTE";
639 case CF_PENDATA: return "CF_PENDATA";
640 case CF_RIFF: return "CF_RIFF";
641 case CF_WAVE: return "CF_WAVE";
642 case CF_UNICODETEXT: return "CF_UNICODETEXT";
643 case CF_ENHMETAFILE: return "CF_ENHMETAFILE";
644 case CF_HDROP: return "CF_HDROP";
645 case CF_LOCALE: return "CF_LOCALE";
646 default:
647 sprintf(s_szBuf, "clipboard format 0x%x (unknown)", format);
648 return s_szBuf;
649 }
650
651 #ifdef __VISUALC__
652 #pragma warning(default:4063)
653 #endif // VC++
654 }
655 #endif // Debug
656
657 // ----------------------------------------------------------------------------
658 // wxPrivateDataObject
659 // ----------------------------------------------------------------------------
660
661 wxPrivateDataObject::wxPrivateDataObject()
662 {
663 m_size = 0;
664 m_data = NULL;
665 }
666
667 void wxPrivateDataObject::Free()
668 {
669 if ( m_data )
670 free(m_data);
671 }
672
673 void wxPrivateDataObject::SetData( const void *data, size_t size )
674 {
675 Free();
676
677 m_size = size;
678 m_data = malloc(size);
679
680 memcpy( m_data, data, size );
681 }
682
683 void wxPrivateDataObject::WriteData( void *dest ) const
684 {
685 WriteData( m_data, dest );
686 }
687
688 size_t wxPrivateDataObject::GetSize() const
689 {
690 return m_size;
691 }
692
693 void wxPrivateDataObject::WriteData( const void *data, void *dest ) const
694 {
695 memcpy( dest, data, GetSize() );
696 }
697
698 // ----------------------------------------------------------------------------
699 // wxBitmapDataObject: it supports standard CF_BITMAP and CF_DIB formats
700 // ----------------------------------------------------------------------------
701
702 size_t wxBitmapDataObject::GetFormatCount(bool outputOnlyToo) const
703 {
704 return 2;
705 }
706
707 void wxBitmapDataObject::GetAllFormats(wxDataFormat *formats,
708 bool outputOnlyToo) const
709 {
710 formats[0] = CF_BITMAP;
711 formats[1] = CF_DIB;
712 }
713
714 // the bitmaps aren't passed by value as other types of data (i.e. by copyign
715 // the data into a global memory chunk and passing it to the clipboard or
716 // another application or whatever), but by handle, so these generic functions
717 // don't make much sense to them.
718
719 size_t wxBitmapDataObject::GetDataSize(const wxDataFormat& format) const
720 {
721 if ( format.GetFormatId() == CF_DIB )
722 {
723 // create the DIB
724 ScreenHDC hdc;
725
726 // shouldn't be selected into a DC or GetDIBits() would fail
727 wxASSERT_MSG( !m_bitmap.GetSelectedInto(),
728 wxT("can't copy bitmap selected into wxMemoryDC") );
729
730 // first get the info
731 BITMAPINFO bi;
732 if ( !GetDIBits(hdc, (HBITMAP)m_bitmap.GetHBITMAP(), 0, 0,
733 NULL, &bi, DIB_RGB_COLORS) )
734 {
735 wxLogLastError("GetDIBits(NULL)");
736
737 return 0;
738 }
739
740 return sizeof(BITMAPINFO) + bi.bmiHeader.biSizeImage;
741 }
742 else // CF_BITMAP
743 {
744 // no data to copy - we don't pass HBITMAP via global memory
745 return 0;
746 }
747 }
748
749 bool wxBitmapDataObject::GetDataHere(const wxDataFormat& format,
750 void *pBuf) const
751 {
752 wxASSERT_MSG( m_bitmap.Ok(), wxT("copying invalid bitmap") );
753
754 HBITMAP hbmp = (HBITMAP)m_bitmap.GetHBITMAP();
755 if ( format.GetFormatId() == CF_DIB )
756 {
757 // create the DIB
758 ScreenHDC hdc;
759
760 // shouldn't be selected into a DC or GetDIBits() would fail
761 wxASSERT_MSG( !m_bitmap.GetSelectedInto(),
762 wxT("can't copy bitmap selected into wxMemoryDC") );
763
764 // first get the info
765 BITMAPINFO *pbi = (BITMAPINFO *)pBuf;
766 if ( !GetDIBits(hdc, hbmp, 0, 0, NULL, pbi, DIB_RGB_COLORS) )
767 {
768 wxLogLastError("GetDIBits(NULL)");
769
770 return 0;
771 }
772
773 // and now copy the bits
774 if ( !GetDIBits(hdc, hbmp, 0, pbi->bmiHeader.biHeight, pbi + 1,
775 pbi, DIB_RGB_COLORS) )
776 {
777 wxLogLastError("GetDIBits");
778
779 return FALSE;
780 }
781 }
782 else // CF_BITMAP
783 {
784 // we put a bitmap handle into pBuf
785 *(HBITMAP *)pBuf = hbmp;
786 }
787
788 return TRUE;
789 }
790
791 bool wxBitmapDataObject::SetData(const wxDataFormat& format, const void *pBuf)
792 {
793 HBITMAP hbmp;
794 if ( format.GetFormatId() == CF_DIB )
795 {
796 // here we get BITMAPINFO struct followed by the actual bitmap bits and
797 // BITMAPINFO starts with BITMAPINFOHEADER followed by colour info
798 ScreenHDC hdc;
799
800 BITMAPINFO *pbmi = (BITMAPINFO *)pBuf;
801 BITMAPINFOHEADER *pbmih = &pbmi->bmiHeader;
802 hbmp = CreateDIBitmap(hdc, pbmih, CBM_INIT,
803 pbmi + 1, pbmi, DIB_RGB_COLORS);
804 if ( !hbmp )
805 {
806 wxLogLastError("CreateDIBitmap");
807 }
808
809 m_bitmap.SetWidth(pbmih->biWidth);
810 m_bitmap.SetHeight(pbmih->biHeight);
811 }
812 else // CF_BITMAP
813 {
814 // it's easy with bitmaps: we pass them by handle
815 hbmp = *(HBITMAP *)pBuf;
816
817 BITMAP bmp;
818 if ( !GetObject(hbmp, sizeof(BITMAP), &bmp) )
819 {
820 wxLogLastError("GetObject(HBITMAP)");
821 }
822
823 m_bitmap.SetWidth(bmp.bmWidth);
824 m_bitmap.SetHeight(bmp.bmHeight);
825 m_bitmap.SetDepth(bmp.bmPlanes);
826 }
827
828 m_bitmap.SetHBITMAP((WXHBITMAP)hbmp);
829
830 wxASSERT_MSG( m_bitmap.Ok(), wxT("pasting invalid bitmap") );
831
832 return TRUE;
833 }
834
835 // ----------------------------------------------------------------------------
836 // private functions
837 // ----------------------------------------------------------------------------
838
839 #ifdef __WXDEBUG__
840
841 static const wxChar *GetTymedName(DWORD tymed)
842 {
843 static wxChar s_szBuf[128];
844 switch ( tymed ) {
845 case TYMED_HGLOBAL: return wxT("TYMED_HGLOBAL");
846 case TYMED_FILE: return wxT("TYMED_FILE");
847 case TYMED_ISTREAM: return wxT("TYMED_ISTREAM");
848 case TYMED_ISTORAGE: return wxT("TYMED_ISTORAGE");
849 case TYMED_GDI: return wxT("TYMED_GDI");
850 case TYMED_MFPICT: return wxT("TYMED_MFPICT");
851 case TYMED_ENHMF: return wxT("TYMED_ENHMF");
852 default:
853 wxSprintf(s_szBuf, wxT("type of media format %d (unknown)"), tymed);
854 return s_szBuf;
855 }
856 }
857
858 #endif // Debug
859
860 #endif // not using OLE at all
861