X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/e4db172a3b318df9aff178eb6c5da149d56e0859..43f4e852a1b2ac37c3db6a2b87315192ac549191:/src/msw/ole/oleutils.cpp diff --git a/src/msw/ole/oleutils.cpp b/src/msw/ole/oleutils.cpp index 058f4afd87..293b4e68ba 100644 --- a/src/msw/ole/oleutils.cpp +++ b/src/msw/ole/oleutils.cpp @@ -48,6 +48,7 @@ #endif #include "wx/msw/ole/oleutils.h" +#include "wx/msw/ole/safearray.h" #if defined(__VISUALC__) && (__VISUALC__ > 1000) #include @@ -58,7 +59,7 @@ // ============================================================================ // return true if the iid is in the array -bool IsIidFromList(REFIID riid, const IID *aIids[], size_t nCount) +WXDLLEXPORT bool IsIidFromList(REFIID riid, const IID *aIids[], size_t nCount) { for ( size_t i = 0; i < nCount; i++ ) { if ( riid == *aIids[i] ) @@ -70,29 +71,32 @@ bool IsIidFromList(REFIID riid, const IID *aIids[], size_t nCount) WXDLLEXPORT BSTR wxConvertStringToOle(const wxString& str) { -/* - unsigned int len = strlen((const char*) str); - unsigned short* s = new unsigned short[len*2+2]; - unsigned int i; - memset(s, 0, len*2+2); - for (i=0; i < len; i++) - s[i*2] = str[i]; -*/ - wxBasicString bstr(str.mb_str()); - return bstr.Get(); + 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); + wxString str(bStr, len); #else - int len = SysStringLen(bStr) + 1; - char *buf = new char[len]; - (void)wcstombs( buf, bStr, len); - wxString str(buf); - delete[] buf; + 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; } @@ -100,58 +104,478 @@ WXDLLEXPORT wxString wxConvertStringFromOle(BSTR bStr) // wxBasicString // ---------------------------------------------------------------------------- -// ctor takes an ANSI string and transforms it to Unicode -wxBasicString::wxBasicString(const char *sz) +wxBasicString::wxBasicString(const wxString& str) { - Init(sz); + m_bstrBuf = SysAllocString(str.wc_str(*wxConvCurrent)); } -// ctor takes an ANSI or Unicode string and transforms it to Unicode -wxBasicString::wxBasicString(const wxString& str) +wxBasicString::wxBasicString(const wxBasicString& src) { -#if wxUSE_UNICODE - m_wzBuf = new OLECHAR[str.length() + 1]; - memcpy(m_wzBuf, str.c_str(), str.length()*2); - m_wzBuf[str.length()] = L'\0'; -#else - Init(str.c_str()); + 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(wxANY_AS(any, CURRENCY)); +} + +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; } -// Takes an ANSI string and transforms it to Unicode -void wxBasicString::Init(const char *sz) +// ---------------------------------------------------------------------------- +// wxVariantDataErrorCode +// ---------------------------------------------------------------------------- + +#if wxUSE_ANY + +bool wxVariantDataErrorCode::GetAsAny(wxAny* any) const { - // get the size of required buffer - UINT lenAnsi = strlen(sz); -#ifdef __MWERKS__ - UINT lenWide = lenAnsi * 2 ; -#else - UINT lenWide = mbstowcs(NULL, sz, lenAnsi); + *any = m_value; + return true; +} + +wxVariantData* wxVariantDataErrorCode::VariantDataFactory(const wxAny& any) +{ + return new wxVariantDataErrorCode(wxANY_AS(any, SCODE)); +} + +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(wxANY_AS(any, SAFEARRAY*)); +} + +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 - if ( lenWide > 0 ) { - m_wzBuf = new OLECHAR[lenWide + 1]; - mbstowcs(m_wzBuf, sz, lenAnsi); - m_wzBuf[lenWide] = L'\0'; +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() ; + } + // Original VC6 came with SDK too old to contain VARIANT::llVal declaration + // and there doesn't seem to be any way to test for it as Microsoft simply + // added it to the later version of oaidl.h without changing anything else. + // So assume it's not present for VC6, even though it might be if an + // updated SDK is used. In this case the user would need to disable this + // check himself. +#if wxUSE_LONGLONG && !defined(__VISUALC6__) + 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 { - m_wzBuf = NULL; + 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; } -// dtor frees memory -wxBasicString::~wxBasicString() +#ifndef VT_TYPEMASK +#define VT_TYPEMASK 0xfff +#endif + +WXDLLEXPORT bool +wxConvertOleToVariant(const VARIANTARG& oleVariant, wxVariant& variant) { - delete [] m_wzBuf; + bool ok = true; + if ( oleVariant.vt & VT_ARRAY ) + { + // TODO: We currently return arrays as wxVariant of the list type + // containing the flattened form of array but we should allow + // getting it as wxVariantDataSafeArray instead. Doing this is + // simple, we'd just need to do something like this: + // + // if ( oleVariant.parray && SafeArrayGetDim(oleVariant.parray) > 1 ) + // { + // variant.SetData(new wxVariantDataSafeArray(oleVariant.parray)); + // } + // + // but currently we don't do it for compatibility reasons. + 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; + + // See the comment before the __VISUALC6__ test above. +#if wxUSE_LONGLONG && !defined(__VISUALC6__) + 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: + variant.MakeNull(); + break; + + case VT_EMPTY: + break; // Ignore Empty Variant, used only during destruction of objects + + default: + wxLogError(wxT("wxAutomationObject::ConvertOleToVariant: Unknown variant value type %X -> %X"), + oleVariant.vt,oleVariant.vt&VT_TYPEMASK); + return false; + } + } + + return ok; } -#if wxUSE_DATAOBJ +#endif // wxUSE_VARIANT + // ---------------------------------------------------------------------------- // Debug support // ---------------------------------------------------------------------------- -#if defined(__WXDEBUG__) && ( ( defined(__VISUALC__) && (__VISUALC__ > 1000) ) || defined(__MWERKS__) ) +#if wxUSE_DATAOBJ + +#if wxDEBUG_LEVEL && (( defined(__VISUALC__) && (__VISUALC__ > 1000) )) static wxString GetIidName(REFIID riid) { // an association between symbolic name and numeric value of an IID @@ -161,14 +585,14 @@ static wxString GetIidName(REFIID riid) }; // construct the table containing all known interfaces - #define ADD_KNOWN_IID(name) { &IID_I##name, _T(#name) } + #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) ) && !defined(__MWERKS__) +#if ( !defined( __VISUALC__) || (__VISUALC__!=1010) ) ADD_KNOWN_IID(ContinueCallback), ADD_KNOWN_IID(EnumOleDocumentViews), ADD_KNOWN_IID(OleCommandTarget), @@ -263,47 +687,26 @@ static wxString GetIidName(REFIID riid) #endif } -void wxLogQueryInterface(const wxChar *szInterface, REFIID riid) +WXDLLEXPORT void wxLogQueryInterface(const wxChar *szInterface, REFIID riid) { wxLogTrace(wxTRACE_OleCalls, wxT("%s::QueryInterface (iid = %s)"), szInterface, GetIidName(riid).c_str()); } -void wxLogAddRef(const wxChar *szInterface, ULONG cRef) +WXDLLEXPORT void wxLogAddRef(const wxChar *szInterface, ULONG cRef) { wxLogTrace(wxTRACE_OleCalls, wxT("After %s::AddRef: m_cRef = %d"), szInterface, cRef + 1); } -void wxLogRelease(const wxChar *szInterface, ULONG cRef) +WXDLLEXPORT void wxLogRelease(const wxChar *szInterface, ULONG cRef) { wxLogTrace(wxTRACE_OleCalls, wxT("After %s::Release: m_cRef = %d"), szInterface, cRef - 1); } -#elif defined(__WXDEBUG__) && defined(__VISUALC__) && (__VISUALC__ <= 1000) +#endif // wxDEBUG_LEVEL -// For VC++ 4 -void wxLogQueryInterface(const char *szInterface, REFIID riid) -{ - wxLogTrace("%s::QueryInterface", szInterface); -} +#endif // wxUSE_DATAOBJ -void wxLogAddRef(const char *szInterface, ULONG cRef) -{ - wxLogTrace("After %s::AddRef: m_cRef = %d", szInterface, cRef + 1); -} +#endif // __CYGWIN10__ -void wxLogRelease(const char *szInterface, ULONG cRef) -{ - wxLogTrace("After %s::Release: m_cRef = %d", szInterface, cRef - 1); -} - -#endif // __WXDEBUG__ - -#endif - // wxUSE_DRAG_AND_DROP - -#endif - // __CYGWIN10__ - -#endif - // wxUSE_OLE +#endif // wxUSE_OLE