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