]> git.saurik.com Git - wxWidgets.git/blob - src/msw/ole/dataobj.cpp
1. wxPostEvent added and documented
[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 char *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
94 DECLARE_IUNKNOWN_METHODS;
95
96 // IDataObject
97 STDMETHODIMP GetData(FORMATETC *pformatetcIn, STGMEDIUM *pmedium);
98 STDMETHODIMP GetDataHere(FORMATETC *pformatetc, STGMEDIUM *pmedium);
99 STDMETHODIMP QueryGetData(FORMATETC *pformatetc);
100 STDMETHODIMP GetCanonicalFormatEtc(FORMATETC *In, FORMATETC *pOut);
101 STDMETHODIMP SetData(FORMATETC *pfetc, STGMEDIUM *pmedium, BOOL fRelease);
102 STDMETHODIMP EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC **ppenumFEtc);
103 STDMETHODIMP DAdvise(FORMATETC *pfetc, DWORD ad, IAdviseSink *p, DWORD *pdw);
104 STDMETHODIMP DUnadvise(DWORD dwConnection);
105 STDMETHODIMP EnumDAdvise(IEnumSTATDATA **ppenumAdvise);
106
107 private:
108 wxDataObject *m_pDataObject; // pointer to C++ class we belong to
109 };
110
111 // ============================================================================
112 // implementation
113 // ============================================================================
114
115 // ----------------------------------------------------------------------------
116 // wxDataFormat
117 // ----------------------------------------------------------------------------
118
119 void wxDataFormat::SetId(const wxChar *format)
120 {
121 m_format = ::RegisterClipboardFormat(format);
122 if ( !m_format )
123 {
124 wxLogError(_("Couldn't register clipboard format '%s'."), format);
125 }
126 }
127
128 wxString wxDataFormat::GetId() const
129 {
130 static const int max = 256;
131
132 wxString s;
133
134 wxCHECK_MSG( !IsStandard(), s,
135 wxT("name of predefined format cannot be retrieved") );
136
137 int len = ::GetClipboardFormatName(m_format, s.GetWriteBuf(max), max);
138 s.UngetWriteBuf();
139
140 if ( !len )
141 {
142 wxLogError(_("The clipboard format '%d' doesn't exist."), m_format);
143 }
144
145 return s;
146 }
147
148 // ----------------------------------------------------------------------------
149 // wxIEnumFORMATETC
150 // ----------------------------------------------------------------------------
151
152 BEGIN_IID_TABLE(wxIEnumFORMATETC)
153 ADD_IID(Unknown)
154 ADD_IID(EnumFORMATETC)
155 END_IID_TABLE;
156
157 IMPLEMENT_IUNKNOWN_METHODS(wxIEnumFORMATETC)
158
159 wxIEnumFORMATETC::wxIEnumFORMATETC(const wxDataFormat *formats, ULONG nCount)
160 {
161 m_cRef = 0;
162 m_nCurrent = 0;
163 m_nCount = nCount;
164 m_formats = new CLIPFORMAT[nCount];
165 for ( ULONG n = 0; n < nCount; n++ ) {
166 m_formats[n] = formats[n].GetFormatId();
167 }
168 }
169
170 STDMETHODIMP wxIEnumFORMATETC::Next(ULONG celt,
171 FORMATETC *rgelt,
172 ULONG *pceltFetched)
173 {
174 wxLogTrace(wxTRACE_OleCalls, wxT("wxIEnumFORMATETC::Next"));
175
176 if ( celt > 1 ) {
177 // we only return 1 element at a time - mainly because I'm too lazy to
178 // implement something which you're never asked for anyhow
179 return S_FALSE;
180 }
181
182 if ( m_nCurrent < m_nCount ) {
183 FORMATETC format;
184 format.cfFormat = m_formats[m_nCurrent++];
185 format.ptd = NULL;
186 format.dwAspect = DVASPECT_CONTENT;
187 format.lindex = -1;
188 format.tymed = TYMED_HGLOBAL;
189 *rgelt = format;
190
191 return S_OK;
192 }
193 else {
194 // bad index
195 return S_FALSE;
196 }
197 }
198
199 STDMETHODIMP wxIEnumFORMATETC::Skip(ULONG celt)
200 {
201 wxLogTrace(wxTRACE_OleCalls, wxT("wxIEnumFORMATETC::Skip"));
202
203 m_nCurrent += celt;
204 if ( m_nCurrent < m_nCount )
205 return S_OK;
206
207 // no, can't skip this many elements
208 m_nCurrent -= celt;
209
210 return S_FALSE;
211 }
212
213 STDMETHODIMP wxIEnumFORMATETC::Reset()
214 {
215 wxLogTrace(wxTRACE_OleCalls, wxT("wxIEnumFORMATETC::Reset"));
216
217 m_nCurrent = 0;
218
219 return S_OK;
220 }
221
222 STDMETHODIMP wxIEnumFORMATETC::Clone(IEnumFORMATETC **ppenum)
223 {
224 wxLogTrace(wxTRACE_OleCalls, wxT("wxIEnumFORMATETC::Clone"));
225
226 // unfortunately, we can't reuse the code in ctor - types are different
227 wxIEnumFORMATETC *pNew = new wxIEnumFORMATETC(NULL, 0);
228 pNew->m_nCount = m_nCount;
229 pNew->m_formats = new CLIPFORMAT[m_nCount];
230 for ( ULONG n = 0; n < m_nCount; n++ ) {
231 pNew->m_formats[n] = m_formats[n];
232 }
233 pNew->AddRef();
234 *ppenum = pNew;
235
236 return S_OK;
237 }
238
239 // ----------------------------------------------------------------------------
240 // wxIDataObject
241 // ----------------------------------------------------------------------------
242
243 BEGIN_IID_TABLE(wxIDataObject)
244 ADD_IID(Unknown)
245 ADD_IID(DataObject)
246 END_IID_TABLE;
247
248 IMPLEMENT_IUNKNOWN_METHODS(wxIDataObject)
249
250 wxIDataObject::wxIDataObject(wxDataObject *pDataObject)
251 {
252 m_cRef = 0;
253 m_pDataObject = pDataObject;
254 }
255
256 // get data functions
257 STDMETHODIMP wxIDataObject::GetData(FORMATETC *pformatetcIn, STGMEDIUM *pmedium)
258 {
259 wxLogTrace(wxTRACE_OleCalls, wxT("wxIDataObject::GetData"));
260
261 // is data is in our format?
262 HRESULT hr = QueryGetData(pformatetcIn);
263 if ( FAILED(hr) )
264 return hr;
265
266 // for the bitmaps and metafiles we use the handles instead of global memory
267 // to pass the data
268 wxDataFormat format = (wxDataFormatId)pformatetcIn->cfFormat;
269
270 switch ( format )
271 {
272 case wxDF_BITMAP:
273 pmedium->tymed = TYMED_GDI;
274 break;
275
276 case wxDF_METAFILE:
277 pmedium->tymed = TYMED_MFPICT;
278 break;
279
280 default:
281 // alloc memory
282 size_t size = m_pDataObject->GetDataSize(format);
283 if ( !size ) {
284 // it probably means that the method is just not implemented
285 wxLogDebug(wxT("Invalid data size - can't be 0"));
286
287 return DV_E_FORMATETC;
288 }
289
290 HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, size);
291 if ( hGlobal == NULL ) {
292 wxLogLastError("GlobalAlloc");
293 return E_OUTOFMEMORY;
294 }
295
296 // copy data
297 pmedium->tymed = TYMED_HGLOBAL;
298 pmedium->hGlobal = hGlobal;
299 }
300
301 pmedium->pUnkForRelease = NULL;
302
303 // do copy the data
304 hr = GetDataHere(pformatetcIn, pmedium);
305 if ( FAILED(hr) ) {
306 // free resources we allocated
307 if ( pmedium->tymed == TYMED_HGLOBAL ) {
308 GlobalFree(pmedium->hGlobal);
309 }
310
311 return hr;
312 }
313
314 return S_OK;
315 }
316
317 STDMETHODIMP wxIDataObject::GetDataHere(FORMATETC *pformatetc,
318 STGMEDIUM *pmedium)
319 {
320 wxLogTrace(wxTRACE_OleCalls, wxT("wxIDataObject::GetDataHere"));
321
322 // put data in caller provided medium
323 switch ( pmedium->tymed )
324 {
325 case TYMED_GDI:
326 m_pDataObject->GetDataHere(wxDF_BITMAP, &pmedium->hBitmap);
327 break;
328
329 case TYMED_MFPICT:
330 // this should be copied on bitmaps - but I don't have time for
331 // this now
332 wxFAIL_MSG(wxT("TODO - no support for metafiles in wxDataObject"));
333 break;
334
335 case TYMED_HGLOBAL:
336 {
337 // copy data
338 void *pBuf = GlobalLock(pmedium->hGlobal);
339 if ( pBuf == NULL ) {
340 wxLogLastError(wxT("GlobalLock"));
341 return E_OUTOFMEMORY;
342 }
343
344 wxDataFormat format = (wxDataFormatId)pformatetc->cfFormat;
345 m_pDataObject->GetDataHere(format, pBuf);
346
347 GlobalUnlock(pmedium->hGlobal);
348 }
349 break;
350
351 default:
352 return DV_E_TYMED;
353 }
354
355 return S_OK;
356 }
357
358 // set data functions (not implemented)
359 STDMETHODIMP wxIDataObject::SetData(FORMATETC *pformatetc,
360 STGMEDIUM *pmedium,
361 BOOL fRelease)
362 {
363 wxLogTrace(wxTRACE_OleCalls, wxT("wxIDataObject::SetData"));
364
365 return E_NOTIMPL;
366 }
367
368 // information functions
369 STDMETHODIMP wxIDataObject::QueryGetData(FORMATETC *pformatetc)
370 {
371 // do we accept data in this format?
372 if ( pformatetc == NULL ) {
373 wxLogTrace(wxTRACE_OleCalls, wxT("wxIDataObject::QueryGetData: invalid ptr."));
374
375 return E_INVALIDARG;
376 }
377
378 // the only one allowed by current COM implementation
379 if ( pformatetc->lindex != -1 ) {
380 wxLogTrace(wxTRACE_OleCalls,
381 wxT("wxIDataObject::QueryGetData: bad lindex %d"),
382 pformatetc->lindex);
383 return DV_E_LINDEX;
384 }
385
386 // we don't support anything other (THUMBNAIL, ICON, DOCPRINT...)
387 if ( pformatetc->dwAspect != DVASPECT_CONTENT ) {
388 wxLogTrace(wxTRACE_OleCalls,
389 wxT("wxIDataObject::QueryGetData: bad dwAspect %d"),
390 pformatetc->dwAspect);
391 return DV_E_DVASPECT;
392 }
393
394 // we only transfer data by global memory, except for some particular cases
395 wxDataFormat format = (wxDataFormatId)pformatetc->cfFormat;
396 DWORD tymed = pformatetc->tymed;
397 if ( (format == wxDF_BITMAP && !(tymed & TYMED_GDI)) ||
398 !(tymed & TYMED_HGLOBAL) ) {
399 // it's not what we're waiting for
400 #ifdef __WXDEBUG__
401 wxLogTrace(wxTRACE_OleCalls,
402 wxT("wxIDataObject::QueryGetData: %s & %s == 0."),
403 GetTymedName(tymed),
404 GetTymedName(format == wxDF_BITMAP ? TYMED_GDI : TYMED_HGLOBAL));
405 #endif // Debug
406 return DV_E_TYMED;
407 }
408
409 // and now check the type of data requested
410 if ( m_pDataObject->IsSupportedFormat(format) ) {
411 #ifdef __WXDEBUG__
412 wxLogTrace(wxTRACE_OleCalls, wxT("wxIDataObject::QueryGetData: %s ok"),
413 wxDataObject::GetFormatName(format));
414 #endif // Debug
415 return S_OK;
416 }
417 else {
418 wxLogTrace(wxTRACE_OleCalls,
419 wxT("wxIDataObject::QueryGetData: %s unsupported"),
420 wxDataObject::GetFormatName((wxDataFormatId)pformatetc->cfFormat));
421 return DV_E_FORMATETC;
422 }
423 }
424
425 STDMETHODIMP wxIDataObject::GetCanonicalFormatEtc(FORMATETC *pFormatetcIn,
426 FORMATETC *pFormatetcOut)
427 {
428 wxLogTrace(wxTRACE_OleCalls, wxT("wxIDataObject::GetCanonicalFormatEtc"));
429
430 // TODO we might want something better than this trivial implementation here
431 if ( pFormatetcOut != NULL )
432 pFormatetcOut->ptd = NULL;
433
434 return DATA_S_SAMEFORMATETC;
435 }
436
437 STDMETHODIMP wxIDataObject::EnumFormatEtc(DWORD dwDirection,
438 IEnumFORMATETC **ppenumFormatEtc)
439 {
440 wxLogTrace(wxTRACE_OleCalls, wxT("wxIDataObject::EnumFormatEtc"));
441
442 if ( dwDirection == DATADIR_SET ) {
443 // we don't allow setting of data anyhow
444 return E_NOTIMPL;
445 }
446
447 size_t nFormatCount = m_pDataObject->GetFormatCount();
448 wxDataFormat format, *formats;
449 if ( nFormatCount == 1 ) {
450 // this is the most common case, this is why we consider it separately
451 formats = &format;
452 format = m_pDataObject->GetPreferredFormat();
453 }
454 else {
455 // bad luck, build the array with all formats
456 formats = new wxDataFormat[nFormatCount];
457 m_pDataObject->GetAllFormats(formats);
458 }
459
460 wxIEnumFORMATETC *pEnum = new wxIEnumFORMATETC(formats, nFormatCount);
461 pEnum->AddRef();
462 *ppenumFormatEtc = pEnum;
463
464 if ( formats != &format ) {
465 delete [] formats;
466 }
467
468 return S_OK;
469 }
470
471 // advise sink functions (not implemented)
472 STDMETHODIMP wxIDataObject::DAdvise(FORMATETC *pformatetc,
473 DWORD advf,
474 IAdviseSink *pAdvSink,
475 DWORD *pdwConnection)
476 {
477 return OLE_E_ADVISENOTSUPPORTED;
478 }
479
480 STDMETHODIMP wxIDataObject::DUnadvise(DWORD dwConnection)
481 {
482 return OLE_E_ADVISENOTSUPPORTED;
483 }
484
485 STDMETHODIMP wxIDataObject::EnumDAdvise(IEnumSTATDATA **ppenumAdvise)
486 {
487 return OLE_E_ADVISENOTSUPPORTED;
488 }
489
490 // ----------------------------------------------------------------------------
491 // wxDataObject
492 // ----------------------------------------------------------------------------
493
494 wxDataObject::wxDataObject()
495 {
496 m_pIDataObject = new wxIDataObject(this);
497 m_pIDataObject->AddRef();
498 }
499
500 wxDataObject::~wxDataObject()
501 {
502 m_pIDataObject->Release();
503 }
504
505 bool wxDataObject::IsSupportedFormat(const wxDataFormat& format) const
506 {
507 size_t nFormatCount = GetFormatCount();
508 if ( nFormatCount == 1 ) {
509 return format == GetPreferredFormat();
510 }
511 else {
512 wxDataFormat *formats = new wxDataFormat[nFormatCount];
513 GetAllFormats(formats);
514
515 size_t n;
516 for ( n = 0; n < nFormatCount; n++ ) {
517 if ( formats[n] == format )
518 break;
519 }
520
521 delete [] formats;
522
523 // found?
524 return n < nFormatCount;
525 }
526 }
527
528 #ifdef __WXDEBUG__
529 const char *wxDataObject::GetFormatName(wxDataFormat format)
530 {
531 // case 'xxx' is not a valid value for switch of enum 'wxDataFormat'
532 #ifdef __VISUALC__
533 #pragma warning(disable:4063)
534 #endif // VC++
535
536 static char s_szBuf[128];
537 switch ( format ) {
538 case CF_TEXT: return "CF_TEXT";
539 case CF_BITMAP: return "CF_BITMAP";
540 case CF_METAFILEPICT: return "CF_METAFILEPICT";
541 case CF_SYLK: return "CF_SYLK";
542 case CF_DIF: return "CF_DIF";
543 case CF_TIFF: return "CF_TIFF";
544 case CF_OEMTEXT: return "CF_OEMTEXT";
545 case CF_DIB: return "CF_DIB";
546 case CF_PALETTE: return "CF_PALETTE";
547 case CF_PENDATA: return "CF_PENDATA";
548 case CF_RIFF: return "CF_RIFF";
549 case CF_WAVE: return "CF_WAVE";
550 case CF_UNICODETEXT: return "CF_UNICODETEXT";
551 case CF_ENHMETAFILE: return "CF_ENHMETAFILE";
552 case CF_HDROP: return "CF_HDROP";
553 case CF_LOCALE: return "CF_LOCALE";
554 default:
555 sprintf(s_szBuf, "clipboard format %d (unknown)", format);
556 return s_szBuf;
557 }
558
559 #ifdef __VISUALC__
560 #pragma warning(default:4063)
561 #endif // VC++
562 }
563 #endif // Debug
564
565 // ----------------------------------------------------------------------------
566 // wxPrivateDataObject
567 // ----------------------------------------------------------------------------
568
569 wxPrivateDataObject::wxPrivateDataObject()
570 {
571 m_size = 0;
572 m_data = NULL;
573 }
574
575 void wxPrivateDataObject::Free()
576 {
577 if ( m_data )
578 free(m_data);
579 }
580
581 void wxPrivateDataObject::SetData( const void *data, size_t size )
582 {
583 Free();
584
585 m_size = size;
586 m_data = malloc(size);
587
588 memcpy( m_data, data, size );
589 }
590
591 void wxPrivateDataObject::WriteData( void *dest ) const
592 {
593 WriteData( m_data, dest );
594 }
595
596 size_t wxPrivateDataObject::GetSize() const
597 {
598 return m_size;
599 }
600
601 void wxPrivateDataObject::WriteData( const void *data, void *dest ) const
602 {
603 memcpy( dest, data, GetSize() );
604 }
605
606 // ----------------------------------------------------------------------------
607 // wxBitmapDataObject
608 // ----------------------------------------------------------------------------
609
610 // the bitmaps aren't passed by value as other types of data (i.e. by copyign
611 // the data into a global memory chunk and passing it to the clipboard or
612 // another application or whatever), but by handle, so these generic functions
613 // don't make much sense to them.
614
615 size_t wxBitmapDataObject::GetDataSize(const wxDataFormat& format) const
616 {
617 // no data to copy anyhow
618 return 0;
619 }
620
621 void wxBitmapDataObject::GetDataHere(const wxDataFormat& format,
622 void *pBuf) const
623 {
624 // we put a bitmap handle into pBuf
625 *(WXHBITMAP *)pBuf = m_bitmap.GetHBITMAP();
626 }
627
628 // ----------------------------------------------------------------------------
629 // private functions
630 // ----------------------------------------------------------------------------
631
632 #ifdef __WXDEBUG__
633
634 static const char *GetTymedName(DWORD tymed)
635 {
636 static char s_szBuf[128];
637 switch ( tymed ) {
638 case TYMED_HGLOBAL: return "TYMED_HGLOBAL";
639 case TYMED_FILE: return "TYMED_FILE";
640 case TYMED_ISTREAM: return "TYMED_ISTREAM";
641 case TYMED_ISTORAGE: return "TYMED_ISTORAGE";
642 case TYMED_GDI: return "TYMED_GDI";
643 case TYMED_MFPICT: return "TYMED_MFPICT";
644 case TYMED_ENHMF: return "TYMED_ENHMF";
645 default:
646 sprintf(s_szBuf, "type of media format %d (unknown)", tymed);
647 return s_szBuf;
648 }
649 }
650
651 #endif // Debug
652
653 #endif
654