]> git.saurik.com Git - wxWidgets.git/blob - src/msw/ole/oleutils.cpp
Refactor SAFEARRAY creation code in wxConvertStringFromOle().
[wxWidgets.git] / src / msw / ole / oleutils.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/ole/oleutils.cpp
3 // Purpose: implementation of OLE helper functions
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 19.02.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 #if wxUSE_OLE
28
29 #ifndef WX_PRECOMP
30 #include "wx/log.h"
31 #endif
32
33 #ifndef __CYGWIN10__
34
35 #include "wx/msw/private.h"
36
37 #ifdef __WXWINCE__
38 #include <winreg.h>
39 #include <ole2.h>
40
41 #define GUID_DEFINED
42 #define UUID_DEFINED
43 #endif
44
45 // OLE
46 #ifndef __WXWINCE__
47 #include "wx/msw/ole/uuid.h"
48 #endif
49
50 #include "wx/msw/ole/oleutils.h"
51
52 #if defined(__VISUALC__) && (__VISUALC__ > 1000)
53 #include <docobj.h>
54 #endif
55
56 // ============================================================================
57 // Implementation
58 // ============================================================================
59
60 // return true if the iid is in the array
61 WXDLLEXPORT bool IsIidFromList(REFIID riid, const IID *aIids[], size_t nCount)
62 {
63 for ( size_t i = 0; i < nCount; i++ ) {
64 if ( riid == *aIids[i] )
65 return true;
66 }
67
68 return false;
69 }
70
71 WXDLLEXPORT BSTR wxConvertStringToOle(const wxString& str)
72 {
73 return wxBasicString(str).Get();
74 }
75
76 WXDLLEXPORT wxString wxConvertStringFromOle(BSTR bStr)
77 {
78 // NULL BSTR is equivalent to an empty string (this is the convention used
79 // by VB and hence we must follow it)
80 if ( !bStr )
81 return wxString();
82
83 const int len = SysStringLen(bStr);
84
85 #if wxUSE_UNICODE
86 wxString str(bStr, len);
87 #else
88 wxString str;
89 if (len)
90 {
91 wxStringBufferLength buf(str, len); // asserts if len == 0
92 buf.SetLength(WideCharToMultiByte(CP_ACP, 0 /* no flags */,
93 bStr, len /* not necessarily NUL-terminated */,
94 buf, len,
95 NULL, NULL /* no default char */));
96 }
97 #endif
98
99 return str;
100 }
101
102 // ----------------------------------------------------------------------------
103 // wxBasicString
104 // ----------------------------------------------------------------------------
105
106 wxBasicString::wxBasicString(const wxString& str)
107 {
108 m_bstrBuf = SysAllocString(str.wc_str(*wxConvCurrent));
109 }
110
111 wxBasicString::wxBasicString(const wxBasicString& src)
112 {
113 m_bstrBuf = src.Get();
114 }
115
116 wxBasicString& wxBasicString::operator=(const wxBasicString& src)
117 {
118 SysReAllocString(&m_bstrBuf, src);
119 return *this;
120 }
121
122 wxBasicString::~wxBasicString()
123 {
124 SysFreeString(m_bstrBuf);
125 }
126
127
128 // ----------------------------------------------------------------------------
129 // Convert variants
130 // ----------------------------------------------------------------------------
131
132 #if wxUSE_VARIANT
133
134 namespace
135 {
136
137 // Helper class for creating and filling SAFEARRAY. To use it, call Create()
138 // first, then SetElement() for each element and finally Detach() the SAFEARRAY
139 // from it if you don't want it to be deleted when this class is.
140 class wxSafeArrayHelper
141 {
142 public:
143 wxSafeArrayHelper();
144 ~wxSafeArrayHelper();
145
146 bool Create(VARTYPE vt, long count); // creates and locks the array
147
148 bool SetElement(size_t index, const wxVariant& variant);
149 bool SetElement(size_t index, const wxString& str);
150
151 SAFEARRAY* Detach(); // unlocks the array and gives up its ownership
152
153 private:
154 void Unlock();
155
156 SAFEARRAY* m_array;
157 };
158
159 wxSafeArrayHelper::wxSafeArrayHelper()
160 {
161 m_array = NULL;
162 }
163
164 wxSafeArrayHelper::~wxSafeArrayHelper()
165 {
166 if ( m_array )
167 {
168 Unlock();
169 SafeArrayDestroy(m_array);
170 }
171 }
172
173 bool wxSafeArrayHelper::Create(VARTYPE vt, long count)
174 {
175 SAFEARRAYBOUND saBound;
176
177 saBound.lLbound = 0;
178 saBound.cElements = count;
179 m_array = SafeArrayCreate(vt, 1, &saBound);
180 if ( !m_array )
181 return false;
182 return SUCCEEDED( SafeArrayLock(m_array) );
183 }
184
185 bool wxSafeArrayHelper::SetElement(size_t index, const wxVariant& variant)
186 {
187 VARIANT* data = (VARIANT*)m_array->pvData;
188 return wxConvertVariantToOle(variant, data[index]);
189 }
190
191 bool wxSafeArrayHelper::SetElement(size_t index, const wxString& str)
192 {
193 BSTR bstr = wxConvertStringToOle(str);
194
195 if ( !bstr && !str.empty() )
196 {
197 // BSTR can be NULL for empty strings but if the string was
198 // not empty, it means we failed to allocate memory for it.
199 return false;
200 }
201
202 BSTR* data = (BSTR*)m_array->pvData;
203 data[index] = bstr;
204 return true;
205 }
206
207 SAFEARRAY* wxSafeArrayHelper::Detach()
208 {
209 Unlock();
210 SAFEARRAY* result = m_array;
211 m_array = NULL;
212 return result;
213 }
214
215 void wxSafeArrayHelper::Unlock()
216 {
217 if ( m_array )
218 SafeArrayUnlock(m_array);
219 }
220
221 } // unnamed namespace
222
223
224 WXDLLEXPORT bool wxConvertVariantToOle(const wxVariant& variant, VARIANTARG& oleVariant)
225 {
226 VariantInit(&oleVariant);
227 if (variant.IsNull())
228 {
229 oleVariant.vt = VT_NULL;
230 return true;
231 }
232
233 wxString type(variant.GetType());
234
235
236 if (type == wxT("long"))
237 {
238 oleVariant.vt = VT_I4;
239 oleVariant.lVal = variant.GetLong() ;
240 }
241 // Original VC6 came with SDK too old to contain VARIANT::llVal declaration
242 // and there doesn't seem to be any way to test for it as Microsoft simply
243 // added it to the later version of oaidl.h without changing anything else.
244 // So assume it's not present for VC6, even though it might be if an
245 // updated SDK is used. In this case the user would need to disable this
246 // check himself.
247 #if wxUSE_LONGLONG && !defined(__VISUALC6__)
248 else if (type == wxT("longlong"))
249 {
250 oleVariant.vt = VT_I8;
251 oleVariant.llVal = variant.GetLongLong().GetValue();
252 }
253 #endif
254 else if (type == wxT("char"))
255 {
256 oleVariant.vt=VT_I1; // Signed Char
257 oleVariant.cVal=variant.GetChar();
258 }
259 else if (type == wxT("double"))
260 {
261 oleVariant.vt = VT_R8;
262 oleVariant.dblVal = variant.GetDouble();
263 }
264 else if (type == wxT("bool"))
265 {
266 oleVariant.vt = VT_BOOL;
267 oleVariant.boolVal = variant.GetBool() ? VARIANT_TRUE : VARIANT_FALSE;
268 }
269 else if (type == wxT("string"))
270 {
271 wxString str( variant.GetString() );
272 oleVariant.vt = VT_BSTR;
273 oleVariant.bstrVal = wxConvertStringToOle(str);
274 }
275 #if wxUSE_DATETIME
276 else if (type == wxT("datetime"))
277 {
278 wxDateTime date( variant.GetDateTime() );
279 oleVariant.vt = VT_DATE;
280
281 SYSTEMTIME st;
282 date.GetAsMSWSysTime(&st);
283
284 SystemTimeToVariantTime(&st, &oleVariant.date);
285 }
286 #endif
287 else if (type == wxT("void*"))
288 {
289 oleVariant.vt = VT_DISPATCH;
290 oleVariant.pdispVal = (IDispatch*) variant.GetVoidPtr();
291 }
292 else if (type == wxT("list"))
293 {
294 wxSafeArrayHelper sah;
295
296 if (!sah.Create(VT_VARIANT, variant.GetCount()))
297 return false;
298
299 for (size_t i = 0; i < variant.GetCount(); i++)
300 {
301 if (!sah.SetElement(i, variant[i]))
302 return false;
303 }
304
305 oleVariant.vt = VT_VARIANT | VT_ARRAY;
306 oleVariant.parray = sah.Detach();
307 }
308 else if (type == wxT("arrstring"))
309 {
310 wxArrayString strings(variant.GetArrayString());
311 wxSafeArrayHelper sah;
312
313 if (!sah.Create(VT_BSTR, strings.GetCount()))
314 return false;
315
316 for (size_t i = 0; i < strings.GetCount(); i++)
317 {
318 if (!sah.SetElement(i, strings[i]))
319 return false;
320 }
321
322 oleVariant.vt = VT_BSTR | VT_ARRAY;
323 oleVariant.parray = sah.Detach();
324 }
325 else
326 {
327 oleVariant.vt = VT_NULL;
328 return false;
329 }
330 return true;
331 }
332
333 #ifndef VT_TYPEMASK
334 #define VT_TYPEMASK 0xfff
335 #endif
336
337 WXDLLEXPORT bool
338 wxConvertOleToVariant(const VARIANTARG& oleVariant, wxVariant& variant)
339 {
340 bool ok = true;
341 if ( oleVariant.vt & VT_ARRAY )
342 {
343
344 // Compute the total number of elements in all array dimensions
345 int cElements = 1;
346 for ( int cDims = 0; cDims < oleVariant.parray->cDims; cDims++ )
347 cElements *= oleVariant.parray->rgsabound[cDims].cElements;
348
349 // Get a pointer to the data
350 void* pvdata;
351 HRESULT hr = SafeArrayAccessData(oleVariant.parray, &pvdata);
352 if ( FAILED(hr) )
353 return false;
354
355 switch (oleVariant.vt & VT_TYPEMASK)
356 {
357 case VT_VARIANT:
358 {
359 variant.ClearList();
360 VARIANTARG *variant_data=(VARIANTARG*)pvdata;
361 for ( int i = 0; i < cElements; i++ )
362 {
363 VARIANTARG& oleElement = variant_data[i];
364 wxVariant vElement;
365 if ( !wxConvertOleToVariant(oleElement, vElement) )
366 {
367 ok = false;
368 variant.ClearList();
369 break;
370 }
371
372 variant.Append(vElement);
373 }
374 }
375 break;
376
377 case VT_BSTR:
378 {
379 wxArrayString strings;
380 BSTR *string_val=(BSTR*)pvdata;
381 for ( int i = 0; i < cElements; ++i )
382 {
383 wxString str=wxConvertStringFromOle(*string_val);
384 strings.Add(str);
385 ++string_val;
386 }
387 variant=strings;
388 }
389 break;
390
391 default:
392 wxLogDebug(wxT("unhandled VT_ARRAY type %x in wxConvertOleToVariant"),
393 oleVariant.vt & VT_TYPEMASK);
394 variant = wxVariant();
395 ok = false;
396 break;
397 }
398
399 SafeArrayUnaccessData(oleVariant.parray);
400 }
401 else if ( oleVariant.vt & VT_BYREF )
402 {
403 switch ( oleVariant.vt & VT_TYPEMASK )
404 {
405 case VT_VARIANT:
406 {
407 VARIANTARG& oleReference = *((LPVARIANT)oleVariant.byref);
408 if (!wxConvertOleToVariant(oleReference,variant))
409 return false;
410 break;
411 }
412
413 default:
414 wxLogError(wxT("wxAutomationObject::ConvertOleToVariant: [as yet] unhandled reference %X"),
415 oleVariant.vt);
416 return false;
417 }
418 }
419 else // simply type (not array or reference)
420 {
421 switch ( oleVariant.vt & VT_TYPEMASK )
422 {
423 case VT_BSTR:
424 {
425 wxString str(wxConvertStringFromOle(oleVariant.bstrVal));
426 variant = str;
427 }
428 break;
429
430 case VT_DATE:
431 #if wxUSE_DATETIME
432 {
433 SYSTEMTIME st;
434 VariantTimeToSystemTime(oleVariant.date, &st);
435
436 wxDateTime date;
437 date.SetFromMSWSysTime(st);
438 variant = date;
439 }
440 #endif // wxUSE_DATETIME
441 break;
442
443 // See the comment before the __VISUALC6__ test above.
444 #if wxUSE_LONGLONG && !defined(__VISUALC6__)
445 case VT_I8:
446 variant = wxLongLong(oleVariant.llVal);
447 break;
448 #endif // wxUSE_LONGLONG
449
450 case VT_I4:
451 variant = (long) oleVariant.lVal;
452 break;
453
454 case VT_I2:
455 variant = (long) oleVariant.iVal;
456 break;
457
458 case VT_BOOL:
459 variant = oleVariant.boolVal != 0;
460 break;
461
462 case VT_R4:
463 variant = oleVariant.fltVal;
464 break;
465
466 case VT_R8:
467 variant = oleVariant.dblVal;
468 break;
469
470 case VT_DISPATCH:
471 variant = (void*) oleVariant.pdispVal;
472 break;
473
474 case VT_NULL:
475 variant.MakeNull();
476 break;
477
478 case VT_EMPTY:
479 break; // Ignore Empty Variant, used only during destruction of objects
480
481 default:
482 wxLogError(wxT("wxAutomationObject::ConvertOleToVariant: Unknown variant value type %X -> %X"),
483 oleVariant.vt,oleVariant.vt&VT_TYPEMASK);
484 return false;
485 }
486 }
487
488 return ok;
489 }
490
491 #endif // wxUSE_VARIANT
492
493
494 // ----------------------------------------------------------------------------
495 // Debug support
496 // ----------------------------------------------------------------------------
497
498 #if wxUSE_DATAOBJ
499
500 #if wxDEBUG_LEVEL && (( defined(__VISUALC__) && (__VISUALC__ > 1000) ))
501 static wxString GetIidName(REFIID riid)
502 {
503 // an association between symbolic name and numeric value of an IID
504 struct KNOWN_IID {
505 const IID *pIid;
506 const wxChar *szName;
507 };
508
509 // construct the table containing all known interfaces
510 #define ADD_KNOWN_IID(name) { &IID_I##name, wxT(#name) }
511
512 static const KNOWN_IID aKnownIids[] = {
513 ADD_KNOWN_IID(AdviseSink),
514 ADD_KNOWN_IID(AdviseSink2),
515 ADD_KNOWN_IID(BindCtx),
516 ADD_KNOWN_IID(ClassFactory),
517 #if ( !defined( __VISUALC__) || (__VISUALC__!=1010) )
518 ADD_KNOWN_IID(ContinueCallback),
519 ADD_KNOWN_IID(EnumOleDocumentViews),
520 ADD_KNOWN_IID(OleCommandTarget),
521 ADD_KNOWN_IID(OleDocument),
522 ADD_KNOWN_IID(OleDocumentSite),
523 ADD_KNOWN_IID(OleDocumentView),
524 ADD_KNOWN_IID(Print),
525 #endif
526 ADD_KNOWN_IID(DataAdviseHolder),
527 ADD_KNOWN_IID(DataObject),
528 ADD_KNOWN_IID(Debug),
529 ADD_KNOWN_IID(DebugStream),
530 ADD_KNOWN_IID(DfReserved1),
531 ADD_KNOWN_IID(DfReserved2),
532 ADD_KNOWN_IID(DfReserved3),
533 ADD_KNOWN_IID(Dispatch),
534 ADD_KNOWN_IID(DropSource),
535 ADD_KNOWN_IID(DropTarget),
536 ADD_KNOWN_IID(EnumCallback),
537 ADD_KNOWN_IID(EnumFORMATETC),
538 ADD_KNOWN_IID(EnumGeneric),
539 ADD_KNOWN_IID(EnumHolder),
540 ADD_KNOWN_IID(EnumMoniker),
541 ADD_KNOWN_IID(EnumOLEVERB),
542 ADD_KNOWN_IID(EnumSTATDATA),
543 ADD_KNOWN_IID(EnumSTATSTG),
544 ADD_KNOWN_IID(EnumString),
545 ADD_KNOWN_IID(EnumUnknown),
546 ADD_KNOWN_IID(EnumVARIANT),
547 ADD_KNOWN_IID(ExternalConnection),
548 ADD_KNOWN_IID(InternalMoniker),
549 ADD_KNOWN_IID(LockBytes),
550 ADD_KNOWN_IID(Malloc),
551 ADD_KNOWN_IID(Marshal),
552 ADD_KNOWN_IID(MessageFilter),
553 ADD_KNOWN_IID(Moniker),
554 ADD_KNOWN_IID(OleAdviseHolder),
555 ADD_KNOWN_IID(OleCache),
556 ADD_KNOWN_IID(OleCache2),
557 ADD_KNOWN_IID(OleCacheControl),
558 ADD_KNOWN_IID(OleClientSite),
559 ADD_KNOWN_IID(OleContainer),
560 ADD_KNOWN_IID(OleInPlaceActiveObject),
561 ADD_KNOWN_IID(OleInPlaceFrame),
562 ADD_KNOWN_IID(OleInPlaceObject),
563 ADD_KNOWN_IID(OleInPlaceSite),
564 ADD_KNOWN_IID(OleInPlaceUIWindow),
565 ADD_KNOWN_IID(OleItemContainer),
566 ADD_KNOWN_IID(OleLink),
567 ADD_KNOWN_IID(OleManager),
568 ADD_KNOWN_IID(OleObject),
569 ADD_KNOWN_IID(OlePresObj),
570 ADD_KNOWN_IID(OleWindow),
571 ADD_KNOWN_IID(PSFactory),
572 ADD_KNOWN_IID(ParseDisplayName),
573 ADD_KNOWN_IID(Persist),
574 ADD_KNOWN_IID(PersistFile),
575 ADD_KNOWN_IID(PersistStorage),
576 ADD_KNOWN_IID(PersistStream),
577 ADD_KNOWN_IID(ProxyManager),
578 ADD_KNOWN_IID(RootStorage),
579 ADD_KNOWN_IID(RpcChannel),
580 ADD_KNOWN_IID(RpcProxy),
581 ADD_KNOWN_IID(RpcStub),
582 ADD_KNOWN_IID(RunnableObject),
583 ADD_KNOWN_IID(RunningObjectTable),
584 ADD_KNOWN_IID(StdMarshalInfo),
585 ADD_KNOWN_IID(Storage),
586 ADD_KNOWN_IID(Stream),
587 ADD_KNOWN_IID(StubManager),
588 ADD_KNOWN_IID(Unknown),
589 ADD_KNOWN_IID(ViewObject),
590 ADD_KNOWN_IID(ViewObject2),
591 };
592
593 // don't clobber preprocessor name space
594 #undef ADD_KNOWN_IID
595
596 // try to find the interface in the table
597 for ( size_t ui = 0; ui < WXSIZEOF(aKnownIids); ui++ ) {
598 if ( riid == *aKnownIids[ui].pIid ) {
599 return aKnownIids[ui].szName;
600 }
601 }
602
603 #ifndef __WXWINCE__
604 // unknown IID, just transform to string
605 Uuid uuid(riid);
606 return wxString((const wxChar *)uuid);
607 #else
608 return wxEmptyString;
609 #endif
610 }
611
612 WXDLLEXPORT void wxLogQueryInterface(const wxChar *szInterface, REFIID riid)
613 {
614 wxLogTrace(wxTRACE_OleCalls, wxT("%s::QueryInterface (iid = %s)"),
615 szInterface, GetIidName(riid).c_str());
616 }
617
618 WXDLLEXPORT void wxLogAddRef(const wxChar *szInterface, ULONG cRef)
619 {
620 wxLogTrace(wxTRACE_OleCalls, wxT("After %s::AddRef: m_cRef = %d"), szInterface, cRef + 1);
621 }
622
623 WXDLLEXPORT void wxLogRelease(const wxChar *szInterface, ULONG cRef)
624 {
625 wxLogTrace(wxTRACE_OleCalls, wxT("After %s::Release: m_cRef = %d"), szInterface, cRef - 1);
626 }
627
628 #endif // wxDEBUG_LEVEL
629
630 #endif // wxUSE_DATAOBJ
631
632 #endif // __CYGWIN10__
633
634 #endif // wxUSE_OLE