/////////////////////////////////////////////////////////////////////////////// // Name: src/msw/ole/oleutils.cpp // Purpose: implementation of OLE helper functions // Author: Vadim Zeitlin // Modified by: // Created: 19.02.98 // Copyright: (c) 1998 Vadim Zeitlin // Licence: wxWindows licence /////////////////////////////////////////////////////////////////////////////// // ============================================================================ // Declarations // ============================================================================ // ---------------------------------------------------------------------------- // headers // ---------------------------------------------------------------------------- // For compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" #if defined(__BORLANDC__) #pragma hdrstop #endif #if wxUSE_OLE #ifndef WX_PRECOMP #include "wx/log.h" #endif #ifndef __CYGWIN10__ #include "wx/msw/private.h" // OLE #include "wx/msw/ole/uuid.h" #include "wx/msw/ole/oleutils.h" #include "wx/msw/ole/safearray.h" #if defined(__VISUALC__) #include #endif // ============================================================================ // Implementation // ============================================================================ // return true if the iid is in the array WXDLLEXPORT bool IsIidFromList(REFIID riid, const IID *aIids[], size_t nCount) { for ( size_t i = 0; i < nCount; i++ ) { if ( riid == *aIids[i] ) return true; } return false; } WXDLLEXPORT BSTR wxConvertStringToOle(const wxString& str) { return wxBasicString(str).Get(); } WXDLLEXPORT wxString wxConvertStringFromOle(BSTR bStr) { // NULL BSTR is equivalent to an empty string (this is the convention used // by VB and hence we must follow it) if ( !bStr ) return wxString(); const int len = SysStringLen(bStr); #if wxUSE_UNICODE wxString str(bStr, len); #else wxString str; if (len) { wxStringBufferLength buf(str, len); // asserts if len == 0 buf.SetLength(WideCharToMultiByte(CP_ACP, 0 /* no flags */, bStr, len /* not necessarily NUL-terminated */, buf, len, NULL, NULL /* no default char */)); } #endif return str; } // ---------------------------------------------------------------------------- // wxBasicString // ---------------------------------------------------------------------------- wxBasicString::wxBasicString(const wxString& str) { m_bstrBuf = SysAllocString(str.wc_str(*wxConvCurrent)); } wxBasicString::wxBasicString(const wxBasicString& src) { m_bstrBuf = src.Get(); } wxBasicString& wxBasicString::operator=(const wxBasicString& src) { SysReAllocString(&m_bstrBuf, src); return *this; } wxBasicString::~wxBasicString() { SysFreeString(m_bstrBuf); } // ---------------------------------------------------------------------------- // Convert variants // ---------------------------------------------------------------------------- #if wxUSE_VARIANT // ---------------------------------------------------------------------------- // wxVariantDataCurrency // ---------------------------------------------------------------------------- #if wxUSE_ANY bool wxVariantDataCurrency::GetAsAny(wxAny* any) const { *any = m_value; return true; } wxVariantData* wxVariantDataCurrency::VariantDataFactory(const wxAny& any) { return new wxVariantDataCurrency(any.As()); } REGISTER_WXANY_CONVERSION(CURRENCY, wxVariantDataCurrency) #endif // wxUSE_ANY bool wxVariantDataCurrency::Eq(wxVariantData& data) const { wxASSERT_MSG( (data.GetType() == wxS("currency")), "wxVariantDataCurrency::Eq: argument mismatch" ); wxVariantDataCurrency& otherData = (wxVariantDataCurrency&) data; return otherData.m_value.int64 == m_value.int64; } #if wxUSE_STD_IOSTREAM bool wxVariantDataCurrency::Write(wxSTD ostream& str) const { wxString s; Write(s); str << s; return true; } #endif bool wxVariantDataCurrency::Write(wxString& str) const { BSTR bStr = NULL; if ( SUCCEEDED(VarBstrFromCy(m_value, LOCALE_USER_DEFAULT, 0, &bStr)) ) { str = wxConvertStringFromOle(bStr); SysFreeString(bStr); return true; } return false; } // ---------------------------------------------------------------------------- // wxVariantDataErrorCode // ---------------------------------------------------------------------------- #if wxUSE_ANY bool wxVariantDataErrorCode::GetAsAny(wxAny* any) const { *any = m_value; return true; } wxVariantData* wxVariantDataErrorCode::VariantDataFactory(const wxAny& any) { return new wxVariantDataErrorCode(any.As()); } REGISTER_WXANY_CONVERSION(SCODE, wxVariantDataErrorCode) #endif // wxUSE_ANY bool wxVariantDataErrorCode::Eq(wxVariantData& data) const { wxASSERT_MSG( (data.GetType() == wxS("errorcode")), "wxVariantDataErrorCode::Eq: argument mismatch" ); wxVariantDataErrorCode& otherData = (wxVariantDataErrorCode&) data; return otherData.m_value == m_value; } #if wxUSE_STD_IOSTREAM bool wxVariantDataErrorCode::Write(wxSTD ostream& str) const { wxString s; Write(s); str << s; return true; } #endif bool wxVariantDataErrorCode::Write(wxString& str) const { str << m_value; return true; } // ---------------------------------------------------------------------------- // wxVariantDataSafeArray // ---------------------------------------------------------------------------- #if wxUSE_ANY bool wxVariantDataSafeArray::GetAsAny(wxAny* any) const { *any = m_value; return true; } wxVariantData* wxVariantDataSafeArray::VariantDataFactory(const wxAny& any) { return new wxVariantDataSafeArray(any.As()); } REGISTER_WXANY_CONVERSION(SAFEARRAY*, wxVariantDataSafeArray) #endif // wxUSE_ANY bool wxVariantDataSafeArray::Eq(wxVariantData& data) const { wxASSERT_MSG( (data.GetType() == wxS("safearray")), "wxVariantDataSafeArray::Eq: argument mismatch" ); wxVariantDataSafeArray& otherData = (wxVariantDataSafeArray&) data; return otherData.m_value == m_value; } #if wxUSE_STD_IOSTREAM bool wxVariantDataSafeArray::Write(wxSTD ostream& str) const { wxString s; Write(s); str << s; return true; } #endif bool wxVariantDataSafeArray::Write(wxString& str) const { str.Printf(wxS("SAFEARRAY: %p"), (void*)m_value); return true; } WXDLLEXPORT bool wxConvertVariantToOle(const wxVariant& variant, VARIANTARG& oleVariant) { VariantInit(&oleVariant); if (variant.IsNull()) { oleVariant.vt = VT_NULL; return true; } wxString type(variant.GetType()); if (type == wxT("errorcode")) { wxVariantDataErrorCode* const ec = wxStaticCastVariantData(variant.GetData(), wxVariantDataErrorCode); oleVariant.vt = VT_ERROR; oleVariant.scode = ec->GetValue(); } else if (type == wxT("currency")) { wxVariantDataCurrency* const c = wxStaticCastVariantData(variant.GetData(), wxVariantDataCurrency); oleVariant.vt = VT_CY; oleVariant.cyVal = c->GetValue(); } else if (type == wxT("safearray")) { wxVariantDataSafeArray* const vsa = wxStaticCastVariantData(variant.GetData(), wxVariantDataSafeArray); SAFEARRAY* psa = vsa->GetValue(); VARTYPE vt; wxCHECK(psa, false); HRESULT hr = SafeArrayGetVartype(psa, &vt); if ( FAILED(hr) ) { wxLogApiError(wxS("SafeArrayGetVartype()"), hr); SafeArrayDestroy(psa); return false; } oleVariant.vt = vt | VT_ARRAY; oleVariant.parray = psa; } else if (type == wxT("long")) { oleVariant.vt = VT_I4; oleVariant.lVal = variant.GetLong() ; } #if wxUSE_LONGLONG else if (type == wxT("longlong")) { oleVariant.vt = VT_I8; oleVariant.llVal = variant.GetLongLong().GetValue(); } #endif else if (type == wxT("char")) { oleVariant.vt=VT_I1; // Signed Char oleVariant.cVal=variant.GetChar(); } else if (type == wxT("double")) { oleVariant.vt = VT_R8; oleVariant.dblVal = variant.GetDouble(); } else if (type == wxT("bool")) { oleVariant.vt = VT_BOOL; oleVariant.boolVal = variant.GetBool() ? VARIANT_TRUE : VARIANT_FALSE; } else if (type == wxT("string")) { wxString str( variant.GetString() ); oleVariant.vt = VT_BSTR; oleVariant.bstrVal = wxConvertStringToOle(str); } #if wxUSE_DATETIME else if (type == wxT("datetime")) { wxDateTime date( variant.GetDateTime() ); oleVariant.vt = VT_DATE; SYSTEMTIME st; date.GetAsMSWSysTime(&st); SystemTimeToVariantTime(&st, &oleVariant.date); } #endif else if (type == wxT("void*")) { oleVariant.vt = VT_DISPATCH; oleVariant.pdispVal = (IDispatch*) variant.GetVoidPtr(); } else if (type == wxT("list")) { wxSafeArray safeArray; if (!safeArray.CreateFromListVariant(variant)) return false; oleVariant.vt = VT_VARIANT | VT_ARRAY; oleVariant.parray = safeArray.Detach(); } else if (type == wxT("arrstring")) { wxSafeArray safeArray; if (!safeArray.CreateFromArrayString(variant.GetArrayString())) return false; oleVariant.vt = VT_BSTR | VT_ARRAY; oleVariant.parray = safeArray.Detach(); } else { oleVariant.vt = VT_NULL; return false; } return true; } WXDLLEXPORT bool wxConvertOleToVariant(const VARIANTARG& oleVariant, wxVariant& variant, long flags) { bool ok = true; if ( oleVariant.vt & VT_ARRAY ) { if ( flags & wxOleConvertVariant_ReturnSafeArrays ) { variant.SetData(new wxVariantDataSafeArray(oleVariant.parray)); } else { switch (oleVariant.vt & VT_TYPEMASK) { case VT_I2: ok = wxSafeArray::ConvertToVariant(oleVariant.parray, variant); break; case VT_I4: ok = wxSafeArray::ConvertToVariant(oleVariant.parray, variant); break; case VT_R4: ok = wxSafeArray::ConvertToVariant(oleVariant.parray, variant); break; case VT_R8: ok = wxSafeArray::ConvertToVariant(oleVariant.parray, variant); break; case VT_VARIANT: ok = wxSafeArray::ConvertToVariant(oleVariant.parray, variant); break; case VT_BSTR: { wxArrayString strings; if ( wxSafeArray::ConvertToArrayString(oleVariant.parray, strings) ) variant = strings; else ok = false; } break; default: ok = false; break; } if ( !ok ) { wxLogDebug(wxT("unhandled VT_ARRAY type %x in wxConvertOleToVariant"), oleVariant.vt & VT_TYPEMASK); variant = wxVariant(); } } } else if ( oleVariant.vt & VT_BYREF ) { switch ( oleVariant.vt & VT_TYPEMASK ) { case VT_VARIANT: { VARIANTARG& oleReference = *((LPVARIANT)oleVariant.byref); if (!wxConvertOleToVariant(oleReference,variant)) return false; break; } default: wxLogError(wxT("wxAutomationObject::ConvertOleToVariant: [as yet] unhandled reference %X"), oleVariant.vt); return false; } } else // simply type (not array or reference) { switch ( oleVariant.vt & VT_TYPEMASK ) { case VT_ERROR: variant.SetData(new wxVariantDataErrorCode(oleVariant.scode)); break; case VT_CY: variant.SetData(new wxVariantDataCurrency(oleVariant.cyVal)); break; case VT_BSTR: { wxString str(wxConvertStringFromOle(oleVariant.bstrVal)); variant = str; } break; case VT_DATE: #if wxUSE_DATETIME { SYSTEMTIME st; VariantTimeToSystemTime(oleVariant.date, &st); wxDateTime date; date.SetFromMSWSysTime(st); variant = date; } #endif // wxUSE_DATETIME break; #if wxUSE_LONGLONG case VT_I8: variant = wxLongLong(oleVariant.llVal); break; #endif // wxUSE_LONGLONG case VT_I4: variant = (long) oleVariant.lVal; break; case VT_I2: variant = (long) oleVariant.iVal; break; case VT_BOOL: variant = oleVariant.boolVal != 0; break; case VT_R4: variant = oleVariant.fltVal; break; case VT_R8: variant = oleVariant.dblVal; break; case VT_DISPATCH: variant = (void*) oleVariant.pdispVal; break; case VT_NULL: case VT_EMPTY: variant.MakeNull(); break; default: wxLogError(wxT("wxAutomationObject::ConvertOleToVariant: Unknown variant value type %X -> %X"), oleVariant.vt,oleVariant.vt&VT_TYPEMASK); return false; } } return ok; } #endif // wxUSE_VARIANT // ---------------------------------------------------------------------------- // Debug support // ---------------------------------------------------------------------------- #if wxUSE_DATAOBJ #if wxDEBUG_LEVEL && defined(__VISUALC__) static wxString GetIidName(REFIID riid) { // an association between symbolic name and numeric value of an IID struct KNOWN_IID { const IID *pIid; const wxChar *szName; }; // construct the table containing all known interfaces #define ADD_KNOWN_IID(name) { &IID_I##name, wxT(#name) } static const KNOWN_IID aKnownIids[] = { ADD_KNOWN_IID(AdviseSink), ADD_KNOWN_IID(AdviseSink2), ADD_KNOWN_IID(BindCtx), ADD_KNOWN_IID(ClassFactory), #if ( !defined( __VISUALC__) || (__VISUALC__!=1010) ) ADD_KNOWN_IID(ContinueCallback), ADD_KNOWN_IID(EnumOleDocumentViews), ADD_KNOWN_IID(OleCommandTarget), ADD_KNOWN_IID(OleDocument), ADD_KNOWN_IID(OleDocumentSite), ADD_KNOWN_IID(OleDocumentView), ADD_KNOWN_IID(Print), #endif ADD_KNOWN_IID(DataAdviseHolder), ADD_KNOWN_IID(DataObject), ADD_KNOWN_IID(Debug), ADD_KNOWN_IID(DebugStream), ADD_KNOWN_IID(DfReserved1), ADD_KNOWN_IID(DfReserved2), ADD_KNOWN_IID(DfReserved3), ADD_KNOWN_IID(Dispatch), ADD_KNOWN_IID(DropSource), ADD_KNOWN_IID(DropTarget), ADD_KNOWN_IID(EnumCallback), ADD_KNOWN_IID(EnumFORMATETC), ADD_KNOWN_IID(EnumGeneric), ADD_KNOWN_IID(EnumHolder), ADD_KNOWN_IID(EnumMoniker), ADD_KNOWN_IID(EnumOLEVERB), ADD_KNOWN_IID(EnumSTATDATA), ADD_KNOWN_IID(EnumSTATSTG), ADD_KNOWN_IID(EnumString), ADD_KNOWN_IID(EnumUnknown), ADD_KNOWN_IID(EnumVARIANT), ADD_KNOWN_IID(ExternalConnection), ADD_KNOWN_IID(InternalMoniker), ADD_KNOWN_IID(LockBytes), ADD_KNOWN_IID(Malloc), ADD_KNOWN_IID(Marshal), ADD_KNOWN_IID(MessageFilter), ADD_KNOWN_IID(Moniker), ADD_KNOWN_IID(OleAdviseHolder), ADD_KNOWN_IID(OleCache), ADD_KNOWN_IID(OleCache2), ADD_KNOWN_IID(OleCacheControl), ADD_KNOWN_IID(OleClientSite), ADD_KNOWN_IID(OleContainer), ADD_KNOWN_IID(OleInPlaceActiveObject), ADD_KNOWN_IID(OleInPlaceFrame), ADD_KNOWN_IID(OleInPlaceObject), ADD_KNOWN_IID(OleInPlaceSite), ADD_KNOWN_IID(OleInPlaceUIWindow), ADD_KNOWN_IID(OleItemContainer), ADD_KNOWN_IID(OleLink), ADD_KNOWN_IID(OleManager), ADD_KNOWN_IID(OleObject), ADD_KNOWN_IID(OlePresObj), ADD_KNOWN_IID(OleWindow), ADD_KNOWN_IID(PSFactory), ADD_KNOWN_IID(ParseDisplayName), ADD_KNOWN_IID(Persist), ADD_KNOWN_IID(PersistFile), ADD_KNOWN_IID(PersistStorage), ADD_KNOWN_IID(PersistStream), ADD_KNOWN_IID(ProxyManager), ADD_KNOWN_IID(RootStorage), ADD_KNOWN_IID(RpcChannel), ADD_KNOWN_IID(RpcProxy), ADD_KNOWN_IID(RpcStub), ADD_KNOWN_IID(RunnableObject), ADD_KNOWN_IID(RunningObjectTable), ADD_KNOWN_IID(StdMarshalInfo), ADD_KNOWN_IID(Storage), ADD_KNOWN_IID(Stream), ADD_KNOWN_IID(StubManager), ADD_KNOWN_IID(Unknown), ADD_KNOWN_IID(ViewObject), ADD_KNOWN_IID(ViewObject2), }; // don't clobber preprocessor name space #undef ADD_KNOWN_IID // try to find the interface in the table for ( size_t ui = 0; ui < WXSIZEOF(aKnownIids); ui++ ) { if ( riid == *aKnownIids[ui].pIid ) { return aKnownIids[ui].szName; } } // unknown IID, just transform to string Uuid uuid(riid); return wxString((const wxChar *)uuid); } WXDLLEXPORT void wxLogQueryInterface(const wxChar *szInterface, REFIID riid) { wxLogTrace(wxTRACE_OleCalls, wxT("%s::QueryInterface (iid = %s)"), szInterface, GetIidName(riid).c_str()); } WXDLLEXPORT void wxLogAddRef(const wxChar *szInterface, ULONG cRef) { wxLogTrace(wxTRACE_OleCalls, wxT("After %s::AddRef: m_cRef = %d"), szInterface, cRef + 1); } WXDLLEXPORT void wxLogRelease(const wxChar *szInterface, ULONG cRef) { wxLogTrace(wxTRACE_OleCalls, wxT("After %s::Release: m_cRef = %d"), szInterface, cRef - 1); } #endif // wxDEBUG_LEVEL #endif // wxUSE_DATAOBJ #endif // __CYGWIN10__ #endif // wxUSE_OLE