Version 6.4.0.0.beta1, tag libreoffice-6.4.0.0.beta1
[LibreOffice.git] / extensions / source / ole / unoconversionutilities.hxx
blob90178e2a6a212942e796979197c0e63f68608ef5
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 #ifndef INCLUDED_EXTENSIONS_SOURCE_OLE_UNOCONVERSIONUTILITIES_HXX
20 #define INCLUDED_EXTENSIONS_SOURCE_OLE_UNOCONVERSIONUTILITIES_HXX
22 #include <memory>
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/oleautomation/Date.hpp>
28 #include <com/sun/star/bridge/oleautomation/Currency.hpp>
29 #include <com/sun/star/bridge/oleautomation/SCode.hpp>
30 #include <com/sun/star/bridge/oleautomation/Decimal.hpp>
31 #include <typelib/typedescription.hxx>
32 #include <o3tl/any.hxx>
33 #include <o3tl/char16_t2wchar_t.hxx>
34 #include "ole2uno.hxx"
35 #include <cppuhelper/weakref.hxx>
37 #include "unotypewrapper.hxx"
38 #include <unordered_map>
40 // for some reason DECIMAL_NEG (wtypes.h) which contains BYTE is not resolved.
41 typedef unsigned char BYTE;
42 // classes for wrapping uno objects
43 #define INTERFACE_OLE_WRAPPER_IMPL 1
44 #define UNO_OBJECT_WRAPPER_REMOTE_OPT 2
46 #define INVOCATION_SERVICE "com.sun.star.script.Invocation"
49 // classes for wrapping ole objects
50 #define IUNKNOWN_WRAPPER_IMPL 1
52 #define INTERFACE_ADAPTER_FACTORY "com.sun.star.script.InvocationAdapterFactory"
53 // COM or JScript objects implementing UNO interfaces have to implement this property
54 #define SUPPORTED_INTERFACES_PROP L"_implementedInterfaces"
55 // Second property without leading underscore for use in VB
56 #define SUPPORTED_INTERFACES_PROP2 L"Bridge_ImplementedInterfaces"
58 using namespace com::sun::star::script;
59 using namespace com::sun::star::beans;
60 using namespace com::sun::star::uno;
61 using namespace com::sun::star::bridge::oleautomation;
63 extern std::unordered_map<sal_uIntPtr, sal_uIntPtr> AdapterToWrapperMap;
64 extern std::unordered_map<sal_uIntPtr, sal_uIntPtr> WrapperToAdapterMap;
66 //Maps IUnknown pointers to a weak reference of the respective wrapper class (e.g.
67 // IUnknownWrapperImpl. It is the responsibility of the wrapper to remove the entry when
68 // it is being destroyed.
69 // Used to ensure that an Automation object is always mapped to the same UNO objects.
70 extern std::unordered_map<sal_uIntPtr, WeakReference<XInterface> > ComPtrToWrapperMap;
72 // Maps XInterface pointers to a weak reference of its wrapper class (i.e.
73 // InterfaceOleWrapper). It is the responsibility of the wrapper to remove the entry when
74 // it is being destroyed. It is used to ensure the identity of objects. That is, a UNO interface
75 // is mapped to IDispatch which is kept alive in the COM environment. If the same
76 // UNO interface is mapped again to COM then the IDispach of the first mapped instance
77 // must be returned.
78 extern std::unordered_map<sal_uIntPtr, WeakReference<XInterface> > UnoObjToWrapperMap;
80 // createUnoObjectWrapper gets a wrapper instance by calling createUnoWrapperInstance
81 // and initializes it via XInitialization. The wrapper object is required to implement
82 // XBridgeSupplier so that it can convert itself to IDispatch.
83 // class T: Deriving class ( must implement XInterface )
84 /** All methods are allowed to throw at least a BridgeRuntimeError.
86 template< class >
87 class UnoConversionUtilities
89 public:
90 explicit UnoConversionUtilities( const Reference<XMultiServiceFactory> & smgr):
91 m_nUnoWrapperClass( INTERFACE_OLE_WRAPPER_IMPL),
92 m_nComWrapperClass( IUNKNOWN_WRAPPER_IMPL),
93 m_smgr( smgr)
96 UnoConversionUtilities( const Reference<XMultiServiceFactory> & xFactory, sal_uInt8 unoWrapperClass, sal_uInt8 comWrapperClass )
97 : m_nUnoWrapperClass(unoWrapperClass),
98 m_nComWrapperClass(comWrapperClass), m_smgr(xFactory)
101 virtual ~UnoConversionUtilities() {}
102 /** converts only into oleautomation types, that is there is no VT_I1, VT_UI2, VT_UI4
103 a sal_Unicode character is converted into a BSTR.
104 @exception com.sun.star.lang.IllegalArgumentException
105 If the any was inappropriate for conversion.
106 @exception com.sun.star.script.CannotConvertException
107 The any contains a type class for which no conversion is provided.
109 void anyToVariant(VARIANT* pVariant, const Any& rAny);
110 void anyToVariant(VARIANT* pVariant, const Any& rAny, VARTYPE type);
112 /** @exception com.sun.star.lang.IllegalArgumentException
113 If rSeq does not contain a sequence then the exception is thrown.
115 SAFEARRAY* createUnoSequenceWrapper(const Any& rSeq);
116 /** @exception com.sun.star.lang.IllegalArgumentException
117 If rSeq does not contain a sequence or elemtype has no proper value
118 then the exception is thrown.
120 SAFEARRAY* createUnoSequenceWrapper(const Any& rSeq, VARTYPE elemtype);
122 @exception com.sun.star.lang.IllegalArgumentException
123 If rObj does not contain a struct or interface
125 void createUnoObjectWrapper(const Any & rObj, VARIANT * pVar);
126 /** @exception CannotConvertException
127 Thrown if the VARIANT contains a type that cannot be coerced in the expected Any.
128 ArgumentIndex is 0.
129 @IllegalArgumentException
130 Thrown if the VARIANT is inappropriate for conversion. ArgumentPosition is -1,
132 void variantToAny(const VARIANT* pVariant, Any& rAny, bool bReduceValueRange = true);
133 /** This method converts variants arguments in calls from COM -> UNO. Only then
134 the expected UNO type is known.
135 @exception CannotConvertException
136 Thrown if the VARIANT contains a type that cannot be coerced in the expected Any.
137 ArgumentIndex is 0.
138 @IllegalArgumentException
139 Thrown if the VARIANT is inappropriate for conversion. ArgumentPosition is -1,
141 void variantToAny( const VARIANTARG* pArg, Any& rAny, const Type& ptype, bool bReduceValueRange = true);
144 @exception IllegalArgumentException
145 -if pVar does not contain VT_UNKNOWN or VT_DISPATCH or
146 pVar is used for a particular UNO type which is not supported by pVar
148 Any createOleObjectWrapper(VARIANT* pVar, const Type& aType= Type());
151 Return true means var contained a ValueObject, and it was successfully converted.
152 The result is in any. It an error occurred a BridgeRuntimeError will be thrown.
154 bool convertValueObject( const VARIANTARG *var, Any& any);
155 void dispatchExObject2Sequence( const VARIANTARG* pvar, Any& anySeq, const Type& type);
157 Sequence<Any> createOleArrayWrapperOfDim(SAFEARRAY* pArray, unsigned int dimCount, unsigned int actDim, long* index,
158 VARTYPE type, const Type& unotype);
159 Sequence<Any> createOleArrayWrapper(SAFEARRAY* pArray, VARTYPE type, const Type& unotype= Type());
162 VARTYPE mapTypeClassToVartype( TypeClass type);
163 Reference< XSingleServiceFactory > getInvocationFactory(const Any& anyObject);
166 virtual Reference< XInterface > createUnoWrapperInstance()=0;
167 virtual Reference< XInterface > createComWrapperInstance()=0;
169 static bool isJScriptArray(const VARIANT* pvar);
171 Sequence<Type> getImplementedInterfaces(IUnknown* pUnk);
173 protected:
174 Reference<XInterface> createAdapter(const Sequence<Type>& types, const Reference<XInterface>& receiver);
176 // helper function for Sequence conversion
177 void getElementCountAndTypeOfSequence( const Any& rSeq, sal_Int32 dim, Sequence< sal_Int32 >& seqElementCounts, TypeDescription& typeDesc);
178 // helper function for Sequence conversion
179 static bool incrementMultidimensionalIndex(sal_Int32 dimensions, const sal_Int32 * parDimensionLength,
180 sal_Int32 * parMultidimensionalIndex);
181 // helper function for Sequence conversion
182 static size_t getOleElementSize( VARTYPE type);
184 static Type getElementTypeOfSequence( const Type& seqType);
186 //Provides a typeconverter
187 Reference<XTypeConverter> getTypeConverter();
189 // This member determines what class is used to convert a UNO object
190 // or struct to a COM object. It is passed along to the anyToVariant
191 // function in the createBridge function implementation
192 const sal_uInt8 m_nUnoWrapperClass;
193 const sal_uInt8 m_nComWrapperClass;
195 // The servicemanager is either a local smgr or remote when the service
196 // com.sun.star.bridge.OleBridgeSupplierVar1 is used. This service can be
197 // created by createInstanceWithArguments where one can supply a service
198 // manager that is to be used.
199 // Local service manager as supplied by the loader when the creator function
200 // of the service is being called.
201 Reference<XMultiServiceFactory> m_smgr;
202 // An explicitly supplied service manager when the service
203 // com.sun.star.bridge.OleBridgeSupplierVar1 is used. That can be a remote
204 // manager.
205 Reference<XMultiServiceFactory> m_smgrRemote;
206 Reference<XSingleServiceFactory> m_xInvocationFactoryLocal;
207 Reference<XSingleServiceFactory> m_xInvocationFactoryRemote;
209 private:
210 // Holds the type converter which is used for sequence conversion etc.
211 // Use the getTypeConverter function to obtain the interface.
212 Reference<XTypeConverter> m_typeConverter;
217 // ask the object for XBridgeSupplier2 and on success bridges
218 // the uno object to IUnknown or IDispatch.
219 // return true the UNO object supports
220 template < class T >
221 bool convertSelfToCom( T& unoInterface, VARIANT * pVar)
223 bool ret = false;
224 Reference< XInterface > xInt( unoInterface, UNO_QUERY);
225 if( xInt.is())
227 Reference< XBridgeSupplier2 > xSupplier( xInt, UNO_QUERY);
228 if( xSupplier.is())
230 sal_Int8 arId[16];
231 rtl_getGlobalProcessId( reinterpret_cast<sal_uInt8*>(arId));
232 Sequence<sal_Int8> seqId( arId, 16);
233 Any anySource;
234 anySource <<= xInt;
235 Any anyDisp = xSupplier->createBridge(anySource, seqId, UNO, OLE);
237 // due to global-process-id check this must be in-process pointer
238 if (auto v = o3tl::tryAccess<sal_uIntPtr>(anyDisp))
240 VARIANT* pvariant= reinterpret_cast<VARIANT*>(*v);
241 HRESULT hr;
242 if (FAILED(hr = VariantCopy(pVar, pvariant)))
243 throw BridgeRuntimeError(
244 "[automation bridge] convertSelfToCom\n"
245 "VariantCopy failed! Error: " +
246 OUString::number(hr));
247 VariantClear( pvariant);
248 CoTaskMemFree( pvariant);
249 ret = true;
253 return ret;
257 // Gets the invocation factory depending on the Type in the Any.
258 // The factory can be created by a local or remote multi service factory.
259 // In case there is a remote multi service factory available there are
260 // some services or types for which the local factory is used. The exceptions
261 // are: all structs.
262 // Param anyObject - contains the object ( interface, struct) for what we need an invocation object.
264 template<class T>
265 Reference< XSingleServiceFactory > UnoConversionUtilities<T>::getInvocationFactory(const Any& anyObject)
267 Reference< XSingleServiceFactory > retVal;
268 MutexGuard guard( getBridgeMutex());
269 if( anyObject.getValueTypeClass() != TypeClass_STRUCT &&
270 m_smgrRemote.is() )
272 if( ! m_xInvocationFactoryRemote.is() )
273 m_xInvocationFactoryRemote.set(m_smgrRemote->createInstance( INVOCATION_SERVICE), UNO_QUERY);
274 retVal= m_xInvocationFactoryRemote;
276 else
278 if( ! m_xInvocationFactoryLocal.is() )
279 m_xInvocationFactoryLocal.set(m_smgr->createInstance(INVOCATION_SERVICE ), UNO_QUERY);
280 retVal= m_xInvocationFactoryLocal;
282 return retVal;
285 template<class T>
286 void UnoConversionUtilities<T>::variantToAny( const VARIANTARG* pArg, Any& rAny, const Type& ptype, bool bReduceValueRange /* = sal_True */)
290 HRESULT hr;
291 bool bFail = false;
292 bool bCannotConvert = false;
293 CComVariant var;
295 // There is no need to support indirect values, since they're not supported by UNO
296 if( FAILED(hr= VariantCopyInd( &var, pArg))) // remove VT_BYREF
297 throw BridgeRuntimeError(
298 "[automation bridge] UnoConversionUtilities<T>::variantToAny \n"
299 "VariantCopyInd failed for reason : " + OUString::number(hr));
300 bool bHandled = convertValueObject( & var, rAny);
301 if( bHandled)
302 OSL_ENSURE( rAny.getValueType() == ptype, "type in Value Object must match the type parameter");
304 if( ! bHandled)
306 // convert into a variant type that is the equivalent to the type
307 // the sequence expects. Thus variantToAny produces the correct type
308 // E.g. An Array object contains VT_I4 and the sequence expects shorts
309 // than the vartype must be changed. The reason is, you can't specify the
310 // type in JavaScript and the script engine determines the type being used.
311 switch( ptype.getTypeClass())
313 case TypeClass_CHAR: // could be: new Array( 12, 'w', "w")
314 if( var.vt == VT_BSTR)
316 if(SUCCEEDED( hr= VariantChangeType( &var, &var, 0, VT_BSTR)))
317 rAny.setValue( V_BSTR( &var), ptype);
318 else if (hr == DISP_E_TYPEMISMATCH)
319 bCannotConvert = true;
320 else
321 bFail = true;
323 else
325 if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_I2)))
326 rAny.setValue(& var.iVal, ptype);
327 else if (hr == DISP_E_TYPEMISMATCH)
328 bCannotConvert = true;
329 else
330 bFail = true;
332 break;
333 case TypeClass_INTERFACE: // could also be an IUnknown
334 case TypeClass_STRUCT:
336 rAny = createOleObjectWrapper( & var, ptype);
337 break;
339 case TypeClass_ENUM:
340 if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_I4)))
341 rAny.setValue(& var.lVal, ptype);
342 else if (hr == DISP_E_TYPEMISMATCH)
343 bCannotConvert = true;
344 else
345 bFail = true;
346 break;
347 case TypeClass_SEQUENCE:
348 // There are different ways of receiving a sequence:
349 // 1: JScript, VARTYPE: VT_DISPATCH
350 // 2. VBScript simple arraysVT_VARIANT|VT_BYREF the referenced VARIANT contains
351 // a VT_ARRAY| <type>
352 // 3. VBScript multi dimensional arrays: VT_ARRAY|VT_BYREF
353 if( pArg->vt == VT_DISPATCH)
355 dispatchExObject2Sequence( pArg, rAny, ptype);
357 else
359 if ((var.vt & VT_ARRAY) != 0)
361 VARTYPE oleType = ::sal::static_int_cast< VARTYPE, int >( var.vt ^ VT_ARRAY );
362 Sequence<Any> unoSeq = createOleArrayWrapper( var.parray, oleType, ptype);
363 Reference<XTypeConverter> conv = getTypeConverter();
364 if (conv.is())
368 Any anySeq = makeAny(unoSeq);
369 Any convAny = conv->convertTo(anySeq, ptype);
370 rAny = convAny;
372 catch (const IllegalArgumentException& e)
374 throw BridgeRuntimeError(
375 "[automation bridge]com.sun.star.lang.IllegalArgumentException "
376 "in UnoConversionUtilities<T>::variantToAny! Message: " +
377 e.Message);
379 catch (const CannotConvertException& e)
381 throw BridgeRuntimeError(
382 "[automation bridge]com.sun.star.script.CannotConvertException "
383 "in UnoConversionUtilities<T>::variantToAny! Message: " +
384 e.Message);
389 break;
390 case TypeClass_VOID:
391 rAny.setValue(nullptr,Type());
392 break;
393 case TypeClass_ANY: // Any
394 // There could be a JScript Array that needs special handling
395 // If an Any is expected and this Any must contain a Sequence
396 // then we cannot figure out what element type is required.
397 // Therefore we convert to Sequence< Any >
398 if( pArg->vt == VT_DISPATCH && isJScriptArray( pArg))
400 dispatchExObject2Sequence( pArg, rAny,
401 cppu::UnoType<Sequence<Any>>::get());
403 else if (pArg->vt == VT_DECIMAL)
405 //Decimal maps to hyper in calls from COM -> UNO
406 // It does not matter if we create a sal_uInt64 or sal_Int64,
407 // because the UNO object is called through invocation which
408 //will do a type conversion if necessary
409 if (var.decVal.sign == 0)
411 // positive value
412 variantToAny( & var, rAny, cppu::UnoType<sal_uInt64>::get(),
413 bReduceValueRange);
415 else
417 //negative value
418 variantToAny( & var, rAny, cppu::UnoType<sal_Int64>::get(),
419 bReduceValueRange);
422 else
424 variantToAny( & var, rAny);
426 break;
427 case TypeClass_BOOLEAN: // VARIANT could be VARIANT_BOOL or other
428 if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_BOOL)))
429 variantToAny( & var, rAny);
430 else if (hr == DISP_E_TYPEMISMATCH)
431 bCannotConvert = true;
432 else
433 bFail = true;
434 break;
435 case TypeClass_STRING: // UString
436 if(var.vt == VT_NULL)
437 var = CComBSTR("");
438 if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_BSTR)))
439 variantToAny( & var, rAny);
440 else if (hr == DISP_E_TYPEMISMATCH)
441 bCannotConvert = true;
442 else
443 bFail = true;
444 break;
445 case TypeClass_FLOAT: // float
446 if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_R4)))
447 variantToAny( & var, rAny);
448 else if (hr == DISP_E_TYPEMISMATCH)
449 bCannotConvert = true;
450 else
451 bFail = true;
452 break;
453 case TypeClass_DOUBLE: // double
454 if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_R8)))
455 variantToAny(& var, rAny);
456 else if (hr == DISP_E_TYPEMISMATCH)
457 bCannotConvert = true;
458 else
459 bFail = true;
460 break;
461 case TypeClass_BYTE: // BYTE
462 if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_I1)))
463 variantToAny( & var, rAny);
464 else if (hr == DISP_E_TYPEMISMATCH)
465 bCannotConvert = true;
466 else
467 bFail = true;
468 break;
469 case TypeClass_SHORT: // INT16
470 if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_I2)))
471 variantToAny( & var, rAny);
472 else if (hr == DISP_E_TYPEMISMATCH)
473 bCannotConvert = true;
474 else
475 bFail = true;
476 break;
477 case TypeClass_LONG:
478 if(SUCCEEDED(hr = VariantChangeType(& var, &var, 0, VT_I4)))
479 variantToAny( & var, rAny, bReduceValueRange);
480 else if (hr == DISP_E_TYPEMISMATCH)
481 bCannotConvert = true;
482 else
483 bFail = true;
484 break;
485 case TypeClass_HYPER:
486 if(SUCCEEDED(hr = VariantChangeType(& var, &var, 0, VT_DECIMAL)))
488 if (var.decVal.Lo64 > SAL_CONST_UINT64(0x8000000000000000)
489 || var.decVal.Hi32 > 0
490 || var.decVal.scale > 0)
492 bFail = true;
493 break;
495 sal_Int64 value = var.decVal.Lo64;
496 if (var.decVal.sign == DECIMAL_NEG)
497 value |= SAL_CONST_UINT64(0x8000000000000000);
498 rAny <<= value;
500 else if (hr == DISP_E_TYPEMISMATCH)
501 bCannotConvert = true;
502 else
503 bFail = true;
504 break;
505 case TypeClass_UNSIGNED_SHORT: // UINT16
506 if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_UI2)))
507 variantToAny( & var, rAny);
508 else if (hr == DISP_E_TYPEMISMATCH)
509 bCannotConvert = true;
510 else
511 bFail = true;
512 break;
513 case TypeClass_UNSIGNED_LONG:
514 if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_UI4)))
515 variantToAny( & var, rAny, bReduceValueRange);
516 else if (hr == DISP_E_TYPEMISMATCH)
517 bCannotConvert = true;
518 else
519 bFail = true;
520 break;
521 case TypeClass_UNSIGNED_HYPER:
522 if(SUCCEEDED(hr = VariantChangeType(& var, &var, 0, VT_DECIMAL)))
524 if (var.decVal.Hi32 > 0 || var.decVal.scale > 0)
526 bFail = true;
527 break;
529 rAny <<= var.decVal.Lo64;
531 else if (hr == DISP_E_TYPEMISMATCH)
532 bCannotConvert = true;
533 else
534 bFail = true;
535 break;
536 case TypeClass_TYPE:
537 if(SUCCEEDED(hr = VariantChangeType(& var, &var, 0, VT_UNKNOWN)))
538 variantToAny( & var, rAny);
539 else if (hr == DISP_E_TYPEMISMATCH)
540 bCannotConvert = true;
541 else
542 bFail = true;
543 break;
544 default:
545 bCannotConvert = true;
546 break;
549 if (bCannotConvert)
550 throw CannotConvertException(
551 "[automation bridge]UnoConversionUtilities<T>::variantToAny \n"
552 "Cannot convert the value of vartype :\"" +
553 OUString::number(static_cast<sal_Int32>(var.vt)) +
554 "\" to the expected UNO type of type class: " +
555 OUString::number(static_cast<sal_Int32>(ptype.getTypeClass())),
556 nullptr, TypeClass_UNKNOWN, FailReason::TYPE_NOT_SUPPORTED,0);
558 if (bFail)
559 throw IllegalArgumentException(
560 "[automation bridge]UnoConversionUtilities<T>:variantToAny\n"
561 "The provided VARIANT of type\" " + OUString::number(static_cast<sal_Int32>(var.vt)) +
562 "\" is unappropriate for conversion!", Reference<XInterface>(), -1);
564 catch (const CannotConvertException &)
566 throw;
568 catch (const IllegalArgumentException &)
570 throw;
572 catch (const BridgeRuntimeError &)
574 throw;
576 catch (const Exception & e)
578 throw BridgeRuntimeError("[automation bridge] unexpected exception in "
579 "UnoConversionUtilities<T>::variantToAny ! Message : \n" +
580 e.Message);
582 catch(...)
584 throw BridgeRuntimeError(
585 "[automation bridge] unexpected exception in "
586 "UnoConversionUtilities<T>::variantToAny !");
590 // The function only converts Sequences to SAFEARRAYS with elements of the type
591 // specified by the parameter type. Everything else is forwarded to
592 // anyToVariant(VARIANT* pVariant, const Any& rAny)
593 // Param type must not be VT_BYREF
594 template<class T>
595 void UnoConversionUtilities<T>::anyToVariant(VARIANT* pVariant, const Any& rAny, VARTYPE type)
599 HRESULT hr= S_OK;
601 OSL_ASSERT( (type & VT_BYREF) == 0);
602 if (type & VT_ARRAY)
604 type ^= VT_ARRAY;
605 SAFEARRAY* ar= createUnoSequenceWrapper( rAny, type);
606 if( ar)
608 VariantClear( pVariant);
609 pVariant->vt= ::sal::static_int_cast< VARTYPE, int >( VT_ARRAY | type );
610 pVariant->byref= ar;
613 else if(type == VT_VARIANT)
615 anyToVariant(pVariant, rAny);
617 else
619 CComVariant var;
620 anyToVariant( &var, rAny);
621 if(FAILED(hr = VariantChangeType(&var, &var, 0, type)))
623 if (hr == DISP_E_TYPEMISMATCH)
624 throw CannotConvertException(
625 "[automation bridge]UnoConversionUtilities<T>::anyToVariant \n"
626 "Cannot convert the value of type :\"" +
627 rAny.getValueTypeName() +
628 "\" to the expected Automation type of VARTYPE: " +
629 OUString::number(static_cast<sal_Int32>(type)),
630 nullptr, TypeClass_UNKNOWN, FailReason::TYPE_NOT_SUPPORTED,0);
632 throw BridgeRuntimeError(
633 "[automation bridge]UnoConversionUtilities<T>::anyToVariant \n"
634 "Conversion of any with " +
635 rAny.getValueType().getTypeName() +
636 " to VARIANT with type: " + OUString::number(static_cast<sal_Int32>(type)) +
637 " failed! Error code: " + OUString::number(hr));
640 if(FAILED(hr = VariantCopy(pVariant, &var)))
642 throw BridgeRuntimeError(
643 "[automation bridge]UnoConversionUtilities<T>::anyToVariant \n"
644 "VariantCopy failed for reason: " + OUString::number(hr));
648 catch (const IllegalArgumentException &)
650 throw;
652 catch (const CannotConvertException &)
654 throw;
656 catch (const BridgeRuntimeError&)
658 throw;
660 catch(const Exception & e)
662 throw BridgeRuntimeError(
663 "[automation bridge]UnoConversionUtilities<T>::anyToVariant \n"
664 "Unexpected exception occurred. Message: " + e.Message);
666 catch(...)
668 throw BridgeRuntimeError(
669 "[automation bridge]UnoConversionUtilities<T>::anyToVariant \n"
670 "Unexpected exception occurred.");
674 template<class T>
675 void UnoConversionUtilities<T>::anyToVariant(VARIANT* pVariant, const Any& rAny)
679 bool bIllegal = false;
680 switch (rAny.getValueTypeClass())
682 case TypeClass_INTERFACE:
684 Reference<XInterface> xInt;
685 if (rAny >>= xInt)
687 createUnoObjectWrapper(rAny, pVariant);
689 else
691 bIllegal = true;
693 break;
695 case TypeClass_STRUCT:
697 if (rAny.getValueType() == cppu::UnoType<Date>::get() )
699 Date d;
700 if (rAny >>= d)
702 pVariant->vt = VT_DATE;
703 pVariant->date = d.Value;
705 else
707 bIllegal = true;
710 else if(rAny.getValueType() == cppu::UnoType<Decimal>::get())
712 Decimal d;
713 if (rAny >>= d)
715 pVariant->vt = VT_DECIMAL;
716 pVariant->decVal.scale = d.Scale;
717 pVariant->decVal.sign = d.Sign;
718 pVariant->decVal.Lo32 = d.LowValue;
719 pVariant->decVal.Mid32 = d.MiddleValue;
720 pVariant->decVal.Hi32 = d.HighValue;
722 else
724 bIllegal = true;
727 else if (rAny.getValueType() == cppu::UnoType<Currency>::get())
729 Currency c;
730 if (rAny >>= c)
732 pVariant->vt = VT_CY;
733 pVariant->cyVal.int64 = c.Value;
735 else
737 bIllegal = true;
740 else if(rAny.getValueType() == cppu::UnoType<SCode>::get())
742 SCode s;
743 if (rAny >>= s)
745 pVariant->vt = VT_ERROR;
746 pVariant->scode = s.Value;
748 else
750 bIllegal = true;
753 else
755 createUnoObjectWrapper(rAny, pVariant);
757 break;
759 case TypeClass_SEQUENCE: // sequence ??? SafeArray descriptor
761 SAFEARRAY* pArray = createUnoSequenceWrapper(rAny);
762 if (pArray)
764 V_VT(pVariant) = VT_ARRAY | VT_VARIANT;
765 V_ARRAY(pVariant) = pArray;
767 else
769 bIllegal = true;
771 break;
773 case TypeClass_VOID:
775 HRESULT hr = S_OK;
776 if (FAILED(hr = VariantClear(pVariant)))
778 throw BridgeRuntimeError(
779 "[automation bridge]UnoConversionUtilities<T>::anyToVariant\n"
780 "VariantClear failed with error:" + OUString::number(hr));
782 break;
784 case TypeClass_BOOLEAN:
786 bool value;
787 if (rAny >>= value)
789 pVariant->vt = VT_BOOL;
790 pVariant->boolVal = value ? VARIANT_TRUE: VARIANT_FALSE;
792 else
794 bIllegal = true;
796 break;
798 case TypeClass_CHAR:
800 // Because VT_UI2 does not conform to oleautomation we convert into VT_I2 instead
801 sal_uInt16 value = *o3tl::forceAccess<sal_Unicode>(rAny);
802 pVariant->vt = VT_I2;
803 pVariant->iVal = value;
804 break;
806 case TypeClass_STRING:
808 OUString value;
809 if (rAny >>= value)
811 pVariant->vt = VT_BSTR;
812 pVariant->bstrVal = SysAllocString(o3tl::toW(value.getStr()));
814 else
816 bIllegal = true;
818 break;
820 case TypeClass_FLOAT:
822 float value;
823 if (rAny >>= value)
825 pVariant->vt = VT_R4;
826 pVariant->fltVal = value;
828 else
830 bIllegal = true;
832 break;
834 case TypeClass_DOUBLE:
836 double value;
837 if (rAny >>= value)
839 pVariant->vt = VT_R8;
840 pVariant->dblVal = value;
842 else
844 bIllegal = true;
846 break;
848 case TypeClass_BYTE:
850 // ole automation does not know a signed char but only unsigned char
851 sal_Int8 value;
852 if (rAny >>= value)
854 pVariant->vt = VT_UI1;
855 pVariant->bVal = value;
857 else
859 bIllegal = true;
861 break;
863 case TypeClass_SHORT: // INT16
864 case TypeClass_UNSIGNED_SHORT: // UINT16
866 sal_Int16 value;
867 if (rAny >>= value)
869 pVariant->vt = VT_I2;
870 pVariant->iVal = value;
872 else
874 bIllegal = true;
876 break;
878 case TypeClass_ENUM:
880 sal_Int32 value = *static_cast<sal_Int32 const *>(rAny.getValue());
881 pVariant->vt = VT_I4;
882 pVariant->lVal= value;
883 break;
885 case TypeClass_LONG:
886 case TypeClass_UNSIGNED_LONG:
888 sal_Int32 value;
889 if (rAny >>= value)
891 pVariant->vt = VT_I4;
892 pVariant->lVal= value;
894 else
896 bIllegal = true;
898 break;
900 case TypeClass_HYPER:
903 pVariant->vt = VT_DECIMAL;
904 pVariant->decVal.scale = 0;
905 pVariant->decVal.sign = 0;
906 pVariant->decVal.Hi32 = 0;
908 sal_Int64 value;
909 rAny >>= value;
911 if (value & SAL_CONST_UINT64(0x8000000000000000))
912 pVariant->decVal.sign = DECIMAL_NEG;
914 pVariant->decVal.Lo64 = value;
915 break;
917 case TypeClass_UNSIGNED_HYPER:
919 pVariant->vt = VT_DECIMAL;
920 pVariant->decVal.scale = 0;
921 pVariant->decVal.sign = 0;
922 pVariant->decVal.Hi32 = 0;
924 sal_uInt64 value;
925 rAny >>= value;
926 pVariant->decVal.Lo64 = value;
927 break;
929 case TypeClass_TYPE:
931 Type type;
932 rAny >>= type;
933 CComVariant var;
934 if (!createUnoTypeWrapper(type.getTypeName(), & var))
935 throw BridgeRuntimeError(
936 "[automation bridge] UnoConversionUtilities<T>::anyToVariant \n"
937 "Error during conversion of UNO type to Automation object!");
939 if (FAILED(VariantCopy(pVariant, &var)))
940 throw BridgeRuntimeError(
941 "[automation bridge] UnoConversionUtilities<T>::anyToVariant \n"
942 "Unexpected error!");
943 break;
945 default:
946 //TypeClass_SERVICE:
947 //TypeClass_EXCEPTION:
948 //When an InvocationTargetException is thrown when calling XInvocation::invoke
949 //on a UNO object, then the target exception is directly used to create a
950 //EXEPINFO structure
951 //TypeClass_TYPEDEF
952 //TypeClass_ANY:
953 //TypeClass_UNKNOWN:
954 //TypeClass_MODULE:
955 throw CannotConvertException(
956 "[automation bridge]UnoConversionUtilities<T>::anyToVariant\n"
957 "There is no conversion for this UNO type to an Automation type."
958 "The destination type class is the type class of the UNO "
959 "argument which was to be converted.",
960 Reference<XInterface>(), rAny.getValueTypeClass(),
961 FailReason::TYPE_NOT_SUPPORTED, 0);
963 break;
965 if (bIllegal)
967 throw IllegalArgumentException(
968 "[automation bridge]UnoConversionUtilities<T>::anyToVariant\n"
969 "The provided any of type\" " + rAny.getValueType().getTypeName() +
970 "\" is unappropriate for conversion!", Reference<XInterface>(), -1);
974 catch (const CannotConvertException &)
976 throw;
978 catch (const IllegalArgumentException &)
980 throw;
982 catch(const BridgeRuntimeError&)
984 throw;
986 catch(const Exception & e)
988 throw BridgeRuntimeError(
989 "[automation bridge]UnoConversionUtilities<T>::anyToVariant \n"
990 "Unexpected exception occurred. Message: " + e.Message);
992 catch(...)
994 throw BridgeRuntimeError(
995 "[automation bridge]UnoConversionUtilities<T>::anyToVariant \n"
996 "Unexpected exception occurred. " );
1000 // Creates an SAFEARRAY of the specified element and if necessary
1001 // creates a SAFEARRAY with multiple dimensions.
1002 // Used by sal_Bool anyToVariant(VARIANT* pVariant, const Any& rAny, VARTYPE type);
1003 template<class T>
1004 SAFEARRAY* UnoConversionUtilities<T>::createUnoSequenceWrapper(const Any& rSeq, VARTYPE elemtype)
1006 if (rSeq.getValueTypeClass() != TypeClass_SEQUENCE)
1007 throw IllegalArgumentException(
1008 "[automation bridge]UnoConversionUtilities<T>::createUnoSequenceWrapper \n"
1009 "The any does not contain a sequence!", nullptr, 0);
1010 if (elemtype == VT_NULL || elemtype == VT_EMPTY)
1011 throw IllegalArgumentException(
1012 "[automation bridge]UnoConversionUtilities<T>::createUnoSequenceWrapper \n"
1013 "No element type supplied!",nullptr, -1);
1014 SAFEARRAY* pArray= nullptr;
1015 // Get the dimensions. This is done by examining the type name string
1016 // The count of brackets determines the dimensions.
1017 OUString sTypeName= rSeq.getValueType().getTypeName();
1018 sal_Int32 dims=0;
1019 for(sal_Int32 lastIndex=0;(lastIndex= sTypeName.indexOf( L'[', lastIndex)) != -1; lastIndex++,dims++);
1021 //get the maximum number of elements per dimensions and the typedescription of the elements
1022 Sequence<sal_Int32> seqElementCounts( dims);
1023 TypeDescription elementTypeDesc;
1024 getElementCountAndTypeOfSequence( rSeq, 1, seqElementCounts, elementTypeDesc );
1026 if( elementTypeDesc.is() )
1028 // set up the SAFEARRAY
1029 std::unique_ptr<SAFEARRAYBOUND[]> sarSafeArrayBound(new SAFEARRAYBOUND[dims]);
1030 SAFEARRAYBOUND* prgsabound= sarSafeArrayBound.get();
1031 for( sal_Int32 i=0; i < dims; i++)
1033 //prgsabound[0] is the right most dimension
1034 prgsabound[dims - i - 1].lLbound = 0;
1035 prgsabound[dims - i - 1].cElements = seqElementCounts[i];
1038 typelib_TypeDescription* rawTypeDesc= elementTypeDesc.get();
1039 sal_Int32 elementSize= rawTypeDesc->nSize;
1040 size_t oleElementSize= getOleElementSize( elemtype);
1041 // SafeArrayCreate clears the memory for the data itself.
1042 pArray = SafeArrayCreate(elemtype, dims, prgsabound);
1044 // convert the Sequence's elements and populate the SAFEARRAY
1045 if( pArray)
1047 // Iterate over every Sequence that contains the actual elements
1048 void* pSAData;
1049 if( SUCCEEDED( SafeArrayAccessData( pArray, &pSAData)))
1051 const sal_Int32* parElementCount= seqElementCounts.getConstArray();
1052 uno_Sequence * pMultiSeq= *static_cast<uno_Sequence* const*>(rSeq.getValue());
1053 sal_Int32 dimsSeq= dims - 1;
1055 // arDimSeqIndices contains the current index of a block of data.
1056 // E.g. Sequence<Sequence<sal_Int32>> , the index would refer to Sequence<sal_Int32>
1057 // In this case arDimSeqIndices would have the size 1. That is the elements are not counted
1058 // but the Sequences that contain those elements.
1059 // The indices are 0 based
1060 std::unique_ptr<sal_Int32[]> sarDimsSeqIndices;
1061 sal_Int32* arDimsSeqIndices= nullptr;
1062 if( dimsSeq > 0)
1064 sarDimsSeqIndices.reset(new sal_Int32[dimsSeq]);
1065 arDimsSeqIndices = sarDimsSeqIndices.get();
1066 memset( arDimsSeqIndices, 0, sizeof( sal_Int32 ) * dimsSeq);
1069 char* psaCurrentData= static_cast<char*>(pSAData);
1073 // Get the Sequence at the current index , see arDimsSeqIndices
1074 uno_Sequence * pCurrentSeq= pMultiSeq;
1075 sal_Int32 curDim=1; // 1 based
1076 bool skipSeq= false;
1077 while( curDim <= dimsSeq )
1079 // get the Sequence at the index if valid
1080 if( pCurrentSeq->nElements > arDimsSeqIndices[ curDim - 1] ) // don't point to Nirvana
1082 // size of Sequence is 4
1083 sal_Int32 offset= arDimsSeqIndices[ curDim - 1] * 4;
1084 pCurrentSeq= *reinterpret_cast<uno_Sequence**>(&pCurrentSeq->elements[ offset]);
1085 curDim++;
1087 else
1089 // There is no Sequence at this index, so skip this index
1090 skipSeq= true;
1091 break;
1095 if( skipSeq)
1096 continue;
1098 // Calculate the current position within the datablock of the SAFEARRAY
1099 // for the next Sequence.
1100 sal_Int32 memOffset= 0;
1101 sal_Int32 dimWeight= parElementCount[ dims - 1]; // size of the rightmost dimension
1102 for(sal_Int32 idims=0; idims < dimsSeq; idims++ )
1104 memOffset+= arDimsSeqIndices[dimsSeq - 1 - idims] * dimWeight;
1105 // now determine the weight of the dimension to the left of the current.
1106 if( dims - 2 - idims >=0)
1107 dimWeight*= parElementCount[dims - 2 - idims];
1109 psaCurrentData= static_cast<char*>(pSAData) + memOffset * oleElementSize;
1110 // convert the Sequence and put the elements into the Safearray
1111 for( sal_Int32 i= 0; i < pCurrentSeq->nElements; i++)
1113 Any unoElement( pCurrentSeq->elements + i * elementSize, rawTypeDesc );
1114 // The any is being converted into a VARIANT which value is then copied
1115 // to the SAFEARRAY's data block. When copying one has to follow the rules for
1116 // copying certain types, as are VT_DISPATCH, VT_UNKNOWN, VT_VARIANT, VT_BSTR.
1117 // To increase performance, we just do a memcpy of VARIANT::byref. This is possible
1118 // because anyToVariant has already followed the copying rules. To make this
1119 // work there must not be a VariantClear.
1120 // One Exception is VARIANT because I don't know how VariantCopy works.
1122 VARIANT var;
1123 VariantInit( &var);
1124 anyToVariant( &var, unoElement);
1125 if( elemtype == VT_VARIANT )
1127 VariantCopy( reinterpret_cast<VARIANT*>(psaCurrentData), &var);
1128 VariantClear( &var);
1130 else
1131 memcpy( psaCurrentData, &var.byref, oleElementSize);
1133 psaCurrentData+= oleElementSize;
1136 while( incrementMultidimensionalIndex( dimsSeq, parElementCount, arDimsSeqIndices));
1138 SafeArrayUnaccessData( pArray);
1142 return pArray;
1145 // Increments a multi dimensional index.
1146 // Returns true as long as the index has been successfully incremented, false otherwise.
1147 // False is also returned if an overflow of the most significant dimension occurs. E.g.
1148 // assume an array with the dimensions (2,2), then the lowest index is (0,0) and the highest
1149 // index is (1,1). If the function is being called with the index (1,1) then the overflow would
1150 // occur, with the result (0,0) and a sal_False as return value.
1151 // Param dimensions - number of dimensions
1152 // Param parDimensionsLength - The array contains the size of each dimension, that is the
1153 // size of the array equals the parameter dimensions.
1154 // The rightmost dimensions is the least significant one
1155 // ( parDimensionsLengths[ dimensions -1 ] ).
1156 // Param parMultiDimensionalIndex - The array contains the index. Each dimension index is
1157 // 0 based.
1158 template<class T>
1159 bool UnoConversionUtilities<T>::incrementMultidimensionalIndex(sal_Int32 dimensions,
1160 const sal_Int32 * parDimensionLengths,
1161 sal_Int32 * parMultidimensionalIndex)
1163 if( dimensions < 1)
1164 return false;
1166 bool ret= true;
1167 bool carry= true; // to get into the while loop
1169 sal_Int32 currentDimension= dimensions; //most significant is 1
1170 while( carry)
1172 parMultidimensionalIndex[ currentDimension - 1]++;
1173 // if carryover, set index to 0 and handle carry on a level above
1174 if( parMultidimensionalIndex[ currentDimension - 1] > (parDimensionLengths[ currentDimension - 1] - 1))
1175 parMultidimensionalIndex[ currentDimension - 1]= 0;
1176 else
1177 carry= false;
1179 currentDimension --;
1180 // if dimensions drops below 1 and carry is set than then all indices are 0 again
1181 // this is signalled by returning sal_False
1182 if( currentDimension < 1 && carry)
1184 carry= false;
1185 ret= false;
1188 return ret;
1191 // Determines the size of a certain OLE type. The function takes
1192 // only those types into account which are oleautomation types and
1193 // can have a value ( unless VT_NULL, VT_EMPTY, VT_ARRAY, VT_BYREF).
1194 // Currently used in createUnoSequenceWrapper to calculate addresses
1195 // for data within a SAFEARRAY.
1196 template<class T>
1197 size_t UnoConversionUtilities<T>::getOleElementSize( VARTYPE type)
1199 size_t size;
1200 switch( type)
1202 case VT_BOOL: size= sizeof( VARIANT_BOOL);break;
1203 case VT_UI1: size= sizeof( unsigned char);break;
1204 case VT_R8: size= sizeof( double);break;
1205 case VT_R4: size= sizeof( float);break;
1206 case VT_I2: size= sizeof( short);break;
1207 case VT_I4: size= sizeof( long);break;
1208 case VT_BSTR: size= sizeof( BSTR); break;
1209 case VT_ERROR: size= sizeof( SCODE); break;
1210 case VT_DISPATCH:
1211 case VT_UNKNOWN: size= sizeof( IUnknown*); break;
1212 case VT_VARIANT: size= sizeof( VARIANT);break;
1213 default: size= 0;
1215 return size;
1218 //If a Sequence is being converted into a SAFEARRAY then we possibly have
1219 // to create a SAFEARRAY with multiple dimensions. This is the case when a
1220 // Sequence contains Sequences ( Sequence< Sequence < XXX > > ). The leftmost
1221 // Sequence in the declaration is assumed to represent dimension 1. Because
1222 // all Sequence elements of a Sequence can have different length, we have to
1223 // determine the maximum length which is then the length of the respective
1224 // dimension.
1225 // getElementCountAndTypeOfSequence determines the length of each dimension and calls itself recursively
1226 // in the process.
1227 // param rSeq - an Any that has to contain a Sequence
1228 // param dim - the dimension for which the number of elements is being determined,
1229 // must be one.
1230 // param seqElementCounts - contains the maximum number of elements for each
1231 // dimension. Index 0 contains the number of dimension one.
1232 // After return the Sequence contains the maximum number of
1233 // elements for each dimension.
1234 // The length of the Sequence must equal the number of dimensions.
1235 // param typeClass - TypeClass of the element type that is no Sequence, e.g.
1236 // Sequence< Sequence <Sequence <sal_Int32> > > - type is sal_Int32)
1237 template<class T>
1238 void UnoConversionUtilities<T>::getElementCountAndTypeOfSequence( const Any& rSeq, sal_Int32 dim,
1239 Sequence< sal_Int32 >& seqElementCounts, TypeDescription& typeDesc)
1241 sal_Int32 dimCount= (*static_cast<uno_Sequence* const *>(rSeq.getValue()))->nElements;
1242 if( dimCount > seqElementCounts[ dim-1])
1243 seqElementCounts[ dim-1]= dimCount;
1245 // we need the element type to construct the any that is
1246 // passed into getElementCountAndTypeOfSequence again
1247 typelib_TypeDescription* pSeqDesc= nullptr;
1248 rSeq.getValueTypeDescription( &pSeqDesc);
1249 typelib_TypeDescriptionReference* pElementDescRef= reinterpret_cast<typelib_IndirectTypeDescription*>(pSeqDesc)->pType;
1251 // if the elements are Sequences then do recursion
1252 if( dim < seqElementCounts.getLength() )
1254 uno_Sequence* pSeq = *static_cast<uno_Sequence* const*>(rSeq.getValue());
1255 uno_Sequence** arSequences= reinterpret_cast<uno_Sequence**>(pSeq->elements);
1256 for( sal_Int32 i=0; i < dimCount; i++)
1258 uno_Sequence* arElement= arSequences[ i];
1259 getElementCountAndTypeOfSequence( Any( &arElement, pElementDescRef), dim + 1 , seqElementCounts, typeDesc);
1262 else
1264 // determine the element type ( e.g. Sequence< Sequence <Sequence <sal_Int32> > > - type is sal_Int32)
1265 typeDesc= pElementDescRef;
1267 typelib_typedescription_release( pSeqDesc);
1271 template<class T>
1272 SAFEARRAY* UnoConversionUtilities<T>::createUnoSequenceWrapper(const Any& rSeq)
1274 SAFEARRAY* pArray = nullptr;
1275 sal_uInt32 n = 0;
1277 if( rSeq.getValueTypeClass() != TypeClass_SEQUENCE )
1278 throw IllegalArgumentException(
1279 "[automation bridge]UnoConversionUtilities<T>::createUnoSequenceWrapper\n"
1280 "The UNO argument is not a sequence", nullptr, -1);
1282 uno_Sequence * punoSeq= *static_cast<uno_Sequence* const *>(rSeq.getValue());
1284 typelib_TypeDescriptionReference* pSeqTypeRef= rSeq.getValueTypeRef();
1285 typelib_TypeDescription* pSeqType= nullptr;
1286 TYPELIB_DANGER_GET( &pSeqType, pSeqTypeRef);
1287 typelib_IndirectTypeDescription * pSeqIndDec= reinterpret_cast<typelib_IndirectTypeDescription*>(pSeqType);
1290 typelib_TypeDescriptionReference * pSeqElementTypeRef= pSeqIndDec->pType;
1291 TYPELIB_DANGER_RELEASE( pSeqType);
1293 typelib_TypeDescription* pSeqElementDesc= nullptr;
1294 TYPELIB_DANGER_GET( &pSeqElementDesc, pSeqElementTypeRef);
1295 sal_Int32 nElementSize= pSeqElementDesc->nSize;
1296 n= punoSeq->nElements;
1298 SAFEARRAYBOUND rgsabound[1];
1299 rgsabound[0].lLbound = 0;
1300 rgsabound[0].cElements = n;
1301 VARIANT oleElement;
1302 long safeI[1];
1304 pArray = SafeArrayCreate(VT_VARIANT, 1, rgsabound);
1306 Any unoElement;
1307 char * pSeqData= punoSeq->elements;
1309 for (sal_uInt32 i = 0; i < n; i++)
1311 unoElement.setValue( pSeqData + i * nElementSize, pSeqElementDesc);
1312 VariantInit(&oleElement);
1314 anyToVariant(&oleElement, unoElement);
1316 safeI[0] = i;
1317 SafeArrayPutElement(pArray, safeI, &oleElement);
1319 VariantClear(&oleElement);
1321 TYPELIB_DANGER_RELEASE( pSeqElementDesc);
1323 return pArray;
1326 /* The argument rObj can contain
1327 - UNO struct
1328 - UNO interface
1329 - UNO interface created by this bridge (adapter factory)
1330 - UNO interface created by this bridge ( COM Wrapper)
1332 pVar must be initialized.
1334 template<class T>
1335 void UnoConversionUtilities<T>::createUnoObjectWrapper(const Any & rObj, VARIANT * pVar)
1337 MutexGuard guard(getBridgeMutex());
1339 Reference<XInterface> xInt;
1341 TypeClass tc = rObj.getValueTypeClass();
1342 if (tc != TypeClass_INTERFACE && tc != TypeClass_STRUCT)
1343 throw IllegalArgumentException(
1344 "[automation bridge]UnoConversionUtilities<T>::createUnoObjectWrapper \n"
1345 "Cannot create an Automation interface for a UNO type which is not "
1346 "a struct or interface!", nullptr, -1);
1348 if (rObj.getValueTypeClass() == TypeClass_INTERFACE)
1350 if (! (rObj >>= xInt))
1351 throw IllegalArgumentException(
1352 "[automation bridge] UnoConversionUtilities<T>::createUnoObjectWrapper\n "
1353 "Could not create wrapper object for UNO object!", nullptr, -1);
1354 //If XInterface is NULL, which is a valid value, then simply return NULL.
1355 if ( ! xInt.is())
1357 pVar->vt = VT_UNKNOWN;
1358 pVar->punkVal = nullptr;
1359 return;
1361 //make sure we have the main XInterface which is used with a map
1362 xInt.set(xInt, UNO_QUERY);
1363 //If there is already a wrapper for the UNO object then use it
1365 Reference<XInterface> xIntWrapper;
1366 // Does a UNO wrapper exist already ?
1367 auto it_uno = UnoObjToWrapperMap.find( reinterpret_cast<sal_uIntPtr>(xInt.get()));
1368 if(it_uno != UnoObjToWrapperMap.end())
1370 xIntWrapper = it_uno->second;
1371 if (xIntWrapper.is())
1373 convertSelfToCom(xIntWrapper, pVar);
1374 return;
1377 // Is the object a COM wrapper ( either XInvocation, or Adapter object)
1378 // or does it supply an IDispatch by its own ?
1379 else
1381 Reference<XInterface> xIntComWrapper = xInt;
1383 // Adapter? then get the COM wrapper to which the adapter delegates its calls
1384 auto it = AdapterToWrapperMap.find( reinterpret_cast<sal_uIntPtr>(xInt.get()));
1385 if( it != AdapterToWrapperMap.end() )
1386 xIntComWrapper= reinterpret_cast<XInterface*>(it->second);
1388 if (convertSelfToCom(xIntComWrapper, pVar))
1389 return;
1392 // If we have no UNO wrapper nor the IDispatch yet then we have to create
1393 // a wrapper. For that we need an XInvocation.
1395 // create an XInvocation using the invocation service
1396 Reference<XInvocation> xInv;
1397 Reference<XSingleServiceFactory> xInvFactory= getInvocationFactory(rObj);
1398 if (xInvFactory.is())
1400 Sequence<Any> params(2);
1401 params.getArray()[0] = rObj;
1402 params.getArray()[1] <<= OUString("FromOLE");
1403 Reference<XInterface> xInt2 = xInvFactory->createInstanceWithArguments(params);
1404 xInv.set(xInt2, UNO_QUERY);
1407 if (xInv.is())
1409 Reference<XInterface> xNewWrapper = createUnoWrapperInstance();
1410 Reference<XInitialization> xInitWrapper(xNewWrapper, UNO_QUERY);
1411 if (xInitWrapper.is())
1413 VARTYPE vartype= getVarType( rObj);
1415 if (xInt.is())
1417 Any params[3];
1418 params[0] <<= xInv;
1419 params[1] <<= xInt;
1420 params[2] <<= vartype;
1421 xInitWrapper->initialize( Sequence<Any>(params, 3));
1423 else
1425 Any params[2];
1426 params[0] <<= xInv;
1427 params[1] <<= vartype;
1428 xInitWrapper->initialize( Sequence<Any>(params, 2));
1431 // put the newly created object into a map. If the same object will
1432 // be mapped again and there is already a wrapper then the old wrapper
1433 // will be used.
1434 if(xInt.is()) // only interfaces
1435 UnoObjToWrapperMap[reinterpret_cast<sal_uIntPtr>(xInt.get())]= xNewWrapper;
1436 convertSelfToCom(xNewWrapper, pVar);
1437 return;
1442 template<class T>
1443 void UnoConversionUtilities<T>::variantToAny( const VARIANT* pVariant, Any& rAny,
1444 bool bReduceValueRange /* = sal_True */)
1446 HRESULT hr = S_OK;
1449 CComVariant var;
1451 // There is no need to support indirect values, since they're not supported by UNO
1452 if( FAILED(hr= VariantCopyInd( &var, pVariant))) // remove VT_BYREF
1453 throw BridgeRuntimeError(
1454 "[automation bridge] UnoConversionUtilities<T>::variantToAny \n"
1455 "VariantCopyInd failed for reason : " + OUString::number(hr));
1457 if ( ! convertValueObject( & var, rAny))
1459 if ((var.vt & VT_ARRAY) > 0)
1461 VARTYPE oleTypeFlags = ::sal::static_int_cast< VARTYPE, int >( var.vt ^ VT_ARRAY );
1463 Sequence<Any> unoSeq = createOleArrayWrapper(var.parray, oleTypeFlags);
1464 rAny.setValue( &unoSeq, cppu::UnoType<decltype(unoSeq)>::get());
1466 else
1468 switch (var.vt)
1470 case VT_EMPTY:
1471 rAny.setValue(nullptr, Type());
1472 break;
1473 case VT_NULL:
1474 rAny.setValue(nullptr, Type());
1475 break;
1476 case VT_I2:
1477 rAny.setValue( & var.iVal, cppu::UnoType<sal_Int16>::get());
1478 break;
1479 case VT_I4:
1480 rAny.setValue( & var.lVal, cppu::UnoType<sal_Int32>::get());
1481 // necessary for use in JavaScript ( see "reduceRange")
1482 if( bReduceValueRange)
1483 reduceRange(rAny);
1484 break;
1485 case VT_R4:
1486 rAny.setValue( & var.fltVal, cppu::UnoType<float>::get());
1487 break;
1488 case VT_R8:
1489 rAny.setValue(& var.dblVal, cppu::UnoType<double>::get());
1490 break;
1491 case VT_CY:
1493 Currency cy(var.cyVal.int64);
1494 rAny <<= cy;
1495 break;
1497 case VT_DATE:
1499 Date d(var.date);
1500 rAny <<= d;
1501 break;
1503 case VT_BSTR:
1505 OUString b(o3tl::toU(var.bstrVal));
1506 rAny.setValue( &b, cppu::UnoType<decltype(b)>::get());
1507 break;
1509 case VT_UNKNOWN:
1510 case VT_DISPATCH:
1512 //check if it is a UNO type
1513 CComQIPtr<IUnoTypeWrapper> spType(static_cast<IUnknown*>(var.byref));
1514 if (spType)
1516 CComBSTR sName;
1517 if (FAILED(spType->get_Name(&sName)))
1518 throw BridgeRuntimeError(
1519 "[automation bridge]UnoConversionUtilities<T>::variantToAny \n"
1520 "Failed to get the type name from a UnoTypeWrapper!");
1521 Type type;
1522 if (!getType(sName, type))
1524 throw CannotConvertException(
1525 OUStringLiteral("[automation bridge]UnoConversionUtilities<T>::variantToAny \n"
1526 "A UNO type with the name: ") + o3tl::toU(LPCOLESTR(sName)) +
1527 "does not exist!",
1528 nullptr, TypeClass_UNKNOWN, FailReason::TYPE_NOT_SUPPORTED,0);
1530 rAny <<= type;
1532 else
1534 rAny = createOleObjectWrapper( & var);
1536 break;
1538 case VT_ERROR:
1540 SCode scode(var.scode);
1541 rAny <<= scode;
1542 break;
1544 case VT_BOOL:
1546 rAny <<= (var.boolVal == VARIANT_TRUE);
1547 break;
1549 case VT_I1:
1550 rAny.setValue( & var.cVal, cppu::UnoType<sal_Int8>::get());
1551 break;
1552 case VT_UI1: // there is no unsigned char in UNO
1553 rAny <<= sal_Int8(var.bVal);
1554 break;
1555 case VT_UI2:
1556 rAny.setValue( & var.uiVal, cppu::UnoType<cppu::UnoUnsignedShortType>::get() );
1557 break;
1558 case VT_UI4:
1559 rAny.setValue( & var.ulVal, cppu::UnoType<sal_uInt32>::get());
1560 break;
1561 case VT_INT:
1562 rAny.setValue( & var.intVal, cppu::UnoType<sal_Int32>::get());
1563 break;
1564 case VT_UINT:
1565 rAny.setValue( & var.uintVal, cppu::UnoType<sal_uInt32>::get());
1566 break;
1567 case VT_VOID:
1568 rAny.setValue( nullptr, Type());
1569 break;
1570 case VT_DECIMAL:
1572 Decimal dec;
1573 dec.Scale = var.decVal.scale;
1574 dec.Sign = var.decVal.sign;
1575 dec.LowValue = var.decVal.Lo32;
1576 dec.MiddleValue = var.decVal.Mid32;
1577 dec.HighValue = var.decVal.Hi32;
1578 rAny <<= dec;
1579 break;
1582 default:
1583 break;
1588 catch (const IllegalArgumentException &)
1590 throw;
1592 catch (const CannotConvertException &)
1594 throw;
1596 catch (const BridgeRuntimeError &)
1598 throw;
1600 catch (const Exception & e)
1602 throw BridgeRuntimeError("[automation bridge] unexpected exception in "
1603 "UnoConversionUtilities<T>::variantToAny ! Message : \n" +
1604 e.Message);
1606 catch(...)
1608 throw BridgeRuntimeError(
1609 "[automation bridge] unexpected exception in "
1610 "UnoConversionUtilities<T>::variantToAny !");
1614 // The function converts an IUnknown* into a UNO interface or struct. The
1615 // IUnknown pointer can constitute different kind of objects:
1616 // 1. a wrapper of a UNO struct (the wrapper was created by this bridge)
1617 // 2. a wrapper of a UNO interface (created by this bridge)
1618 // 3. a dispatch object that implements UNO interfaces
1619 // 4. a dispatch object.
1621 // If the parameter "aType" has a value then the COM object ( pUnknown) is supposed to
1622 // implement the interface described by "aType". Moreover it ( pUnknown) can implement
1623 // several other
1624 // UNO interfaces in which case it has to support the SUPPORTED_INTERFACES_PROP (see
1625 // #define) property. That property contains all names of interfaces.
1626 // "pUnknown" is wrapped by a COM wrapper object that implements XInvocation, e.g.
1627 // IUnknownWrapper. Additionally an object of type "aType" is created by help
1628 // of the INTERFACE_ADAPTER_FACTORY (see #define) service. The implementation of
1629 // "aType" calls on the COM wrapper's XInvocation::invoke. If the COM object supports
1630 // more than one UNO interfaces, as can be determined by the property
1631 // SUPPORTED_INTERFACES_PROP, then the INTERFACE_ADAPTER_FACTORY creates an object that
1632 // implements all these interfaces.
1633 // This is only done if "pUnknown" is not already a UNO wrapper,
1634 // that is it is actually NOT a UNO object that was converted to a COM object. If it is an
1635 // UNO wrapper than the original UNO object is being extracted, queried for "aType" (if
1636 // it is no struct) and returned.
1637 template<class T>
1638 Any UnoConversionUtilities<T>::createOleObjectWrapper(VARIANT* pVar, const Type& aType)
1640 //To allow passing "Nothing" in VS 2008 we need to accept VT_EMPTY
1641 if (pVar->vt != VT_UNKNOWN && pVar->vt != VT_DISPATCH && pVar->vt != VT_EMPTY)
1642 throw IllegalArgumentException(
1643 "[automation bridge]UnoConversionUtilities<T>::createOleObjectWrapper \n"
1644 "The VARIANT does not contain an object type! ", nullptr, -1);
1646 MutexGuard guard( getBridgeMutex());
1648 CComPtr<IUnknown> spUnknown;
1649 CComPtr<IDispatch> spDispatch;
1651 if (pVar->vt == VT_UNKNOWN)
1653 spUnknown = pVar->punkVal;
1654 if (spUnknown)
1655 spUnknown.QueryInterface( & spDispatch.p);
1657 else if (pVar->vt == VT_DISPATCH && pVar->pdispVal != nullptr)
1659 CComPtr<IDispatch> spDispatch2(pVar->pdispVal);
1660 if (spDispatch2)
1661 spDispatch2.QueryInterface( & spUnknown.p);
1664 static Type VOID_TYPE;
1665 Any ret;
1666 //If no Type is provided and pVar contains IUnknown then we return a XInterface.
1667 //If pVar contains an IDispatch then we return a XInvocation.
1668 Type desiredType = aType;
1670 if (aType == VOID_TYPE)
1672 switch (pVar->vt)
1674 case VT_EMPTY:
1675 case VT_UNKNOWN:
1676 desiredType = cppu::UnoType<XInterface>::get();
1677 break;
1678 case VT_DISPATCH:
1679 desiredType = cppu::UnoType<XInvocation>::get();
1680 break;
1681 default:
1682 desiredType = aType;
1686 // COM pointer are NULL, no wrapper required
1687 if (spUnknown == nullptr)
1689 Reference<XInterface> xInt;
1690 if( aType.getTypeClass() == TypeClass_INTERFACE)
1691 ret.setValue( &xInt, aType);
1692 else if( aType.getTypeClass() == TypeClass_STRUCT)
1693 ret.setValue( nullptr, aType);
1694 else
1695 ret <<= xInt;
1696 return ret;
1700 // Check if "spUnknown" is a UNO wrapper, that is a UNO object that has been
1701 // passed to COM. Then it supports IUnoObjectWrapper
1702 // and we extract the original UNO object.
1703 CComQIPtr<IUnoObjectWrapper> spUno( spUnknown);
1704 if( spUno)
1705 { // it is a wrapper
1706 Reference<XInterface> xInt;
1707 if( SUCCEEDED( spUno->getOriginalUnoObject( &xInt)))
1709 ret <<= xInt;
1711 else
1713 Any any;
1714 if( SUCCEEDED( spUno->getOriginalUnoStruct(&any)))
1715 ret= any;
1717 return ret;
1720 // "spUnknown" is a real COM object.
1721 // Before we create a new wrapper object we check if there is an existing wrapper
1722 // There can be two kinds of wrappers, those who wrap dispatch - UNO objects, and those who
1723 // wrap ordinary dispatch objects. The dispatch-UNO objects usually are adapted to represent
1724 // particular UNO interfaces.
1725 Reference<XInterface> xIntWrapper;
1726 auto cit_currWrapper= ComPtrToWrapperMap.find( reinterpret_cast<sal_uIntPtr>(spUnknown.p));
1727 if(cit_currWrapper != ComPtrToWrapperMap.end())
1728 xIntWrapper = cit_currWrapper->second;
1729 if (xIntWrapper.is())
1731 //Try to find an adapter for the wrapper
1732 //find the proper Adapter. The pointer in the WrapperToAdapterMap are valid as long as
1733 //we get a pointer to the wrapper from ComPtrToWrapperMap, because the Adapter hold references
1734 //to the wrapper.
1735 auto it = WrapperToAdapterMap.find(reinterpret_cast<sal_uIntPtr>(xIntWrapper.get()));
1736 if (it == WrapperToAdapterMap.end())
1738 // No adapter available.
1739 //The COM component could be a UNO object. Then we need to provide
1740 // a proxy that implements all interfaces
1741 Sequence<Type> seqTypes= getImplementedInterfaces(spUnknown);
1742 Reference<XInterface> xIntAdapter;
1743 if (seqTypes.getLength() > 0)
1745 //It is a COM UNO object
1746 xIntAdapter = createAdapter(seqTypes, xIntWrapper);
1748 else
1750 // Some ordinary COM object
1751 xIntAdapter = xIntWrapper;
1753 // return the wrapper directly, return XInterface or XInvocation
1754 ret = xIntWrapper->queryInterface(desiredType);
1755 if ( ! ret.hasValue())
1756 throw IllegalArgumentException(
1757 "[automation bridge]UnoConversionUtilities<T>::createOleObjectWrapper \n"
1758 "The COM object is not suitable for the UNO type: " +
1759 desiredType.getTypeName(), nullptr, -1);
1761 else
1763 //There is an adapter available
1764 Reference<XInterface> xIntAdapter(reinterpret_cast<XInterface*>(it->second));
1765 ret = xIntAdapter->queryInterface( desiredType);
1766 if ( ! ret.hasValue())
1767 throw IllegalArgumentException(
1768 "[automation bridge]UnoConversionUtilities<T>::createOleObjectWrapper \n"
1769 "The COM object is not suitable for the UNO type: " +
1770 desiredType.getTypeName(), nullptr, -1);
1773 return ret;
1775 // No existing wrapper. Therefore create a new proxy.
1776 // If the object implements UNO interfaces then get the types.
1777 Sequence<Type> seqTypes = getImplementedInterfaces(spUnknown);
1778 if (seqTypes.getLength() == 0 &&
1779 aType != VOID_TYPE && aType != cppu::UnoType<XInvocation>::get())
1781 seqTypes = Sequence<Type>( & aType, 1);
1784 //There is no existing wrapper, therefore we create one for the real COM object
1785 Reference<XInterface> xIntNewProxy= createComWrapperInstance();
1786 if ( ! xIntNewProxy.is())
1787 throw BridgeRuntimeError(
1788 "[automation bridge]UnoConversionUtilities<T>::createOleObjectWrapper \n"
1789 "Could not create proxy object for COM object!");
1791 // initialize the COM wrapper
1792 Reference<XInitialization> xInit( xIntNewProxy, UNO_QUERY);
1793 OSL_ASSERT( xInit.is());
1795 Any params[3];
1796 params[0] <<= reinterpret_cast<sal_uIntPtr>(spUnknown.p);
1797 params[1] <<= (pVar->vt == VT_DISPATCH);
1798 params[2] <<= seqTypes;
1800 xInit->initialize( Sequence<Any>( params, 3));
1801 ComPtrToWrapperMap[reinterpret_cast<sal_uInt64>(spUnknown.p)] = xIntNewProxy;
1803 // we have a wrapper object
1804 //The wrapper implements already XInvocation and XInterface. If
1805 //param aType is void then the object is supposed to have XInvocation.
1806 if (aType == cppu::UnoType<XInvocation>::get()||
1807 (aType == VOID_TYPE && seqTypes.getLength() == 0 ))
1809 ret = xIntNewProxy->queryInterface(desiredType);
1811 else
1813 Reference<XInterface> xIntAdapter =
1814 createAdapter(seqTypes, xIntNewProxy);
1815 ret = xIntAdapter->queryInterface(desiredType);
1817 return ret;
1819 template<class T>
1820 Reference<XInterface> UnoConversionUtilities<T>::createAdapter(const Sequence<Type>& seqTypes,
1821 const Reference<XInterface>& receiver)
1823 Reference< XInterface> xIntAdapterFac;
1824 xIntAdapterFac= m_smgr->createInstance(INTERFACE_ADAPTER_FACTORY);
1825 // We create an adapter object that does not only implement the required type but also
1826 // all types that the COM object pretends to implement. A COM object must therefore
1827 // support the property "_implementedInterfaces".
1828 Reference<XInterface> xIntAdapted;
1829 Reference<XInvocation> xInv(receiver, UNO_QUERY);
1830 Reference<XInvocationAdapterFactory2> xAdapterFac( xIntAdapterFac, UNO_QUERY);
1831 if( xAdapterFac.is())
1832 xIntAdapted= xAdapterFac->createAdapter( xInv, seqTypes);
1834 if( !xIntAdapted.is())
1836 throw BridgeRuntimeError(
1837 "[automation bridge]UnoConversionUtilities<T>::createOleObjectWrapper \n"
1838 "Could not create a proxy for COM object! Creation of adapter failed.");
1841 // Put the pointer to the wrapper object and the interface pointer of the adapted interface
1842 // in a global map. Thus we can determine in a call to createUnoObjectWrapper whether the UNO
1843 // object is a wrapped COM object. In that case we extract the original COM object rather than
1844 // creating a wrapper around the UNO object.
1845 typedef std::unordered_map<sal_uInt64,sal_uInt64>::value_type VALUE;
1846 AdapterToWrapperMap.insert( VALUE( reinterpret_cast<sal_uInt64>(xIntAdapted.get()), reinterpret_cast<sal_uInt64>(receiver.get())));
1847 WrapperToAdapterMap.insert( VALUE( reinterpret_cast<sal_uInt64>(receiver.get()), reinterpret_cast<sal_uInt64>(xIntAdapted.get())));
1849 return xIntAdapted;
1851 // "convertValueObject" converts a JScriptValue object contained in "var" into
1852 // an any. The type contained in the any is stipulated by a "type value" thas
1853 // was set within the JScript script on the value object ( see JScriptValue).
1854 template<class T>
1855 bool UnoConversionUtilities<T>::convertValueObject( const VARIANTARG *var, Any& any)
1857 bool ret = false;
1860 bool bFail = false;
1861 HRESULT hr= S_OK;
1862 CComVariant varDisp;
1864 if(SUCCEEDED(hr = varDisp.ChangeType( VT_DISPATCH, var)))
1866 CComPtr <IJScriptValueObject> spValue;
1867 VARIANT_BOOL varBool;
1868 CComBSTR bstrType;
1869 CComVariant varValue;
1870 CComPtr<IDispatch> spDisp( varDisp.pdispVal);
1871 if(spDisp)
1873 if(SUCCEEDED( spDisp->QueryInterface( __uuidof( IJScriptValueObject),
1874 reinterpret_cast<void**> (&spValue))))
1876 ret = true; // is a ValueObject
1877 //If it is an out - param then it does not need to be converted. In/out and
1878 // in params does so.
1879 if (SUCCEEDED(hr= spValue->IsOutParam( &varBool)))
1881 // if varBool == true then no conversion needed because out param
1882 if (varBool == VARIANT_FALSE)
1884 if(SUCCEEDED(hr = spValue->GetValue( & bstrType, & varValue)))
1886 Type type;
1887 if (getType(bstrType, type))
1888 variantToAny( & varValue, any, type);
1889 else
1890 bFail = true;
1892 else
1893 bFail = true;
1896 else
1897 bFail = true;
1901 else if( hr != DISP_E_TYPEMISMATCH && hr != E_NOINTERFACE)
1902 bFail = true;
1904 if (bFail)
1905 throw BridgeRuntimeError(
1906 "[automation bridge] Conversion of ValueObject failed ");
1908 catch (const BridgeRuntimeError &)
1910 throw;
1912 catch (const Exception & e)
1914 throw BridgeRuntimeError("[automation bridge] unexpected exception in "
1915 "UnoConversionUtilities<T>::convertValueObject ! Message : \n" +
1916 e.Message);
1918 catch(...)
1920 throw BridgeRuntimeError(
1921 "[automation bridge] unexpected exception in "
1922 "UnoConversionUtilities<T>::convertValueObject !");
1924 return ret;
1927 template<class T>
1928 void UnoConversionUtilities<T>::dispatchExObject2Sequence( const VARIANTARG* pvar, Any& anySeq, const Type& type)
1932 if( pvar->vt != VT_DISPATCH)
1933 throw BridgeRuntimeError("[automation bridge] UnoConversionUtilities<T>::dispatchExObject2Sequence \n"
1934 "Conversion of dispatch object to Sequence failed!");
1935 IDispatchEx* pdispEx;
1936 HRESULT hr;
1937 if( FAILED( hr= pvar->pdispVal->QueryInterface( IID_IDispatchEx,
1938 reinterpret_cast<void**>( &pdispEx))))
1939 throw BridgeRuntimeError("[automation bridge] UnoConversionUtilities<T>::dispatchExObject2Sequence \n"
1940 "Conversion of dispatch object to Sequence failed!");
1942 DISPID dispid;
1943 DISPPARAMS param= {nullptr,nullptr,0,0};
1944 CComVariant result;
1946 OLECHAR const * sLength= L"length";
1948 // Get the length of the array. Can also be obtained through GetNextDispID. The
1949 // method only returns DISPIDs of the array data. Their names are like "0", "1" etc.
1950 if( FAILED( hr= pdispEx->GetIDsOfNames(IID_NULL, const_cast<OLECHAR **>(&sLength), 1, LOCALE_USER_DEFAULT, &dispid)))
1951 throw BridgeRuntimeError("[automation bridge] UnoConversionUtilities<T>::dispatchExObject2Sequence \n"
1952 "Conversion of dispatch object to Sequence failed!");
1953 if( FAILED( hr= pdispEx->InvokeEx(dispid, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET,
1954 &param, &result, nullptr, nullptr)))
1955 throw BridgeRuntimeError("[automation bridge] UnoConversionUtilities<T>::dispatchExObject2Sequence \n"
1956 "Conversion of dispatch object to Sequence failed!");
1957 if( FAILED( VariantChangeType( &result, &result, 0, VT_I4)))
1958 throw BridgeRuntimeError("[automation bridge] UnoConversionUtilities<T>::dispatchExObject2Sequence \n"
1959 "Conversion of dispatch object to Sequence failed!");
1960 long length= result.lVal;
1962 result.Clear();
1964 // get a few basic facts about the sequence, and reallocate:
1965 // create the Sequences
1966 // get the size of the elements
1967 typelib_TypeDescription *pDesc= nullptr;
1968 type.getDescription( &pDesc);
1970 typelib_IndirectTypeDescription *pSeqDesc= reinterpret_cast<typelib_IndirectTypeDescription*>(pDesc);
1971 typelib_TypeDescriptionReference *pSeqElemDescRef= pSeqDesc->pType; // type of the Sequence' elements
1972 Type elemType( pSeqElemDescRef);
1973 _typelib_TypeDescription* pSeqElemDesc=nullptr;
1974 TYPELIB_DANGER_GET( &pSeqElemDesc, pSeqElemDescRef);
1975 sal_uInt32 nelementSize= pSeqElemDesc->nSize;
1976 TYPELIB_DANGER_RELEASE( pSeqElemDesc);
1978 uno_Sequence *p_uno_Seq;
1979 uno_sequence_construct( &p_uno_Seq, pDesc, nullptr, length, cpp_acquire);
1981 typelib_TypeClass typeElement= pSeqDesc->pType->eTypeClass;
1982 char *pArray= p_uno_Seq->elements;
1984 // Get All properties in the object, convert their values to the expected type and
1985 // put them into the passed in sequence
1986 for( sal_Int32 i= 0; i< length; i++)
1988 OUString ousIndex=OUString::number( i);
1989 OLECHAR* sindex = const_cast<OLECHAR *>(o3tl::toW(ousIndex.getStr()));
1991 if( FAILED( hr= pdispEx->GetIDsOfNames(IID_NULL, &sindex , 1, LOCALE_USER_DEFAULT, &dispid)))
1993 throw BridgeRuntimeError("[automation bridge] UnoConversionUtilities<T>::dispatchExObject2Sequence \n"
1994 "Conversion of dispatch object to Sequence failed!");
1996 if( FAILED( hr= pdispEx->InvokeEx(dispid, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET,
1997 &param, &result, nullptr, nullptr)))
1999 throw BridgeRuntimeError("[automation bridge] UnoConversionUtilities<T>::dispatchExObject2Sequence \n"
2000 "Conversion of dispatch object to Sequence failed!");
2003 // If the result is VT_DISPATCH than the Sequence's element type could be Sequence
2004 // Look that up in the CoreReflection to make clear.
2005 // That requires a recursiv conversion
2006 Any any;
2007 // Destination address within the out-Sequence "anySeq" where to copy the next converted element
2008 void* pDest= pArray + (i * nelementSize);
2010 if( result.vt & VT_DISPATCH && typeElement == typelib_TypeClass_SEQUENCE)
2012 variantToAny( &result, any, elemType, false);
2013 // copy the converted VARIANT, that is a Sequence to the Sequence
2014 uno_Sequence * p_unoSeq= *static_cast<uno_Sequence* const *>(any.getValue());
2015 // just copy the pointer of the uno_Sequence
2016 // nelementSize should be 4 !!!!
2017 memcpy( pDest, &p_unoSeq, nelementSize);
2018 osl_atomic_increment( &p_unoSeq->nRefCount);
2020 else // Element type is no Sequence -> do one conversion
2022 variantToAny( &result, any, elemType, false);
2023 if( typeElement == typelib_TypeClass_ANY)
2025 // copy the converted VARIANT to the Sequence
2026 uno_type_assignData( pDest, pSeqElemDescRef , &any, pSeqElemDescRef,cpp_queryInterface,
2027 cpp_acquire, cpp_release);
2029 else
2031 // type after conversion must be the element type of the sequence
2032 OSL_ENSURE(any.getValueTypeClass() == css::uno::TypeClass(typeElement), "wrong conversion");
2033 uno_type_assignData( pDest, pSeqElemDescRef,const_cast<void*>( any.getValue()), any.getValueTypeRef(),
2034 cpp_queryInterface, cpp_acquire, cpp_release);
2037 } // else
2038 result.Clear();
2039 anySeq.setValue( &p_uno_Seq, pDesc);
2040 uno_destructData( &p_uno_Seq, pDesc, cpp_release);
2041 typelib_typedescription_release( pDesc);
2043 catch (const BridgeRuntimeError &)
2045 throw;
2047 catch (const Exception & e)
2049 throw BridgeRuntimeError("[automation bridge] unexpected exception in "
2050 "UnoConversionUtilities<T>::convertValueObject ! Message : \n" +
2051 e.Message);
2053 catch(...)
2055 throw BridgeRuntimeError(
2056 "[automation bridge] unexpected exception in "
2057 "UnoConversionUtilities<T>::convertValueObject !");
2061 /* The argument unotype is the type that is expected by the currently called UNO function.
2062 For example: []long, [][]long. If the function calls itself recursively then the element type
2063 is passed on. For example a two dimensional SAFEARRAY of type VT_I4 is to be converted. Then
2064 unotype has to be either void or [][]long. When the function calls itself recursively then
2065 it passes the element type which is []long.
2067 template<class T>
2068 Sequence<Any> UnoConversionUtilities<T>::createOleArrayWrapperOfDim(SAFEARRAY* pArray,
2069 unsigned int dimCount, unsigned int actDim, long* index, VARTYPE type, const Type& unotype)
2071 HRESULT hr= S_OK;
2072 long lBound;
2073 long uBound;
2074 long nCountElements;
2076 SafeArrayGetLBound(pArray, actDim, &lBound);
2077 SafeArrayGetUBound(pArray, actDim, &uBound);
2078 nCountElements= uBound - lBound +1;
2080 Sequence<Any> anySeq(nCountElements);
2081 Any* pUnoArray = anySeq.getArray();
2083 for (index[actDim - 1] = lBound; index[actDim - 1] <= uBound; index[actDim - 1]++)
2085 if (actDim > 1 )
2087 Sequence<Any> element = createOleArrayWrapperOfDim(pArray, dimCount,
2088 actDim - 1, index, type, getElementTypeOfSequence(unotype));
2090 pUnoArray[index[actDim - 1] - lBound].setValue(&element, cppu::UnoType<decltype(element)>::get());
2092 else
2094 VARIANT variant;
2096 VariantInit(&variant);
2098 V_VT(&variant) = type;
2100 switch (type)
2102 case VT_I2:
2103 SafeArrayGetElement(pArray, index, &V_I2(&variant));
2104 break;
2105 case VT_I4:
2106 SafeArrayGetElement(pArray, index, &V_I4(&variant));
2107 break;
2108 case VT_R4:
2109 SafeArrayGetElement(pArray, index, &V_R4(&variant));
2110 break;
2111 case VT_R8:
2112 SafeArrayGetElement(pArray, index, &V_R8(&variant));
2113 break;
2114 case VT_CY:
2115 SafeArrayGetElement(pArray, index, &V_CY(&variant));
2116 break;
2117 case VT_DATE:
2118 SafeArrayGetElement(pArray, index, &V_DATE(&variant));
2119 break;
2120 case VT_BSTR:
2121 hr= SafeArrayGetElement(pArray, index, &V_BSTR(&variant));
2122 break;
2123 case VT_DISPATCH:
2124 SafeArrayGetElement(pArray, index, &V_DISPATCH(&variant));
2125 break;
2126 case VT_ERROR:
2127 SafeArrayGetElement(pArray, index, &V_ERROR(&variant));
2128 break;
2129 case VT_BOOL:
2130 SafeArrayGetElement(pArray, index, &V_BOOL(&variant));
2131 break;
2132 case VT_VARIANT:
2133 SafeArrayGetElement(pArray, index, &variant);
2134 break;
2135 case VT_UNKNOWN:
2136 SafeArrayGetElement(pArray, index, &V_UNKNOWN(&variant));
2137 break;
2138 case VT_I1:
2139 SafeArrayGetElement(pArray, index, &V_I1(&variant));
2140 break;
2141 case VT_UI1:
2142 SafeArrayGetElement(pArray, index, &V_UI1(&variant));
2143 break;
2144 case VT_UI2:
2145 SafeArrayGetElement(pArray, index, &V_UI2(&variant));
2146 break;
2147 case VT_UI4:
2148 SafeArrayGetElement(pArray, index, &V_UI4(&variant));
2149 break;
2150 default:
2151 break;
2154 if( unotype.getTypeClass() == TypeClass_VOID)
2155 // the function was called without specifying the destination type
2156 variantToAny(&variant, pUnoArray[index[actDim - 1] - lBound], false);
2157 else
2158 variantToAny(&variant, pUnoArray[index[actDim - 1] - lBound],
2159 getElementTypeOfSequence(unotype), false);
2161 VariantClear(&variant);
2164 return anySeq;
2167 template<class T>
2168 Type UnoConversionUtilities<T>::getElementTypeOfSequence( const Type& seqType)
2170 Type retValue;
2171 if( seqType.getTypeClass() != TypeClass_VOID)
2173 OSL_ASSERT( seqType.getTypeClass() == TypeClass_SEQUENCE);
2174 typelib_TypeDescription* pDescSeq= nullptr;
2175 seqType.getDescription(& pDescSeq);
2176 retValue = Type(reinterpret_cast<typelib_IndirectTypeDescription *>(pDescSeq)->pType);
2177 typelib_typedescription_release(pDescSeq);
2179 return retValue;
2181 template<class T>
2182 Sequence<Any> UnoConversionUtilities<T>::createOleArrayWrapper(SAFEARRAY* pArray, VARTYPE type, const Type& unoType)
2184 sal_uInt32 dim = SafeArrayGetDim(pArray);
2186 Sequence<Any> ret;
2188 if (dim > 0)
2190 std::unique_ptr<long[]> sarIndex(new long[dim]);
2191 long * index = sarIndex.get();
2193 for (unsigned int i = 0; i < dim; i++)
2195 index[i] = 0;
2198 ret = createOleArrayWrapperOfDim(pArray, dim, dim, index, type, unoType);
2201 return ret;
2204 // If a VARIANT has the type VT_DISPATCH it can either be a JScript Array
2205 // or some other object. This function finds out if it is such an array or
2206 // not. Currently there's no way to make sure it's an array
2207 // so we assume that when the object has a property "0" then it is an Array.
2208 // A JScript has property like "0", "1", "2" etc. which represent the
2209 // value at the corresponding index of the array
2210 template<class T>
2211 bool UnoConversionUtilities<T>::isJScriptArray(const VARIANT* rvar)
2213 OSL_ENSURE( rvar->vt == VT_DISPATCH, "param is not a VT_DISPATCH");
2214 HRESULT hr;
2215 OLECHAR const * sindex= L"0";
2216 DISPID id;
2217 if ( rvar->vt == VT_DISPATCH && rvar->pdispVal )
2219 hr= rvar->pdispVal->GetIDsOfNames(
2220 IID_NULL, const_cast<OLECHAR **>(&sindex), 1, LOCALE_USER_DEFAULT,
2221 &id);
2223 if( SUCCEEDED ( hr) )
2224 return true;
2227 return false;
2230 template<class T>
2231 VARTYPE UnoConversionUtilities<T>::mapTypeClassToVartype( TypeClass type)
2233 VARTYPE ret;
2234 switch( type)
2236 case TypeClass_INTERFACE: ret= VT_DISPATCH;
2237 break;
2238 case TypeClass_STRUCT: ret= VT_DISPATCH;
2239 break;
2240 case TypeClass_ENUM: ret= VT_I4;
2241 break;
2242 case TypeClass_SEQUENCE: ret= VT_ARRAY;
2243 break;
2244 case TypeClass_ANY: ret= VT_VARIANT;
2245 break;
2246 case TypeClass_BOOLEAN: ret= VT_BOOL;
2247 break;
2248 case TypeClass_CHAR: ret= VT_I2;
2249 break;
2250 case TypeClass_STRING: ret= VT_BSTR;
2251 break;
2252 case TypeClass_FLOAT: ret= VT_R4;
2253 break;
2254 case TypeClass_DOUBLE: ret= VT_R8;
2255 break;
2256 case TypeClass_BYTE: ret= VT_UI1;
2257 break;
2258 case TypeClass_SHORT: ret= VT_I2;
2259 break;
2260 case TypeClass_LONG: ret= VT_I4;
2261 break;
2262 case TypeClass_UNSIGNED_SHORT: ret= VT_UI2;
2263 break;
2264 case TypeClass_UNSIGNED_LONG: ret= VT_UI4;
2265 break;
2266 default:
2267 ret= VT_EMPTY;
2269 return ret;
2272 template<class T>
2273 Sequence<Type> UnoConversionUtilities<T>::getImplementedInterfaces(IUnknown* pUnk)
2275 Sequence<Type> seqTypes;
2276 CComDispatchDriver disp( pUnk);
2277 if( disp)
2279 CComVariant var;
2280 HRESULT hr= S_OK;
2281 // There are two different property names possible.
2282 if( FAILED( hr= disp.GetPropertyByName( SUPPORTED_INTERFACES_PROP, &var)))
2284 hr= disp.GetPropertyByName( SUPPORTED_INTERFACES_PROP2, &var);
2286 if (SUCCEEDED( hr))
2288 // we expect an array( SafeArray or IDispatch) of Strings.
2289 Any anyNames;
2290 variantToAny( &var, anyNames, cppu::UnoType<Sequence<Any>>::get());
2291 Sequence<Any> seqAny;
2292 if( anyNames >>= seqAny)
2294 seqTypes.realloc( seqAny.getLength());
2295 for( sal_Int32 i=0; i < seqAny.getLength(); i++)
2297 OUString typeName;
2298 seqAny[i] >>= typeName;
2299 seqTypes[i]= Type( TypeClass_INTERFACE, typeName);
2304 return seqTypes;
2306 template<class T>
2307 Reference<XTypeConverter> UnoConversionUtilities<T>::getTypeConverter()
2309 if ( ! m_typeConverter.is())
2311 MutexGuard guard(getBridgeMutex());
2312 if ( ! m_typeConverter.is())
2314 Reference<XInterface> xIntConverter =
2315 m_smgr->createInstance("com.sun.star.script.Converter");
2316 if (xIntConverter.is())
2317 m_typeConverter.set(xIntConverter, UNO_QUERY);
2320 return m_typeConverter;
2323 // This function tries to the change the type of a value (contained in the Any)
2324 // to the smallest possible that can hold the value. This is actually done only
2325 // for types of VT_I4 (see o2u_variantToAny). The reason is the following:
2326 // JavaScript passes integer values always as VT_I4. If there is a parameter or
2327 // property of type any then the bridge converts the any's content according
2328 // to "o2u_variantToAny". Because the VARTYPE is VT_I4 the value would be converted
2329 // to TypeClass_LONG. Say the method XPropertySet::setPropertyValue( string name, any value)
2330 // would be called on an object and the property actually is of TypeClass_SHORT.
2331 // After conversion of the VARIANT parameter the Any would contain type
2332 // TypeClass_LONG. Because the corereflection does not cast from long to short
2333 // the "setPropertValue" would fail as the value has not the right type.
2335 // The corereflection does convert small integer types to bigger types.
2336 // Therefore we can reduce the type if possible and avoid the above mentioned
2337 // problem.
2339 // The function is not used when elements are to be converted for Sequences.
2341 inline void reduceRange( Any& any)
2343 OSL_ASSERT( any.getValueTypeClass() == TypeClass_LONG);
2345 sal_Int32 value= *o3tl::doAccess<sal_Int32>(any);
2346 if( value <= 0x7f && value >= -0x80)
2347 {// -128 bis 127
2348 sal_Int8 charVal= static_cast<sal_Int8>( value);
2349 any.setValue( &charVal, cppu::UnoType<sal_Int8>::get());
2351 else if( value <= 0x7fff && value >= -0x8000)
2352 {// -32768 bis 32767
2353 sal_Int16 shortVal= static_cast<sal_Int16>( value);
2354 any.setValue( &shortVal, cppu::UnoType<sal_Int16>::get());
2358 #endif
2360 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */