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