]> git.saurik.com Git - wxWidgets.git/blob - src/msw/ole/dataobj.cpp
d39371cdf4e4400d667bb91b61998420a8ad5f46
[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 static const char *GetTymedName(DWORD tymed);
58
59 // ----------------------------------------------------------------------------
60 // wxIEnumFORMATETC interface implementation
61 // ----------------------------------------------------------------------------
62 class wxIEnumFORMATETC : public IEnumFORMATETC
63 {
64 public:
65 wxIEnumFORMATETC(CLIPFORMAT cf);
66
67 DECLARE_IUNKNOWN_METHODS;
68
69 // IEnumFORMATETC
70 STDMETHODIMP Next(ULONG celt, FORMATETC *rgelt, ULONG *pceltFetched);
71 STDMETHODIMP Skip(ULONG celt);
72 STDMETHODIMP Reset();
73 STDMETHODIMP Clone(IEnumFORMATETC **ppenum);
74
75 private:
76 FORMATETC m_format; // (unique @@@) format we can provide data in
77 ULONG m_nCurrent; // current enum position (currently either 0 or 1)
78 };
79
80 // ----------------------------------------------------------------------------
81 // wxIDataObject implementation of IDataObject interface
82 // ----------------------------------------------------------------------------
83 class wxIDataObject : public IDataObject
84 {
85 public:
86 wxIDataObject(wxDataObject *pDataObject);
87
88 DECLARE_IUNKNOWN_METHODS;
89
90 // IDataObject
91 STDMETHODIMP GetData(FORMATETC *pformatetcIn, STGMEDIUM *pmedium);
92 STDMETHODIMP GetDataHere(FORMATETC *pformatetc, STGMEDIUM *pmedium);
93 STDMETHODIMP QueryGetData(FORMATETC *pformatetc);
94 STDMETHODIMP GetCanonicalFormatEtc(FORMATETC *In, FORMATETC *pOut);
95 STDMETHODIMP SetData(FORMATETC *pfetc, STGMEDIUM *pmedium, BOOL fRelease);
96 STDMETHODIMP EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC **ppenumFEtc);
97 STDMETHODIMP DAdvise(FORMATETC *pfetc, DWORD ad, IAdviseSink *p, DWORD *pdw);
98 STDMETHODIMP DUnadvise(DWORD dwConnection);
99 STDMETHODIMP EnumDAdvise(IEnumSTATDATA **ppenumAdvise);
100
101 private:
102 wxDataObject *m_pDataObject; // pointer to C++ class we belong to
103 };
104
105 // ============================================================================
106 // implementation
107 // ============================================================================
108
109 // ----------------------------------------------------------------------------
110 // wxDataFormat
111 // ----------------------------------------------------------------------------
112
113 void wxDataFormat::SetId(const wxChar *format)
114 {
115 m_format = ::RegisterClipboardFormat(format);
116 if ( !m_format )
117 {
118 wxLogError(_("Couldn't register clipboard format '%s'."), format);
119 }
120 }
121
122 wxString wxDataFormat::GetId() const
123 {
124 static const int max = 256;
125
126 wxString s;
127
128 wxCHECK_MSG( !IsStandard(), s,
129 T("name of predefined format cannot be retrieved") );
130
131 int len = ::GetClipboardFormatName(m_format, s.GetWriteBuf(max), max);
132 s.UngetWriteBuf();
133
134 if ( !len )
135 {
136 wxLogError(_("The clipboard format '%d' doesn't exist."), m_format);
137 }
138
139 return s;
140 }
141
142 // ----------------------------------------------------------------------------
143 // wxIEnumFORMATETC
144 // ----------------------------------------------------------------------------
145
146 BEGIN_IID_TABLE(wxIEnumFORMATETC)
147 ADD_IID(Unknown)
148 ADD_IID(EnumFORMATETC)
149 END_IID_TABLE;
150
151 IMPLEMENT_IUNKNOWN_METHODS(wxIEnumFORMATETC)
152
153 wxIEnumFORMATETC::wxIEnumFORMATETC(CLIPFORMAT cf)
154 {
155 m_format.cfFormat = cf;
156 m_format.ptd = NULL;
157 m_format.dwAspect = DVASPECT_CONTENT;
158 m_format.lindex = -1;
159 m_format.tymed = TYMED_HGLOBAL;
160 m_cRef = 0;
161 m_nCurrent = 0;
162 }
163
164 STDMETHODIMP wxIEnumFORMATETC::Next(ULONG celt,
165 FORMATETC *rgelt,
166 ULONG *pceltFetched)
167 {
168 wxLogTrace(T("wxIEnumFORMATETC::Next"));
169
170 if ( celt > 1 )
171 return S_FALSE;
172
173 if ( m_nCurrent == 0 ) {
174 *rgelt = m_format;
175 m_nCurrent++;
176
177 return S_OK;
178 }
179 else
180 return S_FALSE;
181 }
182
183 STDMETHODIMP wxIEnumFORMATETC::Skip(ULONG celt)
184 {
185 wxLogTrace(T("wxIEnumFORMATETC::Skip"));
186
187 if ( m_nCurrent == 0 )
188 m_nCurrent++;
189
190 return S_FALSE;
191 }
192
193 STDMETHODIMP wxIEnumFORMATETC::Reset()
194 {
195 wxLogTrace(T("wxIEnumFORMATETC::Reset"));
196
197 m_nCurrent = 0;
198
199 return S_OK;
200 }
201
202 STDMETHODIMP wxIEnumFORMATETC::Clone(IEnumFORMATETC **ppenum)
203 {
204 wxLogTrace(T("wxIEnumFORMATETC::Clone"));
205
206 wxIEnumFORMATETC *pNew = new wxIEnumFORMATETC(m_format.cfFormat);
207 pNew->AddRef();
208 *ppenum = pNew;
209
210 return S_OK;
211 }
212
213 // ----------------------------------------------------------------------------
214 // wxIDataObject
215 // ----------------------------------------------------------------------------
216
217 BEGIN_IID_TABLE(wxIDataObject)
218 ADD_IID(Unknown)
219 ADD_IID(DataObject)
220 END_IID_TABLE;
221
222 IMPLEMENT_IUNKNOWN_METHODS(wxIDataObject)
223
224 wxIDataObject::wxIDataObject(wxDataObject *pDataObject)
225 {
226 m_cRef = 0;
227 m_pDataObject = pDataObject;
228 }
229
230 // get data functions
231 STDMETHODIMP wxIDataObject::GetData(FORMATETC *pformatetcIn, STGMEDIUM *pmedium)
232 {
233 wxLogTrace(T("wxIDataObject::GetData"));
234
235 // is data is in our format?
236 HRESULT hr = QueryGetData(pformatetcIn);
237 if ( FAILED(hr) )
238 return hr;
239
240 // alloc memory
241 HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE,
242 m_pDataObject->GetDataSize());
243 if ( hGlobal == NULL ) {
244 wxLogLastError("GlobalAlloc");
245 return E_OUTOFMEMORY;
246 }
247
248 // copy data
249 pmedium->tymed = TYMED_HGLOBAL;
250 pmedium->hGlobal = hGlobal;
251 pmedium->pUnkForRelease = NULL;
252
253 hr = GetDataHere(pformatetcIn, pmedium);
254 if ( FAILED(hr) ) {
255 GlobalFree(hGlobal);
256 return hr;
257 }
258
259 return S_OK;
260 }
261
262 STDMETHODIMP wxIDataObject::GetDataHere(FORMATETC *pformatetc,
263 STGMEDIUM *pmedium)
264 {
265 wxLogTrace(T("wxIDataObject::GetDataHere"));
266
267 // put data in caller provided medium
268 if ( pmedium->tymed != TYMED_HGLOBAL )
269 return DV_E_TYMED;
270
271 // copy data
272 void *pBuf = GlobalLock(pmedium->hGlobal);
273 if ( pBuf == NULL ) {
274 wxLogLastError(T("GlobalLock"));
275 return E_OUTOFMEMORY;
276 }
277
278 m_pDataObject->GetDataHere(pBuf);
279
280 GlobalUnlock(pmedium->hGlobal);
281
282 return S_OK;
283 }
284
285 // set data functions (not implemented)
286 STDMETHODIMP wxIDataObject::SetData(FORMATETC *pformatetc,
287 STGMEDIUM *pmedium,
288 BOOL fRelease)
289 {
290 wxLogTrace(T("wxIDataObject::SetData"));
291 return E_NOTIMPL;
292 }
293
294 // information functions
295 STDMETHODIMP wxIDataObject::QueryGetData(FORMATETC *pformatetc)
296 {
297 // do we accept data in this format?
298 if ( pformatetc == NULL ) {
299 wxLogTrace(T("wxIDataObject::QueryGetData: invalid ptr."));
300 return E_INVALIDARG;
301 }
302
303 // the only one allowed by current COM implementation
304 if ( pformatetc->lindex != -1 ) {
305 wxLogTrace(T("wxIDataObject::QueryGetData: bad lindex %d"),
306 pformatetc->lindex);
307 return DV_E_LINDEX;
308 }
309
310 // we don't support anything other (THUMBNAIL, ICON, DOCPRINT...)
311 if ( pformatetc->dwAspect != DVASPECT_CONTENT ) {
312 wxLogTrace(T("wxIDataObject::QueryGetData: bad dwAspect %d"),
313 pformatetc->dwAspect);
314 return DV_E_DVASPECT;
315 }
316
317 // @@ we only transfer data by global memory (bad for large amounts of it!)
318 if ( !(pformatetc->tymed & TYMED_HGLOBAL) ) {
319 wxLogTrace(T("wxIDataObject::QueryGetData: %s != TYMED_HGLOBAL."),
320 GetTymedName(pformatetc->tymed));
321 return DV_E_TYMED;
322 }
323
324 // and now check the type of data requested
325 if ( m_pDataObject->IsSupportedFormat((wxDataFormatId)pformatetc->cfFormat) ) {
326 wxLogTrace(T("wxIDataObject::QueryGetData: %s ok"),
327 wxDataObject::GetFormatName((wxDataFormatId)pformatetc->cfFormat));
328 return S_OK;
329 }
330 else {
331 wxLogTrace(T("wxIDataObject::QueryGetData: %s unsupported"),
332 wxDataObject::GetFormatName((wxDataFormatId)pformatetc->cfFormat));
333 return DV_E_FORMATETC;
334 }
335 }
336
337 STDMETHODIMP wxIDataObject::GetCanonicalFormatEtc(FORMATETC *pFormatetcIn,
338 FORMATETC *pFormatetcOut)
339 {
340 wxLogTrace(T("wxIDataObject::GetCanonicalFormatEtc"));
341
342 // @@ implementation is trivial, we might want something better here
343 if ( pFormatetcOut != NULL )
344 pFormatetcOut->ptd = NULL;
345 return DATA_S_SAMEFORMATETC;
346 }
347
348 STDMETHODIMP wxIDataObject::EnumFormatEtc(DWORD dwDirection,
349 IEnumFORMATETC **ppenumFormatEtc)
350 {
351 wxLogTrace(T("wxIDataObject::EnumFormatEtc"));
352
353 if ( dwDirection == DATADIR_SET ) {
354 // we don't allow setting of data anyhow
355 return E_NOTIMPL;
356 }
357
358 wxIEnumFORMATETC *pEnum =
359 new wxIEnumFORMATETC(m_pDataObject->GetPreferredFormat());
360 pEnum->AddRef();
361 *ppenumFormatEtc = pEnum;
362
363 return S_OK;
364 }
365
366 // advise sink functions (not implemented)
367 STDMETHODIMP wxIDataObject::DAdvise(FORMATETC *pformatetc,
368 DWORD advf,
369 IAdviseSink *pAdvSink,
370 DWORD *pdwConnection)
371 {
372 return OLE_E_ADVISENOTSUPPORTED;
373 }
374
375 STDMETHODIMP wxIDataObject::DUnadvise(DWORD dwConnection)
376 {
377 return OLE_E_ADVISENOTSUPPORTED;
378 }
379
380 STDMETHODIMP wxIDataObject::EnumDAdvise(IEnumSTATDATA **ppenumAdvise)
381 {
382 return OLE_E_ADVISENOTSUPPORTED;
383 }
384
385 // ----------------------------------------------------------------------------
386 // wxDataObject
387 // ----------------------------------------------------------------------------
388
389 wxDataObject::wxDataObject()
390 {
391 m_pIDataObject = new wxIDataObject(this);
392 m_pIDataObject->AddRef();
393 }
394
395 wxDataObject::~wxDataObject()
396 {
397 m_pIDataObject->Release();
398 }
399
400 const char *wxDataObject::GetFormatName(wxDataFormat format)
401 {
402 #ifdef __WXDEBUG__
403 // case 'xxx' is not a valid value for switch of enum 'wxDataFormat'
404 #ifdef __VISUALC__
405 #pragma warning(disable:4063)
406 #endif // VC++
407
408 static char s_szBuf[128];
409 switch ( format ) {
410 case CF_TEXT: return "CF_TEXT(";
411 case CF_BITMAP: return "CF_BITMAP";
412 case CF_METAFILEPICT: return "CF_METAFILEPICT(";
413 case CF_SYLK: return "CF_SYLK";
414 case CF_DIF: return "CF_DIF";
415 case CF_TIFF: return "CF_TIFF";
416 case CF_OEMTEXT: return "CF_OEMTEXT(";
417 case CF_DIB: return "CF_DIB";
418 case CF_PALETTE: return "CF_PALETTE";
419 case CF_PENDATA: return "CF_PENDATA";
420 case CF_RIFF: return "CF_RIFF";
421 case CF_WAVE: return "CF_WAVE";
422 case CF_UNICODETEXT: return "CF_UNICODETEXT(";
423 case CF_ENHMETAFILE: return "CF_ENHMETAFILE";
424 case CF_HDROP: return "CF_HDROP";
425 case CF_LOCALE: return "CF_LOCALE";
426 default:
427 sprintf(s_szBuf, "clipboard format %d (unknown)", format);
428 return s_szBuf;
429 }
430
431 #ifdef __VISUALC__
432 #pragma warning(default:4063)
433 #endif // VC++
434
435 #else // !Debug
436 return "";
437 #endif // Debug
438 }
439
440 // ----------------------------------------------------------------------------
441 // wxPrivateDataObject
442 // ----------------------------------------------------------------------------
443
444 wxPrivateDataObject::wxPrivateDataObject()
445 {
446 m_size = 0;
447 m_data = NULL;
448 }
449
450 void wxPrivateDataObject::Free()
451 {
452 if ( m_data )
453 free(m_data);
454 }
455
456 void wxPrivateDataObject::SetData( const void *data, size_t size )
457 {
458 Free();
459
460 m_size = size;
461 m_data = malloc(size);
462
463 memcpy( m_data, data, size );
464 }
465
466 void wxPrivateDataObject::WriteData( void *dest ) const
467 {
468 WriteData( m_data, dest );
469 }
470
471 size_t wxPrivateDataObject::GetSize() const
472 {
473 return m_size;
474 }
475
476 void wxPrivateDataObject::WriteData( const void *data, void *dest ) const
477 {
478 memcpy( dest, data, GetSize() );
479 }
480
481 // ----------------------------------------------------------------------------
482 // private functions
483 // ----------------------------------------------------------------------------
484 static const char *GetTymedName(DWORD tymed)
485 {
486 static char s_szBuf[128];
487 switch ( tymed ) {
488 case TYMED_HGLOBAL: return "TYMED_HGLOBAL";
489 case TYMED_FILE: return "TYMED_FILE";
490 case TYMED_ISTREAM: return "TYMED_ISTREAM";
491 case TYMED_ISTORAGE: return "TYMED_ISTORAGE";
492 case TYMED_GDI: return "TYMED_GDI";
493 case TYMED_MFPICT: return "TYMED_MFPICT(";
494 case TYMED_ENHMF: return "TYMED_ENHMF";
495 default:
496 sprintf(s_szBuf, "type of media format %d (unknown)", tymed);
497 return s_szBuf;
498 }
499 }
500
501 // TODO: OLE parts of wxBitmap/File/MetafileDataObject
502
503 #endif
504