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