1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
22 #include <com/sun/star/script/CannotConvertException.hpp>
23 #include <com/sun/star/script/XInvocationAdapterFactory.hpp>
24 #include <com/sun/star/script/XInvocationAdapterFactory2.hpp>
25 #include <com/sun/star/script/XTypeConverter.hpp>
26 #include <com/sun/star/script/FailReason.hpp>
27 #include <com/sun/star/bridge/ModelDependent.hpp>
28 #include <com/sun/star/bridge/XBridgeSupplier2.hpp>
29 #include <com/sun/star/bridge/oleautomation/Date.hpp>
30 #include <com/sun/star/bridge/oleautomation/Currency.hpp>
31 #include <com/sun/star/bridge/oleautomation/SCode.hpp>
32 #include <com/sun/star/bridge/oleautomation/Decimal.hpp>
33 #include <com/sun/star/lang/XInitialization.hpp>
34 #include <typelib/typedescription.hxx>
35 #include <o3tl/any.hxx>
36 #include <o3tl/char16_t2wchar_t.hxx>
37 #include "ole2uno.hxx"
38 #include <cppuhelper/weakref.hxx>
39 #include <systools/win32/oleauto.hxx>
41 #include "unotypewrapper.hxx"
42 #include <unordered_map>
44 // for some reason DECIMAL_NEG (wtypes.h) which contains BYTE is not resolved.
45 typedef unsigned char BYTE
;
46 // classes for wrapping uno objects
47 #define INTERFACE_OLE_WRAPPER_IMPL 1
48 #define UNO_OBJECT_WRAPPER_REMOTE_OPT 2
50 #define INVOCATION_SERVICE "com.sun.star.script.Invocation"
53 // classes for wrapping ole objects
54 #define IUNKNOWN_WRAPPER_IMPL 1
56 #define INTERFACE_ADAPTER_FACTORY "com.sun.star.script.InvocationAdapterFactory"
57 // COM or JScript objects implementing UNO interfaces have to implement this property
58 #define SUPPORTED_INTERFACES_PROP L"_implementedInterfaces"
59 // Second property without leading underscore for use in VB
60 #define SUPPORTED_INTERFACES_PROP2 L"Bridge_ImplementedInterfaces"
62 using namespace com::sun::star::script
;
63 using namespace com::sun::star::beans
;
64 using namespace com::sun::star::uno
;
65 using namespace com::sun::star::bridge::oleautomation
;
67 extern std::unordered_map
<sal_uIntPtr
, sal_uIntPtr
> AdapterToWrapperMap
;
68 extern std::unordered_map
<sal_uIntPtr
, sal_uIntPtr
> WrapperToAdapterMap
;
70 //Maps IUnknown pointers to a weak reference of the respective wrapper class (e.g.
71 // IUnknownWrapperImpl. It is the responsibility of the wrapper to remove the entry when
72 // it is being destroyed.
73 // Used to ensure that an Automation object is always mapped to the same UNO objects.
74 extern std::unordered_map
<sal_uIntPtr
, WeakReference
<XInterface
> > ComPtrToWrapperMap
;
76 // Maps XInterface pointers to a weak reference of its wrapper class (i.e.
77 // InterfaceOleWrapper). It is the responsibility of the wrapper to remove the entry when
78 // it is being destroyed. It is used to ensure the identity of objects. That is, a UNO interface
79 // is mapped to IDispatch which is kept alive in the COM environment. If the same
80 // UNO interface is mapped again to COM then the IDispach of the first mapped instance
82 extern std::unordered_map
<sal_uIntPtr
, WeakReference
<XInterface
> > UnoObjToWrapperMap
;
84 // This function tries to the change the type of a value (contained in the Any)
85 // to the smallest possible that can hold the value. This is actually done only
86 // for types of VT_I4 (see o2u_variantToAny). The reason is the following:
87 // JavaScript passes integer values always as VT_I4. If there is a parameter or
88 // property of type any then the bridge converts the any's content according
89 // to "o2u_variantToAny". Because the VARTYPE is VT_I4 the value would be converted
90 // to TypeClass_LONG. Say the method XPropertySet::setPropertyValue( string name, any value)
91 // would be called on an object and the property actually is of TypeClass_SHORT.
92 // After conversion of the VARIANT parameter the Any would contain type
93 // TypeClass_LONG. Because the corereflection does not cast from long to short
94 // the "setPropertValue" would fail as the value has not the right type.
96 // The corereflection does convert small integer types to bigger types.
97 // Therefore we can reduce the type if possible and avoid the above mentioned
100 // The function is not used when elements are to be converted for Sequences.
102 inline void reduceRange( Any
& any
)
104 OSL_ASSERT( any
.getValueTypeClass() == TypeClass_LONG
);
106 sal_Int32 value
= *o3tl::doAccess
<sal_Int32
>(any
);
107 if( value
<= 0x7f && value
>= -0x80)
109 sal_Int8 charVal
= static_cast<sal_Int8
>( value
);
110 any
.setValue( &charVal
, cppu::UnoType
<sal_Int8
>::get());
112 else if( value
<= 0x7fff && value
>= -0x8000)
114 sal_Int16 shortVal
= static_cast<sal_Int16
>( value
);
115 any
.setValue( &shortVal
, cppu::UnoType
<sal_Int16
>::get());
119 // createUnoObjectWrapper gets a wrapper instance by calling createUnoWrapperInstance
120 // and initializes it via XInitialization. The wrapper object is required to implement
121 // XBridgeSupplier so that it can convert itself to IDispatch.
122 // class T: Deriving class ( must implement XInterface )
123 /** All methods are allowed to throw at least a BridgeRuntimeError.
126 class UnoConversionUtilities
129 explicit UnoConversionUtilities( const Reference
<XMultiServiceFactory
> & smgr
):
130 m_nUnoWrapperClass( INTERFACE_OLE_WRAPPER_IMPL
),
131 m_nComWrapperClass( IUNKNOWN_WRAPPER_IMPL
),
135 UnoConversionUtilities( const Reference
<XMultiServiceFactory
> & xFactory
, sal_uInt8 unoWrapperClass
, sal_uInt8 comWrapperClass
)
136 : m_nUnoWrapperClass(unoWrapperClass
),
137 m_nComWrapperClass(comWrapperClass
), m_smgr(xFactory
)
140 virtual ~UnoConversionUtilities() {}
141 /** converts only into oleautomation types, that is there is no VT_I1, VT_UI2, VT_UI4
142 a sal_Unicode character is converted into a BSTR.
143 @exception com.sun.star.lang.IllegalArgumentException
144 If the any was inappropriate for conversion.
145 @exception com.sun.star.script.CannotConvertException
146 The any contains a type class for which no conversion is provided.
148 void anyToVariant(VARIANT
* pVariant
, const Any
& rAny
);
149 void anyToVariant(VARIANT
* pVariant
, const Any
& rAny
, VARTYPE type
);
151 /** @exception com.sun.star.lang.IllegalArgumentException
152 If rSeq does not contain a sequence then the exception is thrown.
154 SAFEARRAY
* createUnoSequenceWrapper(const Any
& rSeq
);
155 /** @exception com.sun.star.lang.IllegalArgumentException
156 If rSeq does not contain a sequence or elemtype has no proper value
157 then the exception is thrown.
159 SAFEARRAY
* createUnoSequenceWrapper(const Any
& rSeq
, VARTYPE elemtype
);
161 @exception com.sun.star.lang.IllegalArgumentException
162 If rObj does not contain a struct or interface
164 void createUnoObjectWrapper(const Any
& rObj
, VARIANT
* pVar
);
165 /** @exception CannotConvertException
166 Thrown if the VARIANT contains a type that cannot be coerced in the expected Any.
168 @IllegalArgumentException
169 Thrown if the VARIANT is inappropriate for conversion. ArgumentPosition is -1,
171 void variantToAny(const VARIANT
* pVariant
, Any
& rAny
, bool bReduceValueRange
= true);
172 /** This method converts variants arguments in calls from COM -> UNO. Only then
173 the expected UNO type is known.
174 @exception CannotConvertException
175 Thrown if the VARIANT contains a type that cannot be coerced in the expected Any.
177 @IllegalArgumentException
178 Thrown if the VARIANT is inappropriate for conversion. ArgumentPosition is -1,
180 void variantToAny( const VARIANTARG
* pArg
, Any
& rAny
, const Type
& ptype
, bool bReduceValueRange
= true);
183 @exception IllegalArgumentException
184 -if pVar does not contain VT_UNKNOWN or VT_DISPATCH or
185 pVar is used for a particular UNO type which is not supported by pVar
187 Any
createOleObjectWrapper(VARIANT
* pVar
, const Type
& aType
= Type());
190 Return true means var contained a ValueObject, and it was successfully converted.
191 The result is in any. It an error occurred a BridgeRuntimeError will be thrown.
193 bool convertValueObject( const VARIANTARG
*var
, Any
& any
);
194 void dispatchExObject2Sequence( const VARIANTARG
* pvar
, Any
& anySeq
, const Type
& type
);
196 Sequence
<Any
> createOleArrayWrapperOfDim(SAFEARRAY
* pArray
, unsigned int dimCount
, unsigned int actDim
, LONG
* index
,
197 VARTYPE type
, const Type
& unotype
);
198 Sequence
<Any
> createOleArrayWrapper(SAFEARRAY
* pArray
, VARTYPE type
, const Type
& unotype
= Type());
201 VARTYPE
mapTypeClassToVartype( TypeClass type
);
202 Reference
< XSingleServiceFactory
> getInvocationFactory(const Any
& anyObject
);
205 virtual Reference
< XInterface
> createUnoWrapperInstance()=0;
206 virtual Reference
< XInterface
> createComWrapperInstance()=0;
208 static bool isJScriptArray(const VARIANT
* pvar
);
210 Sequence
<Type
> getImplementedInterfaces(IUnknown
* pUnk
);
213 Reference
<XInterface
> createAdapter(const Sequence
<Type
>& types
, const Reference
<XInterface
>& receiver
);
215 // helper function for Sequence conversion
216 void getElementCountAndTypeOfSequence( const Any
& rSeq
, sal_Int32 dim
, Sequence
< sal_Int32
>& seqElementCounts
, TypeDescription
& typeDesc
);
217 // helper function for Sequence conversion
218 static bool incrementMultidimensionalIndex(sal_Int32 dimensions
, const sal_Int32
* parDimensionLength
,
219 sal_Int32
* parMultidimensionalIndex
);
220 // helper function for Sequence conversion
221 static size_t getOleElementSize( VARTYPE type
);
223 static Type
getElementTypeOfSequence( const Type
& seqType
);
225 //Provides a typeconverter
226 Reference
<XTypeConverter
> getTypeConverter();
228 // This member determines what class is used to convert a UNO object
229 // or struct to a COM object. It is passed along to the anyToVariant
230 // function in the createBridge function implementation
231 const sal_uInt8 m_nUnoWrapperClass
;
232 const sal_uInt8 m_nComWrapperClass
;
234 // The servicemanager is either a local smgr or remote when the service
235 // com.sun.star.bridge.OleBridgeSupplierVar1 is used. This service can be
236 // created by createInstanceWithArguments where one can supply a service
237 // manager that is to be used.
238 // Local service manager as supplied by the loader when the creator function
239 // of the service is being called.
240 Reference
<XMultiServiceFactory
> m_smgr
;
241 // An explicitly supplied service manager when the service
242 // com.sun.star.bridge.OleBridgeSupplierVar1 is used. That can be a remote
244 Reference
<XMultiServiceFactory
> m_smgrRemote
;
245 Reference
<XSingleServiceFactory
> m_xInvocationFactoryLocal
;
246 Reference
<XSingleServiceFactory
> m_xInvocationFactoryRemote
;
249 // Holds the type converter which is used for sequence conversion etc.
250 // Use the getTypeConverter function to obtain the interface.
251 Reference
<XTypeConverter
> m_typeConverter
;
256 // ask the object for XBridgeSupplier2 and on success bridges
257 // the uno object to IUnknown or IDispatch.
258 // return true the UNO object supports
260 bool convertSelfToCom( T
& unoInterface
, VARIANT
* pVar
)
263 Reference
< XInterface
> xInt( unoInterface
, UNO_QUERY
);
266 Reference
< css::bridge::XBridgeSupplier2
> xSupplier( xInt
, UNO_QUERY
);
270 rtl_getGlobalProcessId( reinterpret_cast<sal_uInt8
*>(arId
));
271 Sequence
<sal_Int8
> seqId( arId
, 16);
274 Any anyDisp
= xSupplier
->createBridge(
275 anySource
, seqId
, css::bridge::ModelDependent::UNO
,
276 css::bridge::ModelDependent::OLE
);
278 // due to global-process-id check this must be in-process pointer
279 if (auto v
= o3tl::tryAccess
<sal_uIntPtr
>(anyDisp
))
281 VARIANT
* pvariant
= reinterpret_cast<VARIANT
*>(*v
);
283 if (FAILED(hr
= VariantCopy(pVar
, pvariant
)))
284 throw BridgeRuntimeError(
285 "[automation bridge] convertSelfToCom\n"
286 "VariantCopy failed! Error: " +
287 OUString::number(hr
));
288 VariantClear( pvariant
);
289 CoTaskMemFree( pvariant
);
298 // Gets the invocation factory depending on the Type in the Any.
299 // The factory can be created by a local or remote multi service factory.
300 // In case there is a remote multi service factory available there are
301 // some services or types for which the local factory is used. The exceptions
303 // Param anyObject - contains the object ( interface, struct) for what we need an invocation object.
306 Reference
< XSingleServiceFactory
> UnoConversionUtilities
<T
>::getInvocationFactory(const Any
& anyObject
)
308 Reference
< XSingleServiceFactory
> retVal
;
309 MutexGuard
guard( getBridgeMutex());
310 if( anyObject
.getValueTypeClass() != TypeClass_STRUCT
&&
313 if( ! m_xInvocationFactoryRemote
.is() )
314 m_xInvocationFactoryRemote
.set(m_smgrRemote
->createInstance( INVOCATION_SERVICE
), UNO_QUERY
);
315 retVal
= m_xInvocationFactoryRemote
;
319 if( ! m_xInvocationFactoryLocal
.is() )
320 m_xInvocationFactoryLocal
.set(m_smgr
->createInstance(INVOCATION_SERVICE
), UNO_QUERY
);
321 retVal
= m_xInvocationFactoryLocal
;
327 void UnoConversionUtilities
<T
>::variantToAny( const VARIANTARG
* pArg
, Any
& rAny
, const Type
& ptype
, bool bReduceValueRange
/* = sal_True */)
333 bool bCannotConvert
= false;
336 // There is no need to support indirect values, since they're not supported by UNO
337 if( FAILED(hr
= VariantCopyInd( &var
, pArg
))) // remove VT_BYREF
338 throw BridgeRuntimeError(
339 "[automation bridge] UnoConversionUtilities<T>::variantToAny \n"
340 "VariantCopyInd failed for reason : " + OUString::number(hr
));
341 bool bHandled
= convertValueObject( & var
, rAny
);
343 OSL_ENSURE( rAny
.getValueType() == ptype
, "type in Value Object must match the type parameter");
347 // convert into a variant type that is the equivalent to the type
348 // the sequence expects. Thus variantToAny produces the correct type
349 // E.g. An Array object contains VT_I4 and the sequence expects shorts
350 // than the vartype must be changed. The reason is, you can't specify the
351 // type in JavaScript and the script engine determines the type being used.
352 switch( ptype
.getTypeClass())
354 case TypeClass_CHAR
: // could be: new Array( 12, 'w', "w")
355 if( var
.vt
== VT_BSTR
)
357 if(SUCCEEDED( hr
= VariantChangeType( &var
, &var
, 0, VT_BSTR
)))
358 rAny
.setValue( V_BSTR( &var
), ptype
);
359 else if (hr
== DISP_E_TYPEMISMATCH
)
360 bCannotConvert
= true;
366 if(SUCCEEDED(hr
= VariantChangeType( & var
, &var
, 0, VT_I2
)))
367 rAny
.setValue(& var
.iVal
, ptype
);
368 else if (hr
== DISP_E_TYPEMISMATCH
)
369 bCannotConvert
= true;
374 case TypeClass_INTERFACE
: // could also be an IUnknown
375 case TypeClass_STRUCT
:
377 rAny
= createOleObjectWrapper( & var
, ptype
);
381 if(SUCCEEDED(hr
= VariantChangeType( & var
, &var
, 0, VT_I4
)))
382 rAny
.setValue(& var
.lVal
, ptype
);
383 else if (hr
== DISP_E_TYPEMISMATCH
)
384 bCannotConvert
= true;
388 case TypeClass_SEQUENCE
:
389 // There are different ways of receiving a sequence:
390 // 1: JScript, VARTYPE: VT_DISPATCH
391 // 2. VBScript simple arraysVT_VARIANT|VT_BYREF the referenced VARIANT contains
392 // a VT_ARRAY| <type>
393 // 3. VBScript multi dimensional arrays: VT_ARRAY|VT_BYREF
394 if( pArg
->vt
== VT_DISPATCH
)
396 dispatchExObject2Sequence( pArg
, rAny
, ptype
);
400 if ((var
.vt
& VT_ARRAY
) != 0)
402 VARTYPE oleType
= ::sal::static_int_cast
< VARTYPE
, int >( var
.vt
^ VT_ARRAY
);
403 Sequence
<Any
> unoSeq
= createOleArrayWrapper( var
.parray
, oleType
, ptype
);
404 Reference
<XTypeConverter
> conv
= getTypeConverter();
410 Any convAny
= conv
->convertTo(anySeq
, ptype
);
413 catch (const IllegalArgumentException
& e
)
415 throw BridgeRuntimeError(
416 "[automation bridge]com.sun.star.lang.IllegalArgumentException "
417 "in UnoConversionUtilities<T>::variantToAny! Message: " +
420 catch (const CannotConvertException
& e
)
422 throw BridgeRuntimeError(
423 "[automation bridge]com.sun.star.script.CannotConvertException "
424 "in UnoConversionUtilities<T>::variantToAny! Message: " +
432 rAny
.setValue(nullptr,Type());
434 case TypeClass_ANY
: // Any
435 // There could be a JScript Array that needs special handling
436 // If an Any is expected and this Any must contain a Sequence
437 // then we cannot figure out what element type is required.
438 // Therefore we convert to Sequence< Any >
439 if( pArg
->vt
== VT_DISPATCH
&& isJScriptArray( pArg
))
441 dispatchExObject2Sequence( pArg
, rAny
,
442 cppu::UnoType
<Sequence
<Any
>>::get());
444 else if (pArg
->vt
== VT_DECIMAL
)
446 //Decimal maps to hyper in calls from COM -> UNO
447 // It does not matter if we create a sal_uInt64 or sal_Int64,
448 // because the UNO object is called through invocation which
449 //will do a type conversion if necessary
450 if (var
.decVal
.sign
== 0)
453 variantToAny( & var
, rAny
, cppu::UnoType
<sal_uInt64
>::get(),
459 variantToAny( & var
, rAny
, cppu::UnoType
<sal_Int64
>::get(),
465 variantToAny( & var
, rAny
);
468 case TypeClass_BOOLEAN
: // VARIANT could be VARIANT_BOOL or other
469 if(SUCCEEDED(hr
= VariantChangeType( & var
, &var
, 0, VT_BOOL
)))
470 variantToAny( & var
, rAny
);
471 else if (hr
== DISP_E_TYPEMISMATCH
)
472 bCannotConvert
= true;
476 case TypeClass_STRING
: // UString
477 if(var
.vt
== VT_NULL
)
479 if(SUCCEEDED(hr
= VariantChangeType( & var
, &var
, 0, VT_BSTR
)))
480 variantToAny( & var
, rAny
);
481 else if (hr
== DISP_E_TYPEMISMATCH
)
482 bCannotConvert
= true;
486 case TypeClass_FLOAT
: // float
487 if(SUCCEEDED(hr
= VariantChangeType( & var
, &var
, 0, VT_R4
)))
488 variantToAny( & var
, rAny
);
489 else if (hr
== DISP_E_TYPEMISMATCH
)
490 bCannotConvert
= true;
494 case TypeClass_DOUBLE
: // double
495 if(SUCCEEDED(hr
= VariantChangeType( & var
, &var
, 0, VT_R8
)))
496 variantToAny(& var
, rAny
);
497 else if (hr
== DISP_E_TYPEMISMATCH
)
498 bCannotConvert
= true;
502 case TypeClass_BYTE
: // BYTE
503 if(SUCCEEDED(hr
= VariantChangeType( & var
, &var
, 0, VT_I1
)))
504 variantToAny( & var
, rAny
);
505 else if (hr
== DISP_E_TYPEMISMATCH
)
506 bCannotConvert
= true;
510 case TypeClass_SHORT
: // INT16
511 if(SUCCEEDED(hr
= VariantChangeType( & var
, &var
, 0, VT_I2
)))
512 variantToAny( & var
, rAny
);
513 else if (hr
== DISP_E_TYPEMISMATCH
)
514 bCannotConvert
= true;
519 if(SUCCEEDED(hr
= VariantChangeType(& var
, &var
, 0, VT_I4
)))
520 variantToAny( & var
, rAny
, bReduceValueRange
);
521 else if (hr
== DISP_E_TYPEMISMATCH
)
522 bCannotConvert
= true;
526 case TypeClass_HYPER
:
527 if(SUCCEEDED(hr
= VariantChangeType(& var
, &var
, 0, VT_DECIMAL
)))
529 if (var
.decVal
.Lo64
> SAL_CONST_UINT64(0x8000000000000000)
530 || var
.decVal
.Hi32
> 0
531 || var
.decVal
.scale
> 0)
536 sal_Int64 value
= var
.decVal
.Lo64
;
537 if (var
.decVal
.sign
== DECIMAL_NEG
)
538 value
|= SAL_CONST_UINT64(0x8000000000000000);
541 else if (hr
== DISP_E_TYPEMISMATCH
)
542 bCannotConvert
= true;
546 case TypeClass_UNSIGNED_SHORT
: // UINT16
547 if(SUCCEEDED(hr
= VariantChangeType( & var
, &var
, 0, VT_UI2
)))
548 variantToAny( & var
, rAny
);
549 else if (hr
== DISP_E_TYPEMISMATCH
)
550 bCannotConvert
= true;
554 case TypeClass_UNSIGNED_LONG
:
555 if(SUCCEEDED(hr
= VariantChangeType( & var
, &var
, 0, VT_UI4
)))
556 variantToAny( & var
, rAny
, bReduceValueRange
);
557 else if (hr
== DISP_E_TYPEMISMATCH
)
558 bCannotConvert
= true;
562 case TypeClass_UNSIGNED_HYPER
:
563 if(SUCCEEDED(hr
= VariantChangeType(& var
, &var
, 0, VT_DECIMAL
)))
565 if (var
.decVal
.Hi32
> 0 || var
.decVal
.scale
> 0)
570 rAny
<<= var
.decVal
.Lo64
;
572 else if (hr
== DISP_E_TYPEMISMATCH
)
573 bCannotConvert
= true;
578 if(SUCCEEDED(hr
= VariantChangeType(& var
, &var
, 0, VT_UNKNOWN
)))
579 variantToAny( & var
, rAny
);
580 else if (hr
== DISP_E_TYPEMISMATCH
)
581 bCannotConvert
= true;
586 bCannotConvert
= true;
591 throw CannotConvertException(
592 "[automation bridge]UnoConversionUtilities<T>::variantToAny \n"
593 "Cannot convert the value of vartype :\"" +
594 OUString::number(static_cast<sal_Int32
>(var
.vt
)) +
595 "\" to the expected UNO type of type class: " +
596 OUString::number(static_cast<sal_Int32
>(ptype
.getTypeClass())),
597 nullptr, TypeClass_UNKNOWN
, FailReason::TYPE_NOT_SUPPORTED
,0);
600 throw IllegalArgumentException(
601 "[automation bridge]UnoConversionUtilities<T>:variantToAny\n"
602 "The provided VARIANT of type\" " + OUString::number(static_cast<sal_Int32
>(var
.vt
)) +
603 "\" is unappropriate for conversion!", Reference
<XInterface
>(), -1);
605 catch (const CannotConvertException
&)
609 catch (const IllegalArgumentException
&)
613 catch (const BridgeRuntimeError
&)
617 catch (const Exception
& e
)
619 throw BridgeRuntimeError("[automation bridge] unexpected exception in "
620 "UnoConversionUtilities<T>::variantToAny ! Message : \n" +
625 throw BridgeRuntimeError(
626 "[automation bridge] unexpected exception in "
627 "UnoConversionUtilities<T>::variantToAny !");
631 // The function only converts Sequences to SAFEARRAYS with elements of the type
632 // specified by the parameter type. Everything else is forwarded to
633 // anyToVariant(VARIANT* pVariant, const Any& rAny)
634 // Param type must not be VT_BYREF
636 void UnoConversionUtilities
<T
>::anyToVariant(VARIANT
* pVariant
, const Any
& rAny
, VARTYPE type
)
642 OSL_ASSERT( (type
& VT_BYREF
) == 0);
646 SAFEARRAY
* ar
= createUnoSequenceWrapper( rAny
, type
);
649 VariantClear( pVariant
);
650 pVariant
->vt
= ::sal::static_int_cast
< VARTYPE
, int >( VT_ARRAY
| type
);
654 else if(type
== VT_VARIANT
)
656 anyToVariant(pVariant
, rAny
);
661 anyToVariant( &var
, rAny
);
662 if(FAILED(hr
= VariantChangeType(&var
, &var
, 0, type
)))
664 if (hr
== DISP_E_TYPEMISMATCH
)
665 throw CannotConvertException(
666 "[automation bridge]UnoConversionUtilities<T>::anyToVariant \n"
667 "Cannot convert the value of type :\"" +
668 rAny
.getValueTypeName() +
669 "\" to the expected Automation type of VARTYPE: " +
670 OUString::number(static_cast<sal_Int32
>(type
)),
671 nullptr, TypeClass_UNKNOWN
, FailReason::TYPE_NOT_SUPPORTED
,0);
673 throw BridgeRuntimeError(
674 "[automation bridge]UnoConversionUtilities<T>::anyToVariant \n"
675 "Conversion of any with " +
676 rAny
.getValueTypeName() +
677 " to VARIANT with type: " + OUString::number(static_cast<sal_Int32
>(type
)) +
678 " failed! Error code: " + OUString::number(hr
));
681 if(FAILED(hr
= VariantCopy(pVariant
, &var
)))
683 throw BridgeRuntimeError(
684 "[automation bridge]UnoConversionUtilities<T>::anyToVariant \n"
685 "VariantCopy failed for reason: " + OUString::number(hr
));
689 catch (const IllegalArgumentException
&)
693 catch (const CannotConvertException
&)
697 catch (const BridgeRuntimeError
&)
701 catch(const Exception
& e
)
703 throw BridgeRuntimeError(
704 "[automation bridge]UnoConversionUtilities<T>::anyToVariant \n"
705 "Unexpected exception occurred. Message: " + e
.Message
);
709 throw BridgeRuntimeError(
710 "[automation bridge]UnoConversionUtilities<T>::anyToVariant \n"
711 "Unexpected exception occurred.");
716 void UnoConversionUtilities
<T
>::anyToVariant(VARIANT
* pVariant
, const Any
& rAny
)
720 bool bIllegal
= false;
721 switch (rAny
.getValueTypeClass())
723 case TypeClass_INTERFACE
:
725 Reference
<XInterface
> xInt
;
728 createUnoObjectWrapper(rAny
, pVariant
);
736 case TypeClass_STRUCT
:
738 if (rAny
.getValueType() == cppu::UnoType
<Date
>::get() )
743 pVariant
->vt
= VT_DATE
;
744 pVariant
->date
= d
.Value
;
751 else if(rAny
.getValueType() == cppu::UnoType
<Decimal
>::get())
756 pVariant
->vt
= VT_DECIMAL
;
757 pVariant
->decVal
.scale
= d
.Scale
;
758 pVariant
->decVal
.sign
= d
.Sign
;
759 pVariant
->decVal
.Lo32
= d
.LowValue
;
760 pVariant
->decVal
.Mid32
= d
.MiddleValue
;
761 pVariant
->decVal
.Hi32
= d
.HighValue
;
768 else if (rAny
.getValueType() == cppu::UnoType
<Currency
>::get())
773 pVariant
->vt
= VT_CY
;
774 pVariant
->cyVal
.int64
= c
.Value
;
781 else if(rAny
.getValueType() == cppu::UnoType
<SCode
>::get())
786 pVariant
->vt
= VT_ERROR
;
787 pVariant
->scode
= s
.Value
;
796 createUnoObjectWrapper(rAny
, pVariant
);
800 case TypeClass_SEQUENCE
: // sequence ??? SafeArray descriptor
802 SAFEARRAY
* pArray
= createUnoSequenceWrapper(rAny
);
805 V_VT(pVariant
) = VT_ARRAY
| VT_VARIANT
;
806 V_ARRAY(pVariant
) = pArray
;
817 if (FAILED(hr
= VariantClear(pVariant
)))
819 throw BridgeRuntimeError(
820 "[automation bridge]UnoConversionUtilities<T>::anyToVariant\n"
821 "VariantClear failed with error:" + OUString::number(hr
));
825 case TypeClass_BOOLEAN
:
830 pVariant
->vt
= VT_BOOL
;
831 pVariant
->boolVal
= value
? VARIANT_TRUE
: VARIANT_FALSE
;
841 // Because VT_UI2 does not conform to oleautomation we convert into VT_I2 instead
842 sal_uInt16 value
= *o3tl::forceAccess
<sal_Unicode
>(rAny
);
843 pVariant
->vt
= VT_I2
;
844 pVariant
->iVal
= value
;
847 case TypeClass_STRING
:
852 pVariant
->vt
= VT_BSTR
;
853 pVariant
->bstrVal
= sal::systools::BStr::newBSTR(value
);
861 case TypeClass_FLOAT
:
866 pVariant
->vt
= VT_R4
;
867 pVariant
->fltVal
= value
;
875 case TypeClass_DOUBLE
:
880 pVariant
->vt
= VT_R8
;
881 pVariant
->dblVal
= value
;
891 // ole automation does not know a signed char but only unsigned char
895 pVariant
->vt
= VT_UI1
;
896 pVariant
->bVal
= value
;
904 case TypeClass_SHORT
: // INT16
905 case TypeClass_UNSIGNED_SHORT
: // UINT16
910 pVariant
->vt
= VT_I2
;
911 pVariant
->iVal
= value
;
921 sal_Int32 value
= *static_cast<sal_Int32
const *>(rAny
.getValue());
922 pVariant
->vt
= VT_I4
;
923 pVariant
->lVal
= value
;
927 case TypeClass_UNSIGNED_LONG
:
932 pVariant
->vt
= VT_I4
;
933 pVariant
->lVal
= value
;
941 case TypeClass_HYPER
:
944 pVariant
->vt
= VT_DECIMAL
;
945 pVariant
->decVal
.scale
= 0;
946 pVariant
->decVal
.sign
= 0;
947 pVariant
->decVal
.Hi32
= 0;
952 if (value
& SAL_CONST_UINT64(0x8000000000000000))
953 pVariant
->decVal
.sign
= DECIMAL_NEG
;
955 pVariant
->decVal
.Lo64
= value
;
958 case TypeClass_UNSIGNED_HYPER
:
960 pVariant
->vt
= VT_DECIMAL
;
961 pVariant
->decVal
.scale
= 0;
962 pVariant
->decVal
.sign
= 0;
963 pVariant
->decVal
.Hi32
= 0;
967 pVariant
->decVal
.Lo64
= value
;
975 if (!createUnoTypeWrapper(type
.getTypeName(), & var
))
976 throw BridgeRuntimeError(
977 "[automation bridge] UnoConversionUtilities<T>::anyToVariant \n"
978 "Error during conversion of UNO type to Automation object!");
980 if (FAILED(VariantCopy(pVariant
, &var
)))
981 throw BridgeRuntimeError(
982 "[automation bridge] UnoConversionUtilities<T>::anyToVariant \n"
983 "Unexpected error!");
988 //TypeClass_EXCEPTION:
989 //When an InvocationTargetException is thrown when calling XInvocation::invoke
990 //on a UNO object, then the target exception is directly used to create a
996 throw CannotConvertException(
997 "[automation bridge]UnoConversionUtilities<T>::anyToVariant\n"
998 "There is no conversion for this UNO type to an Automation type."
999 "The destination type class is the type class of the UNO "
1000 "argument which was to be converted.",
1001 Reference
<XInterface
>(), rAny
.getValueTypeClass(),
1002 FailReason::TYPE_NOT_SUPPORTED
, 0);
1008 throw IllegalArgumentException(
1009 "[automation bridge]UnoConversionUtilities<T>::anyToVariant\n"
1010 "The provided any of type\" " + rAny
.getValueTypeName() +
1011 "\" is unappropriate for conversion!", Reference
<XInterface
>(), -1);
1015 catch (const CannotConvertException
&)
1019 catch (const IllegalArgumentException
&)
1023 catch(const BridgeRuntimeError
&)
1027 catch(const Exception
& e
)
1029 throw BridgeRuntimeError(
1030 "[automation bridge]UnoConversionUtilities<T>::anyToVariant \n"
1031 "Unexpected exception occurred. Message: " + e
.Message
);
1035 throw BridgeRuntimeError(
1036 "[automation bridge]UnoConversionUtilities<T>::anyToVariant \n"
1037 "Unexpected exception occurred. " );
1041 // Creates an SAFEARRAY of the specified element and if necessary
1042 // creates a SAFEARRAY with multiple dimensions.
1043 // Used by sal_Bool anyToVariant(VARIANT* pVariant, const Any& rAny, VARTYPE type);
1045 SAFEARRAY
* UnoConversionUtilities
<T
>::createUnoSequenceWrapper(const Any
& rSeq
, VARTYPE elemtype
)
1047 if (rSeq
.getValueTypeClass() != TypeClass_SEQUENCE
)
1048 throw IllegalArgumentException(
1049 "[automation bridge]UnoConversionUtilities<T>::createUnoSequenceWrapper \n"
1050 "The any does not contain a sequence!", nullptr, 0);
1051 if (elemtype
== VT_NULL
|| elemtype
== VT_EMPTY
)
1052 throw IllegalArgumentException(
1053 "[automation bridge]UnoConversionUtilities<T>::createUnoSequenceWrapper \n"
1054 "No element type supplied!",nullptr, -1);
1055 SAFEARRAY
* pArray
= nullptr;
1056 // Get the dimensions. This is done by examining the type name string
1057 // The count of brackets determines the dimensions.
1058 OUString sTypeName
= rSeq
.getValueTypeName();
1060 for(sal_Int32 lastIndex
=0;(lastIndex
= sTypeName
.indexOf( L
'[', lastIndex
)) != -1; lastIndex
++,dims
++);
1062 //get the maximum number of elements per dimensions and the typedescription of the elements
1063 Sequence
<sal_Int32
> seqElementCounts( dims
);
1064 TypeDescription elementTypeDesc
;
1065 getElementCountAndTypeOfSequence( rSeq
, 1, seqElementCounts
, elementTypeDesc
);
1067 if( elementTypeDesc
.is() )
1069 // set up the SAFEARRAY
1070 std::unique_ptr
<SAFEARRAYBOUND
[]> sarSafeArrayBound(new SAFEARRAYBOUND
[dims
]);
1071 SAFEARRAYBOUND
* prgsabound
= sarSafeArrayBound
.get();
1072 for( sal_Int32 i
=0; i
< dims
; i
++)
1074 //prgsabound[0] is the right most dimension
1075 prgsabound
[dims
- i
- 1].lLbound
= 0;
1076 prgsabound
[dims
- i
- 1].cElements
= seqElementCounts
[i
];
1079 typelib_TypeDescription
* rawTypeDesc
= elementTypeDesc
.get();
1080 sal_Int32 elementSize
= rawTypeDesc
->nSize
;
1081 size_t oleElementSize
= getOleElementSize( elemtype
);
1082 // SafeArrayCreate clears the memory for the data itself.
1083 pArray
= SafeArrayCreate(elemtype
, dims
, prgsabound
);
1085 // convert the Sequence's elements and populate the SAFEARRAY
1088 // Iterate over every Sequence that contains the actual elements
1090 if( SUCCEEDED( SafeArrayAccessData( pArray
, &pSAData
)))
1092 const sal_Int32
* parElementCount
= seqElementCounts
.getConstArray();
1093 uno_Sequence
* pMultiSeq
= *static_cast<uno_Sequence
* const*>(rSeq
.getValue());
1094 sal_Int32 dimsSeq
= dims
- 1;
1096 // arDimSeqIndices contains the current index of a block of data.
1097 // E.g. Sequence<Sequence<sal_Int32>> , the index would refer to Sequence<sal_Int32>
1098 // In this case arDimSeqIndices would have the size 1. That is the elements are not counted
1099 // but the Sequences that contain those elements.
1100 // The indices are 0 based
1101 std::unique_ptr
<sal_Int32
[]> sarDimsSeqIndices
;
1102 sal_Int32
* arDimsSeqIndices
= nullptr;
1105 sarDimsSeqIndices
.reset(new sal_Int32
[dimsSeq
]);
1106 arDimsSeqIndices
= sarDimsSeqIndices
.get();
1107 memset( arDimsSeqIndices
, 0, sizeof( sal_Int32
) * dimsSeq
);
1110 char* psaCurrentData
= static_cast<char*>(pSAData
);
1114 // Get the Sequence at the current index , see arDimsSeqIndices
1115 uno_Sequence
* pCurrentSeq
= pMultiSeq
;
1116 sal_Int32 curDim
=1; // 1 based
1117 bool skipSeq
= false;
1118 while( curDim
<= dimsSeq
)
1120 // get the Sequence at the index if valid
1121 if( pCurrentSeq
->nElements
> arDimsSeqIndices
[ curDim
- 1] ) // don't point to Nirvana
1123 // size of Sequence is 4
1124 sal_Int32 offset
= arDimsSeqIndices
[ curDim
- 1] * 4;
1125 pCurrentSeq
= *reinterpret_cast<uno_Sequence
**>(&pCurrentSeq
->elements
[ offset
]);
1130 // There is no Sequence at this index, so skip this index
1139 // Calculate the current position within the datablock of the SAFEARRAY
1140 // for the next Sequence.
1141 sal_Int32 memOffset
= 0;
1142 sal_Int32 dimWeight
= parElementCount
[ dims
- 1]; // size of the rightmost dimension
1143 for(sal_Int32 idims
=0; idims
< dimsSeq
; idims
++ )
1145 memOffset
+= arDimsSeqIndices
[dimsSeq
- 1 - idims
] * dimWeight
;
1146 // now determine the weight of the dimension to the left of the current.
1147 if( dims
- 2 - idims
>=0)
1148 dimWeight
*= parElementCount
[dims
- 2 - idims
];
1150 psaCurrentData
= static_cast<char*>(pSAData
) + memOffset
* oleElementSize
;
1151 // convert the Sequence and put the elements into the Safearray
1152 for( sal_Int32 i
= 0; i
< pCurrentSeq
->nElements
; i
++)
1154 Any
unoElement( pCurrentSeq
->elements
+ i
* elementSize
, rawTypeDesc
);
1155 // The any is being converted into a VARIANT which value is then copied
1156 // to the SAFEARRAY's data block. When copying one has to follow the rules for
1157 // copying certain types, as are VT_DISPATCH, VT_UNKNOWN, VT_VARIANT, VT_BSTR.
1158 // To increase performance, we just do a memcpy of VARIANT::byref. This is possible
1159 // because anyToVariant has already followed the copying rules. To make this
1160 // work there must not be a VariantClear.
1161 // One Exception is VARIANT because I don't know how VariantCopy works.
1165 anyToVariant( &var
, unoElement
);
1166 if( elemtype
== VT_VARIANT
)
1168 VariantCopy( reinterpret_cast<VARIANT
*>(psaCurrentData
), &var
);
1169 VariantClear( &var
);
1172 memcpy( psaCurrentData
, &var
.byref
, oleElementSize
);
1174 psaCurrentData
+= oleElementSize
;
1177 while( incrementMultidimensionalIndex( dimsSeq
, parElementCount
, arDimsSeqIndices
));
1179 SafeArrayUnaccessData( pArray
);
1186 // Increments a multi dimensional index.
1187 // Returns true as long as the index has been successfully incremented, false otherwise.
1188 // False is also returned if an overflow of the most significant dimension occurs. E.g.
1189 // assume an array with the dimensions (2,2), then the lowest index is (0,0) and the highest
1190 // index is (1,1). If the function is being called with the index (1,1) then the overflow would
1191 // occur, with the result (0,0) and a sal_False as return value.
1192 // Param dimensions - number of dimensions
1193 // Param parDimensionsLength - The array contains the size of each dimension, that is the
1194 // size of the array equals the parameter dimensions.
1195 // The rightmost dimensions is the least significant one
1196 // ( parDimensionsLengths[ dimensions -1 ] ).
1197 // Param parMultiDimensionalIndex - The array contains the index. Each dimension index is
1200 bool UnoConversionUtilities
<T
>::incrementMultidimensionalIndex(sal_Int32 dimensions
,
1201 const sal_Int32
* parDimensionLengths
,
1202 sal_Int32
* parMultidimensionalIndex
)
1208 bool carry
= true; // to get into the while loop
1210 sal_Int32 currentDimension
= dimensions
; //most significant is 1
1213 parMultidimensionalIndex
[ currentDimension
- 1]++;
1214 // if carryover, set index to 0 and handle carry on a level above
1215 if( parMultidimensionalIndex
[ currentDimension
- 1] > (parDimensionLengths
[ currentDimension
- 1] - 1))
1216 parMultidimensionalIndex
[ currentDimension
- 1]= 0;
1220 currentDimension
--;
1221 // if dimensions drops below 1 and carry is set than then all indices are 0 again
1222 // this is signalled by returning sal_False
1223 if( currentDimension
< 1 && carry
)
1232 // Determines the size of a certain OLE type. The function takes
1233 // only those types into account which are oleautomation types and
1234 // can have a value ( unless VT_NULL, VT_EMPTY, VT_ARRAY, VT_BYREF).
1235 // Currently used in createUnoSequenceWrapper to calculate addresses
1236 // for data within a SAFEARRAY.
1238 size_t UnoConversionUtilities
<T
>::getOleElementSize( VARTYPE type
)
1243 case VT_BOOL
: size
= sizeof( VARIANT_BOOL
);break;
1244 case VT_UI1
: size
= sizeof( unsigned char);break;
1245 case VT_R8
: size
= sizeof( double);break;
1246 case VT_R4
: size
= sizeof( float);break;
1247 case VT_I2
: size
= sizeof( short);break;
1248 case VT_I4
: size
= sizeof( long);break;
1249 case VT_BSTR
: size
= sizeof( BSTR
); break;
1250 case VT_ERROR
: size
= sizeof( SCODE
); break;
1252 case VT_UNKNOWN
: size
= sizeof( IUnknown
*); break;
1253 case VT_VARIANT
: size
= sizeof( VARIANT
);break;
1259 //If a Sequence is being converted into a SAFEARRAY then we possibly have
1260 // to create a SAFEARRAY with multiple dimensions. This is the case when a
1261 // Sequence contains Sequences ( Sequence< Sequence < XXX > > ). The leftmost
1262 // Sequence in the declaration is assumed to represent dimension 1. Because
1263 // all Sequence elements of a Sequence can have different length, we have to
1264 // determine the maximum length which is then the length of the respective
1266 // getElementCountAndTypeOfSequence determines the length of each dimension and calls itself recursively
1268 // param rSeq - an Any that has to contain a Sequence
1269 // param dim - the dimension for which the number of elements is being determined,
1271 // param seqElementCounts - contains the maximum number of elements for each
1272 // dimension. Index 0 contains the number of dimension one.
1273 // After return the Sequence contains the maximum number of
1274 // elements for each dimension.
1275 // The length of the Sequence must equal the number of dimensions.
1276 // param typeClass - TypeClass of the element type that is no Sequence, e.g.
1277 // Sequence< Sequence <Sequence <sal_Int32> > > - type is sal_Int32)
1279 void UnoConversionUtilities
<T
>::getElementCountAndTypeOfSequence( const Any
& rSeq
, sal_Int32 dim
,
1280 Sequence
< sal_Int32
>& seqElementCounts
, TypeDescription
& typeDesc
)
1282 sal_Int32 dimCount
= (*static_cast<uno_Sequence
* const *>(rSeq
.getValue()))->nElements
;
1283 if( dimCount
> seqElementCounts
[ dim
-1])
1284 seqElementCounts
.getArray()[ dim
-1]= dimCount
;
1286 // we need the element type to construct the any that is
1287 // passed into getElementCountAndTypeOfSequence again
1288 typelib_TypeDescription
* pSeqDesc
= nullptr;
1289 rSeq
.getValueTypeDescription( &pSeqDesc
);
1290 typelib_TypeDescriptionReference
* pElementDescRef
= reinterpret_cast<typelib_IndirectTypeDescription
*>(pSeqDesc
)->pType
;
1292 // if the elements are Sequences then do recursion
1293 if( dim
< seqElementCounts
.getLength() )
1295 uno_Sequence
* pSeq
= *static_cast<uno_Sequence
* const*>(rSeq
.getValue());
1296 uno_Sequence
** arSequences
= reinterpret_cast<uno_Sequence
**>(pSeq
->elements
);
1297 for( sal_Int32 i
=0; i
< dimCount
; i
++)
1299 uno_Sequence
* arElement
= arSequences
[ i
];
1300 getElementCountAndTypeOfSequence( Any( &arElement
, pElementDescRef
), dim
+ 1 , seqElementCounts
, typeDesc
);
1305 // determine the element type ( e.g. Sequence< Sequence <Sequence <sal_Int32> > > - type is sal_Int32)
1306 typeDesc
= pElementDescRef
;
1308 typelib_typedescription_release( pSeqDesc
);
1313 SAFEARRAY
* UnoConversionUtilities
<T
>::createUnoSequenceWrapper(const Any
& rSeq
)
1315 SAFEARRAY
* pArray
= nullptr;
1318 if( rSeq
.getValueTypeClass() != TypeClass_SEQUENCE
)
1319 throw IllegalArgumentException(
1320 "[automation bridge]UnoConversionUtilities<T>::createUnoSequenceWrapper\n"
1321 "The UNO argument is not a sequence", nullptr, -1);
1323 uno_Sequence
* punoSeq
= *static_cast<uno_Sequence
* const *>(rSeq
.getValue());
1325 typelib_TypeDescriptionReference
* pSeqTypeRef
= rSeq
.getValueTypeRef();
1326 typelib_TypeDescription
* pSeqType
= nullptr;
1327 TYPELIB_DANGER_GET( &pSeqType
, pSeqTypeRef
);
1328 typelib_IndirectTypeDescription
* pSeqIndDec
= reinterpret_cast<typelib_IndirectTypeDescription
*>(pSeqType
);
1331 typelib_TypeDescriptionReference
* pSeqElementTypeRef
= pSeqIndDec
->pType
;
1332 TYPELIB_DANGER_RELEASE( pSeqType
);
1334 typelib_TypeDescription
* pSeqElementDesc
= nullptr;
1335 TYPELIB_DANGER_GET( &pSeqElementDesc
, pSeqElementTypeRef
);
1336 sal_Int32 nElementSize
= pSeqElementDesc
->nSize
;
1337 n
= punoSeq
->nElements
;
1339 SAFEARRAYBOUND rgsabound
[1];
1340 rgsabound
[0].lLbound
= 0;
1341 rgsabound
[0].cElements
= n
;
1345 pArray
= SafeArrayCreate(VT_VARIANT
, 1, rgsabound
);
1348 char * pSeqData
= punoSeq
->elements
;
1350 for (sal_uInt32 i
= 0; i
< n
; i
++)
1352 unoElement
.setValue( pSeqData
+ i
* nElementSize
, pSeqElementDesc
);
1353 VariantInit(&oleElement
);
1355 anyToVariant(&oleElement
, unoElement
);
1358 SafeArrayPutElement(pArray
, safeI
, &oleElement
);
1360 VariantClear(&oleElement
);
1362 TYPELIB_DANGER_RELEASE( pSeqElementDesc
);
1367 /* The argument rObj can contain
1370 - UNO interface created by this bridge (adapter factory)
1371 - UNO interface created by this bridge ( COM Wrapper)
1373 pVar must be initialized.
1376 void UnoConversionUtilities
<T
>::createUnoObjectWrapper(const Any
& rObj
, VARIANT
* pVar
)
1378 MutexGuard
guard(getBridgeMutex());
1380 Reference
<XInterface
> xInt
;
1382 TypeClass tc
= rObj
.getValueTypeClass();
1383 if (tc
!= TypeClass_INTERFACE
&& tc
!= TypeClass_STRUCT
)
1384 throw IllegalArgumentException(
1385 "[automation bridge]UnoConversionUtilities<T>::createUnoObjectWrapper \n"
1386 "Cannot create an Automation interface for a UNO type which is not "
1387 "a struct or interface!", nullptr, -1);
1389 if (rObj
.getValueTypeClass() == TypeClass_INTERFACE
)
1391 if (! (rObj
>>= xInt
))
1392 throw IllegalArgumentException(
1393 "[automation bridge] UnoConversionUtilities<T>::createUnoObjectWrapper\n "
1394 "Could not create wrapper object for UNO object!", nullptr, -1);
1395 //If XInterface is NULL, which is a valid value, then simply return NULL.
1398 pVar
->vt
= VT_UNKNOWN
;
1399 pVar
->punkVal
= nullptr;
1402 //make sure we have the main XInterface which is used with a map
1403 xInt
.set(xInt
, UNO_QUERY
);
1404 //If there is already a wrapper for the UNO object then use it
1406 Reference
<XInterface
> xIntWrapper
;
1407 // Does a UNO wrapper exist already ?
1408 auto it_uno
= UnoObjToWrapperMap
.find( reinterpret_cast<sal_uIntPtr
>(xInt
.get()));
1409 if(it_uno
!= UnoObjToWrapperMap
.end())
1411 xIntWrapper
= it_uno
->second
;
1412 if (xIntWrapper
.is())
1414 convertSelfToCom(xIntWrapper
, pVar
);
1418 // Is the object a COM wrapper ( either XInvocation, or Adapter object)
1419 // or does it supply an IDispatch by its own ?
1422 Reference
<XInterface
> xIntComWrapper
= xInt
;
1424 // Adapter? then get the COM wrapper to which the adapter delegates its calls
1425 auto it
= AdapterToWrapperMap
.find( reinterpret_cast<sal_uIntPtr
>(xInt
.get()));
1426 if( it
!= AdapterToWrapperMap
.end() )
1427 xIntComWrapper
= reinterpret_cast<XInterface
*>(it
->second
);
1429 if (convertSelfToCom(xIntComWrapper
, pVar
))
1433 // If we have no UNO wrapper nor the IDispatch yet then we have to create
1434 // a wrapper. For that we need an XInvocation.
1436 // create an XInvocation using the invocation service
1437 Reference
<XInvocation
> xInv
;
1438 Reference
<XSingleServiceFactory
> xInvFactory
= getInvocationFactory(rObj
);
1439 if (xInvFactory
.is())
1441 Sequence
<Any
> params(2);
1442 params
.getArray()[0] = rObj
;
1443 params
.getArray()[1] <<= OUString("FromOLE");
1444 Reference
<XInterface
> xInt2
= xInvFactory
->createInstanceWithArguments(params
);
1445 xInv
.set(xInt2
, UNO_QUERY
);
1450 Reference
<XInterface
> xNewWrapper
= createUnoWrapperInstance();
1451 Reference
<css::lang::XInitialization
> xInitWrapper(xNewWrapper
, UNO_QUERY
);
1452 if (xInitWrapper
.is())
1454 VARTYPE vartype
= getVarType( rObj
);
1461 params
[2] <<= vartype
;
1462 xInitWrapper
->initialize( Sequence
<Any
>(params
, 3));
1468 params
[1] <<= vartype
;
1469 xInitWrapper
->initialize( Sequence
<Any
>(params
, 2));
1472 // put the newly created object into a map. If the same object will
1473 // be mapped again and there is already a wrapper then the old wrapper
1475 if(xInt
.is()) // only interfaces
1476 UnoObjToWrapperMap
[reinterpret_cast<sal_uIntPtr
>(xInt
.get())]= xNewWrapper
;
1477 convertSelfToCom(xNewWrapper
, pVar
);
1484 void UnoConversionUtilities
<T
>::variantToAny( const VARIANT
* pVariant
, Any
& rAny
,
1485 bool bReduceValueRange
/* = sal_True */)
1492 // There is no need to support indirect values, since they're not supported by UNO
1493 if( FAILED(hr
= VariantCopyInd( &var
, pVariant
))) // remove VT_BYREF
1494 throw BridgeRuntimeError(
1495 "[automation bridge] UnoConversionUtilities<T>::variantToAny \n"
1496 "VariantCopyInd failed for reason : " + OUString::number(hr
));
1498 if ( ! convertValueObject( & var
, rAny
))
1500 if ((var
.vt
& VT_ARRAY
) > 0)
1502 VARTYPE oleTypeFlags
= ::sal::static_int_cast
< VARTYPE
, int >( var
.vt
^ VT_ARRAY
);
1504 Sequence
<Any
> unoSeq
= createOleArrayWrapper(var
.parray
, oleTypeFlags
);
1505 rAny
.setValue( &unoSeq
, cppu::UnoType
<decltype(unoSeq
)>::get());
1512 rAny
.setValue(nullptr, Type());
1515 rAny
.setValue(nullptr, Type());
1518 rAny
.setValue( & var
.iVal
, cppu::UnoType
<sal_Int16
>::get());
1521 rAny
.setValue( & var
.lVal
, cppu::UnoType
<sal_Int32
>::get());
1522 // necessary for use in JavaScript ( see "reduceRange")
1523 if( bReduceValueRange
)
1527 rAny
.setValue( & var
.fltVal
, cppu::UnoType
<float>::get());
1530 rAny
.setValue(& var
.dblVal
, cppu::UnoType
<double>::get());
1534 Currency
cy(var
.cyVal
.int64
);
1546 OUString
b(o3tl::toU(var
.bstrVal
));
1547 rAny
.setValue( &b
, cppu::UnoType
<decltype(b
)>::get());
1553 //check if it is a UNO type
1554 CComQIPtr
<IUnoTypeWrapper
> spType(static_cast<IUnknown
*>(var
.byref
));
1558 if (FAILED(spType
->get_Name(&sName
)))
1559 throw BridgeRuntimeError(
1560 "[automation bridge]UnoConversionUtilities<T>::variantToAny \n"
1561 "Failed to get the type name from a UnoTypeWrapper!");
1563 if (!getType(sName
, type
))
1565 throw CannotConvertException(
1566 OUString::Concat("[automation bridge]UnoConversionUtilities<T>::variantToAny \n"
1567 "A UNO type with the name: ") + o3tl::toU(LPCOLESTR(sName
)) +
1569 nullptr, TypeClass_UNKNOWN
, FailReason::TYPE_NOT_SUPPORTED
,0);
1575 rAny
= createOleObjectWrapper( & var
);
1581 SCode
scode(var
.scode
);
1587 rAny
<<= (var
.boolVal
== VARIANT_TRUE
);
1591 rAny
.setValue( & var
.cVal
, cppu::UnoType
<sal_Int8
>::get());
1593 case VT_UI1
: // there is no unsigned char in UNO
1594 rAny
<<= sal_Int8(var
.bVal
);
1597 rAny
.setValue( & var
.uiVal
, cppu::UnoType
<cppu::UnoUnsignedShortType
>::get() );
1600 rAny
.setValue( & var
.ulVal
, cppu::UnoType
<sal_uInt32
>::get());
1603 rAny
.setValue( & var
.intVal
, cppu::UnoType
<sal_Int32
>::get());
1606 rAny
.setValue( & var
.uintVal
, cppu::UnoType
<sal_uInt32
>::get());
1609 rAny
.setValue( nullptr, Type());
1614 dec
.Scale
= var
.decVal
.scale
;
1615 dec
.Sign
= var
.decVal
.sign
;
1616 dec
.LowValue
= var
.decVal
.Lo32
;
1617 dec
.MiddleValue
= var
.decVal
.Mid32
;
1618 dec
.HighValue
= var
.decVal
.Hi32
;
1629 catch (const IllegalArgumentException
&)
1633 catch (const CannotConvertException
&)
1637 catch (const BridgeRuntimeError
&)
1641 catch (const Exception
& e
)
1643 throw BridgeRuntimeError("[automation bridge] unexpected exception in "
1644 "UnoConversionUtilities<T>::variantToAny ! Message : \n" +
1649 throw BridgeRuntimeError(
1650 "[automation bridge] unexpected exception in "
1651 "UnoConversionUtilities<T>::variantToAny !");
1655 // The function converts an IUnknown* into a UNO interface or struct. The
1656 // IUnknown pointer can constitute different kind of objects:
1657 // 1. a wrapper of a UNO struct (the wrapper was created by this bridge)
1658 // 2. a wrapper of a UNO interface (created by this bridge)
1659 // 3. a dispatch object that implements UNO interfaces
1660 // 4. a dispatch object.
1662 // If the parameter "aType" has a value then the COM object ( pUnknown) is supposed to
1663 // implement the interface described by "aType". Moreover it ( pUnknown) can implement
1665 // UNO interfaces in which case it has to support the SUPPORTED_INTERFACES_PROP (see
1666 // #define) property. That property contains all names of interfaces.
1667 // "pUnknown" is wrapped by a COM wrapper object that implements XInvocation, e.g.
1668 // IUnknownWrapper. Additionally an object of type "aType" is created by help
1669 // of the INTERFACE_ADAPTER_FACTORY (see #define) service. The implementation of
1670 // "aType" calls on the COM wrapper's XInvocation::invoke. If the COM object supports
1671 // more than one UNO interfaces, as can be determined by the property
1672 // SUPPORTED_INTERFACES_PROP, then the INTERFACE_ADAPTER_FACTORY creates an object that
1673 // implements all these interfaces.
1674 // This is only done if "pUnknown" is not already a UNO wrapper,
1675 // that is it is actually NOT a UNO object that was converted to a COM object. If it is an
1676 // UNO wrapper than the original UNO object is being extracted, queried for "aType" (if
1677 // it is no struct) and returned.
1679 Any UnoConversionUtilities
<T
>::createOleObjectWrapper(VARIANT
* pVar
, const Type
& aType
)
1681 //To allow passing "Nothing" in VS 2008 we need to accept VT_EMPTY
1682 if (pVar
->vt
!= VT_UNKNOWN
&& pVar
->vt
!= VT_DISPATCH
&& pVar
->vt
!= VT_EMPTY
)
1683 throw IllegalArgumentException(
1684 "[automation bridge]UnoConversionUtilities<T>::createOleObjectWrapper \n"
1685 "The VARIANT does not contain an object type! ", nullptr, -1);
1687 MutexGuard
guard( getBridgeMutex());
1689 CComPtr
<IUnknown
> spUnknown
;
1690 CComPtr
<IDispatch
> spDispatch
;
1692 if (pVar
->vt
== VT_UNKNOWN
)
1694 spUnknown
= pVar
->punkVal
;
1696 spUnknown
.QueryInterface( & spDispatch
.p
);
1698 else if (pVar
->vt
== VT_DISPATCH
&& pVar
->pdispVal
!= nullptr)
1700 CComPtr
<IDispatch
> spDispatch2(pVar
->pdispVal
);
1702 spDispatch2
.QueryInterface( & spUnknown
.p
);
1705 static Type VOID_TYPE
;
1707 //If no Type is provided and pVar contains IUnknown then we return a XInterface.
1708 //If pVar contains an IDispatch then we return a XInvocation.
1709 Type desiredType
= aType
;
1711 if (aType
== VOID_TYPE
)
1717 desiredType
= cppu::UnoType
<XInterface
>::get();
1720 desiredType
= cppu::UnoType
<XInvocation
>::get();
1723 desiredType
= aType
;
1727 // COM pointer are NULL, no wrapper required
1728 if (spUnknown
== nullptr)
1730 Reference
<XInterface
> xInt
;
1731 if( aType
.getTypeClass() == TypeClass_INTERFACE
)
1732 ret
.setValue( &xInt
, aType
);
1733 else if( aType
.getTypeClass() == TypeClass_STRUCT
)
1734 ret
.setValue( nullptr, aType
);
1741 // Check if "spUnknown" is a UNO wrapper, that is a UNO object that has been
1742 // passed to COM. Then it supports IUnoObjectWrapper
1743 // and we extract the original UNO object.
1744 CComQIPtr
<IUnoObjectWrapper
> spUno( spUnknown
);
1746 { // it is a wrapper
1747 Reference
<XInterface
> xInt
;
1748 if( SUCCEEDED( spUno
->getOriginalUnoObject( &xInt
)))
1755 if( SUCCEEDED( spUno
->getOriginalUnoStruct(&any
)))
1761 // "spUnknown" is a real COM object.
1762 // Before we create a new wrapper object we check if there is an existing wrapper
1763 // There can be two kinds of wrappers, those who wrap dispatch - UNO objects, and those who
1764 // wrap ordinary dispatch objects. The dispatch-UNO objects usually are adapted to represent
1765 // particular UNO interfaces.
1766 Reference
<XInterface
> xIntWrapper
;
1767 auto cit_currWrapper
= ComPtrToWrapperMap
.find( reinterpret_cast<sal_uIntPtr
>(spUnknown
.p
));
1768 if(cit_currWrapper
!= ComPtrToWrapperMap
.end())
1769 xIntWrapper
= cit_currWrapper
->second
;
1770 if (xIntWrapper
.is())
1772 //Try to find an adapter for the wrapper
1773 //find the proper Adapter. The pointer in the WrapperToAdapterMap are valid as long as
1774 //we get a pointer to the wrapper from ComPtrToWrapperMap, because the Adapter hold references
1776 auto it
= WrapperToAdapterMap
.find(reinterpret_cast<sal_uIntPtr
>(xIntWrapper
.get()));
1777 if (it
== WrapperToAdapterMap
.end())
1779 // No adapter available.
1780 //The COM component could be a UNO object. Then we need to provide
1781 // a proxy that implements all interfaces
1782 Sequence
<Type
> seqTypes
= getImplementedInterfaces(spUnknown
);
1783 Reference
<XInterface
> xIntAdapter
;
1784 if (seqTypes
.getLength() > 0)
1786 //It is a COM UNO object
1787 xIntAdapter
= createAdapter(seqTypes
, xIntWrapper
);
1791 // Some ordinary COM object
1792 xIntAdapter
= xIntWrapper
;
1794 // return the wrapper directly, return XInterface or XInvocation
1795 ret
= xIntWrapper
->queryInterface(desiredType
);
1796 if ( ! ret
.hasValue())
1797 throw IllegalArgumentException(
1798 "[automation bridge]UnoConversionUtilities<T>::createOleObjectWrapper \n"
1799 "The COM object is not suitable for the UNO type: " +
1800 desiredType
.getTypeName(), nullptr, -1);
1804 //There is an adapter available
1805 Reference
<XInterface
> xIntAdapter(reinterpret_cast<XInterface
*>(it
->second
));
1806 ret
= xIntAdapter
->queryInterface( desiredType
);
1807 if ( ! ret
.hasValue())
1808 throw IllegalArgumentException(
1809 "[automation bridge]UnoConversionUtilities<T>::createOleObjectWrapper \n"
1810 "The COM object is not suitable for the UNO type: " +
1811 desiredType
.getTypeName(), nullptr, -1);
1816 // No existing wrapper. Therefore create a new proxy.
1817 // If the object implements UNO interfaces then get the types.
1818 Sequence
<Type
> seqTypes
= getImplementedInterfaces(spUnknown
);
1819 if (seqTypes
.getLength() == 0 &&
1820 aType
!= VOID_TYPE
&& aType
!= cppu::UnoType
<XInvocation
>::get())
1822 seqTypes
= Sequence
<Type
>( & aType
, 1);
1825 //There is no existing wrapper, therefore we create one for the real COM object
1826 Reference
<XInterface
> xIntNewProxy
= createComWrapperInstance();
1827 if ( ! xIntNewProxy
.is())
1828 throw BridgeRuntimeError(
1829 "[automation bridge]UnoConversionUtilities<T>::createOleObjectWrapper \n"
1830 "Could not create proxy object for COM object!");
1832 // initialize the COM wrapper
1833 Reference
<XInitialization
> xInit( xIntNewProxy
, UNO_QUERY
);
1834 OSL_ASSERT( xInit
.is());
1837 params
[0] <<= reinterpret_cast<sal_uIntPtr
>(spUnknown
.p
);
1838 params
[1] <<= (pVar
->vt
== VT_DISPATCH
);
1839 params
[2] <<= seqTypes
;
1841 xInit
->initialize( Sequence
<Any
>( params
, 3));
1842 ComPtrToWrapperMap
[reinterpret_cast<sal_uInt64
>(spUnknown
.p
)] = xIntNewProxy
;
1844 // we have a wrapper object
1845 //The wrapper implements already XInvocation and XInterface. If
1846 //param aType is void then the object is supposed to have XInvocation.
1847 if (aType
== cppu::UnoType
<XInvocation
>::get()||
1848 (aType
== VOID_TYPE
&& seqTypes
.getLength() == 0 ))
1850 ret
= xIntNewProxy
->queryInterface(desiredType
);
1854 Reference
<XInterface
> xIntAdapter
=
1855 createAdapter(seqTypes
, xIntNewProxy
);
1856 ret
= xIntAdapter
->queryInterface(desiredType
);
1861 Reference
<XInterface
> UnoConversionUtilities
<T
>::createAdapter(const Sequence
<Type
>& seqTypes
,
1862 const Reference
<XInterface
>& receiver
)
1864 Reference
< XInterface
> xIntAdapterFac
;
1865 xIntAdapterFac
= m_smgr
->createInstance(INTERFACE_ADAPTER_FACTORY
);
1866 // We create an adapter object that does not only implement the required type but also
1867 // all types that the COM object pretends to implement. A COM object must therefore
1868 // support the property "_implementedInterfaces".
1869 Reference
<XInterface
> xIntAdapted
;
1870 Reference
<XInvocation
> xInv(receiver
, UNO_QUERY
);
1871 Reference
<XInvocationAdapterFactory2
> xAdapterFac( xIntAdapterFac
, UNO_QUERY
);
1872 if( xAdapterFac
.is())
1873 xIntAdapted
= xAdapterFac
->createAdapter( xInv
, seqTypes
);
1875 if( !xIntAdapted
.is())
1877 throw BridgeRuntimeError(
1878 "[automation bridge]UnoConversionUtilities<T>::createOleObjectWrapper \n"
1879 "Could not create a proxy for COM object! Creation of adapter failed.");
1882 // Put the pointer to the wrapper object and the interface pointer of the adapted interface
1883 // in a global map. Thus we can determine in a call to createUnoObjectWrapper whether the UNO
1884 // object is a wrapped COM object. In that case we extract the original COM object rather than
1885 // creating a wrapper around the UNO object.
1886 typedef std::unordered_map
<sal_uInt64
,sal_uInt64
>::value_type VALUE
;
1887 AdapterToWrapperMap
.insert( VALUE( reinterpret_cast<sal_uInt64
>(xIntAdapted
.get()), reinterpret_cast<sal_uInt64
>(receiver
.get())));
1888 WrapperToAdapterMap
.insert( VALUE( reinterpret_cast<sal_uInt64
>(receiver
.get()), reinterpret_cast<sal_uInt64
>(xIntAdapted
.get())));
1892 // "convertValueObject" converts a JScriptValue object contained in "var" into
1893 // an any. The type contained in the any is stipulated by a "type value" thas
1894 // was set within the JScript script on the value object ( see JScriptValue).
1896 bool UnoConversionUtilities
<T
>::convertValueObject( const VARIANTARG
*var
, Any
& any
)
1903 CComVariant varDisp
;
1905 if(SUCCEEDED(hr
= varDisp
.ChangeType( VT_DISPATCH
, var
)))
1907 CComPtr
<IJScriptValueObject
> spValue
;
1908 VARIANT_BOOL varBool
;
1910 CComVariant varValue
;
1911 CComPtr
<IDispatch
> spDisp( varDisp
.pdispVal
);
1914 if(SUCCEEDED( spDisp
->QueryInterface( __uuidof( IJScriptValueObject
),
1915 reinterpret_cast<void**> (&spValue
))))
1917 ret
= true; // is a ValueObject
1918 //If it is an out - param then it does not need to be converted. In/out and
1919 // in params does so.
1920 if (SUCCEEDED(hr
= spValue
->IsOutParam( &varBool
)))
1922 // if varBool == true then no conversion needed because out param
1923 if (varBool
== VARIANT_FALSE
)
1925 if(SUCCEEDED(hr
= spValue
->GetValue( & bstrType
, & varValue
)))
1928 if (getType(bstrType
, type
))
1929 variantToAny( & varValue
, any
, type
);
1942 else if( hr
!= DISP_E_TYPEMISMATCH
&& hr
!= E_NOINTERFACE
)
1946 throw BridgeRuntimeError(
1947 "[automation bridge] Conversion of ValueObject failed ");
1949 catch (const BridgeRuntimeError
&)
1953 catch (const Exception
& e
)
1955 throw BridgeRuntimeError("[automation bridge] unexpected exception in "
1956 "UnoConversionUtilities<T>::convertValueObject ! Message : \n" +
1961 throw BridgeRuntimeError(
1962 "[automation bridge] unexpected exception in "
1963 "UnoConversionUtilities<T>::convertValueObject !");
1969 void UnoConversionUtilities
<T
>::dispatchExObject2Sequence( const VARIANTARG
* pvar
, Any
& anySeq
, const Type
& type
)
1973 if( pvar
->vt
!= VT_DISPATCH
)
1974 throw BridgeRuntimeError("[automation bridge] UnoConversionUtilities<T>::dispatchExObject2Sequence \n"
1975 "Conversion of dispatch object to Sequence failed!");
1976 IDispatchEx
* pdispEx
;
1978 if( FAILED( hr
= pvar
->pdispVal
->QueryInterface( IID_IDispatchEx
,
1979 reinterpret_cast<void**>( &pdispEx
))))
1980 throw BridgeRuntimeError("[automation bridge] UnoConversionUtilities<T>::dispatchExObject2Sequence \n"
1981 "Conversion of dispatch object to Sequence failed!");
1984 DISPPARAMS param
= {nullptr,nullptr,0,0};
1987 OLECHAR
const * sLength
= L
"length";
1989 // Get the length of the array. Can also be obtained through GetNextDispID. The
1990 // method only returns DISPIDs of the array data. Their names are like "0", "1" etc.
1991 if( FAILED( hr
= pdispEx
->GetIDsOfNames(IID_NULL
, const_cast<OLECHAR
**>(&sLength
), 1, LOCALE_USER_DEFAULT
, &dispid
)))
1992 throw BridgeRuntimeError("[automation bridge] UnoConversionUtilities<T>::dispatchExObject2Sequence \n"
1993 "Conversion of dispatch object to Sequence failed!");
1994 if( FAILED( hr
= pdispEx
->InvokeEx(dispid
, LOCALE_USER_DEFAULT
, DISPATCH_PROPERTYGET
,
1995 ¶m
, &result
, nullptr, nullptr)))
1996 throw BridgeRuntimeError("[automation bridge] UnoConversionUtilities<T>::dispatchExObject2Sequence \n"
1997 "Conversion of dispatch object to Sequence failed!");
1998 if( FAILED( VariantChangeType( &result
, &result
, 0, VT_I4
)))
1999 throw BridgeRuntimeError("[automation bridge] UnoConversionUtilities<T>::dispatchExObject2Sequence \n"
2000 "Conversion of dispatch object to Sequence failed!");
2001 LONG length
= result
.lVal
;
2005 // get a few basic facts about the sequence, and reallocate:
2006 // create the Sequences
2007 // get the size of the elements
2008 typelib_TypeDescription
*pDesc
= nullptr;
2009 type
.getDescription( &pDesc
);
2011 typelib_IndirectTypeDescription
*pSeqDesc
= reinterpret_cast<typelib_IndirectTypeDescription
*>(pDesc
);
2012 typelib_TypeDescriptionReference
*pSeqElemDescRef
= pSeqDesc
->pType
; // type of the Sequence' elements
2013 Type
elemType( pSeqElemDescRef
);
2014 _typelib_TypeDescription
* pSeqElemDesc
=nullptr;
2015 TYPELIB_DANGER_GET( &pSeqElemDesc
, pSeqElemDescRef
);
2016 sal_uInt32 nelementSize
= pSeqElemDesc
->nSize
;
2017 TYPELIB_DANGER_RELEASE( pSeqElemDesc
);
2019 uno_Sequence
*p_uno_Seq
;
2020 uno_sequence_construct( &p_uno_Seq
, pDesc
, nullptr, length
, cpp_acquire
);
2022 typelib_TypeClass typeElement
= pSeqDesc
->pType
->eTypeClass
;
2023 char *pArray
= p_uno_Seq
->elements
;
2025 // Get All properties in the object, convert their values to the expected type and
2026 // put them into the passed in sequence
2027 for( sal_Int32 i
= 0; i
< length
; i
++)
2029 OUString ousIndex
=OUString::number( i
);
2030 OLECHAR
* sindex
= const_cast<OLECHAR
*>(o3tl::toW(ousIndex
.getStr()));
2032 if( FAILED( hr
= pdispEx
->GetIDsOfNames(IID_NULL
, &sindex
, 1, LOCALE_USER_DEFAULT
, &dispid
)))
2034 throw BridgeRuntimeError("[automation bridge] UnoConversionUtilities<T>::dispatchExObject2Sequence \n"
2035 "Conversion of dispatch object to Sequence failed!");
2037 if( FAILED( hr
= pdispEx
->InvokeEx(dispid
, LOCALE_USER_DEFAULT
, DISPATCH_PROPERTYGET
,
2038 ¶m
, &result
, nullptr, nullptr)))
2040 throw BridgeRuntimeError("[automation bridge] UnoConversionUtilities<T>::dispatchExObject2Sequence \n"
2041 "Conversion of dispatch object to Sequence failed!");
2044 // If the result is VT_DISPATCH than the Sequence's element type could be Sequence
2045 // Look that up in the CoreReflection to make clear.
2046 // That requires a recursiv conversion
2048 // Destination address within the out-Sequence "anySeq" where to copy the next converted element
2049 void* pDest
= pArray
+ (i
* nelementSize
);
2051 if( result
.vt
& VT_DISPATCH
&& typeElement
== typelib_TypeClass_SEQUENCE
)
2053 variantToAny( &result
, any
, elemType
, false);
2054 // copy the converted VARIANT, that is a Sequence to the Sequence
2055 uno_Sequence
* p_unoSeq
= *static_cast<uno_Sequence
* const *>(any
.getValue());
2056 // just copy the pointer of the uno_Sequence
2057 // nelementSize should be 4 !!!!
2058 memcpy( pDest
, &p_unoSeq
, nelementSize
);
2059 osl_atomic_increment( &p_unoSeq
->nRefCount
);
2061 else // Element type is no Sequence -> do one conversion
2063 variantToAny( &result
, any
, elemType
, false);
2064 if( typeElement
== typelib_TypeClass_ANY
)
2066 // copy the converted VARIANT to the Sequence
2067 uno_type_assignData( pDest
, pSeqElemDescRef
, &any
, pSeqElemDescRef
,cpp_queryInterface
,
2068 cpp_acquire
, cpp_release
);
2072 // type after conversion must be the element type of the sequence
2073 OSL_ENSURE(any
.getValueTypeClass() == css::uno::TypeClass(typeElement
), "wrong conversion");
2074 uno_type_assignData( pDest
, pSeqElemDescRef
,const_cast<void*>( any
.getValue()), any
.getValueTypeRef(),
2075 cpp_queryInterface
, cpp_acquire
, cpp_release
);
2080 anySeq
.setValue( &p_uno_Seq
, pDesc
);
2081 uno_destructData( &p_uno_Seq
, pDesc
, cpp_release
);
2082 typelib_typedescription_release( pDesc
);
2084 catch (const BridgeRuntimeError
&)
2088 catch (const Exception
& e
)
2090 throw BridgeRuntimeError("[automation bridge] unexpected exception in "
2091 "UnoConversionUtilities<T>::convertValueObject ! Message : \n" +
2096 throw BridgeRuntimeError(
2097 "[automation bridge] unexpected exception in "
2098 "UnoConversionUtilities<T>::convertValueObject !");
2102 /* The argument unotype is the type that is expected by the currently called UNO function.
2103 For example: []long, [][]long. If the function calls itself recursively then the element type
2104 is passed on. For example a two dimensional SAFEARRAY of type VT_I4 is to be converted. Then
2105 unotype has to be either void or [][]long. When the function calls itself recursively then
2106 it passes the element type which is []long.
2109 Sequence
<Any
> UnoConversionUtilities
<T
>::createOleArrayWrapperOfDim(SAFEARRAY
* pArray
,
2110 unsigned int dimCount
, unsigned int actDim
, LONG
* index
, VARTYPE type
, const Type
& unotype
)
2114 LONG nCountElements
;
2116 SafeArrayGetLBound(pArray
, actDim
, &lBound
);
2117 SafeArrayGetUBound(pArray
, actDim
, &uBound
);
2118 nCountElements
= uBound
- lBound
+1;
2120 Sequence
<Any
> anySeq(nCountElements
);
2121 Any
* pUnoArray
= anySeq
.getArray();
2123 for (index
[actDim
- 1] = lBound
; index
[actDim
- 1] <= uBound
; index
[actDim
- 1]++)
2127 Sequence
<Any
> element
= createOleArrayWrapperOfDim(pArray
, dimCount
,
2128 actDim
- 1, index
, type
, getElementTypeOfSequence(unotype
));
2130 pUnoArray
[index
[actDim
- 1] - lBound
].setValue(&element
, cppu::UnoType
<decltype(element
)>::get());
2136 VariantInit(&variant
);
2138 V_VT(&variant
) = type
;
2143 SafeArrayGetElement(pArray
, index
, &V_I2(&variant
));
2146 SafeArrayGetElement(pArray
, index
, &V_I4(&variant
));
2149 SafeArrayGetElement(pArray
, index
, &V_R4(&variant
));
2152 SafeArrayGetElement(pArray
, index
, &V_R8(&variant
));
2155 SafeArrayGetElement(pArray
, index
, &V_CY(&variant
));
2158 SafeArrayGetElement(pArray
, index
, &V_DATE(&variant
));
2161 SafeArrayGetElement(pArray
, index
, &V_BSTR(&variant
));
2164 SafeArrayGetElement(pArray
, index
, &V_DISPATCH(&variant
));
2167 SafeArrayGetElement(pArray
, index
, &V_ERROR(&variant
));
2170 SafeArrayGetElement(pArray
, index
, &V_BOOL(&variant
));
2173 SafeArrayGetElement(pArray
, index
, &variant
);
2176 SafeArrayGetElement(pArray
, index
, &V_UNKNOWN(&variant
));
2179 SafeArrayGetElement(pArray
, index
, &V_I1(&variant
));
2182 SafeArrayGetElement(pArray
, index
, &V_UI1(&variant
));
2185 SafeArrayGetElement(pArray
, index
, &V_UI2(&variant
));
2188 SafeArrayGetElement(pArray
, index
, &V_UI4(&variant
));
2194 if( unotype
.getTypeClass() == TypeClass_VOID
)
2195 // the function was called without specifying the destination type
2196 variantToAny(&variant
, pUnoArray
[index
[actDim
- 1] - lBound
], false);
2198 variantToAny(&variant
, pUnoArray
[index
[actDim
- 1] - lBound
],
2199 getElementTypeOfSequence(unotype
), false);
2201 VariantClear(&variant
);
2208 Type UnoConversionUtilities
<T
>::getElementTypeOfSequence( const Type
& seqType
)
2211 if( seqType
.getTypeClass() != TypeClass_VOID
)
2213 OSL_ASSERT( seqType
.getTypeClass() == TypeClass_SEQUENCE
);
2214 typelib_TypeDescription
* pDescSeq
= nullptr;
2215 seqType
.getDescription(& pDescSeq
);
2216 retValue
= Type(reinterpret_cast<typelib_IndirectTypeDescription
*>(pDescSeq
)->pType
);
2217 typelib_typedescription_release(pDescSeq
);
2222 Sequence
<Any
> UnoConversionUtilities
<T
>::createOleArrayWrapper(SAFEARRAY
* pArray
, VARTYPE type
, const Type
& unoType
)
2224 sal_uInt32 dim
= SafeArrayGetDim(pArray
);
2230 std::unique_ptr
<LONG
[]> sarIndex(new LONG
[dim
]);
2231 LONG
* index
= sarIndex
.get();
2233 for (unsigned int i
= 0; i
< dim
; i
++)
2238 ret
= createOleArrayWrapperOfDim(pArray
, dim
, dim
, index
, type
, unoType
);
2244 // If a VARIANT has the type VT_DISPATCH it can either be a JScript Array
2245 // or some other object. This function finds out if it is such an array or
2246 // not. Currently there's no way to make sure it's an array
2247 // so we assume that when the object has a property "0" then it is an Array.
2248 // A JScript has property like "0", "1", "2" etc. which represent the
2249 // value at the corresponding index of the array
2251 bool UnoConversionUtilities
<T
>::isJScriptArray(const VARIANT
* rvar
)
2253 OSL_ENSURE( rvar
->vt
== VT_DISPATCH
, "param is not a VT_DISPATCH");
2255 OLECHAR
const * sindex
= L
"0";
2257 if ( rvar
->vt
== VT_DISPATCH
&& rvar
->pdispVal
)
2259 hr
= rvar
->pdispVal
->GetIDsOfNames(
2260 IID_NULL
, const_cast<OLECHAR
**>(&sindex
), 1, LOCALE_USER_DEFAULT
,
2263 if( SUCCEEDED ( hr
) )
2271 VARTYPE UnoConversionUtilities
<T
>::mapTypeClassToVartype( TypeClass type
)
2276 case TypeClass_INTERFACE
: ret
= VT_DISPATCH
;
2278 case TypeClass_STRUCT
: ret
= VT_DISPATCH
;
2280 case TypeClass_ENUM
: ret
= VT_I4
;
2282 case TypeClass_SEQUENCE
: ret
= VT_ARRAY
;
2284 case TypeClass_ANY
: ret
= VT_VARIANT
;
2286 case TypeClass_BOOLEAN
: ret
= VT_BOOL
;
2288 case TypeClass_CHAR
: ret
= VT_I2
;
2290 case TypeClass_STRING
: ret
= VT_BSTR
;
2292 case TypeClass_FLOAT
: ret
= VT_R4
;
2294 case TypeClass_DOUBLE
: ret
= VT_R8
;
2296 case TypeClass_BYTE
: ret
= VT_UI1
;
2298 case TypeClass_SHORT
: ret
= VT_I2
;
2300 case TypeClass_LONG
: ret
= VT_I4
;
2302 case TypeClass_UNSIGNED_SHORT
: ret
= VT_UI2
;
2304 case TypeClass_UNSIGNED_LONG
: ret
= VT_UI4
;
2313 Sequence
<Type
> UnoConversionUtilities
<T
>::getImplementedInterfaces(IUnknown
* pUnk
)
2315 Sequence
<Type
> seqTypes
;
2316 CComDispatchDriver
disp( pUnk
);
2321 // There are two different property names possible.
2322 if( FAILED( hr
= disp
.GetPropertyByName( SUPPORTED_INTERFACES_PROP
, &var
)))
2324 hr
= disp
.GetPropertyByName( SUPPORTED_INTERFACES_PROP2
, &var
);
2328 // we expect an array( SafeArray or IDispatch) of Strings.
2330 variantToAny( &var
, anyNames
, cppu::UnoType
<Sequence
<Any
>>::get());
2331 Sequence
<Any
> seqAny
;
2332 if( anyNames
>>= seqAny
)
2334 seqTypes
.realloc( seqAny
.getLength());
2335 auto pseqTypes
= seqTypes
.getArray();
2336 for( sal_Int32 i
=0; i
< seqAny
.getLength(); i
++)
2339 seqAny
[i
] >>= typeName
;
2340 pseqTypes
[i
]= Type( TypeClass_INTERFACE
, typeName
);
2348 Reference
<XTypeConverter
> UnoConversionUtilities
<T
>::getTypeConverter()
2350 if ( ! m_typeConverter
.is())
2352 MutexGuard
guard(getBridgeMutex());
2353 if ( ! m_typeConverter
.is())
2355 Reference
<XInterface
> xIntConverter
=
2356 m_smgr
->createInstance("com.sun.star.script.Converter");
2357 if (xIntConverter
.is())
2358 m_typeConverter
.set(xIntConverter
, UNO_QUERY
);
2361 return m_typeConverter
;
2364 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */