]> git.saurik.com Git - wxWidgets.git/blob - src/msw/ole/oleutils.cpp
Use (newly) added wxStaticCastVariantData() to fix wxNO_RTTI build.
[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 // ----------------------------------------------------------------------------
225 // wxVariantDataCurrency
226 // ----------------------------------------------------------------------------
227
228
229 #if wxUSE_ANY
230
231 bool wxVariantDataCurrency::GetAsAny(wxAny* any) const
232 {
233 *any = m_value;
234 return true;
235 }
236
237 wxVariantData* wxVariantDataCurrency::VariantDataFactory(const wxAny& any)
238 {
239 return new wxVariantDataCurrency(wxANY_AS(any, CURRENCY));
240 }
241
242 REGISTER_WXANY_CONVERSION(CURRENCY, wxVariantDataCurrency)
243
244 #endif // wxUSE_ANY
245
246 bool wxVariantDataCurrency::Eq(wxVariantData& data) const
247 {
248 wxASSERT_MSG( (data.GetType() == wxS("currency")),
249 "wxVariantDataCurrency::Eq: argument mismatch" );
250
251 wxVariantDataCurrency& otherData = (wxVariantDataCurrency&) data;
252
253 return otherData.m_value.int64 == m_value.int64;
254 }
255
256 #if wxUSE_STD_IOSTREAM
257 bool wxVariantDataCurrency::Write(wxSTD ostream& str) const
258 {
259 wxString s;
260 Write(s);
261 str << s;
262 return true;
263 }
264 #endif
265
266 bool wxVariantDataCurrency::Write(wxString& str) const
267 {
268 BSTR bStr = NULL;
269 if ( SUCCEEDED(VarBstrFromCy(m_value, LOCALE_USER_DEFAULT, 0, &bStr)) )
270 {
271 str = wxConvertStringFromOle(bStr);
272 SysFreeString(bStr);
273 return true;
274 }
275 return false;
276 }
277
278 // ----------------------------------------------------------------------------
279 // wxVariantDataErrorCode
280 // ----------------------------------------------------------------------------
281
282 #if wxUSE_ANY
283
284 bool wxVariantDataErrorCode::GetAsAny(wxAny* any) const
285 {
286 *any = m_value;
287 return true;
288 }
289
290 wxVariantData* wxVariantDataErrorCode::VariantDataFactory(const wxAny& any)
291 {
292 return new wxVariantDataErrorCode(wxANY_AS(any, SCODE));
293 }
294
295 REGISTER_WXANY_CONVERSION(SCODE, wxVariantDataErrorCode)
296
297 #endif // wxUSE_ANY
298
299 bool wxVariantDataErrorCode::Eq(wxVariantData& data) const
300 {
301 wxASSERT_MSG( (data.GetType() == wxS("errorcode")),
302 "wxVariantDataErrorCode::Eq: argument mismatch" );
303
304 wxVariantDataErrorCode& otherData = (wxVariantDataErrorCode&) data;
305
306 return otherData.m_value == m_value;
307 }
308
309 #if wxUSE_STD_IOSTREAM
310 bool wxVariantDataErrorCode::Write(wxSTD ostream& str) const
311 {
312 wxString s;
313 Write(s);
314 str << s;
315 return true;
316 }
317 #endif
318
319 bool wxVariantDataErrorCode::Write(wxString& str) const
320 {
321 str << m_value;
322 return true;
323 }
324
325
326
327 WXDLLEXPORT bool wxConvertVariantToOle(const wxVariant& variant, VARIANTARG& oleVariant)
328 {
329 VariantInit(&oleVariant);
330 if (variant.IsNull())
331 {
332 oleVariant.vt = VT_NULL;
333 return true;
334 }
335
336 wxString type(variant.GetType());
337
338 if (type == wxT("errorcode"))
339 {
340 wxVariantDataErrorCode* const
341 ec = wxStaticCastVariantData(variant.GetData(),
342 wxVariantDataErrorCode);
343 oleVariant.vt = VT_ERROR;
344 oleVariant.scode = ec->GetValue();
345 }
346 else if (type == wxT("currency"))
347 {
348 wxVariantDataCurrency* const
349 c = wxStaticCastVariantData(variant.GetData(),
350 wxVariantDataCurrency);
351 oleVariant.vt = VT_CY;
352 oleVariant.cyVal = c->GetValue();
353 }
354 else if (type == wxT("long"))
355 {
356 oleVariant.vt = VT_I4;
357 oleVariant.lVal = variant.GetLong() ;
358 }
359 // Original VC6 came with SDK too old to contain VARIANT::llVal declaration
360 // and there doesn't seem to be any way to test for it as Microsoft simply
361 // added it to the later version of oaidl.h without changing anything else.
362 // So assume it's not present for VC6, even though it might be if an
363 // updated SDK is used. In this case the user would need to disable this
364 // check himself.
365 #if wxUSE_LONGLONG && !defined(__VISUALC6__)
366 else if (type == wxT("longlong"))
367 {
368 oleVariant.vt = VT_I8;
369 oleVariant.llVal = variant.GetLongLong().GetValue();
370 }
371 #endif
372 else if (type == wxT("char"))
373 {
374 oleVariant.vt=VT_I1; // Signed Char
375 oleVariant.cVal=variant.GetChar();
376 }
377 else if (type == wxT("double"))
378 {
379 oleVariant.vt = VT_R8;
380 oleVariant.dblVal = variant.GetDouble();
381 }
382 else if (type == wxT("bool"))
383 {
384 oleVariant.vt = VT_BOOL;
385 oleVariant.boolVal = variant.GetBool() ? VARIANT_TRUE : VARIANT_FALSE;
386 }
387 else if (type == wxT("string"))
388 {
389 wxString str( variant.GetString() );
390 oleVariant.vt = VT_BSTR;
391 oleVariant.bstrVal = wxConvertStringToOle(str);
392 }
393 #if wxUSE_DATETIME
394 else if (type == wxT("datetime"))
395 {
396 wxDateTime date( variant.GetDateTime() );
397 oleVariant.vt = VT_DATE;
398
399 SYSTEMTIME st;
400 date.GetAsMSWSysTime(&st);
401
402 SystemTimeToVariantTime(&st, &oleVariant.date);
403 }
404 #endif
405 else if (type == wxT("void*"))
406 {
407 oleVariant.vt = VT_DISPATCH;
408 oleVariant.pdispVal = (IDispatch*) variant.GetVoidPtr();
409 }
410 else if (type == wxT("list"))
411 {
412 wxSafeArrayHelper sah;
413
414 if (!sah.Create(VT_VARIANT, variant.GetCount()))
415 return false;
416
417 for (size_t i = 0; i < variant.GetCount(); i++)
418 {
419 if (!sah.SetElement(i, variant[i]))
420 return false;
421 }
422
423 oleVariant.vt = VT_VARIANT | VT_ARRAY;
424 oleVariant.parray = sah.Detach();
425 }
426 else if (type == wxT("arrstring"))
427 {
428 wxArrayString strings(variant.GetArrayString());
429 wxSafeArrayHelper sah;
430
431 if (!sah.Create(VT_BSTR, strings.GetCount()))
432 return false;
433
434 for (size_t i = 0; i < strings.GetCount(); i++)
435 {
436 if (!sah.SetElement(i, strings[i]))
437 return false;
438 }
439
440 oleVariant.vt = VT_BSTR | VT_ARRAY;
441 oleVariant.parray = sah.Detach();
442 }
443 else
444 {
445 oleVariant.vt = VT_NULL;
446 return false;
447 }
448 return true;
449 }
450
451 #ifndef VT_TYPEMASK
452 #define VT_TYPEMASK 0xfff
453 #endif
454
455 WXDLLEXPORT bool
456 wxConvertOleToVariant(const VARIANTARG& oleVariant, wxVariant& variant)
457 {
458 bool ok = true;
459 if ( oleVariant.vt & VT_ARRAY )
460 {
461
462 // Compute the total number of elements in all array dimensions
463 int cElements = 1;
464 for ( int cDims = 0; cDims < oleVariant.parray->cDims; cDims++ )
465 cElements *= oleVariant.parray->rgsabound[cDims].cElements;
466
467 // Get a pointer to the data
468 void* pvdata;
469 HRESULT hr = SafeArrayAccessData(oleVariant.parray, &pvdata);
470 if ( FAILED(hr) )
471 return false;
472
473 switch (oleVariant.vt & VT_TYPEMASK)
474 {
475 case VT_VARIANT:
476 {
477 variant.ClearList();
478 VARIANTARG *variant_data=(VARIANTARG*)pvdata;
479 for ( int i = 0; i < cElements; i++ )
480 {
481 VARIANTARG& oleElement = variant_data[i];
482 wxVariant vElement;
483 if ( !wxConvertOleToVariant(oleElement, vElement) )
484 {
485 ok = false;
486 variant.ClearList();
487 break;
488 }
489
490 variant.Append(vElement);
491 }
492 }
493 break;
494
495 case VT_BSTR:
496 {
497 wxArrayString strings;
498 BSTR *string_val=(BSTR*)pvdata;
499 for ( int i = 0; i < cElements; ++i )
500 {
501 wxString str=wxConvertStringFromOle(*string_val);
502 strings.Add(str);
503 ++string_val;
504 }
505 variant=strings;
506 }
507 break;
508
509 default:
510 wxLogDebug(wxT("unhandled VT_ARRAY type %x in wxConvertOleToVariant"),
511 oleVariant.vt & VT_TYPEMASK);
512 variant = wxVariant();
513 ok = false;
514 break;
515 }
516
517 SafeArrayUnaccessData(oleVariant.parray);
518 }
519 else if ( oleVariant.vt & VT_BYREF )
520 {
521 switch ( oleVariant.vt & VT_TYPEMASK )
522 {
523 case VT_VARIANT:
524 {
525 VARIANTARG& oleReference = *((LPVARIANT)oleVariant.byref);
526 if (!wxConvertOleToVariant(oleReference,variant))
527 return false;
528 break;
529 }
530
531 default:
532 wxLogError(wxT("wxAutomationObject::ConvertOleToVariant: [as yet] unhandled reference %X"),
533 oleVariant.vt);
534 return false;
535 }
536 }
537 else // simply type (not array or reference)
538 {
539 switch ( oleVariant.vt & VT_TYPEMASK )
540 {
541 case VT_ERROR:
542 variant.SetData(new wxVariantDataErrorCode(oleVariant.scode));
543 break;
544
545 case VT_CY:
546 variant.SetData(new wxVariantDataCurrency(oleVariant.cyVal));
547 break;
548
549 case VT_BSTR:
550 {
551 wxString str(wxConvertStringFromOle(oleVariant.bstrVal));
552 variant = str;
553 }
554 break;
555
556 case VT_DATE:
557 #if wxUSE_DATETIME
558 {
559 SYSTEMTIME st;
560 VariantTimeToSystemTime(oleVariant.date, &st);
561
562 wxDateTime date;
563 date.SetFromMSWSysTime(st);
564 variant = date;
565 }
566 #endif // wxUSE_DATETIME
567 break;
568
569 // See the comment before the __VISUALC6__ test above.
570 #if wxUSE_LONGLONG && !defined(__VISUALC6__)
571 case VT_I8:
572 variant = wxLongLong(oleVariant.llVal);
573 break;
574 #endif // wxUSE_LONGLONG
575
576 case VT_I4:
577 variant = (long) oleVariant.lVal;
578 break;
579
580 case VT_I2:
581 variant = (long) oleVariant.iVal;
582 break;
583
584 case VT_BOOL:
585 variant = oleVariant.boolVal != 0;
586 break;
587
588 case VT_R4:
589 variant = oleVariant.fltVal;
590 break;
591
592 case VT_R8:
593 variant = oleVariant.dblVal;
594 break;
595
596 case VT_DISPATCH:
597 variant = (void*) oleVariant.pdispVal;
598 break;
599
600 case VT_NULL:
601 variant.MakeNull();
602 break;
603
604 case VT_EMPTY:
605 break; // Ignore Empty Variant, used only during destruction of objects
606
607 default:
608 wxLogError(wxT("wxAutomationObject::ConvertOleToVariant: Unknown variant value type %X -> %X"),
609 oleVariant.vt,oleVariant.vt&VT_TYPEMASK);
610 return false;
611 }
612 }
613
614 return ok;
615 }
616
617 #endif // wxUSE_VARIANT
618
619
620 // ----------------------------------------------------------------------------
621 // Debug support
622 // ----------------------------------------------------------------------------
623
624 #if wxUSE_DATAOBJ
625
626 #if wxDEBUG_LEVEL && (( defined(__VISUALC__) && (__VISUALC__ > 1000) ))
627 static wxString GetIidName(REFIID riid)
628 {
629 // an association between symbolic name and numeric value of an IID
630 struct KNOWN_IID {
631 const IID *pIid;
632 const wxChar *szName;
633 };
634
635 // construct the table containing all known interfaces
636 #define ADD_KNOWN_IID(name) { &IID_I##name, wxT(#name) }
637
638 static const KNOWN_IID aKnownIids[] = {
639 ADD_KNOWN_IID(AdviseSink),
640 ADD_KNOWN_IID(AdviseSink2),
641 ADD_KNOWN_IID(BindCtx),
642 ADD_KNOWN_IID(ClassFactory),
643 #if ( !defined( __VISUALC__) || (__VISUALC__!=1010) )
644 ADD_KNOWN_IID(ContinueCallback),
645 ADD_KNOWN_IID(EnumOleDocumentViews),
646 ADD_KNOWN_IID(OleCommandTarget),
647 ADD_KNOWN_IID(OleDocument),
648 ADD_KNOWN_IID(OleDocumentSite),
649 ADD_KNOWN_IID(OleDocumentView),
650 ADD_KNOWN_IID(Print),
651 #endif
652 ADD_KNOWN_IID(DataAdviseHolder),
653 ADD_KNOWN_IID(DataObject),
654 ADD_KNOWN_IID(Debug),
655 ADD_KNOWN_IID(DebugStream),
656 ADD_KNOWN_IID(DfReserved1),
657 ADD_KNOWN_IID(DfReserved2),
658 ADD_KNOWN_IID(DfReserved3),
659 ADD_KNOWN_IID(Dispatch),
660 ADD_KNOWN_IID(DropSource),
661 ADD_KNOWN_IID(DropTarget),
662 ADD_KNOWN_IID(EnumCallback),
663 ADD_KNOWN_IID(EnumFORMATETC),
664 ADD_KNOWN_IID(EnumGeneric),
665 ADD_KNOWN_IID(EnumHolder),
666 ADD_KNOWN_IID(EnumMoniker),
667 ADD_KNOWN_IID(EnumOLEVERB),
668 ADD_KNOWN_IID(EnumSTATDATA),
669 ADD_KNOWN_IID(EnumSTATSTG),
670 ADD_KNOWN_IID(EnumString),
671 ADD_KNOWN_IID(EnumUnknown),
672 ADD_KNOWN_IID(EnumVARIANT),
673 ADD_KNOWN_IID(ExternalConnection),
674 ADD_KNOWN_IID(InternalMoniker),
675 ADD_KNOWN_IID(LockBytes),
676 ADD_KNOWN_IID(Malloc),
677 ADD_KNOWN_IID(Marshal),
678 ADD_KNOWN_IID(MessageFilter),
679 ADD_KNOWN_IID(Moniker),
680 ADD_KNOWN_IID(OleAdviseHolder),
681 ADD_KNOWN_IID(OleCache),
682 ADD_KNOWN_IID(OleCache2),
683 ADD_KNOWN_IID(OleCacheControl),
684 ADD_KNOWN_IID(OleClientSite),
685 ADD_KNOWN_IID(OleContainer),
686 ADD_KNOWN_IID(OleInPlaceActiveObject),
687 ADD_KNOWN_IID(OleInPlaceFrame),
688 ADD_KNOWN_IID(OleInPlaceObject),
689 ADD_KNOWN_IID(OleInPlaceSite),
690 ADD_KNOWN_IID(OleInPlaceUIWindow),
691 ADD_KNOWN_IID(OleItemContainer),
692 ADD_KNOWN_IID(OleLink),
693 ADD_KNOWN_IID(OleManager),
694 ADD_KNOWN_IID(OleObject),
695 ADD_KNOWN_IID(OlePresObj),
696 ADD_KNOWN_IID(OleWindow),
697 ADD_KNOWN_IID(PSFactory),
698 ADD_KNOWN_IID(ParseDisplayName),
699 ADD_KNOWN_IID(Persist),
700 ADD_KNOWN_IID(PersistFile),
701 ADD_KNOWN_IID(PersistStorage),
702 ADD_KNOWN_IID(PersistStream),
703 ADD_KNOWN_IID(ProxyManager),
704 ADD_KNOWN_IID(RootStorage),
705 ADD_KNOWN_IID(RpcChannel),
706 ADD_KNOWN_IID(RpcProxy),
707 ADD_KNOWN_IID(RpcStub),
708 ADD_KNOWN_IID(RunnableObject),
709 ADD_KNOWN_IID(RunningObjectTable),
710 ADD_KNOWN_IID(StdMarshalInfo),
711 ADD_KNOWN_IID(Storage),
712 ADD_KNOWN_IID(Stream),
713 ADD_KNOWN_IID(StubManager),
714 ADD_KNOWN_IID(Unknown),
715 ADD_KNOWN_IID(ViewObject),
716 ADD_KNOWN_IID(ViewObject2),
717 };
718
719 // don't clobber preprocessor name space
720 #undef ADD_KNOWN_IID
721
722 // try to find the interface in the table
723 for ( size_t ui = 0; ui < WXSIZEOF(aKnownIids); ui++ ) {
724 if ( riid == *aKnownIids[ui].pIid ) {
725 return aKnownIids[ui].szName;
726 }
727 }
728
729 #ifndef __WXWINCE__
730 // unknown IID, just transform to string
731 Uuid uuid(riid);
732 return wxString((const wxChar *)uuid);
733 #else
734 return wxEmptyString;
735 #endif
736 }
737
738 WXDLLEXPORT void wxLogQueryInterface(const wxChar *szInterface, REFIID riid)
739 {
740 wxLogTrace(wxTRACE_OleCalls, wxT("%s::QueryInterface (iid = %s)"),
741 szInterface, GetIidName(riid).c_str());
742 }
743
744 WXDLLEXPORT void wxLogAddRef(const wxChar *szInterface, ULONG cRef)
745 {
746 wxLogTrace(wxTRACE_OleCalls, wxT("After %s::AddRef: m_cRef = %d"), szInterface, cRef + 1);
747 }
748
749 WXDLLEXPORT void wxLogRelease(const wxChar *szInterface, ULONG cRef)
750 {
751 wxLogTrace(wxTRACE_OleCalls, wxT("After %s::Release: m_cRef = %d"), szInterface, cRef - 1);
752 }
753
754 #endif // wxDEBUG_LEVEL
755
756 #endif // wxUSE_DATAOBJ
757
758 #endif // __CYGWIN10__
759
760 #endif // wxUSE_OLE