]> git.saurik.com Git - wxWidgets.git/blob - src/msw/ole/dataobj.cpp
Crash fix for inserting text into a buffer without an associated control
[wxWidgets.git] / src / msw / ole / dataobj.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/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 // Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
8 // Licence: wxWindows licence
9 ///////////////////////////////////////////////////////////////////////////////
10
11 // ============================================================================
12 // declarations
13 // ============================================================================
14
15 // ----------------------------------------------------------------------------
16 // headers
17 // ----------------------------------------------------------------------------
18
19 // For compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
21
22 #if defined(__BORLANDC__)
23 #pragma hdrstop
24 #endif
25
26 #ifndef WX_PRECOMP
27 #include "wx/intl.h"
28 #include "wx/log.h"
29 #include "wx/utils.h"
30 #include "wx/wxcrtvararg.h"
31 #endif
32
33 #include "wx/dataobj.h"
34
35 #if wxUSE_OLE && defined(__WIN32__) && !defined(__GNUWIN32_OLD__)
36
37 #include "wx/scopedarray.h"
38 #include "wx/vector.h"
39 #include "wx/msw/private.h" // includes <windows.h>
40
41 #ifdef __WXWINCE__
42 #include <winreg.h>
43 #endif
44
45 // for some compilers, the entire ole2.h must be included, not only oleauto.h
46 #if wxUSE_NORLANDER_HEADERS || defined(__WATCOMC__) || defined(__WXWINCE__)
47 #include <ole2.h>
48 #endif
49
50 #include <oleauto.h>
51 #include <shlobj.h>
52
53 #include "wx/msw/ole/oleutils.h"
54
55 #include "wx/msw/dib.h"
56
57 #ifndef CFSTR_SHELLURL
58 #define CFSTR_SHELLURL wxT("UniformResourceLocator")
59 #endif
60
61 // ----------------------------------------------------------------------------
62 // functions
63 // ----------------------------------------------------------------------------
64
65 #if wxDEBUG_LEVEL
66 static const wxChar *GetTymedName(DWORD tymed);
67 #else // !wxDEBUG_LEVEL
68 #define GetTymedName(tymed) wxEmptyString
69 #endif // wxDEBUG_LEVEL/!wxDEBUG_LEVEL
70
71 namespace
72 {
73
74 wxDataFormat HtmlFormatFixup(wxDataFormat format)
75 {
76 // Since the HTML format is dynamically registered, the wxDF_HTML
77 // format does not match the native constant in the way other formats do,
78 // so for the format checks below to work, we must change the native
79 // id to the wxDF_HTML constant.
80 wxChar s_szBuf[256];
81 if (::GetClipboardFormatName(format, s_szBuf, WXSIZEOF(s_szBuf)))
82 {
83 if (s_szBuf == wxString("HTML Format"))
84 format = wxDF_HTML;
85 }
86 return format;
87 }
88
89 // helper function for wxCopyStgMedium()
90 HGLOBAL wxGlobalClone(HGLOBAL hglobIn)
91 {
92 HGLOBAL hglobOut = NULL;
93
94 LPVOID pvIn = GlobalLock(hglobIn);
95 if (pvIn)
96 {
97 SIZE_T cb = GlobalSize(hglobIn);
98 hglobOut = GlobalAlloc(GMEM_FIXED, cb);
99 if (hglobOut)
100 {
101 CopyMemory(hglobOut, pvIn, cb);
102 }
103 GlobalUnlock(hglobIn);
104 }
105
106 return hglobOut;
107 }
108
109 // Copies the given STGMEDIUM structure.
110 //
111 // This is an local implementation of the function with the same name in
112 // urlmon.lib but to use that function would require linking with urlmon.lib
113 // and we don't want to require it, so simple reimplement it here.
114 HRESULT wxCopyStgMedium(const STGMEDIUM *pmediumIn, STGMEDIUM *pmediumOut)
115 {
116 HRESULT hres = S_OK;
117 STGMEDIUM stgmOut = *pmediumIn;
118
119 if (pmediumIn->pUnkForRelease == NULL &&
120 !(pmediumIn->tymed & (TYMED_ISTREAM | TYMED_ISTORAGE)))
121 {
122 // Object needs to be cloned.
123 if (pmediumIn->tymed == TYMED_HGLOBAL)
124 {
125 stgmOut.hGlobal = wxGlobalClone(pmediumIn->hGlobal);
126 if (!stgmOut.hGlobal)
127 {
128 hres = E_OUTOFMEMORY;
129 }
130 }
131 else
132 {
133 hres = DV_E_TYMED; // Don't know how to clone GDI objects.
134 }
135 }
136
137 if ( SUCCEEDED(hres) )
138 {
139 switch ( stgmOut.tymed )
140 {
141 case TYMED_ISTREAM:
142 stgmOut.pstm->AddRef();
143 break;
144
145 case TYMED_ISTORAGE:
146 stgmOut.pstg->AddRef();
147 break;
148 }
149
150 if ( stgmOut.pUnkForRelease )
151 stgmOut.pUnkForRelease->AddRef();
152
153 *pmediumOut = stgmOut;
154 }
155
156 return hres;
157 }
158
159 } // anonymous namespace
160
161 // ----------------------------------------------------------------------------
162 // wxIEnumFORMATETC interface implementation
163 // ----------------------------------------------------------------------------
164
165 class wxIEnumFORMATETC : public IEnumFORMATETC
166 {
167 public:
168 wxIEnumFORMATETC(const wxDataFormat* formats, ULONG nCount);
169 virtual ~wxIEnumFORMATETC() { delete [] m_formats; }
170
171 // IEnumFORMATETC
172 STDMETHODIMP Next(ULONG celt, FORMATETC *rgelt, ULONG *pceltFetched);
173 STDMETHODIMP Skip(ULONG celt);
174 STDMETHODIMP Reset();
175 STDMETHODIMP Clone(IEnumFORMATETC **ppenum);
176
177 DECLARE_IUNKNOWN_METHODS;
178
179 private:
180 CLIPFORMAT *m_formats; // formats we can provide data in
181 ULONG m_nCount, // number of formats we support
182 m_nCurrent; // current enum position
183
184 wxDECLARE_NO_COPY_CLASS(wxIEnumFORMATETC);
185 };
186
187 // ----------------------------------------------------------------------------
188 // wxIDataObject implementation of IDataObject interface
189 // ----------------------------------------------------------------------------
190
191 class wxIDataObject : public IDataObject
192 {
193 public:
194 wxIDataObject(wxDataObject *pDataObject);
195 virtual ~wxIDataObject();
196
197 // normally, wxDataObject controls our lifetime (i.e. we're deleted when it
198 // is), but in some cases, the situation is reversed, that is we delete it
199 // when this object is deleted - setting this flag enables such logic
200 void SetDeleteFlag() { m_mustDelete = true; }
201
202 // IDataObject
203 STDMETHODIMP GetData(FORMATETC *pformatetcIn, STGMEDIUM *pmedium);
204 STDMETHODIMP GetDataHere(FORMATETC *pformatetc, STGMEDIUM *pmedium);
205 STDMETHODIMP QueryGetData(FORMATETC *pformatetc);
206 STDMETHODIMP GetCanonicalFormatEtc(FORMATETC *In, FORMATETC *pOut);
207 STDMETHODIMP SetData(FORMATETC *pfetc, STGMEDIUM *pmedium, BOOL fRelease);
208 STDMETHODIMP EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC **ppenumFEtc);
209 STDMETHODIMP DAdvise(FORMATETC *pfetc, DWORD ad, IAdviseSink *p, DWORD *pdw);
210 STDMETHODIMP DUnadvise(DWORD dwConnection);
211 STDMETHODIMP EnumDAdvise(IEnumSTATDATA **ppenumAdvise);
212
213 DECLARE_IUNKNOWN_METHODS;
214
215 private:
216 wxDataObject *m_pDataObject; // pointer to C++ class we belong to
217
218 bool m_mustDelete;
219
220 wxDECLARE_NO_COPY_CLASS(wxIDataObject);
221
222 // The following code is need to be able to store system data the operating
223 // system is using for it own purposes, e.g. drag images.
224
225 class SystemDataEntry
226 {
227 public:
228 // Ctor takes ownership of the pointers.
229 SystemDataEntry(FORMATETC *pformatetc, STGMEDIUM *pmedium)
230 : pformatetc(pformatetc), pmedium(pmedium)
231 {
232 }
233
234 ~SystemDataEntry()
235 {
236 delete pformatetc;
237 delete pmedium;
238 }
239
240 FORMATETC *pformatetc;
241 STGMEDIUM *pmedium;
242 };
243 typedef wxVector<SystemDataEntry*> SystemData;
244
245 // get system data specified by the given format
246 bool GetSystemData(wxDataFormat format, STGMEDIUM*) const;
247
248 // determines if the data object contains system data specified by the given format.
249 bool HasSystemData(wxDataFormat format) const;
250
251 // save system data
252 HRESULT SaveSystemData(FORMATETC*, STGMEDIUM*, BOOL fRelease);
253
254 // container for system data
255 SystemData m_systemData;
256 };
257
258 bool
259 wxIDataObject::GetSystemData(wxDataFormat format, STGMEDIUM *pmedium) const
260 {
261 for ( SystemData::const_iterator it = m_systemData.begin();
262 it != m_systemData.end();
263 ++it )
264 {
265 FORMATETC* formatEtc = (*it)->pformatetc;
266 if ( formatEtc->cfFormat == format )
267 {
268 wxCopyStgMedium((*it)->pmedium, pmedium);
269 return true;
270 }
271 }
272
273 return false;
274 }
275
276 bool
277 wxIDataObject::HasSystemData(wxDataFormat format) const
278 {
279 for ( SystemData::const_iterator it = m_systemData.begin();
280 it != m_systemData.end();
281 ++it )
282 {
283 FORMATETC* formatEtc = (*it)->pformatetc;
284 if ( formatEtc->cfFormat == format )
285 return true;
286 }
287
288 return false;
289 }
290
291 // save system data
292 HRESULT
293 wxIDataObject::SaveSystemData(FORMATETC *pformatetc,
294 STGMEDIUM *pmedium,
295 BOOL fRelease)
296 {
297 if ( pformatetc == NULL || pmedium == NULL )
298 return E_INVALIDARG;
299
300 // remove entry if already available
301 for ( SystemData::iterator it = m_systemData.begin();
302 it != m_systemData.end();
303 ++it )
304 {
305 if ( pformatetc->tymed & (*it)->pformatetc->tymed &&
306 pformatetc->dwAspect == (*it)->pformatetc->dwAspect &&
307 pformatetc->cfFormat == (*it)->pformatetc->cfFormat )
308 {
309 delete (*it);
310 m_systemData.erase(it);
311 break;
312 }
313 }
314
315 // create new format/medium
316 FORMATETC* pnewformatEtc = new FORMATETC;
317 STGMEDIUM* pnewmedium = new STGMEDIUM;
318
319 wxZeroMemory(*pnewformatEtc);
320 wxZeroMemory(*pnewmedium);
321
322 // copy format
323 *pnewformatEtc = *pformatetc;
324
325 // copy or take ownerschip of medium
326 if ( fRelease )
327 *pnewmedium = *pmedium;
328 else
329 wxCopyStgMedium(pmedium, pnewmedium);
330
331 // save entry
332 m_systemData.push_back(new SystemDataEntry(pnewformatEtc, pnewmedium));
333
334 return S_OK;
335 }
336
337 // ============================================================================
338 // implementation
339 // ============================================================================
340
341 // ----------------------------------------------------------------------------
342 // wxDataFormat
343 // ----------------------------------------------------------------------------
344
345 void wxDataFormat::SetId(const wxString& format)
346 {
347 m_format = (wxDataFormat::NativeFormat)::RegisterClipboardFormat(format.t_str());
348 if ( !m_format )
349 {
350 wxLogError(_("Couldn't register clipboard format '%s'."), format);
351 }
352 }
353
354 wxString wxDataFormat::GetId() const
355 {
356 static const int max = 256;
357
358 wxString s;
359
360 wxCHECK_MSG( !IsStandard(), s,
361 wxT("name of predefined format cannot be retrieved") );
362
363 int len = ::GetClipboardFormatName(m_format, wxStringBuffer(s, max), max);
364
365 if ( !len )
366 {
367 wxLogError(_("The clipboard format '%d' doesn't exist."), m_format);
368 return wxEmptyString;
369 }
370
371 return s;
372 }
373
374 // ----------------------------------------------------------------------------
375 // wxIEnumFORMATETC
376 // ----------------------------------------------------------------------------
377
378 BEGIN_IID_TABLE(wxIEnumFORMATETC)
379 ADD_IID(Unknown)
380 ADD_IID(EnumFORMATETC)
381 END_IID_TABLE;
382
383 IMPLEMENT_IUNKNOWN_METHODS(wxIEnumFORMATETC)
384
385 wxIEnumFORMATETC::wxIEnumFORMATETC(const wxDataFormat *formats, ULONG nCount)
386 {
387 m_nCurrent = 0;
388 m_nCount = nCount;
389 m_formats = new CLIPFORMAT[nCount];
390 for ( ULONG n = 0; n < nCount; n++ ) {
391 if (formats[n].GetFormatId() != wxDF_HTML)
392 m_formats[n] = formats[n].GetFormatId();
393 else
394 m_formats[n] = ::RegisterClipboardFormat(wxT("HTML Format"));
395 }
396 }
397
398 STDMETHODIMP wxIEnumFORMATETC::Next(ULONG celt,
399 FORMATETC *rgelt,
400 ULONG *pceltFetched)
401 {
402 wxLogTrace(wxTRACE_OleCalls, wxT("wxIEnumFORMATETC::Next"));
403
404 ULONG numFetched = 0;
405 while (m_nCurrent < m_nCount && numFetched < celt) {
406 FORMATETC format;
407 format.cfFormat = m_formats[m_nCurrent++];
408 format.ptd = NULL;
409 format.dwAspect = DVASPECT_CONTENT;
410 format.lindex = -1;
411 format.tymed = TYMED_HGLOBAL;
412
413 *rgelt++ = format;
414 numFetched++;
415 }
416
417 if (pceltFetched)
418 *pceltFetched = numFetched;
419
420 return numFetched == celt ? S_OK : S_FALSE;
421 }
422
423 STDMETHODIMP wxIEnumFORMATETC::Skip(ULONG celt)
424 {
425 wxLogTrace(wxTRACE_OleCalls, wxT("wxIEnumFORMATETC::Skip"));
426
427 m_nCurrent += celt;
428 if ( m_nCurrent < m_nCount )
429 return S_OK;
430
431 // no, can't skip this many elements
432 m_nCurrent -= celt;
433
434 return S_FALSE;
435 }
436
437 STDMETHODIMP wxIEnumFORMATETC::Reset()
438 {
439 wxLogTrace(wxTRACE_OleCalls, wxT("wxIEnumFORMATETC::Reset"));
440
441 m_nCurrent = 0;
442
443 return S_OK;
444 }
445
446 STDMETHODIMP wxIEnumFORMATETC::Clone(IEnumFORMATETC **ppenum)
447 {
448 wxLogTrace(wxTRACE_OleCalls, wxT("wxIEnumFORMATETC::Clone"));
449
450 // unfortunately, we can't reuse the code in ctor - types are different
451 wxIEnumFORMATETC *pNew = new wxIEnumFORMATETC(NULL, 0);
452 pNew->m_nCount = m_nCount;
453 pNew->m_formats = new CLIPFORMAT[m_nCount];
454 for ( ULONG n = 0; n < m_nCount; n++ ) {
455 pNew->m_formats[n] = m_formats[n];
456 }
457 pNew->AddRef();
458 *ppenum = pNew;
459
460 return S_OK;
461 }
462
463 // ----------------------------------------------------------------------------
464 // wxIDataObject
465 // ----------------------------------------------------------------------------
466
467 BEGIN_IID_TABLE(wxIDataObject)
468 ADD_IID(Unknown)
469 ADD_IID(DataObject)
470 END_IID_TABLE;
471
472 IMPLEMENT_IUNKNOWN_METHODS(wxIDataObject)
473
474 wxIDataObject::wxIDataObject(wxDataObject *pDataObject)
475 {
476 m_pDataObject = pDataObject;
477 m_mustDelete = false;
478 }
479
480 wxIDataObject::~wxIDataObject()
481 {
482 // delete system data
483 for ( SystemData::iterator it = m_systemData.begin();
484 it != m_systemData.end();
485 ++it )
486 {
487 delete (*it);
488 }
489
490 if ( m_mustDelete )
491 {
492 delete m_pDataObject;
493 }
494 }
495
496 // get data functions
497 STDMETHODIMP wxIDataObject::GetData(FORMATETC *pformatetcIn, STGMEDIUM *pmedium)
498 {
499 wxLogTrace(wxTRACE_OleCalls, wxT("wxIDataObject::GetData"));
500
501 // is data is in our format?
502 HRESULT hr = QueryGetData(pformatetcIn);
503 if ( FAILED(hr) )
504 return hr;
505
506 // for the bitmaps and metafiles we use the handles instead of global memory
507 // to pass the data
508 wxDataFormat format = (wxDataFormat::NativeFormat)pformatetcIn->cfFormat;
509 format = HtmlFormatFixup(format);
510
511 // is this system data?
512 if ( GetSystemData(format, pmedium) )
513 {
514 // pmedium is already filled with corresponding data, so we're ready.
515 return S_OK;
516 }
517
518 switch ( format )
519 {
520 case wxDF_BITMAP:
521 pmedium->tymed = TYMED_GDI;
522 break;
523
524 case wxDF_ENHMETAFILE:
525 pmedium->tymed = TYMED_ENHMF;
526 break;
527
528 #ifndef __WXWINCE__
529 case wxDF_METAFILE:
530 pmedium->hGlobal = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE,
531 sizeof(METAFILEPICT));
532 if ( !pmedium->hGlobal ) {
533 wxLogLastError(wxT("GlobalAlloc"));
534 return E_OUTOFMEMORY;
535 }
536 pmedium->tymed = TYMED_MFPICT;
537 break;
538 #endif
539 default:
540 // alloc memory
541 size_t size = m_pDataObject->GetDataSize(format);
542 if ( !size ) {
543 // it probably means that the method is just not implemented
544 wxLogDebug(wxT("Invalid data size - can't be 0"));
545
546 return DV_E_FORMATETC;
547 }
548
549 // we may need extra space for the buffer size
550 size += m_pDataObject->GetBufferOffset( format );
551
552 HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, size);
553 if ( hGlobal == NULL ) {
554 wxLogLastError(wxT("GlobalAlloc"));
555 return E_OUTOFMEMORY;
556 }
557
558 // copy data
559 pmedium->tymed = TYMED_HGLOBAL;
560 pmedium->hGlobal = hGlobal;
561 }
562
563 pmedium->pUnkForRelease = NULL;
564
565 // do copy the data
566 hr = GetDataHere(pformatetcIn, pmedium);
567 if ( FAILED(hr) ) {
568 // free resources we allocated
569 if ( pmedium->tymed & (TYMED_HGLOBAL | TYMED_MFPICT) ) {
570 GlobalFree(pmedium->hGlobal);
571 }
572
573 return hr;
574 }
575
576 return S_OK;
577 }
578
579 STDMETHODIMP wxIDataObject::GetDataHere(FORMATETC *pformatetc,
580 STGMEDIUM *pmedium)
581 {
582 wxLogTrace(wxTRACE_OleCalls, wxT("wxIDataObject::GetDataHere"));
583
584 // put data in caller provided medium
585 switch ( pmedium->tymed )
586 {
587 case TYMED_GDI:
588 if ( !m_pDataObject->GetDataHere(wxDF_BITMAP, &pmedium->hBitmap) )
589 return E_UNEXPECTED;
590 break;
591
592 case TYMED_ENHMF:
593 if ( !m_pDataObject->GetDataHere(wxDF_ENHMETAFILE,
594 &pmedium->hEnhMetaFile) )
595 return E_UNEXPECTED;
596 break;
597
598 case TYMED_MFPICT:
599 // fall through - we pass METAFILEPICT through HGLOBAL
600
601 case TYMED_HGLOBAL:
602 {
603 // copy data
604 HGLOBAL hGlobal = pmedium->hGlobal;
605 void *pBuf = GlobalLock(hGlobal);
606 if ( pBuf == NULL ) {
607 wxLogLastError(wxT("GlobalLock"));
608 return E_OUTOFMEMORY;
609 }
610
611 wxDataFormat format = pformatetc->cfFormat;
612
613 // possibly put the size in the beginning of the buffer
614 pBuf = m_pDataObject->SetSizeInBuffer
615 (
616 pBuf,
617 ::GlobalSize(hGlobal),
618 format
619 );
620
621 if ( !m_pDataObject->GetDataHere(format, pBuf) )
622 return E_UNEXPECTED;
623
624 GlobalUnlock(hGlobal);
625 }
626 break;
627
628 default:
629 return DV_E_TYMED;
630 }
631
632 return S_OK;
633 }
634
635
636 // set data functions
637 STDMETHODIMP wxIDataObject::SetData(FORMATETC *pformatetc,
638 STGMEDIUM *pmedium,
639 BOOL fRelease)
640 {
641 wxLogTrace(wxTRACE_OleCalls, wxT("wxIDataObject::SetData"));
642
643 switch ( pmedium->tymed )
644 {
645 case TYMED_GDI:
646 m_pDataObject->SetData(wxDF_BITMAP, 0, &pmedium->hBitmap);
647 break;
648
649 case TYMED_ENHMF:
650 m_pDataObject->SetData(wxDF_ENHMETAFILE, 0, &pmedium->hEnhMetaFile);
651 break;
652
653 case TYMED_ISTREAM:
654 // check if this format is supported
655 if ( !m_pDataObject->IsSupported(pformatetc->cfFormat,
656 wxDataObject::Set) )
657 {
658 // As this is not a supported format (content data), assume it
659 // is system data and save it.
660 return SaveSystemData(pformatetc, pmedium, fRelease);
661 }
662 break;
663
664 case TYMED_MFPICT:
665 // fall through - we pass METAFILEPICT through HGLOBAL
666 case TYMED_HGLOBAL:
667 {
668 wxDataFormat format = pformatetc->cfFormat;
669
670 format = HtmlFormatFixup(format);
671
672 // check if this format is supported
673 if ( !m_pDataObject->IsSupported(format, wxDataObject::Set) ) {
674 // As above, assume that unsupported format must be system
675 // data and just save it.
676 return SaveSystemData(pformatetc, pmedium, fRelease);
677 }
678
679 // copy data
680 const void *pBuf = GlobalLock(pmedium->hGlobal);
681 if ( pBuf == NULL ) {
682 wxLogLastError(wxT("GlobalLock"));
683
684 return E_OUTOFMEMORY;
685 }
686
687 // we've got a problem with SetData() here because the base
688 // class version requires the size parameter which we don't
689 // have anywhere in OLE data transfer - so we need to
690 // synthetise it for known formats and we suppose that all data
691 // in custom formats starts with a DWORD containing the size
692 size_t size;
693 switch ( format )
694 {
695 case wxDF_HTML:
696 case CF_TEXT:
697 case CF_OEMTEXT:
698 size = strlen((const char *)pBuf);
699 break;
700 #if !(defined(__BORLANDC__) && (__BORLANDC__ < 0x500))
701 case CF_UNICODETEXT:
702 #if ( defined(__BORLANDC__) && (__BORLANDC__ > 0x530) )
703 size = std::wcslen((const wchar_t *)pBuf) * sizeof(wchar_t);
704 #else
705 size = wxWcslen((const wchar_t *)pBuf) * sizeof(wchar_t);
706 #endif
707 break;
708 #endif
709 case CF_BITMAP:
710 #ifndef __WXWINCE__
711 case CF_HDROP:
712 // these formats don't use size at all, anyhow (but
713 // pass data by handle, which is always a single DWORD)
714 size = 0;
715 break;
716 #endif
717
718 case CF_DIB:
719 // the handler will calculate size itself (it's too
720 // complicated to do it here)
721 size = 0;
722 break;
723
724 #ifndef __WXWINCE__
725 case CF_METAFILEPICT:
726 size = sizeof(METAFILEPICT);
727 break;
728 #endif
729 default:
730 pBuf = m_pDataObject->
731 GetSizeFromBuffer(pBuf, &size, format);
732 size -= m_pDataObject->GetBufferOffset(format);
733 }
734
735 bool ok = m_pDataObject->SetData(format, size, pBuf);
736
737 GlobalUnlock(pmedium->hGlobal);
738
739 if ( !ok ) {
740 return E_UNEXPECTED;
741 }
742 }
743 break;
744
745 default:
746 return DV_E_TYMED;
747 }
748
749 if ( fRelease ) {
750 // we own the medium, so we must release it - but do *not* free any
751 // data we pass by handle because we have copied it elsewhere
752 switch ( pmedium->tymed )
753 {
754 case TYMED_GDI:
755 pmedium->hBitmap = 0;
756 break;
757
758 case TYMED_MFPICT:
759 pmedium->hMetaFilePict = 0;
760 break;
761
762 case TYMED_ENHMF:
763 pmedium->hEnhMetaFile = 0;
764 break;
765 }
766
767 ReleaseStgMedium(pmedium);
768 }
769
770 return S_OK;
771 }
772
773 // information functions
774 STDMETHODIMP wxIDataObject::QueryGetData(FORMATETC *pformatetc)
775 {
776 // do we accept data in this format?
777 if ( pformatetc == NULL ) {
778 wxLogTrace(wxTRACE_OleCalls,
779 wxT("wxIDataObject::QueryGetData: invalid ptr."));
780
781 return E_INVALIDARG;
782 }
783
784 // the only one allowed by current COM implementation
785 if ( pformatetc->lindex != -1 ) {
786 wxLogTrace(wxTRACE_OleCalls,
787 wxT("wxIDataObject::QueryGetData: bad lindex %ld"),
788 pformatetc->lindex);
789
790 return DV_E_LINDEX;
791 }
792
793 // we don't support anything other (THUMBNAIL, ICON, DOCPRINT...)
794 if ( pformatetc->dwAspect != DVASPECT_CONTENT ) {
795 wxLogTrace(wxTRACE_OleCalls,
796 wxT("wxIDataObject::QueryGetData: bad dwAspect %ld"),
797 pformatetc->dwAspect);
798
799 return DV_E_DVASPECT;
800 }
801
802 // and now check the type of data requested
803 wxDataFormat format = pformatetc->cfFormat;
804 format = HtmlFormatFixup(format);
805
806 if ( m_pDataObject->IsSupportedFormat(format) ) {
807 wxLogTrace(wxTRACE_OleCalls, wxT("wxIDataObject::QueryGetData: %s ok"),
808 wxGetFormatName(format));
809 }
810 else if ( HasSystemData(format) )
811 {
812 wxLogTrace(wxTRACE_OleCalls, wxT("wxIDataObject::QueryGetData: %s ok (system data)"),
813 wxGetFormatName(format));
814 // this is system data, so no further checks needed.
815 return S_OK;
816 }
817 else {
818 wxLogTrace(wxTRACE_OleCalls,
819 wxT("wxIDataObject::QueryGetData: %s unsupported"),
820 wxGetFormatName(format));
821
822 return DV_E_FORMATETC;
823 }
824
825 // we only transfer data by global memory, except for some particular cases
826 DWORD tymed = pformatetc->tymed;
827 if ( (format == wxDF_BITMAP && !(tymed & TYMED_GDI)) &&
828 !(tymed & TYMED_HGLOBAL) ) {
829 // it's not what we're waiting for
830 wxLogTrace(wxTRACE_OleCalls,
831 wxT("wxIDataObject::QueryGetData: %s != %s"),
832 GetTymedName(tymed),
833 GetTymedName(format == wxDF_BITMAP ? TYMED_GDI
834 : TYMED_HGLOBAL));
835
836 return DV_E_TYMED;
837 }
838
839 return S_OK;
840 }
841
842 STDMETHODIMP wxIDataObject::GetCanonicalFormatEtc(FORMATETC *WXUNUSED(pFormatetcIn),
843 FORMATETC *pFormatetcOut)
844 {
845 wxLogTrace(wxTRACE_OleCalls, wxT("wxIDataObject::GetCanonicalFormatEtc"));
846
847 // TODO we might want something better than this trivial implementation here
848 if ( pFormatetcOut != NULL )
849 pFormatetcOut->ptd = NULL;
850
851 return DATA_S_SAMEFORMATETC;
852 }
853
854 STDMETHODIMP wxIDataObject::EnumFormatEtc(DWORD dwDir,
855 IEnumFORMATETC **ppenumFormatEtc)
856 {
857 wxLogTrace(wxTRACE_OleCalls, wxT("wxIDataObject::EnumFormatEtc"));
858
859 wxDataObject::Direction dir = dwDir == DATADIR_GET ? wxDataObject::Get
860 : wxDataObject::Set;
861
862 // format count is total of user specified and system formats.
863 const size_t ourFormatCount = m_pDataObject->GetFormatCount(dir);
864 const size_t sysFormatCount = m_systemData.size();
865
866 const ULONG
867 nFormatCount = wx_truncate_cast(ULONG, ourFormatCount + sysFormatCount);
868
869 // fill format array with formats ...
870 wxScopedArray<wxDataFormat> formats(new wxDataFormat[nFormatCount]);
871
872 // ... from content data (supported formats)
873 m_pDataObject->GetAllFormats(formats.get(), dir);
874
875 // ... from system data
876 for ( size_t j = 0; j < sysFormatCount; j++ )
877 {
878 SystemDataEntry* entry = m_systemData[j];
879 wxDataFormat& format = formats[ourFormatCount + j];
880 format = entry->pformatetc->cfFormat;
881 }
882
883 wxIEnumFORMATETC *pEnum = new wxIEnumFORMATETC(formats.get(), nFormatCount);
884 pEnum->AddRef();
885 *ppenumFormatEtc = pEnum;
886
887 return S_OK;
888 }
889
890 // ----------------------------------------------------------------------------
891 // advise sink functions (not implemented)
892 // ----------------------------------------------------------------------------
893
894 STDMETHODIMP wxIDataObject::DAdvise(FORMATETC *WXUNUSED(pformatetc),
895 DWORD WXUNUSED(advf),
896 IAdviseSink *WXUNUSED(pAdvSink),
897 DWORD *WXUNUSED(pdwConnection))
898 {
899 return OLE_E_ADVISENOTSUPPORTED;
900 }
901
902 STDMETHODIMP wxIDataObject::DUnadvise(DWORD WXUNUSED(dwConnection))
903 {
904 return OLE_E_ADVISENOTSUPPORTED;
905 }
906
907 STDMETHODIMP wxIDataObject::EnumDAdvise(IEnumSTATDATA **WXUNUSED(ppenumAdvise))
908 {
909 return OLE_E_ADVISENOTSUPPORTED;
910 }
911
912 // ----------------------------------------------------------------------------
913 // wxDataObject
914 // ----------------------------------------------------------------------------
915
916 wxDataObject::wxDataObject()
917 {
918 m_pIDataObject = new wxIDataObject(this);
919 m_pIDataObject->AddRef();
920 }
921
922 wxDataObject::~wxDataObject()
923 {
924 ReleaseInterface(m_pIDataObject);
925 }
926
927 void wxDataObject::SetAutoDelete()
928 {
929 ((wxIDataObject *)m_pIDataObject)->SetDeleteFlag();
930 m_pIDataObject->Release();
931
932 // so that the dtor doesn't crash
933 m_pIDataObject = NULL;
934 }
935
936 size_t wxDataObject::GetBufferOffset(const wxDataFormat& format )
937 {
938 // if we prepend the size of the data to the buffer itself, account for it
939 return NeedsVerbatimData(format) ? 0 : sizeof(size_t);
940 }
941
942 const void *wxDataObject::GetSizeFromBuffer(const void *buffer,
943 size_t *size,
944 const wxDataFormat& WXUNUSED(format))
945 {
946 // hack: the third parameter is declared non-const in Wine's headers so
947 // cast away the const
948 const size_t realsz = ::HeapSize(::GetProcessHeap(), 0,
949 const_cast<void*>(buffer));
950 if ( realsz == (size_t)-1 )
951 {
952 // note that HeapSize() does not set last error
953 wxLogApiError(wxT("HeapSize"), 0);
954 return NULL;
955 }
956
957 *size = realsz;
958
959 return buffer;
960 }
961
962 void* wxDataObject::SetSizeInBuffer( void* buffer, size_t size,
963 const wxDataFormat& format )
964 {
965 size_t* p = (size_t *)buffer;
966 if ( !NeedsVerbatimData(format) )
967 {
968 // prepend the size to the data and skip it
969 *p++ = size;
970 }
971
972 return p;
973 }
974
975 #if wxDEBUG_LEVEL
976
977 const wxChar *wxDataObject::GetFormatName(wxDataFormat format)
978 {
979 // case 'xxx' is not a valid value for switch of enum 'wxDataFormat'
980 #ifdef __VISUALC__
981 #pragma warning(disable:4063)
982 #endif // VC++
983
984 static wxChar s_szBuf[256];
985 switch ( format ) {
986 case CF_TEXT: return wxT("CF_TEXT");
987 case CF_BITMAP: return wxT("CF_BITMAP");
988 case CF_SYLK: return wxT("CF_SYLK");
989 case CF_DIF: return wxT("CF_DIF");
990 case CF_TIFF: return wxT("CF_TIFF");
991 case CF_OEMTEXT: return wxT("CF_OEMTEXT");
992 case CF_DIB: return wxT("CF_DIB");
993 case CF_PALETTE: return wxT("CF_PALETTE");
994 case CF_PENDATA: return wxT("CF_PENDATA");
995 case CF_RIFF: return wxT("CF_RIFF");
996 case CF_WAVE: return wxT("CF_WAVE");
997 case CF_UNICODETEXT: return wxT("CF_UNICODETEXT");
998 #ifndef __WXWINCE__
999 case CF_METAFILEPICT: return wxT("CF_METAFILEPICT");
1000 case CF_ENHMETAFILE: return wxT("CF_ENHMETAFILE");
1001 case CF_LOCALE: return wxT("CF_LOCALE");
1002 case CF_HDROP: return wxT("CF_HDROP");
1003 #endif
1004
1005 default:
1006 if ( !::GetClipboardFormatName(format, s_szBuf, WXSIZEOF(s_szBuf)) )
1007 {
1008 // it must be a new predefined format we don't know the name of
1009 wxSprintf(s_szBuf, wxT("unknown CF (0x%04x)"), format.GetFormatId());
1010 }
1011
1012 return s_szBuf;
1013 }
1014
1015 #ifdef __VISUALC__
1016 #pragma warning(default:4063)
1017 #endif // VC++
1018 }
1019
1020 #endif // wxDEBUG_LEVEL
1021
1022 // ----------------------------------------------------------------------------
1023 // wxBitmapDataObject supports CF_DIB format
1024 // ----------------------------------------------------------------------------
1025
1026 // TODO: support CF_DIB under Windows CE as well
1027
1028 size_t wxBitmapDataObject::GetDataSize() const
1029 {
1030 #if wxUSE_WXDIB && !defined(__WXWINCE__)
1031 return wxDIB::ConvertFromBitmap(NULL, GetHbitmapOf(GetBitmap()));
1032 #else
1033 return 0;
1034 #endif
1035 }
1036
1037 bool wxBitmapDataObject::GetDataHere(void *buf) const
1038 {
1039 #if wxUSE_WXDIB && !defined(__WXWINCE__)
1040 BITMAPINFO * const pbi = (BITMAPINFO *)buf;
1041
1042 return wxDIB::ConvertFromBitmap(pbi, GetHbitmapOf(GetBitmap())) != 0;
1043 #else
1044 wxUnusedVar(buf);
1045 return false;
1046 #endif
1047 }
1048
1049 bool wxBitmapDataObject::SetData(size_t WXUNUSED(len), const void *buf)
1050 {
1051 #if wxUSE_WXDIB && !defined(__WXWINCE__)
1052 const BITMAPINFO * const pbmi = (const BITMAPINFO *)buf;
1053
1054 HBITMAP hbmp = wxDIB::ConvertToBitmap(pbmi);
1055
1056 wxCHECK_MSG( hbmp, FALSE, wxT("pasting/dropping invalid bitmap") );
1057
1058 const BITMAPINFOHEADER * const pbmih = &pbmi->bmiHeader;
1059 wxBitmap bitmap(pbmih->biWidth, pbmih->biHeight, pbmih->biBitCount);
1060 bitmap.SetHBITMAP((WXHBITMAP)hbmp);
1061
1062 // TODO: create wxPalette if the bitmap has any
1063
1064 SetBitmap(bitmap);
1065
1066 return true;
1067 #else
1068 wxUnusedVar(buf);
1069 return false;
1070 #endif
1071 }
1072
1073 // ----------------------------------------------------------------------------
1074 // wxBitmapDataObject2 supports CF_BITMAP format
1075 // ----------------------------------------------------------------------------
1076
1077 // the bitmaps aren't passed by value as other types of data (i.e. by copying
1078 // the data into a global memory chunk and passing it to the clipboard or
1079 // another application or whatever), but by handle, so these generic functions
1080 // don't make much sense to them.
1081
1082 size_t wxBitmapDataObject2::GetDataSize() const
1083 {
1084 return 0;
1085 }
1086
1087 bool wxBitmapDataObject2::GetDataHere(void *pBuf) const
1088 {
1089 // we put a bitmap handle into pBuf
1090 *(WXHBITMAP *)pBuf = GetBitmap().GetHBITMAP();
1091
1092 return true;
1093 }
1094
1095 bool wxBitmapDataObject2::SetData(size_t WXUNUSED(len), const void *pBuf)
1096 {
1097 HBITMAP hbmp = *(HBITMAP *)pBuf;
1098
1099 BITMAP bmp;
1100 if ( !GetObject(hbmp, sizeof(BITMAP), &bmp) )
1101 {
1102 wxLogLastError(wxT("GetObject(HBITMAP)"));
1103 }
1104
1105 wxBitmap bitmap(bmp.bmWidth, bmp.bmHeight, bmp.bmPlanes);
1106 bitmap.SetHBITMAP((WXHBITMAP)hbmp);
1107
1108 if ( !bitmap.IsOk() ) {
1109 wxFAIL_MSG(wxT("pasting/dropping invalid bitmap"));
1110
1111 return false;
1112 }
1113
1114 SetBitmap(bitmap);
1115
1116 return true;
1117 }
1118
1119 #if 0
1120
1121 size_t wxBitmapDataObject::GetDataSize(const wxDataFormat& format) const
1122 {
1123 if ( format.GetFormatId() == CF_DIB )
1124 {
1125 // create the DIB
1126 ScreenHDC hdc;
1127
1128 // shouldn't be selected into a DC or GetDIBits() would fail
1129 wxASSERT_MSG( !m_bitmap.GetSelectedInto(),
1130 wxT("can't copy bitmap selected into wxMemoryDC") );
1131
1132 // first get the info
1133 BITMAPINFO bi;
1134 if ( !GetDIBits(hdc, (HBITMAP)m_bitmap.GetHBITMAP(), 0, 0,
1135 NULL, &bi, DIB_RGB_COLORS) )
1136 {
1137 wxLogLastError(wxT("GetDIBits(NULL)"));
1138
1139 return 0;
1140 }
1141
1142 return sizeof(BITMAPINFO) + bi.bmiHeader.biSizeImage;
1143 }
1144 else // CF_BITMAP
1145 {
1146 // no data to copy - we don't pass HBITMAP via global memory
1147 return 0;
1148 }
1149 }
1150
1151 bool wxBitmapDataObject::GetDataHere(const wxDataFormat& format,
1152 void *pBuf) const
1153 {
1154 wxASSERT_MSG( m_bitmap.IsOk(), wxT("copying invalid bitmap") );
1155
1156 HBITMAP hbmp = (HBITMAP)m_bitmap.GetHBITMAP();
1157 if ( format.GetFormatId() == CF_DIB )
1158 {
1159 // create the DIB
1160 ScreenHDC hdc;
1161
1162 // shouldn't be selected into a DC or GetDIBits() would fail
1163 wxASSERT_MSG( !m_bitmap.GetSelectedInto(),
1164 wxT("can't copy bitmap selected into wxMemoryDC") );
1165
1166 // first get the info
1167 BITMAPINFO *pbi = (BITMAPINFO *)pBuf;
1168 if ( !GetDIBits(hdc, hbmp, 0, 0, NULL, pbi, DIB_RGB_COLORS) )
1169 {
1170 wxLogLastError(wxT("GetDIBits(NULL)"));
1171
1172 return 0;
1173 }
1174
1175 // and now copy the bits
1176 if ( !GetDIBits(hdc, hbmp, 0, pbi->bmiHeader.biHeight, pbi + 1,
1177 pbi, DIB_RGB_COLORS) )
1178 {
1179 wxLogLastError(wxT("GetDIBits"));
1180
1181 return false;
1182 }
1183 }
1184 else // CF_BITMAP
1185 {
1186 // we put a bitmap handle into pBuf
1187 *(HBITMAP *)pBuf = hbmp;
1188 }
1189
1190 return true;
1191 }
1192
1193 bool wxBitmapDataObject::SetData(const wxDataFormat& format,
1194 size_t size, const void *pBuf)
1195 {
1196 HBITMAP hbmp;
1197 if ( format.GetFormatId() == CF_DIB )
1198 {
1199 // here we get BITMAPINFO struct followed by the actual bitmap bits and
1200 // BITMAPINFO starts with BITMAPINFOHEADER followed by colour info
1201 ScreenHDC hdc;
1202
1203 BITMAPINFO *pbmi = (BITMAPINFO *)pBuf;
1204 BITMAPINFOHEADER *pbmih = &pbmi->bmiHeader;
1205 hbmp = CreateDIBitmap(hdc, pbmih, CBM_INIT,
1206 pbmi + 1, pbmi, DIB_RGB_COLORS);
1207 if ( !hbmp )
1208 {
1209 wxLogLastError(wxT("CreateDIBitmap"));
1210 }
1211
1212 m_bitmap.SetWidth(pbmih->biWidth);
1213 m_bitmap.SetHeight(pbmih->biHeight);
1214 }
1215 else // CF_BITMAP
1216 {
1217 // it's easy with bitmaps: we pass them by handle
1218 hbmp = *(HBITMAP *)pBuf;
1219
1220 BITMAP bmp;
1221 if ( !GetObject(hbmp, sizeof(BITMAP), &bmp) )
1222 {
1223 wxLogLastError(wxT("GetObject(HBITMAP)"));
1224 }
1225
1226 m_bitmap.SetWidth(bmp.bmWidth);
1227 m_bitmap.SetHeight(bmp.bmHeight);
1228 m_bitmap.SetDepth(bmp.bmPlanes);
1229 }
1230
1231 m_bitmap.SetHBITMAP((WXHBITMAP)hbmp);
1232
1233 wxASSERT_MSG( m_bitmap.IsOk(), wxT("pasting invalid bitmap") );
1234
1235 return true;
1236 }
1237
1238 #endif // 0
1239
1240 // ----------------------------------------------------------------------------
1241 // wxFileDataObject
1242 // ----------------------------------------------------------------------------
1243
1244 bool wxFileDataObject::SetData(size_t WXUNUSED(size),
1245 const void *WXUNUSED_IN_WINCE(pData))
1246 {
1247 #ifndef __WXWINCE__
1248 m_filenames.Empty();
1249
1250 // the documentation states that the first member of DROPFILES structure is
1251 // a "DWORD offset of double NUL terminated file list". What they mean by
1252 // this (I wonder if you see it immediately) is that the list starts at
1253 // ((char *)&(pDropFiles.pFiles)) + pDropFiles.pFiles. We're also advised
1254 // to use DragQueryFile to work with this structure, but not told where and
1255 // how to get HDROP.
1256 HDROP hdrop = (HDROP)pData; // NB: it works, but I'm not sure about it
1257
1258 // get number of files (magic value -1)
1259 UINT nFiles = ::DragQueryFile(hdrop, (unsigned)-1, NULL, 0u);
1260
1261 wxCHECK_MSG ( nFiles != (UINT)-1, FALSE, wxT("wrong HDROP handle") );
1262
1263 // for each file get the length, allocate memory and then get the name
1264 wxString str;
1265 UINT len, n;
1266 for ( n = 0; n < nFiles; n++ ) {
1267 // +1 for terminating NUL
1268 len = ::DragQueryFile(hdrop, n, NULL, 0) + 1;
1269
1270 UINT len2 = ::DragQueryFile(hdrop, n, wxStringBuffer(str, len), len);
1271 m_filenames.Add(str);
1272
1273 if ( len2 != len - 1 ) {
1274 wxLogDebug(wxT("In wxFileDropTarget::OnDrop DragQueryFile returned\
1275 %d characters, %d expected."), len2, len - 1);
1276 }
1277 }
1278
1279 return true;
1280 #else
1281 return false;
1282 #endif
1283 }
1284
1285 void wxFileDataObject::AddFile(const wxString& file)
1286 {
1287 // just add file to filenames array
1288 // all useful data (such as DROPFILES struct) will be
1289 // created later as necessary
1290 m_filenames.Add(file);
1291 }
1292
1293 size_t wxFileDataObject::GetDataSize() const
1294 {
1295 #ifndef __WXWINCE__
1296 // size returned will be the size of the DROPFILES structure, plus the list
1297 // of filesnames (null byte separated), plus a double null at the end
1298
1299 // if no filenames in list, size is 0
1300 if ( m_filenames.empty() )
1301 return 0;
1302
1303 #if wxUSE_UNICODE_MSLU
1304 size_t sizeOfChar;
1305 if ( wxGetOsVersion() == wxOS_WINDOWS_9X )
1306 {
1307 // Win9x always uses ANSI file names and MSLU doesn't help with this
1308 sizeOfChar = 1;
1309 }
1310 else
1311 {
1312 sizeOfChar = sizeof(wxChar);
1313 }
1314 #else // !wxUSE_UNICODE_MSLU
1315 static const size_t sizeOfChar = sizeof(wxChar);
1316 #endif // wxUSE_UNICODE_MSLU/!wxUSE_UNICODE_MSLU
1317
1318 // initial size of DROPFILES struct + null byte
1319 size_t sz = sizeof(DROPFILES) + sizeOfChar;
1320
1321 const size_t count = m_filenames.size();
1322 for ( size_t i = 0; i < count; i++ )
1323 {
1324 // add filename length plus null byte
1325 size_t len;
1326 #if wxUSE_UNICODE_MSLU
1327 if ( sizeOfChar == 1 )
1328 len = strlen(m_filenames[i].mb_str(*wxConvFileName));
1329 else
1330 #endif // wxUSE_UNICODE_MSLU
1331 len = m_filenames[i].length();
1332
1333 sz += (len + 1) * sizeOfChar;
1334 }
1335
1336 return sz;
1337 #else
1338 return 0;
1339 #endif
1340 }
1341
1342 bool wxFileDataObject::GetDataHere(void *WXUNUSED_IN_WINCE(pData)) const
1343 {
1344 #ifndef __WXWINCE__
1345 // pData points to an externally allocated memory block
1346 // created using the size returned by GetDataSize()
1347
1348 // if pData is NULL, or there are no files, return
1349 if ( !pData || m_filenames.empty() )
1350 return false;
1351
1352 // convert data pointer to a DROPFILES struct pointer
1353 LPDROPFILES pDrop = (LPDROPFILES) pData;
1354
1355 // initialize DROPFILES struct
1356 pDrop->pFiles = sizeof(DROPFILES);
1357 pDrop->fNC = FALSE; // not non-client coords
1358 #if wxUSE_UNICODE_MSLU
1359 pDrop->fWide = wxGetOsVersion() != wxOS_WINDOWS_9X ? TRUE : FALSE;
1360 #else
1361 pDrop->fWide = wxUSE_UNICODE;
1362 #endif
1363
1364 const size_t sizeOfChar = pDrop->fWide ? sizeof(wchar_t) : 1;
1365
1366 // set start of filenames list (null separated)
1367 BYTE *pbuf = (BYTE *)(pDrop + 1);
1368
1369 const size_t count = m_filenames.size();
1370 for ( size_t i = 0; i < count; i++ )
1371 {
1372 // copy filename to pbuf and add null terminator
1373 size_t len;
1374 #if wxUSE_UNICODE_MSLU
1375 if ( sizeOfChar == 1 )
1376 {
1377 wxCharBuffer buf(m_filenames[i].mb_str(*wxConvFileName));
1378 len = strlen(buf);
1379 memcpy(pbuf, buf, len*sizeOfChar);
1380 }
1381 else
1382 #endif // wxUSE_UNICODE_MSLU
1383 {
1384 len = m_filenames[i].length();
1385 memcpy(pbuf, m_filenames[i].t_str(), len*sizeOfChar);
1386 }
1387
1388 pbuf += len*sizeOfChar;
1389
1390 memset(pbuf, 0, sizeOfChar);
1391 pbuf += sizeOfChar;
1392 }
1393
1394 // add final null terminator
1395 memset(pbuf, 0, sizeOfChar);
1396
1397 return true;
1398 #else
1399 return false;
1400 #endif
1401 }
1402
1403 // ----------------------------------------------------------------------------
1404 // wxURLDataObject
1405 // ----------------------------------------------------------------------------
1406
1407 // Work around bug in Wine headers
1408 #if defined(__WINE__) && defined(CFSTR_SHELLURL) && wxUSE_UNICODE
1409 #undef CFSTR_SHELLURL
1410 #define CFSTR_SHELLURL wxT("CFSTR_SHELLURL")
1411 #endif
1412
1413 class CFSTR_SHELLURLDataObject : public wxCustomDataObject
1414 {
1415 public:
1416 CFSTR_SHELLURLDataObject() : wxCustomDataObject(CFSTR_SHELLURL) {}
1417
1418 virtual size_t GetBufferOffset( const wxDataFormat& WXUNUSED(format) )
1419 {
1420 return 0;
1421 }
1422
1423 virtual const void* GetSizeFromBuffer( const void* buffer, size_t* size,
1424 const wxDataFormat& WXUNUSED(format) )
1425 {
1426 // CFSTR_SHELLURL is _always_ ANSI text
1427 *size = strlen( (const char*)buffer );
1428
1429 return buffer;
1430 }
1431
1432 virtual void* SetSizeInBuffer( void* buffer, size_t WXUNUSED(size),
1433 const wxDataFormat& WXUNUSED(format) )
1434 {
1435 return buffer;
1436 }
1437
1438 wxDECLARE_NO_COPY_CLASS(CFSTR_SHELLURLDataObject);
1439 };
1440
1441
1442
1443 wxURLDataObject::wxURLDataObject(const wxString& url)
1444 {
1445 // we support CF_TEXT and CFSTR_SHELLURL formats which are basically the
1446 // same but it seems that some browsers only provide one of them so we have
1447 // to support both
1448 Add(new wxTextDataObject);
1449 Add(new CFSTR_SHELLURLDataObject());
1450
1451 // we don't have any data yet
1452 m_dataObjectLast = NULL;
1453
1454 if ( !url.empty() )
1455 SetURL(url);
1456 }
1457
1458 bool wxURLDataObject::SetData(const wxDataFormat& format,
1459 size_t len,
1460 const void *buf)
1461 {
1462 m_dataObjectLast = GetObject(format);
1463
1464 wxCHECK_MSG( m_dataObjectLast, FALSE,
1465 wxT("unsupported format in wxURLDataObject"));
1466
1467 return m_dataObjectLast->SetData(len, buf);
1468 }
1469
1470 wxString wxURLDataObject::GetURL() const
1471 {
1472 wxString url;
1473 wxCHECK_MSG( m_dataObjectLast, url, wxT("no data in wxURLDataObject") );
1474
1475 if ( m_dataObjectLast->GetPreferredFormat() == CFSTR_SHELLURL )
1476 {
1477 const size_t len = m_dataObjectLast->GetDataSize();
1478 if ( !len )
1479 return wxString();
1480
1481 // CFSTR_SHELLURL is always ANSI so we need to convert it from it in
1482 // Unicode build
1483 #if wxUSE_UNICODE
1484 wxCharBuffer buf(len);
1485
1486 if ( m_dataObjectLast->GetDataHere(buf.data()) )
1487 url = buf;
1488 #else // !wxUSE_UNICODE
1489 // in ANSI build no conversion is necessary
1490 m_dataObjectLast->GetDataHere(wxStringBuffer(url, len));
1491 #endif // wxUSE_UNICODE/!wxUSE_UNICODE
1492 }
1493 else // must be wxTextDataObject
1494 {
1495 url = static_cast<wxTextDataObject *>(m_dataObjectLast)->GetText();
1496 }
1497
1498 return url;
1499 }
1500
1501 void wxURLDataObject::SetURL(const wxString& url)
1502 {
1503 wxCharBuffer urlMB(url.mb_str());
1504 if ( urlMB )
1505 {
1506 const size_t len = strlen(urlMB);
1507
1508 #if !wxUSE_UNICODE
1509 // wxTextDataObject takes the number of characters in the string, not
1510 // the size of the buffer (which would be len+1)
1511 SetData(wxDF_TEXT, len, urlMB);
1512 #endif // !wxUSE_UNICODE
1513
1514 // however CFSTR_SHELLURLDataObject doesn't append NUL automatically
1515 // but we probably still want to have it on the clipboard (just to be
1516 // safe), so do append it
1517 SetData(wxDataFormat(CFSTR_SHELLURL), len + 1, urlMB);
1518 }
1519
1520 #if wxUSE_UNICODE
1521 SetData(wxDF_UNICODETEXT, url.length()*sizeof(wxChar), url.wc_str());
1522 #endif
1523 }
1524
1525 // ----------------------------------------------------------------------------
1526 // private functions
1527 // ----------------------------------------------------------------------------
1528
1529 #if wxDEBUG_LEVEL
1530
1531 static const wxChar *GetTymedName(DWORD tymed)
1532 {
1533 static wxChar s_szBuf[128];
1534 switch ( tymed ) {
1535 case TYMED_HGLOBAL: return wxT("TYMED_HGLOBAL");
1536 case TYMED_FILE: return wxT("TYMED_FILE");
1537 case TYMED_ISTREAM: return wxT("TYMED_ISTREAM");
1538 case TYMED_ISTORAGE: return wxT("TYMED_ISTORAGE");
1539 case TYMED_GDI: return wxT("TYMED_GDI");
1540 case TYMED_MFPICT: return wxT("TYMED_MFPICT");
1541 case TYMED_ENHMF: return wxT("TYMED_ENHMF");
1542 default:
1543 wxSprintf(s_szBuf, wxT("type of media format %ld (unknown)"), tymed);
1544 return s_szBuf;
1545 }
1546 }
1547
1548 #endif // Debug
1549
1550 #else // not using OLE at all
1551
1552 // ----------------------------------------------------------------------------
1553 // wxDataObject
1554 // ----------------------------------------------------------------------------
1555
1556 #if wxUSE_DATAOBJ
1557
1558 wxDataObject::wxDataObject()
1559 {
1560 }
1561
1562 wxDataObject::~wxDataObject()
1563 {
1564 }
1565
1566 void wxDataObject::SetAutoDelete()
1567 {
1568 }
1569
1570 const wxChar *wxDataObject::GetFormatName(wxDataFormat WXUNUSED(format))
1571 {
1572 return NULL;
1573 }
1574
1575 #endif // wxUSE_DATAOBJ
1576
1577 #endif // wxUSE_OLE/!wxUSE_OLE
1578
1579