X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/b2aef89b7a675805b601e757492c982031f38d21..7c70331e28be93b833dfa4f2594a25841fcb6e20:/src/msw/ole/oleutils.cpp diff --git a/src/msw/ole/oleutils.cpp b/src/msw/ole/oleutils.cpp index 2de92ce709..f6ec69f5f6 100644 --- a/src/msw/ole/oleutils.cpp +++ b/src/msw/ole/oleutils.cpp @@ -1,12 +1,12 @@ /////////////////////////////////////////////////////////////////////////////// -// Name: ole/oleutils.cpp +// Name: src/msw/ole/oleutils.cpp // Purpose: implementation of OLE helper functions // Author: Vadim Zeitlin -// Modified by: +// Modified by: // Created: 19.02.98 // RCS-ID: $Id$ // Copyright: (c) 1998 Vadim Zeitlin -// Licence: wxWindows license +// Licence: wxWindows licence /////////////////////////////////////////////////////////////////////////////// // ============================================================================ @@ -17,70 +17,630 @@ // headers // ---------------------------------------------------------------------------- -#ifdef __GNUG__ -#pragma implementation "oleutils.h" -#endif - // For compilers that support precompilation, includes "wx.h". -#define IN_WX_MAIN_CPP #include "wx/wxprec.h" #if defined(__BORLANDC__) -#pragma hdrstop + #pragma hdrstop #endif -#include +#if wxUSE_OLE + +#ifndef WX_PRECOMP + #include "wx/log.h" +#endif -#if USE_DRAG_AND_DROP +#ifndef __CYGWIN10__ -#include +#include "wx/msw/private.h" -#include +#ifdef __WXWINCE__ + #include + #include + + #define GUID_DEFINED + #define UUID_DEFINED +#endif // OLE -#include -#include +#ifndef __WXWINCE__ +#include "wx/msw/ole/uuid.h" +#endif -#if defined(_MSC_VER) && (_MSC_VER > 1000) -#include +#include "wx/msw/ole/oleutils.h" + +#if defined(__VISUALC__) && (__VISUALC__ > 1000) + #include #endif // ============================================================================ // Implementation // ============================================================================ -// return TRUE if the iid is in the array -bool IsIidFromList(REFIID riid, const IID *aIids[], size_t nCount) +// 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 true; } - return FALSE; + 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 + +namespace +{ + +// Helper class for creating and filling SAFEARRAY. To use it, call Create() +// first, then SetElement() for each element and finally Detach() the SAFEARRAY +// from it if you don't want it to be deleted when this class is. +class wxSafeArrayHelper +{ +public: + wxSafeArrayHelper(); + ~wxSafeArrayHelper(); + + bool Create(VARTYPE vt, long count); // creates and locks the array + + bool SetElement(size_t index, const wxVariant& variant); + bool SetElement(size_t index, const wxString& str); + + SAFEARRAY* Detach(); // unlocks the array and gives up its ownership + +private: + void Unlock(); + + SAFEARRAY* m_array; +}; + +wxSafeArrayHelper::wxSafeArrayHelper() +{ + m_array = NULL; +} + +wxSafeArrayHelper::~wxSafeArrayHelper() +{ + if ( m_array ) + { + Unlock(); + SafeArrayDestroy(m_array); + } +} + +bool wxSafeArrayHelper::Create(VARTYPE vt, long count) +{ + SAFEARRAYBOUND saBound; + + saBound.lLbound = 0; + saBound.cElements = count; + m_array = SafeArrayCreate(vt, 1, &saBound); + if ( !m_array ) + return false; + return SUCCEEDED( SafeArrayLock(m_array) ); +} + +bool wxSafeArrayHelper::SetElement(size_t index, const wxVariant& variant) +{ + VARIANT* data = (VARIANT*)m_array->pvData; + return wxConvertVariantToOle(variant, data[index]); +} + +bool wxSafeArrayHelper::SetElement(size_t index, const wxString& str) +{ + BSTR bstr = wxConvertStringToOle(str); + + if ( !bstr && !str.empty() ) + { + // BSTR can be NULL for empty strings but if the string was + // not empty, it means we failed to allocate memory for it. + return false; + } + + BSTR* data = (BSTR*)m_array->pvData; + data[index] = bstr; + return true; +} + +SAFEARRAY* wxSafeArrayHelper::Detach() +{ + Unlock(); + SAFEARRAY* result = m_array; + m_array = NULL; + return result; +} + +void wxSafeArrayHelper::Unlock() +{ + if ( m_array ) + SafeArrayUnlock(m_array); +} + +} // unnamed namespace + + +// ---------------------------------------------------------------------------- +// 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; +} + +// ---------------------------------------------------------------------------- +// wxVariantDataErrorCode +// ---------------------------------------------------------------------------- + +#if wxUSE_ANY + +bool wxVariantDataErrorCode::GetAsAny(wxAny* any) const +{ + *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; +} + + + +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 = wxDynamicCastVariantData(variant.GetData(), + wxVariantDataErrorCode); + oleVariant.vt = VT_ERROR; + oleVariant.scode = ec->GetValue(); + } + else if (type == wxT("currency")) + { + wxVariantDataCurrency* const + c = wxDynamicCastVariantData(variant.GetData(), + wxVariantDataCurrency); + oleVariant.vt = VT_CY; + oleVariant.cyVal = c->GetValue(); + } + 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 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")) + { + wxSafeArrayHelper sah; + + if (!sah.Create(VT_VARIANT, variant.GetCount())) + return false; + + for (size_t i = 0; i < variant.GetCount(); i++) + { + if (!sah.SetElement(i, variant[i])) + return false; + } + + oleVariant.vt = VT_VARIANT | VT_ARRAY; + oleVariant.parray = sah.Detach(); + } + else if (type == wxT("arrstring")) + { + wxArrayString strings(variant.GetArrayString()); + wxSafeArrayHelper sah; + + if (!sah.Create(VT_BSTR, strings.GetCount())) + return false; + + for (size_t i = 0; i < strings.GetCount(); i++) + { + if (!sah.SetElement(i, strings[i])) + return false; + } + + oleVariant.vt = VT_BSTR | VT_ARRAY; + oleVariant.parray = sah.Detach(); + } + else + { + oleVariant.vt = VT_NULL; + return false; + } + return true; } +#ifndef VT_TYPEMASK +#define VT_TYPEMASK 0xfff +#endif + +WXDLLEXPORT bool +wxConvertOleToVariant(const VARIANTARG& oleVariant, wxVariant& variant) +{ + bool ok = true; + if ( oleVariant.vt & VT_ARRAY ) + { + + // Compute the total number of elements in all array dimensions + int cElements = 1; + for ( int cDims = 0; cDims < oleVariant.parray->cDims; cDims++ ) + cElements *= oleVariant.parray->rgsabound[cDims].cElements; + + // Get a pointer to the data + void* pvdata; + HRESULT hr = SafeArrayAccessData(oleVariant.parray, &pvdata); + if ( FAILED(hr) ) + return false; + + switch (oleVariant.vt & VT_TYPEMASK) + { + case VT_VARIANT: + { + variant.ClearList(); + VARIANTARG *variant_data=(VARIANTARG*)pvdata; + for ( int i = 0; i < cElements; i++ ) + { + VARIANTARG& oleElement = variant_data[i]; + wxVariant vElement; + if ( !wxConvertOleToVariant(oleElement, vElement) ) + { + ok = false; + variant.ClearList(); + break; + } + + variant.Append(vElement); + } + } + break; + + case VT_BSTR: + { + wxArrayString strings; + BSTR *string_val=(BSTR*)pvdata; + for ( int i = 0; i < cElements; ++i ) + { + wxString str=wxConvertStringFromOle(*string_val); + strings.Add(str); + ++string_val; + } + variant=strings; + } + break; + + default: + wxLogDebug(wxT("unhandled VT_ARRAY type %x in wxConvertOleToVariant"), + oleVariant.vt & VT_TYPEMASK); + variant = wxVariant(); + ok = false; + break; + } + + SafeArrayUnaccessData(oleVariant.parray); + } + 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; +} + +#endif // wxUSE_VARIANT + + // ---------------------------------------------------------------------------- // Debug support // ---------------------------------------------------------------------------- -#if defined(__WXDEBUG__) && defined(_MSC_VER) && (_MSC_VER > 1000) -const char *GetIidName(REFIID riid) +#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 struct KNOWN_IID { const IID *pIid; - const char *szName; + const wxChar *szName; }; // construct the table containing all known interfaces - #define ADD_KNOWN_IID(name) { &IID_I##name, #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) ) ADD_KNOWN_IID(ContinueCallback), ADD_KNOWN_IID(EnumOleDocumentViews), ADD_KNOWN_IID(OleCommandTarget), @@ -88,6 +648,7 @@ const char *GetIidName(REFIID riid) 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), @@ -159,34 +720,41 @@ const char *GetIidName(REFIID riid) #undef ADD_KNOWN_IID // try to find the interface in the table - for ( uint ui = 0; ui < WXSIZEOF(aKnownIids); ui++ ) { + for ( size_t ui = 0; ui < WXSIZEOF(aKnownIids); ui++ ) { if ( riid == *aKnownIids[ui].pIid ) { return aKnownIids[ui].szName; } } +#ifndef __WXWINCE__ // unknown IID, just transform to string - static Uuid s_uuid; - s_uuid.Set(riid); - return s_uuid; + Uuid uuid(riid); + return wxString((const wxChar *)uuid); +#else + return wxEmptyString; +#endif } -void wxLogQueryInterface(const char *szInterface, REFIID riid) +WXDLLEXPORT void wxLogQueryInterface(const wxChar *szInterface, REFIID riid) { - wxLogTrace("%s::QueryInterface (iid = %s)", szInterface, GetIidName(riid)); + wxLogTrace(wxTRACE_OleCalls, wxT("%s::QueryInterface (iid = %s)"), + szInterface, GetIidName(riid).c_str()); } -void wxLogAddRef(const char *szInterface, ULONG cRef) +WXDLLEXPORT void wxLogAddRef(const wxChar *szInterface, ULONG cRef) { - wxLogTrace("After %s::AddRef: m_cRef = %d", szInterface, cRef + 1); + wxLogTrace(wxTRACE_OleCalls, wxT("After %s::AddRef: m_cRef = %d"), szInterface, cRef + 1); } -void wxLogRelease(const char *szInterface, ULONG cRef) +WXDLLEXPORT void wxLogRelease(const wxChar *szInterface, ULONG cRef) { - wxLogTrace("After %s::Release: m_cRef = %d", szInterface, cRef - 1); + wxLogTrace(wxTRACE_OleCalls, wxT("After %s::Release: m_cRef = %d"), szInterface, cRef - 1); } -#endif //WXDEBUG +#endif // wxDEBUG_LEVEL -#endif - // USE_DRAG_AND_DROP +#endif // wxUSE_DATAOBJ + +#endif // __CYGWIN10__ + +#endif // wxUSE_OLE