tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / extensions / source / ole / unoconversionutilities.hxx
blob26b8896267c46a6d225b022acca4f36beac8137a
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 .
19 #pragma once
21 #include <memory>
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
81 // must be returned.
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
98 // problem.
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)
108 {// -128 bis 127
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)
113 {// -32768 bis 32767
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.
125 template< class >
126 class UnoConversionUtilities
128 public:
129 explicit UnoConversionUtilities( const Reference<XMultiServiceFactory> & smgr):
130 m_nUnoWrapperClass( INTERFACE_OLE_WRAPPER_IMPL),
131 m_nComWrapperClass( IUNKNOWN_WRAPPER_IMPL),
132 m_smgr( smgr)
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.
167 ArgumentIndex is 0.
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.
176 ArgumentIndex is 0.
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);
212 protected:
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
243 // manager.
244 Reference<XMultiServiceFactory> m_smgrRemote;
245 Reference<XSingleServiceFactory> m_xInvocationFactoryLocal;
246 Reference<XSingleServiceFactory> m_xInvocationFactoryRemote;
248 private:
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
259 template < class T >
260 bool convertSelfToCom( T& unoInterface, VARIANT * pVar)
262 bool ret = false;
263 Reference< XInterface > xInt( unoInterface, UNO_QUERY);
264 if( xInt.is())
266 Reference< css::bridge::XBridgeSupplier2 > xSupplier( xInt, UNO_QUERY);
267 if( xSupplier.is())
269 sal_Int8 arId[16];
270 rtl_getGlobalProcessId( reinterpret_cast<sal_uInt8*>(arId));
271 Sequence<sal_Int8> seqId( arId, 16);
272 Any anySource;
273 anySource <<= xInt;
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);
282 HRESULT hr;
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);
290 ret = true;
294 return ret;
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
302 // are: all structs.
303 // Param anyObject - contains the object ( interface, struct) for what we need an invocation object.
305 template<class T>
306 Reference< XSingleServiceFactory > UnoConversionUtilities<T>::getInvocationFactory(const Any& anyObject)
308 Reference< XSingleServiceFactory > retVal;
309 MutexGuard guard( getBridgeMutex());
310 if( anyObject.getValueTypeClass() != TypeClass_STRUCT &&
311 m_smgrRemote.is() )
313 if( ! m_xInvocationFactoryRemote.is() )
314 m_xInvocationFactoryRemote.set(m_smgrRemote->createInstance( INVOCATION_SERVICE), UNO_QUERY);
315 retVal= m_xInvocationFactoryRemote;
317 else
319 if( ! m_xInvocationFactoryLocal.is() )
320 m_xInvocationFactoryLocal.set(m_smgr->createInstance(INVOCATION_SERVICE ), UNO_QUERY);
321 retVal= m_xInvocationFactoryLocal;
323 return retVal;
326 template<class T>
327 void UnoConversionUtilities<T>::variantToAny( const VARIANTARG* pArg, Any& rAny, const Type& ptype, bool bReduceValueRange /* = sal_True */)
331 HRESULT hr;
332 bool bFail = false;
333 bool bCannotConvert = false;
334 CComVariant var;
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);
342 if( bHandled)
343 OSL_ENSURE( rAny.getValueType() == ptype, "type in Value Object must match the type parameter");
345 if( ! bHandled)
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;
361 else
362 bFail = true;
364 else
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;
370 else
371 bFail = true;
373 break;
374 case TypeClass_INTERFACE: // could also be an IUnknown
375 case TypeClass_STRUCT:
377 rAny = createOleObjectWrapper( & var, ptype);
378 break;
380 case TypeClass_ENUM:
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;
385 else
386 bFail = true;
387 break;
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);
398 else
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();
405 if (conv.is())
409 Any anySeq(unoSeq);
410 Any convAny = conv->convertTo(anySeq, ptype);
411 rAny = convAny;
413 catch (const IllegalArgumentException& e)
415 throw BridgeRuntimeError(
416 "[automation bridge]com.sun.star.lang.IllegalArgumentException "
417 "in UnoConversionUtilities<T>::variantToAny! Message: " +
418 e.Message);
420 catch (const CannotConvertException& e)
422 throw BridgeRuntimeError(
423 "[automation bridge]com.sun.star.script.CannotConvertException "
424 "in UnoConversionUtilities<T>::variantToAny! Message: " +
425 e.Message);
430 break;
431 case TypeClass_VOID:
432 rAny.setValue(nullptr,Type());
433 break;
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)
452 // positive value
453 variantToAny( & var, rAny, cppu::UnoType<sal_uInt64>::get(),
454 bReduceValueRange);
456 else
458 //negative value
459 variantToAny( & var, rAny, cppu::UnoType<sal_Int64>::get(),
460 bReduceValueRange);
463 else
465 variantToAny( & var, rAny);
467 break;
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;
473 else
474 bFail = true;
475 break;
476 case TypeClass_STRING: // UString
477 if(var.vt == VT_NULL)
478 var = CComBSTR("");
479 if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_BSTR)))
480 variantToAny( & var, rAny);
481 else if (hr == DISP_E_TYPEMISMATCH)
482 bCannotConvert = true;
483 else
484 bFail = true;
485 break;
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;
491 else
492 bFail = true;
493 break;
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;
499 else
500 bFail = true;
501 break;
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;
507 else
508 bFail = true;
509 break;
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;
515 else
516 bFail = true;
517 break;
518 case TypeClass_LONG:
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;
523 else
524 bFail = true;
525 break;
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)
533 bFail = true;
534 break;
536 sal_Int64 value = var.decVal.Lo64;
537 if (var.decVal.sign == DECIMAL_NEG)
538 value |= SAL_CONST_UINT64(0x8000000000000000);
539 rAny <<= value;
541 else if (hr == DISP_E_TYPEMISMATCH)
542 bCannotConvert = true;
543 else
544 bFail = true;
545 break;
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;
551 else
552 bFail = true;
553 break;
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;
559 else
560 bFail = true;
561 break;
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)
567 bFail = true;
568 break;
570 rAny <<= var.decVal.Lo64;
572 else if (hr == DISP_E_TYPEMISMATCH)
573 bCannotConvert = true;
574 else
575 bFail = true;
576 break;
577 case TypeClass_TYPE:
578 if(SUCCEEDED(hr = VariantChangeType(& var, &var, 0, VT_UNKNOWN)))
579 variantToAny( & var, rAny);
580 else if (hr == DISP_E_TYPEMISMATCH)
581 bCannotConvert = true;
582 else
583 bFail = true;
584 break;
585 default:
586 bCannotConvert = true;
587 break;
590 if (bCannotConvert)
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);
599 if (bFail)
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 &)
607 throw;
609 catch (const IllegalArgumentException &)
611 throw;
613 catch (const BridgeRuntimeError &)
615 throw;
617 catch (const Exception & e)
619 throw BridgeRuntimeError("[automation bridge] unexpected exception in "
620 "UnoConversionUtilities<T>::variantToAny ! Message : \n" +
621 e.Message);
623 catch(...)
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
635 template<class T>
636 void UnoConversionUtilities<T>::anyToVariant(VARIANT* pVariant, const Any& rAny, VARTYPE type)
640 HRESULT hr= S_OK;
642 OSL_ASSERT( (type & VT_BYREF) == 0);
643 if (type & VT_ARRAY)
645 type ^= VT_ARRAY;
646 SAFEARRAY* ar= createUnoSequenceWrapper( rAny, type);
647 if( ar)
649 VariantClear( pVariant);
650 pVariant->vt= ::sal::static_int_cast< VARTYPE, int >( VT_ARRAY | type );
651 pVariant->byref= ar;
654 else if(type == VT_VARIANT)
656 anyToVariant(pVariant, rAny);
658 else
660 CComVariant var;
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 &)
691 throw;
693 catch (const CannotConvertException &)
695 throw;
697 catch (const BridgeRuntimeError&)
699 throw;
701 catch(const Exception & e)
703 throw BridgeRuntimeError(
704 "[automation bridge]UnoConversionUtilities<T>::anyToVariant \n"
705 "Unexpected exception occurred. Message: " + e.Message);
707 catch(...)
709 throw BridgeRuntimeError(
710 "[automation bridge]UnoConversionUtilities<T>::anyToVariant \n"
711 "Unexpected exception occurred.");
715 template<class T>
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;
726 if (rAny >>= xInt)
728 createUnoObjectWrapper(rAny, pVariant);
730 else
732 bIllegal = true;
734 break;
736 case TypeClass_STRUCT:
738 if (rAny.getValueType() == cppu::UnoType<Date>::get() )
740 Date d;
741 if (rAny >>= d)
743 pVariant->vt = VT_DATE;
744 pVariant->date = d.Value;
746 else
748 bIllegal = true;
751 else if(rAny.getValueType() == cppu::UnoType<Decimal>::get())
753 Decimal d;
754 if (rAny >>= d)
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;
763 else
765 bIllegal = true;
768 else if (rAny.getValueType() == cppu::UnoType<Currency>::get())
770 Currency c;
771 if (rAny >>= c)
773 pVariant->vt = VT_CY;
774 pVariant->cyVal.int64 = c.Value;
776 else
778 bIllegal = true;
781 else if(rAny.getValueType() == cppu::UnoType<SCode>::get())
783 SCode s;
784 if (rAny >>= s)
786 pVariant->vt = VT_ERROR;
787 pVariant->scode = s.Value;
789 else
791 bIllegal = true;
794 else
796 createUnoObjectWrapper(rAny, pVariant);
798 break;
800 case TypeClass_SEQUENCE: // sequence ??? SafeArray descriptor
802 SAFEARRAY* pArray = createUnoSequenceWrapper(rAny);
803 if (pArray)
805 V_VT(pVariant) = VT_ARRAY | VT_VARIANT;
806 V_ARRAY(pVariant) = pArray;
808 else
810 bIllegal = true;
812 break;
814 case TypeClass_VOID:
816 HRESULT hr = S_OK;
817 if (FAILED(hr = VariantClear(pVariant)))
819 throw BridgeRuntimeError(
820 "[automation bridge]UnoConversionUtilities<T>::anyToVariant\n"
821 "VariantClear failed with error:" + OUString::number(hr));
823 break;
825 case TypeClass_BOOLEAN:
827 bool value;
828 if (rAny >>= value)
830 pVariant->vt = VT_BOOL;
831 pVariant->boolVal = value ? VARIANT_TRUE: VARIANT_FALSE;
833 else
835 bIllegal = true;
837 break;
839 case TypeClass_CHAR:
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;
845 break;
847 case TypeClass_STRING:
849 OUString value;
850 if (rAny >>= value)
852 pVariant->vt = VT_BSTR;
853 pVariant->bstrVal = sal::systools::BStr::newBSTR(value);
855 else
857 bIllegal = true;
859 break;
861 case TypeClass_FLOAT:
863 float value;
864 if (rAny >>= value)
866 pVariant->vt = VT_R4;
867 pVariant->fltVal = value;
869 else
871 bIllegal = true;
873 break;
875 case TypeClass_DOUBLE:
877 double value;
878 if (rAny >>= value)
880 pVariant->vt = VT_R8;
881 pVariant->dblVal = value;
883 else
885 bIllegal = true;
887 break;
889 case TypeClass_BYTE:
891 // ole automation does not know a signed char but only unsigned char
892 sal_Int8 value;
893 if (rAny >>= value)
895 pVariant->vt = VT_UI1;
896 pVariant->bVal = value;
898 else
900 bIllegal = true;
902 break;
904 case TypeClass_SHORT: // INT16
905 case TypeClass_UNSIGNED_SHORT: // UINT16
907 sal_Int16 value;
908 if (rAny >>= value)
910 pVariant->vt = VT_I2;
911 pVariant->iVal = value;
913 else
915 bIllegal = true;
917 break;
919 case TypeClass_ENUM:
921 sal_Int32 value = *static_cast<sal_Int32 const *>(rAny.getValue());
922 pVariant->vt = VT_I4;
923 pVariant->lVal= value;
924 break;
926 case TypeClass_LONG:
927 case TypeClass_UNSIGNED_LONG:
929 sal_Int32 value;
930 if (rAny >>= value)
932 pVariant->vt = VT_I4;
933 pVariant->lVal= value;
935 else
937 bIllegal = true;
939 break;
941 case TypeClass_HYPER:
944 pVariant->vt = VT_DECIMAL;
945 pVariant->decVal.scale = 0;
946 pVariant->decVal.sign = 0;
947 pVariant->decVal.Hi32 = 0;
949 sal_Int64 value;
950 rAny >>= value;
952 if (value & SAL_CONST_UINT64(0x8000000000000000))
953 pVariant->decVal.sign = DECIMAL_NEG;
955 pVariant->decVal.Lo64 = value;
956 break;
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;
965 sal_uInt64 value;
966 rAny >>= value;
967 pVariant->decVal.Lo64 = value;
968 break;
970 case TypeClass_TYPE:
972 Type type;
973 rAny >>= type;
974 CComVariant var;
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!");
984 break;
986 default:
987 //TypeClass_SERVICE:
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
991 //EXEPINFO structure
992 //TypeClass_TYPEDEF
993 //TypeClass_ANY:
994 //TypeClass_UNKNOWN:
995 //TypeClass_MODULE:
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);
1004 break;
1006 if (bIllegal)
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 &)
1017 throw;
1019 catch (const IllegalArgumentException &)
1021 throw;
1023 catch(const BridgeRuntimeError&)
1025 throw;
1027 catch(const Exception & e)
1029 throw BridgeRuntimeError(
1030 "[automation bridge]UnoConversionUtilities<T>::anyToVariant \n"
1031 "Unexpected exception occurred. Message: " + e.Message);
1033 catch(...)
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);
1044 template<class T>
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();
1059 sal_Int32 dims=0;
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
1086 if( pArray)
1088 // Iterate over every Sequence that contains the actual elements
1089 void* pSAData;
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;
1103 if( dimsSeq > 0)
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]);
1126 curDim++;
1128 else
1130 // There is no Sequence at this index, so skip this index
1131 skipSeq= true;
1132 break;
1136 if( skipSeq)
1137 continue;
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.
1163 VARIANT var;
1164 VariantInit( &var);
1165 anyToVariant( &var, unoElement);
1166 if( elemtype == VT_VARIANT )
1168 VariantCopy( reinterpret_cast<VARIANT*>(psaCurrentData), &var);
1169 VariantClear( &var);
1171 else
1172 memcpy( psaCurrentData, &var.byref, oleElementSize);
1174 psaCurrentData+= oleElementSize;
1177 while( incrementMultidimensionalIndex( dimsSeq, parElementCount, arDimsSeqIndices));
1179 SafeArrayUnaccessData( pArray);
1183 return 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
1198 // 0 based.
1199 template<class T>
1200 bool UnoConversionUtilities<T>::incrementMultidimensionalIndex(sal_Int32 dimensions,
1201 const sal_Int32 * parDimensionLengths,
1202 sal_Int32 * parMultidimensionalIndex)
1204 if( dimensions < 1)
1205 return false;
1207 bool ret= true;
1208 bool carry= true; // to get into the while loop
1210 sal_Int32 currentDimension= dimensions; //most significant is 1
1211 while( carry)
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;
1217 else
1218 carry= false;
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)
1225 carry= false;
1226 ret= false;
1229 return ret;
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.
1237 template<class T>
1238 size_t UnoConversionUtilities<T>::getOleElementSize( VARTYPE type)
1240 size_t size;
1241 switch( 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;
1251 case VT_DISPATCH:
1252 case VT_UNKNOWN: size= sizeof( IUnknown*); break;
1253 case VT_VARIANT: size= sizeof( VARIANT);break;
1254 default: size= 0;
1256 return size;
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
1265 // dimension.
1266 // getElementCountAndTypeOfSequence determines the length of each dimension and calls itself recursively
1267 // in the process.
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,
1270 // must be one.
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)
1278 template<class T>
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);
1303 else
1305 // determine the element type ( e.g. Sequence< Sequence <Sequence <sal_Int32> > > - type is sal_Int32)
1306 typeDesc= pElementDescRef;
1308 typelib_typedescription_release( pSeqDesc);
1312 template<class T>
1313 SAFEARRAY* UnoConversionUtilities<T>::createUnoSequenceWrapper(const Any& rSeq)
1315 SAFEARRAY* pArray = nullptr;
1316 sal_uInt32 n = 0;
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;
1342 VARIANT oleElement;
1343 LONG safeI[1];
1345 pArray = SafeArrayCreate(VT_VARIANT, 1, rgsabound);
1347 Any unoElement;
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);
1357 safeI[0] = i;
1358 SafeArrayPutElement(pArray, safeI, &oleElement);
1360 VariantClear(&oleElement);
1362 TYPELIB_DANGER_RELEASE( pSeqElementDesc);
1364 return pArray;
1367 /* The argument rObj can contain
1368 - UNO struct
1369 - UNO interface
1370 - UNO interface created by this bridge (adapter factory)
1371 - UNO interface created by this bridge ( COM Wrapper)
1373 pVar must be initialized.
1375 template<class T>
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.
1396 if ( ! xInt.is())
1398 pVar->vt = VT_UNKNOWN;
1399 pVar->punkVal = nullptr;
1400 return;
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);
1415 return;
1418 // Is the object a COM wrapper ( either XInvocation, or Adapter object)
1419 // or does it supply an IDispatch by its own ?
1420 else
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))
1430 return;
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);
1448 if (xInv.is())
1450 Reference<XInterface> xNewWrapper = createUnoWrapperInstance();
1451 Reference<css::lang::XInitialization> xInitWrapper(xNewWrapper, UNO_QUERY);
1452 if (xInitWrapper.is())
1454 VARTYPE vartype= getVarType( rObj);
1456 if (xInt.is())
1458 Any params[3];
1459 params[0] <<= xInv;
1460 params[1] <<= xInt;
1461 params[2] <<= vartype;
1462 xInitWrapper->initialize( Sequence<Any>(params, 3));
1464 else
1466 Any params[2];
1467 params[0] <<= xInv;
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
1474 // will be used.
1475 if(xInt.is()) // only interfaces
1476 UnoObjToWrapperMap[reinterpret_cast<sal_uIntPtr>(xInt.get())]= xNewWrapper;
1477 convertSelfToCom(xNewWrapper, pVar);
1478 return;
1483 template<class T>
1484 void UnoConversionUtilities<T>::variantToAny( const VARIANT* pVariant, Any& rAny,
1485 bool bReduceValueRange /* = sal_True */)
1487 HRESULT hr = S_OK;
1490 CComVariant var;
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());
1507 else
1509 switch (var.vt)
1511 case VT_EMPTY:
1512 rAny.setValue(nullptr, Type());
1513 break;
1514 case VT_NULL:
1515 rAny.setValue(nullptr, Type());
1516 break;
1517 case VT_I2:
1518 rAny.setValue( & var.iVal, cppu::UnoType<sal_Int16>::get());
1519 break;
1520 case VT_I4:
1521 rAny.setValue( & var.lVal, cppu::UnoType<sal_Int32>::get());
1522 // necessary for use in JavaScript ( see "reduceRange")
1523 if( bReduceValueRange)
1524 reduceRange(rAny);
1525 break;
1526 case VT_R4:
1527 rAny.setValue( & var.fltVal, cppu::UnoType<float>::get());
1528 break;
1529 case VT_R8:
1530 rAny.setValue(& var.dblVal, cppu::UnoType<double>::get());
1531 break;
1532 case VT_CY:
1534 Currency cy(var.cyVal.int64);
1535 rAny <<= cy;
1536 break;
1538 case VT_DATE:
1540 Date d(var.date);
1541 rAny <<= d;
1542 break;
1544 case VT_BSTR:
1546 OUString b(o3tl::toU(var.bstrVal));
1547 rAny.setValue( &b, cppu::UnoType<decltype(b)>::get());
1548 break;
1550 case VT_UNKNOWN:
1551 case VT_DISPATCH:
1553 //check if it is a UNO type
1554 CComQIPtr<IUnoTypeWrapper> spType(static_cast<IUnknown*>(var.byref));
1555 if (spType)
1557 CComBSTR sName;
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!");
1562 Type type;
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)) +
1568 "does not exist!",
1569 nullptr, TypeClass_UNKNOWN, FailReason::TYPE_NOT_SUPPORTED,0);
1571 rAny <<= type;
1573 else
1575 rAny = createOleObjectWrapper( & var);
1577 break;
1579 case VT_ERROR:
1581 SCode scode(var.scode);
1582 rAny <<= scode;
1583 break;
1585 case VT_BOOL:
1587 rAny <<= (var.boolVal == VARIANT_TRUE);
1588 break;
1590 case VT_I1:
1591 rAny.setValue( & var.cVal, cppu::UnoType<sal_Int8>::get());
1592 break;
1593 case VT_UI1: // there is no unsigned char in UNO
1594 rAny <<= sal_Int8(var.bVal);
1595 break;
1596 case VT_UI2:
1597 rAny.setValue( & var.uiVal, cppu::UnoType<cppu::UnoUnsignedShortType>::get() );
1598 break;
1599 case VT_UI4:
1600 rAny.setValue( & var.ulVal, cppu::UnoType<sal_uInt32>::get());
1601 break;
1602 case VT_INT:
1603 rAny.setValue( & var.intVal, cppu::UnoType<sal_Int32>::get());
1604 break;
1605 case VT_UINT:
1606 rAny.setValue( & var.uintVal, cppu::UnoType<sal_uInt32>::get());
1607 break;
1608 case VT_VOID:
1609 rAny.setValue( nullptr, Type());
1610 break;
1611 case VT_DECIMAL:
1613 Decimal dec;
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;
1619 rAny <<= dec;
1620 break;
1623 default:
1624 break;
1629 catch (const IllegalArgumentException &)
1631 throw;
1633 catch (const CannotConvertException &)
1635 throw;
1637 catch (const BridgeRuntimeError &)
1639 throw;
1641 catch (const Exception & e)
1643 throw BridgeRuntimeError("[automation bridge] unexpected exception in "
1644 "UnoConversionUtilities<T>::variantToAny ! Message : \n" +
1645 e.Message);
1647 catch(...)
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
1664 // several other
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.
1678 template<class T>
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;
1695 if (spUnknown)
1696 spUnknown.QueryInterface( & spDispatch.p);
1698 else if (pVar->vt == VT_DISPATCH && pVar->pdispVal != nullptr)
1700 CComPtr<IDispatch> spDispatch2(pVar->pdispVal);
1701 if (spDispatch2)
1702 spDispatch2.QueryInterface( & spUnknown.p);
1705 static Type VOID_TYPE;
1706 Any ret;
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)
1713 switch (pVar->vt)
1715 case VT_EMPTY:
1716 case VT_UNKNOWN:
1717 desiredType = cppu::UnoType<XInterface>::get();
1718 break;
1719 case VT_DISPATCH:
1720 desiredType = cppu::UnoType<XInvocation>::get();
1721 break;
1722 default:
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);
1735 else
1736 ret <<= xInt;
1737 return ret;
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);
1745 if( spUno)
1746 { // it is a wrapper
1747 Reference<XInterface> xInt;
1748 if( SUCCEEDED( spUno->getOriginalUnoObject( &xInt)))
1750 ret <<= xInt;
1752 else
1754 Any any;
1755 if( SUCCEEDED( spUno->getOriginalUnoStruct(&any)))
1756 ret= any;
1758 return ret;
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
1775 //to the wrapper.
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);
1789 else
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);
1802 else
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);
1814 return ret;
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());
1836 Any params[3];
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);
1852 else
1854 Reference<XInterface> xIntAdapter =
1855 createAdapter(seqTypes, xIntNewProxy);
1856 ret = xIntAdapter->queryInterface(desiredType);
1858 return ret;
1860 template<class T>
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())));
1890 return xIntAdapted;
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).
1895 template<class T>
1896 bool UnoConversionUtilities<T>::convertValueObject( const VARIANTARG *var, Any& any)
1898 bool ret = false;
1901 bool bFail = false;
1902 HRESULT hr= S_OK;
1903 CComVariant varDisp;
1905 if(SUCCEEDED(hr = varDisp.ChangeType( VT_DISPATCH, var)))
1907 CComPtr <IJScriptValueObject> spValue;
1908 VARIANT_BOOL varBool;
1909 CComBSTR bstrType;
1910 CComVariant varValue;
1911 CComPtr<IDispatch> spDisp( varDisp.pdispVal);
1912 if(spDisp)
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)))
1927 Type type;
1928 if (getType(bstrType, type))
1929 variantToAny( & varValue, any, type);
1930 else
1931 bFail = true;
1933 else
1934 bFail = true;
1937 else
1938 bFail = true;
1942 else if( hr != DISP_E_TYPEMISMATCH && hr != E_NOINTERFACE)
1943 bFail = true;
1945 if (bFail)
1946 throw BridgeRuntimeError(
1947 "[automation bridge] Conversion of ValueObject failed ");
1949 catch (const BridgeRuntimeError &)
1951 throw;
1953 catch (const Exception & e)
1955 throw BridgeRuntimeError("[automation bridge] unexpected exception in "
1956 "UnoConversionUtilities<T>::convertValueObject ! Message : \n" +
1957 e.Message);
1959 catch(...)
1961 throw BridgeRuntimeError(
1962 "[automation bridge] unexpected exception in "
1963 "UnoConversionUtilities<T>::convertValueObject !");
1965 return ret;
1968 template<class T>
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;
1977 HRESULT hr;
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!");
1983 DISPID dispid;
1984 DISPPARAMS param= {nullptr,nullptr,0,0};
1985 CComVariant result;
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 &param, &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;
2003 result.Clear();
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 &param, &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
2047 Any any;
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);
2070 else
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);
2078 } // else
2079 result.Clear();
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 &)
2086 throw;
2088 catch (const Exception & e)
2090 throw BridgeRuntimeError("[automation bridge] unexpected exception in "
2091 "UnoConversionUtilities<T>::convertValueObject ! Message : \n" +
2092 e.Message);
2094 catch(...)
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.
2108 template<class T>
2109 Sequence<Any> UnoConversionUtilities<T>::createOleArrayWrapperOfDim(SAFEARRAY* pArray,
2110 unsigned int dimCount, unsigned int actDim, LONG* index, VARTYPE type, const Type& unotype)
2112 LONG lBound;
2113 LONG uBound;
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]++)
2125 if (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());
2132 else
2134 VARIANT variant;
2136 VariantInit(&variant);
2138 V_VT(&variant) = type;
2140 switch (type)
2142 case VT_I2:
2143 SafeArrayGetElement(pArray, index, &V_I2(&variant));
2144 break;
2145 case VT_I4:
2146 SafeArrayGetElement(pArray, index, &V_I4(&variant));
2147 break;
2148 case VT_R4:
2149 SafeArrayGetElement(pArray, index, &V_R4(&variant));
2150 break;
2151 case VT_R8:
2152 SafeArrayGetElement(pArray, index, &V_R8(&variant));
2153 break;
2154 case VT_CY:
2155 SafeArrayGetElement(pArray, index, &V_CY(&variant));
2156 break;
2157 case VT_DATE:
2158 SafeArrayGetElement(pArray, index, &V_DATE(&variant));
2159 break;
2160 case VT_BSTR:
2161 SafeArrayGetElement(pArray, index, &V_BSTR(&variant));
2162 break;
2163 case VT_DISPATCH:
2164 SafeArrayGetElement(pArray, index, &V_DISPATCH(&variant));
2165 break;
2166 case VT_ERROR:
2167 SafeArrayGetElement(pArray, index, &V_ERROR(&variant));
2168 break;
2169 case VT_BOOL:
2170 SafeArrayGetElement(pArray, index, &V_BOOL(&variant));
2171 break;
2172 case VT_VARIANT:
2173 SafeArrayGetElement(pArray, index, &variant);
2174 break;
2175 case VT_UNKNOWN:
2176 SafeArrayGetElement(pArray, index, &V_UNKNOWN(&variant));
2177 break;
2178 case VT_I1:
2179 SafeArrayGetElement(pArray, index, &V_I1(&variant));
2180 break;
2181 case VT_UI1:
2182 SafeArrayGetElement(pArray, index, &V_UI1(&variant));
2183 break;
2184 case VT_UI2:
2185 SafeArrayGetElement(pArray, index, &V_UI2(&variant));
2186 break;
2187 case VT_UI4:
2188 SafeArrayGetElement(pArray, index, &V_UI4(&variant));
2189 break;
2190 default:
2191 break;
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);
2197 else
2198 variantToAny(&variant, pUnoArray[index[actDim - 1] - lBound],
2199 getElementTypeOfSequence(unotype), false);
2201 VariantClear(&variant);
2204 return anySeq;
2207 template<class T>
2208 Type UnoConversionUtilities<T>::getElementTypeOfSequence( const Type& seqType)
2210 Type retValue;
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);
2219 return retValue;
2221 template<class T>
2222 Sequence<Any> UnoConversionUtilities<T>::createOleArrayWrapper(SAFEARRAY* pArray, VARTYPE type, const Type& unoType)
2224 sal_uInt32 dim = SafeArrayGetDim(pArray);
2226 Sequence<Any> ret;
2228 if (dim > 0)
2230 std::unique_ptr<LONG[]> sarIndex(new LONG[dim]);
2231 LONG * index = sarIndex.get();
2233 for (unsigned int i = 0; i < dim; i++)
2235 index[i] = 0;
2238 ret = createOleArrayWrapperOfDim(pArray, dim, dim, index, type, unoType);
2241 return ret;
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
2250 template<class T>
2251 bool UnoConversionUtilities<T>::isJScriptArray(const VARIANT* rvar)
2253 OSL_ENSURE( rvar->vt == VT_DISPATCH, "param is not a VT_DISPATCH");
2254 HRESULT hr;
2255 OLECHAR const * sindex= L"0";
2256 DISPID id;
2257 if ( rvar->vt == VT_DISPATCH && rvar->pdispVal )
2259 hr= rvar->pdispVal->GetIDsOfNames(
2260 IID_NULL, const_cast<OLECHAR **>(&sindex), 1, LOCALE_USER_DEFAULT,
2261 &id);
2263 if( SUCCEEDED ( hr) )
2264 return true;
2267 return false;
2270 template<class T>
2271 VARTYPE UnoConversionUtilities<T>::mapTypeClassToVartype( TypeClass type)
2273 VARTYPE ret;
2274 switch( type)
2276 case TypeClass_INTERFACE: ret= VT_DISPATCH;
2277 break;
2278 case TypeClass_STRUCT: ret= VT_DISPATCH;
2279 break;
2280 case TypeClass_ENUM: ret= VT_I4;
2281 break;
2282 case TypeClass_SEQUENCE: ret= VT_ARRAY;
2283 break;
2284 case TypeClass_ANY: ret= VT_VARIANT;
2285 break;
2286 case TypeClass_BOOLEAN: ret= VT_BOOL;
2287 break;
2288 case TypeClass_CHAR: ret= VT_I2;
2289 break;
2290 case TypeClass_STRING: ret= VT_BSTR;
2291 break;
2292 case TypeClass_FLOAT: ret= VT_R4;
2293 break;
2294 case TypeClass_DOUBLE: ret= VT_R8;
2295 break;
2296 case TypeClass_BYTE: ret= VT_UI1;
2297 break;
2298 case TypeClass_SHORT: ret= VT_I2;
2299 break;
2300 case TypeClass_LONG: ret= VT_I4;
2301 break;
2302 case TypeClass_UNSIGNED_SHORT: ret= VT_UI2;
2303 break;
2304 case TypeClass_UNSIGNED_LONG: ret= VT_UI4;
2305 break;
2306 default:
2307 ret= VT_EMPTY;
2309 return ret;
2312 template<class T>
2313 Sequence<Type> UnoConversionUtilities<T>::getImplementedInterfaces(IUnknown* pUnk)
2315 Sequence<Type> seqTypes;
2316 CComDispatchDriver disp( pUnk);
2317 if( disp)
2319 CComVariant var;
2320 HRESULT hr= S_OK;
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);
2326 if (SUCCEEDED( hr))
2328 // we expect an array( SafeArray or IDispatch) of Strings.
2329 Any anyNames;
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++)
2338 OUString typeName;
2339 seqAny[i] >>= typeName;
2340 pseqTypes[i]= Type( TypeClass_INTERFACE, typeName);
2345 return seqTypes;
2347 template<class T>
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: */