1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 #ifndef INCLUDED_EXTENSIONS_SOURCE_OLE_UNOCONVERSIONUTILITIES_HXX
20 #define INCLUDED_EXTENSIONS_SOURCE_OLE_UNOCONVERSIONUTILITIES_HXX
21 
22 #include <memory>
23 #include <com/sun/star/script/XInvocationAdapterFactory.hpp>
24 #include <com/sun/star/script/XInvocationAdapterFactory2.hpp>
25 #include <com/sun/star/script/XTypeConverter.hpp>
26 #include <com/sun/star/script/FailReason.hpp>
27 #include <com/sun/star/bridge/oleautomation/Date.hpp>
28 #include <com/sun/star/bridge/oleautomation/Currency.hpp>
29 #include <com/sun/star/bridge/oleautomation/SCode.hpp>
30 #include <com/sun/star/bridge/oleautomation/Decimal.hpp>
31 #include <typelib/typedescription.hxx>
32 #include <o3tl/any.hxx>
33 #include <o3tl/char16_t2wchar_t.hxx>
34 #include "ole2uno.hxx"
35 #include <cppuhelper/weakref.hxx>
36 
37 #include "unotypewrapper.hxx"
38 #include <unordered_map>
39 
40 // for some reason DECIMAL_NEG (wtypes.h) which contains BYTE is not resolved.
41 typedef unsigned char   BYTE;
42 // classes for wrapping uno objects
43 #define INTERFACE_OLE_WRAPPER_IMPL      1
44 #define UNO_OBJECT_WRAPPER_REMOTE_OPT   2
45 
46 #define INVOCATION_SERVICE "com.sun.star.script.Invocation"
47 
48 
49 // classes for wrapping ole objects
50 #define IUNKNOWN_WRAPPER_IMPL           1
51 
52 #define INTERFACE_ADAPTER_FACTORY  "com.sun.star.script.InvocationAdapterFactory"
53 // COM or JScript objects implementing UNO interfaces have to implement this property
54 #define SUPPORTED_INTERFACES_PROP L"_implementedInterfaces"
55 // Second property without leading underscore for use in VB
56 #define SUPPORTED_INTERFACES_PROP2 L"Bridge_ImplementedInterfaces"
57 
58 using namespace com::sun::star::script;
59 using namespace com::sun::star::beans;
60 using namespace com::sun::star::uno;
61 using namespace com::sun::star::bridge::oleautomation;
62 
63 extern std::unordered_map<sal_uIntPtr, sal_uIntPtr> AdapterToWrapperMap;
64 extern std::unordered_map<sal_uIntPtr, sal_uIntPtr> WrapperToAdapterMap;
65 
66 //Maps IUnknown pointers to a weak reference of the respective wrapper class (e.g.
67 // IUnknownWrapperImpl. It is the responsibility of the wrapper to remove the entry when
68 // it is being destroyed.
69 // Used to ensure that an Automation object is always mapped to the same UNO objects.
70 extern std::unordered_map<sal_uIntPtr, WeakReference<XInterface> > ComPtrToWrapperMap;
71 
72 // Maps XInterface pointers to a weak reference of its wrapper class (i.e.
73 // InterfaceOleWrapper). It is the responsibility of the wrapper to remove the entry when
74 // it is being destroyed. It is used to ensure the identity of objects. That is, a UNO interface
75 // is mapped to IDispatch which is kept alive in the COM environment. If the same
76 // UNO interface is mapped again to COM then the IDispach of the first mapped instance
77 // must be returned.
78 extern std::unordered_map<sal_uIntPtr, WeakReference<XInterface> > UnoObjToWrapperMap;
79 
80 // createUnoObjectWrapper gets a wrapper instance by calling createUnoWrapperInstance
81     // and initializes it via XInitialization. The wrapper object is required to implement
82     // XBridgeSupplier so that it can convert itself to IDispatch.
83     // class T: Deriving class ( must implement XInterface )
84 /** All methods are allowed to throw at least a BridgeRuntimeError.
85  */
86 template< class >
87 class UnoConversionUtilities
88 {
89 public:
UnoConversionUtilities(const Reference<XMultiServiceFactory> & smgr)90     explicit UnoConversionUtilities( const Reference<XMultiServiceFactory> & smgr):
91         m_nUnoWrapperClass( INTERFACE_OLE_WRAPPER_IMPL),
92         m_nComWrapperClass( IUNKNOWN_WRAPPER_IMPL),
93         m_smgr( smgr)
94     {}
95 
UnoConversionUtilities(const Reference<XMultiServiceFactory> & xFactory,sal_uInt8 unoWrapperClass,sal_uInt8 comWrapperClass)96     UnoConversionUtilities( const Reference<XMultiServiceFactory> & xFactory, sal_uInt8 unoWrapperClass, sal_uInt8 comWrapperClass )
97         : m_nUnoWrapperClass(unoWrapperClass),
98           m_nComWrapperClass(comWrapperClass), m_smgr(xFactory)
99     {}
100 
~UnoConversionUtilities()101     virtual ~UnoConversionUtilities() {}
102     /** converts only into oleautomation types, that is there is no VT_I1, VT_UI2, VT_UI4
103         a sal_Unicode character is converted into a BSTR.
104         @exception com.sun.star.lang.IllegalArgumentException
105         If the any was inappropriate for conversion.
106         @exception com.sun.star.script.CannotConvertException
107         The any contains a type class for which no conversion is provided.
108     */
109     void anyToVariant(VARIANT* pVariant, const Any& rAny);
110     void anyToVariant(VARIANT* pVariant, const Any& rAny, VARTYPE type);
111 
112     /** @exception com.sun.star.lang.IllegalArgumentException
113         If rSeq does not contain a sequence then the exception is thrown.
114     */
115     SAFEARRAY*  createUnoSequenceWrapper(const Any& rSeq);
116     /** @exception com.sun.star.lang.IllegalArgumentException
117         If rSeq does not contain a sequence or elemtype has no proper value
118         then the exception is thrown.
119     */
120     SAFEARRAY*  createUnoSequenceWrapper(const Any& rSeq, VARTYPE elemtype);
121     /**
122        @exception com.sun.star.lang.IllegalArgumentException
123        If rObj does not contain a struct or interface
124      */
125     void createUnoObjectWrapper(const Any & rObj, VARIANT * pVar);
126     /** @exception CannotConvertException
127         Thrown if the VARIANT contains a type that cannot be coerced in the expected Any.
128         ArgumentIndex is 0.
129         @IllegalArgumentException
130         Thrown if the VARIANT is inappropriate for conversion. ArgumentPosition is -1,
131      */
132     void variantToAny(const VARIANT* pVariant, Any& rAny, bool bReduceValueRange = true);
133     /** This method converts variants arguments in calls from COM -> UNO. Only then
134         the expected UNO type is known.
135         @exception CannotConvertException
136         Thrown if the VARIANT contains a type that cannot be coerced in the expected Any.
137         ArgumentIndex is 0.
138         @IllegalArgumentException
139         Thrown if the VARIANT is inappropriate for conversion. ArgumentPosition is -1,
140      */
141     void variantToAny( const VARIANTARG* pArg, Any& rAny, const Type& ptype, bool bReduceValueRange = true);
142 
143     /**
144        @exception IllegalArgumentException
145        -if pVar does not contain VT_UNKNOWN or VT_DISPATCH or
146        pVar is used for a particular UNO type which is not supported by pVar
147      */
148     Any createOleObjectWrapper(VARIANT* pVar, const Type& aType= Type());
149 
150     /*
151       Return true means var contained a ValueObject, and it was successfully converted.
152       The result is in any. It an error occurred a BridgeRuntimeError will be thrown.
153      */
154     bool convertValueObject( const VARIANTARG *var, Any& any);
155     void dispatchExObject2Sequence( const VARIANTARG* pvar, Any& anySeq, const Type& type);
156 
157     Sequence<Any> createOleArrayWrapperOfDim(SAFEARRAY* pArray, unsigned int dimCount, unsigned int actDim, long* index,
158                                              VARTYPE type, const Type& unotype);
159     Sequence<Any> createOleArrayWrapper(SAFEARRAY* pArray, VARTYPE type, const Type& unotype= Type());
160 
161 
162     VARTYPE mapTypeClassToVartype( TypeClass type);
163     Reference< XSingleServiceFactory > getInvocationFactory(const Any& anyObject);
164 
165 
166     virtual Reference< XInterface > createUnoWrapperInstance()=0;
167     virtual Reference< XInterface > createComWrapperInstance()=0;
168 
169     static bool isJScriptArray(const VARIANT* pvar);
170 
171     Sequence<Type> getImplementedInterfaces(IUnknown* pUnk);
172 
173 protected:
174     Reference<XInterface> createAdapter(const Sequence<Type>& types, const Reference<XInterface>& receiver);
175 
176     // helper function for Sequence conversion
177     void getElementCountAndTypeOfSequence( const Any& rSeq, sal_Int32 dim, Sequence< sal_Int32 >& seqElementCounts, TypeDescription& typeDesc);
178     // helper function for Sequence conversion
179     static bool incrementMultidimensionalIndex(sal_Int32 dimensions, const sal_Int32 * parDimensionLength,
180                                     sal_Int32 * parMultidimensionalIndex);
181     // helper function for Sequence conversion
182     static size_t getOleElementSize( VARTYPE type);
183 
184     static Type getElementTypeOfSequence( const Type& seqType);
185 
186     //Provides a typeconverter
187     Reference<XTypeConverter> getTypeConverter();
188 
189     // This member determines what class is used to convert a UNO object
190     // or struct to a COM object. It is passed along to the anyToVariant
191     // function in the createBridge function implementation
192     const sal_uInt8 m_nUnoWrapperClass;
193     const sal_uInt8 m_nComWrapperClass;
194 
195     // The servicemanager is either a local smgr or remote when the service
196     // com.sun.star.bridge.OleBridgeSupplierVar1 is used. This service can be
197     // created by createInstanceWithArguments where one can supply a service
198     // manager that is to be used.
199     // Local service manager as supplied by the loader when the creator function
200     // of the service is being called.
201     Reference<XMultiServiceFactory> m_smgr;
202     // An explicitly supplied service manager when the service
203     // com.sun.star.bridge.OleBridgeSupplierVar1 is used. That can be a remote
204     // manager.
205     Reference<XMultiServiceFactory> m_smgrRemote;
206     Reference<XSingleServiceFactory> m_xInvocationFactoryLocal;
207     Reference<XSingleServiceFactory> m_xInvocationFactoryRemote;
208 
209 private:
210     // Holds the type converter which is used for sequence conversion etc.
211     // Use the getTypeConverter function to obtain the interface.
212     Reference<XTypeConverter> m_typeConverter;
213 
214 
215 };
216 
217 // ask the object for XBridgeSupplier2 and on success bridges
218 // the uno object to IUnknown or IDispatch.
219 // return  true the UNO object supports
220 template < class T >
convertSelfToCom(T & unoInterface,VARIANT * pVar)221 bool convertSelfToCom( T& unoInterface, VARIANT * pVar)
222 {
223     bool ret = false;
224     Reference< XInterface > xInt( unoInterface, UNO_QUERY);
225     if( xInt.is())
226     {
227         Reference< XBridgeSupplier2 > xSupplier( xInt, UNO_QUERY);
228         if( xSupplier.is())
229         {
230             sal_Int8 arId[16];
231             rtl_getGlobalProcessId( reinterpret_cast<sal_uInt8*>(arId));
232             Sequence<sal_Int8> seqId( arId, 16);
233             Any anySource;
234             anySource <<= xInt;
235             Any anyDisp = xSupplier->createBridge(anySource, seqId, UNO, OLE);
236 
237             // due to global-process-id check this must be in-process pointer
238             if (auto v = o3tl::tryAccess<sal_uIntPtr>(anyDisp))
239             {
240                 VARIANT* pvariant= reinterpret_cast<VARIANT*>(*v);
241                 HRESULT hr;
242                 if (FAILED(hr = VariantCopy(pVar, pvariant)))
243                     throw BridgeRuntimeError(
244                         "[automation bridge] convertSelfToCom\n"
245                         "VariantCopy failed! Error: " +
246                         OUString::number(hr));
247                 VariantClear( pvariant);
248                 CoTaskMemFree( pvariant);
249                 ret = true;
250             }
251         }
252     }
253     return ret;
254 }
255 
256 
257 // Gets the invocation factory depending on the Type in the Any.
258 // The factory can be created by a local or remote multi service factory.
259 // In case there is a remote multi service factory available there are
260 // some services or types for which the local factory is used. The exceptions
261 // are:  all structs.
262 // Param anyObject - contains the object ( interface, struct) for what we need an invocation object.
263 
264 template<class T>
getInvocationFactory(const Any & anyObject)265 Reference< XSingleServiceFactory > UnoConversionUtilities<T>::getInvocationFactory(const Any& anyObject)
266 {
267     Reference< XSingleServiceFactory > retVal;
268     MutexGuard guard( getBridgeMutex());
269     if( anyObject.getValueTypeClass() != TypeClass_STRUCT &&
270         m_smgrRemote.is() )
271     {
272         if(  ! m_xInvocationFactoryRemote.is() )
273             m_xInvocationFactoryRemote.set(m_smgrRemote->createInstance( INVOCATION_SERVICE), UNO_QUERY);
274         retVal= m_xInvocationFactoryRemote;
275     }
276     else
277     {
278         if( ! m_xInvocationFactoryLocal.is() )
279             m_xInvocationFactoryLocal.set(m_smgr->createInstance(INVOCATION_SERVICE ), UNO_QUERY);
280         retVal= m_xInvocationFactoryLocal;
281     }
282     return retVal;
283 }
284 
285 template<class T>
variantToAny(const VARIANTARG * pArg,Any & rAny,const Type & ptype,bool bReduceValueRange)286 void UnoConversionUtilities<T>::variantToAny( const VARIANTARG* pArg, Any& rAny, const Type& ptype, bool bReduceValueRange /* = sal_True */)
287 {
288     try
289     {
290         HRESULT hr;
291         bool bFail = false;
292         bool bCannotConvert = false;
293         CComVariant var;
294 
295         // There is no need to support indirect values, since they're not supported by UNO
296         if( FAILED(hr= VariantCopyInd( &var, pArg))) // remove VT_BYREF
297             throw BridgeRuntimeError(
298                 "[automation bridge] UnoConversionUtilities<T>::variantToAny \n"
299                 "VariantCopyInd failed for reason : " + OUString::number(hr));
300         bool bHandled = convertValueObject( & var, rAny);
301         if( bHandled)
302             OSL_ENSURE(  rAny.getValueType() == ptype, "type in Value Object must match the type parameter");
303 
304         if( ! bHandled)
305         {
306             // convert into a variant type that is the equivalent to the type
307             // the sequence expects. Thus variantToAny produces the correct type
308             // E.g. An Array object contains VT_I4 and the sequence expects shorts
309             // than the vartype must be changed. The reason is, you can't specify the
310             // type in JavaScript and the script engine determines the type being used.
311             switch( ptype.getTypeClass())
312             {
313             case TypeClass_CHAR: // could be: new Array( 12, 'w', "w")
314                 if( var.vt == VT_BSTR)
315                 {
316                     if(SUCCEEDED( hr= VariantChangeType( &var, &var, 0, VT_BSTR)))
317                         rAny.setValue( V_BSTR( &var), ptype);
318                     else if (hr == DISP_E_TYPEMISMATCH)
319                         bCannotConvert = true;
320                     else
321                         bFail = true;
322                 }
323                 else
324                 {
325                     if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_I2)))
326                         rAny.setValue(& var.iVal, ptype);
327                     else if (hr == DISP_E_TYPEMISMATCH)
328                         bCannotConvert = true;
329                     else
330                         bFail = true;
331                 }
332                 break;
333             case TypeClass_INTERFACE: // could also be an IUnknown
334             case TypeClass_STRUCT:
335             {
336                 rAny = createOleObjectWrapper( & var, ptype);
337                 break;
338             }
339             case TypeClass_ENUM:
340                 if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_I4)))
341                     rAny.setValue(& var.lVal, ptype);
342                 else if (hr == DISP_E_TYPEMISMATCH)
343                     bCannotConvert = true;
344                 else
345                     bFail = true;
346                 break;
347             case TypeClass_SEQUENCE:
348                 // There are different ways of receiving a sequence:
349                 // 1: JScript, VARTYPE: VT_DISPATCH
350                 // 2. VBScript simple arraysVT_VARIANT|VT_BYREF the referenced VARIANT contains
351                 //      a VT_ARRAY|  <type>
352                 // 3. VBScript multi dimensional arrays: VT_ARRAY|VT_BYREF
353                 if( pArg->vt == VT_DISPATCH)
354                 {
355                     dispatchExObject2Sequence( pArg, rAny, ptype);
356                 }
357                 else
358                 {
359                     if ((var.vt & VT_ARRAY) != 0)
360                     {
361                         VARTYPE oleType = ::sal::static_int_cast< VARTYPE, int >( var.vt ^ VT_ARRAY );
362                         Sequence<Any> unoSeq = createOleArrayWrapper( var.parray, oleType, ptype);
363                         Reference<XTypeConverter> conv = getTypeConverter();
364                         if (conv.is())
365                         {
366                             try
367                             {
368                                 Any anySeq = makeAny(unoSeq);
369                                 Any convAny = conv->convertTo(anySeq, ptype);
370                                 rAny = convAny;
371                             }
372                             catch (const IllegalArgumentException& e)
373                             {
374                                 throw BridgeRuntimeError(
375                                     "[automation bridge]com.sun.star.lang.IllegalArgumentException "
376                                     "in UnoConversionUtilities<T>::variantToAny! Message: " +
377                                     e.Message);
378                             }
379                             catch (const CannotConvertException& e)
380                             {
381                                 throw BridgeRuntimeError(
382                                     "[automation bridge]com.sun.star.script.CannotConvertException "
383                                     "in UnoConversionUtilities<T>::variantToAny! Message: " +
384                                     e.Message);
385                             }
386                         }
387                     }
388                 }
389                 break;
390             case TypeClass_VOID:
391                 rAny.setValue(nullptr,Type());
392                 break;
393             case TypeClass_ANY:     //  Any
394                 // There could be a JScript Array that needs special handling
395                 // If an Any is expected and this Any must contain a Sequence
396                 // then we cannot figure out what element type is required.
397                 // Therefore we convert to Sequence< Any >
398                 if( pArg->vt == VT_DISPATCH &&  isJScriptArray( pArg))
399                 {
400                     dispatchExObject2Sequence( pArg, rAny,
401                                                cppu::UnoType<Sequence<Any>>::get());
402                 }
403                 else if (pArg->vt == VT_DECIMAL)
404                 {
405                     //Decimal maps to hyper in calls from COM -> UNO
406                     // It does not matter if we create a sal_uInt64 or sal_Int64,
407                     // because the UNO object is called through invocation which
408                     //will do a type conversion if necessary
409                     if (var.decVal.sign == 0)
410                     {
411                         // positive value
412                         variantToAny( & var, rAny, cppu::UnoType<sal_uInt64>::get(),
413                                       bReduceValueRange);
414                     }
415                     else
416                     {
417                         //negative value
418                         variantToAny( & var, rAny, cppu::UnoType<sal_Int64>::get(),
419                                       bReduceValueRange);
420                     }
421                 }
422                 else
423                 {
424                     variantToAny( & var, rAny);
425                 }
426                 break;
427             case TypeClass_BOOLEAN:         // VARIANT could be VARIANT_BOOL or other
428                 if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_BOOL)))
429                     variantToAny( & var, rAny);
430                 else if (hr == DISP_E_TYPEMISMATCH)
431                     bCannotConvert = true;
432                 else
433                     bFail = true;
434                 break;
435             case TypeClass_STRING:      // UString
436                 if(var.vt == VT_NULL)
437                     var = CComBSTR("");
438                 if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_BSTR)))
439                     variantToAny( & var, rAny);
440                 else if (hr == DISP_E_TYPEMISMATCH)
441                     bCannotConvert = true;
442                 else
443                     bFail = true;
444                 break;
445             case TypeClass_FLOAT:       // float
446                 if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_R4)))
447                     variantToAny( & var, rAny);
448                 else if (hr == DISP_E_TYPEMISMATCH)
449                     bCannotConvert = true;
450                 else
451                     bFail = true;
452                 break;
453             case TypeClass_DOUBLE:      // double
454             if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_R8)))
455                 variantToAny(& var, rAny);
456             else if (hr == DISP_E_TYPEMISMATCH)
457                 bCannotConvert = true;
458             else
459                 bFail = true;
460             break;
461             case TypeClass_BYTE:            // BYTE
462                 if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_I1)))
463                     variantToAny( & var, rAny);
464                 else if (hr == DISP_E_TYPEMISMATCH)
465                     bCannotConvert = true;
466                 else
467                     bFail = true;
468                 break;
469             case TypeClass_SHORT:       // INT16
470                 if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_I2)))
471                     variantToAny( & var, rAny);
472                 else if (hr == DISP_E_TYPEMISMATCH)
473                     bCannotConvert = true;
474                 else
475                     bFail = true;
476                 break;
477             case TypeClass_LONG:
478                 if(SUCCEEDED(hr = VariantChangeType(& var, &var, 0, VT_I4)))
479                     variantToAny( & var, rAny, bReduceValueRange);
480                 else if (hr == DISP_E_TYPEMISMATCH)
481                     bCannotConvert = true;
482                 else
483                     bFail = true;
484                 break;
485             case TypeClass_HYPER:
486                 if(SUCCEEDED(hr = VariantChangeType(& var, &var, 0, VT_DECIMAL)))
487                 {
488                     if (var.decVal.Lo64 > SAL_CONST_UINT64(0x8000000000000000)
489                         || var.decVal.Hi32 > 0
490                         || var.decVal.scale > 0)
491                     {
492                         bFail = true;
493                         break;
494                     }
495                     sal_Int64 value = var.decVal.Lo64;
496                     if (var.decVal.sign == DECIMAL_NEG)
497                         value |=  SAL_CONST_UINT64(0x8000000000000000);
498                     rAny <<= value;
499                 }
500                 else if (hr == DISP_E_TYPEMISMATCH)
501                     bCannotConvert = true;
502                 else
503                     bFail = true;
504                 break;
505             case TypeClass_UNSIGNED_SHORT:  // UINT16
506                 if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_UI2)))
507                     variantToAny( & var, rAny);
508                 else if (hr == DISP_E_TYPEMISMATCH)
509                     bCannotConvert = true;
510                 else
511                     bFail = true;
512                 break;
513             case TypeClass_UNSIGNED_LONG:
514                 if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_UI4)))
515                     variantToAny( & var, rAny, bReduceValueRange);
516                 else if (hr == DISP_E_TYPEMISMATCH)
517                     bCannotConvert = true;
518                 else
519                     bFail = true;
520                 break;
521             case TypeClass_UNSIGNED_HYPER:
522                 if(SUCCEEDED(hr = VariantChangeType(& var, &var, 0, VT_DECIMAL)))
523                 {
524                     if (var.decVal.Hi32 > 0 || var.decVal.scale > 0)
525                     {
526                         bFail = true;
527                         break;
528                     }
529                     rAny <<= var.decVal.Lo64;
530                 }
531                 else if (hr == DISP_E_TYPEMISMATCH)
532                     bCannotConvert = true;
533                 else
534                     bFail = true;
535                 break;
536             case TypeClass_TYPE:
537                 if(SUCCEEDED(hr = VariantChangeType(& var, &var, 0, VT_UNKNOWN)))
538                     variantToAny( & var, rAny);
539                 else if (hr == DISP_E_TYPEMISMATCH)
540                     bCannotConvert = true;
541                 else
542                     bFail = true;
543                 break;
544             default:
545                 bCannotConvert = true;
546                 break;
547             }
548         }
549         if (bCannotConvert)
550             throw CannotConvertException(
551                 "[automation bridge]UnoConversionUtilities<T>::variantToAny \n"
552                 "Cannot convert the value of vartype :\"" +
553                 OUString::number(static_cast<sal_Int32>(var.vt)) +
554                 "\"  to the expected UNO type of type class: " +
555                 OUString::number(static_cast<sal_Int32>(ptype.getTypeClass())),
556                 nullptr, TypeClass_UNKNOWN, FailReason::TYPE_NOT_SUPPORTED,0);
557 
558         if (bFail)
559             throw IllegalArgumentException(
560                 "[automation bridge]UnoConversionUtilities<T>:variantToAny\n"
561                 "The provided VARIANT of type\" " + OUString::number(static_cast<sal_Int32>(var.vt)) +
562                 "\" is unappropriate for conversion!", Reference<XInterface>(), -1);
563     }
564     catch (const CannotConvertException &)
565     {
566         throw;
567     }
568     catch (const IllegalArgumentException &)
569     {
570         throw;
571     }
572     catch (const BridgeRuntimeError &)
573     {
574          throw;
575     }
576     catch (const Exception & e)
577     {
578         throw BridgeRuntimeError("[automation bridge] unexpected exception in "
579                                  "UnoConversionUtilities<T>::variantToAny ! Message : \n" +
580                                e.Message);
581     }
582     catch(...)
583     {
584         throw BridgeRuntimeError(
585                   "[automation bridge] unexpected exception in "
586                   "UnoConversionUtilities<T>::variantToAny !");
587     }
588 }
589 
590 // The function only converts Sequences to SAFEARRAYS with elements of the type
591 // specified by the parameter type. Everything else is forwarded to
592 // anyToVariant(VARIANT* pVariant, const Any& rAny)
593 // Param type must not be VT_BYREF
594 template<class T>
anyToVariant(VARIANT * pVariant,const Any & rAny,VARTYPE type)595 void UnoConversionUtilities<T>::anyToVariant(VARIANT* pVariant, const Any& rAny, VARTYPE type)
596 {
597     try
598     {
599         HRESULT hr= S_OK;
600 
601         OSL_ASSERT( (type & VT_BYREF) == 0);
602         if (type & VT_ARRAY)
603         {
604             type ^= VT_ARRAY;
605             SAFEARRAY* ar= createUnoSequenceWrapper( rAny, type);
606             if( ar)
607             {
608                 VariantClear( pVariant);
609                 pVariant->vt= ::sal::static_int_cast< VARTYPE, int >( VT_ARRAY | type );
610                 pVariant->byref= ar;
611             }
612         }
613         else if(type == VT_VARIANT)
614         {
615             anyToVariant(pVariant, rAny);
616         }
617         else
618         {
619             CComVariant var;
620             anyToVariant( &var, rAny);
621             if(FAILED(hr = VariantChangeType(&var, &var, 0, type)))
622             {
623                 if (hr == DISP_E_TYPEMISMATCH)
624                     throw CannotConvertException(
625                         "[automation bridge]UnoConversionUtilities<T>::anyToVariant \n"
626                         "Cannot convert the value of type :\"" +
627                         rAny.getValueTypeName() +
628                         "\"  to the expected Automation type of VARTYPE: " +
629                         OUString::number(static_cast<sal_Int32>(type)),
630                         nullptr, TypeClass_UNKNOWN, FailReason::TYPE_NOT_SUPPORTED,0);
631 
632                 throw BridgeRuntimeError(
633                     "[automation bridge]UnoConversionUtilities<T>::anyToVariant \n"
634                     "Conversion of any with " +
635                     rAny.getValueType().getTypeName() +
636                     " to VARIANT with type: " + OUString::number(static_cast<sal_Int32>(type)) +
637                     " failed! Error code: " + OUString::number(hr));
638 
639             }
640             if(FAILED(hr = VariantCopy(pVariant, &var)))
641             {
642                 throw BridgeRuntimeError(
643                           "[automation bridge]UnoConversionUtilities<T>::anyToVariant \n"
644                           "VariantCopy failed for reason: " + OUString::number(hr));
645             }
646         }
647     }
648     catch (const IllegalArgumentException &)
649     {
650         throw;
651     }
652     catch (const CannotConvertException &)
653     {
654         throw;
655     }
656     catch (const BridgeRuntimeError&)
657     {
658         throw;
659     }
660     catch(const Exception & e)
661     {
662         throw BridgeRuntimeError(
663                   "[automation bridge]UnoConversionUtilities<T>::anyToVariant \n"
664                   "Unexpected exception occurred. Message: " + e.Message);
665     }
666     catch(...)
667     {
668         throw BridgeRuntimeError(
669                   "[automation bridge]UnoConversionUtilities<T>::anyToVariant \n"
670                   "Unexpected exception occurred.");
671     }
672 }
673 
674 template<class T>
anyToVariant(VARIANT * pVariant,const Any & rAny)675 void UnoConversionUtilities<T>::anyToVariant(VARIANT* pVariant, const Any& rAny)
676 {
677     try
678     {
679         bool bIllegal = false;
680         switch (rAny.getValueTypeClass())
681         {
682         case TypeClass_INTERFACE:
683         {
684             Reference<XInterface> xInt;
685             if (rAny >>= xInt)
686             {
687                 createUnoObjectWrapper(rAny, pVariant);
688             }
689             else
690             {
691                 bIllegal = true;
692             }
693             break;
694         }
695         case TypeClass_STRUCT:
696         {
697             if (rAny.getValueType() == cppu::UnoType<Date>::get() )
698             {
699                 Date d;
700                 if (rAny >>= d)
701                 {
702                     pVariant->vt = VT_DATE;
703                     pVariant->date = d.Value;
704                 }
705                 else
706                 {
707                     bIllegal = true;
708                 }
709             }
710             else if(rAny.getValueType() == cppu::UnoType<Decimal>::get())
711             {
712                 Decimal d;
713                 if (rAny >>= d)
714                 {
715                     pVariant->vt = VT_DECIMAL;
716                     pVariant->decVal.scale = d.Scale;
717                     pVariant->decVal.sign = d.Sign;
718                     pVariant->decVal.Lo32 = d.LowValue;
719                     pVariant->decVal.Mid32 = d.MiddleValue;
720                     pVariant->decVal.Hi32 = d.HighValue;
721                 }
722                 else
723                 {
724                     bIllegal = true;
725                 }
726             }
727             else if (rAny.getValueType() == cppu::UnoType<Currency>::get())
728             {
729                 Currency c;
730                 if (rAny >>= c)
731                 {
732                     pVariant->vt = VT_CY;
733                     pVariant->cyVal.int64 = c.Value;
734                 }
735                 else
736                 {
737                     bIllegal = true;
738                 }
739             }
740             else if(rAny.getValueType() == cppu::UnoType<SCode>::get())
741             {
742                 SCode s;
743                 if (rAny >>= s)
744                 {
745                     pVariant->vt = VT_ERROR;
746                     pVariant->scode = s.Value;
747                 }
748                 else
749                 {
750                     bIllegal = true;
751                 }
752             }
753             else
754             {
755                 createUnoObjectWrapper(rAny, pVariant);
756             }
757             break;
758         }
759         case TypeClass_SEQUENCE:        // sequence ??? SafeArray descriptor
760         {
761             SAFEARRAY* pArray = createUnoSequenceWrapper(rAny);
762             if (pArray)
763             {
764                 V_VT(pVariant) = VT_ARRAY | VT_VARIANT;
765                 V_ARRAY(pVariant) = pArray;
766             }
767             else
768             {
769                 bIllegal = true;
770             }
771             break;
772         }
773         case TypeClass_VOID:
774         {
775             HRESULT hr = S_OK;
776             if (FAILED(hr = VariantClear(pVariant)))
777             {
778                 throw BridgeRuntimeError(
779                         "[automation bridge]UnoConversionUtilities<T>::anyToVariant\n"
780                         "VariantClear failed with error:" + OUString::number(hr));
781             }
782             break;
783         }
784         case TypeClass_BOOLEAN:
785         {
786             bool value;
787             if (rAny >>= value)
788             {
789                 pVariant->vt = VT_BOOL;
790                 pVariant->boolVal = value ? VARIANT_TRUE: VARIANT_FALSE;
791             }
792             else
793             {
794                 bIllegal = true;
795             }
796             break;
797         }
798         case TypeClass_CHAR:
799         {
800             // Because VT_UI2 does not conform to oleautomation we convert into VT_I2 instead
801             sal_uInt16 value = *o3tl::forceAccess<sal_Unicode>(rAny);
802             pVariant->vt = VT_I2;
803             pVariant->iVal = value;
804             break;
805         }
806         case TypeClass_STRING:
807         {
808             OUString value;
809             if (rAny >>= value)
810             {
811                 pVariant->vt = VT_BSTR;
812                 pVariant->bstrVal = SysAllocString(o3tl::toW(value.getStr()));
813             }
814             else
815             {
816                 bIllegal = true;
817             }
818             break;
819         }
820         case TypeClass_FLOAT:
821         {
822             float value;
823             if (rAny >>= value)
824             {
825                 pVariant->vt = VT_R4;
826                 pVariant->fltVal = value;
827             }
828             else
829             {
830                 bIllegal = true;
831             }
832             break;
833         }
834         case TypeClass_DOUBLE:
835         {
836             double value;
837             if (rAny >>= value)
838             {
839                 pVariant->vt = VT_R8;
840                 pVariant->dblVal = value;
841             }
842             else
843             {
844                 bIllegal = true;
845             }
846             break;
847         }
848         case TypeClass_BYTE:
849         {
850             // ole automation does not know a signed char but only unsigned char
851             sal_Int8 value;
852             if (rAny >>= value)
853             {
854                 pVariant->vt = VT_UI1;
855                 pVariant->bVal = value;
856             }
857             else
858             {
859                 bIllegal = true;
860             }
861             break;
862         }
863         case TypeClass_SHORT:       // INT16
864         case TypeClass_UNSIGNED_SHORT:  // UINT16
865         {
866             sal_Int16 value;
867             if (rAny >>= value)
868             {
869                 pVariant->vt = VT_I2;
870                 pVariant->iVal = value;
871             }
872             else
873             {
874                 bIllegal = true;
875             }
876             break;
877         }
878         case TypeClass_ENUM:
879         {
880             sal_Int32 value = *static_cast<sal_Int32 const *>(rAny.getValue());
881             pVariant->vt = VT_I4;
882             pVariant->lVal= value;
883             break;
884         }
885         case TypeClass_LONG:
886         case TypeClass_UNSIGNED_LONG:
887         {
888             sal_Int32 value;
889             if (rAny >>= value)
890             {
891                 pVariant->vt = VT_I4;
892                 pVariant->lVal= value;
893             }
894             else
895             {
896                 bIllegal = true;
897             }
898             break;
899         }
900         case TypeClass_HYPER:
901         {
902 
903             pVariant->vt = VT_DECIMAL;
904             pVariant->decVal.scale = 0;
905             pVariant->decVal.sign = 0;
906             pVariant->decVal.Hi32 = 0;
907 
908             sal_Int64 value;
909             rAny >>= value;
910 
911             if (value & SAL_CONST_UINT64(0x8000000000000000))
912                 pVariant->decVal.sign = DECIMAL_NEG;
913 
914             pVariant->decVal.Lo64 = value;
915             break;
916         }
917         case TypeClass_UNSIGNED_HYPER:
918         {
919             pVariant->vt = VT_DECIMAL;
920             pVariant->decVal.scale = 0;
921             pVariant->decVal.sign = 0;
922             pVariant->decVal.Hi32 = 0;
923 
924             sal_uInt64 value;
925             rAny >>= value;
926             pVariant->decVal.Lo64 = value;
927             break;
928         }
929         case TypeClass_TYPE:
930         {
931             Type type;
932             rAny >>= type;
933             CComVariant var;
934             if (!createUnoTypeWrapper(type.getTypeName(), & var))
935                 throw BridgeRuntimeError(
936                           "[automation bridge] UnoConversionUtilities<T>::anyToVariant \n"
937                           "Error during conversion of UNO type to Automation object!");
938 
939             if (FAILED(VariantCopy(pVariant, &var)))
940                 throw BridgeRuntimeError(
941                           "[automation bridge] UnoConversionUtilities<T>::anyToVariant \n"
942                           "Unexpected error!");
943             break;
944         }
945         default:
946             //TypeClass_SERVICE:
947             //TypeClass_EXCEPTION:
948             //When an InvocationTargetException is thrown when calling XInvocation::invoke
949             //on a UNO object, then the target exception is directly used to create a
950             //EXEPINFO structure
951             //TypeClass_TYPEDEF
952             //TypeClass_ANY:
953             //TypeClass_UNKNOWN:
954             //TypeClass_MODULE:
955             throw CannotConvertException(
956                       "[automation bridge]UnoConversionUtilities<T>::anyToVariant\n"
957                       "There is no conversion for this UNO type to an Automation type."
958                       "The destination type class is the type class of the UNO "
959                       "argument which was to be converted.",
960                 Reference<XInterface>(), rAny.getValueTypeClass(),
961                 FailReason::TYPE_NOT_SUPPORTED, 0);
962 
963             break;
964         }
965         if (bIllegal)
966         {
967             throw IllegalArgumentException(
968                       "[automation bridge]UnoConversionUtilities<T>::anyToVariant\n"
969                       "The provided any of type\" " + rAny.getValueType().getTypeName() +
970                 "\" is unappropriate for conversion!", Reference<XInterface>(), -1);
971 
972         }
973     }
974     catch (const CannotConvertException &)
975     {
976         throw;
977     }
978     catch (const IllegalArgumentException &)
979     {
980         throw;
981     }
982     catch(const BridgeRuntimeError&)
983     {
984         throw;
985     }
986     catch(const Exception & e)
987     {
988         throw BridgeRuntimeError(
989                   "[automation bridge]UnoConversionUtilities<T>::anyToVariant \n"
990                   "Unexpected exception occurred. Message: " + e.Message);
991     }
992     catch(...)
993     {
994         throw BridgeRuntimeError(
995                   "[automation bridge]UnoConversionUtilities<T>::anyToVariant \n"
996                   "Unexpected exception occurred. " );
997     }
998 }
999 
1000 // Creates an SAFEARRAY of the specified element and if necessary
1001 // creates a SAFEARRAY with multiple dimensions.
1002 // Used by sal_Bool anyToVariant(VARIANT* pVariant, const Any& rAny, VARTYPE type);
1003 template<class T>
createUnoSequenceWrapper(const Any & rSeq,VARTYPE elemtype)1004 SAFEARRAY*  UnoConversionUtilities<T>::createUnoSequenceWrapper(const Any& rSeq, VARTYPE elemtype)
1005 {
1006     if (rSeq.getValueTypeClass() != TypeClass_SEQUENCE)
1007         throw IllegalArgumentException(
1008                   "[automation bridge]UnoConversionUtilities<T>::createUnoSequenceWrapper \n"
1009                   "The any does not contain a sequence!", nullptr, 0);
1010     if (elemtype == VT_NULL  ||  elemtype == VT_EMPTY)
1011         throw IllegalArgumentException(
1012                   "[automation bridge]UnoConversionUtilities<T>::createUnoSequenceWrapper \n"
1013                   "No element type supplied!",nullptr, -1);
1014     SAFEARRAY*  pArray= nullptr;
1015     // Get the dimensions. This is done by examining the type name string
1016     // The count of brackets determines the dimensions.
1017     OUString sTypeName= rSeq.getValueType().getTypeName();
1018     sal_Int32 dims=0;
1019     for(sal_Int32 lastIndex=0;(lastIndex= sTypeName.indexOf( L'[', lastIndex)) != -1; lastIndex++,dims++);
1020 
1021     //get the maximum number of elements per dimensions and the typedescription of the elements
1022     Sequence<sal_Int32> seqElementCounts( dims);
1023     TypeDescription elementTypeDesc;
1024     getElementCountAndTypeOfSequence( rSeq, 1, seqElementCounts, elementTypeDesc );
1025 
1026     if( elementTypeDesc.is() )
1027     {
1028         // set up the SAFEARRAY
1029         std::unique_ptr<SAFEARRAYBOUND[]> sarSafeArrayBound(new SAFEARRAYBOUND[dims]);
1030         SAFEARRAYBOUND* prgsabound= sarSafeArrayBound.get();
1031         for( sal_Int32 i=0; i < dims; i++)
1032         {
1033             //prgsabound[0] is the right most dimension
1034             prgsabound[dims - i - 1].lLbound = 0;
1035             prgsabound[dims - i - 1].cElements = seqElementCounts[i];
1036         }
1037 
1038         typelib_TypeDescription* rawTypeDesc= elementTypeDesc.get();
1039         sal_Int32 elementSize= rawTypeDesc->nSize;
1040         size_t oleElementSize= getOleElementSize( elemtype);
1041         // SafeArrayCreate clears the memory for the data itself.
1042         pArray = SafeArrayCreate(elemtype, dims, prgsabound);
1043 
1044         // convert the Sequence's elements and populate the SAFEARRAY
1045         if( pArray)
1046         {
1047             // Iterate over every Sequence that contains the actual elements
1048             void* pSAData;
1049             if( SUCCEEDED( SafeArrayAccessData( pArray, &pSAData)))
1050             {
1051                 const sal_Int32* parElementCount= seqElementCounts.getConstArray();
1052                 uno_Sequence * pMultiSeq= *static_cast<uno_Sequence* const*>(rSeq.getValue());
1053                 sal_Int32 dimsSeq= dims - 1;
1054 
1055                 // arDimSeqIndices contains the current index of a block of data.
1056                 // E.g. Sequence<Sequence<sal_Int32>> , the index would refer to Sequence<sal_Int32>
1057                 // In this case arDimSeqIndices would have the size 1. That is the elements are not counted
1058                 // but the Sequences that contain those elements.
1059                 // The indices are 0 based
1060                 std::unique_ptr<sal_Int32[]> sarDimsSeqIndices;
1061                 sal_Int32* arDimsSeqIndices= nullptr;
1062                 if( dimsSeq > 0)
1063                 {
1064                     sarDimsSeqIndices.reset(new sal_Int32[dimsSeq]);
1065                     arDimsSeqIndices = sarDimsSeqIndices.get();
1066                     memset( arDimsSeqIndices, 0,  sizeof( sal_Int32 ) * dimsSeq);
1067                 }
1068 
1069                 char* psaCurrentData= static_cast<char*>(pSAData);
1070 
1071                 do
1072                 {
1073                     // Get the Sequence at the current index , see arDimsSeqIndices
1074                     uno_Sequence * pCurrentSeq= pMultiSeq;
1075                     sal_Int32 curDim=1; // 1 based
1076                     bool skipSeq= false;
1077                     while( curDim <= dimsSeq )
1078                     {
1079                         // get the Sequence at the index if valid
1080                         if( pCurrentSeq->nElements > arDimsSeqIndices[ curDim - 1] ) // don't point to Nirvana
1081                         {
1082                             // size of Sequence is 4
1083                             sal_Int32 offset= arDimsSeqIndices[ curDim - 1] * 4;
1084                             pCurrentSeq= *reinterpret_cast<uno_Sequence**>(&pCurrentSeq->elements[ offset]);
1085                             curDim++;
1086                         }
1087                         else
1088                         {
1089                             // There is no Sequence at this index, so skip this index
1090                             skipSeq= true;
1091                             break;
1092                         }
1093                     }
1094 
1095                     if( skipSeq)
1096                         continue;
1097 
1098                     // Calculate the current position within the datablock of the SAFEARRAY
1099                     // for the next Sequence.
1100                     sal_Int32 memOffset= 0;
1101                     sal_Int32 dimWeight= parElementCount[ dims - 1]; // size of the rightmost dimension
1102                     for(sal_Int32 idims=0; idims < dimsSeq; idims++ )
1103                     {
1104                         memOffset+= arDimsSeqIndices[dimsSeq - 1 - idims] * dimWeight;
1105                         // now determine the weight of the dimension to the left of the current.
1106                         if( dims - 2 - idims >=0)
1107                             dimWeight*= parElementCount[dims - 2 - idims];
1108                     }
1109                     psaCurrentData= static_cast<char*>(pSAData) + memOffset * oleElementSize;
1110                     // convert the Sequence and put the elements into the Safearray
1111                     for( sal_Int32 i= 0; i < pCurrentSeq->nElements; i++)
1112                     {
1113                         Any unoElement( pCurrentSeq->elements + i * elementSize, rawTypeDesc );
1114                         // The any is being converted into a VARIANT which value is then copied
1115                         // to the SAFEARRAY's data block. When copying one has to follow the rules for
1116                         // copying certain types, as are VT_DISPATCH, VT_UNKNOWN, VT_VARIANT, VT_BSTR.
1117                         // To increase performance, we just do a memcpy of VARIANT::byref. This is possible
1118                         // because anyToVariant has already followed the copying rules. To make this
1119                         // work there must not be a VariantClear.
1120                         // One Exception is VARIANT because I don't know how VariantCopy works.
1121 
1122                         VARIANT var;
1123                         VariantInit( &var);
1124                         anyToVariant( &var, unoElement);
1125                         if( elemtype == VT_VARIANT )
1126                         {
1127                             VariantCopy( reinterpret_cast<VARIANT*>(psaCurrentData), &var);
1128                             VariantClear( &var);
1129                         }
1130                         else
1131                             memcpy( psaCurrentData, &var.byref, oleElementSize);
1132 
1133                         psaCurrentData+= oleElementSize;
1134                     }
1135                 }
1136                 while( incrementMultidimensionalIndex( dimsSeq, parElementCount, arDimsSeqIndices));
1137 
1138                 SafeArrayUnaccessData( pArray);
1139             }
1140         }
1141     }
1142     return pArray;
1143 }
1144 
1145 // Increments a multi dimensional index.
1146 // Returns true as long as the index has been successfully incremented, false otherwise.
1147 // False is also returned if an overflow of the most significant dimension occurs. E.g.
1148 // assume an array with the dimensions (2,2), then the lowest index is (0,0) and the highest
1149 // index is (1,1). If the function is being called with the index (1,1) then the overflow would
1150 // occur, with the result (0,0) and a sal_False as return value.
1151 // Param dimensions - number of dimensions
1152 // Param parDimensionsLength - The array contains the size of each dimension, that is the
1153 //                              size of the array equals the parameter dimensions.
1154 //                              The rightmost dimensions is the least significant one
1155 //                              ( parDimensionsLengths[ dimensions -1 ] ).
1156 // Param parMultiDimensionalIndex - The array contains the index. Each dimension index is
1157 //                                  0 based.
1158 template<class T>
incrementMultidimensionalIndex(sal_Int32 dimensions,const sal_Int32 * parDimensionLengths,sal_Int32 * parMultidimensionalIndex)1159 bool UnoConversionUtilities<T>::incrementMultidimensionalIndex(sal_Int32 dimensions,
1160                                                                    const sal_Int32 * parDimensionLengths,
1161                                                                    sal_Int32 * parMultidimensionalIndex)
1162 {
1163     if( dimensions < 1)
1164         return false;
1165 
1166     bool ret= true;
1167     bool carry= true; // to get into the while loop
1168 
1169     sal_Int32 currentDimension= dimensions; //most significant is 1
1170     while( carry)
1171     {
1172         parMultidimensionalIndex[ currentDimension - 1]++;
1173         // if carryover, set index to 0 and handle carry on a level above
1174         if( parMultidimensionalIndex[ currentDimension - 1] > (parDimensionLengths[ currentDimension - 1] - 1))
1175             parMultidimensionalIndex[ currentDimension - 1]= 0;
1176         else
1177             carry= false;
1178 
1179         currentDimension --;
1180         // if dimensions drops below 1 and carry is set than then all indices are 0 again
1181         // this is signalled by returning sal_False
1182         if( currentDimension < 1 && carry)
1183         {
1184             carry= false;
1185             ret= false;
1186         }
1187     }
1188     return ret;
1189 }
1190 
1191 // Determines the size of a certain OLE type. The function takes
1192 // only those types into account which are oleautomation types and
1193 // can have a value ( unless VT_NULL, VT_EMPTY, VT_ARRAY, VT_BYREF).
1194 // Currently used in createUnoSequenceWrapper to calculate addresses
1195 // for data within a SAFEARRAY.
1196 template<class T>
getOleElementSize(VARTYPE type)1197 size_t UnoConversionUtilities<T>::getOleElementSize( VARTYPE type)
1198 {
1199     size_t size;
1200     switch( type)
1201     {
1202     case VT_BOOL: size= sizeof( VARIANT_BOOL);break;
1203     case VT_UI1: size= sizeof( unsigned char);break;
1204     case VT_R8: size= sizeof( double);break;
1205     case VT_R4: size= sizeof( float);break;
1206     case VT_I2: size= sizeof( short);break;
1207     case VT_I4: size= sizeof( long);break;
1208     case VT_BSTR: size= sizeof( BSTR); break;
1209     case VT_ERROR: size= sizeof( SCODE); break;
1210     case VT_DISPATCH:
1211     case VT_UNKNOWN: size= sizeof( IUnknown*); break;
1212     case VT_VARIANT: size= sizeof( VARIANT);break;
1213     default: size= 0;
1214     }
1215     return size;
1216 }
1217 
1218 //If a Sequence is being converted into a SAFEARRAY then we possibly have
1219 // to create a SAFEARRAY with multiple dimensions. This is the case when a
1220 // Sequence contains Sequences ( Sequence< Sequence < XXX > > ). The leftmost
1221 // Sequence in the declaration is assumed to represent dimension 1. Because
1222 // all Sequence elements of a Sequence can have different length, we have to
1223 // determine the maximum length which is then the length of the respective
1224 // dimension.
1225 // getElementCountAndTypeOfSequence determines the length of each dimension and calls itself recursively
1226 // in the process.
1227 // param rSeq - an Any that has to contain a Sequence
1228 // param dim - the dimension for which the number of elements is being determined,
1229 //              must be one.
1230 // param seqElementCounts - contains the maximum number of elements for each
1231 //                          dimension. Index 0 contains the number of dimension one.
1232 //                          After return the Sequence contains the maximum number of
1233 //                          elements for each dimension.
1234 //                          The length of the Sequence must equal the number of dimensions.
1235 // param typeClass - TypeClass of the element type that is no Sequence, e.g.
1236 //                          Sequence< Sequence <Sequence <sal_Int32> > > - type is sal_Int32)
1237 template<class T>
getElementCountAndTypeOfSequence(const Any & rSeq,sal_Int32 dim,Sequence<sal_Int32> & seqElementCounts,TypeDescription & typeDesc)1238 void  UnoConversionUtilities<T>::getElementCountAndTypeOfSequence( const Any& rSeq, sal_Int32 dim,
1239                                              Sequence< sal_Int32 >& seqElementCounts, TypeDescription& typeDesc)
1240 {
1241     sal_Int32 dimCount= (*static_cast<uno_Sequence* const *>(rSeq.getValue()))->nElements;
1242     if( dimCount > seqElementCounts[ dim-1])
1243         seqElementCounts[ dim-1]= dimCount;
1244 
1245     // we need the element type to construct the any that is
1246     // passed into getElementCountAndTypeOfSequence again
1247     typelib_TypeDescription* pSeqDesc= nullptr;
1248     rSeq.getValueTypeDescription( &pSeqDesc);
1249     typelib_TypeDescriptionReference* pElementDescRef= reinterpret_cast<typelib_IndirectTypeDescription*>(pSeqDesc)->pType;
1250 
1251     // if the elements are Sequences then do recursion
1252     if( dim < seqElementCounts.getLength() )
1253     {
1254         uno_Sequence* pSeq = *static_cast<uno_Sequence* const*>(rSeq.getValue());
1255         uno_Sequence** arSequences= reinterpret_cast<uno_Sequence**>(pSeq->elements);
1256         for( sal_Int32 i=0; i < dimCount; i++)
1257         {
1258             uno_Sequence* arElement=  arSequences[ i];
1259             getElementCountAndTypeOfSequence( Any( &arElement, pElementDescRef), dim + 1 , seqElementCounts, typeDesc);
1260         }
1261     }
1262     else
1263     {
1264         // determine the element type ( e.g. Sequence< Sequence <Sequence <sal_Int32> > > - type is sal_Int32)
1265         typeDesc= pElementDescRef;
1266     }
1267     typelib_typedescription_release( pSeqDesc);
1268 }
1269 
1270 
1271 template<class T>
createUnoSequenceWrapper(const Any & rSeq)1272 SAFEARRAY*  UnoConversionUtilities<T>::createUnoSequenceWrapper(const Any& rSeq)
1273 {
1274     SAFEARRAY* pArray = nullptr;
1275     sal_uInt32 n = 0;
1276 
1277     if( rSeq.getValueTypeClass() != TypeClass_SEQUENCE )
1278         throw IllegalArgumentException(
1279                   "[automation bridge]UnoConversionUtilities<T>::createUnoSequenceWrapper\n"
1280                   "The UNO argument is not a sequence", nullptr, -1);
1281 
1282     uno_Sequence * punoSeq= *static_cast<uno_Sequence* const *>(rSeq.getValue());
1283 
1284     typelib_TypeDescriptionReference* pSeqTypeRef= rSeq.getValueTypeRef();
1285     typelib_TypeDescription* pSeqType= nullptr;
1286     TYPELIB_DANGER_GET( &pSeqType, pSeqTypeRef);
1287     typelib_IndirectTypeDescription * pSeqIndDec=   reinterpret_cast<typelib_IndirectTypeDescription*>(pSeqType);
1288 
1289 
1290     typelib_TypeDescriptionReference * pSeqElementTypeRef= pSeqIndDec->pType;
1291     TYPELIB_DANGER_RELEASE( pSeqType);
1292 
1293     typelib_TypeDescription* pSeqElementDesc= nullptr;
1294     TYPELIB_DANGER_GET( &pSeqElementDesc, pSeqElementTypeRef);
1295     sal_Int32 nElementSize= pSeqElementDesc->nSize;
1296     n= punoSeq->nElements;
1297 
1298     SAFEARRAYBOUND rgsabound[1];
1299     rgsabound[0].lLbound = 0;
1300     rgsabound[0].cElements = n;
1301     VARIANT oleElement;
1302     long safeI[1];
1303 
1304     pArray = SafeArrayCreate(VT_VARIANT, 1, rgsabound);
1305 
1306     Any unoElement;
1307     char * pSeqData= punoSeq->elements;
1308 
1309     for (sal_uInt32 i = 0; i < n; i++)
1310     {
1311         unoElement.setValue( pSeqData + i * nElementSize, pSeqElementDesc);
1312         VariantInit(&oleElement);
1313 
1314         anyToVariant(&oleElement, unoElement);
1315 
1316         safeI[0] = i;
1317         SafeArrayPutElement(pArray, safeI, &oleElement);
1318 
1319         VariantClear(&oleElement);
1320     }
1321     TYPELIB_DANGER_RELEASE( pSeqElementDesc);
1322 
1323     return pArray;
1324 }
1325 
1326 /* The argument rObj can contain
1327 - UNO struct
1328 - UNO interface
1329 - UNO interface created by this bridge (adapter factory)
1330 - UNO interface created by this bridge ( COM Wrapper)
1331 
1332 pVar must be initialized.
1333 */
1334 template<class T>
createUnoObjectWrapper(const Any & rObj,VARIANT * pVar)1335 void UnoConversionUtilities<T>::createUnoObjectWrapper(const Any & rObj, VARIANT * pVar)
1336 {
1337     MutexGuard guard(getBridgeMutex());
1338 
1339     Reference<XInterface> xInt;
1340 
1341     TypeClass tc = rObj.getValueTypeClass();
1342     if (tc != TypeClass_INTERFACE && tc != TypeClass_STRUCT)
1343         throw IllegalArgumentException(
1344                   "[automation bridge]UnoConversionUtilities<T>::createUnoObjectWrapper \n"
1345                   "Cannot create an Automation interface for a UNO type which is not "
1346                   "a struct or interface!", nullptr, -1);
1347 
1348     if (rObj.getValueTypeClass() == TypeClass_INTERFACE)
1349     {
1350         if (! (rObj >>= xInt))
1351             throw IllegalArgumentException(
1352                   "[automation bridge] UnoConversionUtilities<T>::createUnoObjectWrapper\n "
1353                   "Could not create wrapper object for UNO object!", nullptr, -1);
1354         //If XInterface is NULL, which is a valid value, then simply return NULL.
1355         if ( ! xInt.is())
1356         {
1357             pVar->vt = VT_UNKNOWN;
1358             pVar->punkVal = nullptr;
1359             return;
1360         }
1361         //make sure we have the main XInterface which is used with a map
1362         xInt.set(xInt, UNO_QUERY);
1363         //If there is already a wrapper for the UNO object then use it
1364 
1365         Reference<XInterface> xIntWrapper;
1366         // Does a UNO wrapper exist already ?
1367         auto it_uno = UnoObjToWrapperMap.find( reinterpret_cast<sal_uIntPtr>(xInt.get()));
1368         if(it_uno != UnoObjToWrapperMap.end())
1369         {
1370             xIntWrapper =  it_uno->second;
1371             if (xIntWrapper.is())
1372             {
1373                 convertSelfToCom(xIntWrapper, pVar);
1374                 return;
1375             }
1376         }
1377         // Is the object a COM wrapper ( either XInvocation, or Adapter object)
1378         // or does it supply an IDispatch by its own ?
1379         else
1380         {
1381             Reference<XInterface> xIntComWrapper = xInt;
1382 
1383             // Adapter? then get the COM wrapper to which the adapter delegates its calls
1384             auto it = AdapterToWrapperMap.find( reinterpret_cast<sal_uIntPtr>(xInt.get()));
1385             if( it != AdapterToWrapperMap.end() )
1386                 xIntComWrapper= reinterpret_cast<XInterface*>(it->second);
1387 
1388             if (convertSelfToCom(xIntComWrapper, pVar))
1389                 return;
1390         }
1391     }
1392     // If we have no UNO wrapper nor the IDispatch yet then we have to create
1393     // a wrapper. For that we need an XInvocation.
1394 
1395     // create an XInvocation using the invocation service
1396     Reference<XInvocation> xInv;
1397     Reference<XSingleServiceFactory> xInvFactory= getInvocationFactory(rObj);
1398     if (xInvFactory.is())
1399     {
1400         Sequence<Any> params(2);
1401         params.getArray()[0] = rObj;
1402         params.getArray()[1] <<= OUString("FromOLE");
1403         Reference<XInterface> xInt2 = xInvFactory->createInstanceWithArguments(params);
1404         xInv.set(xInt2, UNO_QUERY);
1405     }
1406 
1407     if (xInv.is())
1408     {
1409         Reference<XInterface> xNewWrapper = createUnoWrapperInstance();
1410         Reference<XInitialization> xInitWrapper(xNewWrapper, UNO_QUERY);
1411         if (xInitWrapper.is())
1412         {
1413             VARTYPE vartype= getVarType( rObj);
1414 
1415             if (xInt.is())
1416             {
1417                 Any params[3];
1418                 params[0] <<= xInv;
1419                 params[1] <<= xInt;
1420                 params[2] <<= vartype;
1421                 xInitWrapper->initialize( Sequence<Any>(params, 3));
1422             }
1423             else
1424             {
1425                 Any params[2];
1426                 params[0] <<= xInv;
1427                 params[1] <<= vartype;
1428                 xInitWrapper->initialize( Sequence<Any>(params, 2));
1429             }
1430 
1431             // put the newly created object into a map. If the same object will
1432             // be mapped again and there is already a wrapper then the old wrapper
1433             // will be used.
1434             if(xInt.is()) // only interfaces
1435                 UnoObjToWrapperMap[reinterpret_cast<sal_uIntPtr>(xInt.get())]= xNewWrapper;
1436             convertSelfToCom(xNewWrapper, pVar);
1437             return;
1438         }
1439     }
1440 }
1441 
1442 template<class T>
variantToAny(const VARIANT * pVariant,Any & rAny,bool bReduceValueRange)1443 void UnoConversionUtilities<T>::variantToAny( const VARIANT* pVariant, Any& rAny,
1444                                                   bool bReduceValueRange /* = sal_True */)
1445 {
1446     HRESULT hr = S_OK;
1447     try
1448     {
1449         CComVariant var;
1450 
1451         // There is no need to support indirect values, since they're not supported by UNO
1452         if( FAILED(hr= VariantCopyInd( &var, pVariant))) // remove VT_BYREF
1453             throw BridgeRuntimeError(
1454                       "[automation bridge] UnoConversionUtilities<T>::variantToAny \n"
1455                       "VariantCopyInd failed for reason : " + OUString::number(hr));
1456 
1457         if ( ! convertValueObject( & var, rAny))
1458         {
1459             if ((var.vt & VT_ARRAY) > 0)
1460             {
1461                 VARTYPE oleTypeFlags = ::sal::static_int_cast< VARTYPE, int >( var.vt ^ VT_ARRAY );
1462 
1463                 Sequence<Any> unoSeq = createOleArrayWrapper(var.parray, oleTypeFlags);
1464                 rAny.setValue( &unoSeq, cppu::UnoType<decltype(unoSeq)>::get());
1465             }
1466             else
1467             {
1468                 switch (var.vt)
1469                 {
1470                 case VT_EMPTY:
1471                     rAny.setValue(nullptr, Type());
1472                     break;
1473                 case VT_NULL:
1474                     rAny.setValue(nullptr, Type());
1475                     break;
1476                 case VT_I2:
1477                     rAny.setValue( & var.iVal, cppu::UnoType<sal_Int16>::get());
1478                     break;
1479                 case VT_I4:
1480                     rAny.setValue( & var.lVal, cppu::UnoType<sal_Int32>::get());
1481                     // necessary for use in JavaScript ( see "reduceRange")
1482                     if( bReduceValueRange)
1483                         reduceRange(rAny);
1484                     break;
1485                 case VT_R4:
1486                     rAny.setValue( & var.fltVal, cppu::UnoType<float>::get());
1487                     break;
1488                 case VT_R8:
1489                     rAny.setValue(& var.dblVal, cppu::UnoType<double>::get());
1490                     break;
1491                 case VT_CY:
1492                 {
1493                     Currency cy(var.cyVal.int64);
1494                     rAny <<= cy;
1495                     break;
1496                 }
1497                 case VT_DATE:
1498                 {
1499                     Date d(var.date);
1500                     rAny <<= d;
1501                     break;
1502                 }
1503                 case VT_BSTR:
1504                 {
1505                     OUString b(o3tl::toU(var.bstrVal));
1506                     rAny.setValue( &b, cppu::UnoType<decltype(b)>::get());
1507                     break;
1508                 }
1509                 case VT_UNKNOWN:
1510                 case VT_DISPATCH:
1511                 {
1512                     //check if it is a UNO type
1513                     CComQIPtr<IUnoTypeWrapper> spType(static_cast<IUnknown*>(var.byref));
1514                     if (spType)
1515                     {
1516                         CComBSTR sName;
1517                         if (FAILED(spType->get_Name(&sName)))
1518                             throw BridgeRuntimeError(
1519                                     "[automation bridge]UnoConversionUtilities<T>::variantToAny \n"
1520                                     "Failed to get the type name from a UnoTypeWrapper!");
1521                         Type type;
1522                         if (!getType(sName, type))
1523                         {
1524                             throw CannotConvertException(
1525                                       OUStringLiteral("[automation bridge]UnoConversionUtilities<T>::variantToAny \n"
1526                                       "A UNO type with the name: ") + o3tl::toU(LPCOLESTR(sName)) +
1527                                 "does not exist!",
1528                                 nullptr, TypeClass_UNKNOWN, FailReason::TYPE_NOT_SUPPORTED,0);
1529                         }
1530                         rAny <<= type;
1531                     }
1532                     else
1533                     {
1534                         rAny = createOleObjectWrapper( & var);
1535                     }
1536                     break;
1537                 }
1538                 case VT_ERROR:
1539                 {
1540                     SCode scode(var.scode);
1541                     rAny <<= scode;
1542                     break;
1543                 }
1544                 case VT_BOOL:
1545                 {
1546                     rAny <<= (var.boolVal == VARIANT_TRUE);
1547                     break;
1548                 }
1549                 case VT_I1:
1550                     rAny.setValue( & var.cVal, cppu::UnoType<sal_Int8>::get());
1551                     break;
1552                 case VT_UI1: // there is no unsigned char in UNO
1553                     rAny <<= sal_Int8(var.bVal);
1554                     break;
1555                 case VT_UI2:
1556                     rAny.setValue( & var.uiVal, cppu::UnoType<cppu::UnoUnsignedShortType>::get() );
1557                     break;
1558                 case VT_UI4:
1559                     rAny.setValue( & var.ulVal, cppu::UnoType<sal_uInt32>::get());
1560                     break;
1561                 case VT_INT:
1562                     rAny.setValue( & var.intVal, cppu::UnoType<sal_Int32>::get());
1563                     break;
1564                 case VT_UINT:
1565                     rAny.setValue( & var.uintVal, cppu::UnoType<sal_uInt32>::get());
1566                     break;
1567                 case VT_VOID:
1568                     rAny.setValue( nullptr, Type());
1569                     break;
1570                 case VT_DECIMAL:
1571                 {
1572                     Decimal dec;
1573                     dec.Scale = var.decVal.scale;
1574                     dec.Sign = var.decVal.sign;
1575                     dec.LowValue = var.decVal.Lo32;
1576                     dec.MiddleValue = var.decVal.Mid32;
1577                     dec.HighValue = var.decVal.Hi32;
1578                     rAny <<= dec;
1579                     break;
1580                 }
1581 
1582                 default:
1583                     break;
1584                 }
1585             }
1586         }
1587     }
1588     catch (const IllegalArgumentException &)
1589     {
1590         throw;
1591     }
1592     catch (const CannotConvertException &)
1593     {
1594         throw;
1595     }
1596     catch (const BridgeRuntimeError &)
1597     {
1598          throw;
1599     }
1600     catch (const Exception & e)
1601     {
1602         throw BridgeRuntimeError("[automation bridge] unexpected exception in "
1603                                  "UnoConversionUtilities<T>::variantToAny ! Message : \n" +
1604                                e.Message);
1605     }
1606     catch(...)
1607     {
1608         throw BridgeRuntimeError(
1609                   "[automation bridge] unexpected exception in "
1610                   "UnoConversionUtilities<T>::variantToAny !");
1611     }
1612 
1613 }
1614 // The function converts an IUnknown* into a UNO interface or struct. The
1615 // IUnknown pointer can constitute different kind of objects:
1616 // 1. a wrapper of a UNO struct (the wrapper was created by this bridge)
1617 // 2. a wrapper of a UNO interface (created by this bridge)
1618 // 3. a dispatch object that implements UNO interfaces
1619 // 4. a dispatch object.
1620 
1621 // If the parameter "aType" has a value then the COM object ( pUnknown) is supposed to
1622 // implement the interface described by "aType". Moreover it ( pUnknown) can implement
1623 // several other
1624 // UNO interfaces in which case it has to support the SUPPORTED_INTERFACES_PROP (see
1625 // #define) property. That property contains all names of interfaces.
1626 // "pUnknown" is wrapped by a COM wrapper object that implements XInvocation, e.g.
1627 // IUnknownWrapper. Additionally an object of type "aType" is created by help
1628 // of the INTERFACE_ADAPTER_FACTORY (see #define) service. The implementation of
1629 // "aType" calls on the COM wrapper's XInvocation::invoke. If the COM object supports
1630 // more than one UNO interfaces, as can be determined by the property
1631 // SUPPORTED_INTERFACES_PROP, then the INTERFACE_ADAPTER_FACTORY creates an object that
1632 // implements all these interfaces.
1633 // This is only done if "pUnknown" is not already a UNO wrapper,
1634 // that is it is actually NOT a UNO object that was converted to a COM object. If it is an
1635 // UNO wrapper than the original UNO object is being extracted, queried for "aType" (if
1636 // it is no struct) and returned.
1637 template<class T>
createOleObjectWrapper(VARIANT * pVar,const Type & aType)1638 Any UnoConversionUtilities<T>::createOleObjectWrapper(VARIANT* pVar, const Type& aType)
1639 {
1640     //To allow passing "Nothing" in VS 2008 we need to accept VT_EMPTY
1641     if (pVar->vt != VT_UNKNOWN && pVar->vt != VT_DISPATCH && pVar->vt != VT_EMPTY)
1642         throw IllegalArgumentException(
1643                   "[automation bridge]UnoConversionUtilities<T>::createOleObjectWrapper \n"
1644                   "The VARIANT does not contain an object type! ", nullptr, -1);
1645 
1646     MutexGuard guard( getBridgeMutex());
1647 
1648     CComPtr<IUnknown>  spUnknown;
1649     CComPtr<IDispatch> spDispatch;
1650 
1651     if (pVar->vt == VT_UNKNOWN)
1652     {
1653         spUnknown = pVar->punkVal;
1654         if (spUnknown)
1655             spUnknown.QueryInterface( & spDispatch.p);
1656     }
1657     else if (pVar->vt == VT_DISPATCH && pVar->pdispVal != nullptr)
1658     {
1659         CComPtr<IDispatch> spDispatch2(pVar->pdispVal);
1660         if (spDispatch2)
1661             spDispatch2.QueryInterface( & spUnknown.p);
1662     }
1663 
1664     static Type VOID_TYPE;
1665     Any ret;
1666     //If no Type is provided and pVar contains IUnknown then we return a XInterface.
1667     //If pVar contains an IDispatch then we return a XInvocation.
1668     Type desiredType = aType;
1669 
1670     if (aType == VOID_TYPE)
1671     {
1672         switch (pVar->vt)
1673         {
1674         case VT_EMPTY:
1675         case VT_UNKNOWN:
1676             desiredType = cppu::UnoType<XInterface>::get();
1677             break;
1678         case VT_DISPATCH:
1679             desiredType = cppu::UnoType<XInvocation>::get();
1680             break;
1681         default:
1682             desiredType = aType;
1683         }
1684     }
1685 
1686     // COM pointer are NULL, no wrapper required
1687     if (spUnknown == nullptr)
1688     {
1689         Reference<XInterface> xInt;
1690         if( aType.getTypeClass() == TypeClass_INTERFACE)
1691             ret.setValue( &xInt, aType);
1692         else if( aType.getTypeClass() == TypeClass_STRUCT)
1693             ret.setValue( nullptr, aType);
1694         else
1695             ret <<= xInt;
1696         return ret;
1697     }
1698 
1699 
1700     // Check if "spUnknown" is a UNO wrapper, that is a UNO object that has been
1701     // passed to COM. Then it supports IUnoObjectWrapper
1702     // and we extract the original UNO object.
1703     CComQIPtr<IUnoObjectWrapper> spUno( spUnknown);
1704     if( spUno)
1705     {   // it is a wrapper
1706         Reference<XInterface> xInt;
1707         if( SUCCEEDED( spUno->getOriginalUnoObject( &xInt)))
1708         {
1709             ret <<= xInt;
1710         }
1711         else
1712         {
1713             Any any;
1714             if( SUCCEEDED( spUno->getOriginalUnoStruct(&any)))
1715                 ret= any;
1716         }
1717         return ret;
1718     }
1719 
1720     // "spUnknown" is a real COM object.
1721     // Before we create a new wrapper object we check if there is an existing wrapper
1722     // There can be two kinds of wrappers, those who wrap dispatch - UNO objects, and those who
1723     // wrap ordinary dispatch objects. The dispatch-UNO objects usually are adapted to represent
1724     // particular UNO interfaces.
1725     Reference<XInterface> xIntWrapper;
1726     auto cit_currWrapper= ComPtrToWrapperMap.find( reinterpret_cast<sal_uIntPtr>(spUnknown.p));
1727     if(cit_currWrapper != ComPtrToWrapperMap.end())
1728             xIntWrapper = cit_currWrapper->second;
1729     if (xIntWrapper.is())
1730     {
1731         //Try to find an adapter for the wrapper
1732         //find the proper Adapter. The pointer in the WrapperToAdapterMap are valid as long as
1733         //we get a pointer to the wrapper from ComPtrToWrapperMap, because the Adapter hold references
1734         //to the wrapper.
1735         auto it = WrapperToAdapterMap.find(reinterpret_cast<sal_uIntPtr>(xIntWrapper.get()));
1736         if (it == WrapperToAdapterMap.end())
1737         {
1738             // No adapter available.
1739             //The COM component could be a UNO object. Then we need to provide
1740             // a proxy  that implements all interfaces
1741             Sequence<Type> seqTypes= getImplementedInterfaces(spUnknown);
1742             Reference<XInterface> xIntAdapter;
1743             if (seqTypes.getLength() > 0)
1744             {
1745                 //It is a COM UNO object
1746                 xIntAdapter = createAdapter(seqTypes, xIntWrapper);
1747             }
1748             else
1749             {
1750                 // Some ordinary COM object
1751                 xIntAdapter = xIntWrapper;
1752             }
1753             // return the wrapper directly, return XInterface or XInvocation
1754             ret = xIntWrapper->queryInterface(desiredType);
1755             if ( ! ret.hasValue())
1756                 throw IllegalArgumentException(
1757                           "[automation bridge]UnoConversionUtilities<T>::createOleObjectWrapper \n"
1758                           "The COM object is not suitable for the UNO type: " +
1759                     desiredType.getTypeName(), nullptr, -1);
1760         }
1761         else
1762         {
1763             //There is an adapter available
1764             Reference<XInterface> xIntAdapter(reinterpret_cast<XInterface*>(it->second));
1765             ret = xIntAdapter->queryInterface( desiredType);
1766             if ( ! ret.hasValue())
1767                 throw IllegalArgumentException(
1768                           "[automation bridge]UnoConversionUtilities<T>::createOleObjectWrapper \n"
1769                           "The COM object is not suitable for the UNO type: " +
1770                     desiredType.getTypeName(), nullptr, -1);
1771         }
1772 
1773         return ret;
1774     }
1775     // No existing wrapper. Therefore create a new proxy.
1776     // If the object implements UNO interfaces then get the types.
1777     Sequence<Type> seqTypes = getImplementedInterfaces(spUnknown);
1778     if (seqTypes.getLength() == 0 &&
1779         aType != VOID_TYPE && aType != cppu::UnoType<XInvocation>::get())
1780     {
1781         seqTypes = Sequence<Type>( & aType, 1);
1782     }
1783 
1784     //There is no existing wrapper, therefore we create one for the real COM object
1785     Reference<XInterface> xIntNewProxy= createComWrapperInstance();
1786     if ( ! xIntNewProxy.is())
1787         throw BridgeRuntimeError(
1788                   "[automation bridge]UnoConversionUtilities<T>::createOleObjectWrapper \n"
1789                   "Could not create proxy object for COM object!");
1790 
1791     // initialize the COM wrapper
1792     Reference<XInitialization> xInit( xIntNewProxy, UNO_QUERY);
1793     OSL_ASSERT( xInit.is());
1794 
1795     Any  params[3];
1796     params[0] <<= reinterpret_cast<sal_uIntPtr>(spUnknown.p);
1797     params[1] <<= (pVar->vt == VT_DISPATCH);
1798     params[2] <<= seqTypes;
1799 
1800     xInit->initialize( Sequence<Any>( params, 3));
1801     ComPtrToWrapperMap[reinterpret_cast<sal_uInt64>(spUnknown.p)] = xIntNewProxy;
1802 
1803     // we have a wrapper object
1804     //The wrapper implements already XInvocation and XInterface. If
1805     //param aType is void then the object is supposed to have XInvocation.
1806     if (aType == cppu::UnoType<XInvocation>::get()||
1807         (aType == VOID_TYPE && seqTypes.getLength() == 0 ))
1808     {
1809         ret = xIntNewProxy->queryInterface(desiredType);
1810     }
1811     else
1812     {
1813         Reference<XInterface> xIntAdapter =
1814             createAdapter(seqTypes, xIntNewProxy);
1815         ret = xIntAdapter->queryInterface(desiredType);
1816     }
1817     return ret;
1818 }
1819 template<class T>
createAdapter(const Sequence<Type> & seqTypes,const Reference<XInterface> & receiver)1820 Reference<XInterface> UnoConversionUtilities<T>::createAdapter(const Sequence<Type>& seqTypes,
1821                                     const Reference<XInterface>& receiver)
1822 {
1823     Reference< XInterface> xIntAdapterFac;
1824     xIntAdapterFac= m_smgr->createInstance(INTERFACE_ADAPTER_FACTORY);
1825     // We create an adapter object that does not only implement the required type but also
1826     // all types that the COM object pretends to implement. A COM object must therefore
1827     // support the property "_implementedInterfaces".
1828     Reference<XInterface> xIntAdapted;
1829     Reference<XInvocation> xInv(receiver, UNO_QUERY);
1830     Reference<XInvocationAdapterFactory2> xAdapterFac( xIntAdapterFac, UNO_QUERY);
1831     if( xAdapterFac.is())
1832         xIntAdapted= xAdapterFac->createAdapter( xInv, seqTypes);
1833 
1834     if( !xIntAdapted.is())
1835     {
1836         throw BridgeRuntimeError(
1837                   "[automation bridge]UnoConversionUtilities<T>::createOleObjectWrapper \n"
1838                   "Could not create a proxy for COM object! Creation of adapter failed.");
1839     }
1840 
1841     // Put the pointer to the wrapper object and the interface pointer of the adapted interface
1842     // in a global map. Thus we can determine in a call to createUnoObjectWrapper whether the UNO
1843     // object is a wrapped COM object. In that case we extract the original COM object rather than
1844     // creating a wrapper around the UNO object.
1845     typedef std::unordered_map<sal_uInt64,sal_uInt64>::value_type VALUE;
1846     AdapterToWrapperMap.insert( VALUE( reinterpret_cast<sal_uInt64>(xIntAdapted.get()), reinterpret_cast<sal_uInt64>(receiver.get())));
1847     WrapperToAdapterMap.insert( VALUE( reinterpret_cast<sal_uInt64>(receiver.get()), reinterpret_cast<sal_uInt64>(xIntAdapted.get())));
1848 
1849     return xIntAdapted;
1850 }
1851 // "convertValueObject" converts a JScriptValue object contained in "var" into
1852 // an any. The type contained in the any is stipulated by a "type value" thas
1853 // was set within the JScript script on the value object ( see JScriptValue).
1854 template<class T>
convertValueObject(const VARIANTARG * var,Any & any)1855 bool UnoConversionUtilities<T>::convertValueObject( const VARIANTARG *var, Any& any)
1856 {
1857     bool ret = false;
1858     try
1859     {
1860         bool bFail = false;
1861         HRESULT hr= S_OK;
1862         CComVariant varDisp;
1863 
1864         if(SUCCEEDED(hr = varDisp.ChangeType( VT_DISPATCH, var)))
1865         {
1866             CComPtr <IJScriptValueObject> spValue;
1867             VARIANT_BOOL varBool;
1868             CComBSTR bstrType;
1869             CComVariant varValue;
1870             CComPtr<IDispatch> spDisp( varDisp.pdispVal);
1871             if(spDisp)
1872             {
1873                 if(SUCCEEDED( spDisp->QueryInterface( __uuidof( IJScriptValueObject),
1874                                                        reinterpret_cast<void**> (&spValue))))
1875                 {
1876                     ret = true; // is a ValueObject
1877                     //If it is an out - param then it does not need to be converted. In/out and
1878                     // in params does so.
1879                     if (SUCCEEDED(hr= spValue->IsOutParam( &varBool)))
1880                     {
1881                         // if varBool == true then no conversion needed because out param
1882                         if (varBool == VARIANT_FALSE)
1883                         {
1884                             if(SUCCEEDED(hr = spValue->GetValue( & bstrType, & varValue)))
1885                             {
1886                                 Type type;
1887                                 if (getType(bstrType, type))
1888                                     variantToAny( & varValue, any, type);
1889                                 else
1890                                     bFail = true;
1891                             }
1892                             else
1893                                 bFail = true;
1894                         }
1895                     }
1896                     else
1897                         bFail = true;
1898                 }
1899             }
1900         }
1901         else if( hr != DISP_E_TYPEMISMATCH && hr != E_NOINTERFACE)
1902             bFail = true;
1903 
1904         if (bFail)
1905             throw BridgeRuntimeError(
1906                 "[automation bridge] Conversion of ValueObject failed ");
1907     }
1908     catch (const BridgeRuntimeError &)
1909     {
1910          throw;
1911     }
1912     catch (const Exception & e)
1913     {
1914         throw BridgeRuntimeError("[automation bridge] unexpected exception in "
1915                                  "UnoConversionUtilities<T>::convertValueObject ! Message : \n" +
1916                                e.Message);
1917     }
1918     catch(...)
1919     {
1920         throw BridgeRuntimeError(
1921                   "[automation bridge] unexpected exception in "
1922                   "UnoConversionUtilities<T>::convertValueObject !");
1923     }
1924     return ret;
1925 }
1926 
1927 template<class T>
dispatchExObject2Sequence(const VARIANTARG * pvar,Any & anySeq,const Type & type)1928 void UnoConversionUtilities<T>::dispatchExObject2Sequence( const VARIANTARG* pvar, Any& anySeq, const Type& type)
1929 {
1930     try
1931     {
1932         if( pvar->vt != VT_DISPATCH)
1933             throw BridgeRuntimeError("[automation bridge] UnoConversionUtilities<T>::dispatchExObject2Sequence \n"
1934                                      "Conversion of dispatch object to Sequence failed!");
1935         IDispatchEx* pdispEx;
1936         HRESULT hr;
1937         if( FAILED( hr= pvar->pdispVal->QueryInterface( IID_IDispatchEx,
1938                                                         reinterpret_cast<void**>( &pdispEx))))
1939             throw BridgeRuntimeError("[automation bridge] UnoConversionUtilities<T>::dispatchExObject2Sequence \n"
1940                                      "Conversion of dispatch object to Sequence failed!");
1941 
1942         DISPID dispid;
1943         DISPPARAMS param= {nullptr,nullptr,0,0};
1944         CComVariant result;
1945 
1946         OLECHAR const * sLength= L"length";
1947 
1948         // Get the length of the array. Can also be obtained through GetNextDispID. The
1949         // method only returns DISPIDs of the array data. Their names are like "0", "1" etc.
1950         if( FAILED( hr= pdispEx->GetIDsOfNames(IID_NULL, const_cast<OLECHAR **>(&sLength), 1, LOCALE_USER_DEFAULT, &dispid)))
1951             throw BridgeRuntimeError("[automation bridge] UnoConversionUtilities<T>::dispatchExObject2Sequence \n"
1952                                      "Conversion of dispatch object to Sequence failed!");
1953         if( FAILED( hr= pdispEx->InvokeEx(dispid, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET,
1954                                           &param, &result, nullptr, nullptr)))
1955             throw BridgeRuntimeError("[automation bridge] UnoConversionUtilities<T>::dispatchExObject2Sequence \n"
1956                                      "Conversion of dispatch object to Sequence failed!");
1957         if( FAILED( VariantChangeType( &result, &result, 0, VT_I4)))
1958             throw BridgeRuntimeError("[automation bridge] UnoConversionUtilities<T>::dispatchExObject2Sequence \n"
1959                                      "Conversion of dispatch object to Sequence failed!");
1960         long length= result.lVal;
1961 
1962         result.Clear();
1963 
1964         // get a few basic facts about the sequence, and reallocate:
1965         // create the Sequences
1966         // get the size of the elements
1967         typelib_TypeDescription *pDesc= nullptr;
1968         type.getDescription( &pDesc);
1969 
1970         typelib_IndirectTypeDescription *pSeqDesc= reinterpret_cast<typelib_IndirectTypeDescription*>(pDesc);
1971         typelib_TypeDescriptionReference *pSeqElemDescRef= pSeqDesc->pType; // type of the Sequence' elements
1972         Type elemType( pSeqElemDescRef);
1973         _typelib_TypeDescription* pSeqElemDesc=nullptr;
1974         TYPELIB_DANGER_GET( &pSeqElemDesc, pSeqElemDescRef);
1975         sal_uInt32 nelementSize= pSeqElemDesc->nSize;
1976         TYPELIB_DANGER_RELEASE( pSeqElemDesc);
1977 
1978         uno_Sequence *p_uno_Seq;
1979         uno_sequence_construct( &p_uno_Seq, pDesc, nullptr, length, cpp_acquire);
1980 
1981         typelib_TypeClass typeElement= pSeqDesc->pType->eTypeClass;
1982         char *pArray= p_uno_Seq->elements;
1983 
1984         // Get All properties in the object, convert their values to the expected type and
1985         // put them into the passed in sequence
1986         for( sal_Int32 i= 0; i< length; i++)
1987         {
1988             OUString ousIndex=OUString::number( i);
1989             OLECHAR* sindex = const_cast<OLECHAR *>(o3tl::toW(ousIndex.getStr()));
1990 
1991             if( FAILED( hr= pdispEx->GetIDsOfNames(IID_NULL, &sindex , 1, LOCALE_USER_DEFAULT, &dispid)))
1992             {
1993                 throw BridgeRuntimeError("[automation bridge] UnoConversionUtilities<T>::dispatchExObject2Sequence \n"
1994                                          "Conversion of dispatch object to Sequence failed!");
1995             }
1996             if( FAILED( hr= pdispEx->InvokeEx(dispid, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET,
1997                                               &param, &result, nullptr, nullptr)))
1998             {
1999                 throw BridgeRuntimeError("[automation bridge] UnoConversionUtilities<T>::dispatchExObject2Sequence \n"
2000                                          "Conversion of dispatch object to Sequence failed!");
2001             }
2002 
2003             // If the result is VT_DISPATCH than the Sequence's element type could be Sequence
2004             // Look that up in the CoreReflection to make clear.
2005             // That requires a recursiv conversion
2006             Any any;
2007             // Destination address within the out-Sequence "anySeq" where to copy the next converted element
2008             void* pDest= pArray + (i * nelementSize);
2009 
2010             if( result.vt & VT_DISPATCH && typeElement == typelib_TypeClass_SEQUENCE)
2011             {
2012                 variantToAny( &result, any, elemType, false);
2013                 // copy the converted VARIANT, that is a Sequence to the Sequence
2014                 uno_Sequence * p_unoSeq= *static_cast<uno_Sequence* const *>(any.getValue());
2015                 // just copy the pointer of the uno_Sequence
2016                 // nelementSize should be 4 !!!!
2017                 memcpy( pDest, &p_unoSeq, nelementSize);
2018                 osl_atomic_increment( &p_unoSeq->nRefCount);
2019             }
2020             else // Element type is no Sequence -> do one conversion
2021             {
2022                 variantToAny( &result, any, elemType, false);
2023                 if( typeElement == typelib_TypeClass_ANY)
2024                 {
2025                     // copy the converted VARIANT to the Sequence
2026                     uno_type_assignData( pDest, pSeqElemDescRef , &any, pSeqElemDescRef,cpp_queryInterface,
2027                                          cpp_acquire, cpp_release);
2028                 }
2029                 else
2030                 {
2031                     // type after conversion must be the element type of the sequence
2032                     OSL_ENSURE(any.getValueTypeClass() == css::uno::TypeClass(typeElement), "wrong conversion");
2033                     uno_type_assignData( pDest, pSeqElemDescRef,const_cast<void*>( any.getValue()), any.getValueTypeRef(),
2034                                          cpp_queryInterface, cpp_acquire, cpp_release);
2035                 }
2036             }
2037         } // else
2038         result.Clear();
2039         anySeq.setValue( &p_uno_Seq, pDesc);
2040         uno_destructData( &p_uno_Seq, pDesc, cpp_release);
2041         typelib_typedescription_release( pDesc);
2042     }
2043     catch (const BridgeRuntimeError &)
2044     {
2045         throw;
2046     }
2047     catch (const Exception & e)
2048     {
2049         throw BridgeRuntimeError("[automation bridge] unexpected exception in "
2050                                  "UnoConversionUtilities<T>::convertValueObject ! Message : \n" +
2051                                  e.Message);
2052     }
2053     catch(...)
2054     {
2055         throw BridgeRuntimeError(
2056                   "[automation bridge] unexpected exception in "
2057                   "UnoConversionUtilities<T>::convertValueObject !");
2058     }
2059 }
2060 
2061 /* The argument unotype is the type that is expected by the currently called UNO function.
2062    For example: []long, [][]long. If the function calls itself recursively then the element type
2063    is passed on. For example a two dimensional SAFEARRAY of type VT_I4 is to be converted. Then
2064    unotype has to be either void or [][]long. When the function calls itself recursively then
2065    it passes the element type which is []long.
2066 */
2067 template<class T>
createOleArrayWrapperOfDim(SAFEARRAY * pArray,unsigned int dimCount,unsigned int actDim,long * index,VARTYPE type,const Type & unotype)2068 Sequence<Any> UnoConversionUtilities<T>::createOleArrayWrapperOfDim(SAFEARRAY* pArray,
2069               unsigned int dimCount, unsigned int actDim, long* index, VARTYPE type, const Type& unotype)
2070 {
2071     HRESULT hr= S_OK;
2072     long lBound;
2073     long uBound;
2074     long nCountElements;
2075 
2076     SafeArrayGetLBound(pArray, actDim, &lBound);
2077     SafeArrayGetUBound(pArray, actDim, &uBound);
2078     nCountElements= uBound - lBound +1;
2079 
2080     Sequence<Any>   anySeq(nCountElements);
2081     Any*            pUnoArray = anySeq.getArray();
2082 
2083     for (index[actDim - 1] = lBound; index[actDim - 1] <= uBound; index[actDim - 1]++)
2084     {
2085         if (actDim > 1 )
2086         {
2087             Sequence<Any> element = createOleArrayWrapperOfDim(pArray, dimCount,
2088                 actDim - 1, index, type, getElementTypeOfSequence(unotype));
2089 
2090             pUnoArray[index[actDim - 1] - lBound].setValue(&element, cppu::UnoType<decltype(element)>::get());
2091         }
2092         else
2093         {
2094             VARIANT variant;
2095 
2096             VariantInit(&variant);
2097 
2098             V_VT(&variant) = type;
2099 
2100             switch (type)
2101             {
2102                 case VT_I2:
2103                     SafeArrayGetElement(pArray, index, &V_I2(&variant));
2104                     break;
2105                 case VT_I4:
2106                     SafeArrayGetElement(pArray, index, &V_I4(&variant));
2107                     break;
2108                 case VT_R4:
2109                     SafeArrayGetElement(pArray, index, &V_R4(&variant));
2110                     break;
2111                 case VT_R8:
2112                     SafeArrayGetElement(pArray, index, &V_R8(&variant));
2113                     break;
2114                 case VT_CY:
2115                     SafeArrayGetElement(pArray, index, &V_CY(&variant));
2116                     break;
2117                 case VT_DATE:
2118                     SafeArrayGetElement(pArray, index, &V_DATE(&variant));
2119                     break;
2120                 case VT_BSTR:
2121                     hr= SafeArrayGetElement(pArray, index, &V_BSTR(&variant));
2122                     break;
2123                 case VT_DISPATCH:
2124                     SafeArrayGetElement(pArray, index, &V_DISPATCH(&variant));
2125                     break;
2126                 case VT_ERROR:
2127                     SafeArrayGetElement(pArray, index, &V_ERROR(&variant));
2128                     break;
2129                 case VT_BOOL:
2130                     SafeArrayGetElement(pArray, index, &V_BOOL(&variant));
2131                     break;
2132                 case VT_VARIANT:
2133                     SafeArrayGetElement(pArray, index, &variant);
2134                     break;
2135                 case VT_UNKNOWN:
2136                     SafeArrayGetElement(pArray, index, &V_UNKNOWN(&variant));
2137                     break;
2138                 case VT_I1:
2139                     SafeArrayGetElement(pArray, index, &V_I1(&variant));
2140                     break;
2141                 case VT_UI1:
2142                     SafeArrayGetElement(pArray, index, &V_UI1(&variant));
2143                     break;
2144                 case VT_UI2:
2145                     SafeArrayGetElement(pArray, index, &V_UI2(&variant));
2146                     break;
2147                 case VT_UI4:
2148                     SafeArrayGetElement(pArray, index, &V_UI4(&variant));
2149                     break;
2150                 default:
2151                     break;
2152             }
2153 
2154             if( unotype.getTypeClass() == TypeClass_VOID)
2155                 // the function was called without specifying the destination type
2156                 variantToAny(&variant, pUnoArray[index[actDim - 1] - lBound], false);
2157             else
2158                 variantToAny(&variant, pUnoArray[index[actDim - 1] - lBound],
2159                     getElementTypeOfSequence(unotype), false);
2160 
2161             VariantClear(&variant);
2162         }
2163     }
2164     return anySeq;
2165 }
2166 
2167 template<class T>
getElementTypeOfSequence(const Type & seqType)2168 Type UnoConversionUtilities<T>::getElementTypeOfSequence( const Type& seqType)
2169 {
2170     Type retValue;
2171     if( seqType.getTypeClass() != TypeClass_VOID)
2172     {
2173         OSL_ASSERT( seqType.getTypeClass() == TypeClass_SEQUENCE);
2174         typelib_TypeDescription* pDescSeq= nullptr;
2175         seqType.getDescription(& pDescSeq);
2176         retValue = Type(reinterpret_cast<typelib_IndirectTypeDescription *>(pDescSeq)->pType);
2177         typelib_typedescription_release(pDescSeq);
2178     }
2179     return retValue;
2180 }
2181 template<class T>
createOleArrayWrapper(SAFEARRAY * pArray,VARTYPE type,const Type & unoType)2182 Sequence<Any> UnoConversionUtilities<T>::createOleArrayWrapper(SAFEARRAY* pArray, VARTYPE type, const Type& unoType)
2183 {
2184     sal_uInt32 dim = SafeArrayGetDim(pArray);
2185 
2186     Sequence<Any> ret;
2187 
2188     if (dim > 0)
2189     {
2190         std::unique_ptr<long[]> sarIndex(new long[dim]);
2191         long * index =  sarIndex.get();
2192 
2193         for (unsigned int i = 0; i < dim; i++)
2194         {
2195             index[i] = 0;
2196         }
2197 
2198         ret = createOleArrayWrapperOfDim(pArray, dim, dim, index, type, unoType);
2199     }
2200 
2201     return ret;
2202 }
2203 
2204 // If a VARIANT has the type VT_DISPATCH it can either be a JScript Array
2205 // or some other object. This function finds out if it is such an array or
2206 // not. Currently there's no way to make sure it's an array
2207 // so we assume that when the object has a property "0" then it is an Array.
2208 // A JScript has property like "0", "1", "2" etc. which represent the
2209 // value at the corresponding index of the array
2210 template<class T>
isJScriptArray(const VARIANT * rvar)2211 bool UnoConversionUtilities<T>::isJScriptArray(const VARIANT* rvar)
2212 {
2213     OSL_ENSURE( rvar->vt == VT_DISPATCH, "param is not a VT_DISPATCH");
2214     HRESULT hr;
2215     OLECHAR const * sindex= L"0";
2216     DISPID id;
2217     if ( rvar->vt == VT_DISPATCH && rvar->pdispVal )
2218     {
2219         hr= rvar->pdispVal->GetIDsOfNames(
2220             IID_NULL, const_cast<OLECHAR **>(&sindex), 1, LOCALE_USER_DEFAULT,
2221             &id);
2222 
2223         if( SUCCEEDED ( hr) )
2224             return true;
2225     }
2226 
2227     return false;
2228 }
2229 
2230 template<class T>
mapTypeClassToVartype(TypeClass type)2231 VARTYPE UnoConversionUtilities<T>::mapTypeClassToVartype( TypeClass type)
2232 {
2233     VARTYPE ret;
2234     switch( type)
2235     {
2236     case TypeClass_INTERFACE: ret= VT_DISPATCH;
2237         break;
2238     case TypeClass_STRUCT: ret= VT_DISPATCH;
2239         break;
2240     case TypeClass_ENUM: ret= VT_I4;
2241         break;
2242     case TypeClass_SEQUENCE: ret= VT_ARRAY;
2243         break;
2244     case TypeClass_ANY: ret= VT_VARIANT;
2245         break;
2246     case TypeClass_BOOLEAN: ret= VT_BOOL;
2247         break;
2248     case TypeClass_CHAR: ret= VT_I2;
2249         break;
2250     case TypeClass_STRING: ret= VT_BSTR;
2251         break;
2252     case TypeClass_FLOAT: ret= VT_R4;
2253         break;
2254     case TypeClass_DOUBLE: ret= VT_R8;
2255         break;
2256     case TypeClass_BYTE: ret= VT_UI1;
2257         break;
2258     case TypeClass_SHORT: ret= VT_I2;
2259         break;
2260     case TypeClass_LONG: ret= VT_I4;
2261         break;
2262     case TypeClass_UNSIGNED_SHORT: ret= VT_UI2;
2263          break;
2264     case TypeClass_UNSIGNED_LONG: ret= VT_UI4;
2265         break;
2266     default:
2267         ret= VT_EMPTY;
2268     }
2269     return ret;
2270 }
2271 
2272 template<class T>
getImplementedInterfaces(IUnknown * pUnk)2273 Sequence<Type> UnoConversionUtilities<T>::getImplementedInterfaces(IUnknown* pUnk)
2274 {
2275     Sequence<Type> seqTypes;
2276     CComDispatchDriver disp( pUnk);
2277     if( disp)
2278     {
2279         CComVariant var;
2280         HRESULT hr= S_OK;
2281         // There are two different property names possible.
2282         if( FAILED( hr= disp.GetPropertyByName( SUPPORTED_INTERFACES_PROP, &var)))
2283         {
2284             hr= disp.GetPropertyByName( SUPPORTED_INTERFACES_PROP2, &var);
2285         }
2286         if (SUCCEEDED( hr))
2287         {
2288             // we expect an array( SafeArray or IDispatch) of Strings.
2289             Any anyNames;
2290             variantToAny( &var, anyNames, cppu::UnoType<Sequence<Any>>::get());
2291             Sequence<Any> seqAny;
2292             if( anyNames >>= seqAny)
2293             {
2294                 seqTypes.realloc( seqAny.getLength());
2295                 for( sal_Int32 i=0; i < seqAny.getLength(); i++)
2296                 {
2297                     OUString typeName;
2298                     seqAny[i] >>= typeName;
2299                     seqTypes[i]= Type( TypeClass_INTERFACE, typeName);
2300                 }
2301             }
2302         }
2303     }
2304     return seqTypes;
2305 }
2306 template<class T>
getTypeConverter()2307 Reference<XTypeConverter> UnoConversionUtilities<T>::getTypeConverter()
2308 {
2309     if ( ! m_typeConverter.is())
2310     {
2311         MutexGuard guard(getBridgeMutex());
2312         if ( ! m_typeConverter.is())
2313         {
2314             Reference<XInterface> xIntConverter =
2315                 m_smgr->createInstance("com.sun.star.script.Converter");
2316             if (xIntConverter.is())
2317                 m_typeConverter.set(xIntConverter, UNO_QUERY);
2318         }
2319     }
2320     return m_typeConverter;
2321 }
2322 
2323 // This function tries to the change the type of a value (contained in the Any)
2324 // to the smallest possible that can hold the value. This is actually done only
2325 // for types of VT_I4 (see o2u_variantToAny). The reason is the following:
2326 // JavaScript passes integer values always as VT_I4. If there is a parameter or
2327 // property of type any then the bridge converts the any's content according
2328 // to "o2u_variantToAny". Because the VARTYPE is VT_I4 the value would be converted
2329 // to TypeClass_LONG. Say the method XPropertySet::setPropertyValue( string name, any value)
2330 // would be called on an object and the property actually is of TypeClass_SHORT.
2331 // After conversion of the VARIANT parameter the Any would contain type
2332 // TypeClass_LONG. Because the corereflection does not cast from long to short
2333 // the "setPropertValue" would fail as the value has not the right type.
2334 
2335 // The corereflection does convert small integer types to bigger types.
2336 // Therefore we can reduce the type if possible and avoid the above mentioned
2337 // problem.
2338 
2339 // The function is not used when elements are to be converted for Sequences.
2340 
reduceRange(Any & any)2341 inline void reduceRange( Any& any)
2342 {
2343     OSL_ASSERT( any.getValueTypeClass() == TypeClass_LONG);
2344 
2345     sal_Int32 value= *o3tl::doAccess<sal_Int32>(any);
2346     if( value <= 0x7f &&  value >= -0x80)
2347     {// -128 bis 127
2348         sal_Int8 charVal= static_cast<sal_Int8>( value);
2349         any.setValue( &charVal, cppu::UnoType<sal_Int8>::get());
2350     }
2351     else if( value <= 0x7fff && value >= -0x8000)
2352     {// -32768 bis 32767
2353         sal_Int16 shortVal= static_cast<sal_Int16>( value);
2354         any.setValue( &shortVal, cppu::UnoType<sal_Int16>::get());
2355     }
2356 }
2357 
2358 #endif
2359 
2360 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
2361