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