Update ooo320-m1
[ooovba.git] / extensions / source / ole / unoconversionutilities.hxx
blob0e9a98a80343f87b698115ce2c10c68263b6fca8
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: unoconversionutilities.hxx,v $
10 * $Revision: 1.22 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
30 #ifndef _UNO_CONVERSION_UTILITIES
31 #define _UNO_CONVERSION_UTILITIES
33 #include "boost/scoped_array.hpp"
34 #include "com/sun/star/script/XInvocationAdapterFactory.hpp"
35 #include "com/sun/star/script/XInvocationAdapterFactory2.hpp"
36 #include "com/sun/star/script/XTypeConverter.hpp"
37 #include "com/sun/star/script/FailReason.hpp"
38 #include "com/sun/star/bridge/oleautomation/Date.hpp"
39 #include "com/sun/star/bridge/oleautomation/Currency.hpp"
40 #include "com/sun/star/bridge/oleautomation/SCode.hpp"
41 #include "com/sun/star/bridge/oleautomation/Decimal.hpp"
42 #include "typelib/typedescription.hxx"
43 #include "ole2uno.hxx"
45 #include "unotypewrapper.hxx"
46 #include <hash_map>
48 // for some reason DECIMAL_NEG (wtypes.h) which contains BYTE is not resolved.
49 typedef unsigned char BYTE;
50 // classes for wrapping uno objects
51 #define INTERFACE_OLE_WRAPPER_IMPL 1
52 #define UNO_OBJECT_WRAPPER_REMOTE_OPT 2
54 #define INVOCATION_SERVICE reinterpret_cast<const sal_Unicode*>(L"com.sun.star.script.Invocation")
57 // classes for wrapping ole objects
58 #define IUNKNOWN_WRAPPER_IMPL 1
60 #define INTERFACE_ADAPTER_FACTORY reinterpret_cast<const sal_Unicode*>(L"com.sun.star.script.InvocationAdapterFactory")
61 // COM or JScript objects implementing UNO interfaces have to implement this property
62 #define SUPPORTED_INTERFACES_PROP L"_implementedInterfaces"
63 // Second property without leading underscore for use in VB
64 #define SUPPORTED_INTERFACES_PROP2 L"Bridge_ImplementedInterfaces"
66 using namespace com::sun::star::script;
67 using namespace com::sun::star::beans;
68 using namespace com::sun::star::uno;
69 #ifdef __MINGW32__
70 using namespace com::sun::star::bridge;
71 using namespace com::sun::star::bridge::ModelDependent;
72 #endif
73 using namespace com::sun::star::bridge::oleautomation;
74 using namespace boost;
75 namespace ole_adapter
77 extern hash_map<sal_uInt32, sal_uInt32> AdapterToWrapperMap;
78 extern hash_map<sal_uInt32, sal_uInt32> WrapperToAdapterMap;
79 typedef hash_map<sal_uInt32, sal_uInt32>::iterator IT_Wrap;
80 typedef hash_map<sal_uInt32, sal_uInt32>::iterator CIT_Wrap;
81 //Maps IUnknown pointers to a weak reference of the respective wrapper class (e.g.
82 // IUnknownWrapperImpl. It is the responsibility of the wrapper to remove the entry when
83 // it is being destroyed.
84 // Used to ensure that an Automation object is always mapped to the same UNO objects.
85 extern hash_map<sal_uInt32, WeakReference<XInterface> > ComPtrToWrapperMap;
86 typedef hash_map<sal_uInt32, WeakReference<XInterface> >::iterator IT_Com;
87 typedef hash_map<sal_uInt32, WeakReference<XInterface> >::const_iterator CIT_Com;
89 // Maps XInterface pointers to a weak reference of its wrapper class (i.e.
90 // InterfaceOleWrapper_Impl). It is the responsibility of the wrapper to remove the entry when
91 // it is being destroyed. It is used to ensure the identity of objects. That is, an UNO interface
92 // is mapped to IDispatch which is kept alive in the COM environment. If the same
93 // UNO interface is mapped again to COM then the IDispach of the first mapped instance
94 // must be returned.
95 extern hash_map<sal_uInt32, WeakReference<XInterface> > UnoObjToWrapperMap;
96 typedef hash_map<sal_uInt32, WeakReference<XInterface> >::iterator IT_Uno;
97 typedef hash_map<sal_uInt32, WeakReference<XInterface> >::const_iterator CIT_Uno;
98 #ifdef __MINGW32__
99 inline void reduceRange( Any& any);
100 #endif
105 // createUnoObjectWrapper gets a wrapper instance by calling createUnoWrapperInstance
106 // and initializes it via XInitialization. The wrapper object is required to implement
107 // XBridgeSupplier so that it can convert itself to IDispatch.
108 // class T: Deriving class ( must implement XInterface )
109 /** All methods are allowed to throw at least a BridgeRuntimeError.
111 template< class >
112 class UnoConversionUtilities
114 public:
115 UnoConversionUtilities( const Reference<XMultiServiceFactory> & smgr):
116 m_nUnoWrapperClass( INTERFACE_OLE_WRAPPER_IMPL),
117 m_nComWrapperClass( IUNKNOWN_WRAPPER_IMPL),
118 m_smgr( smgr)
121 UnoConversionUtilities( const Reference<XMultiServiceFactory> & xFactory, sal_uInt8 unoWrapperClass, sal_uInt8 comWrapperClass )
122 : m_smgr( xFactory), m_nComWrapperClass( comWrapperClass), m_nUnoWrapperClass( unoWrapperClass)
125 virtual ~UnoConversionUtilities() {}
126 /** converts only into oleautomation types, that is there is no VT_I1, VT_UI2, VT_UI4
127 a sal_Unicode character is converted into a BSTR.
128 @exception com.sun.star.lang.IllegalArgumentException
129 If the any was inappropriate for conversion.
130 @exception com.sun.star.script.CannotConvertException
131 The any contains a type class for which no conversion is provided.
133 void anyToVariant(VARIANT* pVariant, const Any& rAny);
134 void anyToVariant(VARIANT* pVariant, const Any& rAny, VARTYPE type);
136 /** @exception com.sun.star.lang.IllegalArgumentException
137 If rSeq does not contain a sequence then the exception is thrown.
139 SAFEARRAY* createUnoSequenceWrapper(const Any& rSeq);
140 /** @exception com.sun.star.lang.IllegalArgumentException
141 If rSeq does not contain a sequence or elemtype has no proper value
142 then the exception is thrown.
144 SAFEARRAY* createUnoSequenceWrapper(const Any& rSeq, VARTYPE elemtype);
146 @exception com.sun.star.lang.IllegalArgumentException
147 If rObj does not contain a struct or interface
149 void createUnoObjectWrapper(const Any & rObj, VARIANT * pVar);
150 /** @exception CannotConvertException
151 Thrown if the VARIANT contains a type that cannot be coerced in the expected Any.
152 ArgumentIndex is 0.
153 @IllegalArgumentException
154 Thrown if the VARIANT is inappropriate for conversion. ArgumentPosition is -1,
156 void variantToAny(const VARIANT* pVariant, Any& rAny, sal_Bool bReduceValueRange = sal_True);
157 /** This method converts variants arguments in calls from COM -> UNO. Only then
158 the expected UNO type is known.
159 @exception CannotConvertException
160 Thrown if the VARIANT contains a type that cannot be coerced in the expected Any.
161 ArgumentIndex is 0.
162 @IllegalArgumentException
163 Thrown if the VARIANT is inappropriate for conversion. ArgumentPosition is -1,
165 void variantToAny( const VARIANTARG* pArg, Any& rAny, const Type& ptype, sal_Bool bReduceValueRange = sal_True);
168 @exception IllegalArgumentException
169 -if pVar does not contain VT_UNKNOWN or VT_DISPATCH or
170 pVar is used for a particular UNO type which is not supported by pVar
172 Any createOleObjectWrapper(VARIANT* pVar, const Type& aType= Type());
175 Return true means var contained a ValueObject, and it was successfully converted.
176 The result is in any. It an error occurred a BridgeRuntimeError will be thrown.
178 bool convertValueObject( const VARIANTARG *var, Any& any);
179 void dispatchExObject2Sequence( const VARIANTARG* pvar, Any& anySeq, const Type& type);
181 Sequence<Any> createOleArrayWrapperOfDim(SAFEARRAY* pArray, unsigned int dimCount, unsigned int actDim, long* index,
182 VARTYPE type, const Type& unotype);
183 Sequence<Any> createOleArrayWrapper(SAFEARRAY* pArray, VARTYPE type, const Type& unotype= Type());
186 VARTYPE mapTypeClassToVartype( TypeClass type);
187 Reference< XSingleServiceFactory > getInvocationFactory(const Any& anyObject);
190 virtual Reference< XInterface > createUnoWrapperInstance()=0;
191 virtual Reference< XInterface > createComWrapperInstance()=0;
193 static sal_Bool isJScriptArray(const VARIANT* pvar);
195 Sequence<Type> getImplementedInterfaces(IUnknown* pUnk);
197 protected:
198 Reference<XInterface> createAdapter(const Sequence<Type>& types, const Reference<XInterface>& receiver);
200 // helper function for Sequence conversion
201 void getElementCountAndTypeOfSequence( const Any& rSeq, sal_Int32 dim, Sequence< sal_Int32 >& seqElementCounts, TypeDescription& typeDesc);
202 // helper function for Sequence conversion
203 sal_Bool incrementMultidimensionalIndex(sal_Int32 dimensions, const sal_Int32 * parDimensionLength,
204 sal_Int32 * parMultidimensionalIndex);
205 // helper function for Sequence conversion
206 size_t getOleElementSize( VARTYPE type);
208 Type getElementTypeOfSequence( const Type& seqType);
210 //Provides a typeconverter
211 Reference<XTypeConverter> getTypeConverter();
213 // This member determines what class is used to convert a UNO object
214 // or struct to a COM object. It is passed along to the o2u_anyToVariant
215 // function in the createBridge function implementation
216 sal_uInt8 m_nUnoWrapperClass;
217 sal_uInt8 m_nComWrapperClass;
219 // The servicemanager is either a local smgr or remote when the service
220 // com.sun.star.bridge.OleBridgeSupplierVar1 is used. This service can be
221 // created by createInstanceWithArguments where one can supply a service
222 // manager that is to be used.
223 // Local service manager as supplied by the loader when the creator function
224 // of the service is being called.
225 Reference<XMultiServiceFactory> m_smgr;
226 // An explicitly supplied service manager when the service
227 // com.sun.star.bridge.OleBridgeSupplierVar1 is used. That can be a remote
228 // manager.
229 Reference<XMultiServiceFactory> m_smgrRemote;
230 Reference<XSingleServiceFactory> m_xInvocationFactoryLocal;
231 Reference<XSingleServiceFactory> m_xInvocationFactoryRemote;
233 private:
234 // Holds the type converter which is used for sequence conversion etc.
235 // Use the getTypeConverter function to obtain the interface.
236 Reference<XTypeConverter> m_typeConverter;
241 // ask the object for XBridgeSupplier2 and on success bridges
242 // the uno object to IUnknown or IDispatch.
243 // return true the UNO object supports
244 template < class T >
245 bool convertSelfToCom( T& unoInterface, VARIANT * pVar)
247 bool ret = false;
248 Reference< XInterface > xInt( unoInterface, UNO_QUERY);
249 if( xInt.is())
251 Reference< XBridgeSupplier2 > xSupplier( xInt, UNO_QUERY);
252 if( xSupplier.is())
254 sal_Int8 arId[16];
255 rtl_getGlobalProcessId( (sal_uInt8*)arId);
256 Sequence<sal_Int8> seqId( arId, 16);
257 Any anySource;
258 anySource <<= xInt;
259 Any anyDisp= xSupplier->createBridge( anySource, seqId, UNO, OLE);
260 if( anyDisp.getValueTypeClass() == TypeClass_UNSIGNED_LONG)
262 VARIANT* pvariant= *(VARIANT**)anyDisp.getValue();
263 HRESULT hr;
264 if (FAILED(hr = VariantCopy(pVar, pvariant)))
265 throw BridgeRuntimeError(
266 OUSTR("[automation bridge] convertSelfToCom\n"
267 "VariantCopy failed! Error: ") +
268 OUString::valueOf(hr));
269 VariantClear( pvariant);
270 CoTaskMemFree( pvariant);
271 ret = true;
275 return ret;
280 // Gets the invocation factory depending on the Type in the Any.
281 // The factory can be created by a local or remote multi service factory.
282 // In case there is a remote multi service factory available there are
283 // some services or types for which the local factory is used. The exceptions
284 // are: all structs.
285 // Param anyObject - contains the object ( interface, struct) for what we need an invocation object.
287 template<class T>
288 Reference< XSingleServiceFactory > UnoConversionUtilities<T>::getInvocationFactory(const Any& anyObject)
290 Reference< XSingleServiceFactory > retVal;
291 MutexGuard guard( getBridgeMutex());
292 if( anyObject.getValueTypeClass() != TypeClass_STRUCT &&
293 m_smgrRemote.is() )
295 if( ! m_xInvocationFactoryRemote.is() )
296 m_xInvocationFactoryRemote= Reference<XSingleServiceFactory>(
297 m_smgrRemote->createInstance( INVOCATION_SERVICE), UNO_QUERY);
298 retVal= m_xInvocationFactoryRemote;
300 else
302 if( ! m_xInvocationFactoryLocal.is() )
303 m_xInvocationFactoryLocal= Reference<XSingleServiceFactory>(
304 m_smgr->createInstance(INVOCATION_SERVICE ), UNO_QUERY);
305 retVal= m_xInvocationFactoryLocal;
307 return retVal;
310 template<class T>
311 void UnoConversionUtilities<T>::variantToAny( const VARIANTARG* pArg, Any& rAny, const Type& ptype, sal_Bool bReduceValueRange /* = sal_True */)
315 HRESULT hr;
316 bool bFail = false;
317 bool bCannotConvert = false;
318 CComVariant var;
320 // There is no need to support indirect values, since they're not supported by UNO
321 if( FAILED(hr= VariantCopyInd( &var, const_cast<VARIANTARG*>(pArg)))) // remove VT_BYREF
322 throw BridgeRuntimeError(
323 OUSTR("[automation bridge] UnoConversionUtilities<T>::variantToAny \n"
324 "VariantCopyInd failed for reason : ") + OUString::valueOf(hr));
325 bool bHandled = convertValueObject( & var, rAny);
326 if( bHandled)
327 OSL_ENSURE( rAny.getValueType() == ptype, "type in Value Object must match the type parameter");
329 if( ! bHandled)
331 // convert into a variant type that is the equivalent to the type
332 // the sequence expects. Thus variantToAny produces the correct type
333 // E.g. An Array object contains VT_I4 and the sequence expects shorts
334 // than the vartype must be changed. The reason is, you can't specify the
335 // type in JavaScript and the script engine determines the type beeing used.
336 switch( ptype.getTypeClass())
338 case TypeClass_CHAR: // could be: new Array( 12, 'w', "w")
339 if( var.vt == VT_BSTR)
341 if(SUCCEEDED( hr= VariantChangeType( &var, &var, 0, VT_BSTR)))
342 rAny.setValue( (void*)V_BSTR( &var), ptype);
343 else if (hr == DISP_E_TYPEMISMATCH)
344 bCannotConvert = true;
345 else
346 bFail = true;
348 else
350 if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_I2)))
351 rAny.setValue((void*) & var.iVal, ptype);
352 else if (hr == DISP_E_TYPEMISMATCH)
353 bCannotConvert = true;
354 else
355 bFail = true;
357 break;
358 case TypeClass_INTERFACE: // could also be an IUnknown
359 case TypeClass_STRUCT:
361 rAny = createOleObjectWrapper( & var, ptype);
362 break;
364 case TypeClass_ENUM:
365 if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_I4)))
366 rAny.setValue((void*) & var.lVal, ptype);
367 else if (hr == DISP_E_TYPEMISMATCH)
368 bCannotConvert = true;
369 else
370 bFail = true;
371 break;
372 case TypeClass_SEQUENCE:
373 // There are different ways of receiving a sequence:
374 // 1: JScript, VARTYPE: VT_DISPATCH
375 // 2. VBScript simple arraysVT_VARIANT|VT_BYREF the referenced VARIANT contains
376 // a VT_ARRAY| <type>
377 // 3. VBSrcript multi dimensional arrays: VT_ARRAY|VT_BYREF
378 if( pArg->vt == VT_DISPATCH)
380 dispatchExObject2Sequence( pArg, rAny, ptype);
382 else
384 if ((var.vt & VT_ARRAY) != 0)
386 VARTYPE oleType = ::sal::static_int_cast< VARTYPE, int >( var.vt ^ VT_ARRAY );
387 Sequence<Any> unoSeq = createOleArrayWrapper( var.parray, oleType, ptype);
388 Reference<XTypeConverter> conv = getTypeConverter();
389 if (conv.is())
391 try
393 Any anySeq = makeAny(unoSeq);
394 Any convAny = conv->convertTo(anySeq, ptype);
395 rAny = convAny;
397 catch (IllegalArgumentException& e)
399 throw BridgeRuntimeError(
400 OUSTR("[automation bridge]com.sun.star.lang.IllegalArgumentException "
401 "in UnoConversionUtilities<T>::variantToAny! Message: ") +
402 e.Message);
404 catch (CannotConvertException& e)
406 throw BridgeRuntimeError(
407 OUSTR("[automation bridge]com.sun.star.script.CannotConvertException "
408 "in UnoConversionUtilities<T>::variantToAny! Message: ") +
409 e.Message);
414 break;
415 case TypeClass_VOID:
416 rAny.setValue(NULL,Type());
417 break;
418 case TypeClass_ANY: // Any
419 // There could be a JScript Array that needs special handling
420 // If an Any is expected and this Any must contain a Sequence
421 // then we cannot figure out what element type is required.
422 // Therefore we convert to Sequence< Any >
423 if( pArg->vt == VT_DISPATCH && isJScriptArray( pArg))
425 dispatchExObject2Sequence( pArg, rAny,
426 getCppuType((Sequence<Any>*) 0));
428 else if (pArg->vt == VT_DECIMAL)
430 //Decimal maps to hyper in calls from COM -> UNO
431 // It does not matter if we create a sal_uInt64 or sal_Int64,
432 // because the UNO object is called through invocation which
433 //will do a type conversion if necessary
434 if (var.decVal.sign == 0)
436 // positive value
437 variantToAny( & var, rAny, getCppuType( (sal_uInt64*) 0),
438 bReduceValueRange);
440 else
442 //negative value
443 variantToAny( & var, rAny, getCppuType( (sal_Int64*) 0),
444 bReduceValueRange);
447 else
449 variantToAny( & var, rAny);
451 break;
452 case TypeClass_BOOLEAN: // VARIANT could be VARIANT_BOOL or other
453 if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_BOOL)))
454 variantToAny( & var, rAny);
455 else if (hr == DISP_E_TYPEMISMATCH)
456 bCannotConvert = true;
457 else
458 bFail = true;
459 break;
460 case TypeClass_STRING: // UString
461 if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_BSTR)))
462 variantToAny( & var, rAny);
463 else if (hr == DISP_E_TYPEMISMATCH)
464 bCannotConvert = true;
465 else
466 bFail = true;
467 break;
468 case TypeClass_FLOAT: // float
469 if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_R4)))
470 variantToAny( & var, rAny);
471 else if (hr == DISP_E_TYPEMISMATCH)
472 bCannotConvert = true;
473 else
474 bFail = true;
475 break;
476 case TypeClass_DOUBLE: // double
477 if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_R8)))
478 variantToAny(& var, rAny);
479 else if (hr == DISP_E_TYPEMISMATCH)
480 bCannotConvert = true;
481 else
482 bFail = true;
483 break;
484 case TypeClass_BYTE: // BYTE
485 if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_I1)))
486 variantToAny( & var, rAny);
487 else if (hr == DISP_E_TYPEMISMATCH)
488 bCannotConvert = true;
489 else
490 bFail = true;
491 break;
492 case TypeClass_SHORT: // INT16
493 if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_I2)))
494 variantToAny( & var, rAny);
495 else if (hr == DISP_E_TYPEMISMATCH)
496 bCannotConvert = true;
497 else
498 bFail = true;
499 break;
500 case TypeClass_LONG:
501 if(SUCCEEDED(hr = VariantChangeType(& var, &var, 0, VT_I4)))
502 variantToAny( & var, rAny, bReduceValueRange);
503 else if (hr == DISP_E_TYPEMISMATCH)
504 bCannotConvert = true;
505 else
506 bFail = true;
507 break;
508 case TypeClass_HYPER:
509 if(SUCCEEDED(hr = VariantChangeType(& var, &var, 0, VT_DECIMAL)))
511 if (var.decVal.Lo64 > SAL_CONST_UINT64(0x8000000000000000)
512 || var.decVal.Hi32 > 0
513 || var.decVal.scale > 0)
515 bFail = true;
516 break;
518 sal_Int64 value = var.decVal.Lo64;
519 if (var.decVal.sign == DECIMAL_NEG)
520 value |= SAL_CONST_UINT64(0x8000000000000000);
521 rAny <<= value;
523 else if (hr == DISP_E_TYPEMISMATCH)
524 bCannotConvert = true;
525 else
526 bFail = true;
527 break;
528 case TypeClass_UNSIGNED_SHORT: // UINT16
529 if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_UI2)))
530 variantToAny( & var, rAny);
531 else if (hr == DISP_E_TYPEMISMATCH)
532 bCannotConvert = true;
533 else
534 bFail = true;
535 break;
536 case TypeClass_UNSIGNED_LONG:
537 if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_UI4)))
538 variantToAny( & var, rAny, bReduceValueRange);
539 else if (hr == DISP_E_TYPEMISMATCH)
540 bCannotConvert = true;
541 else
542 bFail = true;
543 break;
544 case TypeClass_UNSIGNED_HYPER:
545 if(SUCCEEDED(hr = VariantChangeType(& var, &var, 0, VT_DECIMAL)))
547 if (var.decVal.Hi32 > 0 || var.decVal.scale > 0)
549 bFail = true;
550 break;
552 rAny <<= var.decVal.Lo64;
554 else if (hr == DISP_E_TYPEMISMATCH)
555 bCannotConvert = true;
556 else
557 bFail = true;
558 break;
559 case TypeClass_TYPE:
560 if(SUCCEEDED(hr = VariantChangeType(& var, &var, 0, VT_UNKNOWN)))
561 variantToAny( & var, rAny);
562 else if (hr == DISP_E_TYPEMISMATCH)
563 bCannotConvert = true;
564 else
565 bFail = true;
566 break;
567 default:
568 // case TypeClass_SERVICE: break; // meta construct
569 // case TypeClass_TYPEDEF: break;
570 // case TypeClass_UNION: break;
571 // case TypeClass_MODULE: break; // module
572 // case TypeClass_EXCEPTION: break;
573 // case TypeClass_ARRAY: break; // there's no Array at the moment
574 // case TypeClass_UNKNOWN: break;
575 bCannotConvert = true;
576 break;
579 if (bCannotConvert)
580 throw CannotConvertException(
581 OUSTR("[automation bridge]UnoConversionUtilities<T>::variantToAny \n"
582 "Cannot convert the value of vartype :\"") +
583 OUString::valueOf((sal_Int32) var.vt) +
584 OUSTR("\" to the expected UNO type of type class: ") +
585 OUString::valueOf((sal_Int32) ptype.getTypeClass()),
586 0, TypeClass_UNKNOWN, FailReason::TYPE_NOT_SUPPORTED,0);
588 if (bFail)
589 throw IllegalArgumentException(
590 OUSTR("[automation bridge]UnoConversionUtilities<T>:variantToAny\n"
591 "The provided VARIANT of type\" ") + OUString::valueOf((sal_Int32) var.vt) +
592 OUSTR("\" is unappropriate for conversion!"), Reference<XInterface>(), -1);
594 catch (CannotConvertException &)
596 throw;
598 catch (IllegalArgumentException &)
600 throw;
602 catch (BridgeRuntimeError &)
604 throw;
606 catch (Exception & e)
608 throw BridgeRuntimeError(OUSTR("[automation bridge] unexpected exception in "
609 "UnoConversionUtilities<T>::variantToAny ! Message : \n") +
610 e.Message);
612 catch(...)
614 throw BridgeRuntimeError(
615 OUSTR("[automation bridge] unexpected exception in "
616 "UnoConversionUtilities<T>::variantToAny !"));
620 // The function only converts Sequences to SAFEARRAYS with elements of the type
621 // specified by the parameter type. Everything else is forwarded to
622 // anyToVariant(VARIANT* pVariant, const Any& rAny)
623 // Param type must not be VT_BYREF
624 template<class T>
625 void UnoConversionUtilities<T>::anyToVariant(VARIANT* pVariant, const Any& rAny, VARTYPE type)
629 HRESULT hr= S_OK;
631 OSL_ASSERT( (type & VT_BYREF) == 0);
632 if (type & VT_ARRAY)
634 type ^= VT_ARRAY;
635 SAFEARRAY* ar= createUnoSequenceWrapper( rAny, type);
636 if( ar)
638 VariantClear( pVariant);
639 pVariant->vt= ::sal::static_int_cast< VARTYPE, int >( VT_ARRAY | type );
640 pVariant->byref= ar;
643 else if(type == VT_VARIANT)
645 anyToVariant(pVariant, rAny);
647 else
649 CComVariant var;
650 anyToVariant( &var, rAny);
651 if(FAILED(hr = VariantChangeType(&var, &var, 0, type)))
653 if (hr == DISP_E_TYPEMISMATCH)
654 throw CannotConvertException(
655 OUSTR("[automation bridge]UnoConversionUtilities<T>::anyToVariant \n"
656 "Cannot convert the value of type :\"") +
657 rAny.getValueTypeName() +
658 OUSTR("\" to the expected Automation type of VARTYPE: ") +
659 OUString::valueOf((sal_Int32)type),
660 0, TypeClass_UNKNOWN, FailReason::TYPE_NOT_SUPPORTED,0);
662 throw BridgeRuntimeError(
663 OUSTR("[automation bridge]UnoConversionUtilities<T>::anyToVariant \n"
664 "Conversion of any with ") +
665 rAny.getValueType().getTypeName() +
666 OUSTR(" to VARIANT with type: ") + OUString::valueOf((sal_Int32) type) +
667 OUSTR(" failed! Error code: ") + OUString::valueOf(hr));
670 if(FAILED(hr = VariantCopy(pVariant, &var)))
672 throw BridgeRuntimeError(
673 OUSTR("[automation bridge]UnoConversionUtilities<T>::anyToVariant \n"
674 "VariantCopy failed for reason: ") + OUString::valueOf(hr));
678 catch (IllegalArgumentException &)
680 throw;
682 catch (CannotConvertException & )
684 throw;
686 catch (BridgeRuntimeError&)
688 throw;
690 catch(Exception & e)
692 throw BridgeRuntimeError(
693 OUSTR("[automation bridge]UnoConversionUtilities<T>::anyToVariant \n"
694 "Unexpected exception occurred. Message: ") + e.Message);
696 catch(...)
698 throw BridgeRuntimeError(
699 OUSTR("[automation bridge]UnoConversionUtilities<T>::anyToVariant \n"
700 "Unexpected exception occurred."));
704 template<class T>
705 void UnoConversionUtilities<T>::anyToVariant(VARIANT* pVariant, const Any& rAny)
707 bool bIllegal = false;
710 switch (rAny.getValueTypeClass())
712 case TypeClass_INTERFACE:
714 Reference<XInterface> xInt;
715 if (rAny >>= xInt)
717 createUnoObjectWrapper(rAny, pVariant);
719 else
721 bIllegal = true;
723 break;
725 case TypeClass_STRUCT:
727 if (rAny.getValueType() == getCppuType((Date*)0))
729 Date d;
730 if (rAny >>= d)
732 pVariant->vt = VT_DATE;
733 pVariant->date = d.Value;
735 else
737 bIllegal = true;
740 else if(rAny.getValueType() == getCppuType((Decimal*)0))
742 Decimal d;
743 if (rAny >>= d)
745 pVariant->vt = VT_DECIMAL;
746 pVariant->decVal.scale = d.Scale;
747 pVariant->decVal.sign = d.Sign;
748 pVariant->decVal.Lo32 = d.LowValue;
749 pVariant->decVal.Mid32 = d.MiddleValue;
750 pVariant->decVal.Hi32 = d.HighValue;
752 else
754 bIllegal = true;
757 else if (rAny.getValueType() == getCppuType((Currency*)0))
759 Currency c;
760 if (rAny >>= c)
762 pVariant->vt = VT_CY;
763 pVariant->cyVal.int64 = c.Value;
765 else
767 bIllegal = true;
770 else if(rAny.getValueType() == getCppuType((SCode*)0))
772 SCode s;
773 if (rAny >>= s)
775 pVariant->vt = VT_ERROR;
776 pVariant->scode = s.Value;
778 else
780 bIllegal = true;
783 else
785 createUnoObjectWrapper(rAny, pVariant);
787 break;
789 case TypeClass_SEQUENCE: // sequence ??? SafeArray descriptor
791 SAFEARRAY* pArray = createUnoSequenceWrapper(rAny);
792 if (pArray)
794 V_VT(pVariant) = VT_ARRAY | VT_VARIANT;
795 V_ARRAY(pVariant) = pArray;
797 else
799 bIllegal = true;
801 break;
803 case TypeClass_VOID:
805 HRESULT hr = S_OK;
806 if (FAILED(hr = VariantClear(pVariant)))
808 throw BridgeRuntimeError(
809 OUSTR("[automation bridge]UnoConversionUtilities<T>::anyToVariant\n"
810 "VariantClear failed with error:") + OUString::valueOf(hr));
812 break;
814 case TypeClass_BOOLEAN:
816 sal_Bool value;
817 if (rAny >>= value)
819 pVariant->vt = VT_BOOL;
820 pVariant->boolVal = value == sal_True? VARIANT_TRUE: VARIANT_FALSE;
822 else
824 bIllegal = true;
826 break;
828 case TypeClass_CHAR:
830 // Because VT_UI2 does not conform to oleautomation we convert into VT_I2 instead
831 sal_uInt16 value = *(sal_Unicode*) rAny.getValue();
832 pVariant->vt = VT_I2;
833 pVariant->iVal = value;
834 break;
836 case TypeClass_STRING:
838 OUString value;
839 if (rAny >>= value)
841 pVariant->vt = VT_BSTR;
842 pVariant->bstrVal = SysAllocString(reinterpret_cast<LPCOLESTR>(value.getStr()));
844 else
846 bIllegal = true;
848 break;
850 case TypeClass_FLOAT:
852 float value;
853 if (rAny >>= value)
855 pVariant->vt = VT_R4;
856 pVariant->fltVal = value;
858 else
860 bIllegal = true;
862 break;
864 case TypeClass_DOUBLE:
866 double value;
867 if (rAny >>= value)
869 pVariant->vt = VT_R8;
870 pVariant->dblVal = value;
872 else
874 bIllegal = true;
876 break;
878 case TypeClass_BYTE:
880 // ole automation does not know a signed char but only unsigned char
881 sal_Int8 value;
882 if (rAny >>= value)
884 pVariant->vt = VT_UI1;
885 pVariant->bVal = value;
887 else
889 bIllegal = true;
891 break;
893 case TypeClass_SHORT: // INT16
894 case TypeClass_UNSIGNED_SHORT: // UINT16
896 sal_Int16 value;
897 if (rAny >>= value)
899 pVariant->vt = VT_I2;
900 pVariant->iVal = value;
902 else
904 bIllegal = true;
906 break;
908 case TypeClass_ENUM:
910 sal_Int32 value = *(sal_Int32*) rAny.getValue();
911 pVariant->vt = VT_I4;
912 pVariant->lVal= value;
913 break;
915 case TypeClass_LONG:
916 case TypeClass_UNSIGNED_LONG:
918 sal_Int32 value;
919 if (rAny >>= value)
921 pVariant->vt = VT_I4;
922 pVariant->lVal= value;
924 else
926 bIllegal = true;
928 break;
930 case TypeClass_HYPER:
933 pVariant->vt = VT_DECIMAL;
934 pVariant->decVal.scale = 0;
935 pVariant->decVal.sign = 0;
936 pVariant->decVal.Hi32 = 0;
938 sal_Int64 value;
939 rAny >>= value;
941 if (value & SAL_CONST_UINT64(0x8000000000000000))
942 pVariant->decVal.sign = DECIMAL_NEG;
944 pVariant->decVal.Lo64 = value;
945 break;
947 case TypeClass_UNSIGNED_HYPER:
949 pVariant->vt = VT_DECIMAL;
950 pVariant->decVal.scale = 0;
951 pVariant->decVal.sign = 0;
952 pVariant->decVal.Hi32 = 0;
954 sal_uInt64 value;
955 rAny >>= value;
956 pVariant->decVal.Lo64 = value;
957 break;
959 case TypeClass_TYPE:
961 Type type;
962 rAny >>= type;
963 CComVariant var;
964 if (createUnoTypeWrapper(type.getTypeName(), & var) == false)
965 throw BridgeRuntimeError(
966 OUSTR("[automation bridge] UnoConversionUtilities<T>::anyToVariant \n"
967 "Error during conversion of UNO type to Automation object!"));
969 if (FAILED(VariantCopy(pVariant, &var)))
970 throw BridgeRuntimeError(
971 OUSTR("[automation bridge] UnoConversionUtilities<T>::anyToVariant \n"
972 "Unexpected error!"));
973 break;
975 default:
976 //TypeClass_SERVICE:
977 //TypeClass_EXCEPTION:
978 //When a InvocationTargetException is thrown when calling XInvocation::invoke
979 //on a UNO object, then the target exception is directly used to create a
980 //EXEPINFO structure
981 //TypeClass_TYPEDEF
982 //TypeClass_ANY:
983 //TypeClass_UNKNOWN:
984 //TypeClass_UNSIGNED_OCTET:
985 // TypeClass_UNION:
986 // TypeClass_ARRAY:
987 // TypeClass_UNSIGNED_INT:
988 // TypeClass_UNSIGNED_BYTE:
989 // TypeClass_MODULE:
990 throw CannotConvertException(
991 OUSTR("[automation bridge]UnoConversionUtilities<T>::anyToVariant\n"
992 "There is no conversion for this UNO type to a Automation type."
993 "The destination type class is the type class of the UNO "
994 "argument which was to be converted."),
995 Reference<XInterface>(), rAny.getValueTypeClass(),
996 FailReason::TYPE_NOT_SUPPORTED, 0);
998 break;
1000 if (bIllegal)
1002 throw IllegalArgumentException(
1003 OUSTR("[automation bridge]UnoConversionUtilities<T>::anyToVariant\n"
1004 "The provided any of type\" ") + rAny.getValueType().getTypeName() +
1005 OUSTR("\" is unappropriate for conversion!"), Reference<XInterface>(), -1);
1009 catch (CannotConvertException & )
1011 throw;
1013 catch (IllegalArgumentException & )
1015 throw;
1017 catch(BridgeRuntimeError&)
1019 throw;
1021 catch(Exception & e)
1023 throw BridgeRuntimeError(
1024 OUSTR("[automation bridge]UnoConversionUtilities<T>::anyToVariant \n"
1025 "Unexpected exception occurred. Message: ") + e.Message);
1027 catch(...)
1029 throw BridgeRuntimeError(
1030 OUSTR("[automation bridge]UnoConversionUtilities<T>::anyToVariant \n"
1031 "Unexpected exception occurred. ") );
1035 // Creates an SAFEARRAY of the specified element and if necessary
1036 // creates a SAFEARRAY whith multiple dimensions.
1037 // Used by sal_Bool anyToVariant(VARIANT* pVariant, const Any& rAny, VARTYPE type);
1038 template<class T>
1039 SAFEARRAY* UnoConversionUtilities<T>::createUnoSequenceWrapper(const Any& rSeq, VARTYPE elemtype)
1041 if (rSeq.getValueTypeClass() != TypeClass_SEQUENCE)
1042 throw IllegalArgumentException(
1043 OUSTR("[automation bridge]UnoConversionUtilities<T>::createUnoSequenceWrapper \n"
1044 "The any does not contain a sequence!"), 0, 0);
1045 if (elemtype == VT_NULL || elemtype == VT_EMPTY)
1046 throw IllegalArgumentException(
1047 OUSTR("[automation bridge]UnoConversionUtilities<T>::createUnoSequenceWrapper \n"
1048 "No element type supplied!"),0, -1);
1049 SAFEARRAY* pArray= NULL;
1050 // Get the dimensions. This is done by examining the type name string
1051 // The count of brackets determines the dimensions.
1052 OUString sTypeName= rSeq.getValueType().getTypeName();
1053 sal_Int32 dims=0;
1054 for(sal_Int32 lastIndex=0;(lastIndex= sTypeName.indexOf( L'[', lastIndex)) != -1; lastIndex++,dims++);
1056 //get the maximum number of elements per dimensions and the typedescription of the elements
1057 Sequence<sal_Int32> seqElementCounts( dims);
1058 TypeDescription elementTypeDesc;
1059 getElementCountAndTypeOfSequence( rSeq, 1, seqElementCounts, elementTypeDesc );
1061 if( elementTypeDesc.is() )
1063 // set up the SAFEARRAY
1064 scoped_array<SAFEARRAYBOUND> sarSafeArrayBound(new SAFEARRAYBOUND[dims]);
1065 SAFEARRAYBOUND* prgsabound= sarSafeArrayBound.get();
1066 for( sal_Int32 i=0; i < dims; i++)
1068 //prgsabound[0] is the right most dimension
1069 prgsabound[dims - i - 1].lLbound = 0;
1070 prgsabound[dims - i - 1].cElements = seqElementCounts[i];
1073 typelib_TypeDescription* rawTypeDesc= elementTypeDesc.get();
1074 sal_Int32 elementSize= rawTypeDesc->nSize;
1075 size_t oleElementSize= getOleElementSize( elemtype);
1076 // SafeArrayCreate clears the memory for the data itself.
1077 pArray = SafeArrayCreate(elemtype, dims, prgsabound);
1079 // convert the Sequence's elements and populate the SAFEARRAY
1080 if( pArray)
1082 // Iterate over every Sequence that contains the actual elements
1083 void* pSAData;
1084 if( SUCCEEDED( SafeArrayAccessData( pArray, &pSAData)))
1086 const sal_Int32* parElementCount= seqElementCounts.getConstArray();
1087 uno_Sequence * pMultiSeq= *(uno_Sequence* const*) rSeq.getValue();
1088 sal_Int32 dimsSeq= dims - 1;
1090 // arDimSeqIndizes contains the current index of a block of data.
1091 // E.g. Sequence<Sequence<sal_Int32>> , the index would refer to Sequence<sal_Int32>
1092 // In this case arDimSeqIndices would have the size 1. That is the elements are not counted
1093 // but the Sequences that contain those elements.
1094 // The indices ar 0 based
1095 scoped_array<sal_Int32> sarDimsSeqIndices;
1096 sal_Int32* arDimsSeqIndices= NULL;
1097 if( dimsSeq > 0)
1099 sarDimsSeqIndices.reset(new sal_Int32[dimsSeq]);
1100 arDimsSeqIndices = sarDimsSeqIndices.get();
1101 memset( arDimsSeqIndices, 0, sizeof( sal_Int32 ) * dimsSeq);
1104 char* psaCurrentData= (char*)pSAData;
1108 // Get the Sequence at the current index , see arDimsSeqIndices
1109 uno_Sequence * pCurrentSeq= pMultiSeq;
1110 sal_Int32 curDim=1; // 1 based
1111 sal_Bool skipSeq= sal_False;
1112 while( curDim <= dimsSeq )
1114 // get the Sequence at the index if valid
1115 if( pCurrentSeq->nElements > arDimsSeqIndices[ curDim - 1] ) // don't point to Nirvana
1117 // size of Sequence is 4
1118 sal_Int32 offset= arDimsSeqIndices[ curDim - 1] * 4;
1119 pCurrentSeq= *(uno_Sequence**) &pCurrentSeq->elements[ offset];
1120 curDim++;
1122 else
1124 // There is no Sequence at this index, so skip this index
1125 skipSeq= sal_True;
1126 break;
1130 if( skipSeq)
1131 continue;
1133 // Calculate the current position within the datablock of the SAFEARRAY
1134 // for the next Sequence.
1135 sal_Int32 memOffset= 0;
1136 sal_Int32 dimWeight= parElementCount[ dims - 1]; // size of the rightmost dimension
1137 for(sal_Int16 idims=0; idims < dimsSeq; idims++ )
1139 memOffset+= arDimsSeqIndices[dimsSeq - 1 - idims] * dimWeight;
1140 // now determine the weight of the dimension to the left of the current.
1141 if( dims - 2 - idims >=0)
1142 dimWeight*= parElementCount[dims - 2 - idims];
1144 psaCurrentData= (char*)pSAData + memOffset * oleElementSize;
1145 // convert the Sequence and put the elements into the Safearray
1146 for( sal_Int32 i= 0; i < pCurrentSeq->nElements; i++)
1148 Any unoElement( pCurrentSeq->elements + i * elementSize, rawTypeDesc );
1149 // The any is being converted into an VARIANT which value is then copied
1150 // to the SAFEARRAY's data block. When copying one has to follow the rules for
1151 // copying certain types, as are VT_DISPATCH, VT_UNKNOWN, VT_VARIANT, VT_BSTR.
1152 // To increase performance, we just do a memcpy of VARIANT::byref. This is possible
1153 // because anyToVariant has already followed the copying rules. To make this
1154 // work there must not be a VariantClear.
1155 // One Exception is VARIANT because I don't know how VariantCopy works.
1157 VARIANT var;
1158 VariantInit( &var);
1159 anyToVariant( &var, unoElement);
1160 if( elemtype == VT_VARIANT )
1162 VariantCopy( ( VARIANT*)psaCurrentData, &var);
1163 VariantClear( &var);
1165 else
1166 memcpy( psaCurrentData, &var.byref, oleElementSize);
1168 psaCurrentData+= oleElementSize;
1171 while( incrementMultidimensionalIndex( dimsSeq, parElementCount, arDimsSeqIndices));
1173 SafeArrayUnaccessData( pArray);
1177 return pArray;
1180 // Increments a multi dimensional index.
1181 // Returns true as long as the index has been successfully incremented, false otherwise.
1182 // False is also returned if an overflow of the most significant dimension occurs. E.g.
1183 // assume an array with the dimensions (2,2), then the lowest index is (0,0) and the highest
1184 // index is (1,1). If the function is being called with the index (1,1) then the overflow would
1185 // occur, with the result (0,0) and a sal_False as return value.
1186 // Param dimensions - number of dimensions
1187 // Param parDimensionsLength - The array contains the size of each dimension, that is the
1188 // size of the array equals the parameter dimensions.
1189 // The rightmost dimensions is the least significant one
1190 // ( parDimensionsLengths[ dimensions -1 ] ).
1191 // Param parMultiDimensionalIndex - The array contains the index. Each dimension index is
1192 // 0 based.
1193 template<class T>
1194 sal_Bool UnoConversionUtilities<T>::incrementMultidimensionalIndex(sal_Int32 dimensions,
1195 const sal_Int32 * parDimensionLengths,
1196 sal_Int32 * parMultidimensionalIndex)
1198 if( dimensions < 1)
1199 return sal_False;
1201 sal_Bool ret= sal_True;
1202 sal_Bool carry= sal_True; // to get into the while loop
1204 sal_Int32 currentDimension= dimensions; //most significant is 1
1205 while( carry)
1207 parMultidimensionalIndex[ currentDimension - 1]++;
1208 // if carryover, set index to 0 and handle carry on a level above
1209 if( parMultidimensionalIndex[ currentDimension - 1] > (parDimensionLengths[ currentDimension - 1] - 1))
1210 parMultidimensionalIndex[ currentDimension - 1]= 0;
1211 else
1212 carry= sal_False;
1214 currentDimension --;
1215 // if dimensions drops below 1 and carry is set than then all indices are 0 again
1216 // this is signalled by returning sal_False
1217 if( currentDimension < 1 && carry)
1219 carry= sal_False;
1220 ret= sal_False;
1223 return ret;
1226 // Determines the size of a certain OLE type. The function takes
1227 // only those types into account which are oleautomation types and
1228 // can have a value ( unless VT_NULL, VT_EMPTY, VT_ARRAY, VT_BYREF).
1229 // Currently used in createUnoSequenceWrapper to calculate addresses
1230 // for data within a SAFEARRAY.
1231 template<class T>
1232 size_t UnoConversionUtilities<T>::getOleElementSize( VARTYPE type)
1234 size_t size;
1235 switch( type)
1237 case VT_BOOL: size= sizeof( VARIANT_BOOL);break;
1238 case VT_UI1: size= sizeof( unsigned char);break;
1239 case VT_R8: size= sizeof( double);break;
1240 case VT_R4: size= sizeof( float);break;
1241 case VT_I2: size= sizeof( short);break;
1242 case VT_I4: size= sizeof( long);break;
1243 case VT_BSTR: size= sizeof( BSTR); break;
1244 case VT_ERROR: size= sizeof( SCODE); break;
1245 case VT_DISPATCH:
1246 case VT_UNKNOWN: size= sizeof( IUnknown*); break;
1247 case VT_VARIANT: size= sizeof( VARIANT);break;
1248 default: size= 0;
1250 return size;
1253 //If a Sequence is being converted into a SAFEARRAY then we possibly have
1254 // to create a SAFEARRAY with multiple dimensions. This is the case when a
1255 // Sequence contains Sequences ( Sequence< Sequence < XXX > > ). The leftmost
1256 // Sequence in the declaration is assumed to represent dimension 1. Because
1257 // all Sequence elements of a Sequence can have different length, we have to
1258 // determine the maximum length which is then the length of the respective
1259 // dimension.
1260 // getElementCountAndTypeOfSequence determines the length of each dimension and calls itself recursively
1261 // in the process.
1262 // param rSeq - an Any that has to contain a Sequence
1263 // param dim - the dimension for which the number of elements is being determined,
1264 // must be one.
1265 // param seqElementCounts - countains the maximum number of elements for each
1266 // dimension. Index 0 contains the number of dimension one.
1267 // After return the Sequence contains the maximum number of
1268 // elements for each dimension.
1269 // The length of the Sequence must equal the number of dimensions.
1270 // param typeClass - TypeClass of the element type that is no Sequence, e.g.
1271 // Sequence< Sequence <Sequence <sal_Int32> > > - type is sal_Int32)
1272 template<class T>
1273 void UnoConversionUtilities<T>::getElementCountAndTypeOfSequence( const Any& rSeq, sal_Int32 dim,
1274 Sequence< sal_Int32 >& seqElementCounts, TypeDescription& typeDesc)
1276 sal_Int32 dimCount= (*(uno_Sequence* const *) rSeq.getValue())->nElements;
1277 if( dimCount > seqElementCounts[ dim-1])
1278 seqElementCounts[ dim-1]= dimCount;
1280 // we need the element type to construct the any that is
1281 // passed into getElementCountAndTypeOfSequence again
1282 typelib_TypeDescription* pSeqDesc= NULL;
1283 rSeq.getValueTypeDescription( &pSeqDesc);
1284 typelib_TypeDescriptionReference* pElementDescRef= ((typelib_IndirectTypeDescription*)pSeqDesc)->pType;
1286 // if the elements are Sequences than do recursion
1287 if( dim < seqElementCounts.getLength() )
1289 uno_Sequence* pSeq = *(uno_Sequence* const*) rSeq.getValue();
1290 uno_Sequence** arSequences= (uno_Sequence**)pSeq->elements;
1291 for( sal_Int32 i=0; i < dimCount; i++)
1293 uno_Sequence* arElement= arSequences[ i];
1294 getElementCountAndTypeOfSequence( Any( &arElement, pElementDescRef), dim + 1 , seqElementCounts, typeDesc);
1297 else
1299 // determine the element type ( e.g. Sequence< Sequence <Sequence <sal_Int32> > > - type is sal_Int32)
1300 typeDesc= pElementDescRef;
1302 typelib_typedescription_release( pSeqDesc);
1306 template<class T>
1307 SAFEARRAY* UnoConversionUtilities<T>::createUnoSequenceWrapper(const Any& rSeq)
1309 SAFEARRAY* pArray = NULL;
1310 sal_uInt32 n = 0;
1312 if( rSeq.getValueTypeClass() != TypeClass_SEQUENCE )
1313 throw IllegalArgumentException(
1314 OUSTR("[automation bridge]UnoConversionUtilities<T>::createUnoSequenceWrapper\n"
1315 "The UNO argument is not a sequence"), 0, -1);
1317 uno_Sequence * punoSeq= *(uno_Sequence**) rSeq.getValue();
1319 typelib_TypeDescriptionReference* pSeqTypeRef= rSeq.getValueTypeRef();
1320 typelib_TypeDescription* pSeqType= NULL;
1321 TYPELIB_DANGER_GET( &pSeqType, pSeqTypeRef);
1322 typelib_IndirectTypeDescription * pSeqIndDec= (typelib_IndirectTypeDescription*) pSeqType;
1325 typelib_TypeDescriptionReference * pSeqElementTypeRef= pSeqIndDec->pType;
1326 TYPELIB_DANGER_RELEASE( pSeqType);
1328 typelib_TypeDescription* pSeqElementDesc= NULL;
1329 TYPELIB_DANGER_GET( &pSeqElementDesc, pSeqElementTypeRef);
1330 sal_Int32 nElementSize= pSeqElementDesc->nSize;
1331 n= punoSeq->nElements;
1333 SAFEARRAYBOUND rgsabound[1];
1334 rgsabound[0].lLbound = 0;
1335 rgsabound[0].cElements = n;
1336 VARIANT oleElement;
1337 long safeI[1];
1339 pArray = SafeArrayCreate(VT_VARIANT, 1, rgsabound);
1341 Any unoElement;
1342 // sal_uInt8 * pSeqData= (sal_uInt8*) punoSeq->pElements;
1343 sal_uInt8 * pSeqData= (sal_uInt8*) punoSeq->elements;
1345 for (sal_uInt32 i = 0; i < n; i++)
1347 unoElement.setValue( pSeqData + i * nElementSize, pSeqElementDesc);
1348 VariantInit(&oleElement);
1350 anyToVariant(&oleElement, unoElement);
1352 safeI[0] = i;
1353 SafeArrayPutElement(pArray, safeI, &oleElement);
1355 VariantClear(&oleElement);
1357 TYPELIB_DANGER_RELEASE( pSeqElementDesc);
1359 return pArray;
1362 /* The argument rObj can contain
1363 - UNO struct
1364 - UNO interface
1365 - UNO interface created by this bridge (adapter factory)
1366 - UNO interface created by this bridge ( COM Wrapper)
1368 pVar must be initialized.
1370 template<class T>
1371 void UnoConversionUtilities<T>::createUnoObjectWrapper(const Any & rObj, VARIANT * pVar)
1373 MutexGuard guard(getBridgeMutex());
1375 Reference<XInterface> xInt;
1377 TypeClass tc = rObj.getValueTypeClass();
1378 if (tc != TypeClass_INTERFACE && tc != TypeClass_STRUCT)
1379 throw IllegalArgumentException(
1380 OUSTR("[automation bridge]UnoConversionUtilities<T>::createUnoObjectWrapper \n"
1381 "Cannot create an Automation interface for a UNO type which is not "
1382 "a struct or interface!"), 0, -1);
1384 if (rObj.getValueTypeClass() == TypeClass_INTERFACE)
1386 if (! (rObj >>= xInt))
1387 throw IllegalArgumentException(
1388 OUSTR("[automation bridge] UnoConversionUtilities<T>::createUnoObjectWrapper\n "
1389 "Could not create wrapper object for UNO object!"), 0, -1);
1390 //If XInterface is NULL, which is a valid value, then simply return NULL.
1391 if ( ! xInt.is())
1393 pVar->vt = VT_UNKNOWN;
1394 pVar->punkVal = NULL;
1395 return;
1397 //make sure we have the main XInterface which is used with a map
1398 xInt = Reference<XInterface>(xInt, UNO_QUERY);
1399 //If there is already a wrapper for the UNO object then use it
1401 Reference<XInterface> xIntWrapper;
1402 // Does a UNO wrapper exist already ?
1403 IT_Uno it_uno = UnoObjToWrapperMap.find( (sal_uInt32) xInt.get());
1404 if(it_uno != UnoObjToWrapperMap.end())
1406 xIntWrapper = it_uno->second;
1407 if (xIntWrapper.is())
1409 convertSelfToCom(xIntWrapper, pVar);
1410 return;
1413 // Is the object a COM wrapper ( either XInvocation, or Adapter object)
1414 // or does it suppy an IDispatch by its own ?
1415 else
1417 Reference<XInterface> xIntComWrapper = xInt;
1418 typedef hash_map<sal_uInt32,sal_uInt32>::iterator _IT;
1419 // Adapter? then get the COM wrapper to which the adapter delegates its calls
1420 _IT it= AdapterToWrapperMap.find( (sal_uInt32) xInt.get());
1421 if( it != AdapterToWrapperMap.end() )
1422 xIntComWrapper= reinterpret_cast<XInterface*>(it->second);
1424 if (convertSelfToCom(xIntComWrapper, pVar))
1425 return;
1428 // If we have no UNO wrapper nor the IDispatch yet then we have to create
1429 // a wrapper. For that we need an XInvocation from the UNO object.
1431 // get an XInvocation or create one using the invocation service
1432 Reference<XInvocation> xInv(xInt, UNO_QUERY);
1433 if ( ! xInv.is())
1435 Reference<XSingleServiceFactory> xInvFactory= getInvocationFactory(rObj);
1436 if (xInvFactory.is())
1438 Sequence<Any> params(1);
1439 params.getArray()[0] = rObj;
1440 Reference<XInterface> xInt = xInvFactory->createInstanceWithArguments(params);
1441 xInv= Reference<XInvocation>(xInt, UNO_QUERY);
1445 if (xInv.is())
1447 Reference<XInterface> xNewWrapper = createUnoWrapperInstance();
1448 Reference<XInitialization> xInitWrapper(xNewWrapper, UNO_QUERY);
1449 if (xInitWrapper.is())
1451 VARTYPE vartype= getVarType( rObj);
1453 if (xInt.is())
1455 Any params[3];
1456 params[0] <<= xInv;
1457 params[1] <<= xInt;
1458 params[2] <<= vartype;
1459 xInitWrapper->initialize( Sequence<Any>(params, 3));
1461 else
1463 Any params[2];
1464 params[0] <<= xInv;
1465 params[1] <<= vartype;
1466 xInitWrapper->initialize( Sequence<Any>(params, 2));
1469 // put the newly created object into a map. If the same object will
1470 // be mapped again and there is already a wrapper then the old wrapper
1471 // will be used.
1472 if(xInt.is()) // only interfaces
1473 UnoObjToWrapperMap[(sal_uInt32) xInt.get()]= xNewWrapper;
1474 convertSelfToCom(xNewWrapper, pVar);
1475 return;
1480 template<class T>
1481 void UnoConversionUtilities<T>::variantToAny( const VARIANT* pVariant, Any& rAny,
1482 sal_Bool bReduceValueRange /* = sal_True */)
1484 HRESULT hr = S_OK;
1487 CComVariant var;
1489 // There is no need to support indirect values, since they're not supported by UNO
1490 if( FAILED(hr= VariantCopyInd( &var, const_cast<VARIANTARG*>(pVariant)))) // remove VT_BYREF
1491 throw BridgeRuntimeError(
1492 OUSTR("[automation bridge] UnoConversionUtilities<T>::variantToAny \n"
1493 "VariantCopyInd failed for reason : ") + OUString::valueOf(hr));
1495 if ( ! convertValueObject( & var, rAny))
1497 if ((var.vt & VT_ARRAY) > 0)
1499 VARTYPE oleTypeFlags = ::sal::static_int_cast< VARTYPE, int >( var.vt ^ VT_ARRAY );
1501 Sequence<Any> unoSeq = createOleArrayWrapper(var.parray, oleTypeFlags);
1502 rAny.setValue( &unoSeq, getCppuType( &unoSeq));
1504 else
1506 switch (var.vt)
1508 case VT_EMPTY:
1509 rAny.setValue(NULL, Type());
1510 break;
1511 case VT_NULL:
1512 rAny.setValue(NULL, Type());
1513 break;
1514 case VT_I2:
1515 rAny.setValue( & var.iVal, getCppuType( (sal_Int16*)0));
1516 break;
1517 case VT_I4:
1518 rAny.setValue( & var.lVal, getCppuType( (sal_Int32*)0));
1519 // necessary for use in JavaScript ( see "reduceRange")
1520 if( bReduceValueRange)
1521 reduceRange(rAny);
1522 break;
1523 case VT_R4:
1524 rAny.setValue( & var.fltVal, getCppuType( (float*)0));
1525 break;
1526 case VT_R8:
1527 rAny.setValue(& var.dblVal, getCppuType( (double*)0));
1528 break;
1529 case VT_CY:
1531 Currency cy(var.cyVal.int64);
1532 rAny <<= cy;
1533 break;
1535 case VT_DATE:
1537 Date d(var.date);
1538 rAny <<= d;
1539 break;
1541 case VT_BSTR:
1543 OUString b(reinterpret_cast<const sal_Unicode*>(var.bstrVal));
1544 rAny.setValue( &b, getCppuType( &b));
1545 break;
1547 case VT_UNKNOWN:
1548 case VT_DISPATCH:
1550 //check if it is a UNO type
1551 #ifdef __MINGW32__
1552 CComQIPtr<IUnoTypeWrapper, &__uuidof(IUnoTypeWrapper)> spType((IUnknown*) var.byref);
1553 #else
1554 CComQIPtr<IUnoTypeWrapper> spType((IUnknown*) var.byref);
1555 #endif
1556 if (spType)
1558 CComBSTR sName;
1559 if (FAILED(spType->get_Name(&sName)))
1560 throw BridgeRuntimeError(
1561 OUSTR("[automation bridge]UnoConversionUtilities<T>::variantToAny \n"
1562 "Failed to get the type name from a UnoTypeWrapper!"));
1563 Type type;
1564 if (getType(sName, type) == false)
1566 throw CannotConvertException(
1567 OUSTR("[automation bridge]UnoConversionUtilities<T>::variantToAny \n"
1568 "A UNO type with the name: ") + OUString(reinterpret_cast<const sal_Unicode*>(LPCOLESTR(sName))) +
1569 OUSTR("does not exist!"),
1570 0, TypeClass_UNKNOWN, FailReason::TYPE_NOT_SUPPORTED,0);
1572 rAny <<= type;
1574 else
1576 rAny = createOleObjectWrapper( & var);
1578 break;
1580 case VT_ERROR:
1582 SCode scode(var.scode);
1583 rAny <<= scode;
1584 break;
1586 case VT_BOOL:
1588 sal_Bool b= var.boolVal == VARIANT_TRUE;
1589 rAny.setValue( &b, getCppuType( &b));
1590 break;
1592 case VT_I1:
1593 rAny.setValue( & var.cVal, getCppuType((sal_Int8*)0));
1594 break;
1595 case VT_UI1: // there is no unsigned char in UNO
1596 rAny.setValue( & var.bVal, getCppuType( (sal_Int8*)0));
1597 break;
1598 case VT_UI2:
1599 rAny.setValue( & var.uiVal, getCppuType( (sal_uInt16*)0));
1600 break;
1601 case VT_UI4:
1602 rAny.setValue( & var.ulVal, getCppuType( (sal_uInt32*)0));
1603 break;
1604 case VT_INT:
1605 rAny.setValue( & var.intVal, getCppuType( (sal_Int32*)0));
1606 break;
1607 case VT_UINT:
1608 rAny.setValue( & var.uintVal, getCppuType( (sal_uInt32*)0));
1609 break;
1610 case VT_VOID:
1611 rAny.setValue( NULL, Type());
1612 break;
1613 case VT_DECIMAL:
1615 Decimal dec;
1616 dec.Scale = var.decVal.scale;
1617 dec.Sign = var.decVal.sign;
1618 dec.LowValue = var.decVal.Lo32;
1619 dec.MiddleValue = var.decVal.Mid32;
1620 dec.HighValue = var.decVal.Hi32;
1621 rAny <<= dec;
1622 break;
1625 default:
1626 break;
1631 catch (IllegalArgumentException & )
1633 throw;
1635 catch (CannotConvertException &)
1637 throw;
1639 catch (BridgeRuntimeError & )
1641 throw;
1643 catch (Exception & e)
1645 throw BridgeRuntimeError(OUSTR("[automation bridge] unexpected exception in "
1646 "UnoConversionUtilities<T>::variantToAny ! Message : \n") +
1647 e.Message);
1649 catch(...)
1651 throw BridgeRuntimeError(
1652 OUSTR("[automation bridge] unexpected exception in "
1653 "UnoConversionUtilities<T>::variantToAny !"));
1657 // The function converts an IUnknown* into an UNO interface or struct. The
1658 // IUnknown pointer can constitute different kind of objects:
1659 // 1. a wrapper of an UNO struct (the wrapper was created by this bridge)
1660 // 2. a wrapper of an UNO interface (created by this bridge)
1661 // 3. a dispatch object that implements UNO interfaces
1662 // 4. a dispatch object.
1664 // If the parameter "aType" has a value then the COM object ( pUnknown) is supposed to
1665 // implement the interface described by "aType". Moreover it ( pUnknown) can implement
1666 // several other
1667 // UNO interfaces in which case it has to support the SUPPORTED_INTERFACES_PROP (see
1668 // #define) property. That property contains all names of interfaces.
1669 // "pUnknown" is wrapped by a COM wrapper object that implements XInvocation, e.g.
1670 // IUnknownWrapper_Impl. Additionally an object of type "aType" is created by help
1671 // of the INTERFACE_ADAPTER_FACTORY (see #define) service. The implementation of
1672 // "aType" calls on the COM wrapper's XInvocation::invoke. If the COM object supports
1673 // more then one UNO interfaces, as can be determined by the property
1674 // SUPPORTED_INTERFACES_PROP, then the INTERFACE_ADAPTER_FACTORY creates an object that
1675 // implements all these interfaces.
1676 // This is only done if "pUnknown" is not already a UNO wrapper,
1677 // that is it is actually NOT an UNO object that was converted to a COM object. If it is an
1678 // UNO wrapper than the original UNO object is being extracted, queried for "aType" (if
1679 // it is no struct) and returned.
1680 template<class T>
1681 #ifdef __MINGW32__
1682 Any UnoConversionUtilities<T>::createOleObjectWrapper(VARIANT* pVar, const Type& aType)
1683 #else
1684 Any UnoConversionUtilities<T>::createOleObjectWrapper(VARIANT* pVar, const Type& aType= Type())
1685 #endif
1687 //To allow passing "Nothing" in VS 2008 we need to accept VT_EMPTY
1688 if (pVar->vt != VT_UNKNOWN && pVar->vt != VT_DISPATCH && pVar->vt != VT_EMPTY)
1689 throw IllegalArgumentException(
1690 OUSTR("[automation bridge]UnoConversionUtilities<T>::createOleObjectWrapper \n"
1691 "The VARIANT does not contain an object type! "), 0, -1);
1693 MutexGuard guard( getBridgeMutex());
1695 CComPtr<IUnknown> spUnknown;
1696 CComPtr<IDispatch> spDispatch;
1698 if (pVar->vt == VT_UNKNOWN)
1700 spUnknown = pVar->punkVal;
1701 if (spUnknown)
1702 #ifdef __MINGW32__
1703 spUnknown->QueryInterface( IID_IDispatch, reinterpret_cast<LPVOID*>( & spDispatch.p));
1704 #else
1705 spUnknown.QueryInterface( & spDispatch.p);
1706 #endif
1708 else if (pVar->vt == VT_DISPATCH && pVar->pdispVal != NULL)
1710 CComPtr<IDispatch> spDispatch(pVar->pdispVal);
1711 if (spDispatch)
1712 #ifdef __MINGW32__
1713 spDispatch->QueryInterface( IID_IUnknown, reinterpret_cast<LPVOID*>( & spUnknown.p));
1714 #else
1715 spDispatch.QueryInterface( & spUnknown.p);
1716 #endif
1719 static Type VOID_TYPE= Type();
1720 Any ret;
1721 //If no Type is provided and pVar contains IUnknown then we return a XInterface.
1722 //If pVar contains an IDispatch then we return a XInvocation.
1723 Type desiredType = aType;
1725 if (aType == VOID_TYPE)
1727 switch (pVar->vt)
1729 case VT_EMPTY:
1730 case VT_UNKNOWN:
1731 desiredType = getCppuType((Reference<XInterface>*) 0);
1732 break;
1733 case VT_DISPATCH:
1734 desiredType = getCppuType((Reference<XInvocation>*) 0);
1735 break;
1736 default:
1737 desiredType = aType;
1741 // COM pointer are NULL, no wrapper required
1742 if (spUnknown == NULL)
1744 Reference<XInterface> xInt;
1745 if( aType.getTypeClass() == TypeClass_INTERFACE)
1746 ret.setValue( &xInt, aType);
1747 else if( aType.getTypeClass() == TypeClass_STRUCT)
1748 ret.setValue( NULL, aType);
1749 else
1750 ret <<= xInt;
1751 return ret;
1755 // Check if "spUnknown" is a UNO wrapper, that is an UNO object that has been
1756 // passed to COM. Then it supports IUnoObjectWrapper
1757 // and we extract the original UNO object.
1758 #ifdef __MINGW32__
1759 CComQIPtr<IUnoObjectWrapper, &__uuidof(IUnoObjectWrapper)> spUno( spUnknown);
1760 #else
1761 CComQIPtr<IUnoObjectWrapper> spUno( spUnknown);
1762 #endif
1763 if( spUno)
1764 { // it is a wrapper
1765 Reference<XInterface> xInt;
1766 if( SUCCEEDED( spUno->getOriginalUnoObject( &xInt)))
1768 ret <<= xInt;
1770 else
1772 Any any;
1773 if( SUCCEEDED( spUno->getOriginalUnoStruct(&any)))
1774 ret= any;
1776 return ret;
1779 // "spUnknown" is a real COM object.
1780 // Before we create a new wrapper object we check if there is an existing wrapper
1781 // There can be two kinds of wrappers, those who wrap dispatch - UNO objects, and those who
1782 // wrap ordinary dispatch objects. The dispatch-UNO objects usually are adapted to represent
1783 // particular UNO interfaces.
1784 Reference<XInterface> xIntWrapper;
1785 CIT_Com cit_currWrapper= ComPtrToWrapperMap.find( reinterpret_cast<sal_uInt32>(spUnknown.p));
1786 if(cit_currWrapper != ComPtrToWrapperMap.end())
1787 xIntWrapper = cit_currWrapper->second;
1788 if (xIntWrapper.is())
1790 //Try to find an adapter for the wrapper
1791 //find the proper Adapter. The pointer in the WrapperToAdapterMap are valid as long as
1792 //we get a pointer to the wrapper from ComPtrToWrapperMap, because the Adapter hold references
1793 //to the wrapper.
1794 CIT_Wrap it = WrapperToAdapterMap.find((sal_uInt32) xIntWrapper.get());
1795 if (it == WrapperToAdapterMap.end())
1797 // No adapter available.
1798 //The COM component could be a UNO object. Then we need to provide
1799 // a proxy that implements all interfaces
1800 Sequence<Type> seqTypes= getImplementedInterfaces(spUnknown);
1801 Reference<XInterface> xIntAdapter;
1802 if (seqTypes.getLength() > 0)
1804 //It is a COM UNO object
1805 xIntAdapter = createAdapter(seqTypes, xIntWrapper);
1807 else
1809 // Some ordinary COM object
1810 xIntAdapter = xIntWrapper;
1812 // return the wrapper directly, return XInterface or XInvocation
1813 ret = xIntWrapper->queryInterface(desiredType);
1814 if ( ! ret.hasValue())
1815 throw IllegalArgumentException(
1816 OUSTR("[automation bridge]UnoConversionUtilities<T>::createOleObjectWrapper \n"
1817 "The COM object is not suitable for the UNO type: ") +
1818 desiredType.getTypeName(), 0, -1);
1820 else
1822 //There is an adapter available
1823 Reference<XInterface> xIntAdapter((XInterface*) it->second);
1824 ret = xIntAdapter->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);
1832 return ret;
1834 // No existing wrapper. Therefore create a new proxy.
1835 // If the object implements UNO interfaces then get the types.
1836 Sequence<Type> seqTypes = getImplementedInterfaces(spUnknown);
1837 if (seqTypes.getLength() == 0 &&
1838 aType != VOID_TYPE && aType != getCppuType((Reference<XInvocation>*)0))
1840 seqTypes = Sequence<Type>( & aType, 1);
1843 //There is no existing wrapper, therefore we create one for the real COM object
1844 Reference<XInterface> xIntNewProxy= createComWrapperInstance();
1845 if ( ! xIntNewProxy.is())
1846 throw BridgeRuntimeError(
1847 OUSTR("[automation bridge]UnoConversionUtilities<T>::createOleObjectWrapper \n"
1848 "Could not create proxy object for COM object!"));
1850 // initialize the COM wrapper
1851 Reference<XInitialization> xInit( xIntNewProxy, UNO_QUERY);
1852 OSL_ASSERT( xInit.is());
1854 Any params[3];
1855 #ifdef __MINGW32__
1856 params[0] <<= reinterpret_cast<sal_uInt32>( spUnknown.p );
1857 #else
1858 params[0] <<= (sal_uInt32) spUnknown.p;
1859 #endif
1860 sal_Bool bDisp = pVar->vt == VT_DISPATCH ? sal_True : sal_False;
1861 params[1].setValue( & bDisp, getBooleanCppuType());
1862 params[2] <<= seqTypes;
1864 xInit->initialize( Sequence<Any>( params, 3));
1865 #ifdef __MINGW32__
1866 ComPtrToWrapperMap[reinterpret_cast<sal_uInt32>( spUnknown.p )]= xIntNewProxy;
1867 #else
1868 ComPtrToWrapperMap[reinterpret_cast<sal_uInt32>(spUnknown.p)]= xIntNewProxy;
1869 #endif
1871 // we have a wrapper object
1872 //The wrapper implements already XInvocation and XInterface. If
1873 //param aType is void then the object is supposed to have XInvocation.
1874 if (aType == getCppuType((Reference<XInvocation>*)0) ||
1875 (aType == VOID_TYPE && seqTypes.getLength() == 0 ))
1877 ret = xIntNewProxy->queryInterface(desiredType);
1879 else
1881 Reference<XInterface> xIntAdapter =
1882 createAdapter(seqTypes, xIntNewProxy);
1883 ret = xIntAdapter->queryInterface(desiredType);
1885 return ret;
1887 template<class T>
1888 Reference<XInterface> UnoConversionUtilities<T>::createAdapter(const Sequence<Type>& seqTypes,
1889 const Reference<XInterface>& receiver)
1891 Reference< XInterface> xIntAdapterFac;
1892 xIntAdapterFac= m_smgr->createInstance(INTERFACE_ADAPTER_FACTORY);
1893 // We create an adapter object that does not only implement the required type but also
1894 // all types that the COM object pretends to implement. An COM object must therefore
1895 // support the property "_implementedInterfaces".
1896 Reference<XInterface> xIntAdapted;
1897 Reference<XInvocation> xInv(receiver, UNO_QUERY);
1898 Reference<XInvocationAdapterFactory2> xAdapterFac( xIntAdapterFac, UNO_QUERY);
1899 if( xAdapterFac.is())
1900 xIntAdapted= xAdapterFac->createAdapter( xInv, seqTypes);
1902 if( xIntAdapted.is())
1904 // Put the pointer to the wrapper object and the interface pointer of the adapted interface
1905 // in a global map. Thus we can determine in a call to createUnoObjectWrapper whether the UNO
1906 // object is a wrapped COM object. In that case we extract the original COM object rather than
1907 // creating a wrapper around the UNO object.
1908 typedef hash_map<sal_uInt32,sal_uInt32>::value_type VALUE;
1909 AdapterToWrapperMap.insert( VALUE( (sal_uInt32) xIntAdapted.get(), (sal_uInt32) receiver.get()));
1910 WrapperToAdapterMap.insert( VALUE( (sal_uInt32) receiver.get(), (sal_uInt32) xIntAdapted.get()));
1912 else
1914 throw BridgeRuntimeError(
1915 OUSTR("[automation bridge]UnoConversionUtilities<T>::createOleObjectWrapper \n"
1916 "Could not create a proxy for COM object! Creation of adapter failed."));
1918 return xIntAdapted;
1920 // "convertValueObject" converts a JScriptValue object contained in "var" into
1921 // an any. The type contained in the any is stipulated by a "type value" thas
1922 // was set within the JScript script on the value object ( see JScriptValue).
1923 template<class T>
1924 bool UnoConversionUtilities<T>::convertValueObject( const VARIANTARG *var, Any& any)
1926 bool ret = false;
1929 bool bFail = false;
1930 HRESULT hr= S_OK;
1931 CComVariant varDisp;
1933 if(SUCCEEDED(hr = varDisp.ChangeType( VT_DISPATCH, var)))
1935 CComPtr <IJScriptValueObject> spValue;
1936 VARIANT_BOOL varBool;
1937 CComBSTR bstrType;
1938 CComVariant varValue;
1939 CComPtr<IDispatch> spDisp( varDisp.pdispVal);
1940 if(spDisp)
1942 if(SUCCEEDED( spDisp->QueryInterface( __uuidof( IJScriptValueObject),
1943 reinterpret_cast<void**> (&spValue))))
1945 ret = true; // is is a ValueObject
1946 //If it is an out - param then it does not need to be converted. In/out and
1947 // in params does so.
1948 if (SUCCEEDED(hr= spValue->IsOutParam( &varBool)))
1950 // if varBool == true then no conversion needed because out param
1951 if (varBool == VARIANT_FALSE)
1953 if(SUCCEEDED(hr = spValue->GetValue( & bstrType, & varValue)))
1955 Type type;
1956 if (getType(bstrType, type))
1957 variantToAny( & varValue, any, type);
1958 else
1959 bFail = true;
1961 else
1962 bFail = true;
1965 else
1966 bFail = true;;
1970 else if( hr != DISP_E_TYPEMISMATCH && hr != E_NOINTERFACE)
1971 bFail = true;
1973 if (bFail)
1974 throw BridgeRuntimeError(
1975 OUSTR("[automation bridge] Conversion of ValueObject failed "));
1977 catch (BridgeRuntimeError &)
1979 throw;
1981 catch (Exception & e)
1983 throw BridgeRuntimeError(OUSTR("[automation bridge] unexpected exception in "
1984 "UnoConversionUtilities<T>::convertValueObject ! Message : \n") +
1985 e.Message);
1987 catch(...)
1989 throw BridgeRuntimeError(
1990 OUSTR("[automation bridge] unexpected exception in "
1991 "UnoConversionUtilities<T>::convertValueObject !"));
1993 return ret;
1996 template<class T>
1997 void UnoConversionUtilities<T>::dispatchExObject2Sequence( const VARIANTARG* pvar, Any& anySeq, const Type& type)
2001 bool bFail = false;
2002 if( pvar->vt != VT_DISPATCH)
2003 throw BridgeRuntimeError(OUSTR("[automation bridge] UnoConversionUtilities<T>::dispatchExObject2Sequence \n"
2004 "Conversion of dispatch object to Sequence failed!"));
2005 IDispatchEx* pdispEx;
2006 HRESULT hr;
2007 if( FAILED( hr= pvar->pdispVal->QueryInterface( IID_IDispatchEx,
2008 reinterpret_cast<void**>( &pdispEx))))
2009 throw BridgeRuntimeError(OUSTR("[automation bridge] UnoConversionUtilities<T>::dispatchExObject2Sequence \n"
2010 "Conversion of dispatch object to Sequence failed!"));
2012 DISPID dispid;
2013 OUString sindex;
2014 DISPPARAMS param= {0,0,0,0};
2015 CComVariant result;
2017 OLECHAR* sLength= L"length";
2019 // Get the length of the array. Can also be obtained throu GetNextDispID. The
2020 // method only returns DISPIDs of the array data. Their names are like "0", "1" etc.
2021 if( FAILED( hr= pdispEx->GetIDsOfNames(IID_NULL, &sLength , 1, LOCALE_USER_DEFAULT, &dispid)))
2022 throw BridgeRuntimeError(OUSTR("[automation bridge] UnoConversionUtilities<T>::dispatchExObject2Sequence \n"
2023 "Conversion of dispatch object to Sequence failed!"));
2024 if( FAILED( hr= pdispEx->InvokeEx(dispid, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET,
2025 &param, &result, NULL, NULL)))
2026 throw BridgeRuntimeError(OUSTR("[automation bridge] UnoConversionUtilities<T>::dispatchExObject2Sequence \n"
2027 "Conversion of dispatch object to Sequence failed!"));
2028 if( FAILED( VariantChangeType( &result, &result, 0, VT_I4)))
2029 throw BridgeRuntimeError(OUSTR("[automation bridge] UnoConversionUtilities<T>::dispatchExObject2Sequence \n"
2030 "Conversion of dispatch object to Sequence failed!"));
2031 long length= result.lVal;
2033 result.Clear();
2035 // get a few basic facts about the sequence, and reallocate:
2036 // create the Sequences
2037 // get the size of the elements
2038 typelib_TypeDescription *pDesc= NULL;
2039 type.getDescription( &pDesc);
2041 typelib_IndirectTypeDescription *pSeqDesc= reinterpret_cast<typelib_IndirectTypeDescription*>(pDesc);
2042 typelib_TypeDescriptionReference *pSeqElemDescRef= pSeqDesc->pType; // type of the Sequence' elements
2043 Type elemType( pSeqElemDescRef);
2044 _typelib_TypeDescription* pSeqElemDesc=NULL;
2045 TYPELIB_DANGER_GET( &pSeqElemDesc, pSeqElemDescRef)
2046 sal_uInt32 nelementSize= pSeqElemDesc->nSize;
2047 TYPELIB_DANGER_RELEASE( pSeqElemDesc)
2049 uno_Sequence *p_uno_Seq;
2050 uno_sequence_construct( &p_uno_Seq, pDesc, NULL, length, cpp_acquire);
2052 typelib_TypeClass typeElement= pSeqDesc->pType->eTypeClass;
2053 char *pArray= p_uno_Seq->elements;
2055 // Get All properties in the object, convert their values to the expected type and
2056 // put them into the passed in sequence
2057 for( sal_Int32 i= 0; i< length; i++)
2059 OUString ousIndex=OUString::valueOf( i);
2060 OLECHAR* sindex = (OLECHAR*)ousIndex.getStr();
2062 if( FAILED( hr= pdispEx->GetIDsOfNames(IID_NULL, &sindex , 1, LOCALE_USER_DEFAULT, &dispid)))
2064 throw BridgeRuntimeError(OUSTR("[automation bridge] UnoConversionUtilities<T>::dispatchExObject2Sequence \n"
2065 "Conversion of dispatch object to Sequence failed!"));
2067 if( FAILED( hr= pdispEx->InvokeEx(dispid, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET,
2068 &param, &result, NULL, NULL)))
2070 throw BridgeRuntimeError(OUSTR("[automation bridge] UnoConversionUtilities<T>::dispatchExObject2Sequence \n"
2071 "Conversion of dispatch object to Sequence failed!"));
2074 // If the result is VT_DISPATCH than the Sequence's element type could be Sequence
2075 // Look that up in the CoreReflection to make clear.
2076 // That requires a recursiv conversion
2077 Any any;
2078 // Destination address within the out-Sequence "anySeq" where to copy the next converted element
2079 void* pDest= (void*)(pArray + (i * nelementSize));
2081 if( result.vt & VT_DISPATCH && typeElement == typelib_TypeClass_SEQUENCE)
2083 variantToAny( &result, any, elemType, sal_False);
2084 // copy the converted VARIANT, that is a Sequence to the Sequence
2085 uno_Sequence * p_unoSeq= *(uno_Sequence**)any.getValue();
2086 // just copy the pointer of the uno_Sequence
2087 // nelementSize should be 4 !!!!
2088 memcpy( pDest, &p_unoSeq, nelementSize);
2089 osl_incrementInterlockedCount( &p_unoSeq->nRefCount);
2091 else // Element type is no Sequence -> do one conversion
2093 variantToAny( &result, any, elemType, sal_False);
2094 if( typeElement == typelib_TypeClass_ANY)
2096 // copy the converted VARIANT to the Sequence
2097 uno_type_assignData( pDest, pSeqElemDescRef , &any, pSeqElemDescRef,cpp_queryInterface,
2098 cpp_acquire, cpp_release);
2100 else
2102 // type after conversion must be the element type of the sequence
2103 OSL_ENSURE( (any.getValueTypeClass() == typeElement), "wrong conversion");
2104 uno_type_assignData( pDest, pSeqElemDescRef,const_cast<void*>( any.getValue()), any.getValueTypeRef(),
2105 cpp_queryInterface, cpp_acquire, cpp_release);
2108 } // else
2109 result.Clear();
2110 anySeq.setValue( &p_uno_Seq, pDesc);
2111 uno_destructData( &p_uno_Seq, pDesc, cpp_release);
2112 typelib_typedescription_release( pDesc);
2114 if (bFail)
2115 throw BridgeRuntimeError(
2116 OUSTR("[automation bridge] Conversion of ValueObject failed "));
2118 catch (BridgeRuntimeError & )
2120 throw;
2122 catch (Exception & e)
2124 throw BridgeRuntimeError(OUSTR("[automation bridge] unexpected exception in "
2125 "UnoConversionUtilities<T>::convertValueObject ! Message : \n") +
2126 e.Message);
2128 catch(...)
2130 throw BridgeRuntimeError(
2131 OUSTR("[automation bridge] unexpected exception in "
2132 "UnoConversionUtilities<T>::convertValueObject !"));
2136 /* The argument unotype is the type that is expected by the currently called UNO function.
2137 For example: []long, [][]long. If the function calls itself recursively then the element type
2138 is passed on. For example a two dimensional SAFEARRAY of type VT_I4 is to be converted. Then
2139 unotype has to be either void or [][]long. When the function calls itself recursivly then
2140 it passes the element type which is []long.
2142 template<class T>
2143 Sequence<Any> UnoConversionUtilities<T>::createOleArrayWrapperOfDim(SAFEARRAY* pArray,
2144 unsigned int dimCount, unsigned int actDim, long* index, VARTYPE type, const Type& unotype)
2146 HRESULT hr= S_OK;
2147 long lBound;
2148 long uBound;
2149 long nCountElements;
2151 SafeArrayGetLBound(pArray, actDim, &lBound);
2152 SafeArrayGetUBound(pArray, actDim, &uBound);
2153 nCountElements= uBound - lBound +1;
2155 Sequence<Any> anySeq(nCountElements);
2156 Any* pUnoArray = anySeq.getArray();
2158 for (index[actDim - 1] = lBound; index[actDim - 1] <= uBound; index[actDim - 1]++)
2160 if (actDim > 1 )
2162 Sequence<Any> element = createOleArrayWrapperOfDim(pArray, dimCount,
2163 actDim - 1, index, type, getElementTypeOfSequence(unotype));
2165 pUnoArray[index[actDim - 1] - lBound].setValue(&element, getCppuType(&element));
2167 else
2169 VARIANT variant;
2171 VariantInit(&variant);
2173 V_VT(&variant) = type;
2175 switch (type)
2177 case VT_I2:
2178 SafeArrayGetElement(pArray, index, &V_I2(&variant));
2179 break;
2180 case VT_I4:
2181 SafeArrayGetElement(pArray, index, &V_I4(&variant));
2182 break;
2183 case VT_R4:
2184 SafeArrayGetElement(pArray, index, &V_R4(&variant));
2185 break;
2186 case VT_R8:
2187 SafeArrayGetElement(pArray, index, &V_R8(&variant));
2188 break;
2189 case VT_CY:
2190 SafeArrayGetElement(pArray, index, &V_CY(&variant));
2191 break;
2192 case VT_DATE:
2193 SafeArrayGetElement(pArray, index, &V_DATE(&variant));
2194 break;
2195 case VT_BSTR:
2196 hr= SafeArrayGetElement(pArray, index, &V_BSTR(&variant));
2197 break;
2198 case VT_DISPATCH:
2199 SafeArrayGetElement(pArray, index, &V_DISPATCH(&variant));
2200 break;
2201 case VT_ERROR:
2202 SafeArrayGetElement(pArray, index, &V_ERROR(&variant));
2203 break;
2204 case VT_BOOL:
2205 SafeArrayGetElement(pArray, index, &V_BOOL(&variant));
2206 break;
2207 case VT_VARIANT:
2208 SafeArrayGetElement(pArray, index, &variant);
2209 break;
2210 case VT_UNKNOWN:
2211 SafeArrayGetElement(pArray, index, &V_UNKNOWN(&variant));
2212 break;
2213 case VT_I1:
2214 SafeArrayGetElement(pArray, index, &V_I1(&variant));
2215 break;
2216 case VT_UI1:
2217 SafeArrayGetElement(pArray, index, &V_UI1(&variant));
2218 break;
2219 case VT_UI2:
2220 SafeArrayGetElement(pArray, index, &V_UI2(&variant));
2221 break;
2222 case VT_UI4:
2223 SafeArrayGetElement(pArray, index, &V_UI4(&variant));
2224 break;
2225 default:
2226 break;
2229 if( unotype.getTypeClass() == TypeClass_VOID)
2230 // the function was called without specifying the destination type
2231 variantToAny(&variant, pUnoArray[index[actDim - 1] - lBound], sal_False);
2232 else
2233 variantToAny(&variant, pUnoArray[index[actDim - 1] - lBound],
2234 getElementTypeOfSequence(unotype), sal_False);
2236 VariantClear(&variant);
2239 return anySeq;
2242 template<class T>
2243 Type UnoConversionUtilities<T>::getElementTypeOfSequence( const Type& seqType)
2245 Type retValue;
2246 if( seqType.getTypeClass() != TypeClass_VOID)
2248 OSL_ASSERT( seqType.getTypeClass() == TypeClass_SEQUENCE);
2249 typelib_IndirectTypeDescription* pDescSeq= NULL;
2250 seqType.getDescription((typelib_TypeDescription** ) & pDescSeq);
2251 retValue = Type(pDescSeq->pType);
2252 typelib_typedescription_release( (typelib_TypeDescription*) pDescSeq);
2254 return retValue;
2256 template<class T>
2257 Sequence<Any> UnoConversionUtilities<T>::createOleArrayWrapper(SAFEARRAY* pArray, VARTYPE type, const Type& unoType)
2259 sal_uInt32 dim = SafeArrayGetDim(pArray);
2261 Sequence<Any> ret;
2263 if (dim > 0)
2265 scoped_array<long> sarIndex(new long[dim]);
2266 long * index = sarIndex.get();
2268 for (unsigned int i = 0; i < dim; i++)
2270 index[i] = 0;
2273 ret = createOleArrayWrapperOfDim(pArray, dim, dim, index, type, unoType);
2276 return ret;
2279 // If an VARIANT has the type VT_DISPATCH it can either be an JScript Array
2280 // or some other object. This function finds out if it is such an array or
2281 // not. Currently there's no way to make sure it's an array
2282 // so we assume that when the object has a property "0" then it is an Array.
2283 // An JScript has property like "0", "1", "2" etc. which represent the
2284 // value at the corresponding index of the array
2285 template<class T>
2286 sal_Bool UnoConversionUtilities<T>::isJScriptArray(const VARIANT* rvar)
2288 OSL_ENSURE( rvar->vt == VT_DISPATCH, "param is not a VT_DISPATCH");
2289 HRESULT hr;
2290 OLECHAR* sindex= L"0";
2291 DISPID id;
2292 if ( rvar->vt == VT_DISPATCH && rvar->pdispVal )
2294 hr= rvar->pdispVal->GetIDsOfNames( IID_NULL, &sindex, 1,
2295 LOCALE_USER_DEFAULT, &id);
2297 if( SUCCEEDED ( hr) )
2298 return sal_True;
2301 return sal_False;
2304 template<class T>
2305 VARTYPE UnoConversionUtilities<T>::mapTypeClassToVartype( TypeClass type)
2307 VARTYPE ret;
2308 switch( type)
2310 case TypeClass_INTERFACE: ret= VT_DISPATCH;
2311 break;
2312 case TypeClass_STRUCT: ret= VT_DISPATCH;
2313 break;
2314 case TypeClass_ENUM: ret= VT_I4;
2315 break;
2316 case TypeClass_SEQUENCE: ret= VT_ARRAY;
2317 break;
2318 case TypeClass_ANY: ret= VT_VARIANT;
2319 break;
2320 case TypeClass_BOOLEAN: ret= VT_BOOL;
2321 break;
2322 case TypeClass_CHAR: ret= VT_I2;
2323 break;
2324 case TypeClass_STRING: ret= VT_BSTR;
2325 break;
2326 case TypeClass_FLOAT: ret= VT_R4;
2327 break;
2328 case TypeClass_DOUBLE: ret= VT_R8;
2329 break;
2330 case TypeClass_BYTE: ret= VT_UI1;
2331 break;
2332 case TypeClass_SHORT: ret= VT_I2;
2333 break;
2334 case TypeClass_LONG: ret= VT_I4;
2335 break;
2336 case TypeClass_UNSIGNED_SHORT: ret= VT_UI2;
2337 break;
2338 case TypeClass_UNSIGNED_LONG: ret= VT_UI4;
2339 break;
2340 default:
2341 ret= VT_EMPTY;
2343 return ret;
2346 template<class T>
2347 Sequence<Type> UnoConversionUtilities<T>::getImplementedInterfaces(IUnknown* pUnk)
2349 Sequence<Type> seqTypes;
2350 CComDispatchDriver disp( pUnk);
2351 if( disp)
2353 CComVariant var;
2354 HRESULT hr= S_OK;
2355 // There are two different property names possible.
2356 if( FAILED( hr= disp.GetPropertyByName( SUPPORTED_INTERFACES_PROP, &var)))
2358 hr= disp.GetPropertyByName( SUPPORTED_INTERFACES_PROP2, &var);
2360 if (SUCCEEDED( hr))
2362 // we exspect an array( SafeArray or IDispatch) of Strings.
2363 Any anyNames;
2364 variantToAny( &var, anyNames, getCppuType( (Sequence<Any>*) 0));
2365 Sequence<Any> seqAny;
2366 if( anyNames >>= seqAny)
2368 seqTypes.realloc( seqAny.getLength());
2369 for( sal_Int32 i=0; i < seqAny.getLength(); i++)
2371 OUString typeName;
2372 seqAny[i] >>= typeName;
2373 seqTypes[i]= Type( TypeClass_INTERFACE, typeName);
2378 return seqTypes;
2380 template<class T>
2381 Reference<XTypeConverter> UnoConversionUtilities<T>::getTypeConverter()
2383 if ( ! m_typeConverter.is())
2385 MutexGuard guard(getBridgeMutex());
2386 if ( ! m_typeConverter.is())
2388 Reference<XInterface> xIntConverter =
2389 m_smgr->createInstance(OUSTR("com.sun.star.script.Converter"));
2390 if (xIntConverter.is())
2391 m_typeConverter = Reference<XTypeConverter>(xIntConverter, UNO_QUERY);
2394 return m_typeConverter;
2397 // This function tries to the change the type of a value (contained in the Any)
2398 // to the smallest possible that can hold the value. This is actually done only
2399 // for types of VT_I4 (see o2u_variantToAny). The reason is the following:
2400 // JavaScript passes integer values always as VT_I4. If there is a parameter or
2401 // property of type any then the bridge converts the any's content according
2402 // to "o2u_variantToAny". Because the VARTYPE is VT_I4 the value would be converted
2403 // to TypeClass_LONG. Say the method XPropertySet::setPropertyValue( string name, any value)
2404 // would be called on an object and the property actually is of TypeClass_SHORT.
2405 // After conversion of the VARIANT parameter the Any would contain type
2406 // TypeClass_LONG. Because the corereflection does not cast from long to short
2407 // the "setPropertValue" would fail as the value has not the right type.
2409 // The corereflection does convert small integer types to bigger types.
2410 // Therefore we can reduce the type if possible and avoid the above mentioned
2411 // problem.
2413 // The function is not used when elements are to be converted for Sequences.
2415 #ifndef _REDUCE_RANGE
2416 #define _REDUCE_RANGE
2417 inline void reduceRange( Any& any)
2419 OSL_ASSERT( any.getValueTypeClass() == TypeClass_LONG);
2421 sal_Int32 value= *(sal_Int32*)any.getValue();
2422 if( value <= 0x7f && value >= -0x80)
2423 {// -128 bis 127
2424 sal_Int8 charVal= static_cast<sal_Int8>( value);
2425 any.setValue( &charVal, getCppuType( (sal_Int8*)0));
2427 else if( value <= 0x7fff && value >= -0x8000)
2428 {// -32768 bis 32767
2429 sal_Int16 shortVal= static_cast<sal_Int16>( value);
2430 any.setValue( &shortVal, getCppuType( (sal_Int16*)0));
2433 #endif
2437 } // end namespace
2438 #endif