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