]> git.saurik.com Git - wxWidgets.git/blame - src/msw/ole/dataobj.cpp
Make public headers compatible with Objective-C++ with ARC.
[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 6// Created: 10.05.98
269a5a34 7// Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
65571936 8// Licence: wxWindows licence
269a5a34
VZ
9///////////////////////////////////////////////////////////////////////////////
10
11// ============================================================================
12// declarations
13// ============================================================================
14
15// ----------------------------------------------------------------------------
16// headers
17// ----------------------------------------------------------------------------
18
269a5a34
VZ
19// For compilers that support precompilation, includes "wx.h".
20#include "wx/wxprec.h"
21
22#if defined(__BORLANDC__)
0d0512bd 23 #pragma hdrstop
269a5a34 24#endif
0d0512bd 25
7dee726c 26#ifndef WX_PRECOMP
0d0512bd
VZ
27 #include "wx/intl.h"
28 #include "wx/log.h"
daac16bb 29 #include "wx/utils.h"
193d0c93 30 #include "wx/wxcrtvararg.h"
7dee726c 31#endif
5260b1c5 32
3f480da3 33#include "wx/dataobj.h"
17b74d79 34
21709999
JS
35#if wxUSE_OLE && defined(__WIN32__) && !defined(__GNUWIN32_OLD__)
36
40375032 37#include "wx/scopedarray.h"
c5860119 38#include "wx/vector.h"
0d0512bd
VZ
39#include "wx/msw/private.h" // includes <windows.h>
40
4676948b
JS
41#ifdef __WXWINCE__
42#include <winreg.h>
43#endif
44
a7b4607f 45// for some compilers, the entire ole2.h must be included, not only oleauto.h
4676948b 46#if wxUSE_NORLANDER_HEADERS || defined(__WATCOMC__) || defined(__WXWINCE__)
7dee726c
RS
47 #include <ole2.h>
48#endif
269a5a34 49
a7b4607f 50#include <oleauto.h>
8b85d24e
VZ
51#include <shlobj.h>
52
0d0512bd
VZ
53#include "wx/msw/ole/oleutils.h"
54
55#include "wx/msw/dib.h"
17b74d79 56
dcbd7ce2 57#ifndef CFSTR_SHELLURL
9a83f860 58#define CFSTR_SHELLURL wxT("UniformResourceLocator")
dcbd7ce2
VS
59#endif
60
269a5a34
VZ
61// ----------------------------------------------------------------------------
62// functions
63// ----------------------------------------------------------------------------
64
4b6a582b 65#if wxDEBUG_LEVEL
d59ceba5 66 static const wxChar *GetTymedName(DWORD tymed);
4b6a582b 67#else // !wxDEBUG_LEVEL
fda7962d 68 #define GetTymedName(tymed) wxEmptyString
4b6a582b 69#endif // wxDEBUG_LEVEL/!wxDEBUG_LEVEL
269a5a34 70
40375032
VZ
71namespace
72{
73
b8acf11e
RD
74wxDataFormat 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
40375032
VZ
89// helper function for wxCopyStgMedium()
90HGLOBAL 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.
114HRESULT 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
269a5a34
VZ
161// ----------------------------------------------------------------------------
162// wxIEnumFORMATETC interface implementation
163// ----------------------------------------------------------------------------
8e193f38 164
269a5a34
VZ
165class wxIEnumFORMATETC : public IEnumFORMATETC
166{
167public:
8e193f38 168 wxIEnumFORMATETC(const wxDataFormat* formats, ULONG nCount);
33ac7e6f 169 virtual ~wxIEnumFORMATETC() { delete [] m_formats; }
269a5a34 170
8e193f38
VZ
171 // IEnumFORMATETC
172 STDMETHODIMP Next(ULONG celt, FORMATETC *rgelt, ULONG *pceltFetched);
173 STDMETHODIMP Skip(ULONG celt);
174 STDMETHODIMP Reset();
175 STDMETHODIMP Clone(IEnumFORMATETC **ppenum);
269a5a34 176
6f02a879
VZ
177 DECLARE_IUNKNOWN_METHODS;
178
269a5a34 179private:
8e193f38
VZ
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
22f3361e 183
c0c133e1 184 wxDECLARE_NO_COPY_CLASS(wxIEnumFORMATETC);
269a5a34
VZ
185};
186
187// ----------------------------------------------------------------------------
188// wxIDataObject implementation of IDataObject interface
189// ----------------------------------------------------------------------------
8e193f38 190
269a5a34
VZ
191class wxIDataObject : public IDataObject
192{
193public:
8e193f38 194 wxIDataObject(wxDataObject *pDataObject);
33ac7e6f 195 virtual ~wxIDataObject();
d59ceba5
VZ
196
197 // normally, wxDataObject controls our lifetime (i.e. we're deleted when it
3103e8a9 198 // is), but in some cases, the situation is reversed, that is we delete it
d59ceba5 199 // when this object is deleted - setting this flag enables such logic
17a6a2e0 200 void SetDeleteFlag() { m_mustDelete = true; }
269a5a34 201
8e193f38
VZ
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);
269a5a34 212
6f02a879
VZ
213 DECLARE_IUNKNOWN_METHODS;
214
269a5a34 215private:
8e193f38 216 wxDataObject *m_pDataObject; // pointer to C++ class we belong to
d59ceba5
VZ
217
218 bool m_mustDelete;
22f3361e 219
c0c133e1 220 wxDECLARE_NO_COPY_CLASS(wxIDataObject);
40375032
VZ
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;
d59ceba5
VZ
256};
257
40375032
VZ
258bool
259wxIDataObject::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
276bool
277wxIDataObject::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
292HRESULT
293wxIDataObject::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
269a5a34
VZ
337// ============================================================================
338// implementation
339// ============================================================================
340
3f480da3
VZ
341// ----------------------------------------------------------------------------
342// wxDataFormat
343// ----------------------------------------------------------------------------
344
a1eb65c2 345void wxDataFormat::SetId(const wxString& format)
3f480da3 346{
017dc06b 347 m_format = (wxDataFormat::NativeFormat)::RegisterClipboardFormat(format.t_str());
3f480da3
VZ
348 if ( !m_format )
349 {
350 wxLogError(_("Couldn't register clipboard format '%s'."), format);
351 }
352}
353
354wxString wxDataFormat::GetId() const
355{
356 static const int max = 256;
357
358 wxString s;
359
360 wxCHECK_MSG( !IsStandard(), s,
223d09f6 361 wxT("name of predefined format cannot be retrieved") );
3f480da3 362
de564874 363 int len = ::GetClipboardFormatName(m_format, wxStringBuffer(s, max), max);
3f480da3
VZ
364
365 if ( !len )
366 {
367 wxLogError(_("The clipboard format '%d' doesn't exist."), m_format);
5712281c 368 return wxEmptyString;
3f480da3
VZ
369 }
370
371 return s;
372}
373
269a5a34
VZ
374// ----------------------------------------------------------------------------
375// wxIEnumFORMATETC
376// ----------------------------------------------------------------------------
377
378BEGIN_IID_TABLE(wxIEnumFORMATETC)
8e193f38
VZ
379 ADD_IID(Unknown)
380 ADD_IID(EnumFORMATETC)
269a5a34
VZ
381END_IID_TABLE;
382
383IMPLEMENT_IUNKNOWN_METHODS(wxIEnumFORMATETC)
384
8e193f38 385wxIEnumFORMATETC::wxIEnumFORMATETC(const wxDataFormat *formats, ULONG nCount)
269a5a34 386{
8e193f38
VZ
387 m_nCurrent = 0;
388 m_nCount = nCount;
389 m_formats = new CLIPFORMAT[nCount];
390 for ( ULONG n = 0; n < nCount; n++ ) {
b8acf11e
RD
391 if (formats[n].GetFormatId() != wxDF_HTML)
392 m_formats[n] = formats[n].GetFormatId();
393 else
394 m_formats[n] = ::RegisterClipboardFormat(wxT("HTML Format"));
8e193f38 395 }
269a5a34
VZ
396}
397
398STDMETHODIMP wxIEnumFORMATETC::Next(ULONG celt,
399 FORMATETC *rgelt,
1f1c4210 400 ULONG *pceltFetched)
269a5a34 401{
8e193f38 402 wxLogTrace(wxTRACE_OleCalls, wxT("wxIEnumFORMATETC::Next"));
269a5a34 403
1f1c4210
VZ
404 ULONG numFetched = 0;
405 while (m_nCurrent < m_nCount && numFetched < celt) {
8e193f38
VZ
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;
269a5a34 412
1f1c4210
VZ
413 *rgelt++ = format;
414 numFetched++;
8e193f38 415 }
1f1c4210
VZ
416
417 if (pceltFetched)
418 *pceltFetched = numFetched;
419
420 return numFetched == celt ? S_OK : S_FALSE;
269a5a34
VZ
421}
422
423STDMETHODIMP wxIEnumFORMATETC::Skip(ULONG celt)
424{
8e193f38
VZ
425 wxLogTrace(wxTRACE_OleCalls, wxT("wxIEnumFORMATETC::Skip"));
426
427 m_nCurrent += celt;
428 if ( m_nCurrent < m_nCount )
429 return S_OK;
269a5a34 430
8e193f38
VZ
431 // no, can't skip this many elements
432 m_nCurrent -= celt;
269a5a34 433
8e193f38 434 return S_FALSE;
269a5a34
VZ
435}
436
437STDMETHODIMP wxIEnumFORMATETC::Reset()
438{
8e193f38 439 wxLogTrace(wxTRACE_OleCalls, wxT("wxIEnumFORMATETC::Reset"));
269a5a34 440
8e193f38 441 m_nCurrent = 0;
269a5a34 442
8e193f38 443 return S_OK;
269a5a34
VZ
444}
445
446STDMETHODIMP wxIEnumFORMATETC::Clone(IEnumFORMATETC **ppenum)
447{
8e193f38
VZ
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;
269a5a34 459
8e193f38 460 return S_OK;
269a5a34
VZ
461}
462
463// ----------------------------------------------------------------------------
464// wxIDataObject
465// ----------------------------------------------------------------------------
466
467BEGIN_IID_TABLE(wxIDataObject)
8e193f38
VZ
468 ADD_IID(Unknown)
469 ADD_IID(DataObject)
269a5a34
VZ
470END_IID_TABLE;
471
472IMPLEMENT_IUNKNOWN_METHODS(wxIDataObject)
473
474wxIDataObject::wxIDataObject(wxDataObject *pDataObject)
475{
8e193f38 476 m_pDataObject = pDataObject;
17a6a2e0 477 m_mustDelete = false;
d59ceba5
VZ
478}
479
480wxIDataObject::~wxIDataObject()
481{
40375032
VZ
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
d59ceba5
VZ
490 if ( m_mustDelete )
491 {
492 delete m_pDataObject;
493 }
269a5a34
VZ
494}
495
496// get data functions
497STDMETHODIMP wxIDataObject::GetData(FORMATETC *pformatetcIn, STGMEDIUM *pmedium)
498{
8e193f38 499 wxLogTrace(wxTRACE_OleCalls, wxT("wxIDataObject::GetData"));
269a5a34 500
8e193f38
VZ
501 // is data is in our format?
502 HRESULT hr = QueryGetData(pformatetcIn);
503 if ( FAILED(hr) )
504 return hr;
269a5a34 505
8e193f38
VZ
506 // for the bitmaps and metafiles we use the handles instead of global memory
507 // to pass the data
f4d0cce0 508 wxDataFormat format = (wxDataFormat::NativeFormat)pformatetcIn->cfFormat;
b8acf11e 509 format = HtmlFormatFixup(format);
269a5a34 510
40375032
VZ
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
8e193f38
VZ
518 switch ( format )
519 {
520 case wxDF_BITMAP:
521 pmedium->tymed = TYMED_GDI;
522 break;
523
d9317fd4
VZ
524 case wxDF_ENHMETAFILE:
525 pmedium->tymed = TYMED_ENHMF;
526 break;
527
4676948b 528#ifndef __WXWINCE__
8e193f38 529 case wxDF_METAFILE:
265b0c07
VZ
530 pmedium->hGlobal = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE,
531 sizeof(METAFILEPICT));
532 if ( !pmedium->hGlobal ) {
f6bcfd97 533 wxLogLastError(wxT("GlobalAlloc"));
265b0c07
VZ
534 return E_OUTOFMEMORY;
535 }
8e193f38
VZ
536 pmedium->tymed = TYMED_MFPICT;
537 break;
4676948b 538#endif
8e193f38
VZ
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
a8e24848
VZ
549 // we may need extra space for the buffer size
550 size += m_pDataObject->GetBufferOffset( format );
9e2896e5 551
8e193f38
VZ
552 HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, size);
553 if ( hGlobal == NULL ) {
f6bcfd97 554 wxLogLastError(wxT("GlobalAlloc"));
8e193f38
VZ
555 return E_OUTOFMEMORY;
556 }
557
558 // copy data
559 pmedium->tymed = TYMED_HGLOBAL;
560 pmedium->hGlobal = hGlobal;
561 }
269a5a34 562
8e193f38
VZ
563 pmedium->pUnkForRelease = NULL;
564
565 // do copy the data
566 hr = GetDataHere(pformatetcIn, pmedium);
567 if ( FAILED(hr) ) {
568 // free resources we allocated
265b0c07 569 if ( pmedium->tymed & (TYMED_HGLOBAL | TYMED_MFPICT) ) {
8e193f38
VZ
570 GlobalFree(pmedium->hGlobal);
571 }
572
573 return hr;
574 }
269a5a34 575
8e193f38 576 return S_OK;
269a5a34
VZ
577}
578
579STDMETHODIMP wxIDataObject::GetDataHere(FORMATETC *pformatetc,
580 STGMEDIUM *pmedium)
581{
8e193f38 582 wxLogTrace(wxTRACE_OleCalls, wxT("wxIDataObject::GetDataHere"));
269a5a34 583
8e193f38
VZ
584 // put data in caller provided medium
585 switch ( pmedium->tymed )
586 {
587 case TYMED_GDI:
d59ceba5
VZ
588 if ( !m_pDataObject->GetDataHere(wxDF_BITMAP, &pmedium->hBitmap) )
589 return E_UNEXPECTED;
8e193f38
VZ
590 break;
591
d9317fd4
VZ
592 case TYMED_ENHMF:
593 if ( !m_pDataObject->GetDataHere(wxDF_ENHMETAFILE,
594 &pmedium->hEnhMetaFile) )
595 return E_UNEXPECTED;
596 break;
597
8e193f38 598 case TYMED_MFPICT:
d9317fd4
VZ
599 // fall through - we pass METAFILEPICT through HGLOBAL
600
8e193f38
VZ
601 case TYMED_HGLOBAL:
602 {
603 // copy data
9e2896e5
VZ
604 HGLOBAL hGlobal = pmedium->hGlobal;
605 void *pBuf = GlobalLock(hGlobal);
8e193f38
VZ
606 if ( pBuf == NULL ) {
607 wxLogLastError(wxT("GlobalLock"));
608 return E_OUTOFMEMORY;
609 }
610
e1b435af 611 wxDataFormat format = pformatetc->cfFormat;
a8e24848
VZ
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 );
9e2896e5 620
d59ceba5
VZ
621 if ( !m_pDataObject->GetDataHere(format, pBuf) )
622 return E_UNEXPECTED;
8e193f38 623
9e2896e5 624 GlobalUnlock(hGlobal);
8e193f38
VZ
625 }
626 break;
627
628 default:
629 return DV_E_TYMED;
630 }
269a5a34 631
8e193f38 632 return S_OK;
269a5a34
VZ
633}
634
d26fad77 635
9e2896e5 636// set data functions
269a5a34
VZ
637STDMETHODIMP wxIDataObject::SetData(FORMATETC *pformatetc,
638 STGMEDIUM *pmedium,
639 BOOL fRelease)
640{
d59ceba5 641 wxLogTrace(wxTRACE_OleCalls, wxT("wxIDataObject::SetData"));
8e193f38 642
d59ceba5
VZ
643 switch ( pmedium->tymed )
644 {
645 case TYMED_GDI:
9e2896e5 646 m_pDataObject->SetData(wxDF_BITMAP, 0, &pmedium->hBitmap);
d59ceba5
VZ
647 break;
648
d9317fd4
VZ
649 case TYMED_ENHMF:
650 m_pDataObject->SetData(wxDF_ENHMETAFILE, 0, &pmedium->hEnhMetaFile);
651 break;
652
40375032
VZ
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
d59ceba5 664 case TYMED_MFPICT:
d9317fd4 665 // fall through - we pass METAFILEPICT through HGLOBAL
d59ceba5
VZ
666 case TYMED_HGLOBAL:
667 {
51edda6a
VZ
668 wxDataFormat format = pformatetc->cfFormat;
669
b8acf11e
RD
670 format = HtmlFormatFixup(format);
671
40375032 672 // check if this format is supported
5015e022 673 if ( !m_pDataObject->IsSupported(format, wxDataObject::Set) ) {
40375032
VZ
674 // As above, assume that unsupported format must be system
675 // data and just save it.
676 return SaveSystemData(pformatetc, pmedium, fRelease);
51edda6a
VZ
677 }
678
d59ceba5 679 // copy data
e1b435af 680 const void *pBuf = GlobalLock(pmedium->hGlobal);
d59ceba5 681 if ( pBuf == NULL ) {
f6bcfd97 682 wxLogLastError(wxT("GlobalLock"));
d59ceba5
VZ
683
684 return E_OUTOFMEMORY;
685 }
686
9e2896e5
VZ
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;
51edda6a 693 switch ( format )
9e2896e5 694 {
b8acf11e 695 case wxDF_HTML:
9e2896e5
VZ
696 case CF_TEXT:
697 case CF_OEMTEXT:
698 size = strlen((const char *)pBuf);
699 break;
afd23c22 700#if !(defined(__BORLANDC__) && (__BORLANDC__ < 0x500))
9e2896e5 701 case CF_UNICODETEXT:
2415cf67 702#if ( defined(__BORLANDC__) && (__BORLANDC__ > 0x530) )
e1b435af 703 size = std::wcslen((const wchar_t *)pBuf) * sizeof(wchar_t);
d834f22c 704#else
17ebae65 705 size = wxWcslen((const wchar_t *)pBuf) * sizeof(wchar_t);
d834f22c 706#endif
9e2896e5 707 break;
4d85bcd1 708#endif
9e2896e5 709 case CF_BITMAP:
4676948b 710#ifndef __WXWINCE__
9e2896e5
VZ
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;
4676948b 716#endif
9e2896e5 717
8ee9d618
VZ
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
4676948b 724#ifndef __WXWINCE__
265b0c07
VZ
725 case CF_METAFILEPICT:
726 size = sizeof(METAFILEPICT);
727 break;
4676948b 728#endif
9e2896e5 729 default:
a8e24848
VZ
730 pBuf = m_pDataObject->
731 GetSizeFromBuffer(pBuf, &size, format);
732 size -= m_pDataObject->GetBufferOffset(format);
9e2896e5
VZ
733 }
734
9e2896e5 735 bool ok = m_pDataObject->SetData(format, size, pBuf);
d59ceba5
VZ
736
737 GlobalUnlock(pmedium->hGlobal);
9e2896e5
VZ
738
739 if ( !ok ) {
740 return E_UNEXPECTED;
741 }
d59ceba5
VZ
742 }
743 break;
744
745 default:
746 return DV_E_TYMED;
747 }
748
749 if ( fRelease ) {
265b0c07
VZ
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 )
d59ceba5 753 {
265b0c07
VZ
754 case TYMED_GDI:
755 pmedium->hBitmap = 0;
756 break;
757
758 case TYMED_MFPICT:
759 pmedium->hMetaFilePict = 0;
760 break;
d9317fd4
VZ
761
762 case TYMED_ENHMF:
763 pmedium->hEnhMetaFile = 0;
764 break;
d59ceba5
VZ
765 }
766
767 ReleaseStgMedium(pmedium);
768 }
769
770 return S_OK;
269a5a34
VZ
771}
772
773// information functions
774STDMETHODIMP wxIDataObject::QueryGetData(FORMATETC *pformatetc)
775{
d59ceba5
VZ
776 // do we accept data in this format?
777 if ( pformatetc == NULL ) {
778 wxLogTrace(wxTRACE_OleCalls,
779 wxT("wxIDataObject::QueryGetData: invalid ptr."));
8e193f38 780
d59ceba5
VZ
781 return E_INVALIDARG;
782 }
269a5a34 783
d59ceba5
VZ
784 // the only one allowed by current COM implementation
785 if ( pformatetc->lindex != -1 ) {
786 wxLogTrace(wxTRACE_OleCalls,
9b601c24 787 wxT("wxIDataObject::QueryGetData: bad lindex %ld"),
d59ceba5 788 pformatetc->lindex);
269a5a34 789
d59ceba5
VZ
790 return DV_E_LINDEX;
791 }
269a5a34 792
d59ceba5
VZ
793 // we don't support anything other (THUMBNAIL, ICON, DOCPRINT...)
794 if ( pformatetc->dwAspect != DVASPECT_CONTENT ) {
795 wxLogTrace(wxTRACE_OleCalls,
9b601c24 796 wxT("wxIDataObject::QueryGetData: bad dwAspect %ld"),
d59ceba5
VZ
797 pformatetc->dwAspect);
798
799 return DV_E_DVASPECT;
800 }
801
802 // and now check the type of data requested
9e2896e5 803 wxDataFormat format = pformatetc->cfFormat;
b8acf11e
RD
804 format = HtmlFormatFixup(format);
805
d59ceba5 806 if ( m_pDataObject->IsSupportedFormat(format) ) {
d59ceba5 807 wxLogTrace(wxTRACE_OleCalls, wxT("wxIDataObject::QueryGetData: %s ok"),
1e8335b0 808 wxGetFormatName(format));
d59ceba5 809 }
40375032
VZ
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 }
d59ceba5
VZ
817 else {
818 wxLogTrace(wxTRACE_OleCalls,
819 wxT("wxIDataObject::QueryGetData: %s unsupported"),
1e8335b0 820 wxGetFormatName(format));
9e2896e5 821
d59ceba5
VZ
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
d59ceba5
VZ
830 wxLogTrace(wxTRACE_OleCalls,
831 wxT("wxIDataObject::QueryGetData: %s != %s"),
832 GetTymedName(tymed),
833 GetTymedName(format == wxDF_BITMAP ? TYMED_GDI
834 : TYMED_HGLOBAL));
d59ceba5
VZ
835
836 return DV_E_TYMED;
837 }
838
269a5a34 839 return S_OK;
269a5a34
VZ
840}
841
33ac7e6f 842STDMETHODIMP wxIDataObject::GetCanonicalFormatEtc(FORMATETC *WXUNUSED(pFormatetcIn),
269a5a34
VZ
843 FORMATETC *pFormatetcOut)
844{
8e193f38
VZ
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;
269a5a34 850
8e193f38 851 return DATA_S_SAMEFORMATETC;
269a5a34
VZ
852}
853
9e2896e5 854STDMETHODIMP wxIDataObject::EnumFormatEtc(DWORD dwDir,
269a5a34
VZ
855 IEnumFORMATETC **ppenumFormatEtc)
856{
8e193f38 857 wxLogTrace(wxTRACE_OleCalls, wxT("wxIDataObject::EnumFormatEtc"));
269a5a34 858
9e2896e5
VZ
859 wxDataObject::Direction dir = dwDir == DATADIR_GET ? wxDataObject::Get
860 : wxDataObject::Set;
269a5a34 861
40375032
VZ
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();
8e193f38 865
40375032
VZ
866 const ULONG
867 nFormatCount = wx_truncate_cast(ULONG, ourFormatCount + sysFormatCount);
8e193f38 868
40375032
VZ
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;
8e193f38 881 }
269a5a34 882
40375032
VZ
883 wxIEnumFORMATETC *pEnum = new wxIEnumFORMATETC(formats.get(), nFormatCount);
884 pEnum->AddRef();
885 *ppenumFormatEtc = pEnum;
886
8e193f38 887 return S_OK;
269a5a34
VZ
888}
889
9e2896e5 890// ----------------------------------------------------------------------------
269a5a34 891// advise sink functions (not implemented)
9e2896e5
VZ
892// ----------------------------------------------------------------------------
893
33ac7e6f
KB
894STDMETHODIMP wxIDataObject::DAdvise(FORMATETC *WXUNUSED(pformatetc),
895 DWORD WXUNUSED(advf),
896 IAdviseSink *WXUNUSED(pAdvSink),
897 DWORD *WXUNUSED(pdwConnection))
269a5a34
VZ
898{
899 return OLE_E_ADVISENOTSUPPORTED;
900}
901
33ac7e6f 902STDMETHODIMP wxIDataObject::DUnadvise(DWORD WXUNUSED(dwConnection))
269a5a34
VZ
903{
904 return OLE_E_ADVISENOTSUPPORTED;
905}
906
33ac7e6f 907STDMETHODIMP wxIDataObject::EnumDAdvise(IEnumSTATDATA **WXUNUSED(ppenumAdvise))
269a5a34
VZ
908{
909 return OLE_E_ADVISENOTSUPPORTED;
910}
911
912// ----------------------------------------------------------------------------
913// wxDataObject
914// ----------------------------------------------------------------------------
915
916wxDataObject::wxDataObject()
917{
d59ceba5
VZ
918 m_pIDataObject = new wxIDataObject(this);
919 m_pIDataObject->AddRef();
269a5a34
VZ
920}
921
922wxDataObject::~wxDataObject()
923{
d59ceba5
VZ
924 ReleaseInterface(m_pIDataObject);
925}
926
927void wxDataObject::SetAutoDelete()
928{
929 ((wxIDataObject *)m_pIDataObject)->SetDeleteFlag();
930 m_pIDataObject->Release();
931
070d6391 932 // so that the dtor doesn't crash
d59ceba5 933 m_pIDataObject = NULL;
269a5a34
VZ
934}
935
a8e24848 936size_t wxDataObject::GetBufferOffset(const wxDataFormat& format )
e1b435af 937{
a8e24848
VZ
938 // if we prepend the size of the data to the buffer itself, account for it
939 return NeedsVerbatimData(format) ? 0 : sizeof(size_t);
e1b435af
MB
940}
941
abb88ef3
VZ
942const void *wxDataObject::GetSizeFromBuffer(const void *buffer,
943 size_t *size,
cb626df2 944 const wxDataFormat& WXUNUSED(format))
e1b435af 945{
24aab8e8
MW
946 // hack: the third parameter is declared non-const in Wine's headers so
947 // cast away the const
abb88ef3 948 const size_t realsz = ::HeapSize(::GetProcessHeap(), 0,
5c33522f 949 const_cast<void*>(buffer));
51d05226 950 if ( realsz == (size_t)-1 )
a8e24848
VZ
951 {
952 // note that HeapSize() does not set last error
953 wxLogApiError(wxT("HeapSize"), 0);
954 return NULL;
955 }
956
957 *size = realsz;
e1b435af 958
abb88ef3 959 return buffer;
e1b435af
MB
960}
961
962void* wxDataObject::SetSizeInBuffer( void* buffer, size_t size,
a8e24848 963 const wxDataFormat& format )
e1b435af 964{
a8e24848
VZ
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 }
e1b435af 971
a8e24848 972 return p;
e1b435af
MB
973}
974
4b6a582b 975#if wxDEBUG_LEVEL
8e193f38 976
f6bcfd97 977const wxChar *wxDataObject::GetFormatName(wxDataFormat format)
d9317fd4
VZ
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
f6bcfd97 984 static wxChar s_szBuf[256];
d9317fd4 985 switch ( format ) {
f6bcfd97
BP
986 case CF_TEXT: return wxT("CF_TEXT");
987 case CF_BITMAP: return wxT("CF_BITMAP");
f6bcfd97
BP
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");
569f027b
VS
998#ifndef __WXWINCE__
999 case CF_METAFILEPICT: return wxT("CF_METAFILEPICT");
f6bcfd97 1000 case CF_ENHMETAFILE: return wxT("CF_ENHMETAFILE");
f6bcfd97 1001 case CF_LOCALE: return wxT("CF_LOCALE");
569f027b
VS
1002 case CF_HDROP: return wxT("CF_HDROP");
1003#endif
8e193f38 1004
d9317fd4 1005 default:
c77ae1d9 1006 if ( !::GetClipboardFormatName(format, s_szBuf, WXSIZEOF(s_szBuf)) )
d9317fd4
VZ
1007 {
1008 // it must be a new predefined format we don't know the name of
f6bcfd97 1009 wxSprintf(s_szBuf, wxT("unknown CF (0x%04x)"), format.GetFormatId());
d9317fd4 1010 }
8e193f38 1011
d9317fd4 1012 return s_szBuf;
8e193f38 1013 }
1e8335b0 1014
d9317fd4
VZ
1015 #ifdef __VISUALC__
1016 #pragma warning(default:4063)
1017 #endif // VC++
269a5a34
VZ
1018}
1019
4b6a582b 1020#endif // wxDEBUG_LEVEL
1e8335b0 1021
3f480da3 1022// ----------------------------------------------------------------------------
9e2896e5 1023// wxBitmapDataObject supports CF_DIB format
3f480da3
VZ
1024// ----------------------------------------------------------------------------
1025
be69f971
VZ
1026// TODO: support CF_DIB under Windows CE as well
1027
9e2896e5 1028size_t wxBitmapDataObject::GetDataSize() const
3f480da3 1029{
be69f971 1030#if wxUSE_WXDIB && !defined(__WXWINCE__)
22be0335 1031 return wxDIB::ConvertFromBitmap(NULL, GetHbitmapOf(GetBitmap()));
4cb88a72
JS
1032#else
1033 return 0;
1034#endif
3f480da3
VZ
1035}
1036
9e2896e5 1037bool wxBitmapDataObject::GetDataHere(void *buf) const
3f480da3 1038{
be69f971 1039#if wxUSE_WXDIB && !defined(__WXWINCE__)
22be0335
VZ
1040 BITMAPINFO * const pbi = (BITMAPINFO *)buf;
1041
1042 return wxDIB::ConvertFromBitmap(pbi, GetHbitmapOf(GetBitmap())) != 0;
4cb88a72 1043#else
17a6a2e0
WS
1044 wxUnusedVar(buf);
1045 return false;
4cb88a72 1046#endif
3f480da3
VZ
1047}
1048
33ac7e6f 1049bool wxBitmapDataObject::SetData(size_t WXUNUSED(len), const void *buf)
3f480da3 1050{
be69f971 1051#if wxUSE_WXDIB && !defined(__WXWINCE__)
22be0335 1052 const BITMAPINFO * const pbmi = (const BITMAPINFO *)buf;
9e2896e5 1053
22be0335 1054 HBITMAP hbmp = wxDIB::ConvertToBitmap(pbmi);
3f480da3 1055
22be0335
VZ
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
9e2896e5
VZ
1063
1064 SetBitmap(bitmap);
3f480da3 1065
17a6a2e0 1066 return true;
4cb88a72 1067#else
17a6a2e0
WS
1068 wxUnusedVar(buf);
1069 return false;
4cb88a72 1070#endif
3f480da3
VZ
1071}
1072
9e2896e5
VZ
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
1082size_t wxBitmapDataObject2::GetDataSize() const
3f480da3 1083{
9e2896e5 1084 return 0;
3f480da3
VZ
1085}
1086
9e2896e5 1087bool wxBitmapDataObject2::GetDataHere(void *pBuf) const
3f480da3 1088{
9e2896e5
VZ
1089 // we put a bitmap handle into pBuf
1090 *(WXHBITMAP *)pBuf = GetBitmap().GetHBITMAP();
1091
17a6a2e0 1092 return true;
3f480da3
VZ
1093}
1094
265b0c07 1095bool wxBitmapDataObject2::SetData(size_t WXUNUSED(len), const void *pBuf)
3f480da3 1096{
9e2896e5 1097 HBITMAP hbmp = *(HBITMAP *)pBuf;
3f480da3 1098
9e2896e5
VZ
1099 BITMAP bmp;
1100 if ( !GetObject(hbmp, sizeof(BITMAP), &bmp) )
1101 {
f6bcfd97 1102 wxLogLastError(wxT("GetObject(HBITMAP)"));
9e2896e5 1103 }
8e193f38 1104
9e2896e5
VZ
1105 wxBitmap bitmap(bmp.bmWidth, bmp.bmHeight, bmp.bmPlanes);
1106 bitmap.SetHBITMAP((WXHBITMAP)hbmp);
d59ceba5 1107
a1b806b9 1108 if ( !bitmap.IsOk() ) {
9e2896e5
VZ
1109 wxFAIL_MSG(wxT("pasting/dropping invalid bitmap"));
1110
17a6a2e0 1111 return false;
9e2896e5
VZ
1112 }
1113
1114 SetBitmap(bitmap);
1115
17a6a2e0 1116 return true;
d59ceba5
VZ
1117}
1118
9e2896e5 1119#if 0
8e193f38
VZ
1120
1121size_t wxBitmapDataObject::GetDataSize(const wxDataFormat& format) const
1122{
d59ceba5
VZ
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 {
f6bcfd97 1137 wxLogLastError(wxT("GetDIBits(NULL)"));
d59ceba5
VZ
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 }
8e193f38
VZ
1149}
1150
d59ceba5 1151bool wxBitmapDataObject::GetDataHere(const wxDataFormat& format,
8e193f38
VZ
1152 void *pBuf) const
1153{
a1b806b9 1154 wxASSERT_MSG( m_bitmap.IsOk(), wxT("copying invalid bitmap") );
d59ceba5
VZ
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 {
f6bcfd97 1170 wxLogLastError(wxT("GetDIBits(NULL)"));
d59ceba5
VZ
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 {
f6bcfd97 1179 wxLogLastError(wxT("GetDIBits"));
d59ceba5 1180
17a6a2e0 1181 return false;
d59ceba5
VZ
1182 }
1183 }
1184 else // CF_BITMAP
1185 {
1186 // we put a bitmap handle into pBuf
1187 *(HBITMAP *)pBuf = hbmp;
1188 }
1189
17a6a2e0 1190 return true;
d59ceba5
VZ
1191}
1192
9e2896e5
VZ
1193bool wxBitmapDataObject::SetData(const wxDataFormat& format,
1194 size_t size, const void *pBuf)
d59ceba5
VZ
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 {
f6bcfd97 1209 wxLogLastError(wxT("CreateDIBitmap"));
d59ceba5
VZ
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 {
f6bcfd97 1223 wxLogLastError(wxT("GetObject(HBITMAP)"));
d59ceba5
VZ
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
a1b806b9 1233 wxASSERT_MSG( m_bitmap.IsOk(), wxT("pasting invalid bitmap") );
d59ceba5 1234
17a6a2e0 1235 return true;
8e193f38
VZ
1236}
1237
9e2896e5
VZ
1238#endif // 0
1239
1240// ----------------------------------------------------------------------------
1241// wxFileDataObject
1242// ----------------------------------------------------------------------------
1243
0c0d1521
WS
1244bool wxFileDataObject::SetData(size_t WXUNUSED(size),
1245 const void *WXUNUSED_IN_WINCE(pData))
9e2896e5 1246{
4676948b 1247#ifndef __WXWINCE__
9e2896e5
VZ
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
51edda6a
VZ
1261 wxCHECK_MSG ( nFiles != (UINT)-1, FALSE, wxT("wrong HDROP handle") );
1262
9e2896e5
VZ
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
de564874 1270 UINT len2 = ::DragQueryFile(hdrop, n, wxStringBuffer(str, len), len);
9e2896e5
VZ
1271 m_filenames.Add(str);
1272
1273 if ( len2 != len - 1 ) {
f6bcfd97
BP
1274 wxLogDebug(wxT("In wxFileDropTarget::OnDrop DragQueryFile returned\
1275 %d characters, %d expected."), len2, len - 1);
9e2896e5
VZ
1276 }
1277 }
1278
17a6a2e0 1279 return true;
4676948b 1280#else
17a6a2e0 1281 return false;
4676948b 1282#endif
9e2896e5
VZ
1283}
1284
8b85d24e
VZ
1285void 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
1293size_t wxFileDataObject::GetDataSize() const
1294{
4676948b 1295#ifndef __WXWINCE__
150194b9
VZ
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
8b85d24e
VZ
1298
1299 // if no filenames in list, size is 0
150194b9 1300 if ( m_filenames.empty() )
dd10a646 1301 return 0;
8b85d24e 1302
150194b9
VZ
1303#if wxUSE_UNICODE_MSLU
1304 size_t sizeOfChar;
dddf9e14 1305 if ( wxGetOsVersion() == wxOS_WINDOWS_9X )
150194b9
VZ
1306 {
1307 // Win9x always uses ANSI file names and MSLU doesn't help with this
784d9056 1308 sizeOfChar = 1;
150194b9
VZ
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
070d6391 1318 // initial size of DROPFILES struct + null byte
150194b9 1319 size_t sz = sizeof(DROPFILES) + sizeOfChar;
8b85d24e 1320
150194b9 1321 const size_t count = m_filenames.size();
dd10a646 1322 for ( size_t i = 0; i < count; i++ )
8b85d24e
VZ
1323 {
1324 // add filename length plus null byte
150194b9
VZ
1325 size_t len;
1326#if wxUSE_UNICODE_MSLU
784d9056 1327 if ( sizeOfChar == 1 )
e0a050e3 1328 len = strlen(m_filenames[i].mb_str(*wxConvFileName));
150194b9
VZ
1329 else
1330#endif // wxUSE_UNICODE_MSLU
1331 len = m_filenames[i].length();
1332
1333 sz += (len + 1) * sizeOfChar;
8b85d24e 1334 }
dd10a646 1335
8b85d24e 1336 return sz;
4676948b
JS
1337#else
1338 return 0;
1339#endif
8b85d24e
VZ
1340}
1341
0c0d1521 1342bool wxFileDataObject::GetDataHere(void *WXUNUSED_IN_WINCE(pData)) const
8b85d24e 1343{
4676948b 1344#ifndef __WXWINCE__
8b85d24e
VZ
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
150194b9 1349 if ( !pData || m_filenames.empty() )
17a6a2e0 1350 return false;
8b85d24e
VZ
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);
dd10a646 1357 pDrop->fNC = FALSE; // not non-client coords
150194b9 1358#if wxUSE_UNICODE_MSLU
dddf9e14 1359 pDrop->fWide = wxGetOsVersion() != wxOS_WINDOWS_9X ? TRUE : FALSE;
150194b9
VZ
1360#else
1361 pDrop->fWide = wxUSE_UNICODE;
1362#endif
1363
784d9056 1364 const size_t sizeOfChar = pDrop->fWide ? sizeof(wchar_t) : 1;
8b85d24e
VZ
1365
1366 // set start of filenames list (null separated)
150194b9 1367 BYTE *pbuf = (BYTE *)(pDrop + 1);
8b85d24e 1368
150194b9
VZ
1369 const size_t count = m_filenames.size();
1370 for ( size_t i = 0; i < count; i++ )
8b85d24e
VZ
1371 {
1372 // copy filename to pbuf and add null terminator
150194b9
VZ
1373 size_t len;
1374#if wxUSE_UNICODE_MSLU
784d9056 1375 if ( sizeOfChar == 1 )
150194b9 1376 {
e0a050e3 1377 wxCharBuffer buf(m_filenames[i].mb_str(*wxConvFileName));
150194b9
VZ
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();
017dc06b 1385 memcpy(pbuf, m_filenames[i].t_str(), len*sizeOfChar);
150194b9
VZ
1386 }
1387
1388 pbuf += len*sizeOfChar;
1389
1390 memset(pbuf, 0, sizeOfChar);
1391 pbuf += sizeOfChar;
8b85d24e 1392 }
dd10a646 1393
c5639a87 1394 // add final null terminator
150194b9 1395 memset(pbuf, 0, sizeOfChar);
8b85d24e 1396
17a6a2e0 1397 return true;
4676948b 1398#else
17a6a2e0 1399 return false;
4676948b 1400#endif
8b85d24e
VZ
1401}
1402
444ad3a7
VZ
1403// ----------------------------------------------------------------------------
1404// wxURLDataObject
1405// ----------------------------------------------------------------------------
1406
219b657f
JS
1407// Work around bug in Wine headers
1408#if defined(__WINE__) && defined(CFSTR_SHELLURL) && wxUSE_UNICODE
1409#undef CFSTR_SHELLURL
9a83f860 1410#define CFSTR_SHELLURL wxT("CFSTR_SHELLURL")
219b657f
JS
1411#endif
1412
4a09bc4e 1413class CFSTR_SHELLURLDataObject : public wxCustomDataObject
e1b435af
MB
1414{
1415public:
1416 CFSTR_SHELLURLDataObject() : wxCustomDataObject(CFSTR_SHELLURL) {}
6f02a879 1417
574c939e 1418 virtual size_t GetBufferOffset( const wxDataFormat& WXUNUSED(format) )
e1b435af
MB
1419 {
1420 return 0;
1421 }
1422
1423 virtual const void* GetSizeFromBuffer( const void* buffer, size_t* size,
574c939e 1424 const wxDataFormat& WXUNUSED(format) )
e1b435af
MB
1425 {
1426 // CFSTR_SHELLURL is _always_ ANSI text
1427 *size = strlen( (const char*)buffer );
1428
1429 return buffer;
1430 }
1431
574c939e
KB
1432 virtual void* SetSizeInBuffer( void* buffer, size_t WXUNUSED(size),
1433 const wxDataFormat& WXUNUSED(format) )
e1b435af
MB
1434 {
1435 return buffer;
1436 }
4a09bc4e 1437
c0c133e1 1438 wxDECLARE_NO_COPY_CLASS(CFSTR_SHELLURLDataObject);
e1b435af
MB
1439};
1440
4a09bc4e
RD
1441
1442
0463eea9 1443wxURLDataObject::wxURLDataObject(const wxString& url)
444ad3a7 1444{
ab250e5c
VZ
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
444ad3a7 1448 Add(new wxTextDataObject);
e6d318c2 1449 Add(new CFSTR_SHELLURLDataObject());
444ad3a7
VZ
1450
1451 // we don't have any data yet
1452 m_dataObjectLast = NULL;
0463eea9
VZ
1453
1454 if ( !url.empty() )
1455 SetURL(url);
444ad3a7
VZ
1456}
1457
1458bool 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
1470wxString wxURLDataObject::GetURL() const
1471{
1472 wxString url;
9a83f860 1473 wxCHECK_MSG( m_dataObjectLast, url, wxT("no data in wxURLDataObject") );
444ad3a7 1474
791f7574
VZ
1475 if ( m_dataObjectLast->GetPreferredFormat() == CFSTR_SHELLURL )
1476 {
1477 const size_t len = m_dataObjectLast->GetDataSize();
1478 if ( !len )
1479 return wxString();
444ad3a7 1480
791f7574
VZ
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 }
444ad3a7
VZ
1497
1498 return url;
1499}
1500
e6d318c2
RD
1501void wxURLDataObject::SetURL(const wxString& url)
1502{
ab250e5c
VZ
1503 wxCharBuffer urlMB(url.mb_str());
1504 if ( urlMB )
1505 {
cd67a80a
VZ
1506 const size_t len = strlen(urlMB);
1507
b9a5faed 1508#if !wxUSE_UNICODE
cd67a80a
VZ
1509 // wxTextDataObject takes the number of characters in the string, not
1510 // the size of the buffer (which would be len+1)
ab250e5c 1511 SetData(wxDF_TEXT, len, urlMB);
cd67a80a
VZ
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);
ab250e5c 1518 }
4a09bc4e 1519
b9a5faed 1520#if wxUSE_UNICODE
cd67a80a 1521 SetData(wxDF_UNICODETEXT, url.length()*sizeof(wxChar), url.wc_str());
b9a5faed 1522#endif
e6d318c2
RD
1523}
1524
269a5a34
VZ
1525// ----------------------------------------------------------------------------
1526// private functions
1527// ----------------------------------------------------------------------------
8e193f38 1528
4b6a582b 1529#if wxDEBUG_LEVEL
8e193f38 1530
d59ceba5
VZ
1531static 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:
dfd2e675 1543 wxSprintf(s_szBuf, wxT("type of media format %ld (unknown)"), tymed);
d59ceba5
VZ
1544 return s_szBuf;
1545 }
269a5a34 1546}
5260b1c5 1547
8e193f38 1548#endif // Debug
2845ddc2 1549
21709999 1550#else // not using OLE at all
9205cb3f 1551
21709999
JS
1552// ----------------------------------------------------------------------------
1553// wxDataObject
1554// ----------------------------------------------------------------------------
1555
461dae94
VZ
1556#if wxUSE_DATAOBJ
1557
21709999
JS
1558wxDataObject::wxDataObject()
1559{
1560}
1561
1562wxDataObject::~wxDataObject()
1563{
1564}
1565
1566void wxDataObject::SetAutoDelete()
1567{
1568}
1569
9205cb3f 1570const wxChar *wxDataObject::GetFormatName(wxDataFormat WXUNUSED(format))
21709999
JS
1571{
1572 return NULL;
1573}
1574
9205cb3f
VZ
1575#endif // wxUSE_DATAOBJ
1576
1577#endif // wxUSE_OLE/!wxUSE_OLE
5260b1c5 1578
461dae94 1579