bump product version to 5.0.4.1
[LibreOffice.git] / extensions / source / ole / unoconversionutilities.hxx
blob1984d1003e0acad7021148ae079bcc287b27d511
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 "boost/scoped_array.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/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 "ole2uno.hxx"
34 #include "unotypewrapper.hxx"
35 #include <unordered_map>
37 // for some reason DECIMAL_NEG (wtypes.h) which contains BYTE is not resolved.
38 typedef unsigned char BYTE;
39 // classes for wrapping uno objects
40 #define INTERFACE_OLE_WRAPPER_IMPL 1
41 #define UNO_OBJECT_WRAPPER_REMOTE_OPT 2
43 #define INVOCATION_SERVICE reinterpret_cast<const sal_Unicode*>(L"com.sun.star.script.Invocation")
46 // classes for wrapping ole objects
47 #define IUNKNOWN_WRAPPER_IMPL 1
49 #define INTERFACE_ADAPTER_FACTORY reinterpret_cast<const sal_Unicode*>(L"com.sun.star.script.InvocationAdapterFactory")
50 // COM or JScript objects implementing UNO interfaces have to implement this property
51 #define SUPPORTED_INTERFACES_PROP L"_implementedInterfaces"
52 // Second property without leading underscore for use in VB
53 #define SUPPORTED_INTERFACES_PROP2 L"Bridge_ImplementedInterfaces"
55 using namespace com::sun::star::script;
56 using namespace com::sun::star::beans;
57 using namespace com::sun::star::uno;
58 #ifdef __MINGW32__
59 using namespace com::sun::star::bridge;
60 using namespace com::sun::star::bridge::ModelDependent;
61 #endif
62 using namespace com::sun::star::bridge::oleautomation;
63 using namespace boost;
64 namespace ole_adapter
66 extern std::unordered_map<sal_uInt32, sal_uInt32> AdapterToWrapperMap;
67 extern std::unordered_map<sal_uInt32, sal_uInt32> WrapperToAdapterMap;
68 typedef std::unordered_map<sal_uInt32, sal_uInt32>::iterator IT_Wrap;
69 typedef std::unordered_map<sal_uInt32, sal_uInt32>::iterator CIT_Wrap;
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_uInt32, WeakReference<XInterface> > ComPtrToWrapperMap;
75 typedef std::unordered_map<sal_uInt32, WeakReference<XInterface> >::iterator IT_Com;
76 typedef std::unordered_map<sal_uInt32, WeakReference<XInterface> >::const_iterator CIT_Com;
78 // Maps XInterface pointers to a weak reference of its wrapper class (i.e.
79 // InterfaceOleWrapper_Impl). It is the responsibility of the wrapper to remove the entry when
80 // it is being destroyed. It is used to ensure the identity of objects. That is, an UNO interface
81 // is mapped to IDispatch which is kept alive in the COM environment. If the same
82 // UNO interface is mapped again to COM then the IDispach of the first mapped instance
83 // must be returned.
84 extern std::unordered_map<sal_uInt32, WeakReference<XInterface> > UnoObjToWrapperMap;
85 typedef std::unordered_map<sal_uInt32, WeakReference<XInterface> >::iterator IT_Uno;
86 typedef std::unordered_map<sal_uInt32, WeakReference<XInterface> >::const_iterator CIT_Uno;
87 #ifdef __MINGW32__
88 inline void reduceRange( Any& any);
89 #endif
94 // createUnoObjectWrapper gets a wrapper instance by calling createUnoWrapperInstance
95 // and initializes it via XInitialization. The wrapper object is required to implement
96 // XBridgeSupplier so that it can convert itself to IDispatch.
97 // class T: Deriving class ( must implement XInterface )
98 /** All methods are allowed to throw at least a BridgeRuntimeError.
100 template< class >
101 class UnoConversionUtilities
103 public:
104 UnoConversionUtilities( const Reference<XMultiServiceFactory> & smgr):
105 m_nUnoWrapperClass( INTERFACE_OLE_WRAPPER_IMPL),
106 m_nComWrapperClass( IUNKNOWN_WRAPPER_IMPL),
107 m_smgr( smgr)
110 UnoConversionUtilities( const Reference<XMultiServiceFactory> & xFactory, sal_uInt8 unoWrapperClass, sal_uInt8 comWrapperClass )
111 : m_smgr( xFactory), m_nComWrapperClass( comWrapperClass), m_nUnoWrapperClass( unoWrapperClass)
114 virtual ~UnoConversionUtilities() {}
115 /** converts only into oleautomation types, that is there is no VT_I1, VT_UI2, VT_UI4
116 a sal_Unicode character is converted into a BSTR.
117 @exception com.sun.star.lang.IllegalArgumentException
118 If the any was inappropriate for conversion.
119 @exception com.sun.star.script.CannotConvertException
120 The any contains a type class for which no conversion is provided.
122 void anyToVariant(VARIANT* pVariant, const Any& rAny);
123 void anyToVariant(VARIANT* pVariant, const Any& rAny, VARTYPE type);
125 /** @exception com.sun.star.lang.IllegalArgumentException
126 If rSeq does not contain a sequence then the exception is thrown.
128 SAFEARRAY* createUnoSequenceWrapper(const Any& rSeq);
129 /** @exception com.sun.star.lang.IllegalArgumentException
130 If rSeq does not contain a sequence or elemtype has no proper value
131 then the exception is thrown.
133 SAFEARRAY* createUnoSequenceWrapper(const Any& rSeq, VARTYPE elemtype);
135 @exception com.sun.star.lang.IllegalArgumentException
136 If rObj does not contain a struct or interface
138 void createUnoObjectWrapper(const Any & rObj, VARIANT * pVar);
139 /** @exception CannotConvertException
140 Thrown if the VARIANT contains a type that cannot be coerced in the expected Any.
141 ArgumentIndex is 0.
142 @IllegalArgumentException
143 Thrown if the VARIANT is inappropriate for conversion. ArgumentPosition is -1,
145 void variantToAny(const VARIANT* pVariant, Any& rAny, sal_Bool bReduceValueRange = sal_True);
146 /** This method converts variants arguments in calls from COM -> UNO. Only then
147 the expected UNO type is known.
148 @exception CannotConvertException
149 Thrown if the VARIANT contains a type that cannot be coerced in the expected Any.
150 ArgumentIndex is 0.
151 @IllegalArgumentException
152 Thrown if the VARIANT is inappropriate for conversion. ArgumentPosition is -1,
154 void variantToAny( const VARIANTARG* pArg, Any& rAny, const Type& ptype, sal_Bool bReduceValueRange = sal_True);
157 @exception IllegalArgumentException
158 -if pVar does not contain VT_UNKNOWN or VT_DISPATCH or
159 pVar is used for a particular UNO type which is not supported by pVar
161 Any createOleObjectWrapper(VARIANT* pVar, const Type& aType= Type());
164 Return true means var contained a ValueObject, and it was successfully converted.
165 The result is in any. It an error occurred a BridgeRuntimeError will be thrown.
167 bool convertValueObject( const VARIANTARG *var, Any& any);
168 void dispatchExObject2Sequence( const VARIANTARG* pvar, Any& anySeq, const Type& type);
170 Sequence<Any> createOleArrayWrapperOfDim(SAFEARRAY* pArray, unsigned int dimCount, unsigned int actDim, long* index,
171 VARTYPE type, const Type& unotype);
172 Sequence<Any> createOleArrayWrapper(SAFEARRAY* pArray, VARTYPE type, const Type& unotype= Type());
175 VARTYPE mapTypeClassToVartype( TypeClass type);
176 Reference< XSingleServiceFactory > getInvocationFactory(const Any& anyObject);
179 virtual Reference< XInterface > createUnoWrapperInstance()=0;
180 virtual Reference< XInterface > createComWrapperInstance()=0;
182 static sal_Bool isJScriptArray(const VARIANT* pvar);
184 Sequence<Type> getImplementedInterfaces(IUnknown* pUnk);
186 protected:
187 Reference<XInterface> createAdapter(const Sequence<Type>& types, const Reference<XInterface>& receiver);
189 // helper function for Sequence conversion
190 void getElementCountAndTypeOfSequence( const Any& rSeq, sal_Int32 dim, Sequence< sal_Int32 >& seqElementCounts, TypeDescription& typeDesc);
191 // helper function for Sequence conversion
192 sal_Bool incrementMultidimensionalIndex(sal_Int32 dimensions, const sal_Int32 * parDimensionLength,
193 sal_Int32 * parMultidimensionalIndex);
194 // helper function for Sequence conversion
195 size_t getOleElementSize( VARTYPE type);
197 Type getElementTypeOfSequence( const Type& seqType);
199 //Provides a typeconverter
200 Reference<XTypeConverter> getTypeConverter();
202 // This member determines what class is used to convert a UNO object
203 // or struct to a COM object. It is passed along to the o2u_anyToVariant
204 // function in the createBridge function implementation
205 sal_uInt8 m_nUnoWrapperClass;
206 sal_uInt8 m_nComWrapperClass;
208 // The servicemanager is either a local smgr or remote when the service
209 // com.sun.star.bridge.OleBridgeSupplierVar1 is used. This service can be
210 // created by createInstanceWithArguments where one can supply a service
211 // manager that is to be used.
212 // Local service manager as supplied by the loader when the creator function
213 // of the service is being called.
214 Reference<XMultiServiceFactory> m_smgr;
215 // An explicitly supplied service manager when the service
216 // com.sun.star.bridge.OleBridgeSupplierVar1 is used. That can be a remote
217 // manager.
218 Reference<XMultiServiceFactory> m_smgrRemote;
219 Reference<XSingleServiceFactory> m_xInvocationFactoryLocal;
220 Reference<XSingleServiceFactory> m_xInvocationFactoryRemote;
222 private:
223 // Holds the type converter which is used for sequence conversion etc.
224 // Use the getTypeConverter function to obtain the interface.
225 Reference<XTypeConverter> m_typeConverter;
230 // ask the object for XBridgeSupplier2 and on success bridges
231 // the uno object to IUnknown or IDispatch.
232 // return true the UNO object supports
233 template < class T >
234 bool convertSelfToCom( T& unoInterface, VARIANT * pVar)
236 bool ret = false;
237 Reference< XInterface > xInt( unoInterface, UNO_QUERY);
238 if( xInt.is())
240 Reference< XBridgeSupplier2 > xSupplier( xInt, UNO_QUERY);
241 if( xSupplier.is())
243 sal_Int8 arId[16];
244 rtl_getGlobalProcessId( (sal_uInt8*)arId);
245 Sequence<sal_Int8> seqId( arId, 16);
246 Any anySource;
247 anySource <<= xInt;
248 Any anyDisp= xSupplier->createBridge( anySource, seqId, UNO, OLE);
249 if( anyDisp.getValueTypeClass() == TypeClass_UNSIGNED_LONG)
251 VARIANT* pvariant= *(VARIANT**)anyDisp.getValue();
252 HRESULT hr;
253 if (FAILED(hr = VariantCopy(pVar, pvariant)))
254 throw BridgeRuntimeError(
255 "[automation bridge] convertSelfToCom\n"
256 "VariantCopy failed! Error: " +
257 OUString::number(hr));
258 VariantClear( pvariant);
259 CoTaskMemFree( pvariant);
260 ret = true;
264 return ret;
269 // Gets the invocation factory depending on the Type in the Any.
270 // The factory can be created by a local or remote multi service factory.
271 // In case there is a remote multi service factory available there are
272 // some services or types for which the local factory is used. The exceptions
273 // are: all structs.
274 // Param anyObject - contains the object ( interface, struct) for what we need an invocation object.
276 template<class T>
277 Reference< XSingleServiceFactory > UnoConversionUtilities<T>::getInvocationFactory(const Any& anyObject)
279 Reference< XSingleServiceFactory > retVal;
280 MutexGuard guard( getBridgeMutex());
281 if( anyObject.getValueTypeClass() != TypeClass_STRUCT &&
282 m_smgrRemote.is() )
284 if( ! m_xInvocationFactoryRemote.is() )
285 m_xInvocationFactoryRemote= Reference<XSingleServiceFactory>(
286 m_smgrRemote->createInstance( INVOCATION_SERVICE), UNO_QUERY);
287 retVal= m_xInvocationFactoryRemote;
289 else
291 if( ! m_xInvocationFactoryLocal.is() )
292 m_xInvocationFactoryLocal= Reference<XSingleServiceFactory>(
293 m_smgr->createInstance(INVOCATION_SERVICE ), UNO_QUERY);
294 retVal= m_xInvocationFactoryLocal;
296 return retVal;
299 template<class T>
300 void UnoConversionUtilities<T>::variantToAny( const VARIANTARG* pArg, Any& rAny, const Type& ptype, sal_Bool bReduceValueRange /* = sal_True */)
304 HRESULT hr;
305 bool bFail = false;
306 bool bCannotConvert = false;
307 CComVariant var;
309 // There is no need to support indirect values, since they're not supported by UNO
310 if( FAILED(hr= VariantCopyInd( &var, const_cast<VARIANTARG*>(pArg)))) // remove VT_BYREF
311 throw BridgeRuntimeError(
312 "[automation bridge] UnoConversionUtilities<T>::variantToAny \n"
313 "VariantCopyInd failed for reason : " + OUString::number(hr));
314 bool bHandled = convertValueObject( & var, rAny);
315 if( bHandled)
316 OSL_ENSURE( rAny.getValueType() == ptype, "type in Value Object must match the type parameter");
318 if( ! bHandled)
320 // convert into a variant type that is the equivalent to the type
321 // the sequence expects. Thus variantToAny produces the correct type
322 // E.g. An Array object contains VT_I4 and the sequence expects shorts
323 // than the vartype must be changed. The reason is, you can't specify the
324 // type in JavaScript and the script engine determines the type being used.
325 switch( ptype.getTypeClass())
327 case TypeClass_CHAR: // could be: new Array( 12, 'w', "w")
328 if( var.vt == VT_BSTR)
330 if(SUCCEEDED( hr= VariantChangeType( &var, &var, 0, VT_BSTR)))
331 rAny.setValue( (void*)V_BSTR( &var), ptype);
332 else if (hr == DISP_E_TYPEMISMATCH)
333 bCannotConvert = true;
334 else
335 bFail = true;
337 else
339 if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_I2)))
340 rAny.setValue((void*) & var.iVal, ptype);
341 else if (hr == DISP_E_TYPEMISMATCH)
342 bCannotConvert = true;
343 else
344 bFail = true;
346 break;
347 case TypeClass_INTERFACE: // could also be an IUnknown
348 case TypeClass_STRUCT:
350 rAny = createOleObjectWrapper( & var, ptype);
351 break;
353 case TypeClass_ENUM:
354 if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_I4)))
355 rAny.setValue((void*) & var.lVal, ptype);
356 else if (hr == DISP_E_TYPEMISMATCH)
357 bCannotConvert = true;
358 else
359 bFail = true;
360 break;
361 case TypeClass_SEQUENCE:
362 // There are different ways of receiving a sequence:
363 // 1: JScript, VARTYPE: VT_DISPATCH
364 // 2. VBScript simple arraysVT_VARIANT|VT_BYREF the referenced VARIANT contains
365 // a VT_ARRAY| <type>
366 // 3. VBSrcript multi dimensional arrays: VT_ARRAY|VT_BYREF
367 if( pArg->vt == VT_DISPATCH)
369 dispatchExObject2Sequence( pArg, rAny, ptype);
371 else
373 if ((var.vt & VT_ARRAY) != 0)
375 VARTYPE oleType = ::sal::static_int_cast< VARTYPE, int >( var.vt ^ VT_ARRAY );
376 Sequence<Any> unoSeq = createOleArrayWrapper( var.parray, oleType, ptype);
377 Reference<XTypeConverter> conv = getTypeConverter();
378 if (conv.is())
382 Any anySeq = makeAny(unoSeq);
383 Any convAny = conv->convertTo(anySeq, ptype);
384 rAny = convAny;
386 catch (const IllegalArgumentException& e)
388 throw BridgeRuntimeError(
389 "[automation bridge]com.sun.star.lang.IllegalArgumentException "
390 "in UnoConversionUtilities<T>::variantToAny! Message: " +
391 e.Message);
393 catch (const CannotConvertException& e)
395 throw BridgeRuntimeError(
396 "[automation bridge]com.sun.star.script.CannotConvertException "
397 "in UnoConversionUtilities<T>::variantToAny! Message: " +
398 e.Message);
403 break;
404 case TypeClass_VOID:
405 rAny.setValue(NULL,Type());
406 break;
407 case TypeClass_ANY: // Any
408 // There could be a JScript Array that needs special handling
409 // If an Any is expected and this Any must contain a Sequence
410 // then we cannot figure out what element type is required.
411 // Therefore we convert to Sequence< Any >
412 if( pArg->vt == VT_DISPATCH && isJScriptArray( pArg))
414 dispatchExObject2Sequence( pArg, rAny,
415 cppu::UnoType<Sequence<Any>>::get());
417 else if (pArg->vt == VT_DECIMAL)
419 //Decimal maps to hyper in calls from COM -> UNO
420 // It does not matter if we create a sal_uInt64 or sal_Int64,
421 // because the UNO object is called through invocation which
422 //will do a type conversion if necessary
423 if (var.decVal.sign == 0)
425 // positive value
426 variantToAny( & var, rAny, cppu::UnoType<sal_uInt64>::get(),
427 bReduceValueRange);
429 else
431 //negative value
432 variantToAny( & var, rAny, cppu::UnoType<sal_Int64>::get(),
433 bReduceValueRange);
436 else
438 variantToAny( & var, rAny);
440 break;
441 case TypeClass_BOOLEAN: // VARIANT could be VARIANT_BOOL or other
442 if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_BOOL)))
443 variantToAny( & var, rAny);
444 else if (hr == DISP_E_TYPEMISMATCH)
445 bCannotConvert = true;
446 else
447 bFail = true;
448 break;
449 case TypeClass_STRING: // UString
450 if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_BSTR)))
451 variantToAny( & var, rAny);
452 else if (hr == DISP_E_TYPEMISMATCH)
453 bCannotConvert = true;
454 else
455 bFail = true;
456 break;
457 case TypeClass_FLOAT: // float
458 if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_R4)))
459 variantToAny( & var, rAny);
460 else if (hr == DISP_E_TYPEMISMATCH)
461 bCannotConvert = true;
462 else
463 bFail = true;
464 break;
465 case TypeClass_DOUBLE: // double
466 if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_R8)))
467 variantToAny(& var, rAny);
468 else if (hr == DISP_E_TYPEMISMATCH)
469 bCannotConvert = true;
470 else
471 bFail = true;
472 break;
473 case TypeClass_BYTE: // BYTE
474 if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_I1)))
475 variantToAny( & var, rAny);
476 else if (hr == DISP_E_TYPEMISMATCH)
477 bCannotConvert = true;
478 else
479 bFail = true;
480 break;
481 case TypeClass_SHORT: // INT16
482 if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_I2)))
483 variantToAny( & var, rAny);
484 else if (hr == DISP_E_TYPEMISMATCH)
485 bCannotConvert = true;
486 else
487 bFail = true;
488 break;
489 case TypeClass_LONG:
490 if(SUCCEEDED(hr = VariantChangeType(& var, &var, 0, VT_I4)))
491 variantToAny( & var, rAny, bReduceValueRange);
492 else if (hr == DISP_E_TYPEMISMATCH)
493 bCannotConvert = true;
494 else
495 bFail = true;
496 break;
497 case TypeClass_HYPER:
498 if(SUCCEEDED(hr = VariantChangeType(& var, &var, 0, VT_DECIMAL)))
500 if (var.decVal.Lo64 > SAL_CONST_UINT64(0x8000000000000000)
501 || var.decVal.Hi32 > 0
502 || var.decVal.scale > 0)
504 bFail = true;
505 break;
507 sal_Int64 value = var.decVal.Lo64;
508 if (var.decVal.sign == DECIMAL_NEG)
509 value |= SAL_CONST_UINT64(0x8000000000000000);
510 rAny <<= value;
512 else if (hr == DISP_E_TYPEMISMATCH)
513 bCannotConvert = true;
514 else
515 bFail = true;
516 break;
517 case TypeClass_UNSIGNED_SHORT: // UINT16
518 if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_UI2)))
519 variantToAny( & var, rAny);
520 else if (hr == DISP_E_TYPEMISMATCH)
521 bCannotConvert = true;
522 else
523 bFail = true;
524 break;
525 case TypeClass_UNSIGNED_LONG:
526 if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_UI4)))
527 variantToAny( & var, rAny, bReduceValueRange);
528 else if (hr == DISP_E_TYPEMISMATCH)
529 bCannotConvert = true;
530 else
531 bFail = true;
532 break;
533 case TypeClass_UNSIGNED_HYPER:
534 if(SUCCEEDED(hr = VariantChangeType(& var, &var, 0, VT_DECIMAL)))
536 if (var.decVal.Hi32 > 0 || var.decVal.scale > 0)
538 bFail = true;
539 break;
541 rAny <<= var.decVal.Lo64;
543 else if (hr == DISP_E_TYPEMISMATCH)
544 bCannotConvert = true;
545 else
546 bFail = true;
547 break;
548 case TypeClass_TYPE:
549 if(SUCCEEDED(hr = VariantChangeType(& var, &var, 0, VT_UNKNOWN)))
550 variantToAny( & var, rAny);
551 else if (hr == DISP_E_TYPEMISMATCH)
552 bCannotConvert = true;
553 else
554 bFail = true;
555 break;
556 default:
557 bCannotConvert = true;
558 break;
561 if (bCannotConvert)
562 throw CannotConvertException(
563 "[automation bridge]UnoConversionUtilities<T>::variantToAny \n"
564 "Cannot convert the value of vartype :\"" +
565 OUString::number((sal_Int32) var.vt) +
566 "\" to the expected UNO type of type class: " +
567 OUString::number((sal_Int32) ptype.getTypeClass()),
568 0, TypeClass_UNKNOWN, FailReason::TYPE_NOT_SUPPORTED,0);
570 if (bFail)
571 throw IllegalArgumentException(
572 "[automation bridge]UnoConversionUtilities<T>:variantToAny\n"
573 "The provided VARIANT of type\" " + OUString::number((sal_Int32) var.vt) +
574 "\" is unappropriate for conversion!", Reference<XInterface>(), -1);
576 catch (const CannotConvertException &)
578 throw;
580 catch (const IllegalArgumentException &)
582 throw;
584 catch (const BridgeRuntimeError &)
586 throw;
588 catch (const Exception & e)
590 throw BridgeRuntimeError("[automation bridge] unexpected exception in "
591 "UnoConversionUtilities<T>::variantToAny ! Message : \n" +
592 e.Message);
594 catch(...)
596 throw BridgeRuntimeError(
597 "[automation bridge] unexpected exception in "
598 "UnoConversionUtilities<T>::variantToAny !");
602 // The function only converts Sequences to SAFEARRAYS with elements of the type
603 // specified by the parameter type. Everything else is forwarded to
604 // anyToVariant(VARIANT* pVariant, const Any& rAny)
605 // Param type must not be VT_BYREF
606 template<class T>
607 void UnoConversionUtilities<T>::anyToVariant(VARIANT* pVariant, const Any& rAny, VARTYPE type)
611 HRESULT hr= S_OK;
613 OSL_ASSERT( (type & VT_BYREF) == 0);
614 if (type & VT_ARRAY)
616 type ^= VT_ARRAY;
617 SAFEARRAY* ar= createUnoSequenceWrapper( rAny, type);
618 if( ar)
620 VariantClear( pVariant);
621 pVariant->vt= ::sal::static_int_cast< VARTYPE, int >( VT_ARRAY | type );
622 pVariant->byref= ar;
625 else if(type == VT_VARIANT)
627 anyToVariant(pVariant, rAny);
629 else
631 CComVariant var;
632 anyToVariant( &var, rAny);
633 if(FAILED(hr = VariantChangeType(&var, &var, 0, type)))
635 if (hr == DISP_E_TYPEMISMATCH)
636 throw CannotConvertException(
637 "[automation bridge]UnoConversionUtilities<T>::anyToVariant \n"
638 "Cannot convert the value of type :\"" +
639 rAny.getValueTypeName() +
640 "\" to the expected Automation type of VARTYPE: " +
641 OUString::number((sal_Int32)type),
642 0, TypeClass_UNKNOWN, FailReason::TYPE_NOT_SUPPORTED,0);
644 throw BridgeRuntimeError(
645 "[automation bridge]UnoConversionUtilities<T>::anyToVariant \n"
646 "Conversion of any with " +
647 rAny.getValueType().getTypeName() +
648 " to VARIANT with type: " + OUString::number((sal_Int32) type) +
649 " failed! Error code: " + OUString::number(hr));
652 if(FAILED(hr = VariantCopy(pVariant, &var)))
654 throw BridgeRuntimeError(
655 "[automation bridge]UnoConversionUtilities<T>::anyToVariant \n"
656 "VariantCopy failed for reason: " + OUString::number(hr));
660 catch (const IllegalArgumentException &)
662 throw;
664 catch (const CannotConvertException &)
666 throw;
668 catch (const BridgeRuntimeError&)
670 throw;
672 catch(const Exception & e)
674 throw BridgeRuntimeError(
675 "[automation bridge]UnoConversionUtilities<T>::anyToVariant \n"
676 "Unexpected exception occurred. Message: " + e.Message);
678 catch(...)
680 throw BridgeRuntimeError(
681 "[automation bridge]UnoConversionUtilities<T>::anyToVariant \n"
682 "Unexpected exception occurred.");
686 template<class T>
687 void UnoConversionUtilities<T>::anyToVariant(VARIANT* pVariant, const Any& rAny)
691 bool bIllegal = false;
692 switch (rAny.getValueTypeClass())
694 case TypeClass_INTERFACE:
696 Reference<XInterface> xInt;
697 if (rAny >>= xInt)
699 createUnoObjectWrapper(rAny, pVariant);
701 else
703 bIllegal = true;
705 break;
707 case TypeClass_STRUCT:
709 if (rAny.getValueType() == cppu::UnoType<Date>::get() )
711 Date d;
712 if (rAny >>= d)
714 pVariant->vt = VT_DATE;
715 pVariant->date = d.Value;
717 else
719 bIllegal = true;
722 else if(rAny.getValueType() == cppu::UnoType<Decimal>::get())
724 Decimal d;
725 if (rAny >>= d)
727 pVariant->vt = VT_DECIMAL;
728 pVariant->decVal.scale = d.Scale;
729 pVariant->decVal.sign = d.Sign;
730 pVariant->decVal.Lo32 = d.LowValue;
731 pVariant->decVal.Mid32 = d.MiddleValue;
732 pVariant->decVal.Hi32 = d.HighValue;
734 else
736 bIllegal = true;
739 else if (rAny.getValueType() == cppu::UnoType<Currency>::get())
741 Currency c;
742 if (rAny >>= c)
744 pVariant->vt = VT_CY;
745 pVariant->cyVal.int64 = c.Value;
747 else
749 bIllegal = true;
752 else if(rAny.getValueType() == cppu::UnoType<SCode>::get())
754 SCode s;
755 if (rAny >>= s)
757 pVariant->vt = VT_ERROR;
758 pVariant->scode = s.Value;
760 else
762 bIllegal = true;
765 else
767 createUnoObjectWrapper(rAny, pVariant);
769 break;
771 case TypeClass_SEQUENCE: // sequence ??? SafeArray descriptor
773 SAFEARRAY* pArray = createUnoSequenceWrapper(rAny);
774 if (pArray)
776 V_VT(pVariant) = VT_ARRAY | VT_VARIANT;
777 V_ARRAY(pVariant) = pArray;
779 else
781 bIllegal = true;
783 break;
785 case TypeClass_VOID:
787 HRESULT hr = S_OK;
788 if (FAILED(hr = VariantClear(pVariant)))
790 throw BridgeRuntimeError(
791 "[automation bridge]UnoConversionUtilities<T>::anyToVariant\n"
792 "VariantClear failed with error:" + OUString::number(hr));
794 break;
796 case TypeClass_BOOLEAN:
798 sal_Bool value;
799 if (rAny >>= value)
801 pVariant->vt = VT_BOOL;
802 pVariant->boolVal = value == sal_True? VARIANT_TRUE: VARIANT_FALSE;
804 else
806 bIllegal = true;
808 break;
810 case TypeClass_CHAR:
812 // Because VT_UI2 does not conform to oleautomation we convert into VT_I2 instead
813 sal_uInt16 value = *(sal_Unicode*) rAny.getValue();
814 pVariant->vt = VT_I2;
815 pVariant->iVal = value;
816 break;
818 case TypeClass_STRING:
820 OUString value;
821 if (rAny >>= value)
823 pVariant->vt = VT_BSTR;
824 pVariant->bstrVal = SysAllocString(reinterpret_cast<LPCOLESTR>(value.getStr()));
826 else
828 bIllegal = true;
830 break;
832 case TypeClass_FLOAT:
834 float value;
835 if (rAny >>= value)
837 pVariant->vt = VT_R4;
838 pVariant->fltVal = value;
840 else
842 bIllegal = true;
844 break;
846 case TypeClass_DOUBLE:
848 double value;
849 if (rAny >>= value)
851 pVariant->vt = VT_R8;
852 pVariant->dblVal = value;
854 else
856 bIllegal = true;
858 break;
860 case TypeClass_BYTE:
862 // ole automation does not know a signed char but only unsigned char
863 sal_Int8 value;
864 if (rAny >>= value)
866 pVariant->vt = VT_UI1;
867 pVariant->bVal = value;
869 else
871 bIllegal = true;
873 break;
875 case TypeClass_SHORT: // INT16
876 case TypeClass_UNSIGNED_SHORT: // UINT16
878 sal_Int16 value;
879 if (rAny >>= value)
881 pVariant->vt = VT_I2;
882 pVariant->iVal = value;
884 else
886 bIllegal = true;
888 break;
890 case TypeClass_ENUM:
892 sal_Int32 value = *(sal_Int32*) rAny.getValue();
893 pVariant->vt = VT_I4;
894 pVariant->lVal= value;
895 break;
897 case TypeClass_LONG:
898 case TypeClass_UNSIGNED_LONG:
900 sal_Int32 value;
901 if (rAny >>= value)
903 pVariant->vt = VT_I4;
904 pVariant->lVal= value;
906 else
908 bIllegal = true;
910 break;
912 case TypeClass_HYPER:
915 pVariant->vt = VT_DECIMAL;
916 pVariant->decVal.scale = 0;
917 pVariant->decVal.sign = 0;
918 pVariant->decVal.Hi32 = 0;
920 sal_Int64 value;
921 rAny >>= value;
923 if (value & SAL_CONST_UINT64(0x8000000000000000))
924 pVariant->decVal.sign = DECIMAL_NEG;
926 pVariant->decVal.Lo64 = value;
927 break;
929 case TypeClass_UNSIGNED_HYPER:
931 pVariant->vt = VT_DECIMAL;
932 pVariant->decVal.scale = 0;
933 pVariant->decVal.sign = 0;
934 pVariant->decVal.Hi32 = 0;
936 sal_uInt64 value;
937 rAny >>= value;
938 pVariant->decVal.Lo64 = value;
939 break;
941 case TypeClass_TYPE:
943 Type type;
944 rAny >>= type;
945 CComVariant var;
946 if (createUnoTypeWrapper(type.getTypeName(), & var) == false)
947 throw BridgeRuntimeError(
948 "[automation bridge] UnoConversionUtilities<T>::anyToVariant \n"
949 "Error during conversion of UNO type to Automation object!");
951 if (FAILED(VariantCopy(pVariant, &var)))
952 throw BridgeRuntimeError(
953 "[automation bridge] UnoConversionUtilities<T>::anyToVariant \n"
954 "Unexpected error!");
955 break;
957 default:
958 //TypeClass_SERVICE:
959 //TypeClass_EXCEPTION:
960 //When a InvocationTargetException is thrown when calling XInvocation::invoke
961 //on a UNO object, then the target exception is directly used to create a
962 //EXEPINFO structure
963 //TypeClass_TYPEDEF
964 //TypeClass_ANY:
965 //TypeClass_UNKNOWN:
966 //TypeClass_MODULE:
967 throw CannotConvertException(
968 "[automation bridge]UnoConversionUtilities<T>::anyToVariant\n"
969 "There is no conversion for this UNO type to a Automation type."
970 "The destination type class is the type class of the UNO "
971 "argument which was to be converted.",
972 Reference<XInterface>(), rAny.getValueTypeClass(),
973 FailReason::TYPE_NOT_SUPPORTED, 0);
975 break;
977 if (bIllegal)
979 throw IllegalArgumentException(
980 "[automation bridge]UnoConversionUtilities<T>::anyToVariant\n"
981 "The provided any of type\" " + rAny.getValueType().getTypeName() +
982 "\" is unappropriate for conversion!", Reference<XInterface>(), -1);
986 catch (const CannotConvertException &)
988 throw;
990 catch (const IllegalArgumentException &)
992 throw;
994 catch(const BridgeRuntimeError&)
996 throw;
998 catch(const Exception & e)
1000 throw BridgeRuntimeError(
1001 "[automation bridge]UnoConversionUtilities<T>::anyToVariant \n"
1002 "Unexpected exception occurred. Message: " + e.Message);
1004 catch(...)
1006 throw BridgeRuntimeError(
1007 "[automation bridge]UnoConversionUtilities<T>::anyToVariant \n"
1008 "Unexpected exception occurred. " );
1012 // Creates an SAFEARRAY of the specified element and if necessary
1013 // creates a SAFEARRAY with multiple dimensions.
1014 // Used by sal_Bool anyToVariant(VARIANT* pVariant, const Any& rAny, VARTYPE type);
1015 template<class T>
1016 SAFEARRAY* UnoConversionUtilities<T>::createUnoSequenceWrapper(const Any& rSeq, VARTYPE elemtype)
1018 if (rSeq.getValueTypeClass() != TypeClass_SEQUENCE)
1019 throw IllegalArgumentException(
1020 "[automation bridge]UnoConversionUtilities<T>::createUnoSequenceWrapper \n"
1021 "The any does not contain a sequence!", 0, 0);
1022 if (elemtype == VT_NULL || elemtype == VT_EMPTY)
1023 throw IllegalArgumentException(
1024 "[automation bridge]UnoConversionUtilities<T>::createUnoSequenceWrapper \n"
1025 "No element type supplied!",0, -1);
1026 SAFEARRAY* pArray= NULL;
1027 // Get the dimensions. This is done by examining the type name string
1028 // The count of brackets determines the dimensions.
1029 OUString sTypeName= rSeq.getValueType().getTypeName();
1030 sal_Int32 dims=0;
1031 for(sal_Int32 lastIndex=0;(lastIndex= sTypeName.indexOf( L'[', lastIndex)) != -1; lastIndex++,dims++);
1033 //get the maximum number of elements per dimensions and the typedescription of the elements
1034 Sequence<sal_Int32> seqElementCounts( dims);
1035 TypeDescription elementTypeDesc;
1036 getElementCountAndTypeOfSequence( rSeq, 1, seqElementCounts, elementTypeDesc );
1038 if( elementTypeDesc.is() )
1040 // set up the SAFEARRAY
1041 scoped_array<SAFEARRAYBOUND> sarSafeArrayBound(new SAFEARRAYBOUND[dims]);
1042 SAFEARRAYBOUND* prgsabound= sarSafeArrayBound.get();
1043 for( sal_Int32 i=0; i < dims; i++)
1045 //prgsabound[0] is the right most dimension
1046 prgsabound[dims - i - 1].lLbound = 0;
1047 prgsabound[dims - i - 1].cElements = seqElementCounts[i];
1050 typelib_TypeDescription* rawTypeDesc= elementTypeDesc.get();
1051 sal_Int32 elementSize= rawTypeDesc->nSize;
1052 size_t oleElementSize= getOleElementSize( elemtype);
1053 // SafeArrayCreate clears the memory for the data itself.
1054 pArray = SafeArrayCreate(elemtype, dims, prgsabound);
1056 // convert the Sequence's elements and populate the SAFEARRAY
1057 if( pArray)
1059 // Iterate over every Sequence that contains the actual elements
1060 void* pSAData;
1061 if( SUCCEEDED( SafeArrayAccessData( pArray, &pSAData)))
1063 const sal_Int32* parElementCount= seqElementCounts.getConstArray();
1064 uno_Sequence * pMultiSeq= *(uno_Sequence* const*) rSeq.getValue();
1065 sal_Int32 dimsSeq= dims - 1;
1067 // arDimSeqIndices contains the current index of a block of data.
1068 // E.g. Sequence<Sequence<sal_Int32>> , the index would refer to Sequence<sal_Int32>
1069 // In this case arDimSeqIndices would have the size 1. That is the elements are not counted
1070 // but the Sequences that contain those elements.
1071 // The indices ar 0 based
1072 scoped_array<sal_Int32> sarDimsSeqIndices;
1073 sal_Int32* arDimsSeqIndices= NULL;
1074 if( dimsSeq > 0)
1076 sarDimsSeqIndices.reset(new sal_Int32[dimsSeq]);
1077 arDimsSeqIndices = sarDimsSeqIndices.get();
1078 memset( arDimsSeqIndices, 0, sizeof( sal_Int32 ) * dimsSeq);
1081 char* psaCurrentData= (char*)pSAData;
1085 // Get the Sequence at the current index , see arDimsSeqIndices
1086 uno_Sequence * pCurrentSeq= pMultiSeq;
1087 sal_Int32 curDim=1; // 1 based
1088 sal_Bool skipSeq= sal_False;
1089 while( curDim <= dimsSeq )
1091 // get the Sequence at the index if valid
1092 if( pCurrentSeq->nElements > arDimsSeqIndices[ curDim - 1] ) // don't point to Nirvana
1094 // size of Sequence is 4
1095 sal_Int32 offset= arDimsSeqIndices[ curDim - 1] * 4;
1096 pCurrentSeq= *(uno_Sequence**) &pCurrentSeq->elements[ offset];
1097 curDim++;
1099 else
1101 // There is no Sequence at this index, so skip this index
1102 skipSeq= sal_True;
1103 break;
1107 if( skipSeq)
1108 continue;
1110 // Calculate the current position within the datablock of the SAFEARRAY
1111 // for the next Sequence.
1112 sal_Int32 memOffset= 0;
1113 sal_Int32 dimWeight= parElementCount[ dims - 1]; // size of the rightmost dimension
1114 for(sal_Int16 idims=0; idims < dimsSeq; idims++ )
1116 memOffset+= arDimsSeqIndices[dimsSeq - 1 - idims] * dimWeight;
1117 // now determine the weight of the dimension to the left of the current.
1118 if( dims - 2 - idims >=0)
1119 dimWeight*= parElementCount[dims - 2 - idims];
1121 psaCurrentData= (char*)pSAData + memOffset * oleElementSize;
1122 // convert the Sequence and put the elements into the Safearray
1123 for( sal_Int32 i= 0; i < pCurrentSeq->nElements; i++)
1125 Any unoElement( pCurrentSeq->elements + i * elementSize, rawTypeDesc );
1126 // The any is being converted into an VARIANT which value is then copied
1127 // to the SAFEARRAY's data block. When copying one has to follow the rules for
1128 // copying certain types, as are VT_DISPATCH, VT_UNKNOWN, VT_VARIANT, VT_BSTR.
1129 // To increase performance, we just do a memcpy of VARIANT::byref. This is possible
1130 // because anyToVariant has already followed the copying rules. To make this
1131 // work there must not be a VariantClear.
1132 // One Exception is VARIANT because I don't know how VariantCopy works.
1134 VARIANT var;
1135 VariantInit( &var);
1136 anyToVariant( &var, unoElement);
1137 if( elemtype == VT_VARIANT )
1139 VariantCopy( ( VARIANT*)psaCurrentData, &var);
1140 VariantClear( &var);
1142 else
1143 memcpy( psaCurrentData, &var.byref, oleElementSize);
1145 psaCurrentData+= oleElementSize;
1148 while( incrementMultidimensionalIndex( dimsSeq, parElementCount, arDimsSeqIndices));
1150 SafeArrayUnaccessData( pArray);
1154 return pArray;
1157 // Increments a multi dimensional index.
1158 // Returns true as long as the index has been successfully incremented, false otherwise.
1159 // False is also returned if an overflow of the most significant dimension occurs. E.g.
1160 // assume an array with the dimensions (2,2), then the lowest index is (0,0) and the highest
1161 // index is (1,1). If the function is being called with the index (1,1) then the overflow would
1162 // occur, with the result (0,0) and a sal_False as return value.
1163 // Param dimensions - number of dimensions
1164 // Param parDimensionsLength - The array contains the size of each dimension, that is the
1165 // size of the array equals the parameter dimensions.
1166 // The rightmost dimensions is the least significant one
1167 // ( parDimensionsLengths[ dimensions -1 ] ).
1168 // Param parMultiDimensionalIndex - The array contains the index. Each dimension index is
1169 // 0 based.
1170 template<class T>
1171 sal_Bool UnoConversionUtilities<T>::incrementMultidimensionalIndex(sal_Int32 dimensions,
1172 const sal_Int32 * parDimensionLengths,
1173 sal_Int32 * parMultidimensionalIndex)
1175 if( dimensions < 1)
1176 return sal_False;
1178 sal_Bool ret= sal_True;
1179 sal_Bool carry= sal_True; // to get into the while loop
1181 sal_Int32 currentDimension= dimensions; //most significant is 1
1182 while( carry)
1184 parMultidimensionalIndex[ currentDimension - 1]++;
1185 // if carryover, set index to 0 and handle carry on a level above
1186 if( parMultidimensionalIndex[ currentDimension - 1] > (parDimensionLengths[ currentDimension - 1] - 1))
1187 parMultidimensionalIndex[ currentDimension - 1]= 0;
1188 else
1189 carry= sal_False;
1191 currentDimension --;
1192 // if dimensions drops below 1 and carry is set than then all indices are 0 again
1193 // this is signalled by returning sal_False
1194 if( currentDimension < 1 && carry)
1196 carry= sal_False;
1197 ret= sal_False;
1200 return ret;
1203 // Determines the size of a certain OLE type. The function takes
1204 // only those types into account which are oleautomation types and
1205 // can have a value ( unless VT_NULL, VT_EMPTY, VT_ARRAY, VT_BYREF).
1206 // Currently used in createUnoSequenceWrapper to calculate addresses
1207 // for data within a SAFEARRAY.
1208 template<class T>
1209 size_t UnoConversionUtilities<T>::getOleElementSize( VARTYPE type)
1211 size_t size;
1212 switch( type)
1214 case VT_BOOL: size= sizeof( VARIANT_BOOL);break;
1215 case VT_UI1: size= sizeof( unsigned char);break;
1216 case VT_R8: size= sizeof( double);break;
1217 case VT_R4: size= sizeof( float);break;
1218 case VT_I2: size= sizeof( short);break;
1219 case VT_I4: size= sizeof( long);break;
1220 case VT_BSTR: size= sizeof( BSTR); break;
1221 case VT_ERROR: size= sizeof( SCODE); break;
1222 case VT_DISPATCH:
1223 case VT_UNKNOWN: size= sizeof( IUnknown*); break;
1224 case VT_VARIANT: size= sizeof( VARIANT);break;
1225 default: size= 0;
1227 return size;
1230 //If a Sequence is being converted into a SAFEARRAY then we possibly have
1231 // to create a SAFEARRAY with multiple dimensions. This is the case when a
1232 // Sequence contains Sequences ( Sequence< Sequence < XXX > > ). The leftmost
1233 // Sequence in the declaration is assumed to represent dimension 1. Because
1234 // all Sequence elements of a Sequence can have different length, we have to
1235 // determine the maximum length which is then the length of the respective
1236 // dimension.
1237 // getElementCountAndTypeOfSequence determines the length of each dimension and calls itself recursively
1238 // in the process.
1239 // param rSeq - an Any that has to contain a Sequence
1240 // param dim - the dimension for which the number of elements is being determined,
1241 // must be one.
1242 // param seqElementCounts - contains the maximum number of elements for each
1243 // dimension. Index 0 contains the number of dimension one.
1244 // After return the Sequence contains the maximum number of
1245 // elements for each dimension.
1246 // The length of the Sequence must equal the number of dimensions.
1247 // param typeClass - TypeClass of the element type that is no Sequence, e.g.
1248 // Sequence< Sequence <Sequence <sal_Int32> > > - type is sal_Int32)
1249 template<class T>
1250 void UnoConversionUtilities<T>::getElementCountAndTypeOfSequence( const Any& rSeq, sal_Int32 dim,
1251 Sequence< sal_Int32 >& seqElementCounts, TypeDescription& typeDesc)
1253 sal_Int32 dimCount= (*(uno_Sequence* const *) rSeq.getValue())->nElements;
1254 if( dimCount > seqElementCounts[ dim-1])
1255 seqElementCounts[ dim-1]= dimCount;
1257 // we need the element type to construct the any that is
1258 // passed into getElementCountAndTypeOfSequence again
1259 typelib_TypeDescription* pSeqDesc= NULL;
1260 rSeq.getValueTypeDescription( &pSeqDesc);
1261 typelib_TypeDescriptionReference* pElementDescRef= ((typelib_IndirectTypeDescription*)pSeqDesc)->pType;
1263 // if the elements are Sequences than do recursion
1264 if( dim < seqElementCounts.getLength() )
1266 uno_Sequence* pSeq = *(uno_Sequence* const*) rSeq.getValue();
1267 uno_Sequence** arSequences= (uno_Sequence**)pSeq->elements;
1268 for( sal_Int32 i=0; i < dimCount; i++)
1270 uno_Sequence* arElement= arSequences[ i];
1271 getElementCountAndTypeOfSequence( Any( &arElement, pElementDescRef), dim + 1 , seqElementCounts, typeDesc);
1274 else
1276 // determine the element type ( e.g. Sequence< Sequence <Sequence <sal_Int32> > > - type is sal_Int32)
1277 typeDesc= pElementDescRef;
1279 typelib_typedescription_release( pSeqDesc);
1283 template<class T>
1284 SAFEARRAY* UnoConversionUtilities<T>::createUnoSequenceWrapper(const Any& rSeq)
1286 SAFEARRAY* pArray = NULL;
1287 sal_uInt32 n = 0;
1289 if( rSeq.getValueTypeClass() != TypeClass_SEQUENCE )
1290 throw IllegalArgumentException(
1291 "[automation bridge]UnoConversionUtilities<T>::createUnoSequenceWrapper\n"
1292 "The UNO argument is not a sequence", 0, -1);
1294 uno_Sequence * punoSeq= *(uno_Sequence**) rSeq.getValue();
1296 typelib_TypeDescriptionReference* pSeqTypeRef= rSeq.getValueTypeRef();
1297 typelib_TypeDescription* pSeqType= NULL;
1298 TYPELIB_DANGER_GET( &pSeqType, pSeqTypeRef);
1299 typelib_IndirectTypeDescription * pSeqIndDec= (typelib_IndirectTypeDescription*) pSeqType;
1302 typelib_TypeDescriptionReference * pSeqElementTypeRef= pSeqIndDec->pType;
1303 TYPELIB_DANGER_RELEASE( pSeqType);
1305 typelib_TypeDescription* pSeqElementDesc= NULL;
1306 TYPELIB_DANGER_GET( &pSeqElementDesc, pSeqElementTypeRef);
1307 sal_Int32 nElementSize= pSeqElementDesc->nSize;
1308 n= punoSeq->nElements;
1310 SAFEARRAYBOUND rgsabound[1];
1311 rgsabound[0].lLbound = 0;
1312 rgsabound[0].cElements = n;
1313 VARIANT oleElement;
1314 long safeI[1];
1316 pArray = SafeArrayCreate(VT_VARIANT, 1, rgsabound);
1318 Any unoElement;
1319 sal_uInt8 * pSeqData= (sal_uInt8*) punoSeq->elements;
1321 for (sal_uInt32 i = 0; i < n; i++)
1323 unoElement.setValue( pSeqData + i * nElementSize, pSeqElementDesc);
1324 VariantInit(&oleElement);
1326 anyToVariant(&oleElement, unoElement);
1328 safeI[0] = i;
1329 SafeArrayPutElement(pArray, safeI, &oleElement);
1331 VariantClear(&oleElement);
1333 TYPELIB_DANGER_RELEASE( pSeqElementDesc);
1335 return pArray;
1338 /* The argument rObj can contain
1339 - UNO struct
1340 - UNO interface
1341 - UNO interface created by this bridge (adapter factory)
1342 - UNO interface created by this bridge ( COM Wrapper)
1344 pVar must be initialized.
1346 template<class T>
1347 void UnoConversionUtilities<T>::createUnoObjectWrapper(const Any & rObj, VARIANT * pVar)
1349 MutexGuard guard(getBridgeMutex());
1351 Reference<XInterface> xInt;
1353 TypeClass tc = rObj.getValueTypeClass();
1354 if (tc != TypeClass_INTERFACE && tc != TypeClass_STRUCT)
1355 throw IllegalArgumentException(
1356 "[automation bridge]UnoConversionUtilities<T>::createUnoObjectWrapper \n"
1357 "Cannot create an Automation interface for a UNO type which is not "
1358 "a struct or interface!", 0, -1);
1360 if (rObj.getValueTypeClass() == TypeClass_INTERFACE)
1362 if (! (rObj >>= xInt))
1363 throw IllegalArgumentException(
1364 "[automation bridge] UnoConversionUtilities<T>::createUnoObjectWrapper\n "
1365 "Could not create wrapper object for UNO object!", 0, -1);
1366 //If XInterface is NULL, which is a valid value, then simply return NULL.
1367 if ( ! xInt.is())
1369 pVar->vt = VT_UNKNOWN;
1370 pVar->punkVal = NULL;
1371 return;
1373 //make sure we have the main XInterface which is used with a map
1374 xInt = Reference<XInterface>(xInt, UNO_QUERY);
1375 //If there is already a wrapper for the UNO object then use it
1377 Reference<XInterface> xIntWrapper;
1378 // Does a UNO wrapper exist already ?
1379 IT_Uno it_uno = UnoObjToWrapperMap.find( (sal_uInt32) xInt.get());
1380 if(it_uno != UnoObjToWrapperMap.end())
1382 xIntWrapper = it_uno->second;
1383 if (xIntWrapper.is())
1385 convertSelfToCom(xIntWrapper, pVar);
1386 return;
1389 // Is the object a COM wrapper ( either XInvocation, or Adapter object)
1390 // or does it supply an IDispatch by its own ?
1391 else
1393 Reference<XInterface> xIntComWrapper = xInt;
1394 typedef std::unordered_map<sal_uInt32,sal_uInt32>::iterator _IT;
1395 // Adapter? then get the COM wrapper to which the adapter delegates its calls
1396 _IT it= AdapterToWrapperMap.find( (sal_uInt32) xInt.get());
1397 if( it != AdapterToWrapperMap.end() )
1398 xIntComWrapper= reinterpret_cast<XInterface*>(it->second);
1400 if (convertSelfToCom(xIntComWrapper, pVar))
1401 return;
1404 // If we have no UNO wrapper nor the IDispatch yet then we have to create
1405 // a wrapper. For that we need an XInvocation from the UNO object.
1407 // get an XInvocation or create one using the invocation service
1408 Reference<XInvocation> xInv(xInt, UNO_QUERY);
1409 if ( ! xInv.is())
1411 Reference<XSingleServiceFactory> xInvFactory= getInvocationFactory(rObj);
1412 if (xInvFactory.is())
1414 Sequence<Any> params(1);
1415 params.getArray()[0] = rObj;
1416 Reference<XInterface> xInt = xInvFactory->createInstanceWithArguments(params);
1417 xInv= Reference<XInvocation>(xInt, UNO_QUERY);
1421 if (xInv.is())
1423 Reference<XInterface> xNewWrapper = createUnoWrapperInstance();
1424 Reference<XInitialization> xInitWrapper(xNewWrapper, UNO_QUERY);
1425 if (xInitWrapper.is())
1427 VARTYPE vartype= getVarType( rObj);
1429 if (xInt.is())
1431 Any params[3];
1432 params[0] <<= xInv;
1433 params[1] <<= xInt;
1434 params[2] <<= vartype;
1435 xInitWrapper->initialize( Sequence<Any>(params, 3));
1437 else
1439 Any params[2];
1440 params[0] <<= xInv;
1441 params[1] <<= vartype;
1442 xInitWrapper->initialize( Sequence<Any>(params, 2));
1445 // put the newly created object into a map. If the same object will
1446 // be mapped again and there is already a wrapper then the old wrapper
1447 // will be used.
1448 if(xInt.is()) // only interfaces
1449 UnoObjToWrapperMap[(sal_uInt32) xInt.get()]= xNewWrapper;
1450 convertSelfToCom(xNewWrapper, pVar);
1451 return;
1456 template<class T>
1457 void UnoConversionUtilities<T>::variantToAny( const VARIANT* pVariant, Any& rAny,
1458 sal_Bool bReduceValueRange /* = sal_True */)
1460 HRESULT hr = S_OK;
1463 CComVariant var;
1465 // There is no need to support indirect values, since they're not supported by UNO
1466 if( FAILED(hr= VariantCopyInd( &var, const_cast<VARIANTARG*>(pVariant)))) // remove VT_BYREF
1467 throw BridgeRuntimeError(
1468 "[automation bridge] UnoConversionUtilities<T>::variantToAny \n"
1469 "VariantCopyInd failed for reason : " + OUString::number(hr));
1471 if ( ! convertValueObject( & var, rAny))
1473 if ((var.vt & VT_ARRAY) > 0)
1475 VARTYPE oleTypeFlags = ::sal::static_int_cast< VARTYPE, int >( var.vt ^ VT_ARRAY );
1477 Sequence<Any> unoSeq = createOleArrayWrapper(var.parray, oleTypeFlags);
1478 rAny.setValue( &unoSeq, cppu::UnoType<decltype(unoSeq)>::get());
1480 else
1482 switch (var.vt)
1484 case VT_EMPTY:
1485 rAny.setValue(NULL, Type());
1486 break;
1487 case VT_NULL:
1488 rAny.setValue(NULL, Type());
1489 break;
1490 case VT_I2:
1491 rAny.setValue( & var.iVal, cppu::UnoType<sal_Int16>::get());
1492 break;
1493 case VT_I4:
1494 rAny.setValue( & var.lVal, cppu::UnoType<sal_Int32>::get());
1495 // necessary for use in JavaScript ( see "reduceRange")
1496 if( bReduceValueRange)
1497 reduceRange(rAny);
1498 break;
1499 case VT_R4:
1500 rAny.setValue( & var.fltVal, cppu::UnoType<float>::get());
1501 break;
1502 case VT_R8:
1503 rAny.setValue(& var.dblVal, cppu::UnoType<double>::get());
1504 break;
1505 case VT_CY:
1507 Currency cy(var.cyVal.int64);
1508 rAny <<= cy;
1509 break;
1511 case VT_DATE:
1513 Date d(var.date);
1514 rAny <<= d;
1515 break;
1517 case VT_BSTR:
1519 OUString b(reinterpret_cast<const sal_Unicode*>(var.bstrVal));
1520 rAny.setValue( &b, cppu::UnoType<decltype(b)>::get());
1521 break;
1523 case VT_UNKNOWN:
1524 case VT_DISPATCH:
1526 //check if it is a UNO type
1527 #ifdef __MINGW32__
1528 CComQIPtr<IUnoTypeWrapper, &__uuidof(IUnoTypeWrapper)> spType((IUnknown*) var.byref);
1529 #else
1530 CComQIPtr<IUnoTypeWrapper> spType((IUnknown*) var.byref);
1531 #endif
1532 if (spType)
1534 CComBSTR sName;
1535 if (FAILED(spType->get_Name(&sName)))
1536 throw BridgeRuntimeError(
1537 "[automation bridge]UnoConversionUtilities<T>::variantToAny \n"
1538 "Failed to get the type name from a UnoTypeWrapper!");
1539 Type type;
1540 if (getType(sName, type) == false)
1542 throw CannotConvertException(
1543 "[automation bridge]UnoConversionUtilities<T>::variantToAny \n"
1544 "A UNO type with the name: " + OUString(reinterpret_cast<const sal_Unicode*>(LPCOLESTR(sName))) +
1545 "does not exist!",
1546 0, TypeClass_UNKNOWN, FailReason::TYPE_NOT_SUPPORTED,0);
1548 rAny <<= type;
1550 else
1552 rAny = createOleObjectWrapper( & var);
1554 break;
1556 case VT_ERROR:
1558 SCode scode(var.scode);
1559 rAny <<= scode;
1560 break;
1562 case VT_BOOL:
1564 sal_Bool b= var.boolVal == VARIANT_TRUE;
1565 rAny.setValue( &b, cppu::UnoType<decltype(b)>::get());
1566 break;
1568 case VT_I1:
1569 rAny.setValue( & var.cVal, cppu::UnoType<sal_Int8>::get());
1570 break;
1571 case VT_UI1: // there is no unsigned char in UNO
1572 rAny.setValue( & var.bVal, cppu::UnoType<sal_Int8>::get());
1573 break;
1574 case VT_UI2:
1575 rAny.setValue( & var.uiVal, cppu::UnoType<cppu::UnoUnsignedShortType>::get() );
1576 break;
1577 case VT_UI4:
1578 rAny.setValue( & var.ulVal, cppu::UnoType<sal_uInt32>::get());
1579 break;
1580 case VT_INT:
1581 rAny.setValue( & var.intVal, cppu::UnoType<sal_Int32>::get());
1582 break;
1583 case VT_UINT:
1584 rAny.setValue( & var.uintVal, cppu::UnoType<sal_uInt32>::get());
1585 break;
1586 case VT_VOID:
1587 rAny.setValue( NULL, Type());
1588 break;
1589 case VT_DECIMAL:
1591 Decimal dec;
1592 dec.Scale = var.decVal.scale;
1593 dec.Sign = var.decVal.sign;
1594 dec.LowValue = var.decVal.Lo32;
1595 dec.MiddleValue = var.decVal.Mid32;
1596 dec.HighValue = var.decVal.Hi32;
1597 rAny <<= dec;
1598 break;
1601 default:
1602 break;
1607 catch (const IllegalArgumentException &)
1609 throw;
1611 catch (const CannotConvertException &)
1613 throw;
1615 catch (const BridgeRuntimeError &)
1617 throw;
1619 catch (const Exception & e)
1621 throw BridgeRuntimeError("[automation bridge] unexpected exception in "
1622 "UnoConversionUtilities<T>::variantToAny ! Message : \n" +
1623 e.Message);
1625 catch(...)
1627 throw BridgeRuntimeError(
1628 "[automation bridge] unexpected exception in "
1629 "UnoConversionUtilities<T>::variantToAny !");
1633 // The function converts an IUnknown* into an UNO interface or struct. The
1634 // IUnknown pointer can constitute different kind of objects:
1635 // 1. a wrapper of an UNO struct (the wrapper was created by this bridge)
1636 // 2. a wrapper of an UNO interface (created by this bridge)
1637 // 3. a dispatch object that implements UNO interfaces
1638 // 4. a dispatch object.
1640 // If the parameter "aType" has a value then the COM object ( pUnknown) is supposed to
1641 // implement the interface described by "aType". Moreover it ( pUnknown) can implement
1642 // several other
1643 // UNO interfaces in which case it has to support the SUPPORTED_INTERFACES_PROP (see
1644 // #define) property. That property contains all names of interfaces.
1645 // "pUnknown" is wrapped by a COM wrapper object that implements XInvocation, e.g.
1646 // IUnknownWrapper_Impl. Additionally an object of type "aType" is created by help
1647 // of the INTERFACE_ADAPTER_FACTORY (see #define) service. The implementation of
1648 // "aType" calls on the COM wrapper's XInvocation::invoke. If the COM object supports
1649 // more than one UNO interfaces, as can be determined by the property
1650 // SUPPORTED_INTERFACES_PROP, then the INTERFACE_ADAPTER_FACTORY creates an object that
1651 // implements all these interfaces.
1652 // This is only done if "pUnknown" is not already a UNO wrapper,
1653 // that is it is actually NOT an UNO object that was converted to a COM object. If it is an
1654 // UNO wrapper than the original UNO object is being extracted, queried for "aType" (if
1655 // it is no struct) and returned.
1656 template<class T>
1657 #ifdef __MINGW32__
1658 Any UnoConversionUtilities<T>::createOleObjectWrapper(VARIANT* pVar, const Type& aType)
1659 #else
1660 Any UnoConversionUtilities<T>::createOleObjectWrapper(VARIANT* pVar, const Type& aType= Type())
1661 #endif
1663 //To allow passing "Nothing" in VS 2008 we need to accept VT_EMPTY
1664 if (pVar->vt != VT_UNKNOWN && pVar->vt != VT_DISPATCH && pVar->vt != VT_EMPTY)
1665 throw IllegalArgumentException(
1666 "[automation bridge]UnoConversionUtilities<T>::createOleObjectWrapper \n"
1667 "The VARIANT does not contain an object type! ", 0, -1);
1669 MutexGuard guard( getBridgeMutex());
1671 CComPtr<IUnknown> spUnknown;
1672 CComPtr<IDispatch> spDispatch;
1674 if (pVar->vt == VT_UNKNOWN)
1676 spUnknown = pVar->punkVal;
1677 if (spUnknown)
1678 #ifdef __MINGW32__
1679 spUnknown->QueryInterface( IID_IDispatch, reinterpret_cast<LPVOID*>( & spDispatch.p));
1680 #else
1681 spUnknown.QueryInterface( & spDispatch.p);
1682 #endif
1684 else if (pVar->vt == VT_DISPATCH && pVar->pdispVal != NULL)
1686 CComPtr<IDispatch> spDispatch(pVar->pdispVal);
1687 if (spDispatch)
1688 #ifdef __MINGW32__
1689 spDispatch->QueryInterface( IID_IUnknown, reinterpret_cast<LPVOID*>( & spUnknown.p));
1690 #else
1691 spDispatch.QueryInterface( & spUnknown.p);
1692 #endif
1695 static Type VOID_TYPE= Type();
1696 Any ret;
1697 //If no Type is provided and pVar contains IUnknown then we return a XInterface.
1698 //If pVar contains an IDispatch then we return a XInvocation.
1699 Type desiredType = aType;
1701 if (aType == VOID_TYPE)
1703 switch (pVar->vt)
1705 case VT_EMPTY:
1706 case VT_UNKNOWN:
1707 desiredType = cppu::UnoType<XInterface>::get();
1708 break;
1709 case VT_DISPATCH:
1710 desiredType = cppu::UnoType<XInvocation>::get();
1711 break;
1712 default:
1713 desiredType = aType;
1717 // COM pointer are NULL, no wrapper required
1718 if (spUnknown == NULL)
1720 Reference<XInterface> xInt;
1721 if( aType.getTypeClass() == TypeClass_INTERFACE)
1722 ret.setValue( &xInt, aType);
1723 else if( aType.getTypeClass() == TypeClass_STRUCT)
1724 ret.setValue( NULL, aType);
1725 else
1726 ret <<= xInt;
1727 return ret;
1731 // Check if "spUnknown" is a UNO wrapper, that is an UNO object that has been
1732 // passed to COM. Then it supports IUnoObjectWrapper
1733 // and we extract the original UNO object.
1734 #ifdef __MINGW32__
1735 CComQIPtr<IUnoObjectWrapper, &__uuidof(IUnoObjectWrapper)> spUno( spUnknown);
1736 #else
1737 CComQIPtr<IUnoObjectWrapper> spUno( spUnknown);
1738 #endif
1739 if( spUno)
1740 { // it is a wrapper
1741 Reference<XInterface> xInt;
1742 if( SUCCEEDED( spUno->getOriginalUnoObject( &xInt)))
1744 ret <<= xInt;
1746 else
1748 Any any;
1749 if( SUCCEEDED( spUno->getOriginalUnoStruct(&any)))
1750 ret= any;
1752 return ret;
1755 // "spUnknown" is a real COM object.
1756 // Before we create a new wrapper object we check if there is an existing wrapper
1757 // There can be two kinds of wrappers, those who wrap dispatch - UNO objects, and those who
1758 // wrap ordinary dispatch objects. The dispatch-UNO objects usually are adapted to represent
1759 // particular UNO interfaces.
1760 Reference<XInterface> xIntWrapper;
1761 CIT_Com cit_currWrapper= ComPtrToWrapperMap.find( reinterpret_cast<sal_uInt32>(spUnknown.p));
1762 if(cit_currWrapper != ComPtrToWrapperMap.end())
1763 xIntWrapper = cit_currWrapper->second;
1764 if (xIntWrapper.is())
1766 //Try to find an adapter for the wrapper
1767 //find the proper Adapter. The pointer in the WrapperToAdapterMap are valid as long as
1768 //we get a pointer to the wrapper from ComPtrToWrapperMap, because the Adapter hold references
1769 //to the wrapper.
1770 CIT_Wrap it = WrapperToAdapterMap.find((sal_uInt32) xIntWrapper.get());
1771 if (it == WrapperToAdapterMap.end())
1773 // No adapter available.
1774 //The COM component could be a UNO object. Then we need to provide
1775 // a proxy that implements all interfaces
1776 Sequence<Type> seqTypes= getImplementedInterfaces(spUnknown);
1777 Reference<XInterface> xIntAdapter;
1778 if (seqTypes.getLength() > 0)
1780 //It is a COM UNO object
1781 xIntAdapter = createAdapter(seqTypes, xIntWrapper);
1783 else
1785 // Some ordinary COM object
1786 xIntAdapter = xIntWrapper;
1788 // return the wrapper directly, return XInterface or XInvocation
1789 ret = xIntWrapper->queryInterface(desiredType);
1790 if ( ! ret.hasValue())
1791 throw IllegalArgumentException(
1792 "[automation bridge]UnoConversionUtilities<T>::createOleObjectWrapper \n"
1793 "The COM object is not suitable for the UNO type: " +
1794 desiredType.getTypeName(), 0, -1);
1796 else
1798 //There is an adapter available
1799 Reference<XInterface> xIntAdapter((XInterface*) it->second);
1800 ret = xIntAdapter->queryInterface( desiredType);
1801 if ( ! ret.hasValue())
1802 throw IllegalArgumentException(
1803 "[automation bridge]UnoConversionUtilities<T>::createOleObjectWrapper \n"
1804 "The COM object is not suitable for the UNO type: " +
1805 desiredType.getTypeName(), 0, -1);
1808 return ret;
1810 // No existing wrapper. Therefore create a new proxy.
1811 // If the object implements UNO interfaces then get the types.
1812 Sequence<Type> seqTypes = getImplementedInterfaces(spUnknown);
1813 if (seqTypes.getLength() == 0 &&
1814 aType != VOID_TYPE && aType != cppu::UnoType<XInvocation>::get())
1816 seqTypes = Sequence<Type>( & aType, 1);
1819 //There is no existing wrapper, therefore we create one for the real COM object
1820 Reference<XInterface> xIntNewProxy= createComWrapperInstance();
1821 if ( ! xIntNewProxy.is())
1822 throw BridgeRuntimeError(
1823 "[automation bridge]UnoConversionUtilities<T>::createOleObjectWrapper \n"
1824 "Could not create proxy object for COM object!");
1826 // initialize the COM wrapper
1827 Reference<XInitialization> xInit( xIntNewProxy, UNO_QUERY);
1828 OSL_ASSERT( xInit.is());
1830 Any params[3];
1831 #ifdef __MINGW32__
1832 params[0] <<= reinterpret_cast<sal_uInt32>( spUnknown.p );
1833 #else
1834 params[0] <<= reinterpret_cast<sal_uIntPtr>(spUnknown.p);
1835 #endif
1836 sal_Bool bDisp = pVar->vt == VT_DISPATCH ? sal_True : sal_False;
1837 params[1].setValue( & bDisp, cppu::UnoType<bool>::get());
1838 params[2] <<= seqTypes;
1840 xInit->initialize( Sequence<Any>( params, 3));
1841 #ifdef __MINGW32__
1842 ComPtrToWrapperMap[reinterpret_cast<sal_uInt32>( spUnknown.p )]= xIntNewProxy;
1843 #else
1844 ComPtrToWrapperMap[reinterpret_cast<sal_uInt32>(spUnknown.p)]= xIntNewProxy;
1845 #endif
1847 // we have a wrapper object
1848 //The wrapper implements already XInvocation and XInterface. If
1849 //param aType is void then the object is supposed to have XInvocation.
1850 if (aType == cppu::UnoType<XInvocation>::get()||
1851 (aType == VOID_TYPE && seqTypes.getLength() == 0 ))
1853 ret = xIntNewProxy->queryInterface(desiredType);
1855 else
1857 Reference<XInterface> xIntAdapter =
1858 createAdapter(seqTypes, xIntNewProxy);
1859 ret = xIntAdapter->queryInterface(desiredType);
1861 return ret;
1863 template<class T>
1864 Reference<XInterface> UnoConversionUtilities<T>::createAdapter(const Sequence<Type>& seqTypes,
1865 const Reference<XInterface>& receiver)
1867 Reference< XInterface> xIntAdapterFac;
1868 xIntAdapterFac= m_smgr->createInstance(INTERFACE_ADAPTER_FACTORY);
1869 // We create an adapter object that does not only implement the required type but also
1870 // all types that the COM object pretends to implement. An COM object must therefore
1871 // support the property "_implementedInterfaces".
1872 Reference<XInterface> xIntAdapted;
1873 Reference<XInvocation> xInv(receiver, UNO_QUERY);
1874 Reference<XInvocationAdapterFactory2> xAdapterFac( xIntAdapterFac, UNO_QUERY);
1875 if( xAdapterFac.is())
1876 xIntAdapted= xAdapterFac->createAdapter( xInv, seqTypes);
1878 if( xIntAdapted.is())
1880 // Put the pointer to the wrapper object and the interface pointer of the adapted interface
1881 // in a global map. Thus we can determine in a call to createUnoObjectWrapper whether the UNO
1882 // object is a wrapped COM object. In that case we extract the original COM object rather than
1883 // creating a wrapper around the UNO object.
1884 typedef std::unordered_map<sal_uInt32,sal_uInt32>::value_type VALUE;
1885 AdapterToWrapperMap.insert( VALUE( (sal_uInt32) xIntAdapted.get(), (sal_uInt32) receiver.get()));
1886 WrapperToAdapterMap.insert( VALUE( (sal_uInt32) receiver.get(), (sal_uInt32) xIntAdapted.get()));
1888 else
1890 throw BridgeRuntimeError(
1891 "[automation bridge]UnoConversionUtilities<T>::createOleObjectWrapper \n"
1892 "Could not create a proxy for COM object! Creation of adapter failed.");
1894 return xIntAdapted;
1896 // "convertValueObject" converts a JScriptValue object contained in "var" into
1897 // an any. The type contained in the any is stipulated by a "type value" thas
1898 // was set within the JScript script on the value object ( see JScriptValue).
1899 template<class T>
1900 bool UnoConversionUtilities<T>::convertValueObject( const VARIANTARG *var, Any& any)
1902 bool ret = false;
1905 bool bFail = false;
1906 HRESULT hr= S_OK;
1907 CComVariant varDisp;
1909 if(SUCCEEDED(hr = varDisp.ChangeType( VT_DISPATCH, var)))
1911 CComPtr <IJScriptValueObject> spValue;
1912 VARIANT_BOOL varBool;
1913 CComBSTR bstrType;
1914 CComVariant varValue;
1915 CComPtr<IDispatch> spDisp( varDisp.pdispVal);
1916 if(spDisp)
1918 if(SUCCEEDED( spDisp->QueryInterface( __uuidof( IJScriptValueObject),
1919 reinterpret_cast<void**> (&spValue))))
1921 ret = true; // is a ValueObject
1922 //If it is an out - param then it does not need to be converted. In/out and
1923 // in params does so.
1924 if (SUCCEEDED(hr= spValue->IsOutParam( &varBool)))
1926 // if varBool == true then no conversion needed because out param
1927 if (varBool == VARIANT_FALSE)
1929 if(SUCCEEDED(hr = spValue->GetValue( & bstrType, & varValue)))
1931 Type type;
1932 if (getType(bstrType, type))
1933 variantToAny( & varValue, any, type);
1934 else
1935 bFail = true;
1937 else
1938 bFail = true;
1941 else
1942 bFail = true;
1946 else if( hr != DISP_E_TYPEMISMATCH && hr != E_NOINTERFACE)
1947 bFail = true;
1949 if (bFail)
1950 throw BridgeRuntimeError(
1951 "[automation bridge] Conversion of ValueObject failed ");
1953 catch (const BridgeRuntimeError &)
1955 throw;
1957 catch (const Exception & e)
1959 throw BridgeRuntimeError("[automation bridge] unexpected exception in "
1960 "UnoConversionUtilities<T>::convertValueObject ! Message : \n" +
1961 e.Message);
1963 catch(...)
1965 throw BridgeRuntimeError(
1966 "[automation bridge] unexpected exception in "
1967 "UnoConversionUtilities<T>::convertValueObject !");
1969 return ret;
1972 template<class T>
1973 void UnoConversionUtilities<T>::dispatchExObject2Sequence( const VARIANTARG* pvar, Any& anySeq, const Type& type)
1977 bool bFail = false;
1978 if( pvar->vt != VT_DISPATCH)
1979 throw BridgeRuntimeError("[automation bridge] UnoConversionUtilities<T>::dispatchExObject2Sequence \n"
1980 "Conversion of dispatch object to Sequence failed!");
1981 IDispatchEx* pdispEx;
1982 HRESULT hr;
1983 if( FAILED( hr= pvar->pdispVal->QueryInterface( IID_IDispatchEx,
1984 reinterpret_cast<void**>( &pdispEx))))
1985 throw BridgeRuntimeError("[automation bridge] UnoConversionUtilities<T>::dispatchExObject2Sequence \n"
1986 "Conversion of dispatch object to Sequence failed!");
1988 DISPID dispid;
1989 OUString sindex;
1990 DISPPARAMS param= {0,0,0,0};
1991 CComVariant result;
1993 OLECHAR* sLength= L"length";
1995 // Get the length of the array. Can also be obtained throu GetNextDispID. The
1996 // method only returns DISPIDs of the array data. Their names are like "0", "1" etc.
1997 if( FAILED( hr= pdispEx->GetIDsOfNames(IID_NULL, &sLength , 1, LOCALE_USER_DEFAULT, &dispid)))
1998 throw BridgeRuntimeError("[automation bridge] UnoConversionUtilities<T>::dispatchExObject2Sequence \n"
1999 "Conversion of dispatch object to Sequence failed!");
2000 if( FAILED( hr= pdispEx->InvokeEx(dispid, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET,
2001 &param, &result, NULL, NULL)))
2002 throw BridgeRuntimeError("[automation bridge] UnoConversionUtilities<T>::dispatchExObject2Sequence \n"
2003 "Conversion of dispatch object to Sequence failed!");
2004 if( FAILED( VariantChangeType( &result, &result, 0, VT_I4)))
2005 throw BridgeRuntimeError("[automation bridge] UnoConversionUtilities<T>::dispatchExObject2Sequence \n"
2006 "Conversion of dispatch object to Sequence failed!");
2007 long length= result.lVal;
2009 result.Clear();
2011 // get a few basic facts about the sequence, and reallocate:
2012 // create the Sequences
2013 // get the size of the elements
2014 typelib_TypeDescription *pDesc= NULL;
2015 type.getDescription( &pDesc);
2017 typelib_IndirectTypeDescription *pSeqDesc= reinterpret_cast<typelib_IndirectTypeDescription*>(pDesc);
2018 typelib_TypeDescriptionReference *pSeqElemDescRef= pSeqDesc->pType; // type of the Sequence' elements
2019 Type elemType( pSeqElemDescRef);
2020 _typelib_TypeDescription* pSeqElemDesc=NULL;
2021 TYPELIB_DANGER_GET( &pSeqElemDesc, pSeqElemDescRef);
2022 sal_uInt32 nelementSize= pSeqElemDesc->nSize;
2023 TYPELIB_DANGER_RELEASE( pSeqElemDesc);
2025 uno_Sequence *p_uno_Seq;
2026 uno_sequence_construct( &p_uno_Seq, pDesc, NULL, length, cpp_acquire);
2028 typelib_TypeClass typeElement= pSeqDesc->pType->eTypeClass;
2029 char *pArray= p_uno_Seq->elements;
2031 // Get All properties in the object, convert their values to the expected type and
2032 // put them into the passed in sequence
2033 for( sal_Int32 i= 0; i< length; i++)
2035 OUString ousIndex=OUString::number( i);
2036 OLECHAR* sindex = (OLECHAR*)ousIndex.getStr();
2038 if( FAILED( hr= pdispEx->GetIDsOfNames(IID_NULL, &sindex , 1, LOCALE_USER_DEFAULT, &dispid)))
2040 throw BridgeRuntimeError("[automation bridge] UnoConversionUtilities<T>::dispatchExObject2Sequence \n"
2041 "Conversion of dispatch object to Sequence failed!");
2043 if( FAILED( hr= pdispEx->InvokeEx(dispid, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET,
2044 &param, &result, NULL, NULL)))
2046 throw BridgeRuntimeError("[automation bridge] UnoConversionUtilities<T>::dispatchExObject2Sequence \n"
2047 "Conversion of dispatch object to Sequence failed!");
2050 // If the result is VT_DISPATCH than the Sequence's element type could be Sequence
2051 // Look that up in the CoreReflection to make clear.
2052 // That requires a recursiv conversion
2053 Any any;
2054 // Destination address within the out-Sequence "anySeq" where to copy the next converted element
2055 void* pDest= (void*)(pArray + (i * nelementSize));
2057 if( result.vt & VT_DISPATCH && typeElement == typelib_TypeClass_SEQUENCE)
2059 variantToAny( &result, any, elemType, sal_False);
2060 // copy the converted VARIANT, that is a Sequence to the Sequence
2061 uno_Sequence * p_unoSeq= *(uno_Sequence**)any.getValue();
2062 // just copy the pointer of the uno_Sequence
2063 // nelementSize should be 4 !!!!
2064 memcpy( pDest, &p_unoSeq, nelementSize);
2065 osl_atomic_increment( &p_unoSeq->nRefCount);
2067 else // Element type is no Sequence -> do one conversion
2069 variantToAny( &result, any, elemType, sal_False);
2070 if( typeElement == typelib_TypeClass_ANY)
2072 // copy the converted VARIANT to the Sequence
2073 uno_type_assignData( pDest, pSeqElemDescRef , &any, pSeqElemDescRef,cpp_queryInterface,
2074 cpp_acquire, cpp_release);
2076 else
2078 // type after conversion must be the element type of the sequence
2079 OSL_ENSURE( (any.getValueTypeClass() == typeElement), "wrong conversion");
2080 uno_type_assignData( pDest, pSeqElemDescRef,const_cast<void*>( any.getValue()), any.getValueTypeRef(),
2081 cpp_queryInterface, cpp_acquire, cpp_release);
2084 } // else
2085 result.Clear();
2086 anySeq.setValue( &p_uno_Seq, pDesc);
2087 uno_destructData( &p_uno_Seq, pDesc, cpp_release);
2088 typelib_typedescription_release( pDesc);
2090 if (bFail)
2091 throw BridgeRuntimeError(
2092 "[automation bridge] Conversion of ValueObject failed ");
2094 catch (const BridgeRuntimeError &)
2096 throw;
2098 catch (const Exception & e)
2100 throw BridgeRuntimeError("[automation bridge] unexpected exception in "
2101 "UnoConversionUtilities<T>::convertValueObject ! Message : \n" +
2102 e.Message);
2104 catch(...)
2106 throw BridgeRuntimeError(
2107 "[automation bridge] unexpected exception in "
2108 "UnoConversionUtilities<T>::convertValueObject !");
2112 /* The argument unotype is the type that is expected by the currently called UNO function.
2113 For example: []long, [][]long. If the function calls itself recursively then the element type
2114 is passed on. For example a two dimensional SAFEARRAY of type VT_I4 is to be converted. Then
2115 unotype has to be either void or [][]long. When the function calls itself recursivly then
2116 it passes the element type which is []long.
2118 template<class T>
2119 Sequence<Any> UnoConversionUtilities<T>::createOleArrayWrapperOfDim(SAFEARRAY* pArray,
2120 unsigned int dimCount, unsigned int actDim, long* index, VARTYPE type, const Type& unotype)
2122 HRESULT hr= S_OK;
2123 long lBound;
2124 long uBound;
2125 long nCountElements;
2127 SafeArrayGetLBound(pArray, actDim, &lBound);
2128 SafeArrayGetUBound(pArray, actDim, &uBound);
2129 nCountElements= uBound - lBound +1;
2131 Sequence<Any> anySeq(nCountElements);
2132 Any* pUnoArray = anySeq.getArray();
2134 for (index[actDim - 1] = lBound; index[actDim - 1] <= uBound; index[actDim - 1]++)
2136 if (actDim > 1 )
2138 Sequence<Any> element = createOleArrayWrapperOfDim(pArray, dimCount,
2139 actDim - 1, index, type, getElementTypeOfSequence(unotype));
2141 pUnoArray[index[actDim - 1] - lBound].setValue(&element, cppu::UnoType<decltype(element)>::get());
2143 else
2145 VARIANT variant;
2147 VariantInit(&variant);
2149 V_VT(&variant) = type;
2151 switch (type)
2153 case VT_I2:
2154 SafeArrayGetElement(pArray, index, &V_I2(&variant));
2155 break;
2156 case VT_I4:
2157 SafeArrayGetElement(pArray, index, &V_I4(&variant));
2158 break;
2159 case VT_R4:
2160 SafeArrayGetElement(pArray, index, &V_R4(&variant));
2161 break;
2162 case VT_R8:
2163 SafeArrayGetElement(pArray, index, &V_R8(&variant));
2164 break;
2165 case VT_CY:
2166 SafeArrayGetElement(pArray, index, &V_CY(&variant));
2167 break;
2168 case VT_DATE:
2169 SafeArrayGetElement(pArray, index, &V_DATE(&variant));
2170 break;
2171 case VT_BSTR:
2172 hr= SafeArrayGetElement(pArray, index, &V_BSTR(&variant));
2173 break;
2174 case VT_DISPATCH:
2175 SafeArrayGetElement(pArray, index, &V_DISPATCH(&variant));
2176 break;
2177 case VT_ERROR:
2178 SafeArrayGetElement(pArray, index, &V_ERROR(&variant));
2179 break;
2180 case VT_BOOL:
2181 SafeArrayGetElement(pArray, index, &V_BOOL(&variant));
2182 break;
2183 case VT_VARIANT:
2184 SafeArrayGetElement(pArray, index, &variant);
2185 break;
2186 case VT_UNKNOWN:
2187 SafeArrayGetElement(pArray, index, &V_UNKNOWN(&variant));
2188 break;
2189 case VT_I1:
2190 SafeArrayGetElement(pArray, index, &V_I1(&variant));
2191 break;
2192 case VT_UI1:
2193 SafeArrayGetElement(pArray, index, &V_UI1(&variant));
2194 break;
2195 case VT_UI2:
2196 SafeArrayGetElement(pArray, index, &V_UI2(&variant));
2197 break;
2198 case VT_UI4:
2199 SafeArrayGetElement(pArray, index, &V_UI4(&variant));
2200 break;
2201 default:
2202 break;
2205 if( unotype.getTypeClass() == TypeClass_VOID)
2206 // the function was called without specifying the destination type
2207 variantToAny(&variant, pUnoArray[index[actDim - 1] - lBound], sal_False);
2208 else
2209 variantToAny(&variant, pUnoArray[index[actDim - 1] - lBound],
2210 getElementTypeOfSequence(unotype), sal_False);
2212 VariantClear(&variant);
2215 return anySeq;
2218 template<class T>
2219 Type UnoConversionUtilities<T>::getElementTypeOfSequence( const Type& seqType)
2221 Type retValue;
2222 if( seqType.getTypeClass() != TypeClass_VOID)
2224 OSL_ASSERT( seqType.getTypeClass() == TypeClass_SEQUENCE);
2225 typelib_IndirectTypeDescription* pDescSeq= NULL;
2226 seqType.getDescription((typelib_TypeDescription** ) & pDescSeq);
2227 retValue = Type(pDescSeq->pType);
2228 typelib_typedescription_release( (typelib_TypeDescription*) pDescSeq);
2230 return retValue;
2232 template<class T>
2233 Sequence<Any> UnoConversionUtilities<T>::createOleArrayWrapper(SAFEARRAY* pArray, VARTYPE type, const Type& unoType)
2235 sal_uInt32 dim = SafeArrayGetDim(pArray);
2237 Sequence<Any> ret;
2239 if (dim > 0)
2241 scoped_array<long> sarIndex(new long[dim]);
2242 long * index = sarIndex.get();
2244 for (unsigned int i = 0; i < dim; i++)
2246 index[i] = 0;
2249 ret = createOleArrayWrapperOfDim(pArray, dim, dim, index, type, unoType);
2252 return ret;
2255 // If an VARIANT has the type VT_DISPATCH it can either be an JScript Array
2256 // or some other object. This function finds out if it is such an array or
2257 // not. Currently there's no way to make sure it's an array
2258 // so we assume that when the object has a property "0" then it is an Array.
2259 // An JScript has property like "0", "1", "2" etc. which represent the
2260 // value at the corresponding index of the array
2261 template<class T>
2262 sal_Bool UnoConversionUtilities<T>::isJScriptArray(const VARIANT* rvar)
2264 OSL_ENSURE( rvar->vt == VT_DISPATCH, "param is not a VT_DISPATCH");
2265 HRESULT hr;
2266 OLECHAR* sindex= L"0";
2267 DISPID id;
2268 if ( rvar->vt == VT_DISPATCH && rvar->pdispVal )
2270 hr= rvar->pdispVal->GetIDsOfNames( IID_NULL, &sindex, 1,
2271 LOCALE_USER_DEFAULT, &id);
2273 if( SUCCEEDED ( hr) )
2274 return sal_True;
2277 return sal_False;
2280 template<class T>
2281 VARTYPE UnoConversionUtilities<T>::mapTypeClassToVartype( TypeClass type)
2283 VARTYPE ret;
2284 switch( type)
2286 case TypeClass_INTERFACE: ret= VT_DISPATCH;
2287 break;
2288 case TypeClass_STRUCT: ret= VT_DISPATCH;
2289 break;
2290 case TypeClass_ENUM: ret= VT_I4;
2291 break;
2292 case TypeClass_SEQUENCE: ret= VT_ARRAY;
2293 break;
2294 case TypeClass_ANY: ret= VT_VARIANT;
2295 break;
2296 case TypeClass_BOOLEAN: ret= VT_BOOL;
2297 break;
2298 case TypeClass_CHAR: ret= VT_I2;
2299 break;
2300 case TypeClass_STRING: ret= VT_BSTR;
2301 break;
2302 case TypeClass_FLOAT: ret= VT_R4;
2303 break;
2304 case TypeClass_DOUBLE: ret= VT_R8;
2305 break;
2306 case TypeClass_BYTE: ret= VT_UI1;
2307 break;
2308 case TypeClass_SHORT: ret= VT_I2;
2309 break;
2310 case TypeClass_LONG: ret= VT_I4;
2311 break;
2312 case TypeClass_UNSIGNED_SHORT: ret= VT_UI2;
2313 break;
2314 case TypeClass_UNSIGNED_LONG: ret= VT_UI4;
2315 break;
2316 default:
2317 ret= VT_EMPTY;
2319 return ret;
2322 template<class T>
2323 Sequence<Type> UnoConversionUtilities<T>::getImplementedInterfaces(IUnknown* pUnk)
2325 Sequence<Type> seqTypes;
2326 CComDispatchDriver disp( pUnk);
2327 if( disp)
2329 CComVariant var;
2330 HRESULT hr= S_OK;
2331 // There are two different property names possible.
2332 if( FAILED( hr= disp.GetPropertyByName( SUPPORTED_INTERFACES_PROP, &var)))
2334 hr= disp.GetPropertyByName( SUPPORTED_INTERFACES_PROP2, &var);
2336 if (SUCCEEDED( hr))
2338 // we exspect an array( SafeArray or IDispatch) of Strings.
2339 Any anyNames;
2340 variantToAny( &var, anyNames, cppu::UnoType<Sequence<Any>>::get());
2341 Sequence<Any> seqAny;
2342 if( anyNames >>= seqAny)
2344 seqTypes.realloc( seqAny.getLength());
2345 for( sal_Int32 i=0; i < seqAny.getLength(); i++)
2347 OUString typeName;
2348 seqAny[i] >>= typeName;
2349 seqTypes[i]= Type( TypeClass_INTERFACE, typeName);
2354 return seqTypes;
2356 template<class T>
2357 Reference<XTypeConverter> UnoConversionUtilities<T>::getTypeConverter()
2359 if ( ! m_typeConverter.is())
2361 MutexGuard guard(getBridgeMutex());
2362 if ( ! m_typeConverter.is())
2364 Reference<XInterface> xIntConverter =
2365 m_smgr->createInstance("com.sun.star.script.Converter");
2366 if (xIntConverter.is())
2367 m_typeConverter = Reference<XTypeConverter>(xIntConverter, UNO_QUERY);
2370 return m_typeConverter;
2373 // This function tries to the change the type of a value (contained in the Any)
2374 // to the smallest possible that can hold the value. This is actually done only
2375 // for types of VT_I4 (see o2u_variantToAny). The reason is the following:
2376 // JavaScript passes integer values always as VT_I4. If there is a parameter or
2377 // property of type any then the bridge converts the any's content according
2378 // to "o2u_variantToAny". Because the VARTYPE is VT_I4 the value would be converted
2379 // to TypeClass_LONG. Say the method XPropertySet::setPropertyValue( string name, any value)
2380 // would be called on an object and the property actually is of TypeClass_SHORT.
2381 // After conversion of the VARIANT parameter the Any would contain type
2382 // TypeClass_LONG. Because the corereflection does not cast from long to short
2383 // the "setPropertValue" would fail as the value has not the right type.
2385 // The corereflection does convert small integer types to bigger types.
2386 // Therefore we can reduce the type if possible and avoid the above mentioned
2387 // problem.
2389 // The function is not used when elements are to be converted for Sequences.
2391 #ifndef _REDUCE_RANGE
2392 #define _REDUCE_RANGE
2393 inline void reduceRange( Any& any)
2395 OSL_ASSERT( any.getValueTypeClass() == TypeClass_LONG);
2397 sal_Int32 value= *(sal_Int32*)any.getValue();
2398 if( value <= 0x7f && value >= -0x80)
2399 {// -128 bis 127
2400 sal_Int8 charVal= static_cast<sal_Int8>( value);
2401 any.setValue( &charVal, cppu::UnoType<sal_Int8>::get());
2403 else if( value <= 0x7fff && value >= -0x8000)
2404 {// -32768 bis 32767
2405 sal_Int16 shortVal= static_cast<sal_Int16>( value);
2406 any.setValue( &shortVal, cppu::UnoType<sal_Int16>::get());
2409 #endif
2413 } // end namespace
2414 #endif
2416 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */