xref: /core/extensions/source/ole/oleobjw.cxx (revision 3752d828)
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 
20 #include "ole2uno.hxx"
21 #include <sal/log.hxx>
22 #include <o3tl/char16_t2wchar_t.hxx>
23 
24 #include <osl/diagnose.h>
25 #include <osl/doublecheckedlocking.h>
26 #include <osl/thread.h>
27 
28 #include <memory>
29 #include <string_view>
30 #include <com/sun/star/script/CannotConvertException.hpp>
31 #include <com/sun/star/script/FailReason.hpp>
32 #include <com/sun/star/beans/XMaterialHolder.hpp>
33 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
34 #include <com/sun/star/script/XInvocation.hpp>
35 #include <com/sun/star/bridge/ModelDependent.hpp>
36 
37 #include <com/sun/star/bridge/oleautomation/NamedArgument.hpp>
38 #include <com/sun/star/bridge/oleautomation/PropertyPutArgument.hpp>
39 #include <cppuhelper/exc_hlp.hxx>
40 
41 #include <typelib/typedescription.hxx>
42 #include <rtl/uuid.h>
43 #include <rtl/ustring.hxx>
44 
45 #include "jscriptclasses.hxx"
46 
47 #include "oleobjw.hxx"
48 #include "unoobjw.hxx"
49 #include <stdio.h>
50 using namespace osl;
51 using namespace cppu;
52 using namespace com::sun::star::script;
53 using namespace com::sun::star::lang;
54 using namespace com::sun::star::bridge;
55 using namespace com::sun::star::bridge::oleautomation;
56 using namespace com::sun::star::bridge::ModelDependent;
57 using namespace ::com::sun::star;
58 
59 
60 #define JSCRIPT_ID_PROPERTY L"_environment"
61 #define JSCRIPT_ID          L"jscript"
62 
63 // key: XInterface pointer created by Invocation Adapter Factory
64 // value: XInterface pointer to the wrapper class.
65 // Entries to the map are made within
66 // Any createOleObjectWrapper(IUnknown* pUnknown, const Type& aType);
67 // Entries are being deleted if the wrapper class's destructor has been
68 // called.
69 // Before UNO object is wrapped to COM object this map is checked
70 // to see if the UNO object is already a wrapper.
71 std::unordered_map<sal_uIntPtr, sal_uIntPtr> AdapterToWrapperMap;
72 // key: XInterface of the wrapper object.
73 // value: XInterface of the Interface created by the Invocation Adapter Factory.
74 // A COM wrapper is responsible for removing the corresponding entry
75 // in AdapterToWrapperMap if it is being destroyed. Because the wrapper does not
76 // know about its adapted interface it uses WrapperToAdapterMap to get the
77 // adapted interface which is then used to locate the entry in AdapterToWrapperMap.
78 std::unordered_map<sal_uIntPtr,sal_uIntPtr> WrapperToAdapterMap;
79 
80 std::unordered_map<sal_uIntPtr, WeakReference<XInterface> > ComPtrToWrapperMap;
81 
IUnknownWrapper(Reference<XMultiServiceFactory> const & xFactory,sal_uInt8 unoWrapperClass,sal_uInt8 comWrapperClass)82 IUnknownWrapper::IUnknownWrapper( Reference<XMultiServiceFactory> const & xFactory,
83                                   sal_uInt8 unoWrapperClass, sal_uInt8 comWrapperClass):
84     UnoConversionUtilities<IUnknownWrapper>( xFactory, unoWrapperClass, comWrapperClass),
85     m_pxIdlClass( nullptr), m_eJScript( JScriptUndefined),
86     m_bComTlbIndexInit(false),  m_bHasDfltMethod(false), m_bHasDfltProperty(false)
87 {
88 }
89 
90 
~IUnknownWrapper()91 IUnknownWrapper::~IUnknownWrapper()
92 {
93     o2u_attachCurrentThread();
94     MutexGuard guard(getBridgeMutex());
95     XInterface * xIntRoot = static_cast<OWeakObject *>(this);
96 #if OSL_DEBUG_LEVEL > 0
97     acquire(); // make sure we don't delete us twice because of Reference
98     OSL_ASSERT( Reference<XInterface>( static_cast<XWeak*>(this), UNO_QUERY).get() == xIntRoot );
99 #endif
100 
101     // remove entries in global maps
102     auto it= WrapperToAdapterMap.find( reinterpret_cast<sal_uIntPtr>(xIntRoot));
103     if( it != WrapperToAdapterMap.end())
104     {
105         sal_uIntPtr adapter= it->second;
106 
107         AdapterToWrapperMap.erase( adapter);
108         WrapperToAdapterMap.erase( it);
109     }
110 
111     auto it_c= ComPtrToWrapperMap.find( reinterpret_cast<sal_uIntPtr>(m_spUnknown.p));
112     if(it_c != ComPtrToWrapperMap.end())
113         ComPtrToWrapperMap.erase(it_c);
114 }
115 
queryInterface(const Type & t)116 Any IUnknownWrapper::queryInterface(const Type& t)
117 {
118     if (t == cppu::UnoType<XDefaultMethod>::get() && !m_bHasDfltMethod )
119         return Any();
120     if (t == cppu::UnoType<XDefaultProperty>::get() && !m_bHasDfltProperty )
121         return Any();
122     if ( ( t == cppu::UnoType<XInvocation>::get() || t == cppu::UnoType<XAutomationInvocation>::get() ) && !m_spDispatch)
123         return Any();
124     // XDirectInvocation seems to be an oracle replacement for XAutomationInvocation, however it is flawed especially wrt. assumptions about whether to invoke a
125     // Put or Get property, the implementation code has no business guessing that, it's up to the caller to decide that. Worse XDirectInvocation duplicates lots of code.
126     // XAutomationInvocation provides separate calls for put& get
127     // properties. Note: Currently the basic runtime doesn't call put properties directly, it should... after all the basic runtime should know whether it is calling a put or get property.
128     // For the moment for ease of merging we will let the XDirectInvoke and XAuthomationInvocation interfaces stay side by side (and for the moment at least I would prefer the basic
129     // runtime to call XAutomationInvocation instead of XDirectInvoke
130     return WeakImplHelper<XBridgeSupplier2,
131         XInitialization, XAutomationObject, XDefaultProperty, XDefaultMethod, XDirectInvocation, XAutomationInvocation >::queryInterface(t);
132 }
133 
getIntrospection()134 Reference<XIntrospectionAccess> SAL_CALL IUnknownWrapper::getIntrospection()
135 {
136     Reference<XIntrospectionAccess> ret;
137 
138     return ret;
139 }
140 
invokeGetProperty(const OUString & aPropertyName,const Sequence<Any> & aParams,Sequence<sal_Int16> & aOutParamIndex,Sequence<Any> & aOutParam)141 Any SAL_CALL IUnknownWrapper::invokeGetProperty( const OUString& aPropertyName, const Sequence< Any >& aParams, Sequence< sal_Int16 >& aOutParamIndex, Sequence< Any >& aOutParam )
142 {
143     Any aResult;
144     try
145     {
146         o2u_attachCurrentThread();
147         ITypeInfo * pInfo = getTypeInfo();
148         FuncDesc aDescGet(pInfo);
149         FuncDesc aDescPut(pInfo);
150         VarDesc aVarDesc(pInfo);
151         getPropDesc(aPropertyName, & aDescGet, & aDescPut, & aVarDesc);
152         if ( !aDescGet )
153         {
154             OUString msg("[automation bridge]Property \"" + aPropertyName +
155                 "\" is not supported");
156             throw UnknownPropertyException(msg);
157         }
158         aResult = invokeWithDispIdComTlb( aDescGet, aPropertyName, aParams, aOutParamIndex, aOutParam );
159     }
160     catch ( const Exception& e )
161     {
162         css::uno::Any anyEx = cppu::getCaughtException();
163         throw css::lang::WrappedTargetRuntimeException("[automation bridge] unexpected exception in "
164                 "IUnknownWrapper::invokeGetProperty ! Message : \n " +
165                 e.Message,
166                 nullptr, anyEx );
167     }
168     return aResult;
169 }
170 
invokePutProperty(const OUString & aPropertyName,const Sequence<Any> & aParams,Sequence<sal_Int16> & aOutParamIndex,Sequence<Any> & aOutParam)171 Any SAL_CALL IUnknownWrapper::invokePutProperty( const OUString& aPropertyName, const Sequence< Any >& aParams, Sequence< sal_Int16 >& aOutParamIndex, Sequence< Any >& aOutParam )
172 {
173     Any aResult;
174     try
175     {
176         o2u_attachCurrentThread();
177         ITypeInfo * pInfo = getTypeInfo();
178         FuncDesc aDescGet(pInfo);
179         FuncDesc aDescPut(pInfo);
180         VarDesc aVarDesc(pInfo);
181         getPropDesc(aPropertyName, & aDescGet, & aDescPut, & aVarDesc);
182         if ( !aDescPut )
183         {
184             OUString msg("[automation bridge]Property \"" + aPropertyName +
185                 "\" is not supported");
186             throw UnknownPropertyException(msg);
187         }
188         aResult = invokeWithDispIdComTlb( aDescPut, aPropertyName, aParams, aOutParamIndex, aOutParam );
189     }
190     catch ( const Exception& e )
191     {
192         css::uno::Any anyEx = cppu::getCaughtException();
193         throw css::lang::WrappedTargetRuntimeException("[automation bridge] unexpected exception in "
194                 "IUnknownWrapper::invokePutProperty ! Message : \n" +
195                 e.Message,
196                 nullptr, anyEx );
197     }
198     return aResult;
199 }
200 
201 
invoke(const OUString & aFunctionName,const Sequence<Any> & aParams,Sequence<sal_Int16> & aOutParamIndex,Sequence<Any> & aOutParam)202 Any SAL_CALL IUnknownWrapper::invoke( const OUString& aFunctionName,
203              const Sequence< Any >& aParams, Sequence< sal_Int16 >& aOutParamIndex,
204              Sequence< Any >& aOutParam )
205 {
206     if ( ! m_spDispatch )
207     {
208         throw RuntimeException(
209             "[automation bridge] The object does not have an IDispatch interface");
210     }
211 
212     Any ret;
213 
214     try
215     {
216         o2u_attachCurrentThread();
217 
218         TypeDescription methodDesc;
219         getMethodInfo(aFunctionName, methodDesc);
220         if( methodDesc.is())
221         {
222             ret = invokeWithDispIdUnoTlb(aFunctionName,
223                                          aParams,
224                                          aOutParamIndex,
225                                          aOutParam);
226         }
227         else
228         {
229             ret= invokeWithDispIdComTlb( aFunctionName,
230                                          aParams,
231                                          aOutParamIndex,
232                                          aOutParam);
233         }
234     }
235     catch (const IllegalArgumentException &)
236     {
237         throw;
238     }
239     catch (const CannotConvertException &)
240     {
241         throw;
242     }
243     catch (const BridgeRuntimeError & e)
244     {
245          throw RuntimeException(e.message);
246     }
247     catch (const Exception & e)
248     {
249         css::uno::Any anyEx = cppu::getCaughtException();
250         throw css::lang::WrappedTargetRuntimeException("[automation bridge] unexpected exception in "
251                 "IUnknownWrapper::invoke ! Message : \n" +
252                 e.Message,
253                 nullptr, anyEx );
254 
255     }
256     catch(...)
257     {
258         throw RuntimeException("[automation bridge] unexpected exception in "
259                   "IUnknownWrapper::Invoke !");
260     }
261     return ret;
262 }
263 
setValue(const OUString & aPropertyName,const Any & aValue)264 void SAL_CALL IUnknownWrapper::setValue( const OUString& aPropertyName,
265                  const Any& aValue )
266 {
267     if ( ! m_spDispatch )
268     {
269         throw RuntimeException(
270             "[automation bridge] The object does not have an IDispatch interface");
271     }
272     try
273     {
274         o2u_attachCurrentThread();
275 
276         ITypeInfo * pInfo = getTypeInfo();
277         FuncDesc aDescGet(pInfo);
278         FuncDesc aDescPut(pInfo);
279         VarDesc aVarDesc(pInfo);
280         getPropDesc(aPropertyName, & aDescGet, & aDescPut, & aVarDesc);
281         //check if there is such a property at all or if it is read only
282         if ( ! aDescPut && ! aDescGet && ! aVarDesc)
283         {
284             OUString msg("[automation bridge]Property \"" + aPropertyName +
285                          "\" is not supported");
286             throw UnknownPropertyException(msg);
287         }
288 
289         if ( (! aDescPut && aDescGet)
290              || (aVarDesc && aVarDesc->wVarFlags == VARFLAG_FREADONLY) )
291         {
292             //read-only
293             SAL_WARN( "extensions.olebridge", "[automation bridge] Property " << aPropertyName << " is read-only");
294             // ignore silently
295             return;
296         }
297 
298         HRESULT hr= S_OK;
299         DISPPARAMS dispparams;
300         CComVariant varArg;
301         CComVariant varRefArg;
302         CComVariant varResult;
303         ExcepInfo excepinfo;
304         unsigned int uArgErr;
305 
306         // converting UNO value to OLE variant
307         DISPID dispidPut= DISPID_PROPERTYPUT;
308         dispparams.rgdispidNamedArgs = &dispidPut;
309         dispparams.cArgs = 1;
310         dispparams.cNamedArgs = 1;
311         dispparams.rgvarg = & varArg;
312 
313         OSL_ASSERT(aDescPut || aVarDesc);
314 
315         VARTYPE vt = 0;
316         DISPID dispid = 0;
317         INVOKEKIND invkind = INVOKE_PROPERTYPUT;
318         //determine the expected type, dispid, invoke kind (DISPATCH_PROPERTYPUT,
319         //DISPATCH_PROPERTYPUTREF)
320         if (aDescPut)
321         {
322             vt = getElementTypeDesc(& aDescPut->lprgelemdescParam[0].tdesc);
323             dispid = aDescPut->memid;
324             invkind = aDescPut->invkind;
325         }
326         else
327         {
328             vt = getElementTypeDesc( & aVarDesc->elemdescVar.tdesc);
329             dispid = aVarDesc->memid;
330             if (vt == VT_UNKNOWN || vt == VT_DISPATCH ||
331                 (vt & VT_ARRAY) || (vt & VT_BYREF))
332             {
333                 invkind = INVOKE_PROPERTYPUTREF;
334             }
335         }
336 
337         // convert the uno argument
338         if (vt & VT_BYREF)
339         {
340             anyToVariant( & varRefArg, aValue, ::sal::static_int_cast< VARTYPE, int >( vt ^ VT_BYREF ) );
341             varArg.vt = vt;
342             if( (vt & VT_TYPEMASK) == VT_VARIANT)
343                 varArg.byref = & varRefArg;
344             else if ((vt & VT_TYPEMASK) == VT_DECIMAL)
345                 varArg.byref = & varRefArg.decVal;
346             else
347                 varArg.byref = & varRefArg.byref;
348         }
349         else
350         {
351             anyToVariant(& varArg, aValue, vt);
352         }
353         // call to IDispatch
354         hr = m_spDispatch->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, ::sal::static_int_cast< WORD, INVOKEKIND >( invkind ),
355                                  &dispparams, & varResult, & excepinfo, &uArgErr);
356 
357         // lookup error code
358         switch (hr)
359         {
360         case S_OK:
361             break;
362         case DISP_E_BADPARAMCOUNT:
363             throw RuntimeException();
364             break;
365         case DISP_E_BADVARTYPE:
366             throw RuntimeException();
367             break;
368         case DISP_E_EXCEPTION:
369             throw InvocationTargetException();
370             break;
371         case DISP_E_MEMBERNOTFOUND:
372             throw UnknownPropertyException();
373             break;
374         case DISP_E_NONAMEDARGS:
375             throw RuntimeException();
376             break;
377         case DISP_E_OVERFLOW:
378             throw CannotConvertException("call to OLE object failed", static_cast<XInterface*>(
379                                              static_cast<XWeak*>(this)), TypeClass_UNKNOWN, FailReason::OUT_OF_RANGE, uArgErr);
380             break;
381         case DISP_E_PARAMNOTFOUND:
382             throw IllegalArgumentException("call to OLE object failed", static_cast<XInterface*>(
383                                             static_cast<XWeak*>(this)), ::sal::static_int_cast< sal_Int16, unsigned int >( uArgErr )) ;
384             break;
385         case DISP_E_TYPEMISMATCH:
386             throw CannotConvertException("call to OLE object failed", static_cast<XInterface*>(
387                                              static_cast<XWeak*>(this)), TypeClass_UNKNOWN, FailReason::UNKNOWN, ::sal::static_int_cast< sal_Int16, unsigned int >( uArgErr ));
388             break;
389         case DISP_E_UNKNOWNINTERFACE:
390             throw RuntimeException();
391             break;
392         case DISP_E_UNKNOWNLCID:
393             throw RuntimeException();
394             break;
395         case DISP_E_PARAMNOTOPTIONAL:
396             throw CannotConvertException("call to OLE object failed",static_cast<XInterface*>(
397                                              static_cast<XWeak*>(this)) , TypeClass_UNKNOWN, FailReason::NO_DEFAULT_AVAILABLE, uArgErr);
398             break;
399         default:
400             throw  RuntimeException();
401             break;
402         }
403     }
404     catch (const CannotConvertException &)
405     {
406         throw;
407     }
408     catch (const UnknownPropertyException &)
409     {
410         throw;
411     }
412     catch (const BridgeRuntimeError& e)
413     {
414         throw RuntimeException(e.message);
415     }
416     catch (const Exception & e)
417     {
418         css::uno::Any anyEx = cppu::getCaughtException();
419         throw css::lang::WrappedTargetRuntimeException("[automation bridge] unexpected exception in "
420                 "IUnknownWrapper::setValue ! Message : \n" +
421                 e.Message,
422                 nullptr, anyEx );
423 
424     }
425     catch (...)
426     {
427         throw RuntimeException(
428             "[automation bridge] unexpected exception in "
429             "IUnknownWrapper::setValue !");
430     }
431 }
432 
getValue(const OUString & aPropertyName)433 Any SAL_CALL IUnknownWrapper::getValue( const OUString& aPropertyName )
434 {
435     if ( ! m_spDispatch )
436     {
437         throw RuntimeException(
438             "[automation bridge] The object does not have an IDispatch interface");
439     }
440     Any ret;
441     try
442     {
443         o2u_attachCurrentThread();
444         ITypeInfo * pInfo = getTypeInfo();
445         // I was going to implement an XServiceInfo interface to allow the type
446         // of the automation object to be exposed... but it seems
447         // from looking at comments in the code that it is possible for
448         // this object to actually wrap a UNO object ( I guess if automation is
449         // used from MSO to create Openoffice objects ) Therefore, those objects
450         // will more than likely already have their own XServiceInfo interface.
451         // Instead here I chose a name that should be illegal both in COM and
452         // UNO ( from an IDL point of view ) therefore I think this is a safe
453         // hack
454         if ( aPropertyName == "$GetTypeName" )
455         {
456             if ( pInfo && m_sTypeName.getLength() == 0 )
457             {
458                 m_sTypeName = "IDispatch";
459                 CComBSTR sName;
460 
461                 if ( SUCCEEDED( pInfo->GetDocumentation( -1, &sName, nullptr, nullptr, nullptr  ) ) )
462                 {
463                     OUString sTmp( o3tl::toU(LPCOLESTR(sName)));
464                     if ( sTmp.startsWith("_") )
465                        sTmp = sTmp.copy(1);
466                     // do we own the memory for pTypeLib, msdn doc is vague
467                     // I'll assume we do
468                     CComPtr< ITypeLib > pTypeLib;
469                     unsigned int index;
470                     if ( SUCCEEDED(  pInfo->GetContainingTypeLib(  &pTypeLib.p, &index )) )
471                     {
472                         if ( SUCCEEDED( pTypeLib->GetDocumentation( -1, &sName, nullptr, nullptr, nullptr  ) ) )
473                         {
474                             OUString sLibName( o3tl::toU(LPCOLESTR(sName)));
475                             m_sTypeName = sLibName + "." + sTmp;
476 
477                         }
478                     }
479                 }
480 
481             }
482             ret <<= m_sTypeName;
483             return ret;
484         }
485         FuncDesc aDescGet(pInfo);
486         FuncDesc aDescPut(pInfo);
487         VarDesc aVarDesc(pInfo);
488         getPropDesc(aPropertyName, & aDescGet, & aDescPut, & aVarDesc);
489         if ( ! aDescGet && ! aDescPut && ! aVarDesc)
490         {
491             //property not found
492             OUString msg("[automation bridge]Property \"" + aPropertyName +
493                          "\" is not supported");
494             throw UnknownPropertyException(msg);
495         }
496         // write-only should not be possible
497         OSL_ASSERT(  aDescGet  || ! aDescPut);
498 
499         HRESULT hr;
500         DISPPARAMS dispparams = {nullptr, nullptr, 0, 0};
501         CComVariant varResult;
502         ExcepInfo excepinfo;
503         unsigned int uArgErr;
504         DISPID dispid;
505         if (aDescGet)
506             dispid = aDescGet->memid;
507         else if (aVarDesc)
508             dispid = aVarDesc->memid;
509         else
510             dispid = aDescPut->memid;
511 
512         hr = m_spDispatch->Invoke(dispid,
513                                  IID_NULL,
514                                  LOCALE_USER_DEFAULT,
515                                  DISPATCH_PROPERTYGET,
516                                  &dispparams,
517                                  &varResult,
518                                  &excepinfo,
519                                  &uArgErr);
520 
521         // converting return value and out parameter back to UNO
522         if (hr == S_OK)
523         {
524             // If the com object implements uno interfaces then we have
525             // to convert the attribute into the expected type.
526             TypeDescription attrInfo;
527             getAttributeInfo(aPropertyName, attrInfo);
528             if( attrInfo.is() )
529                 variantToAny( &varResult, ret, Type( attrInfo.get()->pWeakRef));
530             else
531                 variantToAny(&varResult, ret);
532         }
533 
534         // lookup error code
535         switch (hr)
536         {
537         case S_OK:
538             break;
539         case DISP_E_BADPARAMCOUNT:
540         case DISP_E_BADVARTYPE:
541         case DISP_E_EXCEPTION:
542             throw RuntimeException(OUString(o3tl::toU(excepinfo.bstrDescription)));
543             break;
544         case DISP_E_MEMBERNOTFOUND:
545             throw UnknownPropertyException(OUString(o3tl::toU(excepinfo.bstrDescription)));
546             break;
547         default:
548             throw RuntimeException(OUString(o3tl::toU(excepinfo.bstrDescription)));
549             break;
550         }
551     }
552     catch ( const UnknownPropertyException& )
553     {
554         throw;
555     }
556     catch (const BridgeRuntimeError& e)
557     {
558         throw RuntimeException(e.message);
559     }
560     catch (const Exception & e)
561     {
562         css::uno::Any anyEx = cppu::getCaughtException();
563         throw css::lang::WrappedTargetRuntimeException("[automation bridge] unexpected exception in "
564                 "IUnknownWrapper::getValue ! Message : \n" +
565                 e.Message,
566                 nullptr, anyEx );
567     }
568     catch (...)
569     {
570         throw RuntimeException(
571             "[automation bridge] unexpected exception in "
572             "IUnknownWrapper::getValue !");
573     }
574     return ret;
575 }
576 
hasMethod(const OUString & aName)577 sal_Bool SAL_CALL IUnknownWrapper::hasMethod( const OUString& aName )
578 {
579     if ( ! m_spDispatch )
580     {
581         throw RuntimeException(
582             "[automation bridge] The object does not have an IDispatch interface");
583     }
584     bool ret = false;
585 
586     try
587     {
588         o2u_attachCurrentThread();
589         ITypeInfo* pInfo = getTypeInfo();
590         FuncDesc aDesc(pInfo);
591         getFuncDesc(aName, & aDesc);
592         // Automation properties can have arguments. Those are treated as methods and
593         //are called through XInvocation::invoke.
594         if ( ! aDesc)
595         {
596             FuncDesc aDescGet(pInfo);
597             FuncDesc aDescPut(pInfo);
598             VarDesc aVarDesc(pInfo);
599             getPropDesc( aName, & aDescGet, & aDescPut, & aVarDesc);
600             if ((aDescGet && aDescGet->cParams > 0)
601                 || (aDescPut && aDescPut->cParams > 0))
602                 ret = true;
603         }
604         else
605             ret = true;
606     }
607     catch (const BridgeRuntimeError& e)
608     {
609         throw RuntimeException(e.message);
610     }
611     catch (const Exception & e)
612     {
613         css::uno::Any anyEx = cppu::getCaughtException();
614         throw css::lang::WrappedTargetRuntimeException("[automation bridge] unexpected exception in "
615                 "IUnknownWrapper::hasMethod ! Message : \n" +
616                 e.Message,
617                 nullptr, anyEx );
618     }
619     catch (...)
620     {
621         throw RuntimeException("[automation bridge] unexpected exception in "
622             "IUnknownWrapper::hasMethod !");
623     }
624     return ret;
625 }
626 
hasProperty(const OUString & aName)627 sal_Bool SAL_CALL IUnknownWrapper::hasProperty( const OUString& aName )
628 {
629     if ( ! m_spDispatch )
630     {
631         throw RuntimeException("[automation bridge] The object does not have an "
632             "IDispatch interface");
633     }
634     bool ret = false;
635     try
636     {
637         o2u_attachCurrentThread();
638 
639         ITypeInfo * pInfo = getTypeInfo();
640         FuncDesc aDescGet(pInfo);
641         FuncDesc aDescPut(pInfo);
642         VarDesc aVarDesc(pInfo);
643         getPropDesc(aName, & aDescGet, & aDescPut, & aVarDesc);
644 
645     // we should probably just check the func kind
646         // basic has been modified to handle properties ( 'get' ) props at
647     // least with parameters
648     // additionally you can call invoke(Get|Set)Property on the bridge
649         // you can determine if a property has parameter is hasMethod
650     // returns true for the name
651         if (aVarDesc
652             || aDescPut
653             || aDescGet )
654         {
655             ret = true;
656         }
657     }
658     catch (const BridgeRuntimeError& e)
659     {
660         throw RuntimeException(e.message);
661     }
662     catch (const Exception & e)
663     {
664         css::uno::Any anyEx = cppu::getCaughtException();
665         throw css::lang::WrappedTargetRuntimeException("[automation bridge] unexpected exception in "
666                 "IUnknownWrapper::hasProperty ! Message : \n" +
667                 e.Message,
668                 nullptr, anyEx );
669 
670     }
671     catch (...)
672     {
673         throw RuntimeException("[automation bridge] unexpected exception in "
674             "IUnknownWrapper::hasProperty !");
675     }
676     return ret;
677 }
678 
createBridge(const Any & modelDepObject,const Sequence<sal_Int8> &,sal_Int16 sourceModelType,sal_Int16 destModelType)679 Any SAL_CALL IUnknownWrapper::createBridge( const Any& modelDepObject,
680                 const Sequence< sal_Int8 >& /*aProcessId*/, sal_Int16 sourceModelType,
681                  sal_Int16 destModelType )
682 {
683     Any ret;
684     o2u_attachCurrentThread();
685 
686     if (
687         (sourceModelType == UNO) &&
688         (destModelType == OLE) &&
689         (modelDepObject.getValueTypeClass() == TypeClass_INTERFACE)
690        )
691     {
692         Reference<XInterface> xInt( *static_cast<XInterface* const *>(modelDepObject.getValue()));
693         Reference<XInterface> xSelf( static_cast<OWeakObject*>(this));
694 
695         if (xInt == xSelf)
696         {
697             VARIANT* pVariant = static_cast<VARIANT*>(CoTaskMemAlloc(sizeof(VARIANT)));
698             assert(pVariant && "Don't handle OOM conditions");
699 
700             VariantInit(pVariant);
701             if (m_bOriginalDispatch)
702             {
703                 pVariant->vt = VT_DISPATCH;
704                 pVariant->pdispVal = m_spDispatch;
705                 pVariant->pdispVal->AddRef();
706             }
707             else
708             {
709                 pVariant->vt = VT_UNKNOWN;
710                 pVariant->punkVal = m_spUnknown;
711                 pVariant->punkVal->AddRef();
712             }
713 
714             ret.setValue(static_cast<void*>(&pVariant), cppu::UnoType<sal_uIntPtr>::get());
715         }
716     }
717 
718     return ret;
719 }
720 /** @internal
721     @exception IllegalArgumentException
722     @exception CannotConvertException
723     @exception InvocationTargetException
724     @RuntimeException
725 */
invokeWithDispIdUnoTlb(const OUString & sFunctionName,const Sequence<Any> & Params,Sequence<sal_Int16> & OutParamIndex,Sequence<Any> & OutParam)726 Any  IUnknownWrapper::invokeWithDispIdUnoTlb(const OUString& sFunctionName,
727                                              const Sequence< Any >& Params,
728                                              Sequence< sal_Int16 >& OutParamIndex,
729                                              Sequence< Any >& OutParam)
730 {
731     Any ret;
732     HRESULT hr= S_OK;
733 
734     sal_Int32 parameterCount= Params.getLength();
735     sal_Int32 outParameterCount= 0;
736     typelib_InterfaceMethodTypeDescription* pMethod= nullptr;
737     TypeDescription methodDesc;
738     getMethodInfo(sFunctionName, methodDesc);
739 
740     // We need to know whether the IDispatch is from a JScript object.
741     // Then out and in/out parameters have to be treated differently than
742     // with common COM objects.
743     bool bJScriptObject= isJScriptObject();
744     std::unique_ptr<CComVariant[]> sarParams;
745     std::unique_ptr<CComVariant[]> sarParamsRef;
746     CComVariant *pVarParams= nullptr;
747     CComVariant *pVarParamsRef= nullptr;
748     bool bConvRet= true;
749 
750     if( methodDesc.is())
751     {
752         pMethod = reinterpret_cast<typelib_InterfaceMethodTypeDescription*>(methodDesc.get());
753         parameterCount = pMethod->nParams;
754         // Create the Array for the array being passed in DISPPARAMS
755         // the array also contains the outparameter (but not the values)
756         if( pMethod->nParams > 0)
757         {
758             sarParams.reset(new CComVariant[ parameterCount]);
759             pVarParams = sarParams.get();
760         }
761 
762         // Create the Array for the out an in/out parameter. These values
763         // are referenced by the VT_BYREF VARIANTs in DISPPARAMS.
764         // We need to find out the number of out and in/out parameter.
765         for( sal_Int32 i=0; i < parameterCount; i++)
766         {
767             if( pMethod->pParams[i].bOut)
768                 outParameterCount++;
769         }
770 
771         if( !bJScriptObject)
772         {
773             sarParamsRef.reset(new CComVariant[outParameterCount]);
774             pVarParamsRef = sarParamsRef.get();
775             // build up the parameters for IDispatch::Invoke
776             sal_Int32 outParamIndex=0;
777             int i = 0;
778             try
779             {
780                 for( i= 0; i < parameterCount; i++)
781                 {
782                     // In parameter
783                     if( pMethod->pParams[i].bIn && ! pMethod->pParams[i].bOut)
784                     {
785                         anyToVariant( &pVarParams[parameterCount - i -1], Params.getConstArray()[i]);
786                     }
787                     // Out parameter + in/out parameter
788                     else if( pMethod->pParams[i].bOut )
789                     {
790                         CComVariant var;
791                         if(pMethod->pParams[i].bIn)
792                         {
793                             anyToVariant( & var,Params[i]);
794                             pVarParamsRef[outParamIndex] = var;
795                         }
796 
797                         switch( pMethod->pParams[i].pTypeRef->eTypeClass)
798                         {
799                         case typelib_TypeClass_INTERFACE:
800                         case typelib_TypeClass_STRUCT:
801                             if( ! pMethod->pParams[i].bIn)
802                             {
803                                 pVarParamsRef[ outParamIndex].vt= VT_DISPATCH;
804                                 pVarParamsRef[ outParamIndex].pdispVal= nullptr;
805                             }
806                             pVarParams[parameterCount - i -1].vt = VT_DISPATCH | VT_BYREF;
807                             pVarParams[parameterCount - i -1].ppdispVal= &pVarParamsRef[outParamIndex].pdispVal;
808                             break;
809                         case typelib_TypeClass_ENUM:
810                         case typelib_TypeClass_LONG:
811                         case typelib_TypeClass_UNSIGNED_LONG:
812                             if( ! pMethod->pParams[i].bIn)
813                             {
814                                 pVarParamsRef[ outParamIndex].vt = VT_I4;
815                                 pVarParamsRef[ outParamIndex].lVal = 0;
816                             }
817                             pVarParams[parameterCount - i -1].vt = VT_I4 | VT_BYREF;
818                             pVarParams[parameterCount - i -1].plVal= &pVarParamsRef[outParamIndex].lVal;
819                             break;
820                         case typelib_TypeClass_SEQUENCE:
821                             if( ! pMethod->pParams[i].bIn)
822                             {
823                                 pVarParamsRef[ outParamIndex].vt = VT_ARRAY| VT_VARIANT;
824                                 pVarParamsRef[ outParamIndex].parray= nullptr;
825                             }
826                             pVarParams[parameterCount - i -1].vt = VT_ARRAY| VT_BYREF | VT_VARIANT;
827                             pVarParams[parameterCount - i -1].pparray= &pVarParamsRef[outParamIndex].parray;
828                             break;
829                         case typelib_TypeClass_ANY:
830                             if( ! pMethod->pParams[i].bIn)
831                             {
832                                 pVarParamsRef[ outParamIndex].vt = VT_EMPTY;
833                                 pVarParamsRef[ outParamIndex].lVal = 0;
834                             }
835                             pVarParams[parameterCount - i -1].vt = VT_VARIANT | VT_BYREF;
836                             pVarParams[parameterCount - i -1].pvarVal = &pVarParamsRef[outParamIndex];
837                             break;
838                         case typelib_TypeClass_BOOLEAN:
839                             if( ! pMethod->pParams[i].bIn)
840                             {
841                                 pVarParamsRef[ outParamIndex].vt = VT_BOOL;
842                                 pVarParamsRef[ outParamIndex].boolVal = 0;
843                             }
844                             pVarParams[parameterCount - i -1].vt = VT_BOOL| VT_BYREF;
845                             pVarParams[parameterCount - i -1].pboolVal =
846                                 & pVarParamsRef[outParamIndex].boolVal;
847                             break;
848 
849                         case typelib_TypeClass_STRING:
850                             if( ! pMethod->pParams[i].bIn)
851                             {
852                                 pVarParamsRef[ outParamIndex].vt = VT_BSTR;
853                                 pVarParamsRef[ outParamIndex].bstrVal= nullptr;
854                             }
855                             pVarParams[parameterCount - i -1].vt = VT_BSTR| VT_BYREF;
856                             pVarParams[parameterCount - i -1].pbstrVal=
857                                 & pVarParamsRef[outParamIndex].bstrVal;
858                             break;
859 
860                         case typelib_TypeClass_FLOAT:
861                             if( ! pMethod->pParams[i].bIn)
862                             {
863                                 pVarParamsRef[ outParamIndex].vt = VT_R4;
864                                 pVarParamsRef[ outParamIndex].fltVal= 0;
865                             }
866                             pVarParams[parameterCount - i -1].vt = VT_R4| VT_BYREF;
867                             pVarParams[parameterCount - i -1].pfltVal =
868                                 & pVarParamsRef[outParamIndex].fltVal;
869                             break;
870                         case typelib_TypeClass_DOUBLE:
871                             if( ! pMethod->pParams[i].bIn)
872                             {
873                                 pVarParamsRef[ outParamIndex].vt = VT_R8;
874                                 pVarParamsRef[ outParamIndex].dblVal= 0;
875                             }
876                             pVarParams[parameterCount - i -1].vt = VT_R8| VT_BYREF;
877                             pVarParams[parameterCount - i -1].pdblVal=
878                                 & pVarParamsRef[outParamIndex].dblVal;
879                             break;
880                         case typelib_TypeClass_BYTE:
881                             if( ! pMethod->pParams[i].bIn)
882                             {
883                                 pVarParamsRef[ outParamIndex].vt = VT_UI1;
884                                 pVarParamsRef[ outParamIndex].bVal= 0;
885                             }
886                             pVarParams[parameterCount - i -1].vt = VT_UI1| VT_BYREF;
887                             pVarParams[parameterCount - i -1].pbVal=
888                                 & pVarParamsRef[outParamIndex].bVal;
889                             break;
890                         case typelib_TypeClass_CHAR:
891                         case typelib_TypeClass_SHORT:
892                         case typelib_TypeClass_UNSIGNED_SHORT:
893                             if( ! pMethod->pParams[i].bIn)
894                             {
895                                 pVarParamsRef[ outParamIndex].vt = VT_I2;
896                                 pVarParamsRef[ outParamIndex].iVal = 0;
897                             }
898                             pVarParams[parameterCount - i -1].vt = VT_I2| VT_BYREF;
899                             pVarParams[parameterCount - i -1].piVal=
900                                 & pVarParamsRef[outParamIndex].iVal;
901                             break;
902 
903                         default:
904                             if( ! pMethod->pParams[i].bIn)
905                             {
906                                 pVarParamsRef[ outParamIndex].vt = VT_EMPTY;
907                                 pVarParamsRef[ outParamIndex].lVal = 0;
908                             }
909                             pVarParams[parameterCount - i -1].vt = VT_VARIANT | VT_BYREF;
910                             pVarParams[parameterCount - i -1].pvarVal =
911                                 & pVarParamsRef[outParamIndex];
912                         }
913                         outParamIndex++;
914                     } // end else if
915                 } // end for
916             }
917             catch (IllegalArgumentException & e)
918             {
919                 e.ArgumentPosition = ::sal::static_int_cast< sal_Int16, int >( i );
920                 throw;
921             }
922             catch (CannotConvertException & e)
923             {
924                 e.ArgumentIndex = i;
925                 throw;
926             }
927         }
928         else // it is a JScriptObject
929         {
930             int i = 0;
931             try
932             {
933                 for( ; i< parameterCount; i++)
934                 {
935                     // In parameter
936                     if( pMethod->pParams[i].bIn && ! pMethod->pParams[i].bOut)
937                     {
938                         anyToVariant( &pVarParams[parameterCount - i -1], Params.getConstArray()[i]);
939                     }
940                     // Out parameter + in/out parameter
941                     else if( pMethod->pParams[i].bOut )
942                     {
943                         CComObject<JScriptOutParam>* pParamObject;
944                         if( !SUCCEEDED( CComObject<JScriptOutParam>::CreateInstance( &pParamObject)))
945                         {
946                             throw BridgeRuntimeError(
947                                       "[automation bridge]IUnknownWrapper::"
948                                       "invokeWithDispIdUnoTlb\n"
949                                       "Could not create out parameter at index: " +
950                                 OUString::number(static_cast<sal_Int32>(i)));
951                         }
952 
953                         CComPtr<IUnknown> pUnk(pParamObject->GetUnknown());
954                         CComQIPtr<IDispatch> pDisp( pUnk);
955 
956                         pVarParams[ parameterCount - i -1].vt= VT_DISPATCH;
957                         pVarParams[ parameterCount - i -1].pdispVal= pDisp;
958                         pVarParams[ parameterCount - i -1].pdispVal->AddRef();
959                         // if the param is in/out then put the parameter on index 0
960                         if( pMethod->pParams[i].bIn ) // in / out
961                         {
962                             CComVariant varParam;
963                             anyToVariant( &varParam, Params.getConstArray()[i]);
964                             CComDispatchDriver dispDriver( pDisp);
965                             if(FAILED( dispDriver.PutPropertyByName( L"0", &varParam)))
966                                 throw BridgeRuntimeError(
967                                     "[automation bridge]IUnknownWrapper::"
968                                     "invokeWithDispIdUnoTlb\n"
969                                     "Could not set property \"0\" for the in/out "
970                                     "param!");
971 
972                         }
973                     }
974                 }
975             }
976             catch (IllegalArgumentException & e)
977             {
978                 e.ArgumentPosition = ::sal::static_int_cast< sal_Int16, int >( i );
979                 throw;
980             }
981             catch (CannotConvertException & e)
982             {
983                 e.ArgumentIndex = i;
984                 throw;
985             }
986         }
987     }
988     // No type description Available, that is we have to deal with a COM component,
989     // that does not implements UNO interfaces ( IDispatch based)
990     else
991     {
992         //We should not run into this block, because invokeWithDispIdComTlb should
993         //have been called instead.
994         OSL_ASSERT(false);
995     }
996 
997 
998     CComVariant     varResult;
999     ExcepInfo       excepinfo;
1000     unsigned int    uArgErr;
1001     DISPPARAMS dispparams= { pVarParams, nullptr, static_cast<UINT>(parameterCount), 0};
1002 
1003     // Get the DISPID
1004     FuncDesc aDesc(getTypeInfo());
1005     getFuncDesc(sFunctionName, & aDesc);
1006     // invoking OLE method
1007     hr = m_spDispatch->Invoke(aDesc->memid,
1008                              IID_NULL,
1009                              LOCALE_USER_DEFAULT,
1010                              DISPATCH_METHOD,
1011                              &dispparams,
1012                              &varResult,
1013                              &excepinfo,
1014                              &uArgErr);
1015 
1016     // converting return value and out parameter back to UNO
1017     if (hr == S_OK)
1018     {
1019         if( outParameterCount && pMethod)
1020         {
1021             OutParamIndex.realloc( outParameterCount);
1022             auto pOutParamIndex = OutParamIndex.getArray();
1023             OutParam.realloc( outParameterCount);
1024             auto pOutParam = OutParam.getArray();
1025             sal_Int32 outIndex=0;
1026             int i = 0;
1027             try
1028             {
1029                 for( ; i < parameterCount; i++)
1030                 {
1031                     if( pMethod->pParams[i].bOut )
1032                     {
1033                         pOutParamIndex[outIndex]= static_cast<sal_Int16>(i);
1034                         Any outAny;
1035                         if( !bJScriptObject)
1036                         {
1037                             variantToAny( &pVarParamsRef[outIndex], outAny,
1038                                         Type(pMethod->pParams[i].pTypeRef), false);
1039                             pOutParam[outIndex++]= outAny;
1040                         }
1041                         else //JScriptObject
1042                         {
1043                             if( pVarParams[i].vt == VT_DISPATCH)
1044                             {
1045                                 CComDispatchDriver pDisp( pVarParams[i].pdispVal);
1046                                 if( pDisp)
1047                                 {
1048                                     CComVariant varOut;
1049                                     if( SUCCEEDED( pDisp.GetPropertyByName( L"0", &varOut)))
1050                                     {
1051                                         variantToAny( &varOut, outAny,
1052                                                     Type(pMethod->pParams[parameterCount - 1 - i].pTypeRef), false);
1053                                         pOutParam[outParameterCount - 1 - outIndex++]= outAny;
1054                                     }
1055                                     else
1056                                         bConvRet= false;
1057                                 }
1058                                 else
1059                                     bConvRet= false;
1060                             }
1061                             else
1062                                 bConvRet= false;
1063                         }
1064                     }
1065                     if( !bConvRet) break;
1066                 }
1067             }
1068             catch(IllegalArgumentException & e)
1069             {
1070                 e.ArgumentPosition = ::sal::static_int_cast< sal_Int16, int >( i );
1071                 throw;
1072             }
1073             catch(CannotConvertException & e)
1074             {
1075                 e.ArgumentIndex = i;
1076                 throw;
1077             }
1078         }
1079         // return value, no type information available
1080         if ( bConvRet)
1081         {
1082             try
1083             {
1084                 if( pMethod )
1085                     variantToAny(&varResult, ret, Type( pMethod->pReturnTypeRef), false);
1086                 else
1087                     variantToAny(&varResult, ret, false);
1088             }
1089             catch (IllegalArgumentException & e)
1090             {
1091                 e.Message =
1092                     "[automation bridge]IUnknownWrapper::invokeWithDispIdUnoTlb\n"
1093                     "Could not convert return value! \n Message: \n" + e.Message;
1094                 throw;
1095             }
1096             catch (CannotConvertException & e)
1097             {
1098                 e.Message =
1099                     "[automation bridge]IUnknownWrapper::invokeWithDispIdUnoTlb\n"
1100                     "Could not convert return value! \n Message: \n" + e.Message;
1101                 throw;
1102             }
1103         }
1104     }
1105 
1106     if( !bConvRet) // conversion of return or out parameter failed
1107         throw CannotConvertException("Call to COM object failed. Conversion of return or out value failed",
1108                                       Reference<XInterface>( static_cast<XWeak*>(this), UNO_QUERY   ), TypeClass_UNKNOWN,
1109                                       FailReason::UNKNOWN, 0);// lookup error code
1110     // conversion of return or out parameter failed
1111     switch (hr)
1112     {
1113     case S_OK:
1114         break;
1115     case DISP_E_BADPARAMCOUNT:
1116         throw IllegalArgumentException();
1117         break;
1118     case DISP_E_BADVARTYPE:
1119         throw RuntimeException();
1120         break;
1121     case DISP_E_EXCEPTION:
1122         throw InvocationTargetException();
1123         break;
1124     case DISP_E_MEMBERNOTFOUND:
1125         throw IllegalArgumentException();
1126         break;
1127     case DISP_E_NONAMEDARGS:
1128         throw IllegalArgumentException();
1129         break;
1130     case DISP_E_OVERFLOW:
1131         throw CannotConvertException("call to OLE object failed", static_cast<XInterface*>(
1132                                          static_cast<XWeak*>(this)), TypeClass_UNKNOWN, FailReason::OUT_OF_RANGE, uArgErr);
1133         break;
1134     case DISP_E_PARAMNOTFOUND:
1135         throw IllegalArgumentException("call to OLE object failed", static_cast<XInterface*>(
1136                                            static_cast<XWeak*>(this)), ::sal::static_int_cast< sal_Int16, unsigned int >( uArgErr ));
1137         break;
1138     case DISP_E_TYPEMISMATCH:
1139         throw CannotConvertException("call to OLE object failed",static_cast<XInterface*>(
1140                                          static_cast<XWeak*>(this)) , TypeClass_UNKNOWN, FailReason::UNKNOWN, uArgErr);
1141         break;
1142     case DISP_E_UNKNOWNINTERFACE:
1143         throw RuntimeException() ;
1144         break;
1145     case DISP_E_UNKNOWNLCID:
1146         throw RuntimeException() ;
1147         break;
1148     case DISP_E_PARAMNOTOPTIONAL:
1149         throw CannotConvertException("call to OLE object failed", static_cast<XInterface*>(
1150                                          static_cast<XWeak*>(this)), TypeClass_UNKNOWN, FailReason::NO_DEFAULT_AVAILABLE, uArgErr);
1151                 break;
1152     default:
1153         throw RuntimeException();
1154         break;
1155     }
1156 
1157     return ret;
1158 }
1159 
1160 
1161 // XInitialization
initialize(const Sequence<Any> & aArguments)1162 void SAL_CALL IUnknownWrapper::initialize( const Sequence< Any >& aArguments )
1163 {
1164     // 1.parameter is IUnknown
1165     // 2.parameter is a boolean which indicates if the COM pointer was an IUnknown or IDispatch
1166     // 3.parameter is a Sequence<Type>
1167     o2u_attachCurrentThread();
1168     OSL_ASSERT(aArguments.getLength() == 3);
1169 
1170     m_spUnknown= *static_cast<IUnknown* const *>(aArguments[0].getValue());
1171     m_spUnknown.QueryInterface( & m_spDispatch.p);
1172 
1173     aArguments[1] >>= m_bOriginalDispatch;
1174     aArguments[2] >>= m_seqTypes;
1175 
1176     ITypeInfo* pType = nullptr;
1177     try
1178     {
1179         // a COM object implementation that has no TypeInfo is still a legal COM object;
1180         // such objects can at least be transported through UNO using the bridge
1181         // so we should allow to create wrappers for them as well
1182         pType = getTypeInfo();
1183     }
1184     catch( const BridgeRuntimeError& )
1185     {}
1186     catch( const Exception& )
1187     {}
1188 
1189     if ( pType )
1190     {
1191         try
1192         {
1193             // Get Default member
1194             CComBSTR defaultMemberName;
1195             if ( SUCCEEDED( pType->GetDocumentation(0, &defaultMemberName, nullptr, nullptr, nullptr ) ) )
1196             {
1197                 OUString usName(o3tl::toU(LPCOLESTR(defaultMemberName)));
1198                 FuncDesc aDescGet(pType);
1199                 FuncDesc aDescPut(pType);
1200                 VarDesc aVarDesc(pType);
1201                 // see if this is a property first ( more likely to be a property then a method )
1202                 getPropDesc( usName, & aDescGet, & aDescPut, & aVarDesc);
1203 
1204                 if ( !aDescGet && !aDescPut )
1205                 {
1206                     getFuncDesc( usName, &aDescGet );
1207                     if ( !aDescGet )
1208                         throw BridgeRuntimeError( "[automation bridge]IUnknownWrapper::initialize() Failed to get Function or Property desc. for " + usName );
1209                 }
1210                 // now for some funny heuristics to make basic understand what to do
1211                 // a single aDescGet ( that doesn't take any params ) would be
1212                 // a read only ( defaultmember ) property e.g. this object
1213                 // should implement XDefaultProperty
1214                 // a single aDescGet ( that *does* ) take params is basically a
1215                 // default method e.g. implement XDefaultMethod
1216 
1217                 // a DescPut ( I guess we only really support a default param with '1' param ) as a setValue ( but I guess we can leave it through, the object will fail if we don't get it right anyway )
1218                 if ( aDescPut || ( aDescGet && aDescGet->cParams == 0 ) )
1219                     m_bHasDfltProperty = true;
1220                 if ( aDescGet->cParams > 0 )
1221                     m_bHasDfltMethod = true;
1222                 if ( m_bHasDfltProperty || m_bHasDfltMethod )
1223                     m_sDefaultMember = usName;
1224             }
1225         }
1226         catch ( const BridgeRuntimeError & e )
1227         {
1228             throw RuntimeException( e.message );
1229         }
1230         catch( const Exception& e )
1231         {
1232             css::uno::Any anyEx = cppu::getCaughtException();
1233             throw css::lang::WrappedTargetRuntimeException(
1234                     "[automation bridge] unexpected exception in IUnknownWrapper::initialize() error message: \n" + e.Message,
1235                     nullptr, anyEx );
1236         }
1237     }
1238 }
1239 
1240 
1241 // XDirectInvocation
directInvoke(const OUString & aName,const uno::Sequence<uno::Any> & aParams)1242 uno::Any SAL_CALL IUnknownWrapper::directInvoke( const OUString& aName, const uno::Sequence< uno::Any >& aParams )
1243 {
1244     Any aResult;
1245 
1246     if ( !m_spDispatch )
1247     {
1248         throw RuntimeException(
1249             "[automation bridge] The object does not have an IDispatch interface");
1250     }
1251 
1252     o2u_attachCurrentThread();
1253     DISPID dispid;
1254     if ( !getDispid( aName, &dispid ) )
1255         throw IllegalArgumentException(
1256             "[automation bridge] The object does not have a function or property "
1257             + aName, Reference<XInterface>(), 0);
1258 
1259     CComVariant     varResult;
1260     ExcepInfo       excepinfo;
1261     unsigned int    uArgErr = 0;
1262     INVOKEKIND pInvkinds[2];
1263     pInvkinds[0] = INVOKE_FUNC;
1264     pInvkinds[1] = aParams.getLength() ? INVOKE_PROPERTYPUT : INVOKE_PROPERTYGET;
1265     HRESULT hInvRes = E_FAIL;
1266 
1267     // try Invoke first, if it does not work, try put/get property
1268     for ( sal_Int32 nStep = 0; FAILED( hInvRes ) && nStep < 2; nStep++ )
1269     {
1270         DISPPARAMS      dispparams = {nullptr, nullptr, 0, 0};
1271 
1272         std::unique_ptr<DISPID[]> arDispidNamedArgs;
1273         std::unique_ptr<CComVariant[]> ptrArgs;
1274         std::unique_ptr<CComVariant[]> ptrRefArgs; // referenced arguments
1275         CComVariant * arArgs = nullptr;
1276         CComVariant * arRefArgs = nullptr;
1277 
1278         dispparams.cArgs = aParams.getLength();
1279 
1280         // Determine the number of named arguments
1281         for ( uno::Any const & any : aParams )
1282             if ( any.getValueType() == cppu::UnoType<NamedArgument>::get() )
1283                 dispparams.cNamedArgs ++;
1284 
1285         // fill the named arguments
1286         if ( dispparams.cNamedArgs > 0
1287           && ( dispparams.cNamedArgs != 1 || pInvkinds[nStep] != INVOKE_PROPERTYPUT ) )
1288         {
1289             int nSizeAr = dispparams.cNamedArgs + 1;
1290             if ( pInvkinds[nStep] == INVOKE_PROPERTYPUT )
1291                 nSizeAr = dispparams.cNamedArgs;
1292 
1293             std::unique_ptr<OLECHAR*[]> saNames(new OLECHAR*[nSizeAr]);
1294             OLECHAR ** pNames = saNames.get();
1295             pNames[0] = const_cast<OLECHAR*>(o3tl::toW(aName.getStr()));
1296 
1297             int cNamedArg = 0;
1298             for ( size_t nInd = 0; nInd < dispparams.cArgs; nInd++ )
1299             {
1300                 if (auto v = o3tl::tryAccess<NamedArgument>(aParams[nInd]))
1301                 {
1302                     const NamedArgument& arg = *v;
1303 
1304                     //We put the parameter names in reverse order into the array,
1305                     //so we can use the DISPID array for DISPPARAMS::rgdispidNamedArgs
1306                     //The first name in the array is the method name
1307                     pNames[nSizeAr - 1 - cNamedArg++] = const_cast<OLECHAR*>(o3tl::toW(arg.Name.getStr()));
1308                 }
1309             }
1310 
1311             arDispidNamedArgs.reset( new DISPID[nSizeAr] );
1312             HRESULT hr = getTypeInfo()->GetIDsOfNames( pNames, nSizeAr, arDispidNamedArgs.get() );
1313             if ( hr == E_NOTIMPL )
1314                 hr = m_spDispatch->GetIDsOfNames(IID_NULL, pNames, nSizeAr, LOCALE_USER_DEFAULT, arDispidNamedArgs.get() );
1315 
1316             if ( SUCCEEDED( hr ) )
1317             {
1318                 if ( pInvkinds[nStep] == DISPATCH_PROPERTYPUT )
1319                 {
1320                     DISPID*  arIDs = arDispidNamedArgs.get();
1321                     arIDs[0] = DISPID_PROPERTYPUT;
1322                     dispparams.rgdispidNamedArgs = arIDs;
1323                 }
1324                 else
1325                 {
1326                     DISPID*  arIDs = arDispidNamedArgs.get();
1327                     dispparams.rgdispidNamedArgs = & arIDs[1];
1328                 }
1329             }
1330             else if (hr == DISP_E_UNKNOWNNAME)
1331             {
1332                  throw IllegalArgumentException(
1333                      "[automation bridge]One of the named arguments is wrong!",
1334                      Reference<XInterface>(), 0);
1335             }
1336             else
1337             {
1338                 throw InvocationTargetException(
1339                     "[automation bridge] ITypeInfo::GetIDsOfNames returned error "
1340                     + OUString::number(static_cast<sal_Int32>(hr), 16), Reference<XInterface>(), Any());
1341             }
1342         }
1343 
1344         //Convert arguments
1345         ptrArgs.reset(new CComVariant[dispparams.cArgs]);
1346         ptrRefArgs.reset(new CComVariant[dispparams.cArgs]);
1347         arArgs = ptrArgs.get();
1348         arRefArgs = ptrRefArgs.get();
1349 
1350         sal_Int32 nInd = 0;
1351         try
1352         {
1353             sal_Int32 revIndex = 0;
1354             for ( nInd = 0; nInd < sal_Int32(dispparams.cArgs); nInd++)
1355             {
1356                 revIndex = dispparams.cArgs - nInd - 1;
1357                 arRefArgs[revIndex].byref = nullptr;
1358                 Any  anyArg;
1359                 if ( nInd < aParams.getLength() )
1360                     anyArg = aParams.getConstArray()[nInd];
1361 
1362                 // Property Put arguments
1363                 if ( anyArg.getValueType() == cppu::UnoType<PropertyPutArgument>::get() )
1364                 {
1365                     PropertyPutArgument arg;
1366                     anyArg >>= arg;
1367                     anyArg = arg.Value;
1368                 }
1369                 // named argument
1370                 if (anyArg.getValueType() == cppu::UnoType<NamedArgument>::get())
1371                 {
1372                     NamedArgument aNamedArgument;
1373                     anyArg >>= aNamedArgument;
1374                     anyArg = aNamedArgument.Value;
1375                 }
1376 
1377                 if ( nInd < aParams.getLength() && anyArg.getValueTypeClass() != TypeClass_VOID )
1378                 {
1379                     anyToVariant( &arArgs[revIndex], anyArg, VT_VARIANT );
1380                 }
1381                 else
1382                 {
1383                     arArgs[revIndex].vt = VT_ERROR;
1384                     arArgs[revIndex].scode = DISP_E_PARAMNOTFOUND;
1385                 }
1386             }
1387         }
1388         catch (IllegalArgumentException & e)
1389         {
1390             e.ArgumentPosition = ::sal::static_int_cast< sal_Int16, sal_Int32 >( nInd );
1391             throw;
1392         }
1393         catch (CannotConvertException & e)
1394         {
1395             e.ArgumentIndex = nInd;
1396             throw;
1397         }
1398 
1399         dispparams.rgvarg = arArgs;
1400         // invoking OLE method
1401         hInvRes = m_spDispatch->Invoke( dispid,
1402                                         IID_NULL,
1403                                         LOCALE_USER_DEFAULT,
1404                                         ::sal::static_int_cast< WORD, INVOKEKIND >( pInvkinds[nStep] ),
1405                                         &dispparams,
1406                                         &varResult,
1407                                         &excepinfo,
1408                                         &uArgErr);
1409     }
1410 
1411     // converting return value and out parameter back to UNO
1412     if ( SUCCEEDED( hInvRes ) )
1413         variantToAny( &varResult, aResult, false );
1414     else
1415     {
1416         // map error codes to exceptions
1417         OUString message;
1418         switch ( hInvRes )
1419         {
1420             case S_OK:
1421                 break;
1422             case DISP_E_BADPARAMCOUNT:
1423                 throw IllegalArgumentException("[automation bridge] Wrong "
1424                       "number of arguments. Object returned DISP_E_BADPARAMCOUNT.",
1425                       nullptr, 0);
1426                 break;
1427             case DISP_E_BADVARTYPE:
1428                 throw RuntimeException("[automation bridge] One or more "
1429                       "arguments have the wrong type. Object returned "
1430                       "DISP_E_BADVARTYPE.", nullptr);
1431                 break;
1432             case DISP_E_EXCEPTION:
1433                     message = OUString::Concat("[automation bridge]: ")
1434                         + std::u16string_view(o3tl::toU(excepinfo.bstrDescription),
1435                             ::SysStringLen(excepinfo.bstrDescription));
1436                     throw InvocationTargetException(message, Reference<XInterface>(), Any());
1437                     break;
1438             case DISP_E_MEMBERNOTFOUND:
1439                 message = "[automation bridge]: A function with the name \""
1440                     + aName + "\" is not supported. Object returned "
1441                     "DISP_E_MEMBERNOTFOUND.";
1442                 throw IllegalArgumentException(message, nullptr, 0);
1443                 break;
1444             case DISP_E_NONAMEDARGS:
1445                 throw IllegalArgumentException("[automation bridge] Object "
1446                       "returned DISP_E_NONAMEDARGS",nullptr, ::sal::static_int_cast< sal_Int16, unsigned int >( uArgErr ));
1447                 break;
1448             case DISP_E_OVERFLOW:
1449                 throw CannotConvertException("[automation bridge] Call failed.",
1450                                              static_cast<XInterface*>(
1451                     static_cast<XWeak*>(this)), TypeClass_UNKNOWN, FailReason::OUT_OF_RANGE, uArgErr);
1452                 break;
1453             case DISP_E_PARAMNOTFOUND:
1454                 throw IllegalArgumentException("[automation bridge]Call failed."
1455                                                "Object returned DISP_E_PARAMNOTFOUND.",
1456                                                nullptr, ::sal::static_int_cast< sal_Int16, unsigned int >( uArgErr ));
1457                 break;
1458             case DISP_E_TYPEMISMATCH:
1459                 throw CannotConvertException("[automation bridge] Call  failed. "
1460                                              "Object returned DISP_E_TYPEMISMATCH",
1461                     static_cast<XInterface*>(
1462                     static_cast<XWeak*>(this)) , TypeClass_UNKNOWN, FailReason::UNKNOWN, uArgErr);
1463                 break;
1464             case DISP_E_UNKNOWNINTERFACE:
1465                 throw RuntimeException("[automation bridge] Call failed. "
1466                                            "Object returned DISP_E_UNKNOWNINTERFACE.",nullptr);
1467                 break;
1468             case DISP_E_UNKNOWNLCID:
1469                 throw RuntimeException("[automation bridge] Call failed. "
1470                                            "Object returned DISP_E_UNKNOWNLCID.",nullptr);
1471                 break;
1472             case DISP_E_PARAMNOTOPTIONAL:
1473                 throw CannotConvertException("[automation bridge] Call failed."
1474                       "Object returned DISP_E_PARAMNOTOPTIONAL",
1475                             static_cast<XInterface*>(static_cast<XWeak*>(this)),
1476                                   TypeClass_UNKNOWN, FailReason::NO_DEFAULT_AVAILABLE, uArgErr);
1477                 break;
1478             default:
1479                 throw RuntimeException();
1480                 break;
1481         }
1482     }
1483 
1484     return aResult;
1485 }
1486 
hasMember(const OUString & aName)1487 sal_Bool SAL_CALL IUnknownWrapper::hasMember( const OUString& aName )
1488 {
1489     if ( ! m_spDispatch )
1490     {
1491         throw RuntimeException(
1492             "[automation bridge] The object does not have an IDispatch interface");
1493     }
1494 
1495     o2u_attachCurrentThread();
1496     DISPID dispid;
1497     return getDispid( aName, &dispid );
1498 }
1499 
1500 
1501 // UnoConversionUtilities --------------------------------------------------------------------------------
createUnoWrapperInstance()1502 Reference< XInterface > IUnknownWrapper::createUnoWrapperInstance()
1503 {
1504     if( m_nUnoWrapperClass == INTERFACE_OLE_WRAPPER_IMPL)
1505     {
1506         Reference<XWeak> xWeak= static_cast<XWeak*>( new InterfaceOleWrapper(
1507                                 m_smgr, m_nUnoWrapperClass, m_nComWrapperClass));
1508         return Reference<XInterface>( xWeak, UNO_QUERY);
1509     }
1510     else if( m_nUnoWrapperClass == UNO_OBJECT_WRAPPER_REMOTE_OPT)
1511     {
1512         Reference<XWeak> xWeak= static_cast<XWeak*>( new UnoObjectWrapperRemoteOpt(
1513                                 m_smgr, m_nUnoWrapperClass, m_nComWrapperClass));
1514         return Reference<XInterface>( xWeak, UNO_QUERY);
1515     }
1516     else
1517         return Reference<XInterface>();
1518 }
createComWrapperInstance()1519 Reference<XInterface> IUnknownWrapper::createComWrapperInstance()
1520 {
1521     Reference<XWeak> xWeak= static_cast<XWeak*>( new IUnknownWrapper(
1522                             m_smgr, m_nUnoWrapperClass, m_nComWrapperClass));
1523     return Reference<XInterface>( xWeak, UNO_QUERY);
1524 }
1525 
1526 
getMethodInfo(std::u16string_view sName,TypeDescription & methodInfo)1527 void IUnknownWrapper::getMethodInfo(std::u16string_view sName, TypeDescription& methodInfo)
1528 {
1529     TypeDescription desc= getInterfaceMemberDescOfCurrentCall(sName);
1530     if( desc.is())
1531     {
1532         typelib_TypeDescription* pMember= desc.get();
1533         if( pMember->eTypeClass == typelib_TypeClass_INTERFACE_METHOD )
1534             methodInfo= pMember;
1535     }
1536 }
1537 
getAttributeInfo(std::u16string_view sName,TypeDescription & attributeInfo)1538 void IUnknownWrapper::getAttributeInfo(std::u16string_view sName, TypeDescription& attributeInfo)
1539 {
1540     TypeDescription desc= getInterfaceMemberDescOfCurrentCall(sName);
1541     if( desc.is())
1542     {
1543         typelib_TypeDescription* pMember= desc.get();
1544         if( pMember->eTypeClass == typelib_TypeClass_INTERFACE_ATTRIBUTE )
1545         {
1546             attributeInfo= reinterpret_cast<typelib_InterfaceAttributeTypeDescription*>(pMember)->pAttributeTypeRef;
1547         }
1548     }
1549 }
getInterfaceMemberDescOfCurrentCall(std::u16string_view sName)1550 TypeDescription IUnknownWrapper::getInterfaceMemberDescOfCurrentCall(std::u16string_view sName)
1551 {
1552     TypeDescription ret;
1553 
1554     for (auto const& rType : m_seqTypes)
1555     {
1556         TypeDescription _curDesc( rType );
1557         _curDesc.makeComplete();
1558         typelib_InterfaceTypeDescription * pInterface= reinterpret_cast<typelib_InterfaceTypeDescription*>(_curDesc.get());
1559         if( pInterface)
1560         {
1561             typelib_InterfaceMemberTypeDescription* pMember= nullptr;
1562             //find the member description of the current call
1563             for( int j=0; j < pInterface->nAllMembers; j++)
1564             {
1565                 typelib_TypeDescriptionReference* pTypeRefMember = pInterface->ppAllMembers[j];
1566                 typelib_TypeDescription* pDescMember= nullptr;
1567                 TYPELIB_DANGER_GET( &pDescMember, pTypeRefMember);
1568 
1569                 typelib_InterfaceMemberTypeDescription* pInterfaceMember=
1570                     reinterpret_cast<typelib_InterfaceMemberTypeDescription*>(pDescMember);
1571                 if( OUString( pInterfaceMember->pMemberName) == sName)
1572                 {
1573                     pMember= pInterfaceMember;
1574                     break;
1575                 }
1576                 TYPELIB_DANGER_RELEASE( pDescMember);
1577             }
1578 
1579             if( pMember)
1580             {
1581                 ret= &pMember->aBase;
1582                 TYPELIB_DANGER_RELEASE( &pMember->aBase);
1583             }
1584         }
1585         if( ret.is())
1586             break;
1587     }
1588     return ret;
1589 }
1590 
isJScriptObject()1591 bool IUnknownWrapper::isJScriptObject()
1592 {
1593     if(  m_eJScript == JScriptUndefined)
1594     {
1595         CComDispatchDriver disp( m_spDispatch);
1596         if( disp)
1597         {
1598             CComVariant result;
1599             if( SUCCEEDED(  disp.GetPropertyByName( JSCRIPT_ID_PROPERTY, &result)))
1600             {
1601                 if(result.vt == VT_BSTR)
1602                 {
1603                     CComBSTR name( result.bstrVal);
1604                     name.ToLower();
1605                     if( name == CComBSTR(JSCRIPT_ID))
1606                         m_eJScript= IsJScript;
1607                 }
1608             }
1609         }
1610         if( m_eJScript == JScriptUndefined)
1611             m_eJScript= NoJScript;
1612     }
1613 
1614     return m_eJScript != NoJScript;
1615 }
1616 
1617 
1618 /** @internal
1619     The function ultimately calls IDispatch::Invoke on the wrapped COM object.
1620     The COM object does not implement UNO Interfaces ( via IDispatch). This
1621     is the case when the OleObjectFactory service has been used to create a
1622     component.
1623     @exception IllegalArgumentException
1624     @exception CannotConvertException
1625     @InvocationTargetException
1626     @RuntimeException
1627     @BridgeRuntimeError
1628 */
invokeWithDispIdComTlb(const OUString & sFuncName,const Sequence<Any> & Params,Sequence<sal_Int16> & OutParamIndex,Sequence<Any> & OutParam)1629 Any  IUnknownWrapper::invokeWithDispIdComTlb(const OUString& sFuncName,
1630                                              const Sequence< Any >& Params,
1631                                              Sequence< sal_Int16 >& OutParamIndex,
1632                                              Sequence< Any >& OutParam)
1633 {
1634     // Get type info for the call. It can be a method call or property put or
1635     // property get operation.
1636     FuncDesc aFuncDesc(getTypeInfo());
1637     getFuncDescForInvoke(sFuncName, Params, & aFuncDesc);
1638     return invokeWithDispIdComTlb( aFuncDesc, sFuncName, Params, OutParamIndex, OutParam );
1639 }
1640 
invokeWithDispIdComTlb(FuncDesc & aFuncDesc,const OUString & sFuncName,const Sequence<Any> & Params,Sequence<sal_Int16> & OutParamIndex,Sequence<Any> & OutParam)1641 Any  IUnknownWrapper::invokeWithDispIdComTlb(FuncDesc& aFuncDesc,
1642                                              const OUString& sFuncName,
1643                                              const Sequence< Any >& Params,
1644                                              Sequence< sal_Int16 >& OutParamIndex,
1645                                              Sequence< Any >& OutParam)
1646 {
1647     Any ret;
1648     HRESULT result;
1649 
1650     DISPPARAMS      dispparams = {nullptr, nullptr, 0, 0};
1651     CComVariant     varResult;
1652     ExcepInfo       excepinfo;
1653     unsigned int    uArgErr;
1654     sal_Int32       i = 0;
1655     sal_Int32 nUnoArgs = Params.getLength();
1656     DISPID idPropertyPut = DISPID_PROPERTYPUT;
1657     std::unique_ptr<DISPID[]> arDispidNamedArgs;
1658     std::unique_ptr<CComVariant[]> ptrArgs;
1659     std::unique_ptr<CComVariant[]> ptrRefArgs; // referenced arguments
1660     CComVariant * arArgs = nullptr;
1661     CComVariant * arRefArgs = nullptr;
1662     sal_Int32 revIndex = 0;
1663 
1664     //Set the array of DISPIDs for named args if it is a property put operation.
1665     //If there are other named arguments another array is set later on.
1666     if (aFuncDesc->invkind == INVOKE_PROPERTYPUT
1667         || aFuncDesc->invkind == INVOKE_PROPERTYPUTREF)
1668         dispparams.rgdispidNamedArgs = & idPropertyPut;
1669 
1670     //Determine the number of named arguments
1671     for (int iParam = 0; iParam < nUnoArgs; iParam ++)
1672     {
1673         const Any & curArg = Params[iParam];
1674         if (curArg.getValueType() == cppu::UnoType<NamedArgument>::get())
1675             dispparams.cNamedArgs ++;
1676     }
1677     //In a property put operation a property value is a named argument (DISPID_PROPERTYPUT).
1678     //Therefore the number of named arguments is increased by one.
1679     //Although named, the argument is not named in an actual language, such as Basic,
1680     //therefore it is never a com.sun.star.bridge.oleautomation.NamedArgument
1681     if (aFuncDesc->invkind == DISPATCH_PROPERTYPUT
1682         || aFuncDesc->invkind == DISPATCH_PROPERTYPUTREF)
1683         dispparams.cNamedArgs ++;
1684 
1685     //Determine the number of all arguments and named arguments
1686     if (aFuncDesc->cParamsOpt == -1)
1687     {
1688         //Attribute vararg is set on this method. "Unlimited" number of args
1689         //supported. There can be no optional or defaultvalue on any of the arguments.
1690         dispparams.cArgs = nUnoArgs;
1691     }
1692     else
1693     {
1694         //If there are named arguments, then the dispparams.cArgs
1695         //is the number of supplied args, otherwise it is the expected number.
1696         if (dispparams.cNamedArgs)
1697             dispparams.cArgs = nUnoArgs;
1698         else
1699             dispparams.cArgs = aFuncDesc->cParams;
1700     }
1701 
1702     //check if there are not too many arguments supplied
1703     if (::sal::static_int_cast< sal_uInt32, int >( nUnoArgs ) > dispparams.cArgs)
1704     {
1705         throw IllegalArgumentException(
1706             "[automation bridge] There are too many arguments for this method",
1707             Reference<XInterface>(), static_cast<sal_Int16>(dispparams.cArgs));
1708     }
1709 
1710     //Set up the array of DISPIDs (DISPPARAMS::rgdispidNamedArgs)
1711     //for the named arguments.
1712     //If there is only one named arg and if it is because of a property put
1713     //operation, then we need not set up the DISPID array.
1714     if (dispparams.cNamedArgs > 0 &&
1715         ! (dispparams.cNamedArgs == 1 &&
1716            (aFuncDesc->invkind == INVOKE_PROPERTYPUT ||
1717             aFuncDesc->invkind == INVOKE_PROPERTYPUTREF)))
1718     {
1719         //set up an array containing the member and parameter names
1720         //which is then used in ITypeInfo::GetIDsOfNames
1721         //First determine the size of the array of names which is passed to
1722         //ITypeInfo::GetIDsOfNames. It must hold the method names + the named
1723         //args.
1724         int nSizeAr = dispparams.cNamedArgs + 1;
1725         if (aFuncDesc->invkind == INVOKE_PROPERTYPUT
1726             || aFuncDesc->invkind == INVOKE_PROPERTYPUTREF)
1727         {
1728             nSizeAr = dispparams.cNamedArgs; //counts the DISID_PROPERTYPUT
1729         }
1730 
1731         std::unique_ptr<OLECHAR*[]> saNames(new OLECHAR*[nSizeAr]);
1732         OLECHAR ** arNames = saNames.get();
1733         arNames[0] = const_cast<OLECHAR*>(o3tl::toW(sFuncName.getStr()));
1734 
1735         int cNamedArg = 0;
1736         for (size_t iParams = 0; iParams < dispparams.cArgs; iParams ++)
1737         {
1738             const Any &  curArg = Params[iParams];
1739             if (auto v = o3tl::tryAccess<NamedArgument>(curArg))
1740             {
1741                 const NamedArgument& arg = *v;
1742                 //We put the parameter names in reverse order into the array,
1743                 //so we can use the DISPID array for DISPPARAMS::rgdispidNamedArgs
1744                 //The first name in the array is the method name
1745                 arNames[nSizeAr - 1 - cNamedArg++] = const_cast<OLECHAR*>(o3tl::toW(arg.Name.getStr()));
1746             }
1747         }
1748 
1749         //Prepare the array of DISPIDs for ITypeInfo::GetIDsOfNames
1750         //it must be big enough to contain the DISPIDs of the member + parameters
1751         arDispidNamedArgs.reset(new DISPID[nSizeAr]);
1752         HRESULT hr = getTypeInfo()->GetIDsOfNames(arNames, nSizeAr,
1753                                                   arDispidNamedArgs.get());
1754         if ( hr == E_NOTIMPL )
1755             hr = m_spDispatch->GetIDsOfNames(IID_NULL, arNames, nSizeAr, LOCALE_USER_DEFAULT, arDispidNamedArgs.get() );
1756 
1757         if (hr == S_OK)
1758         {
1759             // In a "property put" operation, the property value is a named param with the
1760             //special DISPID DISPID_PROPERTYPUT
1761             if (aFuncDesc->invkind == DISPATCH_PROPERTYPUT
1762                 || aFuncDesc->invkind == DISPATCH_PROPERTYPUTREF)
1763             {
1764                 //Element at index 0 in the DISPID array must be DISPID_PROPERTYPUT
1765                 //The first item in the array arDispidNamedArgs is the DISPID for
1766                 //the method. We replace it with DISPID_PROPERTYPUT.
1767                 DISPID*  arIDs = arDispidNamedArgs.get();
1768                 arIDs[0] = DISPID_PROPERTYPUT;
1769                 dispparams.rgdispidNamedArgs = arIDs;
1770             }
1771             else
1772             {
1773                 //The first item in the array arDispidNamedArgs is the DISPID for
1774                 //the method. It must be removed
1775                 DISPID*  arIDs = arDispidNamedArgs.get();
1776                 dispparams.rgdispidNamedArgs = & arIDs[1];
1777             }
1778         }
1779         else if (hr == DISP_E_UNKNOWNNAME)
1780         {
1781              throw IllegalArgumentException(
1782                  "[automation bridge]One of the named arguments is wrong!",
1783                  Reference<XInterface>(), 0);
1784         }
1785         else
1786         {
1787             throw InvocationTargetException(
1788                 "[automation bridge] ITypeInfo::GetIDsOfNames returned error "
1789                 + OUString::number(static_cast<sal_Int32>(hr), 16), Reference<XInterface>(), Any());
1790         }
1791     }
1792 
1793     //Convert arguments
1794     ptrArgs.reset(new CComVariant[dispparams.cArgs]);
1795     ptrRefArgs.reset(new CComVariant[dispparams.cArgs]);
1796     arArgs = ptrArgs.get();
1797     arRefArgs = ptrRefArgs.get();
1798     try
1799     {
1800         for (i = 0; i < static_cast<sal_Int32>(dispparams.cArgs); i++)
1801         {
1802             revIndex= dispparams.cArgs - i -1;
1803             arRefArgs[revIndex].byref=nullptr;
1804             Any  anyArg;
1805             if ( i < nUnoArgs)
1806                 anyArg= Params.getConstArray()[i];
1807 
1808             unsigned short paramFlags = PARAMFLAG_FOPT | PARAMFLAG_FIN;
1809             VARTYPE varType = VT_VARIANT;
1810             if (aFuncDesc->cParamsOpt != -1 || aFuncDesc->cParams != (i + 1))
1811             {
1812                 paramFlags = aFuncDesc->lprgelemdescParam[i].paramdesc.wParamFlags;
1813                 varType = getElementTypeDesc(&aFuncDesc->lprgelemdescParam[i].tdesc);
1814             }
1815 
1816             // Make sure that there is a UNO parameter for every
1817             // expected parameter. If there is no UNO parameter where the
1818             // called function expects one, then it must be optional. Otherwise
1819             // it's a UNO programming error.
1820             if (i  >= nUnoArgs && !(paramFlags & PARAMFLAG_FOPT))
1821             {
1822                 throw IllegalArgumentException(
1823                     ("ole automation bridge: The called function expects an argument at position: "
1824                      + OUString::number(i) + " (index starting at 0)."),
1825                     Reference<XInterface>(), static_cast<sal_Int16>(i));
1826             }
1827 
1828             // Property Put arguments
1829             if (anyArg.getValueType() == cppu::UnoType<PropertyPutArgument>::get())
1830             {
1831                 PropertyPutArgument arg;
1832                 anyArg >>= arg;
1833                 anyArg = arg.Value;
1834             }
1835             // named argument
1836             if (anyArg.getValueType() == cppu::UnoType<NamedArgument>::get())
1837             {
1838                 NamedArgument aNamedArgument;
1839                 anyArg >>= aNamedArgument;
1840                 anyArg = aNamedArgument.Value;
1841             }
1842             // out param
1843             if (paramFlags & PARAMFLAG_FOUT &&
1844                 ! (paramFlags & PARAMFLAG_FIN)  )
1845             {
1846                 VARTYPE type = ::sal::static_int_cast< VARTYPE, int >( varType ^ VT_BYREF );
1847                 if (i < nUnoArgs)
1848                 {
1849                     arRefArgs[revIndex].vt= type;
1850                 }
1851                 else
1852                 {
1853                     //optional arg
1854                     arRefArgs[revIndex].vt = VT_ERROR;
1855                     arRefArgs[revIndex].scode = DISP_E_PARAMNOTFOUND;
1856                 }
1857                 if( type == VT_VARIANT )
1858                 {
1859                     arArgs[revIndex].vt= VT_VARIANT | VT_BYREF;
1860                     arArgs[revIndex].byref= &arRefArgs[revIndex];
1861                 }
1862                 else
1863                 {
1864                     arArgs[revIndex].vt= varType;
1865                     if (type == VT_DECIMAL)
1866                         arArgs[revIndex].byref= & arRefArgs[revIndex].decVal;
1867                     else
1868                         arArgs[revIndex].byref= & arRefArgs[revIndex].byref;
1869                 }
1870             }
1871             // in/out  + in byref params
1872             else if (varType & VT_BYREF)
1873             {
1874                 VARTYPE type = ::sal::static_int_cast< VARTYPE, int >( varType ^ VT_BYREF );
1875                 CComVariant var;
1876 
1877                 if (i < nUnoArgs && anyArg.getValueTypeClass() != TypeClass_VOID)
1878                 {
1879                     anyToVariant( & arRefArgs[revIndex], anyArg, type);
1880                 }
1881                 else if (paramFlags & PARAMFLAG_FHASDEFAULT)
1882                 {
1883                     //optional arg with default
1884                     VariantCopy( & arRefArgs[revIndex],
1885                                 & aFuncDesc->lprgelemdescParam[i].paramdesc.
1886                                 pparamdescex->varDefaultValue);
1887                 }
1888                 else
1889                 {
1890                     //optional arg
1891                     //e.g: call func(x) in basic : func() ' no arg supplied
1892                     OSL_ASSERT(paramFlags & PARAMFLAG_FOPT);
1893                     arRefArgs[revIndex].vt = VT_ERROR;
1894                     arRefArgs[revIndex].scode = DISP_E_PARAMNOTFOUND;
1895                 }
1896 
1897                 // Set the converted arguments in the array which will be
1898                 // DISPPARAMS::rgvarg
1899                 // byref arg VT_XXX |VT_BYREF
1900                 arArgs[revIndex].vt = varType;
1901                 if (revIndex == 0 && aFuncDesc->invkind == INVOKE_PROPERTYPUT)
1902                 {
1903                     arArgs[revIndex] = arRefArgs[revIndex];
1904                 }
1905                 else if (type == VT_DECIMAL)
1906                 {
1907                     arArgs[revIndex].byref= & arRefArgs[revIndex].decVal;
1908                 }
1909                 else if (type == VT_VARIANT)
1910                 {
1911                     if ( ! (paramFlags & PARAMFLAG_FOUT))
1912                         arArgs[revIndex] = arRefArgs[revIndex];
1913                     else
1914                         arArgs[revIndex].byref = & arRefArgs[revIndex];
1915                 }
1916                 else
1917                 {
1918                     arArgs[revIndex].byref = & arRefArgs[revIndex].byref;
1919                     arArgs[revIndex].vt = ::sal::static_int_cast< VARTYPE, int >( arRefArgs[revIndex].vt | VT_BYREF );
1920                 }
1921 
1922             }
1923             // in parameter no VT_BYREF except for array, interfaces
1924             else
1925             {   // void any stands for optional param
1926                 if (i < nUnoArgs && anyArg.getValueTypeClass() != TypeClass_VOID)
1927                 {
1928                     anyToVariant( & arArgs[revIndex], anyArg, varType);
1929                 }
1930                 //optional arg but no void any supplied
1931                 //Basic:  obj.func() ' first parameter left out because it is optional
1932                 else if (paramFlags & PARAMFLAG_FHASDEFAULT)
1933                 {
1934                     //optional arg with default either as direct arg : VT_XXX or
1935                     VariantCopy( & arArgs[revIndex],
1936                         & aFuncDesc->lprgelemdescParam[i].paramdesc.
1937                             pparamdescex->varDefaultValue);
1938                 }
1939                 else if (paramFlags & PARAMFLAG_FOPT)
1940                 {
1941                     arArgs[revIndex].vt = VT_ERROR;
1942                     arArgs[revIndex].scode = DISP_E_PARAMNOTFOUND;
1943                 }
1944                 else
1945                 {
1946                     arArgs[revIndex].vt = VT_EMPTY;
1947                     arArgs[revIndex].lVal = 0;
1948                 }
1949             }
1950         }
1951     }
1952     catch (IllegalArgumentException & e)
1953     {
1954         e.ArgumentPosition = ::sal::static_int_cast< sal_Int16, sal_Int32 >( i );
1955         throw;
1956     }
1957     catch (CannotConvertException & e)
1958     {
1959         e.ArgumentIndex = i;
1960         throw;
1961     }
1962     dispparams.rgvarg= arArgs;
1963     // invoking OLE method
1964     result = m_spDispatch->Invoke(aFuncDesc->memid,
1965                                  IID_NULL,
1966                                  LOCALE_USER_DEFAULT,
1967                                  ::sal::static_int_cast< WORD, INVOKEKIND >( aFuncDesc->invkind ),
1968                                  &dispparams,
1969                                  &varResult,
1970                                  &excepinfo,
1971                                  &uArgErr);
1972 
1973     // converting return value and out parameter back to UNO
1974     if (result == S_OK)
1975     {
1976 
1977         // allocate space for the out param Sequence and indices Sequence
1978         int outParamsCount= 0; // includes in/out parameter
1979         for (int j = 0; j < aFuncDesc->cParams; j++)
1980         {
1981             if (aFuncDesc->lprgelemdescParam[j].paramdesc.wParamFlags &
1982                 PARAMFLAG_FOUT)
1983                 outParamsCount++;
1984         }
1985 
1986         OutParamIndex.realloc(outParamsCount);
1987         OutParam.realloc(outParamsCount);
1988         // Convert out params
1989         if (outParamsCount)
1990         {
1991             auto pOutParamIndex = OutParamIndex.getArray();
1992             auto pOutParam = OutParam.getArray();
1993             int outParamIndex=0;
1994             for (int paramIndex = 0; paramIndex < nUnoArgs; paramIndex ++)
1995             {
1996                 //Determine the index within the method signature
1997                 int realParamIndex = paramIndex;
1998                 int revParamIndex = dispparams.cArgs - paramIndex - 1;
1999                 if (Params[paramIndex].getValueType()
2000                     == cppu::UnoType<NamedArgument>::get())
2001                 {
2002                     //dispparams.rgdispidNamedArgs contains the mapping from index
2003                     //of named args list to index of parameter list
2004                     realParamIndex = dispparams.rgdispidNamedArgs[revParamIndex];
2005                 }
2006 
2007                 // no named arg, always come before named args
2008                 if (! (aFuncDesc->lprgelemdescParam[realParamIndex].paramdesc.wParamFlags
2009                        & PARAMFLAG_FOUT))
2010                     continue;
2011                 Any outAny;
2012                 // variantToAny is called with the "reduce range" parameter set to sal_False.
2013                 // That causes VT_I4 values not to be converted down to a "lower" type. That
2014                 // feature exist for JScript only because it only uses VT_I4 for integer types.
2015                 try
2016                 {
2017                     variantToAny( & arRefArgs[revParamIndex], outAny, false );
2018                 }
2019                 catch (IllegalArgumentException & e)
2020                 {
2021                     e.ArgumentPosition = static_cast<sal_Int16>(paramIndex);
2022                     throw;
2023                 }
2024                 catch (CannotConvertException & e)
2025                 {
2026                     e.ArgumentIndex = paramIndex;
2027                     throw;
2028                 }
2029                 pOutParam[outParamIndex] = outAny;
2030                 pOutParamIndex[outParamIndex] = ::sal::static_int_cast< sal_Int16, int >( paramIndex );
2031                 outParamIndex++;
2032             }
2033             OutParam.realloc(outParamIndex);
2034             OutParamIndex.realloc(outParamIndex);
2035         }
2036         // Return value
2037         variantToAny(&varResult, ret, false);
2038     }
2039 
2040     // map error codes to exceptions
2041     OUString message;
2042     switch (result)
2043     {
2044         case S_OK:
2045             break;
2046         case DISP_E_BADPARAMCOUNT:
2047             throw IllegalArgumentException("[automation bridge] Wrong "
2048                   "number of arguments. Object returned DISP_E_BADPARAMCOUNT.",
2049                   nullptr, 0);
2050             break;
2051         case DISP_E_BADVARTYPE:
2052             throw RuntimeException("[automation bridge] One or more "
2053                   "arguments have the wrong type. Object returned "
2054                   "DISP_E_BADVARTYPE.", nullptr);
2055             break;
2056         case DISP_E_EXCEPTION:
2057                 message = OUString::Concat("[automation bridge]: ")
2058                     + std::u16string_view(o3tl::toU(excepinfo.bstrDescription),
2059                                     ::SysStringLen(excepinfo.bstrDescription));
2060 
2061                 throw InvocationTargetException(message, Reference<XInterface>(), Any());
2062             break;
2063         case DISP_E_MEMBERNOTFOUND:
2064             message = "[automation bridge]: A function with the name \""
2065                 + sFuncName + "\" is not supported. Object returned "
2066                 "DISP_E_MEMBERNOTFOUND.";
2067             throw IllegalArgumentException(message, nullptr, 0);
2068             break;
2069         case DISP_E_NONAMEDARGS:
2070             throw IllegalArgumentException("[automation bridge] Object "
2071                   "returned DISP_E_NONAMEDARGS",nullptr, ::sal::static_int_cast< sal_Int16, unsigned int >( uArgErr ));
2072             break;
2073         case DISP_E_OVERFLOW:
2074             throw CannotConvertException("[automation bridge] Call failed.",
2075                                          static_cast<XInterface*>(
2076                 static_cast<XWeak*>(this)), TypeClass_UNKNOWN, FailReason::OUT_OF_RANGE, uArgErr);
2077             break;
2078         case DISP_E_PARAMNOTFOUND:
2079             throw IllegalArgumentException("[automation bridge]Call failed."
2080                                            "Object returned DISP_E_PARAMNOTFOUND.",
2081                                            nullptr, ::sal::static_int_cast< sal_Int16, unsigned int >( uArgErr ));
2082             break;
2083         case DISP_E_TYPEMISMATCH:
2084             throw CannotConvertException("[automation bridge] Call  failed. "
2085                                          "Object returned DISP_E_TYPEMISMATCH",
2086                 static_cast<XInterface*>(
2087                 static_cast<XWeak*>(this)) , TypeClass_UNKNOWN, FailReason::UNKNOWN, uArgErr);
2088             break;
2089         case DISP_E_UNKNOWNINTERFACE:
2090             throw RuntimeException("[automation bridge] Call failed. "
2091                                        "Object returned DISP_E_UNKNOWNINTERFACE.",nullptr);
2092             break;
2093         case DISP_E_UNKNOWNLCID:
2094             throw RuntimeException("[automation bridge] Call failed. "
2095                                        "Object returned DISP_E_UNKNOWNLCID.",nullptr);
2096             break;
2097         case DISP_E_PARAMNOTOPTIONAL:
2098             throw CannotConvertException("[automation bridge] Call failed."
2099                   "Object returned DISP_E_PARAMNOTOPTIONAL",
2100                         static_cast<XInterface*>(static_cast<XWeak*>(this)),
2101                               TypeClass_UNKNOWN, FailReason::NO_DEFAULT_AVAILABLE, uArgErr);
2102             break;
2103         default:
2104             throw RuntimeException();
2105             break;
2106     }
2107 
2108     return ret;
2109 }
2110 
getFuncDescForInvoke(const OUString & sFuncName,const Sequence<Any> & seqArgs,FUNCDESC ** pFuncDesc)2111 void IUnknownWrapper::getFuncDescForInvoke(const OUString & sFuncName,
2112                                            const Sequence<Any> & seqArgs,
2113                                            FUNCDESC** pFuncDesc)
2114 {
2115     int nUnoArgs = seqArgs.getLength();
2116     const Any * arArgs = seqArgs.getConstArray();
2117     ITypeInfo* pInfo = getTypeInfo();
2118 
2119     //If the last of the positional arguments is a PropertyPutArgument
2120     //then obtain the type info for the property put operation.
2121 
2122     //The property value is always the last argument, in a positional argument list
2123     //or in a list of named arguments. A PropertyPutArgument is actually a named argument
2124     //hence it must not be put in an extra NamedArgument structure
2125     if (nUnoArgs > 0 &&
2126         arArgs[nUnoArgs - 1].getValueType() == cppu::UnoType<PropertyPutArgument>::get())
2127     {
2128         // DISPATCH_PROPERTYPUT
2129         FuncDesc aDescGet(pInfo);
2130         FuncDesc aDescPut(pInfo);
2131         VarDesc aVarDesc(pInfo);
2132         getPropDesc(sFuncName, & aDescGet, & aDescPut, & aVarDesc);
2133         if ( ! aDescPut)
2134         {
2135             throw IllegalArgumentException(
2136                 "[automation bridge] The object does not have a writeable property: "
2137                 + sFuncName, Reference<XInterface>(), 0);
2138         }
2139         *pFuncDesc = aDescPut.Detach();
2140     }
2141     else
2142     {   // DISPATCH_METHOD
2143         FuncDesc aFuncDesc(pInfo);
2144         getFuncDesc(sFuncName, & aFuncDesc);
2145         if ( ! aFuncDesc)
2146         {
2147             // Fallback: DISPATCH_PROPERTYGET can mostly be called as
2148             // DISPATCH_METHOD
2149             ITypeInfo * pTypeInfo = getTypeInfo();
2150             FuncDesc aDescPut(pTypeInfo);
2151             VarDesc aVarDesc(pTypeInfo);
2152             getPropDesc(sFuncName, & aFuncDesc, & aDescPut, & aVarDesc);
2153             if ( ! aFuncDesc )
2154             {
2155                 throw IllegalArgumentException(
2156                     "[automation bridge] The object does not have a function"
2157                     " or readable property \""
2158                     + sFuncName + "\"", Reference<XInterface>(), 0);
2159             }
2160         }
2161         *pFuncDesc = aFuncDesc.Detach();
2162     }
2163 }
getDispid(const OUString & sFuncName,DISPID * id)2164 bool IUnknownWrapper::getDispid(const OUString& sFuncName, DISPID * id)
2165 {
2166     OSL_ASSERT(m_spDispatch);
2167     LPOLESTR lpsz = const_cast<LPOLESTR> (o3tl::toW(sFuncName.getStr()));
2168     HRESULT hr = m_spDispatch->GetIDsOfNames(IID_NULL, &lpsz, 1, LOCALE_USER_DEFAULT, id);
2169     return hr == S_OK;
2170 }
getFuncDesc(const OUString & sFuncName,FUNCDESC ** pFuncDesc)2171 void IUnknownWrapper::getFuncDesc(const OUString & sFuncName, FUNCDESC ** pFuncDesc)
2172 
2173 {
2174     OSL_ASSERT( * pFuncDesc == nullptr);
2175     buildComTlbIndex();
2176     typedef TLBFuncIndexMap::const_iterator cit;
2177     //We assume there is only one entry with the function name. A property
2178     //would have two entries.
2179     cit itIndex= m_mapComFunc.find(sFuncName);
2180     if (itIndex == m_mapComFunc.end())
2181     {
2182         //try case insensitive with IDispatch::GetIDsOfNames
2183         DISPID id;
2184         if (getDispid(sFuncName, &id))
2185         {
2186             CComBSTR memberName;
2187             unsigned int pcNames=0;
2188             // get the case sensitive name
2189             if( SUCCEEDED(getTypeInfo()->GetNames( id, & memberName, 1, &pcNames)))
2190             {
2191                 //get the associated index and add an entry to the map
2192                 //with the name sFuncName which differs in the casing of the letters to
2193                 //the actual name as obtained from ITypeInfo
2194                 OUString sRealName(o3tl::toU(LPCOLESTR(memberName)));
2195                 cit itOrg  = m_mapComFunc.find(sRealName);
2196                 OSL_ASSERT(itOrg != m_mapComFunc.end());
2197                 // maybe this is a property, if so we need
2198                 // to store either both id's ( put/get ) or
2199                 // just the get. Storing both is more consistent
2200                 std::pair<cit, cit> pItems = m_mapComFunc.equal_range( sRealName );
2201                 for ( ;pItems.first != pItems.second; ++pItems.first )
2202                     m_mapComFunc.insert( TLBFuncIndexMap::value_type ( std::make_pair(sFuncName, pItems.first->second ) ));
2203                 itIndex =
2204                     m_mapComFunc.find( sFuncName );
2205             }
2206         }
2207     }
2208 
2209 #if OSL_DEBUG_LEVEL >= 1
2210     // There must only be one entry if sFuncName represents a function or two
2211     // if it is a property
2212     std::pair<cit, cit> p = m_mapComFunc.equal_range(sFuncName.toAsciiLowerCase());
2213     int numEntries = 0;
2214     for ( ;p.first != p.second; p.first ++, numEntries ++);
2215     OSL_ASSERT( ! (numEntries > 3) );
2216 #endif
2217     if( itIndex != m_mapComFunc.end())
2218     {
2219         ITypeInfo* pType= getTypeInfo();
2220         FUNCDESC * pDesc = nullptr;
2221         if (!SUCCEEDED(pType->GetFuncDesc(itIndex->second, & pDesc)))
2222         {
2223             throw BridgeRuntimeError("[automation bridge] Could not get "
2224                                      "FUNCDESC for " + sFuncName);
2225         }
2226         if (pDesc->invkind == INVOKE_FUNC)
2227         {
2228             (*pFuncDesc) = pDesc;
2229         }
2230         else
2231         {
2232             pType->ReleaseFuncDesc(pDesc);
2233         }
2234     }
2235    //else no entry found for sFuncName, pFuncDesc will not be filled in
2236 }
2237 
getPropDesc(const OUString & sFuncName,FUNCDESC ** pFuncDescGet,FUNCDESC ** pFuncDescPut,VARDESC ** pVarDesc)2238 void IUnknownWrapper::getPropDesc(const OUString & sFuncName, FUNCDESC ** pFuncDescGet,
2239                                   FUNCDESC** pFuncDescPut, VARDESC** pVarDesc)
2240 {
2241     OSL_ASSERT( * pFuncDescGet == nullptr && * pFuncDescPut == nullptr);
2242     buildComTlbIndex();
2243     typedef TLBFuncIndexMap::const_iterator cit;
2244     std::pair<cit, cit> p = m_mapComFunc.equal_range(sFuncName);
2245     if (p.first == m_mapComFunc.end())
2246     {
2247         //try case insensitive with IDispatch::GetIDsOfNames
2248         DISPID id;
2249         if (getDispid(sFuncName, &id))
2250         {
2251             CComBSTR memberName;
2252             unsigned int pcNames=0;
2253             // get the case sensitive name
2254             if( SUCCEEDED(getTypeInfo()->GetNames( id, & memberName, 1, &pcNames)))
2255             {
2256                 //As opposed to getFuncDesc, we do not add the value because we would
2257                 // need to find the get and set description for the property. This would
2258                 //mean to iterate over all FUNCDESCs again.
2259                 p = m_mapComFunc.equal_range(OUString(o3tl::toU(LPCOLESTR(memberName))));
2260             }
2261         }
2262     }
2263 
2264     for ( int i = 0 ;p.first != p.second; p.first ++, i ++)
2265     {
2266         // There are a maximum of two entries, property put and property get
2267         OSL_ASSERT( ! (i > 2) );
2268         ITypeInfo* pType= getTypeInfo();
2269         FUNCDESC * pFuncDesc = nullptr;
2270         if (SUCCEEDED( pType->GetFuncDesc(p.first->second, & pFuncDesc)))
2271         {
2272             if (pFuncDesc->invkind == INVOKE_PROPERTYGET)
2273             {
2274                 (*pFuncDescGet) = pFuncDesc;
2275             }
2276             else if (pFuncDesc->invkind == INVOKE_PROPERTYPUT ||
2277                      pFuncDesc->invkind == INVOKE_PROPERTYPUTREF)
2278             {
2279                 //a property can have 3 entries, put, put ref, get
2280                 // If INVOKE_PROPERTYPUTREF or INVOKE_PROPERTYPUT is used
2281                 //depends on what is found first.
2282                 if ( * pFuncDescPut)
2283                 {
2284                     //we already have found one
2285                     pType->ReleaseFuncDesc(pFuncDesc);
2286                 }
2287                 else
2288                 {
2289                     (*pFuncDescPut) = pFuncDesc;
2290                 }
2291             }
2292             else
2293             {
2294                 pType->ReleaseFuncDesc(pFuncDesc);
2295             }
2296         }
2297         //ITypeInfo::GetFuncDesc may even provide a funcdesc for a VARDESC
2298         // with invkind = INVOKE_FUNC. Since this function should only return
2299         //a value for a real property (XInvokation::hasMethod, ..::hasProperty
2300         //we need to make sure that sFuncName represents a real property.
2301         VARDESC * pVD = nullptr;
2302         if (SUCCEEDED(pType->GetVarDesc(p.first->second, & pVD)))
2303             (*pVarDesc) = pVD;
2304     }
2305    //else no entry for sFuncName, pFuncDesc will not be filled in
2306 }
2307 
getUserDefinedElementType(ITypeInfo * pTypeInfo,const DWORD nHrefType)2308 VARTYPE IUnknownWrapper::getUserDefinedElementType( ITypeInfo* pTypeInfo, const DWORD nHrefType )
2309 {
2310     VARTYPE _type( VT_NULL );
2311     if ( pTypeInfo )
2312     {
2313         CComPtr<ITypeInfo> spRefInfo;
2314         pTypeInfo->GetRefTypeInfo( nHrefType, &spRefInfo.p );
2315         if ( spRefInfo )
2316         {
2317             TypeAttr attr( spRefInfo );
2318             spRefInfo->GetTypeAttr( &attr );
2319             if ( attr->typekind == TKIND_ENUM )
2320             {
2321                 // We use the type of the first enum value.
2322                 if ( attr->cVars == 0 )
2323                 {
2324                     throw BridgeRuntimeError("[automation bridge] Could not obtain type description");
2325                 }
2326                 VarDesc var( spRefInfo );
2327                 spRefInfo->GetVarDesc( 0, &var );
2328                 _type = var->lpvarValue->vt;
2329             }
2330             else if ( attr->typekind == TKIND_INTERFACE )
2331             {
2332                 _type = VT_UNKNOWN;
2333             }
2334             else if ( attr->typekind == TKIND_DISPATCH )
2335             {
2336                 _type = VT_DISPATCH;
2337             }
2338             else if ( attr->typekind == TKIND_ALIAS )
2339             {
2340                 // TKIND_ALIAS is a type that is an alias for another type. So get that alias type.
2341                 _type = getUserDefinedElementType( pTypeInfo, attr->tdescAlias.hreftype );
2342             }
2343             else
2344             {
2345                 throw BridgeRuntimeError( "[automation bridge] Unhandled user defined type." );
2346             }
2347         }
2348     }
2349     return _type;
2350 }
2351 
getElementTypeDesc(const TYPEDESC * desc)2352 VARTYPE IUnknownWrapper::getElementTypeDesc(const TYPEDESC *desc)
2353 {
2354     VARTYPE _type( VT_NULL );
2355 
2356     if (desc->vt == VT_PTR)
2357     {
2358         _type = getElementTypeDesc(desc->lptdesc);
2359         _type |= VT_BYREF;
2360     }
2361     else if (desc->vt == VT_SAFEARRAY)
2362     {
2363         _type = getElementTypeDesc(desc->lptdesc);
2364         _type |= VT_ARRAY;
2365     }
2366     else if (desc->vt == VT_USERDEFINED)
2367     {
2368         ITypeInfo* thisInfo = getTypeInfo(); //kept by this instance
2369         _type = getUserDefinedElementType( thisInfo, desc->hreftype );
2370     }
2371     else
2372     {
2373         _type = desc->vt;
2374     }
2375     return _type;
2376 }
2377 
buildComTlbIndex()2378 void IUnknownWrapper::buildComTlbIndex()
2379 {
2380     if ( ! m_bComTlbIndexInit)
2381     {
2382         MutexGuard guard(getBridgeMutex());
2383         {
2384             if ( ! m_bComTlbIndexInit)
2385             {
2386                 OUString sError;
2387                 ITypeInfo* pType= getTypeInfo();
2388                 TypeAttr typeAttr(pType);
2389                 if( SUCCEEDED( pType->GetTypeAttr( &typeAttr)))
2390                 {
2391                     for( WORD i= 0; i < typeAttr->cFuncs; i++)
2392                     {
2393                         FuncDesc funcDesc(pType);
2394                         if( SUCCEEDED( pType->GetFuncDesc( i, &funcDesc)))
2395                         {
2396                             CComBSTR memberName;
2397                             unsigned int pcNames=0;
2398                             if( SUCCEEDED(pType->GetNames( funcDesc->memid, & memberName, 1, &pcNames)))
2399                             {
2400                                 OUString usName(o3tl::toU(LPCOLESTR(memberName)));
2401                                 m_mapComFunc.emplace(usName, i);
2402                             }
2403                             else
2404                             {
2405                                 sError = "[automation bridge] IUnknownWrapper::buildComTlbIndex, "
2406                                          "ITypeInfo::GetNames failed.";
2407                             }
2408                         }
2409                         else
2410                             sError = "[automation bridge] IUnknownWrapper::buildComTlbIndex, "
2411                                      "ITypeInfo::GetFuncDesc failed.";
2412                     }
2413 
2414                     //If we create an Object in JScript and a property then it
2415                     //has VARDESC instead of FUNCDESC
2416                     for (WORD i = 0; i < typeAttr->cVars; i++)
2417                     {
2418                         VarDesc varDesc(pType);
2419                         if (SUCCEEDED(pType->GetVarDesc(i, & varDesc)))
2420                         {
2421                             CComBSTR memberName;
2422                             unsigned int pcNames = 0;
2423                             if (SUCCEEDED(pType->GetNames(varDesc->memid, & memberName, 1, &pcNames)))
2424                             {
2425                                 if (varDesc->varkind == VAR_DISPATCH)
2426                                 {
2427                                     OUString usName(o3tl::toU(LPCOLESTR(memberName)));
2428                                     m_mapComFunc.emplace(usName, i);
2429                                 }
2430                             }
2431                             else
2432                             {
2433                                 sError = "[automation bridge] IUnknownWrapper::buildComTlbIndex, "
2434                                          "ITypeInfo::GetNames failed.";
2435                             }
2436                         }
2437                         else
2438                             sError = "[automation bridge] IUnknownWrapper::buildComTlbIndex, "
2439                                      "ITypeInfo::GetVarDesc failed.";
2440 
2441                     }
2442                 }
2443                 else
2444                     sError = "[automation bridge] IUnknownWrapper::buildComTlbIndex, "
2445                              "ITypeInfo::GetTypeAttr failed.";
2446 
2447                 if (sError.getLength())
2448                 {
2449                     throw BridgeRuntimeError(sError);
2450                 }
2451 
2452                 m_bComTlbIndexInit = true;
2453             }
2454         }
2455     }
2456 }
2457 
getTypeInfo()2458 ITypeInfo* IUnknownWrapper::getTypeInfo()
2459 {
2460     if( !m_spDispatch)
2461     {
2462         throw BridgeRuntimeError("The object has no IDispatch interface!");
2463     }
2464 
2465     if( !m_spTypeInfo )
2466     {
2467         MutexGuard guard(getBridgeMutex());
2468         if( ! m_spTypeInfo)
2469         {
2470             CComPtr< ITypeInfo > spType;
2471             if( !SUCCEEDED( m_spDispatch->GetTypeInfo( 0, LOCALE_USER_DEFAULT, &spType.p)))
2472             {
2473                 throw BridgeRuntimeError("[automation bridge]The dispatch object does not "
2474                                          "support ITypeInfo!");
2475             }
2476 
2477             OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
2478 
2479             //If this is a dual interface then TYPEATTR::typekind is usually TKIND_INTERFACE
2480             //We need to get the type description for TKIND_DISPATCH
2481             TypeAttr typeAttr(spType.p);
2482             if( SUCCEEDED(spType->GetTypeAttr( &typeAttr)))
2483             {
2484                 if (typeAttr->typekind == TKIND_INTERFACE &&
2485                     typeAttr->wTypeFlags & TYPEFLAG_FDUAL)
2486                 {
2487                     HREFTYPE refDispatch;
2488                     if (!SUCCEEDED(spType->GetRefTypeOfImplType(::sal::static_int_cast< UINT, int >( -1 ), &refDispatch)))
2489                     {
2490                         throw BridgeRuntimeError(
2491                             "[automation bridge] Could not obtain type information "
2492                             "for dispatch interface." );
2493                     }
2494                     CComPtr<ITypeInfo> spTypeDisp;
2495                     if (SUCCEEDED(spType->GetRefTypeInfo(refDispatch, & spTypeDisp)))
2496                         m_spTypeInfo= spTypeDisp;
2497                 }
2498                 else if (typeAttr->typekind == TKIND_DISPATCH)
2499                 {
2500                     m_spTypeInfo= spType;
2501                 }
2502                 else
2503                 {
2504                     throw BridgeRuntimeError(
2505                         "[automation bridge] Automation object does not "
2506                         "provide type information.");
2507                 }
2508             }
2509         }
2510     }
2511     return m_spTypeInfo;
2512 }
2513 
2514 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
2515