]> git.saurik.com Git - wxWidgets.git/blob - src/msw/ole/dataobj.cpp
Fixed bug in MDI
[wxWidgets.git] / src / msw / ole / dataobj.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: 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 license
10 ///////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 #ifdef __GNUG__
21 #pragma implementation "dataobj.h"
22 #endif
23
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
26
27 #if defined(__BORLANDC__)
28 #pragma hdrstop
29 #endif
30
31 #include <wx/defs.h>
32
33 #if defined(__WIN32__) && !defined(__GNUWIN32__)
34
35 #include <wx/log.h>
36 #include <wx/msw/ole/oleutils.h>
37 #include <wx/msw/ole/dataobj.h>
38
39 #ifndef __WIN32__
40 #include <ole2.h>
41 #include <olestd.h>
42 #endif
43
44 // ----------------------------------------------------------------------------
45 // functions
46 // ----------------------------------------------------------------------------
47
48 static const char *GetTymedName(DWORD tymed);
49
50 // ----------------------------------------------------------------------------
51 // wxIEnumFORMATETC interface implementation
52 // ----------------------------------------------------------------------------
53 class wxIEnumFORMATETC : public IEnumFORMATETC
54 {
55 public:
56 wxIEnumFORMATETC(CLIPFORMAT cf);
57
58 DECLARE_IUNKNOWN_METHODS;
59
60 // IEnumFORMATETC
61 STDMETHODIMP Next(ULONG celt, FORMATETC *rgelt, ULONG *pceltFetched);
62 STDMETHODIMP Skip(ULONG celt);
63 STDMETHODIMP Reset();
64 STDMETHODIMP Clone(IEnumFORMATETC **ppenum);
65
66 private:
67 FORMATETC m_format; // (unique @@@) format we can provide data in
68 ULONG m_nCurrent; // current enum position (currently either 0 or 1)
69 };
70
71 // ----------------------------------------------------------------------------
72 // wxIDataObject implementation of IDataObject interface
73 // ----------------------------------------------------------------------------
74 class wxIDataObject : public IDataObject
75 {
76 public:
77 wxIDataObject(wxDataObject *pDataObject);
78
79 DECLARE_IUNKNOWN_METHODS;
80
81 // IDataObject
82 STDMETHODIMP GetData(FORMATETC *pformatetcIn, STGMEDIUM *pmedium);
83 STDMETHODIMP GetDataHere(FORMATETC *pformatetc, STGMEDIUM *pmedium);
84 STDMETHODIMP QueryGetData(FORMATETC *pformatetc);
85 STDMETHODIMP GetCanonicalFormatEtc(FORMATETC *In, FORMATETC *pOut);
86 STDMETHODIMP SetData(FORMATETC *pfetc, STGMEDIUM *pmedium, BOOL fRelease);
87 STDMETHODIMP EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC **ppenumFEtc);
88 STDMETHODIMP DAdvise(FORMATETC *pfetc, DWORD ad, IAdviseSink *p, DWORD *pdw);
89 STDMETHODIMP DUnadvise(DWORD dwConnection);
90 STDMETHODIMP EnumDAdvise(IEnumSTATDATA **ppenumAdvise);
91
92 private:
93 wxDataObject *m_pDataObject; // pointer to C++ class we belong to
94 };
95
96 // ============================================================================
97 // implementation
98 // ============================================================================
99
100 // ----------------------------------------------------------------------------
101 // wxIEnumFORMATETC
102 // ----------------------------------------------------------------------------
103
104 BEGIN_IID_TABLE(wxIEnumFORMATETC)
105 ADD_IID(Unknown)
106 ADD_IID(EnumFORMATETC)
107 END_IID_TABLE;
108
109 IMPLEMENT_IUNKNOWN_METHODS(wxIEnumFORMATETC)
110
111 wxIEnumFORMATETC::wxIEnumFORMATETC(CLIPFORMAT cf)
112 {
113 m_format.cfFormat = cf;
114 m_format.ptd = NULL;
115 m_format.dwAspect = DVASPECT_CONTENT;
116 m_format.lindex = -1;
117 m_format.tymed = TYMED_HGLOBAL;
118 m_cRef = 0;
119 m_nCurrent = 0;
120 }
121
122 STDMETHODIMP wxIEnumFORMATETC::Next(ULONG celt,
123 FORMATETC *rgelt,
124 ULONG *pceltFetched)
125 {
126 wxLogTrace("wxIEnumFORMATETC::Next");
127
128 if ( celt > 1 )
129 return S_FALSE;
130
131 if ( m_nCurrent == 0 ) {
132 *rgelt = m_format;
133 m_nCurrent++;
134
135 return S_OK;
136 }
137 else
138 return S_FALSE;
139 }
140
141 STDMETHODIMP wxIEnumFORMATETC::Skip(ULONG celt)
142 {
143 wxLogTrace("wxIEnumFORMATETC::Skip");
144
145 if ( m_nCurrent == 0 )
146 m_nCurrent++;
147
148 return S_FALSE;
149 }
150
151 STDMETHODIMP wxIEnumFORMATETC::Reset()
152 {
153 wxLogTrace("wxIEnumFORMATETC::Reset");
154
155 m_nCurrent = 0;
156
157 return S_OK;
158 }
159
160 STDMETHODIMP wxIEnumFORMATETC::Clone(IEnumFORMATETC **ppenum)
161 {
162 wxLogTrace("wxIEnumFORMATETC::Clone");
163
164 wxIEnumFORMATETC *pNew = new wxIEnumFORMATETC(m_format.cfFormat);
165 pNew->AddRef();
166 *ppenum = pNew;
167
168 return S_OK;
169 }
170
171 // ----------------------------------------------------------------------------
172 // wxIDataObject
173 // ----------------------------------------------------------------------------
174
175 BEGIN_IID_TABLE(wxIDataObject)
176 ADD_IID(Unknown)
177 ADD_IID(DataObject)
178 END_IID_TABLE;
179
180 IMPLEMENT_IUNKNOWN_METHODS(wxIDataObject)
181
182 wxIDataObject::wxIDataObject(wxDataObject *pDataObject)
183 {
184 m_cRef = 0;
185 m_pDataObject = pDataObject;
186 }
187
188 // get data functions
189 STDMETHODIMP wxIDataObject::GetData(FORMATETC *pformatetcIn, STGMEDIUM *pmedium)
190 {
191 wxLogTrace("wxIDataObject::GetData");
192
193 // is data is in our format?
194 HRESULT hr = QueryGetData(pformatetcIn);
195 if ( FAILED(hr) )
196 return hr;
197
198 // alloc memory
199 HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE,
200 m_pDataObject->GetDataSize());
201 if ( hGlobal == NULL ) {
202 wxLogLastError("GlobalAlloc");
203 return E_OUTOFMEMORY;
204 }
205
206 // copy data
207 pmedium->tymed = TYMED_HGLOBAL;
208 pmedium->hGlobal = hGlobal;
209 pmedium->pUnkForRelease = NULL;
210
211 hr = GetDataHere(pformatetcIn, pmedium);
212 if ( FAILED(hr) ) {
213 GlobalFree(hGlobal);
214 return hr;
215 }
216
217 return S_OK;
218 }
219
220 STDMETHODIMP wxIDataObject::GetDataHere(FORMATETC *pformatetc,
221 STGMEDIUM *pmedium)
222 {
223 wxLogTrace("wxIDataObject::GetDataHere");
224
225 // put data in caller provided medium
226 if ( pmedium->tymed != TYMED_HGLOBAL )
227 return DV_E_TYMED;
228
229 // copy data
230 void *pBuf = GlobalLock(pmedium->hGlobal);
231 if ( pBuf == NULL ) {
232 wxLogLastError("GlobalLock");
233 return E_OUTOFMEMORY;
234 }
235
236 m_pDataObject->GetDataHere(pBuf);
237
238 GlobalUnlock(pmedium->hGlobal);
239
240 return S_OK;
241 }
242
243 // set data functions (not implemented)
244 STDMETHODIMP wxIDataObject::SetData(FORMATETC *pformatetc,
245 STGMEDIUM *pmedium,
246 BOOL fRelease)
247 {
248 wxLogTrace("wxIDataObject::SetData");
249 return E_NOTIMPL;
250 }
251
252 // information functions
253 STDMETHODIMP wxIDataObject::QueryGetData(FORMATETC *pformatetc)
254 {
255 // do we accept data in this format?
256 if ( pformatetc == NULL ) {
257 wxLogTrace("wxIDataObject::QueryGetData: invalid ptr.");
258 return E_INVALIDARG;
259 }
260
261 // the only one allowed by current COM implementation
262 if ( pformatetc->lindex != -1 ) {
263 wxLogTrace("wxIDataObject::QueryGetData: bad lindex %d",
264 pformatetc->lindex);
265 return DV_E_LINDEX;
266 }
267
268 // we don't support anything other (THUMBNAIL, ICON, DOCPRINT...)
269 if ( pformatetc->dwAspect != DVASPECT_CONTENT ) {
270 wxLogTrace("wxIDataObject::QueryGetData: bad dwAspect %d",
271 pformatetc->dwAspect);
272 return DV_E_DVASPECT;
273 }
274
275 // @@ we only transfer data by global memory (bad for large amounts of it!)
276 if ( !(pformatetc->tymed & TYMED_HGLOBAL) ) {
277 wxLogTrace("wxIDataObject::QueryGetData: %s != TYMED_HGLOBAL.",
278 GetTymedName(pformatetc->tymed));
279 return DV_E_TYMED;
280 }
281
282 // and now check the type of data requested
283 if ( m_pDataObject->IsSupportedFormat(pformatetc->cfFormat) ) {
284 wxLogTrace("wxIDataObject::QueryGetData: %s ok",
285 wxDataObject::GetFormatName(pformatetc->cfFormat));
286 return S_OK;
287 }
288 else {
289 wxLogTrace("wxIDataObject::QueryGetData: %s unsupported",
290 wxDataObject::GetFormatName(pformatetc->cfFormat));
291 return DV_E_FORMATETC;
292 }
293 }
294
295 STDMETHODIMP wxIDataObject::GetCanonicalFormatEtc(FORMATETC *pFormatetcIn,
296 FORMATETC *pFormatetcOut)
297 {
298 wxLogTrace("wxIDataObject::GetCanonicalFormatEtc");
299
300 // @@ implementation is trivial, we might want something better here
301 if ( pFormatetcOut != NULL )
302 pFormatetcOut->ptd = NULL;
303 return DATA_S_SAMEFORMATETC;
304 }
305
306 STDMETHODIMP wxIDataObject::EnumFormatEtc(DWORD dwDirection,
307 IEnumFORMATETC **ppenumFormatEtc)
308 {
309 wxLogTrace("wxIDataObject::EnumFormatEtc");
310
311 if ( dwDirection == DATADIR_SET ) {
312 // we don't allow setting of data anyhow
313 return E_NOTIMPL;
314 }
315
316 wxIEnumFORMATETC *pEnum =
317 new wxIEnumFORMATETC(m_pDataObject->GetPreferredFormat());
318 pEnum->AddRef();
319 *ppenumFormatEtc = pEnum;
320
321 return S_OK;
322 }
323
324 // advise sink functions (not implemented)
325 STDMETHODIMP wxIDataObject::DAdvise(FORMATETC *pformatetc,
326 DWORD advf,
327 IAdviseSink *pAdvSink,
328 DWORD *pdwConnection)
329 {
330 return OLE_E_ADVISENOTSUPPORTED;
331 }
332
333 STDMETHODIMP wxIDataObject::DUnadvise(DWORD dwConnection)
334 {
335 return OLE_E_ADVISENOTSUPPORTED;
336 }
337
338 STDMETHODIMP wxIDataObject::EnumDAdvise(IEnumSTATDATA **ppenumAdvise)
339 {
340 return OLE_E_ADVISENOTSUPPORTED;
341 }
342
343 // ----------------------------------------------------------------------------
344 // wxDataObject
345 // ----------------------------------------------------------------------------
346
347 wxDataObject::wxDataObject()
348 {
349 m_pIDataObject = new wxIDataObject(this);
350 m_pIDataObject->AddRef();
351 }
352
353 wxDataObject::~wxDataObject()
354 {
355 m_pIDataObject->Release();
356 }
357
358 const char *wxDataObject::GetFormatName(wxDataFormat format)
359 {
360 #ifdef __WXDEBUG__
361 static char s_szBuf[128];
362 switch ( format ) {
363 case CF_TEXT: return "CF_TEXT";
364 case CF_BITMAP: return "CF_BITMAP";
365 case CF_METAFILEPICT: return "CF_METAFILEPICT";
366 case CF_SYLK: return "CF_SYLK";
367 case CF_DIF: return "CF_DIF";
368 case CF_TIFF: return "CF_TIFF";
369 case CF_OEMTEXT: return "CF_OEMTEXT";
370 case CF_DIB: return "CF_DIB";
371 case CF_PALETTE: return "CF_PALETTE";
372 case CF_PENDATA: return "CF_PENDATA";
373 case CF_RIFF: return "CF_RIFF";
374 case CF_WAVE: return "CF_WAVE";
375 case CF_UNICODETEXT: return "CF_UNICODETEXT";
376 case CF_ENHMETAFILE: return "CF_ENHMETAFILE";
377 case CF_HDROP: return "CF_HDROP";
378 case CF_LOCALE: return "CF_LOCALE";
379 default:
380 sprintf(s_szBuf, "clipboard format %d (unknown)", format);
381 return s_szBuf;
382 }
383 #else
384 return "";
385 #endif
386 }
387
388 // ----------------------------------------------------------------------------
389 // private functions
390 // ----------------------------------------------------------------------------
391 static const char *GetTymedName(DWORD tymed)
392 {
393 static char s_szBuf[128];
394 switch ( tymed ) {
395 case TYMED_HGLOBAL: return "TYMED_HGLOBAL";
396 case TYMED_FILE: return "TYMED_FILE";
397 case TYMED_ISTREAM: return "TYMED_ISTREAM";
398 case TYMED_ISTORAGE: return "TYMED_ISTORAGE";
399 case TYMED_GDI: return "TYMED_GDI";
400 case TYMED_MFPICT: return "TYMED_MFPICT";
401 case TYMED_ENHMF: return "TYMED_ENHMF";
402 default:
403 sprintf(s_szBuf, "type of media format %d (unknown)", tymed);
404 return s_szBuf;
405 }
406 }
407
408 #endif
409