]> git.saurik.com Git - wxWidgets.git/blame - src/msw/ole/dataobj.cpp
Fix to prevent Assert when there is an empty string in a combobox/choice.
[wxWidgets.git] / src / msw / ole / dataobj.cpp
CommitLineData
269a5a34
VZ
1///////////////////////////////////////////////////////////////////////////////
2// Name: msw/ole/dataobj.cpp
3// Purpose: implementation of wx[I]DataObject class
4// Author: Vadim Zeitlin
3f4a0c5b 5// Modified by:
269a5a34
VZ
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
7dee726c
RS
30#ifndef WX_PRECOMP
31#include "wx/intl.h"
32#endif
3f480da3 33#include "wx/defs.h"
5260b1c5 34
7dee726c 35#if defined(__WIN32__) && !defined(__GNUWIN32__) || defined(wxUSE_NORLANDER_HEADERS)
5260b1c5 36
3f480da3
VZ
37#include "wx/log.h"
38#include "wx/dataobj.h"
17b74d79
JS
39
40#include <windows.h>
7dee726c
RS
41#ifdef wxUSE_NORLANDER_HEADERS
42 #include <ole2.h>
43#endif
17b74d79 44#include <oleauto.h>
269a5a34 45
7dee726c 46#ifndef __WIN32__
269a5a34
VZ
47 #include <ole2.h>
48 #include <olestd.h>
49#endif
50
3f480da3 51#include "wx/msw/ole/oleutils.h"
17b74d79 52
269a5a34
VZ
53// ----------------------------------------------------------------------------
54// functions
55// ----------------------------------------------------------------------------
56
40e1a9c0 57static const char *GetTymedName(DWORD tymed);
269a5a34
VZ
58
59// ----------------------------------------------------------------------------
60// wxIEnumFORMATETC interface implementation
61// ----------------------------------------------------------------------------
62class wxIEnumFORMATETC : public IEnumFORMATETC
63{
64public:
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
75private:
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// ----------------------------------------------------------------------------
83class wxIDataObject : public IDataObject
84{
85public:
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
101private:
102 wxDataObject *m_pDataObject; // pointer to C++ class we belong to
103};
104
105// ============================================================================
106// implementation
107// ============================================================================
108
3f480da3
VZ
109// ----------------------------------------------------------------------------
110// wxDataFormat
111// ----------------------------------------------------------------------------
112
113void 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
122wxString 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
269a5a34
VZ
142// ----------------------------------------------------------------------------
143// wxIEnumFORMATETC
144// ----------------------------------------------------------------------------
145
146BEGIN_IID_TABLE(wxIEnumFORMATETC)
147 ADD_IID(Unknown)
148 ADD_IID(EnumFORMATETC)
149END_IID_TABLE;
150
151IMPLEMENT_IUNKNOWN_METHODS(wxIEnumFORMATETC)
152
153wxIEnumFORMATETC::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
164STDMETHODIMP wxIEnumFORMATETC::Next(ULONG celt,
165 FORMATETC *rgelt,
166 ULONG *pceltFetched)
167{
5f8e1c16 168 wxLogTrace(_T("wxIEnumFORMATETC::Next"));
269a5a34
VZ
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
183STDMETHODIMP wxIEnumFORMATETC::Skip(ULONG celt)
184{
5f8e1c16 185 wxLogTrace(_T("wxIEnumFORMATETC::Skip"));
269a5a34
VZ
186
187 if ( m_nCurrent == 0 )
188 m_nCurrent++;
189
190 return S_FALSE;
191}
192
193STDMETHODIMP wxIEnumFORMATETC::Reset()
194{
5f8e1c16 195 wxLogTrace(_T("wxIEnumFORMATETC::Reset"));
269a5a34
VZ
196
197 m_nCurrent = 0;
198
199 return S_OK;
200}
201
202STDMETHODIMP wxIEnumFORMATETC::Clone(IEnumFORMATETC **ppenum)
203{
5f8e1c16 204 wxLogTrace(_T("wxIEnumFORMATETC::Clone"));
269a5a34
VZ
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
217BEGIN_IID_TABLE(wxIDataObject)
218 ADD_IID(Unknown)
219 ADD_IID(DataObject)
220END_IID_TABLE;
221
222IMPLEMENT_IUNKNOWN_METHODS(wxIDataObject)
223
224wxIDataObject::wxIDataObject(wxDataObject *pDataObject)
225{
226 m_cRef = 0;
227 m_pDataObject = pDataObject;
228}
229
230// get data functions
231STDMETHODIMP wxIDataObject::GetData(FORMATETC *pformatetcIn, STGMEDIUM *pmedium)
232{
5f8e1c16 233 wxLogTrace(_T("wxIDataObject::GetData"));
269a5a34
VZ
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
262STDMETHODIMP wxIDataObject::GetDataHere(FORMATETC *pformatetc,
263 STGMEDIUM *pmedium)
264{
5f8e1c16 265 wxLogTrace(_T("wxIDataObject::GetDataHere"));
269a5a34
VZ
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 ) {
5f8e1c16 274 wxLogLastError(_T("GlobalLock"));
269a5a34
VZ
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)
286STDMETHODIMP wxIDataObject::SetData(FORMATETC *pformatetc,
287 STGMEDIUM *pmedium,
288 BOOL fRelease)
289{
5f8e1c16 290 wxLogTrace(_T("wxIDataObject::SetData"));
269a5a34
VZ
291 return E_NOTIMPL;
292}
293
294// information functions
295STDMETHODIMP wxIDataObject::QueryGetData(FORMATETC *pformatetc)
296{
297 // do we accept data in this format?
298 if ( pformatetc == NULL ) {
5f8e1c16 299 wxLogTrace(_T("wxIDataObject::QueryGetData: invalid ptr."));
269a5a34
VZ
300 return E_INVALIDARG;
301 }
302
303 // the only one allowed by current COM implementation
304 if ( pformatetc->lindex != -1 ) {
5f8e1c16 305 wxLogTrace(_T("wxIDataObject::QueryGetData: bad lindex %d"),
269a5a34
VZ
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 ) {
5f8e1c16 312 wxLogTrace(_T("wxIDataObject::QueryGetData: bad dwAspect %d"),
269a5a34
VZ
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) ) {
5f8e1c16 319 wxLogTrace(_T("wxIDataObject::QueryGetData: %s != TYMED_HGLOBAL."),
269a5a34
VZ
320 GetTymedName(pformatetc->tymed));
321 return DV_E_TYMED;
322 }
323
324 // and now check the type of data requested
3f480da3 325 if ( m_pDataObject->IsSupportedFormat((wxDataFormatId)pformatetc->cfFormat) ) {
5f8e1c16 326 wxLogTrace(_T("wxIDataObject::QueryGetData: %s ok"),
3f480da3 327 wxDataObject::GetFormatName((wxDataFormatId)pformatetc->cfFormat));
269a5a34
VZ
328 return S_OK;
329 }
330 else {
5f8e1c16 331 wxLogTrace(_T("wxIDataObject::QueryGetData: %s unsupported"),
3f480da3 332 wxDataObject::GetFormatName((wxDataFormatId)pformatetc->cfFormat));
269a5a34
VZ
333 return DV_E_FORMATETC;
334 }
335}
336
337STDMETHODIMP wxIDataObject::GetCanonicalFormatEtc(FORMATETC *pFormatetcIn,
338 FORMATETC *pFormatetcOut)
339{
5f8e1c16 340 wxLogTrace(_T("wxIDataObject::GetCanonicalFormatEtc"));
269a5a34
VZ
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
348STDMETHODIMP wxIDataObject::EnumFormatEtc(DWORD dwDirection,
349 IEnumFORMATETC **ppenumFormatEtc)
350{
5f8e1c16 351 wxLogTrace(_T("wxIDataObject::EnumFormatEtc"));
269a5a34
VZ
352
353 if ( dwDirection == DATADIR_SET ) {
354 // we don't allow setting of data anyhow
355 return E_NOTIMPL;
356 }
357
3f4a0c5b 358 wxIEnumFORMATETC *pEnum =
269a5a34
VZ
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)
367STDMETHODIMP wxIDataObject::DAdvise(FORMATETC *pformatetc,
368 DWORD advf,
369 IAdviseSink *pAdvSink,
370 DWORD *pdwConnection)
371{
372 return OLE_E_ADVISENOTSUPPORTED;
373}
374
375STDMETHODIMP wxIDataObject::DUnadvise(DWORD dwConnection)
376{
377 return OLE_E_ADVISENOTSUPPORTED;
378}
379
380STDMETHODIMP wxIDataObject::EnumDAdvise(IEnumSTATDATA **ppenumAdvise)
381{
382 return OLE_E_ADVISENOTSUPPORTED;
383}
384
385// ----------------------------------------------------------------------------
386// wxDataObject
387// ----------------------------------------------------------------------------
388
389wxDataObject::wxDataObject()
390{
391 m_pIDataObject = new wxIDataObject(this);
392 m_pIDataObject->AddRef();
393}
394
395wxDataObject::~wxDataObject()
396{
397 m_pIDataObject->Release();
398}
399
269a5a34
VZ
400const char *wxDataObject::GetFormatName(wxDataFormat format)
401{
b2aef89b 402#ifdef __WXDEBUG__
fd3f686c 403 // case 'xxx' is not a valid value for switch of enum 'wxDataFormat'
3f4a0c5b 404 #ifdef __VISUALC__
fd3f686c
VZ
405 #pragma warning(disable:4063)
406 #endif // VC++
407
269a5a34
VZ
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 }
fd3f686c 430
3f4a0c5b 431 #ifdef __VISUALC__
fd3f686c
VZ
432 #pragma warning(default:4063)
433 #endif // VC++
434
435#else // !Debug
40e1a9c0 436 return "";
fd3f686c 437#endif // Debug
269a5a34
VZ
438}
439
3f480da3
VZ
440// ----------------------------------------------------------------------------
441// wxPrivateDataObject
442// ----------------------------------------------------------------------------
443
444wxPrivateDataObject::wxPrivateDataObject()
445{
446 m_size = 0;
447 m_data = NULL;
448}
449
450void wxPrivateDataObject::Free()
451{
452 if ( m_data )
453 free(m_data);
454}
455
456void 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
466void wxPrivateDataObject::WriteData( void *dest ) const
467{
468 WriteData( m_data, dest );
469}
470
471size_t wxPrivateDataObject::GetSize() const
472{
473 return m_size;
474}
475
476void wxPrivateDataObject::WriteData( const void *data, void *dest ) const
477{
478 memcpy( dest, data, GetSize() );
479}
480
269a5a34
VZ
481// ----------------------------------------------------------------------------
482// private functions
483// ----------------------------------------------------------------------------
484static 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}
5260b1c5 500
2845ddc2
JS
501// TODO: OLE parts of wxBitmap/File/MetafileDataObject
502
5260b1c5
JS
503#endif
504