diff options
Diffstat (limited to 'extensions/source/ole/unoconversionutilities.hxx')
-rw-r--r-- | extensions/source/ole/unoconversionutilities.hxx | 2445 |
1 files changed, 0 insertions, 2445 deletions
diff --git a/extensions/source/ole/unoconversionutilities.hxx b/extensions/source/ole/unoconversionutilities.hxx deleted file mode 100644 index 328fec41e..000000000 --- a/extensions/source/ole/unoconversionutilities.hxx +++ /dev/null @@ -1,2445 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/************************************************************************* - * - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * Copyright 2000, 2010 Oracle and/or its affiliates. - * - * OpenOffice.org - a multi-platform office productivity suite - * - * This file is part of OpenOffice.org. - * - * OpenOffice.org is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License version 3 - * only, as published by the Free Software Foundation. - * - * OpenOffice.org is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License version 3 for more details - * (a copy is included in the LICENSE file that accompanied this code). - * - * You should have received a copy of the GNU Lesser General Public License - * version 3 along with OpenOffice.org. If not, see - * <http://www.openoffice.org/license.html> - * for a copy of the LGPLv3 License. - * - ************************************************************************/ -#ifndef _UNO_CONVERSION_UTILITIES -#define _UNO_CONVERSION_UTILITIES - -#include "boost/scoped_array.hpp" -#include "com/sun/star/script/XInvocationAdapterFactory.hpp" -#include "com/sun/star/script/XInvocationAdapterFactory2.hpp" -#include "com/sun/star/script/XTypeConverter.hpp" -#include "com/sun/star/script/FailReason.hpp" -#include "com/sun/star/bridge/oleautomation/Date.hpp" -#include "com/sun/star/bridge/oleautomation/Currency.hpp" -#include "com/sun/star/bridge/oleautomation/SCode.hpp" -#include "com/sun/star/bridge/oleautomation/Decimal.hpp" -#include "typelib/typedescription.hxx" -#include "ole2uno.hxx" - -#include "unotypewrapper.hxx" -#include <boost/unordered_map.hpp> - -// for some reason DECIMAL_NEG (wtypes.h) which contains BYTE is not resolved. -typedef unsigned char BYTE; -// classes for wrapping uno objects -#define INTERFACE_OLE_WRAPPER_IMPL 1 -#define UNO_OBJECT_WRAPPER_REMOTE_OPT 2 - -#define INVOCATION_SERVICE reinterpret_cast<const sal_Unicode*>(L"com.sun.star.script.Invocation") - - -// classes for wrapping ole objects -#define IUNKNOWN_WRAPPER_IMPL 1 - -#define INTERFACE_ADAPTER_FACTORY reinterpret_cast<const sal_Unicode*>(L"com.sun.star.script.InvocationAdapterFactory") -// COM or JScript objects implementing UNO interfaces have to implement this property -#define SUPPORTED_INTERFACES_PROP L"_implementedInterfaces" -// Second property without leading underscore for use in VB -#define SUPPORTED_INTERFACES_PROP2 L"Bridge_ImplementedInterfaces" - -using namespace com::sun::star::script; -using namespace com::sun::star::beans; -using namespace com::sun::star::uno; -#ifdef __MINGW32__ -using namespace com::sun::star::bridge; -using namespace com::sun::star::bridge::ModelDependent; -#endif -using namespace com::sun::star::bridge::oleautomation; -using namespace boost; -namespace ole_adapter -{ -extern boost::unordered_map<sal_uInt32, sal_uInt32> AdapterToWrapperMap; -extern boost::unordered_map<sal_uInt32, sal_uInt32> WrapperToAdapterMap; -typedef boost::unordered_map<sal_uInt32, sal_uInt32>::iterator IT_Wrap; -typedef boost::unordered_map<sal_uInt32, sal_uInt32>::iterator CIT_Wrap; -//Maps IUnknown pointers to a weak reference of the respective wrapper class (e.g. -// IUnknownWrapperImpl. It is the responsibility of the wrapper to remove the entry when -// it is being destroyed. -// Used to ensure that an Automation object is always mapped to the same UNO objects. -extern boost::unordered_map<sal_uInt32, WeakReference<XInterface> > ComPtrToWrapperMap; -typedef boost::unordered_map<sal_uInt32, WeakReference<XInterface> >::iterator IT_Com; -typedef boost::unordered_map<sal_uInt32, WeakReference<XInterface> >::const_iterator CIT_Com; - -// Maps XInterface pointers to a weak reference of its wrapper class (i.e. -// InterfaceOleWrapper_Impl). It is the responsibility of the wrapper to remove the entry when -// it is being destroyed. It is used to ensure the identity of objects. That is, an UNO interface -// is mapped to IDispatch which is kept alive in the COM environment. If the same -// UNO interface is mapped again to COM then the IDispach of the first mapped instance -// must be returned. -extern boost::unordered_map<sal_uInt32, WeakReference<XInterface> > UnoObjToWrapperMap; -typedef boost::unordered_map<sal_uInt32, WeakReference<XInterface> >::iterator IT_Uno; -typedef boost::unordered_map<sal_uInt32, WeakReference<XInterface> >::const_iterator CIT_Uno; -#ifdef __MINGW32__ -inline void reduceRange( Any& any); -#endif - - - - -// createUnoObjectWrapper gets a wrapper instance by calling createUnoWrapperInstance - // and initializes it via XInitialization. The wrapper object is required to implement - // XBridgeSupplier so that it can convert itself to IDispatch. - // class T: Deriving class ( must implement XInterface ) -/** All methods are allowed to throw at least a BridgeRuntimeError. - */ -template< class > -class UnoConversionUtilities -{ -public: - UnoConversionUtilities( const Reference<XMultiServiceFactory> & smgr): - m_nUnoWrapperClass( INTERFACE_OLE_WRAPPER_IMPL), - m_nComWrapperClass( IUNKNOWN_WRAPPER_IMPL), - m_smgr( smgr) - {} - - UnoConversionUtilities( const Reference<XMultiServiceFactory> & xFactory, sal_uInt8 unoWrapperClass, sal_uInt8 comWrapperClass ) - : m_smgr( xFactory), m_nComWrapperClass( comWrapperClass), m_nUnoWrapperClass( unoWrapperClass) - {} - - virtual ~UnoConversionUtilities() {} - /** converts only into oleautomation types, that is there is no VT_I1, VT_UI2, VT_UI4 - a sal_Unicode character is converted into a BSTR. - @exception com.sun.star.lang.IllegalArgumentException - If the any was inappropriate for conversion. - @exception com.sun.star.script.CannotConvertException - The any contains a type class for which no conversion is provided. - */ - void anyToVariant(VARIANT* pVariant, const Any& rAny); - void anyToVariant(VARIANT* pVariant, const Any& rAny, VARTYPE type); - - /** @exception com.sun.star.lang.IllegalArgumentException - If rSeq does not contain a sequence then the exception is thrown. - */ - SAFEARRAY* createUnoSequenceWrapper(const Any& rSeq); - /** @exception com.sun.star.lang.IllegalArgumentException - If rSeq does not contain a sequence or elemtype has no proper value - then the exception is thrown. - */ - SAFEARRAY* createUnoSequenceWrapper(const Any& rSeq, VARTYPE elemtype); - /** - @exception com.sun.star.lang.IllegalArgumentException - If rObj does not contain a struct or interface - */ - void createUnoObjectWrapper(const Any & rObj, VARIANT * pVar); - /** @exception CannotConvertException - Thrown if the VARIANT contains a type that cannot be coerced in the expected Any. - ArgumentIndex is 0. - @IllegalArgumentException - Thrown if the VARIANT is inappropriate for conversion. ArgumentPosition is -1, - */ - void variantToAny(const VARIANT* pVariant, Any& rAny, sal_Bool bReduceValueRange = sal_True); - /** This method converts variants arguments in calls from COM -> UNO. Only then - the expected UNO type is known. - @exception CannotConvertException - Thrown if the VARIANT contains a type that cannot be coerced in the expected Any. - ArgumentIndex is 0. - @IllegalArgumentException - Thrown if the VARIANT is inappropriate for conversion. ArgumentPosition is -1, - */ - void variantToAny( const VARIANTARG* pArg, Any& rAny, const Type& ptype, sal_Bool bReduceValueRange = sal_True); - - /** - @exception IllegalArgumentException - -if pVar does not contain VT_UNKNOWN or VT_DISPATCH or - pVar is used for a particular UNO type which is not supported by pVar - */ - Any createOleObjectWrapper(VARIANT* pVar, const Type& aType= Type()); - - /* - Return true means var contained a ValueObject, and it was successfully converted. - The result is in any. It an error occurred a BridgeRuntimeError will be thrown. - */ - bool convertValueObject( const VARIANTARG *var, Any& any); - void dispatchExObject2Sequence( const VARIANTARG* pvar, Any& anySeq, const Type& type); - - Sequence<Any> createOleArrayWrapperOfDim(SAFEARRAY* pArray, unsigned int dimCount, unsigned int actDim, long* index, - VARTYPE type, const Type& unotype); - Sequence<Any> createOleArrayWrapper(SAFEARRAY* pArray, VARTYPE type, const Type& unotype= Type()); - - - VARTYPE mapTypeClassToVartype( TypeClass type); - Reference< XSingleServiceFactory > getInvocationFactory(const Any& anyObject); - - - virtual Reference< XInterface > createUnoWrapperInstance()=0; - virtual Reference< XInterface > createComWrapperInstance()=0; - - static sal_Bool isJScriptArray(const VARIANT* pvar); - - Sequence<Type> getImplementedInterfaces(IUnknown* pUnk); - -protected: - Reference<XInterface> createAdapter(const Sequence<Type>& types, const Reference<XInterface>& receiver); - - // helper function for Sequence conversion - void getElementCountAndTypeOfSequence( const Any& rSeq, sal_Int32 dim, Sequence< sal_Int32 >& seqElementCounts, TypeDescription& typeDesc); - // helper function for Sequence conversion - sal_Bool incrementMultidimensionalIndex(sal_Int32 dimensions, const sal_Int32 * parDimensionLength, - sal_Int32 * parMultidimensionalIndex); - // helper function for Sequence conversion - size_t getOleElementSize( VARTYPE type); - - Type getElementTypeOfSequence( const Type& seqType); - - //Provides a typeconverter - Reference<XTypeConverter> getTypeConverter(); - - // This member determines what class is used to convert a UNO object - // or struct to a COM object. It is passed along to the o2u_anyToVariant - // function in the createBridge function implementation - sal_uInt8 m_nUnoWrapperClass; - sal_uInt8 m_nComWrapperClass; - - // The servicemanager is either a local smgr or remote when the service - // com.sun.star.bridge.OleBridgeSupplierVar1 is used. This service can be - // created by createInstanceWithArguments where one can supply a service - // manager that is to be used. - // Local service manager as supplied by the loader when the creator function - // of the service is being called. - Reference<XMultiServiceFactory> m_smgr; - // An explicitly supplied service manager when the service - // com.sun.star.bridge.OleBridgeSupplierVar1 is used. That can be a remote - // manager. - Reference<XMultiServiceFactory> m_smgrRemote; - Reference<XSingleServiceFactory> m_xInvocationFactoryLocal; - Reference<XSingleServiceFactory> m_xInvocationFactoryRemote; - -private: - // Holds the type converter which is used for sequence conversion etc. - // Use the getTypeConverter function to obtain the interface. - Reference<XTypeConverter> m_typeConverter; - - -}; - -// ask the object for XBridgeSupplier2 and on success bridges -// the uno object to IUnknown or IDispatch. -// return true the UNO object supports -template < class T > -bool convertSelfToCom( T& unoInterface, VARIANT * pVar) -{ - bool ret = false; - Reference< XInterface > xInt( unoInterface, UNO_QUERY); - if( xInt.is()) - { - Reference< XBridgeSupplier2 > xSupplier( xInt, UNO_QUERY); - if( xSupplier.is()) - { - sal_Int8 arId[16]; - rtl_getGlobalProcessId( (sal_uInt8*)arId); - Sequence<sal_Int8> seqId( arId, 16); - Any anySource; - anySource <<= xInt; - Any anyDisp= xSupplier->createBridge( anySource, seqId, UNO, OLE); - if( anyDisp.getValueTypeClass() == TypeClass_UNSIGNED_LONG) - { - VARIANT* pvariant= *(VARIANT**)anyDisp.getValue(); - HRESULT hr; - if (FAILED(hr = VariantCopy(pVar, pvariant))) - throw BridgeRuntimeError( - OUSTR("[automation bridge] convertSelfToCom\n" - "VariantCopy failed! Error: ") + - OUString::valueOf(hr)); - VariantClear( pvariant); - CoTaskMemFree( pvariant); - ret = true; - } - } - } - return ret; -} - - - -// Gets the invocation factory depending on the Type in the Any. -// The factory can be created by a local or remote multi service factory. -// In case there is a remote multi service factory available there are -// some services or types for which the local factory is used. The exceptions -// are: all structs. -// Param anyObject - contains the object ( interface, struct) for what we need an invocation object. -// -template<class T> -Reference< XSingleServiceFactory > UnoConversionUtilities<T>::getInvocationFactory(const Any& anyObject) -{ - Reference< XSingleServiceFactory > retVal; - MutexGuard guard( getBridgeMutex()); - if( anyObject.getValueTypeClass() != TypeClass_STRUCT && - m_smgrRemote.is() ) - { - if( ! m_xInvocationFactoryRemote.is() ) - m_xInvocationFactoryRemote= Reference<XSingleServiceFactory>( - m_smgrRemote->createInstance( INVOCATION_SERVICE), UNO_QUERY); - retVal= m_xInvocationFactoryRemote; - } - else - { - if( ! m_xInvocationFactoryLocal.is() ) - m_xInvocationFactoryLocal= Reference<XSingleServiceFactory>( - m_smgr->createInstance(INVOCATION_SERVICE ), UNO_QUERY); - retVal= m_xInvocationFactoryLocal; - } - return retVal; -} - -template<class T> -void UnoConversionUtilities<T>::variantToAny( const VARIANTARG* pArg, Any& rAny, const Type& ptype, sal_Bool bReduceValueRange /* = sal_True */) -{ - try - { - HRESULT hr; - bool bFail = false; - bool bCannotConvert = false; - CComVariant var; - - // There is no need to support indirect values, since they're not supported by UNO - if( FAILED(hr= VariantCopyInd( &var, const_cast<VARIANTARG*>(pArg)))) // remove VT_BYREF - throw BridgeRuntimeError( - OUSTR("[automation bridge] UnoConversionUtilities<T>::variantToAny \n" - "VariantCopyInd failed for reason : ") + OUString::valueOf(hr)); - bool bHandled = convertValueObject( & var, rAny); - if( bHandled) - OSL_ENSURE( rAny.getValueType() == ptype, "type in Value Object must match the type parameter"); - - if( ! bHandled) - { - // convert into a variant type that is the equivalent to the type - // the sequence expects. Thus variantToAny produces the correct type - // E.g. An Array object contains VT_I4 and the sequence expects shorts - // than the vartype must be changed. The reason is, you can't specify the - // type in JavaScript and the script engine determines the type beeing used. - switch( ptype.getTypeClass()) - { - case TypeClass_CHAR: // could be: new Array( 12, 'w', "w") - if( var.vt == VT_BSTR) - { - if(SUCCEEDED( hr= VariantChangeType( &var, &var, 0, VT_BSTR))) - rAny.setValue( (void*)V_BSTR( &var), ptype); - else if (hr == DISP_E_TYPEMISMATCH) - bCannotConvert = true; - else - bFail = true; - } - else - { - if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_I2))) - rAny.setValue((void*) & var.iVal, ptype); - else if (hr == DISP_E_TYPEMISMATCH) - bCannotConvert = true; - else - bFail = true; - } - break; - case TypeClass_INTERFACE: // could also be an IUnknown - case TypeClass_STRUCT: - { - rAny = createOleObjectWrapper( & var, ptype); - break; - } - case TypeClass_ENUM: - if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_I4))) - rAny.setValue((void*) & var.lVal, ptype); - else if (hr == DISP_E_TYPEMISMATCH) - bCannotConvert = true; - else - bFail = true; - break; - case TypeClass_SEQUENCE: - // There are different ways of receiving a sequence: - // 1: JScript, VARTYPE: VT_DISPATCH - // 2. VBScript simple arraysVT_VARIANT|VT_BYREF the referenced VARIANT contains - // a VT_ARRAY| <type> - // 3. VBSrcript multi dimensional arrays: VT_ARRAY|VT_BYREF - if( pArg->vt == VT_DISPATCH) - { - dispatchExObject2Sequence( pArg, rAny, ptype); - } - else - { - if ((var.vt & VT_ARRAY) != 0) - { - VARTYPE oleType = ::sal::static_int_cast< VARTYPE, int >( var.vt ^ VT_ARRAY ); - Sequence<Any> unoSeq = createOleArrayWrapper( var.parray, oleType, ptype); - Reference<XTypeConverter> conv = getTypeConverter(); - if (conv.is()) - { - try - { - Any anySeq = makeAny(unoSeq); - Any convAny = conv->convertTo(anySeq, ptype); - rAny = convAny; - } - catch (IllegalArgumentException& e) - { - throw BridgeRuntimeError( - OUSTR("[automation bridge]com.sun.star.lang.IllegalArgumentException " - "in UnoConversionUtilities<T>::variantToAny! Message: ") + - e.Message); - } - catch (CannotConvertException& e) - { - throw BridgeRuntimeError( - OUSTR("[automation bridge]com.sun.star.script.CannotConvertException " - "in UnoConversionUtilities<T>::variantToAny! Message: ") + - e.Message); - } - } - } - } - break; - case TypeClass_VOID: - rAny.setValue(NULL,Type()); - break; - case TypeClass_ANY: // Any - // There could be a JScript Array that needs special handling - // If an Any is expected and this Any must contain a Sequence - // then we cannot figure out what element type is required. - // Therefore we convert to Sequence< Any > - if( pArg->vt == VT_DISPATCH && isJScriptArray( pArg)) - { - dispatchExObject2Sequence( pArg, rAny, - getCppuType((Sequence<Any>*) 0)); - } - else if (pArg->vt == VT_DECIMAL) - { - //Decimal maps to hyper in calls from COM -> UNO - // It does not matter if we create a sal_uInt64 or sal_Int64, - // because the UNO object is called through invocation which - //will do a type conversion if necessary - if (var.decVal.sign == 0) - { - // positive value - variantToAny( & var, rAny, getCppuType( (sal_uInt64*) 0), - bReduceValueRange); - } - else - { - //negative value - variantToAny( & var, rAny, getCppuType( (sal_Int64*) 0), - bReduceValueRange); - } - } - else - { - variantToAny( & var, rAny); - } - break; - case TypeClass_BOOLEAN: // VARIANT could be VARIANT_BOOL or other - if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_BOOL))) - variantToAny( & var, rAny); - else if (hr == DISP_E_TYPEMISMATCH) - bCannotConvert = true; - else - bFail = true; - break; - case TypeClass_STRING: // UString - if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_BSTR))) - variantToAny( & var, rAny); - else if (hr == DISP_E_TYPEMISMATCH) - bCannotConvert = true; - else - bFail = true; - break; - case TypeClass_FLOAT: // float - if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_R4))) - variantToAny( & var, rAny); - else if (hr == DISP_E_TYPEMISMATCH) - bCannotConvert = true; - else - bFail = true; - break; - case TypeClass_DOUBLE: // double - if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_R8))) - variantToAny(& var, rAny); - else if (hr == DISP_E_TYPEMISMATCH) - bCannotConvert = true; - else - bFail = true; - break; - case TypeClass_BYTE: // BYTE - if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_I1))) - variantToAny( & var, rAny); - else if (hr == DISP_E_TYPEMISMATCH) - bCannotConvert = true; - else - bFail = true; - break; - case TypeClass_SHORT: // INT16 - if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_I2))) - variantToAny( & var, rAny); - else if (hr == DISP_E_TYPEMISMATCH) - bCannotConvert = true; - else - bFail = true; - break; - case TypeClass_LONG: - if(SUCCEEDED(hr = VariantChangeType(& var, &var, 0, VT_I4))) - variantToAny( & var, rAny, bReduceValueRange); - else if (hr == DISP_E_TYPEMISMATCH) - bCannotConvert = true; - else - bFail = true; - break; - case TypeClass_HYPER: - if(SUCCEEDED(hr = VariantChangeType(& var, &var, 0, VT_DECIMAL))) - { - if (var.decVal.Lo64 > SAL_CONST_UINT64(0x8000000000000000) - || var.decVal.Hi32 > 0 - || var.decVal.scale > 0) - { - bFail = true; - break; - } - sal_Int64 value = var.decVal.Lo64; - if (var.decVal.sign == DECIMAL_NEG) - value |= SAL_CONST_UINT64(0x8000000000000000); - rAny <<= value; - } - else if (hr == DISP_E_TYPEMISMATCH) - bCannotConvert = true; - else - bFail = true; - break; - case TypeClass_UNSIGNED_SHORT: // UINT16 - if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_UI2))) - variantToAny( & var, rAny); - else if (hr == DISP_E_TYPEMISMATCH) - bCannotConvert = true; - else - bFail = true; - break; - case TypeClass_UNSIGNED_LONG: - if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_UI4))) - variantToAny( & var, rAny, bReduceValueRange); - else if (hr == DISP_E_TYPEMISMATCH) - bCannotConvert = true; - else - bFail = true; - break; - case TypeClass_UNSIGNED_HYPER: - if(SUCCEEDED(hr = VariantChangeType(& var, &var, 0, VT_DECIMAL))) - { - if (var.decVal.Hi32 > 0 || var.decVal.scale > 0) - { - bFail = true; - break; - } - rAny <<= var.decVal.Lo64; - } - else if (hr == DISP_E_TYPEMISMATCH) - bCannotConvert = true; - else - bFail = true; - break; - case TypeClass_TYPE: - if(SUCCEEDED(hr = VariantChangeType(& var, &var, 0, VT_UNKNOWN))) - variantToAny( & var, rAny); - else if (hr == DISP_E_TYPEMISMATCH) - bCannotConvert = true; - else - bFail = true; - break; - default: - bCannotConvert = true; - break; - } - } - if (bCannotConvert) - throw CannotConvertException( - OUSTR("[automation bridge]UnoConversionUtilities<T>::variantToAny \n" - "Cannot convert the value of vartype :\"") + - OUString::valueOf((sal_Int32) var.vt) + - OUSTR("\" to the expected UNO type of type class: ") + - OUString::valueOf((sal_Int32) ptype.getTypeClass()), - 0, TypeClass_UNKNOWN, FailReason::TYPE_NOT_SUPPORTED,0); - - if (bFail) - throw IllegalArgumentException( - OUSTR("[automation bridge]UnoConversionUtilities<T>:variantToAny\n" - "The provided VARIANT of type\" ") + OUString::valueOf((sal_Int32) var.vt) + - OUSTR("\" is unappropriate for conversion!"), Reference<XInterface>(), -1); - } - catch (CannotConvertException &) - { - throw; - } - catch (IllegalArgumentException &) - { - throw; - } - catch (BridgeRuntimeError &) - { - throw; - } - catch (Exception & e) - { - throw BridgeRuntimeError(OUSTR("[automation bridge] unexpected exception in " - "UnoConversionUtilities<T>::variantToAny ! Message : \n") + - e.Message); - } - catch(...) - { - throw BridgeRuntimeError( - OUSTR("[automation bridge] unexpected exception in " - "UnoConversionUtilities<T>::variantToAny !")); - } -} - -// The function only converts Sequences to SAFEARRAYS with elements of the type -// specified by the parameter type. Everything else is forwarded to -// anyToVariant(VARIANT* pVariant, const Any& rAny) -// Param type must not be VT_BYREF -template<class T> -void UnoConversionUtilities<T>::anyToVariant(VARIANT* pVariant, const Any& rAny, VARTYPE type) -{ - try - { - HRESULT hr= S_OK; - - OSL_ASSERT( (type & VT_BYREF) == 0); - if (type & VT_ARRAY) - { - type ^= VT_ARRAY; - SAFEARRAY* ar= createUnoSequenceWrapper( rAny, type); - if( ar) - { - VariantClear( pVariant); - pVariant->vt= ::sal::static_int_cast< VARTYPE, int >( VT_ARRAY | type ); - pVariant->byref= ar; - } - } - else if(type == VT_VARIANT) - { - anyToVariant(pVariant, rAny); - } - else - { - CComVariant var; - anyToVariant( &var, rAny); - if(FAILED(hr = VariantChangeType(&var, &var, 0, type))) - { - if (hr == DISP_E_TYPEMISMATCH) - throw CannotConvertException( - OUSTR("[automation bridge]UnoConversionUtilities<T>::anyToVariant \n" - "Cannot convert the value of type :\"") + - rAny.getValueTypeName() + - OUSTR("\" to the expected Automation type of VARTYPE: ") + - OUString::valueOf((sal_Int32)type), - 0, TypeClass_UNKNOWN, FailReason::TYPE_NOT_SUPPORTED,0); - - throw BridgeRuntimeError( - OUSTR("[automation bridge]UnoConversionUtilities<T>::anyToVariant \n" - "Conversion of any with ") + - rAny.getValueType().getTypeName() + - OUSTR(" to VARIANT with type: ") + OUString::valueOf((sal_Int32) type) + - OUSTR(" failed! Error code: ") + OUString::valueOf(hr)); - - } - if(FAILED(hr = VariantCopy(pVariant, &var))) - { - throw BridgeRuntimeError( - OUSTR("[automation bridge]UnoConversionUtilities<T>::anyToVariant \n" - "VariantCopy failed for reason: ") + OUString::valueOf(hr)); - } - } - } - catch (IllegalArgumentException &) - { - throw; - } - catch (CannotConvertException & ) - { - throw; - } - catch (BridgeRuntimeError&) - { - throw; - } - catch(Exception & e) - { - throw BridgeRuntimeError( - OUSTR("[automation bridge]UnoConversionUtilities<T>::anyToVariant \n" - "Unexpected exception occurred. Message: ") + e.Message); - } - catch(...) - { - throw BridgeRuntimeError( - OUSTR("[automation bridge]UnoConversionUtilities<T>::anyToVariant \n" - "Unexpected exception occurred.")); - } -} - -template<class T> -void UnoConversionUtilities<T>::anyToVariant(VARIANT* pVariant, const Any& rAny) -{ - bool bIllegal = false; - try - { - switch (rAny.getValueTypeClass()) - { - case TypeClass_INTERFACE: - { - Reference<XInterface> xInt; - if (rAny >>= xInt) - { - createUnoObjectWrapper(rAny, pVariant); - } - else - { - bIllegal = true; - } - break; - } - case TypeClass_STRUCT: - { - if (rAny.getValueType() == getCppuType((Date*)0)) - { - Date d; - if (rAny >>= d) - { - pVariant->vt = VT_DATE; - pVariant->date = d.Value; - } - else - { - bIllegal = true; - } - } - else if(rAny.getValueType() == getCppuType((Decimal*)0)) - { - Decimal d; - if (rAny >>= d) - { - pVariant->vt = VT_DECIMAL; - pVariant->decVal.scale = d.Scale; - pVariant->decVal.sign = d.Sign; - pVariant->decVal.Lo32 = d.LowValue; - pVariant->decVal.Mid32 = d.MiddleValue; - pVariant->decVal.Hi32 = d.HighValue; - } - else - { - bIllegal = true; - } - } - else if (rAny.getValueType() == getCppuType((Currency*)0)) - { - Currency c; - if (rAny >>= c) - { - pVariant->vt = VT_CY; - pVariant->cyVal.int64 = c.Value; - } - else - { - bIllegal = true; - } - } - else if(rAny.getValueType() == getCppuType((SCode*)0)) - { - SCode s; - if (rAny >>= s) - { - pVariant->vt = VT_ERROR; - pVariant->scode = s.Value; - } - else - { - bIllegal = true; - } - } - else - { - createUnoObjectWrapper(rAny, pVariant); - } - break; - } - case TypeClass_SEQUENCE: // sequence ??? SafeArray descriptor - { - SAFEARRAY* pArray = createUnoSequenceWrapper(rAny); - if (pArray) - { - V_VT(pVariant) = VT_ARRAY | VT_VARIANT; - V_ARRAY(pVariant) = pArray; - } - else - { - bIllegal = true; - } - break; - } - case TypeClass_VOID: - { - HRESULT hr = S_OK; - if (FAILED(hr = VariantClear(pVariant))) - { - throw BridgeRuntimeError( - OUSTR("[automation bridge]UnoConversionUtilities<T>::anyToVariant\n" - "VariantClear failed with error:") + OUString::valueOf(hr)); - } - break; - } - case TypeClass_BOOLEAN: - { - sal_Bool value; - if (rAny >>= value) - { - pVariant->vt = VT_BOOL; - pVariant->boolVal = value == sal_True? VARIANT_TRUE: VARIANT_FALSE; - } - else - { - bIllegal = true; - } - break; - } - case TypeClass_CHAR: - { - // Because VT_UI2 does not conform to oleautomation we convert into VT_I2 instead - sal_uInt16 value = *(sal_Unicode*) rAny.getValue(); - pVariant->vt = VT_I2; - pVariant->iVal = value; - break; - } - case TypeClass_STRING: - { - OUString value; - if (rAny >>= value) - { - pVariant->vt = VT_BSTR; - pVariant->bstrVal = SysAllocString(reinterpret_cast<LPCOLESTR>(value.getStr())); - } - else - { - bIllegal = true; - } - break; - } - case TypeClass_FLOAT: - { - float value; - if (rAny >>= value) - { - pVariant->vt = VT_R4; - pVariant->fltVal = value; - } - else - { - bIllegal = true; - } - break; - } - case TypeClass_DOUBLE: - { - double value; - if (rAny >>= value) - { - pVariant->vt = VT_R8; - pVariant->dblVal = value; - } - else - { - bIllegal = true; - } - break; - } - case TypeClass_BYTE: - { - // ole automation does not know a signed char but only unsigned char - sal_Int8 value; - if (rAny >>= value) - { - pVariant->vt = VT_UI1; - pVariant->bVal = value; - } - else - { - bIllegal = true; - } - break; - } - case TypeClass_SHORT: // INT16 - case TypeClass_UNSIGNED_SHORT: // UINT16 - { - sal_Int16 value; - if (rAny >>= value) - { - pVariant->vt = VT_I2; - pVariant->iVal = value; - } - else - { - bIllegal = true; - } - break; - } - case TypeClass_ENUM: - { - sal_Int32 value = *(sal_Int32*) rAny.getValue(); - pVariant->vt = VT_I4; - pVariant->lVal= value; - break; - } - case TypeClass_LONG: - case TypeClass_UNSIGNED_LONG: - { - sal_Int32 value; - if (rAny >>= value) - { - pVariant->vt = VT_I4; - pVariant->lVal= value; - } - else - { - bIllegal = true; - } - break; - } - case TypeClass_HYPER: - { - - pVariant->vt = VT_DECIMAL; - pVariant->decVal.scale = 0; - pVariant->decVal.sign = 0; - pVariant->decVal.Hi32 = 0; - - sal_Int64 value; - rAny >>= value; - - if (value & SAL_CONST_UINT64(0x8000000000000000)) - pVariant->decVal.sign = DECIMAL_NEG; - - pVariant->decVal.Lo64 = value; - break; - } - case TypeClass_UNSIGNED_HYPER: - { - pVariant->vt = VT_DECIMAL; - pVariant->decVal.scale = 0; - pVariant->decVal.sign = 0; - pVariant->decVal.Hi32 = 0; - - sal_uInt64 value; - rAny >>= value; - pVariant->decVal.Lo64 = value; - break; - } - case TypeClass_TYPE: - { - Type type; - rAny >>= type; - CComVariant var; - if (createUnoTypeWrapper(type.getTypeName(), & var) == false) - throw BridgeRuntimeError( - OUSTR("[automation bridge] UnoConversionUtilities<T>::anyToVariant \n" - "Error during conversion of UNO type to Automation object!")); - - if (FAILED(VariantCopy(pVariant, &var))) - throw BridgeRuntimeError( - OUSTR("[automation bridge] UnoConversionUtilities<T>::anyToVariant \n" - "Unexpected error!")); - break; - } - default: - //TypeClass_SERVICE: - //TypeClass_EXCEPTION: - //When a InvocationTargetException is thrown when calling XInvocation::invoke - //on a UNO object, then the target exception is directly used to create a - //EXEPINFO structure - //TypeClass_TYPEDEF - //TypeClass_ANY: - //TypeClass_UNKNOWN: - //TypeClass_UNSIGNED_OCTET: - // TypeClass_UNION: - // TypeClass_ARRAY: - // TypeClass_UNSIGNED_INT: - // TypeClass_UNSIGNED_BYTE: - // TypeClass_MODULE: - throw CannotConvertException( - OUSTR("[automation bridge]UnoConversionUtilities<T>::anyToVariant\n" - "There is no conversion for this UNO type to a Automation type." - "The destination type class is the type class of the UNO " - "argument which was to be converted."), - Reference<XInterface>(), rAny.getValueTypeClass(), - FailReason::TYPE_NOT_SUPPORTED, 0); - - break; - } - if (bIllegal) - { - throw IllegalArgumentException( - OUSTR("[automation bridge]UnoConversionUtilities<T>::anyToVariant\n" - "The provided any of type\" ") + rAny.getValueType().getTypeName() + - OUSTR("\" is unappropriate for conversion!"), Reference<XInterface>(), -1); - - } - } - catch (CannotConvertException & ) - { - throw; - } - catch (IllegalArgumentException & ) - { - throw; - } - catch(BridgeRuntimeError&) - { - throw; - } - catch(Exception & e) - { - throw BridgeRuntimeError( - OUSTR("[automation bridge]UnoConversionUtilities<T>::anyToVariant \n" - "Unexpected exception occurred. Message: ") + e.Message); - } - catch(...) - { - throw BridgeRuntimeError( - OUSTR("[automation bridge]UnoConversionUtilities<T>::anyToVariant \n" - "Unexpected exception occurred. ") ); - } -} - -// Creates an SAFEARRAY of the specified element and if necessary -// creates a SAFEARRAY whith multiple dimensions. -// Used by sal_Bool anyToVariant(VARIANT* pVariant, const Any& rAny, VARTYPE type); -template<class T> -SAFEARRAY* UnoConversionUtilities<T>::createUnoSequenceWrapper(const Any& rSeq, VARTYPE elemtype) -{ - if (rSeq.getValueTypeClass() != TypeClass_SEQUENCE) - throw IllegalArgumentException( - OUSTR("[automation bridge]UnoConversionUtilities<T>::createUnoSequenceWrapper \n" - "The any does not contain a sequence!"), 0, 0); - if (elemtype == VT_NULL || elemtype == VT_EMPTY) - throw IllegalArgumentException( - OUSTR("[automation bridge]UnoConversionUtilities<T>::createUnoSequenceWrapper \n" - "No element type supplied!"),0, -1); - SAFEARRAY* pArray= NULL; - // Get the dimensions. This is done by examining the type name string - // The count of brackets determines the dimensions. - OUString sTypeName= rSeq.getValueType().getTypeName(); - sal_Int32 dims=0; - for(sal_Int32 lastIndex=0;(lastIndex= sTypeName.indexOf( L'[', lastIndex)) != -1; lastIndex++,dims++); - - //get the maximum number of elements per dimensions and the typedescription of the elements - Sequence<sal_Int32> seqElementCounts( dims); - TypeDescription elementTypeDesc; - getElementCountAndTypeOfSequence( rSeq, 1, seqElementCounts, elementTypeDesc ); - - if( elementTypeDesc.is() ) - { - // set up the SAFEARRAY - scoped_array<SAFEARRAYBOUND> sarSafeArrayBound(new SAFEARRAYBOUND[dims]); - SAFEARRAYBOUND* prgsabound= sarSafeArrayBound.get(); - for( sal_Int32 i=0; i < dims; i++) - { - //prgsabound[0] is the right most dimension - prgsabound[dims - i - 1].lLbound = 0; - prgsabound[dims - i - 1].cElements = seqElementCounts[i]; - } - - typelib_TypeDescription* rawTypeDesc= elementTypeDesc.get(); - sal_Int32 elementSize= rawTypeDesc->nSize; - size_t oleElementSize= getOleElementSize( elemtype); - // SafeArrayCreate clears the memory for the data itself. - pArray = SafeArrayCreate(elemtype, dims, prgsabound); - - // convert the Sequence's elements and populate the SAFEARRAY - if( pArray) - { - // Iterate over every Sequence that contains the actual elements - void* pSAData; - if( SUCCEEDED( SafeArrayAccessData( pArray, &pSAData))) - { - const sal_Int32* parElementCount= seqElementCounts.getConstArray(); - uno_Sequence * pMultiSeq= *(uno_Sequence* const*) rSeq.getValue(); - sal_Int32 dimsSeq= dims - 1; - - // arDimSeqIndizes contains the current index of a block of data. - // E.g. Sequence<Sequence<sal_Int32>> , the index would refer to Sequence<sal_Int32> - // In this case arDimSeqIndices would have the size 1. That is the elements are not counted - // but the Sequences that contain those elements. - // The indices ar 0 based - scoped_array<sal_Int32> sarDimsSeqIndices; - sal_Int32* arDimsSeqIndices= NULL; - if( dimsSeq > 0) - { - sarDimsSeqIndices.reset(new sal_Int32[dimsSeq]); - arDimsSeqIndices = sarDimsSeqIndices.get(); - memset( arDimsSeqIndices, 0, sizeof( sal_Int32 ) * dimsSeq); - } - - char* psaCurrentData= (char*)pSAData; - - do - { - // Get the Sequence at the current index , see arDimsSeqIndices - uno_Sequence * pCurrentSeq= pMultiSeq; - sal_Int32 curDim=1; // 1 based - sal_Bool skipSeq= sal_False; - while( curDim <= dimsSeq ) - { - // get the Sequence at the index if valid - if( pCurrentSeq->nElements > arDimsSeqIndices[ curDim - 1] ) // don't point to Nirvana - { - // size of Sequence is 4 - sal_Int32 offset= arDimsSeqIndices[ curDim - 1] * 4; - pCurrentSeq= *(uno_Sequence**) &pCurrentSeq->elements[ offset]; - curDim++; - } - else - { - // There is no Sequence at this index, so skip this index - skipSeq= sal_True; - break; - } - } - - if( skipSeq) - continue; - - // Calculate the current position within the datablock of the SAFEARRAY - // for the next Sequence. - sal_Int32 memOffset= 0; - sal_Int32 dimWeight= parElementCount[ dims - 1]; // size of the rightmost dimension - for(sal_Int16 idims=0; idims < dimsSeq; idims++ ) - { - memOffset+= arDimsSeqIndices[dimsSeq - 1 - idims] * dimWeight; - // now determine the weight of the dimension to the left of the current. - if( dims - 2 - idims >=0) - dimWeight*= parElementCount[dims - 2 - idims]; - } - psaCurrentData= (char*)pSAData + memOffset * oleElementSize; - // convert the Sequence and put the elements into the Safearray - for( sal_Int32 i= 0; i < pCurrentSeq->nElements; i++) - { - Any unoElement( pCurrentSeq->elements + i * elementSize, rawTypeDesc ); - // The any is being converted into an VARIANT which value is then copied - // to the SAFEARRAY's data block. When copying one has to follow the rules for - // copying certain types, as are VT_DISPATCH, VT_UNKNOWN, VT_VARIANT, VT_BSTR. - // To increase performance, we just do a memcpy of VARIANT::byref. This is possible - // because anyToVariant has already followed the copying rules. To make this - // work there must not be a VariantClear. - // One Exception is VARIANT because I don't know how VariantCopy works. - - VARIANT var; - VariantInit( &var); - anyToVariant( &var, unoElement); - if( elemtype == VT_VARIANT ) - { - VariantCopy( ( VARIANT*)psaCurrentData, &var); - VariantClear( &var); - } - else - memcpy( psaCurrentData, &var.byref, oleElementSize); - - psaCurrentData+= oleElementSize; - } - } - while( incrementMultidimensionalIndex( dimsSeq, parElementCount, arDimsSeqIndices)); - - SafeArrayUnaccessData( pArray); - } - } - } - return pArray; -} - -// Increments a multi dimensional index. -// Returns true as long as the index has been successfully incremented, false otherwise. -// False is also returned if an overflow of the most significant dimension occurs. E.g. -// assume an array with the dimensions (2,2), then the lowest index is (0,0) and the highest -// index is (1,1). If the function is being called with the index (1,1) then the overflow would -// occur, with the result (0,0) and a sal_False as return value. -// Param dimensions - number of dimensions -// Param parDimensionsLength - The array contains the size of each dimension, that is the -// size of the array equals the parameter dimensions. -// The rightmost dimensions is the least significant one -// ( parDimensionsLengths[ dimensions -1 ] ). -// Param parMultiDimensionalIndex - The array contains the index. Each dimension index is -// 0 based. -template<class T> -sal_Bool UnoConversionUtilities<T>::incrementMultidimensionalIndex(sal_Int32 dimensions, - const sal_Int32 * parDimensionLengths, - sal_Int32 * parMultidimensionalIndex) -{ - if( dimensions < 1) - return sal_False; - - sal_Bool ret= sal_True; - sal_Bool carry= sal_True; // to get into the while loop - - sal_Int32 currentDimension= dimensions; //most significant is 1 - while( carry) - { - parMultidimensionalIndex[ currentDimension - 1]++; - // if carryover, set index to 0 and handle carry on a level above - if( parMultidimensionalIndex[ currentDimension - 1] > (parDimensionLengths[ currentDimension - 1] - 1)) - parMultidimensionalIndex[ currentDimension - 1]= 0; - else - carry= sal_False; - - currentDimension --; - // if dimensions drops below 1 and carry is set than then all indices are 0 again - // this is signalled by returning sal_False - if( currentDimension < 1 && carry) - { - carry= sal_False; - ret= sal_False; - } - } - return ret; -} - -// Determines the size of a certain OLE type. The function takes -// only those types into account which are oleautomation types and -// can have a value ( unless VT_NULL, VT_EMPTY, VT_ARRAY, VT_BYREF). -// Currently used in createUnoSequenceWrapper to calculate addresses -// for data within a SAFEARRAY. -template<class T> -size_t UnoConversionUtilities<T>::getOleElementSize( VARTYPE type) -{ - size_t size; - switch( type) - { - case VT_BOOL: size= sizeof( VARIANT_BOOL);break; - case VT_UI1: size= sizeof( unsigned char);break; - case VT_R8: size= sizeof( double);break; - case VT_R4: size= sizeof( float);break; - case VT_I2: size= sizeof( short);break; - case VT_I4: size= sizeof( long);break; - case VT_BSTR: size= sizeof( BSTR); break; - case VT_ERROR: size= sizeof( SCODE); break; - case VT_DISPATCH: - case VT_UNKNOWN: size= sizeof( IUnknown*); break; - case VT_VARIANT: size= sizeof( VARIANT);break; - default: size= 0; - } - return size; -} - -//If a Sequence is being converted into a SAFEARRAY then we possibly have -// to create a SAFEARRAY with multiple dimensions. This is the case when a -// Sequence contains Sequences ( Sequence< Sequence < XXX > > ). The leftmost -// Sequence in the declaration is assumed to represent dimension 1. Because -// all Sequence elements of a Sequence can have different length, we have to -// determine the maximum length which is then the length of the respective -// dimension. -// getElementCountAndTypeOfSequence determines the length of each dimension and calls itself recursively -// in the process. -// param rSeq - an Any that has to contain a Sequence -// param dim - the dimension for which the number of elements is being determined, -// must be one. -// param seqElementCounts - countains the maximum number of elements for each -// dimension. Index 0 contains the number of dimension one. -// After return the Sequence contains the maximum number of -// elements for each dimension. -// The length of the Sequence must equal the number of dimensions. -// param typeClass - TypeClass of the element type that is no Sequence, e.g. -// Sequence< Sequence <Sequence <sal_Int32> > > - type is sal_Int32) -template<class T> -void UnoConversionUtilities<T>::getElementCountAndTypeOfSequence( const Any& rSeq, sal_Int32 dim, - Sequence< sal_Int32 >& seqElementCounts, TypeDescription& typeDesc) -{ - sal_Int32 dimCount= (*(uno_Sequence* const *) rSeq.getValue())->nElements; - if( dimCount > seqElementCounts[ dim-1]) - seqElementCounts[ dim-1]= dimCount; - - // we need the element type to construct the any that is - // passed into getElementCountAndTypeOfSequence again - typelib_TypeDescription* pSeqDesc= NULL; - rSeq.getValueTypeDescription( &pSeqDesc); - typelib_TypeDescriptionReference* pElementDescRef= ((typelib_IndirectTypeDescription*)pSeqDesc)->pType; - - // if the elements are Sequences than do recursion - if( dim < seqElementCounts.getLength() ) - { - uno_Sequence* pSeq = *(uno_Sequence* const*) rSeq.getValue(); - uno_Sequence** arSequences= (uno_Sequence**)pSeq->elements; - for( sal_Int32 i=0; i < dimCount; i++) - { - uno_Sequence* arElement= arSequences[ i]; - getElementCountAndTypeOfSequence( Any( &arElement, pElementDescRef), dim + 1 , seqElementCounts, typeDesc); - } - } - else - { - // determine the element type ( e.g. Sequence< Sequence <Sequence <sal_Int32> > > - type is sal_Int32) - typeDesc= pElementDescRef; - } - typelib_typedescription_release( pSeqDesc); -} - - -template<class T> -SAFEARRAY* UnoConversionUtilities<T>::createUnoSequenceWrapper(const Any& rSeq) -{ - SAFEARRAY* pArray = NULL; - sal_uInt32 n = 0; - - if( rSeq.getValueTypeClass() != TypeClass_SEQUENCE ) - throw IllegalArgumentException( - OUSTR("[automation bridge]UnoConversionUtilities<T>::createUnoSequenceWrapper\n" - "The UNO argument is not a sequence"), 0, -1); - - uno_Sequence * punoSeq= *(uno_Sequence**) rSeq.getValue(); - - typelib_TypeDescriptionReference* pSeqTypeRef= rSeq.getValueTypeRef(); - typelib_TypeDescription* pSeqType= NULL; - TYPELIB_DANGER_GET( &pSeqType, pSeqTypeRef); - typelib_IndirectTypeDescription * pSeqIndDec= (typelib_IndirectTypeDescription*) pSeqType; - - - typelib_TypeDescriptionReference * pSeqElementTypeRef= pSeqIndDec->pType; - TYPELIB_DANGER_RELEASE( pSeqType); - - typelib_TypeDescription* pSeqElementDesc= NULL; - TYPELIB_DANGER_GET( &pSeqElementDesc, pSeqElementTypeRef); - - // try to find VARIANT type that is related to the UNO type of the sequence elements - // the sequence as a sequence element should be handled in a special way - VARTYPE eTargetElementType = VT_EMPTY; - if ( pSeqElementDesc->eTypeClass != TypeClass_SEQUENCE ) - eTargetElementType = mapTypeClassToVartype( static_cast< TypeClass >( pSeqElementDesc->eTypeClass ) ); - - if ( eTargetElementType != VT_EMPTY ) - pArray = createUnoSequenceWrapper( rSeq, eTargetElementType ); - - if ( !pArray ) - { - sal_Int32 nElementSize= pSeqElementDesc->nSize; - n= punoSeq->nElements; - - SAFEARRAYBOUND rgsabound[1]; - rgsabound[0].lLbound = 0; - rgsabound[0].cElements = n; - VARIANT oleElement; - long safeI[1]; - - pArray = SafeArrayCreate(VT_VARIANT, 1, rgsabound); - - Any unoElement; - // sal_uInt8 * pSeqData= (sal_uInt8*) punoSeq->pElements; - sal_uInt8 * pSeqData= (sal_uInt8*) punoSeq->elements; - - for (sal_uInt32 i = 0; i < n; i++) - { - unoElement.setValue( pSeqData + i * nElementSize, pSeqElementDesc); - VariantInit(&oleElement); - - anyToVariant(&oleElement, unoElement); - - safeI[0] = i; - SafeArrayPutElement(pArray, safeI, &oleElement); - - VariantClear(&oleElement); - } - } - - TYPELIB_DANGER_RELEASE( pSeqElementDesc); - - return pArray; -} - -/* The argument rObj can contain -- UNO struct -- UNO interface -- UNO interface created by this bridge (adapter factory) -- UNO interface created by this bridge ( COM Wrapper) - -pVar must be initialized. -*/ -template<class T> -void UnoConversionUtilities<T>::createUnoObjectWrapper(const Any & rObj, VARIANT * pVar) -{ - MutexGuard guard(getBridgeMutex()); - - Reference<XInterface> xInt; - - TypeClass tc = rObj.getValueTypeClass(); - if (tc != TypeClass_INTERFACE && tc != TypeClass_STRUCT) - throw IllegalArgumentException( - OUSTR("[automation bridge]UnoConversionUtilities<T>::createUnoObjectWrapper \n" - "Cannot create an Automation interface for a UNO type which is not " - "a struct or interface!"), 0, -1); - - if (rObj.getValueTypeClass() == TypeClass_INTERFACE) - { - if (! (rObj >>= xInt)) - throw IllegalArgumentException( - OUSTR("[automation bridge] UnoConversionUtilities<T>::createUnoObjectWrapper\n " - "Could not create wrapper object for UNO object!"), 0, -1); - //If XInterface is NULL, which is a valid value, then simply return NULL. - if ( ! xInt.is()) - { - pVar->vt = VT_UNKNOWN; - pVar->punkVal = NULL; - return; - } - //make sure we have the main XInterface which is used with a map - xInt = Reference<XInterface>(xInt, UNO_QUERY); - //If there is already a wrapper for the UNO object then use it - - Reference<XInterface> xIntWrapper; - // Does a UNO wrapper exist already ? - IT_Uno it_uno = UnoObjToWrapperMap.find( (sal_uInt32) xInt.get()); - if(it_uno != UnoObjToWrapperMap.end()) - { - xIntWrapper = it_uno->second; - if (xIntWrapper.is()) - { - convertSelfToCom(xIntWrapper, pVar); - return; - } - } - // Is the object a COM wrapper ( either XInvocation, or Adapter object) - // or does it suppy an IDispatch by its own ? - else - { - Reference<XInterface> xIntComWrapper = xInt; - typedef boost::unordered_map<sal_uInt32,sal_uInt32>::iterator _IT; - // Adapter? then get the COM wrapper to which the adapter delegates its calls - _IT it= AdapterToWrapperMap.find( (sal_uInt32) xInt.get()); - if( it != AdapterToWrapperMap.end() ) - xIntComWrapper= reinterpret_cast<XInterface*>(it->second); - - if (convertSelfToCom(xIntComWrapper, pVar)) - return; - } - } - // If we have no UNO wrapper nor the IDispatch yet then we have to create - // a wrapper. For that we need an XInvocation from the UNO object. - - // get an XInvocation or create one using the invocation service - Reference<XInvocation> xInv(xInt, UNO_QUERY); - if ( ! xInv.is()) - { - Reference<XSingleServiceFactory> xInvFactory= getInvocationFactory(rObj); - if (xInvFactory.is()) - { - Sequence<Any> params(1); - params.getArray()[0] = rObj; - Reference<XInterface> xInt = xInvFactory->createInstanceWithArguments(params); - xInv= Reference<XInvocation>(xInt, UNO_QUERY); - } - } - - if (xInv.is()) - { - Reference<XInterface> xNewWrapper = createUnoWrapperInstance(); - Reference<XInitialization> xInitWrapper(xNewWrapper, UNO_QUERY); - if (xInitWrapper.is()) - { - VARTYPE vartype= getVarType( rObj); - - if (xInt.is()) - { - Any params[3]; - params[0] <<= xInv; - params[1] <<= xInt; - params[2] <<= vartype; - xInitWrapper->initialize( Sequence<Any>(params, 3)); - } - else - { - Any params[2]; - params[0] <<= xInv; - params[1] <<= vartype; - xInitWrapper->initialize( Sequence<Any>(params, 2)); - } - - // put the newly created object into a map. If the same object will - // be mapped again and there is already a wrapper then the old wrapper - // will be used. - if(xInt.is()) // only interfaces - UnoObjToWrapperMap[(sal_uInt32) xInt.get()]= xNewWrapper; - convertSelfToCom(xNewWrapper, pVar); - return; - } - } -} - -template<class T> -void UnoConversionUtilities<T>::variantToAny( const VARIANT* pVariant, Any& rAny, - sal_Bool bReduceValueRange /* = sal_True */) -{ - HRESULT hr = S_OK; - try - { - CComVariant var; - - // There is no need to support indirect values, since they're not supported by UNO - if( FAILED(hr= VariantCopyInd( &var, const_cast<VARIANTARG*>(pVariant)))) // remove VT_BYREF - throw BridgeRuntimeError( - OUSTR("[automation bridge] UnoConversionUtilities<T>::variantToAny \n" - "VariantCopyInd failed for reason : ") + OUString::valueOf(hr)); - - if ( ! convertValueObject( & var, rAny)) - { - if ((var.vt & VT_ARRAY) > 0) - { - VARTYPE oleTypeFlags = ::sal::static_int_cast< VARTYPE, int >( var.vt ^ VT_ARRAY ); - - Sequence<Any> unoSeq = createOleArrayWrapper(var.parray, oleTypeFlags); - rAny.setValue( &unoSeq, getCppuType( &unoSeq)); - } - else - { - switch (var.vt) - { - case VT_EMPTY: - rAny.setValue(NULL, Type()); - break; - case VT_NULL: - rAny.setValue(NULL, Type()); - break; - case VT_I2: - rAny.setValue( & var.iVal, getCppuType( (sal_Int16*)0)); - break; - case VT_I4: - rAny.setValue( & var.lVal, getCppuType( (sal_Int32*)0)); - // necessary for use in JavaScript ( see "reduceRange") - if( bReduceValueRange) - reduceRange(rAny); - break; - case VT_R4: - rAny.setValue( & var.fltVal, getCppuType( (float*)0)); - break; - case VT_R8: - rAny.setValue(& var.dblVal, getCppuType( (double*)0)); - break; - case VT_CY: - { - Currency cy(var.cyVal.int64); - rAny <<= cy; - break; - } - case VT_DATE: - { - Date d(var.date); - rAny <<= d; - break; - } - case VT_BSTR: - { - OUString b(reinterpret_cast<const sal_Unicode*>(var.bstrVal)); - rAny.setValue( &b, getCppuType( &b)); - break; - } - case VT_UNKNOWN: - case VT_DISPATCH: - { - //check if it is a UNO type -#ifdef __MINGW32__ - CComQIPtr<IUnoTypeWrapper, &__uuidof(IUnoTypeWrapper)> spType((IUnknown*) var.byref); -#else - CComQIPtr<IUnoTypeWrapper> spType((IUnknown*) var.byref); -#endif - if (spType) - { - CComBSTR sName; - if (FAILED(spType->get_Name(&sName))) - throw BridgeRuntimeError( - OUSTR("[automation bridge]UnoConversionUtilities<T>::variantToAny \n" - "Failed to get the type name from a UnoTypeWrapper!")); - Type type; - if (getType(sName, type) == false) - { - throw CannotConvertException( - OUSTR("[automation bridge]UnoConversionUtilities<T>::variantToAny \n" - "A UNO type with the name: ") + OUString(reinterpret_cast<const sal_Unicode*>(LPCOLESTR(sName))) + - OUSTR("does not exist!"), - 0, TypeClass_UNKNOWN, FailReason::TYPE_NOT_SUPPORTED,0); - } - rAny <<= type; - } - else - { - rAny = createOleObjectWrapper( & var); - } - break; - } - case VT_ERROR: - { - SCode scode(var.scode); - rAny <<= scode; - break; - } - case VT_BOOL: - { - sal_Bool b= var.boolVal == VARIANT_TRUE; - rAny.setValue( &b, getCppuType( &b)); - break; - } - case VT_I1: - rAny.setValue( & var.cVal, getCppuType((sal_Int8*)0)); - break; - case VT_UI1: // there is no unsigned char in UNO - rAny.setValue( & var.bVal, getCppuType( (sal_Int8*)0)); - break; - case VT_UI2: - rAny.setValue( & var.uiVal, getCppuType( (sal_uInt16*)0)); - break; - case VT_UI4: - rAny.setValue( & var.ulVal, getCppuType( (sal_uInt32*)0)); - break; - case VT_INT: - rAny.setValue( & var.intVal, getCppuType( (sal_Int32*)0)); - break; - case VT_UINT: - rAny.setValue( & var.uintVal, getCppuType( (sal_uInt32*)0)); - break; - case VT_VOID: - rAny.setValue( NULL, Type()); - break; - case VT_DECIMAL: - { - Decimal dec; - dec.Scale = var.decVal.scale; - dec.Sign = var.decVal.sign; - dec.LowValue = var.decVal.Lo32; - dec.MiddleValue = var.decVal.Mid32; - dec.HighValue = var.decVal.Hi32; - rAny <<= dec; - break; - } - - default: - break; - } - } - } - } - catch (IllegalArgumentException & ) - { - throw; - } - catch (CannotConvertException &) - { - throw; - } - catch (BridgeRuntimeError & ) - { - throw; - } - catch (Exception & e) - { - throw BridgeRuntimeError(OUSTR("[automation bridge] unexpected exception in " - "UnoConversionUtilities<T>::variantToAny ! Message : \n") + - e.Message); - } - catch(...) - { - throw BridgeRuntimeError( - OUSTR("[automation bridge] unexpected exception in " - "UnoConversionUtilities<T>::variantToAny !")); - } - -} -// The function converts an IUnknown* into an UNO interface or struct. The -// IUnknown pointer can constitute different kind of objects: -// 1. a wrapper of an UNO struct (the wrapper was created by this bridge) -// 2. a wrapper of an UNO interface (created by this bridge) -// 3. a dispatch object that implements UNO interfaces -// 4. a dispatch object. - -// If the parameter "aType" has a value then the COM object ( pUnknown) is supposed to -// implement the interface described by "aType". Moreover it ( pUnknown) can implement -// several other -// UNO interfaces in which case it has to support the SUPPORTED_INTERFACES_PROP (see -// #define) property. That property contains all names of interfaces. -// "pUnknown" is wrapped by a COM wrapper object that implements XInvocation, e.g. -// IUnknownWrapper_Impl. Additionally an object of type "aType" is created by help -// of the INTERFACE_ADAPTER_FACTORY (see #define) service. The implementation of -// "aType" calls on the COM wrapper's XInvocation::invoke. If the COM object supports -// more then one UNO interfaces, as can be determined by the property -// SUPPORTED_INTERFACES_PROP, then the INTERFACE_ADAPTER_FACTORY creates an object that -// implements all these interfaces. -// This is only done if "pUnknown" is not already a UNO wrapper, -// that is it is actually NOT an UNO object that was converted to a COM object. If it is an -// UNO wrapper than the original UNO object is being extracted, queried for "aType" (if -// it is no struct) and returned. -template<class T> -#ifdef __MINGW32__ -Any UnoConversionUtilities<T>::createOleObjectWrapper(VARIANT* pVar, const Type& aType) -#else -Any UnoConversionUtilities<T>::createOleObjectWrapper(VARIANT* pVar, const Type& aType= Type()) -#endif -{ - //To allow passing "Nothing" in VS 2008 we need to accept VT_EMPTY - if (pVar->vt != VT_UNKNOWN && pVar->vt != VT_DISPATCH && pVar->vt != VT_EMPTY) - throw IllegalArgumentException( - OUSTR("[automation bridge]UnoConversionUtilities<T>::createOleObjectWrapper \n" - "The VARIANT does not contain an object type! "), 0, -1); - - MutexGuard guard( getBridgeMutex()); - - CComPtr<IUnknown> spUnknown; - CComPtr<IDispatch> spDispatch; - - if (pVar->vt == VT_UNKNOWN) - { - spUnknown = pVar->punkVal; - if (spUnknown) -#ifdef __MINGW32__ - spUnknown->QueryInterface( IID_IDispatch, reinterpret_cast<LPVOID*>( & spDispatch.p)); -#else - spUnknown.QueryInterface( & spDispatch.p); -#endif - } - else if (pVar->vt == VT_DISPATCH && pVar->pdispVal != NULL) - { - CComPtr<IDispatch> spDispatch(pVar->pdispVal); - if (spDispatch) -#ifdef __MINGW32__ - spDispatch->QueryInterface( IID_IUnknown, reinterpret_cast<LPVOID*>( & spUnknown.p)); -#else - spDispatch.QueryInterface( & spUnknown.p); -#endif - } - - static Type VOID_TYPE= Type(); - Any ret; - //If no Type is provided and pVar contains IUnknown then we return a XInterface. - //If pVar contains an IDispatch then we return a XInvocation. - Type desiredType = aType; - - if (aType == VOID_TYPE) - { - switch (pVar->vt) - { - case VT_EMPTY: - case VT_UNKNOWN: - desiredType = getCppuType((Reference<XInterface>*) 0); - break; - case VT_DISPATCH: - desiredType = getCppuType((Reference<XInvocation>*) 0); - break; - default: - desiredType = aType; - } - } - - // COM pointer are NULL, no wrapper required - if (spUnknown == NULL) - { - Reference<XInterface> xInt; - if( aType.getTypeClass() == TypeClass_INTERFACE) - ret.setValue( &xInt, aType); - else if( aType.getTypeClass() == TypeClass_STRUCT) - ret.setValue( NULL, aType); - else - ret <<= xInt; - return ret; - } - - - // Check if "spUnknown" is a UNO wrapper, that is an UNO object that has been - // passed to COM. Then it supports IUnoObjectWrapper - // and we extract the original UNO object. -#ifdef __MINGW32__ - CComQIPtr<IUnoObjectWrapper, &__uuidof(IUnoObjectWrapper)> spUno( spUnknown); -#else - CComQIPtr<IUnoObjectWrapper> spUno( spUnknown); -#endif - if( spUno) - { // it is a wrapper - Reference<XInterface> xInt; - if( SUCCEEDED( spUno->getOriginalUnoObject( &xInt))) - { - ret <<= xInt; - } - else - { - Any any; - if( SUCCEEDED( spUno->getOriginalUnoStruct(&any))) - ret= any; - } - return ret; - } - - // "spUnknown" is a real COM object. - // Before we create a new wrapper object we check if there is an existing wrapper - // There can be two kinds of wrappers, those who wrap dispatch - UNO objects, and those who - // wrap ordinary dispatch objects. The dispatch-UNO objects usually are adapted to represent - // particular UNO interfaces. - Reference<XInterface> xIntWrapper; - CIT_Com cit_currWrapper= ComPtrToWrapperMap.find( reinterpret_cast<sal_uInt32>(spUnknown.p)); - if(cit_currWrapper != ComPtrToWrapperMap.end()) - xIntWrapper = cit_currWrapper->second; - if (xIntWrapper.is()) - { - //Try to find an adapter for the wrapper - //find the proper Adapter. The pointer in the WrapperToAdapterMap are valid as long as - //we get a pointer to the wrapper from ComPtrToWrapperMap, because the Adapter hold references - //to the wrapper. - CIT_Wrap it = WrapperToAdapterMap.find((sal_uInt32) xIntWrapper.get()); - if (it == WrapperToAdapterMap.end()) - { - // No adapter available. - //The COM component could be a UNO object. Then we need to provide - // a proxy that implements all interfaces - Sequence<Type> seqTypes= getImplementedInterfaces(spUnknown); - Reference<XInterface> xIntAdapter; - if (seqTypes.getLength() > 0) - { - //It is a COM UNO object - xIntAdapter = createAdapter(seqTypes, xIntWrapper); - } - else - { - // Some ordinary COM object - xIntAdapter = xIntWrapper; - } - // return the wrapper directly, return XInterface or XInvocation - ret = xIntWrapper->queryInterface(desiredType); - if ( ! ret.hasValue()) - throw IllegalArgumentException( - OUSTR("[automation bridge]UnoConversionUtilities<T>::createOleObjectWrapper \n" - "The COM object is not suitable for the UNO type: ") + - desiredType.getTypeName(), 0, -1); - } - else - { - //There is an adapter available - Reference<XInterface> xIntAdapter((XInterface*) it->second); - ret = xIntAdapter->queryInterface( desiredType); - if ( ! ret.hasValue()) - throw IllegalArgumentException( - OUSTR("[automation bridge]UnoConversionUtilities<T>::createOleObjectWrapper \n" - "The COM object is not suitable for the UNO type: ") + - desiredType.getTypeName(), 0, -1); - } - - return ret; - } - // No existing wrapper. Therefore create a new proxy. - // If the object implements UNO interfaces then get the types. - Sequence<Type> seqTypes = getImplementedInterfaces(spUnknown); - if (seqTypes.getLength() == 0 && - aType != VOID_TYPE && aType != getCppuType((Reference<XInvocation>*)0)) - { - seqTypes = Sequence<Type>( & aType, 1); - } - - //There is no existing wrapper, therefore we create one for the real COM object - Reference<XInterface> xIntNewProxy= createComWrapperInstance(); - if ( ! xIntNewProxy.is()) - throw BridgeRuntimeError( - OUSTR("[automation bridge]UnoConversionUtilities<T>::createOleObjectWrapper \n" - "Could not create proxy object for COM object!")); - - // initialize the COM wrapper - Reference<XInitialization> xInit( xIntNewProxy, UNO_QUERY); - OSL_ASSERT( xInit.is()); - - Any params[3]; -#ifdef __MINGW32__ - params[0] <<= reinterpret_cast<sal_uInt32>( spUnknown.p ); -#else - params[0] <<= (sal_uInt32) spUnknown.p; -#endif - sal_Bool bDisp = pVar->vt == VT_DISPATCH ? sal_True : sal_False; - params[1].setValue( & bDisp, getBooleanCppuType()); - params[2] <<= seqTypes; - - xInit->initialize( Sequence<Any>( params, 3)); -#ifdef __MINGW32__ - ComPtrToWrapperMap[reinterpret_cast<sal_uInt32>( spUnknown.p )]= xIntNewProxy; -#else - ComPtrToWrapperMap[reinterpret_cast<sal_uInt32>(spUnknown.p)]= xIntNewProxy; -#endif - - // we have a wrapper object - //The wrapper implements already XInvocation and XInterface. If - //param aType is void then the object is supposed to have XInvocation. - if (aType == getCppuType((Reference<XInvocation>*)0) || - (aType == VOID_TYPE && seqTypes.getLength() == 0 )) - { - ret = xIntNewProxy->queryInterface(desiredType); - } - else - { - Reference<XInterface> xIntAdapter = - createAdapter(seqTypes, xIntNewProxy); - ret = xIntAdapter->queryInterface(desiredType); - } - return ret; -} -template<class T> -Reference<XInterface> UnoConversionUtilities<T>::createAdapter(const Sequence<Type>& seqTypes, - const Reference<XInterface>& receiver) -{ - Reference< XInterface> xIntAdapterFac; - xIntAdapterFac= m_smgr->createInstance(INTERFACE_ADAPTER_FACTORY); - // We create an adapter object that does not only implement the required type but also - // all types that the COM object pretends to implement. An COM object must therefore - // support the property "_implementedInterfaces". - Reference<XInterface> xIntAdapted; - Reference<XInvocation> xInv(receiver, UNO_QUERY); - Reference<XInvocationAdapterFactory2> xAdapterFac( xIntAdapterFac, UNO_QUERY); - if( xAdapterFac.is()) - xIntAdapted= xAdapterFac->createAdapter( xInv, seqTypes); - - if( xIntAdapted.is()) - { - // Put the pointer to the wrapper object and the interface pointer of the adapted interface - // in a global map. Thus we can determine in a call to createUnoObjectWrapper whether the UNO - // object is a wrapped COM object. In that case we extract the original COM object rather than - // creating a wrapper around the UNO object. - typedef boost::unordered_map<sal_uInt32,sal_uInt32>::value_type VALUE; - AdapterToWrapperMap.insert( VALUE( (sal_uInt32) xIntAdapted.get(), (sal_uInt32) receiver.get())); - WrapperToAdapterMap.insert( VALUE( (sal_uInt32) receiver.get(), (sal_uInt32) xIntAdapted.get())); - } - else - { - throw BridgeRuntimeError( - OUSTR("[automation bridge]UnoConversionUtilities<T>::createOleObjectWrapper \n" - "Could not create a proxy for COM object! Creation of adapter failed.")); - } - return xIntAdapted; -} -// "convertValueObject" converts a JScriptValue object contained in "var" into -// an any. The type contained in the any is stipulated by a "type value" thas -// was set within the JScript script on the value object ( see JScriptValue). -template<class T> -bool UnoConversionUtilities<T>::convertValueObject( const VARIANTARG *var, Any& any) -{ - bool ret = false; - try - { - bool bFail = false; - HRESULT hr= S_OK; - CComVariant varDisp; - - if(SUCCEEDED(hr = varDisp.ChangeType( VT_DISPATCH, var))) - { - CComPtr <IJScriptValueObject> spValue; - VARIANT_BOOL varBool; - CComBSTR bstrType; - CComVariant varValue; - CComPtr<IDispatch> spDisp( varDisp.pdispVal); - if(spDisp) - { - if(SUCCEEDED( spDisp->QueryInterface( __uuidof( IJScriptValueObject), - reinterpret_cast<void**> (&spValue)))) - { - ret = true; // is is a ValueObject - //If it is an out - param then it does not need to be converted. In/out and - // in params does so. - if (SUCCEEDED(hr= spValue->IsOutParam( &varBool))) - { - // if varBool == true then no conversion needed because out param - if (varBool == VARIANT_FALSE) - { - if(SUCCEEDED(hr = spValue->GetValue( & bstrType, & varValue))) - { - Type type; - if (getType(bstrType, type)) - variantToAny( & varValue, any, type); - else - bFail = true; - } - else - bFail = true; - } - } - else - bFail = true;; - } - } - } - else if( hr != DISP_E_TYPEMISMATCH && hr != E_NOINTERFACE) - bFail = true; - - if (bFail) - throw BridgeRuntimeError( - OUSTR("[automation bridge] Conversion of ValueObject failed ")); - } - catch (BridgeRuntimeError &) - { - throw; - } - catch (Exception & e) - { - throw BridgeRuntimeError(OUSTR("[automation bridge] unexpected exception in " - "UnoConversionUtilities<T>::convertValueObject ! Message : \n") + - e.Message); - } - catch(...) - { - throw BridgeRuntimeError( - OUSTR("[automation bridge] unexpected exception in " - "UnoConversionUtilities<T>::convertValueObject !")); - } - return ret; -} - -template<class T> -void UnoConversionUtilities<T>::dispatchExObject2Sequence( const VARIANTARG* pvar, Any& anySeq, const Type& type) -{ - try - { - bool bFail = false; - if( pvar->vt != VT_DISPATCH) - throw BridgeRuntimeError(OUSTR("[automation bridge] UnoConversionUtilities<T>::dispatchExObject2Sequence \n" - "Conversion of dispatch object to Sequence failed!")); - IDispatchEx* pdispEx; - HRESULT hr; - if( FAILED( hr= pvar->pdispVal->QueryInterface( IID_IDispatchEx, - reinterpret_cast<void**>( &pdispEx)))) - throw BridgeRuntimeError(OUSTR("[automation bridge] UnoConversionUtilities<T>::dispatchExObject2Sequence \n" - "Conversion of dispatch object to Sequence failed!")); - - DISPID dispid; - OUString sindex; - DISPPARAMS param= {0,0,0,0}; - CComVariant result; - - OLECHAR* sLength= L"length"; - - // Get the length of the array. Can also be obtained throu GetNextDispID. The - // method only returns DISPIDs of the array data. Their names are like "0", "1" etc. - if( FAILED( hr= pdispEx->GetIDsOfNames(IID_NULL, &sLength , 1, LOCALE_USER_DEFAULT, &dispid))) - throw BridgeRuntimeError(OUSTR("[automation bridge] UnoConversionUtilities<T>::dispatchExObject2Sequence \n" - "Conversion of dispatch object to Sequence failed!")); - if( FAILED( hr= pdispEx->InvokeEx(dispid, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET, - ¶m, &result, NULL, NULL))) - throw BridgeRuntimeError(OUSTR("[automation bridge] UnoConversionUtilities<T>::dispatchExObject2Sequence \n" - "Conversion of dispatch object to Sequence failed!")); - if( FAILED( VariantChangeType( &result, &result, 0, VT_I4))) - throw BridgeRuntimeError(OUSTR("[automation bridge] UnoConversionUtilities<T>::dispatchExObject2Sequence \n" - "Conversion of dispatch object to Sequence failed!")); - long length= result.lVal; - - result.Clear(); - - // get a few basic facts about the sequence, and reallocate: - // create the Sequences - // get the size of the elements - typelib_TypeDescription *pDesc= NULL; - type.getDescription( &pDesc); - - typelib_IndirectTypeDescription *pSeqDesc= reinterpret_cast<typelib_IndirectTypeDescription*>(pDesc); - typelib_TypeDescriptionReference *pSeqElemDescRef= pSeqDesc->pType; // type of the Sequence' elements - Type elemType( pSeqElemDescRef); - _typelib_TypeDescription* pSeqElemDesc=NULL; - TYPELIB_DANGER_GET( &pSeqElemDesc, pSeqElemDescRef) - sal_uInt32 nelementSize= pSeqElemDesc->nSize; - TYPELIB_DANGER_RELEASE( pSeqElemDesc) - - uno_Sequence *p_uno_Seq; - uno_sequence_construct( &p_uno_Seq, pDesc, NULL, length, cpp_acquire); - - typelib_TypeClass typeElement= pSeqDesc->pType->eTypeClass; - char *pArray= p_uno_Seq->elements; - - // Get All properties in the object, convert their values to the expected type and - // put them into the passed in sequence - for( sal_Int32 i= 0; i< length; i++) - { - OUString ousIndex=OUString::valueOf( i); - OLECHAR* sindex = (OLECHAR*)ousIndex.getStr(); - - if( FAILED( hr= pdispEx->GetIDsOfNames(IID_NULL, &sindex , 1, LOCALE_USER_DEFAULT, &dispid))) - { - throw BridgeRuntimeError(OUSTR("[automation bridge] UnoConversionUtilities<T>::dispatchExObject2Sequence \n" - "Conversion of dispatch object to Sequence failed!")); - } - if( FAILED( hr= pdispEx->InvokeEx(dispid, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET, - ¶m, &result, NULL, NULL))) - { - throw BridgeRuntimeError(OUSTR("[automation bridge] UnoConversionUtilities<T>::dispatchExObject2Sequence \n" - "Conversion of dispatch object to Sequence failed!")); - } - - // If the result is VT_DISPATCH than the Sequence's element type could be Sequence - // Look that up in the CoreReflection to make clear. - // That requires a recursiv conversion - Any any; - // Destination address within the out-Sequence "anySeq" where to copy the next converted element - void* pDest= (void*)(pArray + (i * nelementSize)); - - if( result.vt & VT_DISPATCH && typeElement == typelib_TypeClass_SEQUENCE) - { - variantToAny( &result, any, elemType, sal_False); - // copy the converted VARIANT, that is a Sequence to the Sequence - uno_Sequence * p_unoSeq= *(uno_Sequence**)any.getValue(); - // just copy the pointer of the uno_Sequence - // nelementSize should be 4 !!!! - memcpy( pDest, &p_unoSeq, nelementSize); - osl_incrementInterlockedCount( &p_unoSeq->nRefCount); - } - else // Element type is no Sequence -> do one conversion - { - variantToAny( &result, any, elemType, sal_False); - if( typeElement == typelib_TypeClass_ANY) - { - // copy the converted VARIANT to the Sequence - uno_type_assignData( pDest, pSeqElemDescRef , &any, pSeqElemDescRef,cpp_queryInterface, - cpp_acquire, cpp_release); - } - else - { - // type after conversion must be the element type of the sequence - OSL_ENSURE( (any.getValueTypeClass() == typeElement), "wrong conversion"); - uno_type_assignData( pDest, pSeqElemDescRef,const_cast<void*>( any.getValue()), any.getValueTypeRef(), - cpp_queryInterface, cpp_acquire, cpp_release); - } - } - } // else - result.Clear(); - anySeq.setValue( &p_uno_Seq, pDesc); - uno_destructData( &p_uno_Seq, pDesc, cpp_release); - typelib_typedescription_release( pDesc); - - if (bFail) - throw BridgeRuntimeError( - OUSTR("[automation bridge] Conversion of ValueObject failed ")); - } - catch (BridgeRuntimeError & ) - { - throw; - } - catch (Exception & e) - { - throw BridgeRuntimeError(OUSTR("[automation bridge] unexpected exception in " - "UnoConversionUtilities<T>::convertValueObject ! Message : \n") + - e.Message); - } - catch(...) - { - throw BridgeRuntimeError( - OUSTR("[automation bridge] unexpected exception in " - "UnoConversionUtilities<T>::convertValueObject !")); - } -} - -/* The argument unotype is the type that is expected by the currently called UNO function. - For example: []long, [][]long. If the function calls itself recursively then the element type - is passed on. For example a two dimensional SAFEARRAY of type VT_I4 is to be converted. Then - unotype has to be either void or [][]long. When the function calls itself recursivly then - it passes the element type which is []long. -*/ -template<class T> -Sequence<Any> UnoConversionUtilities<T>::createOleArrayWrapperOfDim(SAFEARRAY* pArray, - unsigned int dimCount, unsigned int actDim, long* index, VARTYPE type, const Type& unotype) -{ - HRESULT hr= S_OK; - long lBound; - long uBound; - long nCountElements; - - SafeArrayGetLBound(pArray, actDim, &lBound); - SafeArrayGetUBound(pArray, actDim, &uBound); - nCountElements= uBound - lBound +1; - - Sequence<Any> anySeq(nCountElements); - Any* pUnoArray = anySeq.getArray(); - - for (index[actDim - 1] = lBound; index[actDim - 1] <= uBound; index[actDim - 1]++) - { - if (actDim > 1 ) - { - Sequence<Any> element = createOleArrayWrapperOfDim(pArray, dimCount, - actDim - 1, index, type, getElementTypeOfSequence(unotype)); - - pUnoArray[index[actDim - 1] - lBound].setValue(&element, getCppuType(&element)); - } - else - { - VARIANT variant; - - VariantInit(&variant); - - V_VT(&variant) = type; - - switch (type) - { - case VT_I2: - SafeArrayGetElement(pArray, index, &V_I2(&variant)); - break; - case VT_I4: - SafeArrayGetElement(pArray, index, &V_I4(&variant)); - break; - case VT_R4: - SafeArrayGetElement(pArray, index, &V_R4(&variant)); - break; - case VT_R8: - SafeArrayGetElement(pArray, index, &V_R8(&variant)); - break; - case VT_CY: - SafeArrayGetElement(pArray, index, &V_CY(&variant)); - break; - case VT_DATE: - SafeArrayGetElement(pArray, index, &V_DATE(&variant)); - break; - case VT_BSTR: - hr= SafeArrayGetElement(pArray, index, &V_BSTR(&variant)); - break; - case VT_DISPATCH: - SafeArrayGetElement(pArray, index, &V_DISPATCH(&variant)); - break; - case VT_ERROR: - SafeArrayGetElement(pArray, index, &V_ERROR(&variant)); - break; - case VT_BOOL: - SafeArrayGetElement(pArray, index, &V_BOOL(&variant)); - break; - case VT_VARIANT: - SafeArrayGetElement(pArray, index, &variant); - break; - case VT_UNKNOWN: - SafeArrayGetElement(pArray, index, &V_UNKNOWN(&variant)); - break; - case VT_I1: - SafeArrayGetElement(pArray, index, &V_I1(&variant)); - break; - case VT_UI1: - SafeArrayGetElement(pArray, index, &V_UI1(&variant)); - break; - case VT_UI2: - SafeArrayGetElement(pArray, index, &V_UI2(&variant)); - break; - case VT_UI4: - SafeArrayGetElement(pArray, index, &V_UI4(&variant)); - break; - default: - break; - } - - if( unotype.getTypeClass() == TypeClass_VOID) - // the function was called without specifying the destination type - variantToAny(&variant, pUnoArray[index[actDim - 1] - lBound], sal_False); - else - variantToAny(&variant, pUnoArray[index[actDim - 1] - lBound], - getElementTypeOfSequence(unotype), sal_False); - - VariantClear(&variant); - } - } - return anySeq; -} - -template<class T> -Type UnoConversionUtilities<T>::getElementTypeOfSequence( const Type& seqType) -{ - Type retValue; - if( seqType.getTypeClass() != TypeClass_VOID) - { - OSL_ASSERT( seqType.getTypeClass() == TypeClass_SEQUENCE); - typelib_IndirectTypeDescription* pDescSeq= NULL; - seqType.getDescription((typelib_TypeDescription** ) & pDescSeq); - retValue = Type(pDescSeq->pType); - typelib_typedescription_release( (typelib_TypeDescription*) pDescSeq); - } - return retValue; -} -template<class T> -Sequence<Any> UnoConversionUtilities<T>::createOleArrayWrapper(SAFEARRAY* pArray, VARTYPE type, const Type& unoType) -{ - sal_uInt32 dim = SafeArrayGetDim(pArray); - - Sequence<Any> ret; - - if (dim > 0) - { - scoped_array<long> sarIndex(new long[dim]); - long * index = sarIndex.get(); - - for (unsigned int i = 0; i < dim; i++) - { - index[i] = 0; - } - - ret = createOleArrayWrapperOfDim(pArray, dim, dim, index, type, unoType); - } - - return ret; -} - -// If an VARIANT has the type VT_DISPATCH it can either be an JScript Array -// or some other object. This function finds out if it is such an array or -// not. Currently there's no way to make sure it's an array -// so we assume that when the object has a property "0" then it is an Array. -// An JScript has property like "0", "1", "2" etc. which represent the -// value at the corresponding index of the array -template<class T> -sal_Bool UnoConversionUtilities<T>::isJScriptArray(const VARIANT* rvar) -{ - OSL_ENSURE( rvar->vt == VT_DISPATCH, "param is not a VT_DISPATCH"); - HRESULT hr; - OLECHAR* sindex= L"0"; - DISPID id; - if ( rvar->vt == VT_DISPATCH && rvar->pdispVal ) - { - hr= rvar->pdispVal->GetIDsOfNames( IID_NULL, &sindex, 1, - LOCALE_USER_DEFAULT, &id); - - if( SUCCEEDED ( hr) ) - return sal_True; - } - - return sal_False; -} - -template<class T> -VARTYPE UnoConversionUtilities<T>::mapTypeClassToVartype( TypeClass type) -{ - VARTYPE ret; - switch( type) - { - case TypeClass_INTERFACE: ret= VT_DISPATCH; - break; - case TypeClass_STRUCT: ret= VT_DISPATCH; - break; - case TypeClass_ENUM: ret= VT_I4; - break; - case TypeClass_SEQUENCE: ret= VT_ARRAY; - break; - case TypeClass_ANY: ret= VT_VARIANT; - break; - case TypeClass_BOOLEAN: ret= VT_BOOL; - break; - case TypeClass_CHAR: ret= VT_I2; - break; - case TypeClass_STRING: ret= VT_BSTR; - break; - case TypeClass_FLOAT: ret= VT_R4; - break; - case TypeClass_DOUBLE: ret= VT_R8; - break; - case TypeClass_BYTE: ret= VT_UI1; - break; - case TypeClass_SHORT: ret= VT_I2; - break; - case TypeClass_LONG: ret= VT_I4; - break; - case TypeClass_UNSIGNED_SHORT: ret= VT_UI2; - break; - case TypeClass_UNSIGNED_LONG: ret= VT_UI4; - break; - default: - ret= VT_EMPTY; - } - return ret; -} - -template<class T> -Sequence<Type> UnoConversionUtilities<T>::getImplementedInterfaces(IUnknown* pUnk) -{ - Sequence<Type> seqTypes; - CComDispatchDriver disp( pUnk); - if( disp) - { - CComVariant var; - HRESULT hr= S_OK; - // There are two different property names possible. - if( FAILED( hr= disp.GetPropertyByName( SUPPORTED_INTERFACES_PROP, &var))) - { - hr= disp.GetPropertyByName( SUPPORTED_INTERFACES_PROP2, &var); - } - if (SUCCEEDED( hr)) - { - // we exspect an array( SafeArray or IDispatch) of Strings. - Any anyNames; - variantToAny( &var, anyNames, getCppuType( (Sequence<Any>*) 0)); - Sequence<Any> seqAny; - if( anyNames >>= seqAny) - { - seqTypes.realloc( seqAny.getLength()); - for( sal_Int32 i=0; i < seqAny.getLength(); i++) - { - OUString typeName; - seqAny[i] >>= typeName; - seqTypes[i]= Type( TypeClass_INTERFACE, typeName); - } - } - } - } - return seqTypes; -} -template<class T> -Reference<XTypeConverter> UnoConversionUtilities<T>::getTypeConverter() -{ - if ( ! m_typeConverter.is()) - { - MutexGuard guard(getBridgeMutex()); - if ( ! m_typeConverter.is()) - { - Reference<XInterface> xIntConverter = - m_smgr->createInstance(OUSTR("com.sun.star.script.Converter")); - if (xIntConverter.is()) - m_typeConverter = Reference<XTypeConverter>(xIntConverter, UNO_QUERY); - } - } - return m_typeConverter; -} - -// This function tries to the change the type of a value (contained in the Any) -// to the smallest possible that can hold the value. This is actually done only -// for types of VT_I4 (see o2u_variantToAny). The reason is the following: -// JavaScript passes integer values always as VT_I4. If there is a parameter or -// property of type any then the bridge converts the any's content according -// to "o2u_variantToAny". Because the VARTYPE is VT_I4 the value would be converted -// to TypeClass_LONG. Say the method XPropertySet::setPropertyValue( string name, any value) -// would be called on an object and the property actually is of TypeClass_SHORT. -// After conversion of the VARIANT parameter the Any would contain type -// TypeClass_LONG. Because the corereflection does not cast from long to short -// the "setPropertValue" would fail as the value has not the right type. - -// The corereflection does convert small integer types to bigger types. -// Therefore we can reduce the type if possible and avoid the above mentioned -// problem. - -// The function is not used when elements are to be converted for Sequences. - -#ifndef _REDUCE_RANGE -#define _REDUCE_RANGE -inline void reduceRange( Any& any) -{ - OSL_ASSERT( any.getValueTypeClass() == TypeClass_LONG); - - sal_Int32 value= *(sal_Int32*)any.getValue(); - if( value <= 0x7f && value >= -0x80) - {// -128 bis 127 - sal_Int8 charVal= static_cast<sal_Int8>( value); - any.setValue( &charVal, getCppuType( (sal_Int8*)0)); - } - else if( value <= 0x7fff && value >= -0x8000) - {// -32768 bis 32767 - sal_Int16 shortVal= static_cast<sal_Int16>( value); - any.setValue( &shortVal, getCppuType( (sal_Int16*)0)); - } -} -#endif - - - -} // end namespace -#endif - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |