1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
11 * OpenOffice.org is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License version 3
13 * only, as published by the Free Software Foundation.
15 * OpenOffice.org is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License version 3 for more details
19 * (a copy is included in the LICENSE file that accompanied this code).
21 * You should have received a copy of the GNU Lesser General Public License
22 * version 3 along with OpenOffice.org. If not, see
23 * <http://www.openoffice.org/license.html>
24 * for a copy of the LGPLv3 License.
26 ************************************************************************/
27 #ifndef _UNO_CONVERSION_UTILITIES
28 #define _UNO_CONVERSION_UTILITIES
30 #include "boost/scoped_array.hpp"
31 #include "com/sun/star/script/XInvocationAdapterFactory.hpp"
32 #include "com/sun/star/script/XInvocationAdapterFactory2.hpp"
33 #include "com/sun/star/script/XTypeConverter.hpp"
34 #include "com/sun/star/script/FailReason.hpp"
35 #include "com/sun/star/bridge/oleautomation/Date.hpp"
36 #include "com/sun/star/bridge/oleautomation/Currency.hpp"
37 #include "com/sun/star/bridge/oleautomation/SCode.hpp"
38 #include "com/sun/star/bridge/oleautomation/Decimal.hpp"
39 #include "typelib/typedescription.hxx"
40 #include "ole2uno.hxx"
42 #include "unotypewrapper.hxx"
45 // for some reason DECIMAL_NEG (wtypes.h) which contains BYTE is not resolved.
46 typedef unsigned char BYTE
;
47 // classes for wrapping uno objects
48 #define INTERFACE_OLE_WRAPPER_IMPL 1
49 #define UNO_OBJECT_WRAPPER_REMOTE_OPT 2
51 #define INVOCATION_SERVICE reinterpret_cast<const sal_Unicode*>(L"com.sun.star.script.Invocation")
54 // classes for wrapping ole objects
55 #define IUNKNOWN_WRAPPER_IMPL 1
57 #define INTERFACE_ADAPTER_FACTORY reinterpret_cast<const sal_Unicode*>(L"com.sun.star.script.InvocationAdapterFactory")
58 // COM or JScript objects implementing UNO interfaces have to implement this property
59 #define SUPPORTED_INTERFACES_PROP L"_implementedInterfaces"
60 // Second property without leading underscore for use in VB
61 #define SUPPORTED_INTERFACES_PROP2 L"Bridge_ImplementedInterfaces"
63 using namespace com::sun::star::script
;
64 using namespace com::sun::star::beans
;
65 using namespace com::sun::star::uno
;
67 using namespace com::sun::star::bridge
;
68 using namespace com::sun::star::bridge::ModelDependent
;
70 using namespace com::sun::star::bridge::oleautomation
;
71 using namespace boost
;
74 extern hash_map
<sal_uInt32
, sal_uInt32
> AdapterToWrapperMap
;
75 extern hash_map
<sal_uInt32
, sal_uInt32
> WrapperToAdapterMap
;
76 typedef hash_map
<sal_uInt32
, sal_uInt32
>::iterator IT_Wrap
;
77 typedef hash_map
<sal_uInt32
, sal_uInt32
>::iterator CIT_Wrap
;
78 //Maps IUnknown pointers to a weak reference of the respective wrapper class (e.g.
79 // IUnknownWrapperImpl. It is the responsibility of the wrapper to remove the entry when
80 // it is being destroyed.
81 // Used to ensure that an Automation object is always mapped to the same UNO objects.
82 extern hash_map
<sal_uInt32
, WeakReference
<XInterface
> > ComPtrToWrapperMap
;
83 typedef hash_map
<sal_uInt32
, WeakReference
<XInterface
> >::iterator IT_Com
;
84 typedef hash_map
<sal_uInt32
, WeakReference
<XInterface
> >::const_iterator CIT_Com
;
86 // Maps XInterface pointers to a weak reference of its wrapper class (i.e.
87 // InterfaceOleWrapper_Impl). It is the responsibility of the wrapper to remove the entry when
88 // it is being destroyed. It is used to ensure the identity of objects. That is, an UNO interface
89 // is mapped to IDispatch which is kept alive in the COM environment. If the same
90 // UNO interface is mapped again to COM then the IDispach of the first mapped instance
92 extern hash_map
<sal_uInt32
, WeakReference
<XInterface
> > UnoObjToWrapperMap
;
93 typedef hash_map
<sal_uInt32
, WeakReference
<XInterface
> >::iterator IT_Uno
;
94 typedef hash_map
<sal_uInt32
, WeakReference
<XInterface
> >::const_iterator CIT_Uno
;
96 inline void reduceRange( Any
& any
);
102 // createUnoObjectWrapper gets a wrapper instance by calling createUnoWrapperInstance
103 // and initializes it via XInitialization. The wrapper object is required to implement
104 // XBridgeSupplier so that it can convert itself to IDispatch.
105 // class T: Deriving class ( must implement XInterface )
106 /** All methods are allowed to throw at least a BridgeRuntimeError.
109 class UnoConversionUtilities
112 UnoConversionUtilities( const Reference
<XMultiServiceFactory
> & smgr
):
113 m_nUnoWrapperClass( INTERFACE_OLE_WRAPPER_IMPL
),
114 m_nComWrapperClass( IUNKNOWN_WRAPPER_IMPL
),
118 UnoConversionUtilities( const Reference
<XMultiServiceFactory
> & xFactory
, sal_uInt8 unoWrapperClass
, sal_uInt8 comWrapperClass
)
119 : m_smgr( xFactory
), m_nComWrapperClass( comWrapperClass
), m_nUnoWrapperClass( unoWrapperClass
)
122 virtual ~UnoConversionUtilities() {}
123 /** converts only into oleautomation types, that is there is no VT_I1, VT_UI2, VT_UI4
124 a sal_Unicode character is converted into a BSTR.
125 @exception com.sun.star.lang.IllegalArgumentException
126 If the any was inappropriate for conversion.
127 @exception com.sun.star.script.CannotConvertException
128 The any contains a type class for which no conversion is provided.
130 void anyToVariant(VARIANT
* pVariant
, const Any
& rAny
);
131 void anyToVariant(VARIANT
* pVariant
, const Any
& rAny
, VARTYPE type
);
133 /** @exception com.sun.star.lang.IllegalArgumentException
134 If rSeq does not contain a sequence then the exception is thrown.
136 SAFEARRAY
* createUnoSequenceWrapper(const Any
& rSeq
);
137 /** @exception com.sun.star.lang.IllegalArgumentException
138 If rSeq does not contain a sequence or elemtype has no proper value
139 then the exception is thrown.
141 SAFEARRAY
* createUnoSequenceWrapper(const Any
& rSeq
, VARTYPE elemtype
);
143 @exception com.sun.star.lang.IllegalArgumentException
144 If rObj does not contain a struct or interface
146 void createUnoObjectWrapper(const Any
& rObj
, VARIANT
* pVar
);
147 /** @exception CannotConvertException
148 Thrown if the VARIANT contains a type that cannot be coerced in the expected Any.
150 @IllegalArgumentException
151 Thrown if the VARIANT is inappropriate for conversion. ArgumentPosition is -1,
153 void variantToAny(const VARIANT
* pVariant
, Any
& rAny
, sal_Bool bReduceValueRange
= sal_True
);
154 /** This method converts variants arguments in calls from COM -> UNO. Only then
155 the expected UNO type is known.
156 @exception CannotConvertException
157 Thrown if the VARIANT contains a type that cannot be coerced in the expected Any.
159 @IllegalArgumentException
160 Thrown if the VARIANT is inappropriate for conversion. ArgumentPosition is -1,
162 void variantToAny( const VARIANTARG
* pArg
, Any
& rAny
, const Type
& ptype
, sal_Bool bReduceValueRange
= sal_True
);
165 @exception IllegalArgumentException
166 -if pVar does not contain VT_UNKNOWN or VT_DISPATCH or
167 pVar is used for a particular UNO type which is not supported by pVar
169 Any
createOleObjectWrapper(VARIANT
* pVar
, const Type
& aType
= Type());
172 Return true means var contained a ValueObject, and it was successfully converted.
173 The result is in any. It an error occurred a BridgeRuntimeError will be thrown.
175 bool convertValueObject( const VARIANTARG
*var
, Any
& any
);
176 void dispatchExObject2Sequence( const VARIANTARG
* pvar
, Any
& anySeq
, const Type
& type
);
178 Sequence
<Any
> createOleArrayWrapperOfDim(SAFEARRAY
* pArray
, unsigned int dimCount
, unsigned int actDim
, long* index
,
179 VARTYPE type
, const Type
& unotype
);
180 Sequence
<Any
> createOleArrayWrapper(SAFEARRAY
* pArray
, VARTYPE type
, const Type
& unotype
= Type());
183 VARTYPE
mapTypeClassToVartype( TypeClass type
);
184 Reference
< XSingleServiceFactory
> getInvocationFactory(const Any
& anyObject
);
187 virtual Reference
< XInterface
> createUnoWrapperInstance()=0;
188 virtual Reference
< XInterface
> createComWrapperInstance()=0;
190 static sal_Bool
isJScriptArray(const VARIANT
* pvar
);
192 Sequence
<Type
> getImplementedInterfaces(IUnknown
* pUnk
);
195 Reference
<XInterface
> createAdapter(const Sequence
<Type
>& types
, const Reference
<XInterface
>& receiver
);
197 // helper function for Sequence conversion
198 void getElementCountAndTypeOfSequence( const Any
& rSeq
, sal_Int32 dim
, Sequence
< sal_Int32
>& seqElementCounts
, TypeDescription
& typeDesc
);
199 // helper function for Sequence conversion
200 sal_Bool
incrementMultidimensionalIndex(sal_Int32 dimensions
, const sal_Int32
* parDimensionLength
,
201 sal_Int32
* parMultidimensionalIndex
);
202 // helper function for Sequence conversion
203 size_t getOleElementSize( VARTYPE type
);
205 Type
getElementTypeOfSequence( const Type
& seqType
);
207 //Provides a typeconverter
208 Reference
<XTypeConverter
> getTypeConverter();
210 // This member determines what class is used to convert a UNO object
211 // or struct to a COM object. It is passed along to the o2u_anyToVariant
212 // function in the createBridge function implementation
213 sal_uInt8 m_nUnoWrapperClass
;
214 sal_uInt8 m_nComWrapperClass
;
216 // The servicemanager is either a local smgr or remote when the service
217 // com.sun.star.bridge.OleBridgeSupplierVar1 is used. This service can be
218 // created by createInstanceWithArguments where one can supply a service
219 // manager that is to be used.
220 // Local service manager as supplied by the loader when the creator function
221 // of the service is being called.
222 Reference
<XMultiServiceFactory
> m_smgr
;
223 // An explicitly supplied service manager when the service
224 // com.sun.star.bridge.OleBridgeSupplierVar1 is used. That can be a remote
226 Reference
<XMultiServiceFactory
> m_smgrRemote
;
227 Reference
<XSingleServiceFactory
> m_xInvocationFactoryLocal
;
228 Reference
<XSingleServiceFactory
> m_xInvocationFactoryRemote
;
231 // Holds the type converter which is used for sequence conversion etc.
232 // Use the getTypeConverter function to obtain the interface.
233 Reference
<XTypeConverter
> m_typeConverter
;
238 // ask the object for XBridgeSupplier2 and on success bridges
239 // the uno object to IUnknown or IDispatch.
240 // return true the UNO object supports
242 bool convertSelfToCom( T
& unoInterface
, VARIANT
* pVar
)
245 Reference
< XInterface
> xInt( unoInterface
, UNO_QUERY
);
248 Reference
< XBridgeSupplier2
> xSupplier( xInt
, UNO_QUERY
);
252 rtl_getGlobalProcessId( (sal_uInt8
*)arId
);
253 Sequence
<sal_Int8
> seqId( arId
, 16);
256 Any anyDisp
= xSupplier
->createBridge( anySource
, seqId
, UNO
, OLE
);
257 if( anyDisp
.getValueTypeClass() == TypeClass_UNSIGNED_LONG
)
259 VARIANT
* pvariant
= *(VARIANT
**)anyDisp
.getValue();
261 if (FAILED(hr
= VariantCopy(pVar
, pvariant
)))
262 throw BridgeRuntimeError(
263 OUSTR("[automation bridge] convertSelfToCom\n"
264 "VariantCopy failed! Error: ") +
265 OUString::valueOf(hr
));
266 VariantClear( pvariant
);
267 CoTaskMemFree( pvariant
);
277 // Gets the invocation factory depending on the Type in the Any.
278 // The factory can be created by a local or remote multi service factory.
279 // In case there is a remote multi service factory available there are
280 // some services or types for which the local factory is used. The exceptions
282 // Param anyObject - contains the object ( interface, struct) for what we need an invocation object.
285 Reference
< XSingleServiceFactory
> UnoConversionUtilities
<T
>::getInvocationFactory(const Any
& anyObject
)
287 Reference
< XSingleServiceFactory
> retVal
;
288 MutexGuard
guard( getBridgeMutex());
289 if( anyObject
.getValueTypeClass() != TypeClass_STRUCT
&&
292 if( ! m_xInvocationFactoryRemote
.is() )
293 m_xInvocationFactoryRemote
= Reference
<XSingleServiceFactory
>(
294 m_smgrRemote
->createInstance( INVOCATION_SERVICE
), UNO_QUERY
);
295 retVal
= m_xInvocationFactoryRemote
;
299 if( ! m_xInvocationFactoryLocal
.is() )
300 m_xInvocationFactoryLocal
= Reference
<XSingleServiceFactory
>(
301 m_smgr
->createInstance(INVOCATION_SERVICE
), UNO_QUERY
);
302 retVal
= m_xInvocationFactoryLocal
;
308 void UnoConversionUtilities
<T
>::variantToAny( const VARIANTARG
* pArg
, Any
& rAny
, const Type
& ptype
, sal_Bool bReduceValueRange
/* = sal_True */)
314 bool bCannotConvert
= false;
317 // There is no need to support indirect values, since they're not supported by UNO
318 if( FAILED(hr
= VariantCopyInd( &var
, const_cast<VARIANTARG
*>(pArg
)))) // remove VT_BYREF
319 throw BridgeRuntimeError(
320 OUSTR("[automation bridge] UnoConversionUtilities<T>::variantToAny \n"
321 "VariantCopyInd failed for reason : ") + OUString::valueOf(hr
));
322 bool bHandled
= convertValueObject( & var
, rAny
);
324 OSL_ENSURE( rAny
.getValueType() == ptype
, "type in Value Object must match the type parameter");
328 // convert into a variant type that is the equivalent to the type
329 // the sequence expects. Thus variantToAny produces the correct type
330 // E.g. An Array object contains VT_I4 and the sequence expects shorts
331 // than the vartype must be changed. The reason is, you can't specify the
332 // type in JavaScript and the script engine determines the type beeing used.
333 switch( ptype
.getTypeClass())
335 case TypeClass_CHAR
: // could be: new Array( 12, 'w', "w")
336 if( var
.vt
== VT_BSTR
)
338 if(SUCCEEDED( hr
= VariantChangeType( &var
, &var
, 0, VT_BSTR
)))
339 rAny
.setValue( (void*)V_BSTR( &var
), ptype
);
340 else if (hr
== DISP_E_TYPEMISMATCH
)
341 bCannotConvert
= true;
347 if(SUCCEEDED(hr
= VariantChangeType( & var
, &var
, 0, VT_I2
)))
348 rAny
.setValue((void*) & var
.iVal
, ptype
);
349 else if (hr
== DISP_E_TYPEMISMATCH
)
350 bCannotConvert
= true;
355 case TypeClass_INTERFACE
: // could also be an IUnknown
356 case TypeClass_STRUCT
:
358 rAny
= createOleObjectWrapper( & var
, ptype
);
362 if(SUCCEEDED(hr
= VariantChangeType( & var
, &var
, 0, VT_I4
)))
363 rAny
.setValue((void*) & var
.lVal
, ptype
);
364 else if (hr
== DISP_E_TYPEMISMATCH
)
365 bCannotConvert
= true;
369 case TypeClass_SEQUENCE
:
370 // There are different ways of receiving a sequence:
371 // 1: JScript, VARTYPE: VT_DISPATCH
372 // 2. VBScript simple arraysVT_VARIANT|VT_BYREF the referenced VARIANT contains
373 // a VT_ARRAY| <type>
374 // 3. VBSrcript multi dimensional arrays: VT_ARRAY|VT_BYREF
375 if( pArg
->vt
== VT_DISPATCH
)
377 dispatchExObject2Sequence( pArg
, rAny
, ptype
);
381 if ((var
.vt
& VT_ARRAY
) != 0)
383 VARTYPE oleType
= ::sal::static_int_cast
< VARTYPE
, int >( var
.vt
^ VT_ARRAY
);
384 Sequence
<Any
> unoSeq
= createOleArrayWrapper( var
.parray
, oleType
, ptype
);
385 Reference
<XTypeConverter
> conv
= getTypeConverter();
390 Any anySeq
= makeAny(unoSeq
);
391 Any convAny
= conv
->convertTo(anySeq
, ptype
);
394 catch (IllegalArgumentException
& e
)
396 throw BridgeRuntimeError(
397 OUSTR("[automation bridge]com.sun.star.lang.IllegalArgumentException "
398 "in UnoConversionUtilities<T>::variantToAny! Message: ") +
401 catch (CannotConvertException
& e
)
403 throw BridgeRuntimeError(
404 OUSTR("[automation bridge]com.sun.star.script.CannotConvertException "
405 "in UnoConversionUtilities<T>::variantToAny! Message: ") +
413 rAny
.setValue(NULL
,Type());
415 case TypeClass_ANY
: // Any
416 // There could be a JScript Array that needs special handling
417 // If an Any is expected and this Any must contain a Sequence
418 // then we cannot figure out what element type is required.
419 // Therefore we convert to Sequence< Any >
420 if( pArg
->vt
== VT_DISPATCH
&& isJScriptArray( pArg
))
422 dispatchExObject2Sequence( pArg
, rAny
,
423 getCppuType((Sequence
<Any
>*) 0));
425 else if (pArg
->vt
== VT_DECIMAL
)
427 //Decimal maps to hyper in calls from COM -> UNO
428 // It does not matter if we create a sal_uInt64 or sal_Int64,
429 // because the UNO object is called through invocation which
430 //will do a type conversion if necessary
431 if (var
.decVal
.sign
== 0)
434 variantToAny( & var
, rAny
, getCppuType( (sal_uInt64
*) 0),
440 variantToAny( & var
, rAny
, getCppuType( (sal_Int64
*) 0),
446 variantToAny( & var
, rAny
);
449 case TypeClass_BOOLEAN
: // VARIANT could be VARIANT_BOOL or other
450 if(SUCCEEDED(hr
= VariantChangeType( & var
, &var
, 0, VT_BOOL
)))
451 variantToAny( & var
, rAny
);
452 else if (hr
== DISP_E_TYPEMISMATCH
)
453 bCannotConvert
= true;
457 case TypeClass_STRING
: // UString
458 if(SUCCEEDED(hr
= VariantChangeType( & var
, &var
, 0, VT_BSTR
)))
459 variantToAny( & var
, rAny
);
460 else if (hr
== DISP_E_TYPEMISMATCH
)
461 bCannotConvert
= true;
465 case TypeClass_FLOAT
: // float
466 if(SUCCEEDED(hr
= VariantChangeType( & var
, &var
, 0, VT_R4
)))
467 variantToAny( & var
, rAny
);
468 else if (hr
== DISP_E_TYPEMISMATCH
)
469 bCannotConvert
= true;
473 case TypeClass_DOUBLE
: // double
474 if(SUCCEEDED(hr
= VariantChangeType( & var
, &var
, 0, VT_R8
)))
475 variantToAny(& var
, rAny
);
476 else if (hr
== DISP_E_TYPEMISMATCH
)
477 bCannotConvert
= true;
481 case TypeClass_BYTE
: // BYTE
482 if(SUCCEEDED(hr
= VariantChangeType( & var
, &var
, 0, VT_I1
)))
483 variantToAny( & var
, rAny
);
484 else if (hr
== DISP_E_TYPEMISMATCH
)
485 bCannotConvert
= true;
489 case TypeClass_SHORT
: // INT16
490 if(SUCCEEDED(hr
= VariantChangeType( & var
, &var
, 0, VT_I2
)))
491 variantToAny( & var
, rAny
);
492 else if (hr
== DISP_E_TYPEMISMATCH
)
493 bCannotConvert
= true;
498 if(SUCCEEDED(hr
= VariantChangeType(& var
, &var
, 0, VT_I4
)))
499 variantToAny( & var
, rAny
, bReduceValueRange
);
500 else if (hr
== DISP_E_TYPEMISMATCH
)
501 bCannotConvert
= true;
505 case TypeClass_HYPER
:
506 if(SUCCEEDED(hr
= VariantChangeType(& var
, &var
, 0, VT_DECIMAL
)))
508 if (var
.decVal
.Lo64
> SAL_CONST_UINT64(0x8000000000000000)
509 || var
.decVal
.Hi32
> 0
510 || var
.decVal
.scale
> 0)
515 sal_Int64 value
= var
.decVal
.Lo64
;
516 if (var
.decVal
.sign
== DECIMAL_NEG
)
517 value
|= SAL_CONST_UINT64(0x8000000000000000);
520 else if (hr
== DISP_E_TYPEMISMATCH
)
521 bCannotConvert
= true;
525 case TypeClass_UNSIGNED_SHORT
: // UINT16
526 if(SUCCEEDED(hr
= VariantChangeType( & var
, &var
, 0, VT_UI2
)))
527 variantToAny( & var
, rAny
);
528 else if (hr
== DISP_E_TYPEMISMATCH
)
529 bCannotConvert
= true;
533 case TypeClass_UNSIGNED_LONG
:
534 if(SUCCEEDED(hr
= VariantChangeType( & var
, &var
, 0, VT_UI4
)))
535 variantToAny( & var
, rAny
, bReduceValueRange
);
536 else if (hr
== DISP_E_TYPEMISMATCH
)
537 bCannotConvert
= true;
541 case TypeClass_UNSIGNED_HYPER
:
542 if(SUCCEEDED(hr
= VariantChangeType(& var
, &var
, 0, VT_DECIMAL
)))
544 if (var
.decVal
.Hi32
> 0 || var
.decVal
.scale
> 0)
549 rAny
<<= var
.decVal
.Lo64
;
551 else if (hr
== DISP_E_TYPEMISMATCH
)
552 bCannotConvert
= true;
557 if(SUCCEEDED(hr
= VariantChangeType(& var
, &var
, 0, VT_UNKNOWN
)))
558 variantToAny( & var
, rAny
);
559 else if (hr
== DISP_E_TYPEMISMATCH
)
560 bCannotConvert
= true;
565 // case TypeClass_SERVICE: break; // meta construct
566 // case TypeClass_TYPEDEF: break;
567 // case TypeClass_UNION: break;
568 // case TypeClass_MODULE: break; // module
569 // case TypeClass_EXCEPTION: break;
570 // case TypeClass_ARRAY: break; // there's no Array at the moment
571 // case TypeClass_UNKNOWN: break;
572 bCannotConvert
= true;
577 throw CannotConvertException(
578 OUSTR("[automation bridge]UnoConversionUtilities<T>::variantToAny \n"
579 "Cannot convert the value of vartype :\"") +
580 OUString::valueOf((sal_Int32
) var
.vt
) +
581 OUSTR("\" to the expected UNO type of type class: ") +
582 OUString::valueOf((sal_Int32
) ptype
.getTypeClass()),
583 0, TypeClass_UNKNOWN
, FailReason::TYPE_NOT_SUPPORTED
,0);
586 throw IllegalArgumentException(
587 OUSTR("[automation bridge]UnoConversionUtilities<T>:variantToAny\n"
588 "The provided VARIANT of type\" ") + OUString::valueOf((sal_Int32
) var
.vt
) +
589 OUSTR("\" is unappropriate for conversion!"), Reference
<XInterface
>(), -1);
591 catch (CannotConvertException
&)
595 catch (IllegalArgumentException
&)
599 catch (BridgeRuntimeError
&)
603 catch (Exception
& e
)
605 throw BridgeRuntimeError(OUSTR("[automation bridge] unexpected exception in "
606 "UnoConversionUtilities<T>::variantToAny ! Message : \n") +
611 throw BridgeRuntimeError(
612 OUSTR("[automation bridge] unexpected exception in "
613 "UnoConversionUtilities<T>::variantToAny !"));
617 // The function only converts Sequences to SAFEARRAYS with elements of the type
618 // specified by the parameter type. Everything else is forwarded to
619 // anyToVariant(VARIANT* pVariant, const Any& rAny)
620 // Param type must not be VT_BYREF
622 void UnoConversionUtilities
<T
>::anyToVariant(VARIANT
* pVariant
, const Any
& rAny
, VARTYPE type
)
628 OSL_ASSERT( (type
& VT_BYREF
) == 0);
632 SAFEARRAY
* ar
= createUnoSequenceWrapper( rAny
, type
);
635 VariantClear( pVariant
);
636 pVariant
->vt
= ::sal::static_int_cast
< VARTYPE
, int >( VT_ARRAY
| type
);
640 else if(type
== VT_VARIANT
)
642 anyToVariant(pVariant
, rAny
);
647 anyToVariant( &var
, rAny
);
648 if(FAILED(hr
= VariantChangeType(&var
, &var
, 0, type
)))
650 if (hr
== DISP_E_TYPEMISMATCH
)
651 throw CannotConvertException(
652 OUSTR("[automation bridge]UnoConversionUtilities<T>::anyToVariant \n"
653 "Cannot convert the value of type :\"") +
654 rAny
.getValueTypeName() +
655 OUSTR("\" to the expected Automation type of VARTYPE: ") +
656 OUString::valueOf((sal_Int32
)type
),
657 0, TypeClass_UNKNOWN
, FailReason::TYPE_NOT_SUPPORTED
,0);
659 throw BridgeRuntimeError(
660 OUSTR("[automation bridge]UnoConversionUtilities<T>::anyToVariant \n"
661 "Conversion of any with ") +
662 rAny
.getValueType().getTypeName() +
663 OUSTR(" to VARIANT with type: ") + OUString::valueOf((sal_Int32
) type
) +
664 OUSTR(" failed! Error code: ") + OUString::valueOf(hr
));
667 if(FAILED(hr
= VariantCopy(pVariant
, &var
)))
669 throw BridgeRuntimeError(
670 OUSTR("[automation bridge]UnoConversionUtilities<T>::anyToVariant \n"
671 "VariantCopy failed for reason: ") + OUString::valueOf(hr
));
675 catch (IllegalArgumentException
&)
679 catch (CannotConvertException
& )
683 catch (BridgeRuntimeError
&)
689 throw BridgeRuntimeError(
690 OUSTR("[automation bridge]UnoConversionUtilities<T>::anyToVariant \n"
691 "Unexpected exception occurred. Message: ") + e
.Message
);
695 throw BridgeRuntimeError(
696 OUSTR("[automation bridge]UnoConversionUtilities<T>::anyToVariant \n"
697 "Unexpected exception occurred."));
702 void UnoConversionUtilities
<T
>::anyToVariant(VARIANT
* pVariant
, const Any
& rAny
)
704 bool bIllegal
= false;
707 switch (rAny
.getValueTypeClass())
709 case TypeClass_INTERFACE
:
711 Reference
<XInterface
> xInt
;
714 createUnoObjectWrapper(rAny
, pVariant
);
722 case TypeClass_STRUCT
:
724 if (rAny
.getValueType() == getCppuType((Date
*)0))
729 pVariant
->vt
= VT_DATE
;
730 pVariant
->date
= d
.Value
;
737 else if(rAny
.getValueType() == getCppuType((Decimal
*)0))
742 pVariant
->vt
= VT_DECIMAL
;
743 pVariant
->decVal
.scale
= d
.Scale
;
744 pVariant
->decVal
.sign
= d
.Sign
;
745 pVariant
->decVal
.Lo32
= d
.LowValue
;
746 pVariant
->decVal
.Mid32
= d
.MiddleValue
;
747 pVariant
->decVal
.Hi32
= d
.HighValue
;
754 else if (rAny
.getValueType() == getCppuType((Currency
*)0))
759 pVariant
->vt
= VT_CY
;
760 pVariant
->cyVal
.int64
= c
.Value
;
767 else if(rAny
.getValueType() == getCppuType((SCode
*)0))
772 pVariant
->vt
= VT_ERROR
;
773 pVariant
->scode
= s
.Value
;
782 createUnoObjectWrapper(rAny
, pVariant
);
786 case TypeClass_SEQUENCE
: // sequence ??? SafeArray descriptor
788 SAFEARRAY
* pArray
= createUnoSequenceWrapper(rAny
);
791 V_VT(pVariant
) = VT_ARRAY
| VT_VARIANT
;
792 V_ARRAY(pVariant
) = pArray
;
803 if (FAILED(hr
= VariantClear(pVariant
)))
805 throw BridgeRuntimeError(
806 OUSTR("[automation bridge]UnoConversionUtilities<T>::anyToVariant\n"
807 "VariantClear failed with error:") + OUString::valueOf(hr
));
811 case TypeClass_BOOLEAN
:
816 pVariant
->vt
= VT_BOOL
;
817 pVariant
->boolVal
= value
== sal_True
? VARIANT_TRUE
: VARIANT_FALSE
;
827 // Because VT_UI2 does not conform to oleautomation we convert into VT_I2 instead
828 sal_uInt16 value
= *(sal_Unicode
*) rAny
.getValue();
829 pVariant
->vt
= VT_I2
;
830 pVariant
->iVal
= value
;
833 case TypeClass_STRING
:
838 pVariant
->vt
= VT_BSTR
;
839 pVariant
->bstrVal
= SysAllocString(reinterpret_cast<LPCOLESTR
>(value
.getStr()));
847 case TypeClass_FLOAT
:
852 pVariant
->vt
= VT_R4
;
853 pVariant
->fltVal
= value
;
861 case TypeClass_DOUBLE
:
866 pVariant
->vt
= VT_R8
;
867 pVariant
->dblVal
= value
;
877 // ole automation does not know a signed char but only unsigned char
881 pVariant
->vt
= VT_UI1
;
882 pVariant
->bVal
= value
;
890 case TypeClass_SHORT
: // INT16
891 case TypeClass_UNSIGNED_SHORT
: // UINT16
896 pVariant
->vt
= VT_I2
;
897 pVariant
->iVal
= value
;
907 sal_Int32 value
= *(sal_Int32
*) rAny
.getValue();
908 pVariant
->vt
= VT_I4
;
909 pVariant
->lVal
= value
;
913 case TypeClass_UNSIGNED_LONG
:
918 pVariant
->vt
= VT_I4
;
919 pVariant
->lVal
= value
;
927 case TypeClass_HYPER
:
930 pVariant
->vt
= VT_DECIMAL
;
931 pVariant
->decVal
.scale
= 0;
932 pVariant
->decVal
.sign
= 0;
933 pVariant
->decVal
.Hi32
= 0;
938 if (value
& SAL_CONST_UINT64(0x8000000000000000))
939 pVariant
->decVal
.sign
= DECIMAL_NEG
;
941 pVariant
->decVal
.Lo64
= value
;
944 case TypeClass_UNSIGNED_HYPER
:
946 pVariant
->vt
= VT_DECIMAL
;
947 pVariant
->decVal
.scale
= 0;
948 pVariant
->decVal
.sign
= 0;
949 pVariant
->decVal
.Hi32
= 0;
953 pVariant
->decVal
.Lo64
= value
;
961 if (createUnoTypeWrapper(type
.getTypeName(), & var
) == false)
962 throw BridgeRuntimeError(
963 OUSTR("[automation bridge] UnoConversionUtilities<T>::anyToVariant \n"
964 "Error during conversion of UNO type to Automation object!"));
966 if (FAILED(VariantCopy(pVariant
, &var
)))
967 throw BridgeRuntimeError(
968 OUSTR("[automation bridge] UnoConversionUtilities<T>::anyToVariant \n"
969 "Unexpected error!"));
974 //TypeClass_EXCEPTION:
975 //When a InvocationTargetException is thrown when calling XInvocation::invoke
976 //on a UNO object, then the target exception is directly used to create a
981 //TypeClass_UNSIGNED_OCTET:
984 // TypeClass_UNSIGNED_INT:
985 // TypeClass_UNSIGNED_BYTE:
987 throw CannotConvertException(
988 OUSTR("[automation bridge]UnoConversionUtilities<T>::anyToVariant\n"
989 "There is no conversion for this UNO type to a Automation type."
990 "The destination type class is the type class of the UNO "
991 "argument which was to be converted."),
992 Reference
<XInterface
>(), rAny
.getValueTypeClass(),
993 FailReason::TYPE_NOT_SUPPORTED
, 0);
999 throw IllegalArgumentException(
1000 OUSTR("[automation bridge]UnoConversionUtilities<T>::anyToVariant\n"
1001 "The provided any of type\" ") + rAny
.getValueType().getTypeName() +
1002 OUSTR("\" is unappropriate for conversion!"), Reference
<XInterface
>(), -1);
1006 catch (CannotConvertException
& )
1010 catch (IllegalArgumentException
& )
1014 catch(BridgeRuntimeError
&)
1018 catch(Exception
& e
)
1020 throw BridgeRuntimeError(
1021 OUSTR("[automation bridge]UnoConversionUtilities<T>::anyToVariant \n"
1022 "Unexpected exception occurred. Message: ") + e
.Message
);
1026 throw BridgeRuntimeError(
1027 OUSTR("[automation bridge]UnoConversionUtilities<T>::anyToVariant \n"
1028 "Unexpected exception occurred. ") );
1032 // Creates an SAFEARRAY of the specified element and if necessary
1033 // creates a SAFEARRAY whith multiple dimensions.
1034 // Used by sal_Bool anyToVariant(VARIANT* pVariant, const Any& rAny, VARTYPE type);
1036 SAFEARRAY
* UnoConversionUtilities
<T
>::createUnoSequenceWrapper(const Any
& rSeq
, VARTYPE elemtype
)
1038 if (rSeq
.getValueTypeClass() != TypeClass_SEQUENCE
)
1039 throw IllegalArgumentException(
1040 OUSTR("[automation bridge]UnoConversionUtilities<T>::createUnoSequenceWrapper \n"
1041 "The any does not contain a sequence!"), 0, 0);
1042 if (elemtype
== VT_NULL
|| elemtype
== VT_EMPTY
)
1043 throw IllegalArgumentException(
1044 OUSTR("[automation bridge]UnoConversionUtilities<T>::createUnoSequenceWrapper \n"
1045 "No element type supplied!"),0, -1);
1046 SAFEARRAY
* pArray
= NULL
;
1047 // Get the dimensions. This is done by examining the type name string
1048 // The count of brackets determines the dimensions.
1049 OUString sTypeName
= rSeq
.getValueType().getTypeName();
1051 for(sal_Int32 lastIndex
=0;(lastIndex
= sTypeName
.indexOf( L
'[', lastIndex
)) != -1; lastIndex
++,dims
++);
1053 //get the maximum number of elements per dimensions and the typedescription of the elements
1054 Sequence
<sal_Int32
> seqElementCounts( dims
);
1055 TypeDescription elementTypeDesc
;
1056 getElementCountAndTypeOfSequence( rSeq
, 1, seqElementCounts
, elementTypeDesc
);
1058 if( elementTypeDesc
.is() )
1060 // set up the SAFEARRAY
1061 scoped_array
<SAFEARRAYBOUND
> sarSafeArrayBound(new SAFEARRAYBOUND
[dims
]);
1062 SAFEARRAYBOUND
* prgsabound
= sarSafeArrayBound
.get();
1063 for( sal_Int32 i
=0; i
< dims
; i
++)
1065 //prgsabound[0] is the right most dimension
1066 prgsabound
[dims
- i
- 1].lLbound
= 0;
1067 prgsabound
[dims
- i
- 1].cElements
= seqElementCounts
[i
];
1070 typelib_TypeDescription
* rawTypeDesc
= elementTypeDesc
.get();
1071 sal_Int32 elementSize
= rawTypeDesc
->nSize
;
1072 size_t oleElementSize
= getOleElementSize( elemtype
);
1073 // SafeArrayCreate clears the memory for the data itself.
1074 pArray
= SafeArrayCreate(elemtype
, dims
, prgsabound
);
1076 // convert the Sequence's elements and populate the SAFEARRAY
1079 // Iterate over every Sequence that contains the actual elements
1081 if( SUCCEEDED( SafeArrayAccessData( pArray
, &pSAData
)))
1083 const sal_Int32
* parElementCount
= seqElementCounts
.getConstArray();
1084 uno_Sequence
* pMultiSeq
= *(uno_Sequence
* const*) rSeq
.getValue();
1085 sal_Int32 dimsSeq
= dims
- 1;
1087 // arDimSeqIndizes contains the current index of a block of data.
1088 // E.g. Sequence<Sequence<sal_Int32>> , the index would refer to Sequence<sal_Int32>
1089 // In this case arDimSeqIndices would have the size 1. That is the elements are not counted
1090 // but the Sequences that contain those elements.
1091 // The indices ar 0 based
1092 scoped_array
<sal_Int32
> sarDimsSeqIndices
;
1093 sal_Int32
* arDimsSeqIndices
= NULL
;
1096 sarDimsSeqIndices
.reset(new sal_Int32
[dimsSeq
]);
1097 arDimsSeqIndices
= sarDimsSeqIndices
.get();
1098 memset( arDimsSeqIndices
, 0, sizeof( sal_Int32
) * dimsSeq
);
1101 char* psaCurrentData
= (char*)pSAData
;
1105 // Get the Sequence at the current index , see arDimsSeqIndices
1106 uno_Sequence
* pCurrentSeq
= pMultiSeq
;
1107 sal_Int32 curDim
=1; // 1 based
1108 sal_Bool skipSeq
= sal_False
;
1109 while( curDim
<= dimsSeq
)
1111 // get the Sequence at the index if valid
1112 if( pCurrentSeq
->nElements
> arDimsSeqIndices
[ curDim
- 1] ) // don't point to Nirvana
1114 // size of Sequence is 4
1115 sal_Int32 offset
= arDimsSeqIndices
[ curDim
- 1] * 4;
1116 pCurrentSeq
= *(uno_Sequence
**) &pCurrentSeq
->elements
[ offset
];
1121 // There is no Sequence at this index, so skip this index
1130 // Calculate the current position within the datablock of the SAFEARRAY
1131 // for the next Sequence.
1132 sal_Int32 memOffset
= 0;
1133 sal_Int32 dimWeight
= parElementCount
[ dims
- 1]; // size of the rightmost dimension
1134 for(sal_Int16 idims
=0; idims
< dimsSeq
; idims
++ )
1136 memOffset
+= arDimsSeqIndices
[dimsSeq
- 1 - idims
] * dimWeight
;
1137 // now determine the weight of the dimension to the left of the current.
1138 if( dims
- 2 - idims
>=0)
1139 dimWeight
*= parElementCount
[dims
- 2 - idims
];
1141 psaCurrentData
= (char*)pSAData
+ memOffset
* oleElementSize
;
1142 // convert the Sequence and put the elements into the Safearray
1143 for( sal_Int32 i
= 0; i
< pCurrentSeq
->nElements
; i
++)
1145 Any
unoElement( pCurrentSeq
->elements
+ i
* elementSize
, rawTypeDesc
);
1146 // The any is being converted into an VARIANT which value is then copied
1147 // to the SAFEARRAY's data block. When copying one has to follow the rules for
1148 // copying certain types, as are VT_DISPATCH, VT_UNKNOWN, VT_VARIANT, VT_BSTR.
1149 // To increase performance, we just do a memcpy of VARIANT::byref. This is possible
1150 // because anyToVariant has already followed the copying rules. To make this
1151 // work there must not be a VariantClear.
1152 // One Exception is VARIANT because I don't know how VariantCopy works.
1156 anyToVariant( &var
, unoElement
);
1157 if( elemtype
== VT_VARIANT
)
1159 VariantCopy( ( VARIANT
*)psaCurrentData
, &var
);
1160 VariantClear( &var
);
1163 memcpy( psaCurrentData
, &var
.byref
, oleElementSize
);
1165 psaCurrentData
+= oleElementSize
;
1168 while( incrementMultidimensionalIndex( dimsSeq
, parElementCount
, arDimsSeqIndices
));
1170 SafeArrayUnaccessData( pArray
);
1177 // Increments a multi dimensional index.
1178 // Returns true as long as the index has been successfully incremented, false otherwise.
1179 // False is also returned if an overflow of the most significant dimension occurs. E.g.
1180 // assume an array with the dimensions (2,2), then the lowest index is (0,0) and the highest
1181 // index is (1,1). If the function is being called with the index (1,1) then the overflow would
1182 // occur, with the result (0,0) and a sal_False as return value.
1183 // Param dimensions - number of dimensions
1184 // Param parDimensionsLength - The array contains the size of each dimension, that is the
1185 // size of the array equals the parameter dimensions.
1186 // The rightmost dimensions is the least significant one
1187 // ( parDimensionsLengths[ dimensions -1 ] ).
1188 // Param parMultiDimensionalIndex - The array contains the index. Each dimension index is
1191 sal_Bool UnoConversionUtilities
<T
>::incrementMultidimensionalIndex(sal_Int32 dimensions
,
1192 const sal_Int32
* parDimensionLengths
,
1193 sal_Int32
* parMultidimensionalIndex
)
1198 sal_Bool ret
= sal_True
;
1199 sal_Bool carry
= sal_True
; // to get into the while loop
1201 sal_Int32 currentDimension
= dimensions
; //most significant is 1
1204 parMultidimensionalIndex
[ currentDimension
- 1]++;
1205 // if carryover, set index to 0 and handle carry on a level above
1206 if( parMultidimensionalIndex
[ currentDimension
- 1] > (parDimensionLengths
[ currentDimension
- 1] - 1))
1207 parMultidimensionalIndex
[ currentDimension
- 1]= 0;
1211 currentDimension
--;
1212 // if dimensions drops below 1 and carry is set than then all indices are 0 again
1213 // this is signalled by returning sal_False
1214 if( currentDimension
< 1 && carry
)
1223 // Determines the size of a certain OLE type. The function takes
1224 // only those types into account which are oleautomation types and
1225 // can have a value ( unless VT_NULL, VT_EMPTY, VT_ARRAY, VT_BYREF).
1226 // Currently used in createUnoSequenceWrapper to calculate addresses
1227 // for data within a SAFEARRAY.
1229 size_t UnoConversionUtilities
<T
>::getOleElementSize( VARTYPE type
)
1234 case VT_BOOL
: size
= sizeof( VARIANT_BOOL
);break;
1235 case VT_UI1
: size
= sizeof( unsigned char);break;
1236 case VT_R8
: size
= sizeof( double);break;
1237 case VT_R4
: size
= sizeof( float);break;
1238 case VT_I2
: size
= sizeof( short);break;
1239 case VT_I4
: size
= sizeof( long);break;
1240 case VT_BSTR
: size
= sizeof( BSTR
); break;
1241 case VT_ERROR
: size
= sizeof( SCODE
); break;
1243 case VT_UNKNOWN
: size
= sizeof( IUnknown
*); break;
1244 case VT_VARIANT
: size
= sizeof( VARIANT
);break;
1250 //If a Sequence is being converted into a SAFEARRAY then we possibly have
1251 // to create a SAFEARRAY with multiple dimensions. This is the case when a
1252 // Sequence contains Sequences ( Sequence< Sequence < XXX > > ). The leftmost
1253 // Sequence in the declaration is assumed to represent dimension 1. Because
1254 // all Sequence elements of a Sequence can have different length, we have to
1255 // determine the maximum length which is then the length of the respective
1257 // getElementCountAndTypeOfSequence determines the length of each dimension and calls itself recursively
1259 // param rSeq - an Any that has to contain a Sequence
1260 // param dim - the dimension for which the number of elements is being determined,
1262 // param seqElementCounts - countains the maximum number of elements for each
1263 // dimension. Index 0 contains the number of dimension one.
1264 // After return the Sequence contains the maximum number of
1265 // elements for each dimension.
1266 // The length of the Sequence must equal the number of dimensions.
1267 // param typeClass - TypeClass of the element type that is no Sequence, e.g.
1268 // Sequence< Sequence <Sequence <sal_Int32> > > - type is sal_Int32)
1270 void UnoConversionUtilities
<T
>::getElementCountAndTypeOfSequence( const Any
& rSeq
, sal_Int32 dim
,
1271 Sequence
< sal_Int32
>& seqElementCounts
, TypeDescription
& typeDesc
)
1273 sal_Int32 dimCount
= (*(uno_Sequence
* const *) rSeq
.getValue())->nElements
;
1274 if( dimCount
> seqElementCounts
[ dim
-1])
1275 seqElementCounts
[ dim
-1]= dimCount
;
1277 // we need the element type to construct the any that is
1278 // passed into getElementCountAndTypeOfSequence again
1279 typelib_TypeDescription
* pSeqDesc
= NULL
;
1280 rSeq
.getValueTypeDescription( &pSeqDesc
);
1281 typelib_TypeDescriptionReference
* pElementDescRef
= ((typelib_IndirectTypeDescription
*)pSeqDesc
)->pType
;
1283 // if the elements are Sequences than do recursion
1284 if( dim
< seqElementCounts
.getLength() )
1286 uno_Sequence
* pSeq
= *(uno_Sequence
* const*) rSeq
.getValue();
1287 uno_Sequence
** arSequences
= (uno_Sequence
**)pSeq
->elements
;
1288 for( sal_Int32 i
=0; i
< dimCount
; i
++)
1290 uno_Sequence
* arElement
= arSequences
[ i
];
1291 getElementCountAndTypeOfSequence( Any( &arElement
, pElementDescRef
), dim
+ 1 , seqElementCounts
, typeDesc
);
1296 // determine the element type ( e.g. Sequence< Sequence <Sequence <sal_Int32> > > - type is sal_Int32)
1297 typeDesc
= pElementDescRef
;
1299 typelib_typedescription_release( pSeqDesc
);
1304 SAFEARRAY
* UnoConversionUtilities
<T
>::createUnoSequenceWrapper(const Any
& rSeq
)
1306 SAFEARRAY
* pArray
= NULL
;
1309 if( rSeq
.getValueTypeClass() != TypeClass_SEQUENCE
)
1310 throw IllegalArgumentException(
1311 OUSTR("[automation bridge]UnoConversionUtilities<T>::createUnoSequenceWrapper\n"
1312 "The UNO argument is not a sequence"), 0, -1);
1314 uno_Sequence
* punoSeq
= *(uno_Sequence
**) rSeq
.getValue();
1316 typelib_TypeDescriptionReference
* pSeqTypeRef
= rSeq
.getValueTypeRef();
1317 typelib_TypeDescription
* pSeqType
= NULL
;
1318 TYPELIB_DANGER_GET( &pSeqType
, pSeqTypeRef
);
1319 typelib_IndirectTypeDescription
* pSeqIndDec
= (typelib_IndirectTypeDescription
*) pSeqType
;
1322 typelib_TypeDescriptionReference
* pSeqElementTypeRef
= pSeqIndDec
->pType
;
1323 TYPELIB_DANGER_RELEASE( pSeqType
);
1325 typelib_TypeDescription
* pSeqElementDesc
= NULL
;
1326 TYPELIB_DANGER_GET( &pSeqElementDesc
, pSeqElementTypeRef
);
1328 // try to find VARIANT type that is related to the UNO type of the sequence elements
1329 // the sequence as a sequence element should be handled in a special way
1330 VARTYPE eTargetElementType
= VT_EMPTY
;
1331 if ( pSeqElementDesc
->eTypeClass
!= TypeClass_SEQUENCE
)
1332 eTargetElementType
= mapTypeClassToVartype( static_cast< TypeClass
>( pSeqElementDesc
->eTypeClass
) );
1334 if ( eTargetElementType
!= VT_EMPTY
)
1335 pArray
= createUnoSequenceWrapper( rSeq
, eTargetElementType
);
1339 sal_Int32 nElementSize
= pSeqElementDesc
->nSize
;
1340 n
= punoSeq
->nElements
;
1342 SAFEARRAYBOUND rgsabound
[1];
1343 rgsabound
[0].lLbound
= 0;
1344 rgsabound
[0].cElements
= n
;
1348 pArray
= SafeArrayCreate(VT_VARIANT
, 1, rgsabound
);
1351 // sal_uInt8 * pSeqData= (sal_uInt8*) punoSeq->pElements;
1352 sal_uInt8
* pSeqData
= (sal_uInt8
*) punoSeq
->elements
;
1354 for (sal_uInt32 i
= 0; i
< n
; i
++)
1356 unoElement
.setValue( pSeqData
+ i
* nElementSize
, pSeqElementDesc
);
1357 VariantInit(&oleElement
);
1359 anyToVariant(&oleElement
, unoElement
);
1362 SafeArrayPutElement(pArray
, safeI
, &oleElement
);
1364 VariantClear(&oleElement
);
1368 TYPELIB_DANGER_RELEASE( pSeqElementDesc
);
1373 /* The argument rObj can contain
1376 - UNO interface created by this bridge (adapter factory)
1377 - UNO interface created by this bridge ( COM Wrapper)
1379 pVar must be initialized.
1382 void UnoConversionUtilities
<T
>::createUnoObjectWrapper(const Any
& rObj
, VARIANT
* pVar
)
1384 MutexGuard
guard(getBridgeMutex());
1386 Reference
<XInterface
> xInt
;
1388 TypeClass tc
= rObj
.getValueTypeClass();
1389 if (tc
!= TypeClass_INTERFACE
&& tc
!= TypeClass_STRUCT
)
1390 throw IllegalArgumentException(
1391 OUSTR("[automation bridge]UnoConversionUtilities<T>::createUnoObjectWrapper \n"
1392 "Cannot create an Automation interface for a UNO type which is not "
1393 "a struct or interface!"), 0, -1);
1395 if (rObj
.getValueTypeClass() == TypeClass_INTERFACE
)
1397 if (! (rObj
>>= xInt
))
1398 throw IllegalArgumentException(
1399 OUSTR("[automation bridge] UnoConversionUtilities<T>::createUnoObjectWrapper\n "
1400 "Could not create wrapper object for UNO object!"), 0, -1);
1401 //If XInterface is NULL, which is a valid value, then simply return NULL.
1404 pVar
->vt
= VT_UNKNOWN
;
1405 pVar
->punkVal
= NULL
;
1408 //make sure we have the main XInterface which is used with a map
1409 xInt
= Reference
<XInterface
>(xInt
, UNO_QUERY
);
1410 //If there is already a wrapper for the UNO object then use it
1412 Reference
<XInterface
> xIntWrapper
;
1413 // Does a UNO wrapper exist already ?
1414 IT_Uno it_uno
= UnoObjToWrapperMap
.find( (sal_uInt32
) xInt
.get());
1415 if(it_uno
!= UnoObjToWrapperMap
.end())
1417 xIntWrapper
= it_uno
->second
;
1418 if (xIntWrapper
.is())
1420 convertSelfToCom(xIntWrapper
, pVar
);
1424 // Is the object a COM wrapper ( either XInvocation, or Adapter object)
1425 // or does it suppy an IDispatch by its own ?
1428 Reference
<XInterface
> xIntComWrapper
= xInt
;
1429 typedef hash_map
<sal_uInt32
,sal_uInt32
>::iterator _IT
;
1430 // Adapter? then get the COM wrapper to which the adapter delegates its calls
1431 _IT it
= AdapterToWrapperMap
.find( (sal_uInt32
) xInt
.get());
1432 if( it
!= AdapterToWrapperMap
.end() )
1433 xIntComWrapper
= reinterpret_cast<XInterface
*>(it
->second
);
1435 if (convertSelfToCom(xIntComWrapper
, pVar
))
1439 // If we have no UNO wrapper nor the IDispatch yet then we have to create
1440 // a wrapper. For that we need an XInvocation from the UNO object.
1442 // get an XInvocation or create one using the invocation service
1443 Reference
<XInvocation
> xInv(xInt
, UNO_QUERY
);
1446 Reference
<XSingleServiceFactory
> xInvFactory
= getInvocationFactory(rObj
);
1447 if (xInvFactory
.is())
1449 Sequence
<Any
> params(1);
1450 params
.getArray()[0] = rObj
;
1451 Reference
<XInterface
> xInt
= xInvFactory
->createInstanceWithArguments(params
);
1452 xInv
= Reference
<XInvocation
>(xInt
, UNO_QUERY
);
1458 Reference
<XInterface
> xNewWrapper
= createUnoWrapperInstance();
1459 Reference
<XInitialization
> xInitWrapper(xNewWrapper
, UNO_QUERY
);
1460 if (xInitWrapper
.is())
1462 VARTYPE vartype
= getVarType( rObj
);
1469 params
[2] <<= vartype
;
1470 xInitWrapper
->initialize( Sequence
<Any
>(params
, 3));
1476 params
[1] <<= vartype
;
1477 xInitWrapper
->initialize( Sequence
<Any
>(params
, 2));
1480 // put the newly created object into a map. If the same object will
1481 // be mapped again and there is already a wrapper then the old wrapper
1483 if(xInt
.is()) // only interfaces
1484 UnoObjToWrapperMap
[(sal_uInt32
) xInt
.get()]= xNewWrapper
;
1485 convertSelfToCom(xNewWrapper
, pVar
);
1492 void UnoConversionUtilities
<T
>::variantToAny( const VARIANT
* pVariant
, Any
& rAny
,
1493 sal_Bool bReduceValueRange
/* = sal_True */)
1500 // There is no need to support indirect values, since they're not supported by UNO
1501 if( FAILED(hr
= VariantCopyInd( &var
, const_cast<VARIANTARG
*>(pVariant
)))) // remove VT_BYREF
1502 throw BridgeRuntimeError(
1503 OUSTR("[automation bridge] UnoConversionUtilities<T>::variantToAny \n"
1504 "VariantCopyInd failed for reason : ") + OUString::valueOf(hr
));
1506 if ( ! convertValueObject( & var
, rAny
))
1508 if ((var
.vt
& VT_ARRAY
) > 0)
1510 VARTYPE oleTypeFlags
= ::sal::static_int_cast
< VARTYPE
, int >( var
.vt
^ VT_ARRAY
);
1512 Sequence
<Any
> unoSeq
= createOleArrayWrapper(var
.parray
, oleTypeFlags
);
1513 rAny
.setValue( &unoSeq
, getCppuType( &unoSeq
));
1520 rAny
.setValue(NULL
, Type());
1523 rAny
.setValue(NULL
, Type());
1526 rAny
.setValue( & var
.iVal
, getCppuType( (sal_Int16
*)0));
1529 rAny
.setValue( & var
.lVal
, getCppuType( (sal_Int32
*)0));
1530 // necessary for use in JavaScript ( see "reduceRange")
1531 if( bReduceValueRange
)
1535 rAny
.setValue( & var
.fltVal
, getCppuType( (float*)0));
1538 rAny
.setValue(& var
.dblVal
, getCppuType( (double*)0));
1542 Currency
cy(var
.cyVal
.int64
);
1554 OUString
b(reinterpret_cast<const sal_Unicode
*>(var
.bstrVal
));
1555 rAny
.setValue( &b
, getCppuType( &b
));
1561 //check if it is a UNO type
1563 CComQIPtr
<IUnoTypeWrapper
, &__uuidof(IUnoTypeWrapper
)> spType((IUnknown
*) var
.byref
);
1565 CComQIPtr
<IUnoTypeWrapper
> spType((IUnknown
*) var
.byref
);
1570 if (FAILED(spType
->get_Name(&sName
)))
1571 throw BridgeRuntimeError(
1572 OUSTR("[automation bridge]UnoConversionUtilities<T>::variantToAny \n"
1573 "Failed to get the type name from a UnoTypeWrapper!"));
1575 if (getType(sName
, type
) == false)
1577 throw CannotConvertException(
1578 OUSTR("[automation bridge]UnoConversionUtilities<T>::variantToAny \n"
1579 "A UNO type with the name: ") + OUString(reinterpret_cast<const sal_Unicode
*>(LPCOLESTR(sName
))) +
1580 OUSTR("does not exist!"),
1581 0, TypeClass_UNKNOWN
, FailReason::TYPE_NOT_SUPPORTED
,0);
1587 rAny
= createOleObjectWrapper( & var
);
1593 SCode
scode(var
.scode
);
1599 sal_Bool b
= var
.boolVal
== VARIANT_TRUE
;
1600 rAny
.setValue( &b
, getCppuType( &b
));
1604 rAny
.setValue( & var
.cVal
, getCppuType((sal_Int8
*)0));
1606 case VT_UI1
: // there is no unsigned char in UNO
1607 rAny
.setValue( & var
.bVal
, getCppuType( (sal_Int8
*)0));
1610 rAny
.setValue( & var
.uiVal
, getCppuType( (sal_uInt16
*)0));
1613 rAny
.setValue( & var
.ulVal
, getCppuType( (sal_uInt32
*)0));
1616 rAny
.setValue( & var
.intVal
, getCppuType( (sal_Int32
*)0));
1619 rAny
.setValue( & var
.uintVal
, getCppuType( (sal_uInt32
*)0));
1622 rAny
.setValue( NULL
, Type());
1627 dec
.Scale
= var
.decVal
.scale
;
1628 dec
.Sign
= var
.decVal
.sign
;
1629 dec
.LowValue
= var
.decVal
.Lo32
;
1630 dec
.MiddleValue
= var
.decVal
.Mid32
;
1631 dec
.HighValue
= var
.decVal
.Hi32
;
1642 catch (IllegalArgumentException
& )
1646 catch (CannotConvertException
&)
1650 catch (BridgeRuntimeError
& )
1654 catch (Exception
& e
)
1656 throw BridgeRuntimeError(OUSTR("[automation bridge] unexpected exception in "
1657 "UnoConversionUtilities<T>::variantToAny ! Message : \n") +
1662 throw BridgeRuntimeError(
1663 OUSTR("[automation bridge] unexpected exception in "
1664 "UnoConversionUtilities<T>::variantToAny !"));
1668 // The function converts an IUnknown* into an UNO interface or struct. The
1669 // IUnknown pointer can constitute different kind of objects:
1670 // 1. a wrapper of an UNO struct (the wrapper was created by this bridge)
1671 // 2. a wrapper of an UNO interface (created by this bridge)
1672 // 3. a dispatch object that implements UNO interfaces
1673 // 4. a dispatch object.
1675 // If the parameter "aType" has a value then the COM object ( pUnknown) is supposed to
1676 // implement the interface described by "aType". Moreover it ( pUnknown) can implement
1678 // UNO interfaces in which case it has to support the SUPPORTED_INTERFACES_PROP (see
1679 // #define) property. That property contains all names of interfaces.
1680 // "pUnknown" is wrapped by a COM wrapper object that implements XInvocation, e.g.
1681 // IUnknownWrapper_Impl. Additionally an object of type "aType" is created by help
1682 // of the INTERFACE_ADAPTER_FACTORY (see #define) service. The implementation of
1683 // "aType" calls on the COM wrapper's XInvocation::invoke. If the COM object supports
1684 // more then one UNO interfaces, as can be determined by the property
1685 // SUPPORTED_INTERFACES_PROP, then the INTERFACE_ADAPTER_FACTORY creates an object that
1686 // implements all these interfaces.
1687 // This is only done if "pUnknown" is not already a UNO wrapper,
1688 // that is it is actually NOT an UNO object that was converted to a COM object. If it is an
1689 // UNO wrapper than the original UNO object is being extracted, queried for "aType" (if
1690 // it is no struct) and returned.
1693 Any UnoConversionUtilities
<T
>::createOleObjectWrapper(VARIANT
* pVar
, const Type
& aType
)
1695 Any UnoConversionUtilities
<T
>::createOleObjectWrapper(VARIANT
* pVar
, const Type
& aType
= Type())
1698 //To allow passing "Nothing" in VS 2008 we need to accept VT_EMPTY
1699 if (pVar
->vt
!= VT_UNKNOWN
&& pVar
->vt
!= VT_DISPATCH
&& pVar
->vt
!= VT_EMPTY
)
1700 throw IllegalArgumentException(
1701 OUSTR("[automation bridge]UnoConversionUtilities<T>::createOleObjectWrapper \n"
1702 "The VARIANT does not contain an object type! "), 0, -1);
1704 MutexGuard
guard( getBridgeMutex());
1706 CComPtr
<IUnknown
> spUnknown
;
1707 CComPtr
<IDispatch
> spDispatch
;
1709 if (pVar
->vt
== VT_UNKNOWN
)
1711 spUnknown
= pVar
->punkVal
;
1714 spUnknown
->QueryInterface( IID_IDispatch
, reinterpret_cast<LPVOID
*>( & spDispatch
.p
));
1716 spUnknown
.QueryInterface( & spDispatch
.p
);
1719 else if (pVar
->vt
== VT_DISPATCH
&& pVar
->pdispVal
!= NULL
)
1721 CComPtr
<IDispatch
> spDispatch(pVar
->pdispVal
);
1724 spDispatch
->QueryInterface( IID_IUnknown
, reinterpret_cast<LPVOID
*>( & spUnknown
.p
));
1726 spDispatch
.QueryInterface( & spUnknown
.p
);
1730 static Type VOID_TYPE
= Type();
1732 //If no Type is provided and pVar contains IUnknown then we return a XInterface.
1733 //If pVar contains an IDispatch then we return a XInvocation.
1734 Type desiredType
= aType
;
1736 if (aType
== VOID_TYPE
)
1742 desiredType
= getCppuType((Reference
<XInterface
>*) 0);
1745 desiredType
= getCppuType((Reference
<XInvocation
>*) 0);
1748 desiredType
= aType
;
1752 // COM pointer are NULL, no wrapper required
1753 if (spUnknown
== NULL
)
1755 Reference
<XInterface
> xInt
;
1756 if( aType
.getTypeClass() == TypeClass_INTERFACE
)
1757 ret
.setValue( &xInt
, aType
);
1758 else if( aType
.getTypeClass() == TypeClass_STRUCT
)
1759 ret
.setValue( NULL
, aType
);
1766 // Check if "spUnknown" is a UNO wrapper, that is an UNO object that has been
1767 // passed to COM. Then it supports IUnoObjectWrapper
1768 // and we extract the original UNO object.
1770 CComQIPtr
<IUnoObjectWrapper
, &__uuidof(IUnoObjectWrapper
)> spUno( spUnknown
);
1772 CComQIPtr
<IUnoObjectWrapper
> spUno( spUnknown
);
1775 { // it is a wrapper
1776 Reference
<XInterface
> xInt
;
1777 if( SUCCEEDED( spUno
->getOriginalUnoObject( &xInt
)))
1784 if( SUCCEEDED( spUno
->getOriginalUnoStruct(&any
)))
1790 // "spUnknown" is a real COM object.
1791 // Before we create a new wrapper object we check if there is an existing wrapper
1792 // There can be two kinds of wrappers, those who wrap dispatch - UNO objects, and those who
1793 // wrap ordinary dispatch objects. The dispatch-UNO objects usually are adapted to represent
1794 // particular UNO interfaces.
1795 Reference
<XInterface
> xIntWrapper
;
1796 CIT_Com cit_currWrapper
= ComPtrToWrapperMap
.find( reinterpret_cast<sal_uInt32
>(spUnknown
.p
));
1797 if(cit_currWrapper
!= ComPtrToWrapperMap
.end())
1798 xIntWrapper
= cit_currWrapper
->second
;
1799 if (xIntWrapper
.is())
1801 //Try to find an adapter for the wrapper
1802 //find the proper Adapter. The pointer in the WrapperToAdapterMap are valid as long as
1803 //we get a pointer to the wrapper from ComPtrToWrapperMap, because the Adapter hold references
1805 CIT_Wrap it
= WrapperToAdapterMap
.find((sal_uInt32
) xIntWrapper
.get());
1806 if (it
== WrapperToAdapterMap
.end())
1808 // No adapter available.
1809 //The COM component could be a UNO object. Then we need to provide
1810 // a proxy that implements all interfaces
1811 Sequence
<Type
> seqTypes
= getImplementedInterfaces(spUnknown
);
1812 Reference
<XInterface
> xIntAdapter
;
1813 if (seqTypes
.getLength() > 0)
1815 //It is a COM UNO object
1816 xIntAdapter
= createAdapter(seqTypes
, xIntWrapper
);
1820 // Some ordinary COM object
1821 xIntAdapter
= xIntWrapper
;
1823 // return the wrapper directly, return XInterface or XInvocation
1824 ret
= xIntWrapper
->queryInterface(desiredType
);
1825 if ( ! ret
.hasValue())
1826 throw IllegalArgumentException(
1827 OUSTR("[automation bridge]UnoConversionUtilities<T>::createOleObjectWrapper \n"
1828 "The COM object is not suitable for the UNO type: ") +
1829 desiredType
.getTypeName(), 0, -1);
1833 //There is an adapter available
1834 Reference
<XInterface
> xIntAdapter((XInterface
*) it
->second
);
1835 ret
= xIntAdapter
->queryInterface( desiredType
);
1836 if ( ! ret
.hasValue())
1837 throw IllegalArgumentException(
1838 OUSTR("[automation bridge]UnoConversionUtilities<T>::createOleObjectWrapper \n"
1839 "The COM object is not suitable for the UNO type: ") +
1840 desiredType
.getTypeName(), 0, -1);
1845 // No existing wrapper. Therefore create a new proxy.
1846 // If the object implements UNO interfaces then get the types.
1847 Sequence
<Type
> seqTypes
= getImplementedInterfaces(spUnknown
);
1848 if (seqTypes
.getLength() == 0 &&
1849 aType
!= VOID_TYPE
&& aType
!= getCppuType((Reference
<XInvocation
>*)0))
1851 seqTypes
= Sequence
<Type
>( & aType
, 1);
1854 //There is no existing wrapper, therefore we create one for the real COM object
1855 Reference
<XInterface
> xIntNewProxy
= createComWrapperInstance();
1856 if ( ! xIntNewProxy
.is())
1857 throw BridgeRuntimeError(
1858 OUSTR("[automation bridge]UnoConversionUtilities<T>::createOleObjectWrapper \n"
1859 "Could not create proxy object for COM object!"));
1861 // initialize the COM wrapper
1862 Reference
<XInitialization
> xInit( xIntNewProxy
, UNO_QUERY
);
1863 OSL_ASSERT( xInit
.is());
1867 params
[0] <<= reinterpret_cast<sal_uInt32
>( spUnknown
.p
);
1869 params
[0] <<= (sal_uInt32
) spUnknown
.p
;
1871 sal_Bool bDisp
= pVar
->vt
== VT_DISPATCH
? sal_True
: sal_False
;
1872 params
[1].setValue( & bDisp
, getBooleanCppuType());
1873 params
[2] <<= seqTypes
;
1875 xInit
->initialize( Sequence
<Any
>( params
, 3));
1877 ComPtrToWrapperMap
[reinterpret_cast<sal_uInt32
>( spUnknown
.p
)]= xIntNewProxy
;
1879 ComPtrToWrapperMap
[reinterpret_cast<sal_uInt32
>(spUnknown
.p
)]= xIntNewProxy
;
1882 // we have a wrapper object
1883 //The wrapper implements already XInvocation and XInterface. If
1884 //param aType is void then the object is supposed to have XInvocation.
1885 if (aType
== getCppuType((Reference
<XInvocation
>*)0) ||
1886 (aType
== VOID_TYPE
&& seqTypes
.getLength() == 0 ))
1888 ret
= xIntNewProxy
->queryInterface(desiredType
);
1892 Reference
<XInterface
> xIntAdapter
=
1893 createAdapter(seqTypes
, xIntNewProxy
);
1894 ret
= xIntAdapter
->queryInterface(desiredType
);
1899 Reference
<XInterface
> UnoConversionUtilities
<T
>::createAdapter(const Sequence
<Type
>& seqTypes
,
1900 const Reference
<XInterface
>& receiver
)
1902 Reference
< XInterface
> xIntAdapterFac
;
1903 xIntAdapterFac
= m_smgr
->createInstance(INTERFACE_ADAPTER_FACTORY
);
1904 // We create an adapter object that does not only implement the required type but also
1905 // all types that the COM object pretends to implement. An COM object must therefore
1906 // support the property "_implementedInterfaces".
1907 Reference
<XInterface
> xIntAdapted
;
1908 Reference
<XInvocation
> xInv(receiver
, UNO_QUERY
);
1909 Reference
<XInvocationAdapterFactory2
> xAdapterFac( xIntAdapterFac
, UNO_QUERY
);
1910 if( xAdapterFac
.is())
1911 xIntAdapted
= xAdapterFac
->createAdapter( xInv
, seqTypes
);
1913 if( xIntAdapted
.is())
1915 // Put the pointer to the wrapper object and the interface pointer of the adapted interface
1916 // in a global map. Thus we can determine in a call to createUnoObjectWrapper whether the UNO
1917 // object is a wrapped COM object. In that case we extract the original COM object rather than
1918 // creating a wrapper around the UNO object.
1919 typedef hash_map
<sal_uInt32
,sal_uInt32
>::value_type VALUE
;
1920 AdapterToWrapperMap
.insert( VALUE( (sal_uInt32
) xIntAdapted
.get(), (sal_uInt32
) receiver
.get()));
1921 WrapperToAdapterMap
.insert( VALUE( (sal_uInt32
) receiver
.get(), (sal_uInt32
) xIntAdapted
.get()));
1925 throw BridgeRuntimeError(
1926 OUSTR("[automation bridge]UnoConversionUtilities<T>::createOleObjectWrapper \n"
1927 "Could not create a proxy for COM object! Creation of adapter failed."));
1931 // "convertValueObject" converts a JScriptValue object contained in "var" into
1932 // an any. The type contained in the any is stipulated by a "type value" thas
1933 // was set within the JScript script on the value object ( see JScriptValue).
1935 bool UnoConversionUtilities
<T
>::convertValueObject( const VARIANTARG
*var
, Any
& any
)
1942 CComVariant varDisp
;
1944 if(SUCCEEDED(hr
= varDisp
.ChangeType( VT_DISPATCH
, var
)))
1946 CComPtr
<IJScriptValueObject
> spValue
;
1947 VARIANT_BOOL varBool
;
1949 CComVariant varValue
;
1950 CComPtr
<IDispatch
> spDisp( varDisp
.pdispVal
);
1953 if(SUCCEEDED( spDisp
->QueryInterface( __uuidof( IJScriptValueObject
),
1954 reinterpret_cast<void**> (&spValue
))))
1956 ret
= true; // is is a ValueObject
1957 //If it is an out - param then it does not need to be converted. In/out and
1958 // in params does so.
1959 if (SUCCEEDED(hr
= spValue
->IsOutParam( &varBool
)))
1961 // if varBool == true then no conversion needed because out param
1962 if (varBool
== VARIANT_FALSE
)
1964 if(SUCCEEDED(hr
= spValue
->GetValue( & bstrType
, & varValue
)))
1967 if (getType(bstrType
, type
))
1968 variantToAny( & varValue
, any
, type
);
1981 else if( hr
!= DISP_E_TYPEMISMATCH
&& hr
!= E_NOINTERFACE
)
1985 throw BridgeRuntimeError(
1986 OUSTR("[automation bridge] Conversion of ValueObject failed "));
1988 catch (BridgeRuntimeError
&)
1992 catch (Exception
& e
)
1994 throw BridgeRuntimeError(OUSTR("[automation bridge] unexpected exception in "
1995 "UnoConversionUtilities<T>::convertValueObject ! Message : \n") +
2000 throw BridgeRuntimeError(
2001 OUSTR("[automation bridge] unexpected exception in "
2002 "UnoConversionUtilities<T>::convertValueObject !"));
2008 void UnoConversionUtilities
<T
>::dispatchExObject2Sequence( const VARIANTARG
* pvar
, Any
& anySeq
, const Type
& type
)
2013 if( pvar
->vt
!= VT_DISPATCH
)
2014 throw BridgeRuntimeError(OUSTR("[automation bridge] UnoConversionUtilities<T>::dispatchExObject2Sequence \n"
2015 "Conversion of dispatch object to Sequence failed!"));
2016 IDispatchEx
* pdispEx
;
2018 if( FAILED( hr
= pvar
->pdispVal
->QueryInterface( IID_IDispatchEx
,
2019 reinterpret_cast<void**>( &pdispEx
))))
2020 throw BridgeRuntimeError(OUSTR("[automation bridge] UnoConversionUtilities<T>::dispatchExObject2Sequence \n"
2021 "Conversion of dispatch object to Sequence failed!"));
2025 DISPPARAMS param
= {0,0,0,0};
2028 OLECHAR
* sLength
= L
"length";
2030 // Get the length of the array. Can also be obtained throu GetNextDispID. The
2031 // method only returns DISPIDs of the array data. Their names are like "0", "1" etc.
2032 if( FAILED( hr
= pdispEx
->GetIDsOfNames(IID_NULL
, &sLength
, 1, LOCALE_USER_DEFAULT
, &dispid
)))
2033 throw BridgeRuntimeError(OUSTR("[automation bridge] UnoConversionUtilities<T>::dispatchExObject2Sequence \n"
2034 "Conversion of dispatch object to Sequence failed!"));
2035 if( FAILED( hr
= pdispEx
->InvokeEx(dispid
, LOCALE_USER_DEFAULT
, DISPATCH_PROPERTYGET
,
2036 ¶m
, &result
, NULL
, NULL
)))
2037 throw BridgeRuntimeError(OUSTR("[automation bridge] UnoConversionUtilities<T>::dispatchExObject2Sequence \n"
2038 "Conversion of dispatch object to Sequence failed!"));
2039 if( FAILED( VariantChangeType( &result
, &result
, 0, VT_I4
)))
2040 throw BridgeRuntimeError(OUSTR("[automation bridge] UnoConversionUtilities<T>::dispatchExObject2Sequence \n"
2041 "Conversion of dispatch object to Sequence failed!"));
2042 long length
= result
.lVal
;
2046 // get a few basic facts about the sequence, and reallocate:
2047 // create the Sequences
2048 // get the size of the elements
2049 typelib_TypeDescription
*pDesc
= NULL
;
2050 type
.getDescription( &pDesc
);
2052 typelib_IndirectTypeDescription
*pSeqDesc
= reinterpret_cast<typelib_IndirectTypeDescription
*>(pDesc
);
2053 typelib_TypeDescriptionReference
*pSeqElemDescRef
= pSeqDesc
->pType
; // type of the Sequence' elements
2054 Type
elemType( pSeqElemDescRef
);
2055 _typelib_TypeDescription
* pSeqElemDesc
=NULL
;
2056 TYPELIB_DANGER_GET( &pSeqElemDesc
, pSeqElemDescRef
)
2057 sal_uInt32 nelementSize
= pSeqElemDesc
->nSize
;
2058 TYPELIB_DANGER_RELEASE( pSeqElemDesc
)
2060 uno_Sequence
*p_uno_Seq
;
2061 uno_sequence_construct( &p_uno_Seq
, pDesc
, NULL
, length
, cpp_acquire
);
2063 typelib_TypeClass typeElement
= pSeqDesc
->pType
->eTypeClass
;
2064 char *pArray
= p_uno_Seq
->elements
;
2066 // Get All properties in the object, convert their values to the expected type and
2067 // put them into the passed in sequence
2068 for( sal_Int32 i
= 0; i
< length
; i
++)
2070 OUString ousIndex
=OUString::valueOf( i
);
2071 OLECHAR
* sindex
= (OLECHAR
*)ousIndex
.getStr();
2073 if( FAILED( hr
= pdispEx
->GetIDsOfNames(IID_NULL
, &sindex
, 1, LOCALE_USER_DEFAULT
, &dispid
)))
2075 throw BridgeRuntimeError(OUSTR("[automation bridge] UnoConversionUtilities<T>::dispatchExObject2Sequence \n"
2076 "Conversion of dispatch object to Sequence failed!"));
2078 if( FAILED( hr
= pdispEx
->InvokeEx(dispid
, LOCALE_USER_DEFAULT
, DISPATCH_PROPERTYGET
,
2079 ¶m
, &result
, NULL
, NULL
)))
2081 throw BridgeRuntimeError(OUSTR("[automation bridge] UnoConversionUtilities<T>::dispatchExObject2Sequence \n"
2082 "Conversion of dispatch object to Sequence failed!"));
2085 // If the result is VT_DISPATCH than the Sequence's element type could be Sequence
2086 // Look that up in the CoreReflection to make clear.
2087 // That requires a recursiv conversion
2089 // Destination address within the out-Sequence "anySeq" where to copy the next converted element
2090 void* pDest
= (void*)(pArray
+ (i
* nelementSize
));
2092 if( result
.vt
& VT_DISPATCH
&& typeElement
== typelib_TypeClass_SEQUENCE
)
2094 variantToAny( &result
, any
, elemType
, sal_False
);
2095 // copy the converted VARIANT, that is a Sequence to the Sequence
2096 uno_Sequence
* p_unoSeq
= *(uno_Sequence
**)any
.getValue();
2097 // just copy the pointer of the uno_Sequence
2098 // nelementSize should be 4 !!!!
2099 memcpy( pDest
, &p_unoSeq
, nelementSize
);
2100 osl_incrementInterlockedCount( &p_unoSeq
->nRefCount
);
2102 else // Element type is no Sequence -> do one conversion
2104 variantToAny( &result
, any
, elemType
, sal_False
);
2105 if( typeElement
== typelib_TypeClass_ANY
)
2107 // copy the converted VARIANT to the Sequence
2108 uno_type_assignData( pDest
, pSeqElemDescRef
, &any
, pSeqElemDescRef
,cpp_queryInterface
,
2109 cpp_acquire
, cpp_release
);
2113 // type after conversion must be the element type of the sequence
2114 OSL_ENSURE( (any
.getValueTypeClass() == typeElement
), "wrong conversion");
2115 uno_type_assignData( pDest
, pSeqElemDescRef
,const_cast<void*>( any
.getValue()), any
.getValueTypeRef(),
2116 cpp_queryInterface
, cpp_acquire
, cpp_release
);
2121 anySeq
.setValue( &p_uno_Seq
, pDesc
);
2122 uno_destructData( &p_uno_Seq
, pDesc
, cpp_release
);
2123 typelib_typedescription_release( pDesc
);
2126 throw BridgeRuntimeError(
2127 OUSTR("[automation bridge] Conversion of ValueObject failed "));
2129 catch (BridgeRuntimeError
& )
2133 catch (Exception
& e
)
2135 throw BridgeRuntimeError(OUSTR("[automation bridge] unexpected exception in "
2136 "UnoConversionUtilities<T>::convertValueObject ! Message : \n") +
2141 throw BridgeRuntimeError(
2142 OUSTR("[automation bridge] unexpected exception in "
2143 "UnoConversionUtilities<T>::convertValueObject !"));
2147 /* The argument unotype is the type that is expected by the currently called UNO function.
2148 For example: []long, [][]long. If the function calls itself recursively then the element type
2149 is passed on. For example a two dimensional SAFEARRAY of type VT_I4 is to be converted. Then
2150 unotype has to be either void or [][]long. When the function calls itself recursivly then
2151 it passes the element type which is []long.
2154 Sequence
<Any
> UnoConversionUtilities
<T
>::createOleArrayWrapperOfDim(SAFEARRAY
* pArray
,
2155 unsigned int dimCount
, unsigned int actDim
, long* index
, VARTYPE type
, const Type
& unotype
)
2160 long nCountElements
;
2162 SafeArrayGetLBound(pArray
, actDim
, &lBound
);
2163 SafeArrayGetUBound(pArray
, actDim
, &uBound
);
2164 nCountElements
= uBound
- lBound
+1;
2166 Sequence
<Any
> anySeq(nCountElements
);
2167 Any
* pUnoArray
= anySeq
.getArray();
2169 for (index
[actDim
- 1] = lBound
; index
[actDim
- 1] <= uBound
; index
[actDim
- 1]++)
2173 Sequence
<Any
> element
= createOleArrayWrapperOfDim(pArray
, dimCount
,
2174 actDim
- 1, index
, type
, getElementTypeOfSequence(unotype
));
2176 pUnoArray
[index
[actDim
- 1] - lBound
].setValue(&element
, getCppuType(&element
));
2182 VariantInit(&variant
);
2184 V_VT(&variant
) = type
;
2189 SafeArrayGetElement(pArray
, index
, &V_I2(&variant
));
2192 SafeArrayGetElement(pArray
, index
, &V_I4(&variant
));
2195 SafeArrayGetElement(pArray
, index
, &V_R4(&variant
));
2198 SafeArrayGetElement(pArray
, index
, &V_R8(&variant
));
2201 SafeArrayGetElement(pArray
, index
, &V_CY(&variant
));
2204 SafeArrayGetElement(pArray
, index
, &V_DATE(&variant
));
2207 hr
= SafeArrayGetElement(pArray
, index
, &V_BSTR(&variant
));
2210 SafeArrayGetElement(pArray
, index
, &V_DISPATCH(&variant
));
2213 SafeArrayGetElement(pArray
, index
, &V_ERROR(&variant
));
2216 SafeArrayGetElement(pArray
, index
, &V_BOOL(&variant
));
2219 SafeArrayGetElement(pArray
, index
, &variant
);
2222 SafeArrayGetElement(pArray
, index
, &V_UNKNOWN(&variant
));
2225 SafeArrayGetElement(pArray
, index
, &V_I1(&variant
));
2228 SafeArrayGetElement(pArray
, index
, &V_UI1(&variant
));
2231 SafeArrayGetElement(pArray
, index
, &V_UI2(&variant
));
2234 SafeArrayGetElement(pArray
, index
, &V_UI4(&variant
));
2240 if( unotype
.getTypeClass() == TypeClass_VOID
)
2241 // the function was called without specifying the destination type
2242 variantToAny(&variant
, pUnoArray
[index
[actDim
- 1] - lBound
], sal_False
);
2244 variantToAny(&variant
, pUnoArray
[index
[actDim
- 1] - lBound
],
2245 getElementTypeOfSequence(unotype
), sal_False
);
2247 VariantClear(&variant
);
2254 Type UnoConversionUtilities
<T
>::getElementTypeOfSequence( const Type
& seqType
)
2257 if( seqType
.getTypeClass() != TypeClass_VOID
)
2259 OSL_ASSERT( seqType
.getTypeClass() == TypeClass_SEQUENCE
);
2260 typelib_IndirectTypeDescription
* pDescSeq
= NULL
;
2261 seqType
.getDescription((typelib_TypeDescription
** ) & pDescSeq
);
2262 retValue
= Type(pDescSeq
->pType
);
2263 typelib_typedescription_release( (typelib_TypeDescription
*) pDescSeq
);
2268 Sequence
<Any
> UnoConversionUtilities
<T
>::createOleArrayWrapper(SAFEARRAY
* pArray
, VARTYPE type
, const Type
& unoType
)
2270 sal_uInt32 dim
= SafeArrayGetDim(pArray
);
2276 scoped_array
<long> sarIndex(new long[dim
]);
2277 long * index
= sarIndex
.get();
2279 for (unsigned int i
= 0; i
< dim
; i
++)
2284 ret
= createOleArrayWrapperOfDim(pArray
, dim
, dim
, index
, type
, unoType
);
2290 // If an VARIANT has the type VT_DISPATCH it can either be an JScript Array
2291 // or some other object. This function finds out if it is such an array or
2292 // not. Currently there's no way to make sure it's an array
2293 // so we assume that when the object has a property "0" then it is an Array.
2294 // An JScript has property like "0", "1", "2" etc. which represent the
2295 // value at the corresponding index of the array
2297 sal_Bool UnoConversionUtilities
<T
>::isJScriptArray(const VARIANT
* rvar
)
2299 OSL_ENSURE( rvar
->vt
== VT_DISPATCH
, "param is not a VT_DISPATCH");
2301 OLECHAR
* sindex
= L
"0";
2303 if ( rvar
->vt
== VT_DISPATCH
&& rvar
->pdispVal
)
2305 hr
= rvar
->pdispVal
->GetIDsOfNames( IID_NULL
, &sindex
, 1,
2306 LOCALE_USER_DEFAULT
, &id
);
2308 if( SUCCEEDED ( hr
) )
2316 VARTYPE UnoConversionUtilities
<T
>::mapTypeClassToVartype( TypeClass type
)
2321 case TypeClass_INTERFACE
: ret
= VT_DISPATCH
;
2323 case TypeClass_STRUCT
: ret
= VT_DISPATCH
;
2325 case TypeClass_ENUM
: ret
= VT_I4
;
2327 case TypeClass_SEQUENCE
: ret
= VT_ARRAY
;
2329 case TypeClass_ANY
: ret
= VT_VARIANT
;
2331 case TypeClass_BOOLEAN
: ret
= VT_BOOL
;
2333 case TypeClass_CHAR
: ret
= VT_I2
;
2335 case TypeClass_STRING
: ret
= VT_BSTR
;
2337 case TypeClass_FLOAT
: ret
= VT_R4
;
2339 case TypeClass_DOUBLE
: ret
= VT_R8
;
2341 case TypeClass_BYTE
: ret
= VT_UI1
;
2343 case TypeClass_SHORT
: ret
= VT_I2
;
2345 case TypeClass_LONG
: ret
= VT_I4
;
2347 case TypeClass_UNSIGNED_SHORT
: ret
= VT_UI2
;
2349 case TypeClass_UNSIGNED_LONG
: ret
= VT_UI4
;
2358 Sequence
<Type
> UnoConversionUtilities
<T
>::getImplementedInterfaces(IUnknown
* pUnk
)
2360 Sequence
<Type
> seqTypes
;
2361 CComDispatchDriver
disp( pUnk
);
2366 // There are two different property names possible.
2367 if( FAILED( hr
= disp
.GetPropertyByName( SUPPORTED_INTERFACES_PROP
, &var
)))
2369 hr
= disp
.GetPropertyByName( SUPPORTED_INTERFACES_PROP2
, &var
);
2373 // we exspect an array( SafeArray or IDispatch) of Strings.
2375 variantToAny( &var
, anyNames
, getCppuType( (Sequence
<Any
>*) 0));
2376 Sequence
<Any
> seqAny
;
2377 if( anyNames
>>= seqAny
)
2379 seqTypes
.realloc( seqAny
.getLength());
2380 for( sal_Int32 i
=0; i
< seqAny
.getLength(); i
++)
2383 seqAny
[i
] >>= typeName
;
2384 seqTypes
[i
]= Type( TypeClass_INTERFACE
, typeName
);
2392 Reference
<XTypeConverter
> UnoConversionUtilities
<T
>::getTypeConverter()
2394 if ( ! m_typeConverter
.is())
2396 MutexGuard
guard(getBridgeMutex());
2397 if ( ! m_typeConverter
.is())
2399 Reference
<XInterface
> xIntConverter
=
2400 m_smgr
->createInstance(OUSTR("com.sun.star.script.Converter"));
2401 if (xIntConverter
.is())
2402 m_typeConverter
= Reference
<XTypeConverter
>(xIntConverter
, UNO_QUERY
);
2405 return m_typeConverter
;
2408 // This function tries to the change the type of a value (contained in the Any)
2409 // to the smallest possible that can hold the value. This is actually done only
2410 // for types of VT_I4 (see o2u_variantToAny). The reason is the following:
2411 // JavaScript passes integer values always as VT_I4. If there is a parameter or
2412 // property of type any then the bridge converts the any's content according
2413 // to "o2u_variantToAny". Because the VARTYPE is VT_I4 the value would be converted
2414 // to TypeClass_LONG. Say the method XPropertySet::setPropertyValue( string name, any value)
2415 // would be called on an object and the property actually is of TypeClass_SHORT.
2416 // After conversion of the VARIANT parameter the Any would contain type
2417 // TypeClass_LONG. Because the corereflection does not cast from long to short
2418 // the "setPropertValue" would fail as the value has not the right type.
2420 // The corereflection does convert small integer types to bigger types.
2421 // Therefore we can reduce the type if possible and avoid the above mentioned
2424 // The function is not used when elements are to be converted for Sequences.
2426 #ifndef _REDUCE_RANGE
2427 #define _REDUCE_RANGE
2428 inline void reduceRange( Any
& any
)
2430 OSL_ASSERT( any
.getValueTypeClass() == TypeClass_LONG
);
2432 sal_Int32 value
= *(sal_Int32
*)any
.getValue();
2433 if( value
<= 0x7f && value
>= -0x80)
2435 sal_Int8 charVal
= static_cast<sal_Int8
>( value
);
2436 any
.setValue( &charVal
, getCppuType( (sal_Int8
*)0));
2438 else if( value
<= 0x7fff && value
>= -0x8000)
2439 {// -32768 bis 32767
2440 sal_Int16 shortVal
= static_cast<sal_Int16
>( value
);
2441 any
.setValue( &shortVal
, getCppuType( (sal_Int16
*)0));