1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include "ole2uno.hxx"
21 #include <sal/log.hxx>
22 #include <o3tl/char16_t2wchar_t.hxx>
24 #include <osl/diagnose.h>
25 #include <osl/doublecheckedlocking.h>
26 #include <osl/thread.h>
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>
37 #include <com/sun/star/bridge/oleautomation/NamedArgument.hpp>
38 #include <com/sun/star/bridge/oleautomation/PropertyPutArgument.hpp>
39 #include <cppuhelper/exc_hlp.hxx>
41 #include <typelib/typedescription.hxx>
43 #include <rtl/ustring.hxx>
45 #include "jscriptclasses.hxx"
47 #include "oleobjw.hxx"
48 #include "unoobjw.hxx"
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
;
60 #define JSCRIPT_ID_PROPERTY L"_environment"
61 #define JSCRIPT_ID L"jscript"
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
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
;
80 std::unordered_map
<sal_uIntPtr
, WeakReference
<XInterface
> > ComPtrToWrapperMap
;
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)
91 IUnknownWrapper::~IUnknownWrapper()
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
);
101 // remove entries in global maps
102 auto it
= WrapperToAdapterMap
.find( reinterpret_cast<sal_uIntPtr
>(xIntRoot
));
103 if( it
!= WrapperToAdapterMap
.end())
105 sal_uIntPtr adapter
= it
->second
;
107 AdapterToWrapperMap
.erase( adapter
);
108 WrapperToAdapterMap
.erase( it
);
111 auto it_c
= ComPtrToWrapperMap
.find( reinterpret_cast<sal_uIntPtr
>(m_spUnknown
.p
));
112 if(it_c
!= ComPtrToWrapperMap
.end())
113 ComPtrToWrapperMap
.erase(it_c
);
116 Any
IUnknownWrapper::queryInterface(const Type
& t
)
118 if (t
== cppu::UnoType
<XDefaultMethod
>::get() && !m_bHasDfltMethod
)
120 if (t
== cppu::UnoType
<XDefaultProperty
>::get() && !m_bHasDfltProperty
)
122 if ( ( t
== cppu::UnoType
<XInvocation
>::get() || t
== cppu::UnoType
<XAutomationInvocation
>::get() ) && !m_spDispatch
)
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
);
134 Reference
<XIntrospectionAccess
> SAL_CALL
IUnknownWrapper::getIntrospection()
136 Reference
<XIntrospectionAccess
> ret
;
141 Any SAL_CALL
IUnknownWrapper::invokeGetProperty( const OUString
& aPropertyName
, const Sequence
< Any
>& aParams
, Sequence
< sal_Int16
>& aOutParamIndex
, Sequence
< Any
>& aOutParam
)
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
);
154 OUString
msg("[automation bridge]Property \"" + aPropertyName
+
155 "\" is not supported");
156 throw UnknownPropertyException(msg
);
158 aResult
= invokeWithDispIdComTlb( aDescGet
, aPropertyName
, aParams
, aOutParamIndex
, aOutParam
);
160 catch ( const Exception
& e
)
162 css::uno::Any anyEx
= cppu::getCaughtException();
163 throw css::lang::WrappedTargetRuntimeException("[automation bridge] unexpected exception in "
164 "IUnknownWrapper::invokeGetProperty ! Message : \n " +
171 Any SAL_CALL
IUnknownWrapper::invokePutProperty( const OUString
& aPropertyName
, const Sequence
< Any
>& aParams
, Sequence
< sal_Int16
>& aOutParamIndex
, Sequence
< Any
>& aOutParam
)
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
);
184 OUString
msg("[automation bridge]Property \"" + aPropertyName
+
185 "\" is not supported");
186 throw UnknownPropertyException(msg
);
188 aResult
= invokeWithDispIdComTlb( aDescPut
, aPropertyName
, aParams
, aOutParamIndex
, aOutParam
);
190 catch ( const Exception
& e
)
192 css::uno::Any anyEx
= cppu::getCaughtException();
193 throw css::lang::WrappedTargetRuntimeException("[automation bridge] unexpected exception in "
194 "IUnknownWrapper::invokePutProperty ! Message : \n" +
202 Any SAL_CALL
IUnknownWrapper::invoke( const OUString
& aFunctionName
,
203 const Sequence
< Any
>& aParams
, Sequence
< sal_Int16
>& aOutParamIndex
,
204 Sequence
< Any
>& aOutParam
)
206 if ( ! m_spDispatch
)
208 throw RuntimeException(
209 "[automation bridge] The object does not have an IDispatch interface");
216 o2u_attachCurrentThread();
218 TypeDescription methodDesc
;
219 getMethodInfo(aFunctionName
, methodDesc
);
222 ret
= invokeWithDispIdUnoTlb(aFunctionName
,
229 ret
= invokeWithDispIdComTlb( aFunctionName
,
235 catch (const IllegalArgumentException
&)
239 catch (const CannotConvertException
&)
243 catch (const BridgeRuntimeError
& e
)
245 throw RuntimeException(e
.message
);
247 catch (const Exception
& e
)
249 css::uno::Any anyEx
= cppu::getCaughtException();
250 throw css::lang::WrappedTargetRuntimeException("[automation bridge] unexpected exception in "
251 "IUnknownWrapper::invoke ! Message : \n" +
258 throw RuntimeException("[automation bridge] unexpected exception in "
259 "IUnknownWrapper::Invoke !");
264 void SAL_CALL
IUnknownWrapper::setValue( const OUString
& aPropertyName
,
267 if ( ! m_spDispatch
)
269 throw RuntimeException(
270 "[automation bridge] The object does not have an IDispatch interface");
274 o2u_attachCurrentThread();
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
)
284 OUString
msg("[automation bridge]Property \"" + aPropertyName
+
285 "\" is not supported");
286 throw UnknownPropertyException(msg
);
289 if ( (! aDescPut
&& aDescGet
)
290 || (aVarDesc
&& aVarDesc
->wVarFlags
== VARFLAG_FREADONLY
) )
293 SAL_WARN( "extensions.olebridge", "[automation bridge] Property " << aPropertyName
<< " is read-only");
299 DISPPARAMS dispparams
;
301 CComVariant varRefArg
;
302 CComVariant varResult
;
304 unsigned int uArgErr
;
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
;
313 OSL_ASSERT(aDescPut
|| aVarDesc
);
317 INVOKEKIND invkind
= INVOKE_PROPERTYPUT
;
318 //determine the expected type, dispid, invoke kind (DISPATCH_PROPERTYPUT,
319 //DISPATCH_PROPERTYPUTREF)
322 vt
= getElementTypeDesc(& aDescPut
->lprgelemdescParam
[0].tdesc
);
323 dispid
= aDescPut
->memid
;
324 invkind
= aDescPut
->invkind
;
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
))
333 invkind
= INVOKE_PROPERTYPUTREF
;
337 // convert the uno argument
340 anyToVariant( & varRefArg
, aValue
, ::sal::static_int_cast
< VARTYPE
, int >( vt
^ VT_BYREF
) );
342 if( (vt
& VT_TYPEMASK
) == VT_VARIANT
)
343 varArg
.byref
= & varRefArg
;
344 else if ((vt
& VT_TYPEMASK
) == VT_DECIMAL
)
345 varArg
.byref
= & varRefArg
.decVal
;
347 varArg
.byref
= & varRefArg
.byref
;
351 anyToVariant(& varArg
, aValue
, vt
);
354 hr
= m_spDispatch
->Invoke(dispid
, IID_NULL
, LOCALE_USER_DEFAULT
, ::sal::static_int_cast
< WORD
, INVOKEKIND
>( invkind
),
355 &dispparams
, & varResult
, & excepinfo
, &uArgErr
);
362 case DISP_E_BADPARAMCOUNT
:
363 throw RuntimeException();
365 case DISP_E_BADVARTYPE
:
366 throw RuntimeException();
368 case DISP_E_EXCEPTION
:
369 throw InvocationTargetException();
371 case DISP_E_MEMBERNOTFOUND
:
372 throw UnknownPropertyException();
374 case DISP_E_NONAMEDARGS
:
375 throw RuntimeException();
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
);
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
)) ;
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
));
389 case DISP_E_UNKNOWNINTERFACE
:
390 throw RuntimeException();
392 case DISP_E_UNKNOWNLCID
:
393 throw RuntimeException();
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
);
400 throw RuntimeException();
404 catch (const CannotConvertException
&)
408 catch (const UnknownPropertyException
&)
412 catch (const BridgeRuntimeError
& e
)
414 throw RuntimeException(e
.message
);
416 catch (const Exception
& e
)
418 css::uno::Any anyEx
= cppu::getCaughtException();
419 throw css::lang::WrappedTargetRuntimeException("[automation bridge] unexpected exception in "
420 "IUnknownWrapper::setValue ! Message : \n" +
427 throw RuntimeException(
428 "[automation bridge] unexpected exception in "
429 "IUnknownWrapper::setValue !");
433 Any SAL_CALL
IUnknownWrapper::getValue( const OUString
& aPropertyName
)
435 if ( ! m_spDispatch
)
437 throw RuntimeException(
438 "[automation bridge] The object does not have an IDispatch interface");
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
454 if ( aPropertyName
== "$GetTypeName" )
456 if ( pInfo
&& m_sTypeName
.getLength() == 0 )
458 m_sTypeName
= "IDispatch";
461 if ( SUCCEEDED( pInfo
->GetDocumentation( -1, &sName
, nullptr, nullptr, nullptr ) ) )
463 OUString
sTmp( o3tl::toU(LPCOLESTR(sName
)));
464 if ( sTmp
.startsWith("_") )
466 // do we own the memory for pTypeLib, msdn doc is vague
468 CComPtr
< ITypeLib
> pTypeLib
;
470 if ( SUCCEEDED( pInfo
->GetContainingTypeLib( &pTypeLib
.p
, &index
)) )
472 if ( SUCCEEDED( pTypeLib
->GetDocumentation( -1, &sName
, nullptr, nullptr, nullptr ) ) )
474 OUString
sLibName( o3tl::toU(LPCOLESTR(sName
)));
475 m_sTypeName
= sLibName
+ "." + sTmp
;
485 FuncDesc
aDescGet(pInfo
);
486 FuncDesc
aDescPut(pInfo
);
487 VarDesc
aVarDesc(pInfo
);
488 getPropDesc(aPropertyName
, & aDescGet
, & aDescPut
, & aVarDesc
);
489 if ( ! aDescGet
&& ! aDescPut
&& ! aVarDesc
)
492 OUString
msg("[automation bridge]Property \"" + aPropertyName
+
493 "\" is not supported");
494 throw UnknownPropertyException(msg
);
496 // write-only should not be possible
497 OSL_ASSERT( aDescGet
|| ! aDescPut
);
500 DISPPARAMS dispparams
= {nullptr, nullptr, 0, 0};
501 CComVariant varResult
;
503 unsigned int uArgErr
;
506 dispid
= aDescGet
->memid
;
508 dispid
= aVarDesc
->memid
;
510 dispid
= aDescPut
->memid
;
512 hr
= m_spDispatch
->Invoke(dispid
,
515 DISPATCH_PROPERTYGET
,
521 // converting return value and out parameter back to UNO
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
);
529 variantToAny( &varResult
, ret
, Type( attrInfo
.get()->pWeakRef
));
531 variantToAny(&varResult
, ret
);
539 case DISP_E_BADPARAMCOUNT
:
540 case DISP_E_BADVARTYPE
:
541 case DISP_E_EXCEPTION
:
542 throw RuntimeException(OUString(o3tl::toU(excepinfo
.bstrDescription
)));
544 case DISP_E_MEMBERNOTFOUND
:
545 throw UnknownPropertyException(OUString(o3tl::toU(excepinfo
.bstrDescription
)));
548 throw RuntimeException(OUString(o3tl::toU(excepinfo
.bstrDescription
)));
552 catch ( const UnknownPropertyException
& )
556 catch (const BridgeRuntimeError
& e
)
558 throw RuntimeException(e
.message
);
560 catch (const Exception
& e
)
562 css::uno::Any anyEx
= cppu::getCaughtException();
563 throw css::lang::WrappedTargetRuntimeException("[automation bridge] unexpected exception in "
564 "IUnknownWrapper::getValue ! Message : \n" +
570 throw RuntimeException(
571 "[automation bridge] unexpected exception in "
572 "IUnknownWrapper::getValue !");
577 sal_Bool SAL_CALL
IUnknownWrapper::hasMethod( const OUString
& aName
)
579 if ( ! m_spDispatch
)
581 throw RuntimeException(
582 "[automation bridge] The object does not have an IDispatch interface");
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.
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))
607 catch (const BridgeRuntimeError
& e
)
609 throw RuntimeException(e
.message
);
611 catch (const Exception
& e
)
613 css::uno::Any anyEx
= cppu::getCaughtException();
614 throw css::lang::WrappedTargetRuntimeException("[automation bridge] unexpected exception in "
615 "IUnknownWrapper::hasMethod ! Message : \n" +
621 throw RuntimeException("[automation bridge] unexpected exception in "
622 "IUnknownWrapper::hasMethod !");
627 sal_Bool SAL_CALL
IUnknownWrapper::hasProperty( const OUString
& aName
)
629 if ( ! m_spDispatch
)
631 throw RuntimeException("[automation bridge] The object does not have an "
632 "IDispatch interface");
637 o2u_attachCurrentThread();
639 ITypeInfo
* pInfo
= getTypeInfo();
640 FuncDesc
aDescGet(pInfo
);
641 FuncDesc
aDescPut(pInfo
);
642 VarDesc
aVarDesc(pInfo
);
643 getPropDesc(aName
, & aDescGet
, & aDescPut
, & aVarDesc
);
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
658 catch (const BridgeRuntimeError
& e
)
660 throw RuntimeException(e
.message
);
662 catch (const Exception
& e
)
664 css::uno::Any anyEx
= cppu::getCaughtException();
665 throw css::lang::WrappedTargetRuntimeException("[automation bridge] unexpected exception in "
666 "IUnknownWrapper::hasProperty ! Message : \n" +
673 throw RuntimeException("[automation bridge] unexpected exception in "
674 "IUnknownWrapper::hasProperty !");
679 Any SAL_CALL
IUnknownWrapper::createBridge( const Any
& modelDepObject
,
680 const Sequence
< sal_Int8
>& /*aProcessId*/, sal_Int16 sourceModelType
,
681 sal_Int16 destModelType
)
684 o2u_attachCurrentThread();
687 (sourceModelType
== UNO
) &&
688 (destModelType
== OLE
) &&
689 (modelDepObject
.getValueTypeClass() == TypeClass_INTERFACE
)
692 Reference
<XInterface
> xInt( *static_cast<XInterface
* const *>(modelDepObject
.getValue()));
693 Reference
<XInterface
> xSelf( static_cast<OWeakObject
*>(this));
697 VARIANT
* pVariant
= static_cast<VARIANT
*>(CoTaskMemAlloc(sizeof(VARIANT
)));
698 assert(pVariant
&& "Don't handle OOM conditions");
700 VariantInit(pVariant
);
701 if (m_bOriginalDispatch
)
703 pVariant
->vt
= VT_DISPATCH
;
704 pVariant
->pdispVal
= m_spDispatch
;
705 pVariant
->pdispVal
->AddRef();
709 pVariant
->vt
= VT_UNKNOWN
;
710 pVariant
->punkVal
= m_spUnknown
;
711 pVariant
->punkVal
->AddRef();
714 ret
.setValue(static_cast<void*>(&pVariant
), cppu::UnoType
<sal_uIntPtr
>::get());
721 @exception IllegalArgumentException
722 @exception CannotConvertException
723 @exception InvocationTargetException
726 Any
IUnknownWrapper::invokeWithDispIdUnoTlb(const OUString
& sFunctionName
,
727 const Sequence
< Any
>& Params
,
728 Sequence
< sal_Int16
>& OutParamIndex
,
729 Sequence
< Any
>& OutParam
)
734 sal_Int32 parameterCount
= Params
.getLength();
735 sal_Int32 outParameterCount
= 0;
736 typelib_InterfaceMethodTypeDescription
* pMethod
= nullptr;
737 TypeDescription methodDesc
;
738 getMethodInfo(sFunctionName
, methodDesc
);
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;
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)
758 sarParams
.reset(new CComVariant
[ parameterCount
]);
759 pVarParams
= sarParams
.get();
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
++)
767 if( pMethod
->pParams
[i
].bOut
)
773 sarParamsRef
.reset(new CComVariant
[outParameterCount
]);
774 pVarParamsRef
= sarParamsRef
.get();
775 // build up the parameters for IDispatch::Invoke
776 sal_Int32 outParamIndex
=0;
780 for( i
= 0; i
< parameterCount
; i
++)
783 if( pMethod
->pParams
[i
].bIn
&& ! pMethod
->pParams
[i
].bOut
)
785 anyToVariant( &pVarParams
[parameterCount
- i
-1], Params
.getConstArray()[i
]);
787 // Out parameter + in/out parameter
788 else if( pMethod
->pParams
[i
].bOut
)
791 if(pMethod
->pParams
[i
].bIn
)
793 anyToVariant( & var
,Params
[i
]);
794 pVarParamsRef
[outParamIndex
] = var
;
797 switch( pMethod
->pParams
[i
].pTypeRef
->eTypeClass
)
799 case typelib_TypeClass_INTERFACE
:
800 case typelib_TypeClass_STRUCT
:
801 if( ! pMethod
->pParams
[i
].bIn
)
803 pVarParamsRef
[ outParamIndex
].vt
= VT_DISPATCH
;
804 pVarParamsRef
[ outParamIndex
].pdispVal
= nullptr;
806 pVarParams
[parameterCount
- i
-1].vt
= VT_DISPATCH
| VT_BYREF
;
807 pVarParams
[parameterCount
- i
-1].ppdispVal
= &pVarParamsRef
[outParamIndex
].pdispVal
;
809 case typelib_TypeClass_ENUM
:
810 case typelib_TypeClass_LONG
:
811 case typelib_TypeClass_UNSIGNED_LONG
:
812 if( ! pMethod
->pParams
[i
].bIn
)
814 pVarParamsRef
[ outParamIndex
].vt
= VT_I4
;
815 pVarParamsRef
[ outParamIndex
].lVal
= 0;
817 pVarParams
[parameterCount
- i
-1].vt
= VT_I4
| VT_BYREF
;
818 pVarParams
[parameterCount
- i
-1].plVal
= &pVarParamsRef
[outParamIndex
].lVal
;
820 case typelib_TypeClass_SEQUENCE
:
821 if( ! pMethod
->pParams
[i
].bIn
)
823 pVarParamsRef
[ outParamIndex
].vt
= VT_ARRAY
| VT_VARIANT
;
824 pVarParamsRef
[ outParamIndex
].parray
= nullptr;
826 pVarParams
[parameterCount
- i
-1].vt
= VT_ARRAY
| VT_BYREF
| VT_VARIANT
;
827 pVarParams
[parameterCount
- i
-1].pparray
= &pVarParamsRef
[outParamIndex
].parray
;
829 case typelib_TypeClass_ANY
:
830 if( ! pMethod
->pParams
[i
].bIn
)
832 pVarParamsRef
[ outParamIndex
].vt
= VT_EMPTY
;
833 pVarParamsRef
[ outParamIndex
].lVal
= 0;
835 pVarParams
[parameterCount
- i
-1].vt
= VT_VARIANT
| VT_BYREF
;
836 pVarParams
[parameterCount
- i
-1].pvarVal
= &pVarParamsRef
[outParamIndex
];
838 case typelib_TypeClass_BOOLEAN
:
839 if( ! pMethod
->pParams
[i
].bIn
)
841 pVarParamsRef
[ outParamIndex
].vt
= VT_BOOL
;
842 pVarParamsRef
[ outParamIndex
].boolVal
= 0;
844 pVarParams
[parameterCount
- i
-1].vt
= VT_BOOL
| VT_BYREF
;
845 pVarParams
[parameterCount
- i
-1].pboolVal
=
846 & pVarParamsRef
[outParamIndex
].boolVal
;
849 case typelib_TypeClass_STRING
:
850 if( ! pMethod
->pParams
[i
].bIn
)
852 pVarParamsRef
[ outParamIndex
].vt
= VT_BSTR
;
853 pVarParamsRef
[ outParamIndex
].bstrVal
= nullptr;
855 pVarParams
[parameterCount
- i
-1].vt
= VT_BSTR
| VT_BYREF
;
856 pVarParams
[parameterCount
- i
-1].pbstrVal
=
857 & pVarParamsRef
[outParamIndex
].bstrVal
;
860 case typelib_TypeClass_FLOAT
:
861 if( ! pMethod
->pParams
[i
].bIn
)
863 pVarParamsRef
[ outParamIndex
].vt
= VT_R4
;
864 pVarParamsRef
[ outParamIndex
].fltVal
= 0;
866 pVarParams
[parameterCount
- i
-1].vt
= VT_R4
| VT_BYREF
;
867 pVarParams
[parameterCount
- i
-1].pfltVal
=
868 & pVarParamsRef
[outParamIndex
].fltVal
;
870 case typelib_TypeClass_DOUBLE
:
871 if( ! pMethod
->pParams
[i
].bIn
)
873 pVarParamsRef
[ outParamIndex
].vt
= VT_R8
;
874 pVarParamsRef
[ outParamIndex
].dblVal
= 0;
876 pVarParams
[parameterCount
- i
-1].vt
= VT_R8
| VT_BYREF
;
877 pVarParams
[parameterCount
- i
-1].pdblVal
=
878 & pVarParamsRef
[outParamIndex
].dblVal
;
880 case typelib_TypeClass_BYTE
:
881 if( ! pMethod
->pParams
[i
].bIn
)
883 pVarParamsRef
[ outParamIndex
].vt
= VT_UI1
;
884 pVarParamsRef
[ outParamIndex
].bVal
= 0;
886 pVarParams
[parameterCount
- i
-1].vt
= VT_UI1
| VT_BYREF
;
887 pVarParams
[parameterCount
- i
-1].pbVal
=
888 & pVarParamsRef
[outParamIndex
].bVal
;
890 case typelib_TypeClass_CHAR
:
891 case typelib_TypeClass_SHORT
:
892 case typelib_TypeClass_UNSIGNED_SHORT
:
893 if( ! pMethod
->pParams
[i
].bIn
)
895 pVarParamsRef
[ outParamIndex
].vt
= VT_I2
;
896 pVarParamsRef
[ outParamIndex
].iVal
= 0;
898 pVarParams
[parameterCount
- i
-1].vt
= VT_I2
| VT_BYREF
;
899 pVarParams
[parameterCount
- i
-1].piVal
=
900 & pVarParamsRef
[outParamIndex
].iVal
;
904 if( ! pMethod
->pParams
[i
].bIn
)
906 pVarParamsRef
[ outParamIndex
].vt
= VT_EMPTY
;
907 pVarParamsRef
[ outParamIndex
].lVal
= 0;
909 pVarParams
[parameterCount
- i
-1].vt
= VT_VARIANT
| VT_BYREF
;
910 pVarParams
[parameterCount
- i
-1].pvarVal
=
911 & pVarParamsRef
[outParamIndex
];
917 catch (IllegalArgumentException
& e
)
919 e
.ArgumentPosition
= ::sal::static_int_cast
< sal_Int16
, int >( i
);
922 catch (CannotConvertException
& e
)
928 else // it is a JScriptObject
933 for( ; i
< parameterCount
; i
++)
936 if( pMethod
->pParams
[i
].bIn
&& ! pMethod
->pParams
[i
].bOut
)
938 anyToVariant( &pVarParams
[parameterCount
- i
-1], Params
.getConstArray()[i
]);
940 // Out parameter + in/out parameter
941 else if( pMethod
->pParams
[i
].bOut
)
943 CComObject
<JScriptOutParam
>* pParamObject
;
944 if( !SUCCEEDED( CComObject
<JScriptOutParam
>::CreateInstance( &pParamObject
)))
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
)));
953 CComPtr
<IUnknown
> pUnk(pParamObject
->GetUnknown());
954 CComQIPtr
<IDispatch
> pDisp( pUnk
);
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
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 "
976 catch (IllegalArgumentException
& e
)
978 e
.ArgumentPosition
= ::sal::static_int_cast
< sal_Int16
, int >( i
);
981 catch (CannotConvertException
& e
)
988 // No type description Available, that is we have to deal with a COM component,
989 // that does not implements UNO interfaces ( IDispatch based)
992 //We should not run into this block, because invokeWithDispIdComTlb should
993 //have been called instead.
998 CComVariant varResult
;
1000 unsigned int uArgErr
;
1001 DISPPARAMS dispparams
= { pVarParams
, nullptr, static_cast<UINT
>(parameterCount
), 0};
1004 FuncDesc
aDesc(getTypeInfo());
1005 getFuncDesc(sFunctionName
, & aDesc
);
1006 // invoking OLE method
1007 hr
= m_spDispatch
->Invoke(aDesc
->memid
,
1009 LOCALE_USER_DEFAULT
,
1016 // converting return value and out parameter back to UNO
1019 if( outParameterCount
&& pMethod
)
1021 OutParamIndex
.realloc( outParameterCount
);
1022 auto pOutParamIndex
= OutParamIndex
.getArray();
1023 OutParam
.realloc( outParameterCount
);
1024 auto pOutParam
= OutParam
.getArray();
1025 sal_Int32 outIndex
=0;
1029 for( ; i
< parameterCount
; i
++)
1031 if( pMethod
->pParams
[i
].bOut
)
1033 pOutParamIndex
[outIndex
]= static_cast<sal_Int16
>(i
);
1035 if( !bJScriptObject
)
1037 variantToAny( &pVarParamsRef
[outIndex
], outAny
,
1038 Type(pMethod
->pParams
[i
].pTypeRef
), false);
1039 pOutParam
[outIndex
++]= outAny
;
1041 else //JScriptObject
1043 if( pVarParams
[i
].vt
== VT_DISPATCH
)
1045 CComDispatchDriver
pDisp( pVarParams
[i
].pdispVal
);
1049 if( SUCCEEDED( pDisp
.GetPropertyByName( L
"0", &varOut
)))
1051 variantToAny( &varOut
, outAny
,
1052 Type(pMethod
->pParams
[parameterCount
- 1 - i
].pTypeRef
), false);
1053 pOutParam
[outParameterCount
- 1 - outIndex
++]= outAny
;
1065 if( !bConvRet
) break;
1068 catch(IllegalArgumentException
& e
)
1070 e
.ArgumentPosition
= ::sal::static_int_cast
< sal_Int16
, int >( i
);
1073 catch(CannotConvertException
& e
)
1075 e
.ArgumentIndex
= i
;
1079 // return value, no type information available
1085 variantToAny(&varResult
, ret
, Type( pMethod
->pReturnTypeRef
), false);
1087 variantToAny(&varResult
, ret
, false);
1089 catch (IllegalArgumentException
& e
)
1092 "[automation bridge]IUnknownWrapper::invokeWithDispIdUnoTlb\n"
1093 "Could not convert return value! \n Message: \n" + e
.Message
;
1096 catch (CannotConvertException
& e
)
1099 "[automation bridge]IUnknownWrapper::invokeWithDispIdUnoTlb\n"
1100 "Could not convert return value! \n Message: \n" + e
.Message
;
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
1115 case DISP_E_BADPARAMCOUNT
:
1116 throw IllegalArgumentException();
1118 case DISP_E_BADVARTYPE
:
1119 throw RuntimeException();
1121 case DISP_E_EXCEPTION
:
1122 throw InvocationTargetException();
1124 case DISP_E_MEMBERNOTFOUND
:
1125 throw IllegalArgumentException();
1127 case DISP_E_NONAMEDARGS
:
1128 throw IllegalArgumentException();
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
);
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
));
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
);
1142 case DISP_E_UNKNOWNINTERFACE
:
1143 throw RuntimeException() ;
1145 case DISP_E_UNKNOWNLCID
:
1146 throw RuntimeException() ;
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
);
1153 throw RuntimeException();
1162 void SAL_CALL
IUnknownWrapper::initialize( const Sequence
< Any
>& aArguments
)
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);
1170 m_spUnknown
= *static_cast<IUnknown
* const *>(aArguments
[0].getValue());
1171 m_spUnknown
.QueryInterface( & m_spDispatch
.p
);
1173 aArguments
[1] >>= m_bOriginalDispatch
;
1174 aArguments
[2] >>= m_seqTypes
;
1176 ITypeInfo
* pType
= nullptr;
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();
1184 catch( const BridgeRuntimeError
& )
1186 catch( const Exception
& )
1193 // Get Default member
1194 CComBSTR defaultMemberName
;
1195 if ( SUCCEEDED( pType
->GetDocumentation(0, &defaultMemberName
, nullptr, nullptr, nullptr ) ) )
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
);
1204 if ( !aDescGet
&& !aDescPut
)
1206 getFuncDesc( usName
, &aDescGet
);
1208 throw BridgeRuntimeError( "[automation bridge]IUnknownWrapper::initialize() Failed to get Function or Property desc. for " + usName
);
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
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
;
1226 catch ( const BridgeRuntimeError
& e
)
1228 throw RuntimeException( e
.message
);
1230 catch( const Exception
& e
)
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
,
1241 // XDirectInvocation
1242 uno::Any SAL_CALL
IUnknownWrapper::directInvoke( const OUString
& aName
, const uno::Sequence
< uno::Any
>& aParams
)
1246 if ( !m_spDispatch
)
1248 throw RuntimeException(
1249 "[automation bridge] The object does not have an IDispatch interface");
1252 o2u_attachCurrentThread();
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);
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
;
1267 // try Invoke first, if it does not work, try put/get property
1268 for ( sal_Int32 nStep
= 0; FAILED( hInvRes
) && nStep
< 2; nStep
++ )
1270 DISPPARAMS dispparams
= {nullptr, nullptr, 0, 0};
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;
1278 dispparams
.cArgs
= aParams
.getLength();
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
++;
1285 // fill the named arguments
1286 if ( dispparams
.cNamedArgs
> 0
1287 && ( dispparams
.cNamedArgs
!= 1 || pInvkinds
[nStep
] != INVOKE_PROPERTYPUT
) )
1289 int nSizeAr
= dispparams
.cNamedArgs
+ 1;
1290 if ( pInvkinds
[nStep
] == INVOKE_PROPERTYPUT
)
1291 nSizeAr
= dispparams
.cNamedArgs
;
1293 std::unique_ptr
<OLECHAR
*[]> saNames(new OLECHAR
*[nSizeAr
]);
1294 OLECHAR
** pNames
= saNames
.get();
1295 pNames
[0] = const_cast<OLECHAR
*>(o3tl::toW(aName
.getStr()));
1298 for ( size_t nInd
= 0; nInd
< dispparams
.cArgs
; nInd
++ )
1300 if (auto v
= o3tl::tryAccess
<NamedArgument
>(aParams
[nInd
]))
1302 const NamedArgument
& arg
= *v
;
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()));
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() );
1316 if ( SUCCEEDED( hr
) )
1318 if ( pInvkinds
[nStep
] == DISPATCH_PROPERTYPUT
)
1320 DISPID
* arIDs
= arDispidNamedArgs
.get();
1321 arIDs
[0] = DISPID_PROPERTYPUT
;
1322 dispparams
.rgdispidNamedArgs
= arIDs
;
1326 DISPID
* arIDs
= arDispidNamedArgs
.get();
1327 dispparams
.rgdispidNamedArgs
= & arIDs
[1];
1330 else if (hr
== DISP_E_UNKNOWNNAME
)
1332 throw IllegalArgumentException(
1333 "[automation bridge]One of the named arguments is wrong!",
1334 Reference
<XInterface
>(), 0);
1338 throw InvocationTargetException(
1339 "[automation bridge] ITypeInfo::GetIDsOfNames returned error "
1340 + OUString::number(static_cast<sal_Int32
>(hr
), 16), Reference
<XInterface
>(), Any());
1345 ptrArgs
.reset(new CComVariant
[dispparams
.cArgs
]);
1346 ptrRefArgs
.reset(new CComVariant
[dispparams
.cArgs
]);
1347 arArgs
= ptrArgs
.get();
1348 arRefArgs
= ptrRefArgs
.get();
1353 sal_Int32 revIndex
= 0;
1354 for ( nInd
= 0; nInd
< sal_Int32(dispparams
.cArgs
); nInd
++)
1356 revIndex
= dispparams
.cArgs
- nInd
- 1;
1357 arRefArgs
[revIndex
].byref
= nullptr;
1359 if ( nInd
< aParams
.getLength() )
1360 anyArg
= aParams
.getConstArray()[nInd
];
1362 // Property Put arguments
1363 if ( anyArg
.getValueType() == cppu::UnoType
<PropertyPutArgument
>::get() )
1365 PropertyPutArgument arg
;
1370 if (anyArg
.getValueType() == cppu::UnoType
<NamedArgument
>::get())
1372 NamedArgument aNamedArgument
;
1373 anyArg
>>= aNamedArgument
;
1374 anyArg
= aNamedArgument
.Value
;
1377 if ( nInd
< aParams
.getLength() && anyArg
.getValueTypeClass() != TypeClass_VOID
)
1379 anyToVariant( &arArgs
[revIndex
], anyArg
, VT_VARIANT
);
1383 arArgs
[revIndex
].vt
= VT_ERROR
;
1384 arArgs
[revIndex
].scode
= DISP_E_PARAMNOTFOUND
;
1388 catch (IllegalArgumentException
& e
)
1390 e
.ArgumentPosition
= ::sal::static_int_cast
< sal_Int16
, sal_Int32
>( nInd
);
1393 catch (CannotConvertException
& e
)
1395 e
.ArgumentIndex
= nInd
;
1399 dispparams
.rgvarg
= arArgs
;
1400 // invoking OLE method
1401 hInvRes
= m_spDispatch
->Invoke( dispid
,
1403 LOCALE_USER_DEFAULT
,
1404 ::sal::static_int_cast
< WORD
, INVOKEKIND
>( pInvkinds
[nStep
] ),
1411 // converting return value and out parameter back to UNO
1412 if ( SUCCEEDED( hInvRes
) )
1413 variantToAny( &varResult
, aResult
, false );
1416 // map error codes to exceptions
1422 case DISP_E_BADPARAMCOUNT
:
1423 throw IllegalArgumentException("[automation bridge] Wrong "
1424 "number of arguments. Object returned DISP_E_BADPARAMCOUNT.",
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);
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());
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);
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
));
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
);
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
));
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
);
1464 case DISP_E_UNKNOWNINTERFACE
:
1465 throw RuntimeException("[automation bridge] Call failed. "
1466 "Object returned DISP_E_UNKNOWNINTERFACE.",nullptr);
1468 case DISP_E_UNKNOWNLCID
:
1469 throw RuntimeException("[automation bridge] Call failed. "
1470 "Object returned DISP_E_UNKNOWNLCID.",nullptr);
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
);
1479 throw RuntimeException();
1487 sal_Bool SAL_CALL
IUnknownWrapper::hasMember( const OUString
& aName
)
1489 if ( ! m_spDispatch
)
1491 throw RuntimeException(
1492 "[automation bridge] The object does not have an IDispatch interface");
1495 o2u_attachCurrentThread();
1497 return getDispid( aName
, &dispid
);
1501 // UnoConversionUtilities --------------------------------------------------------------------------------
1502 Reference
< XInterface
> IUnknownWrapper::createUnoWrapperInstance()
1504 if( m_nUnoWrapperClass
== INTERFACE_OLE_WRAPPER_IMPL
)
1506 Reference
<XWeak
> xWeak
= static_cast<XWeak
*>( new InterfaceOleWrapper(
1507 m_smgr
, m_nUnoWrapperClass
, m_nComWrapperClass
));
1508 return Reference
<XInterface
>( xWeak
, UNO_QUERY
);
1510 else if( m_nUnoWrapperClass
== UNO_OBJECT_WRAPPER_REMOTE_OPT
)
1512 Reference
<XWeak
> xWeak
= static_cast<XWeak
*>( new UnoObjectWrapperRemoteOpt(
1513 m_smgr
, m_nUnoWrapperClass
, m_nComWrapperClass
));
1514 return Reference
<XInterface
>( xWeak
, UNO_QUERY
);
1517 return Reference
<XInterface
>();
1519 Reference
<XInterface
> IUnknownWrapper::createComWrapperInstance()
1521 Reference
<XWeak
> xWeak
= static_cast<XWeak
*>( new IUnknownWrapper(
1522 m_smgr
, m_nUnoWrapperClass
, m_nComWrapperClass
));
1523 return Reference
<XInterface
>( xWeak
, UNO_QUERY
);
1527 void IUnknownWrapper::getMethodInfo(std::u16string_view sName
, TypeDescription
& methodInfo
)
1529 TypeDescription desc
= getInterfaceMemberDescOfCurrentCall(sName
);
1532 typelib_TypeDescription
* pMember
= desc
.get();
1533 if( pMember
->eTypeClass
== typelib_TypeClass_INTERFACE_METHOD
)
1534 methodInfo
= pMember
;
1538 void IUnknownWrapper::getAttributeInfo(std::u16string_view sName
, TypeDescription
& attributeInfo
)
1540 TypeDescription desc
= getInterfaceMemberDescOfCurrentCall(sName
);
1543 typelib_TypeDescription
* pMember
= desc
.get();
1544 if( pMember
->eTypeClass
== typelib_TypeClass_INTERFACE_ATTRIBUTE
)
1546 attributeInfo
= reinterpret_cast<typelib_InterfaceAttributeTypeDescription
*>(pMember
)->pAttributeTypeRef
;
1550 TypeDescription
IUnknownWrapper::getInterfaceMemberDescOfCurrentCall(std::u16string_view sName
)
1552 TypeDescription ret
;
1554 for (auto const& rType
: m_seqTypes
)
1556 TypeDescription
_curDesc( rType
);
1557 _curDesc
.makeComplete();
1558 typelib_InterfaceTypeDescription
* pInterface
= reinterpret_cast<typelib_InterfaceTypeDescription
*>(_curDesc
.get());
1561 typelib_InterfaceMemberTypeDescription
* pMember
= nullptr;
1562 //find the member description of the current call
1563 for( int j
=0; j
< pInterface
->nAllMembers
; j
++)
1565 typelib_TypeDescriptionReference
* pTypeRefMember
= pInterface
->ppAllMembers
[j
];
1566 typelib_TypeDescription
* pDescMember
= nullptr;
1567 TYPELIB_DANGER_GET( &pDescMember
, pTypeRefMember
);
1569 typelib_InterfaceMemberTypeDescription
* pInterfaceMember
=
1570 reinterpret_cast<typelib_InterfaceMemberTypeDescription
*>(pDescMember
);
1571 if( OUString( pInterfaceMember
->pMemberName
) == sName
)
1573 pMember
= pInterfaceMember
;
1576 TYPELIB_DANGER_RELEASE( pDescMember
);
1581 ret
= &pMember
->aBase
;
1582 TYPELIB_DANGER_RELEASE( &pMember
->aBase
);
1591 bool IUnknownWrapper::isJScriptObject()
1593 if( m_eJScript
== JScriptUndefined
)
1595 CComDispatchDriver
disp( m_spDispatch
);
1599 if( SUCCEEDED( disp
.GetPropertyByName( JSCRIPT_ID_PROPERTY
, &result
)))
1601 if(result
.vt
== VT_BSTR
)
1603 CComBSTR
name( result
.bstrVal
);
1605 if( name
== CComBSTR(JSCRIPT_ID
))
1606 m_eJScript
= IsJScript
;
1610 if( m_eJScript
== JScriptUndefined
)
1611 m_eJScript
= NoJScript
;
1614 return m_eJScript
!= NoJScript
;
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
1623 @exception IllegalArgumentException
1624 @exception CannotConvertException
1625 @InvocationTargetException
1629 Any
IUnknownWrapper::invokeWithDispIdComTlb(const OUString
& sFuncName
,
1630 const Sequence
< Any
>& Params
,
1631 Sequence
< sal_Int16
>& OutParamIndex
,
1632 Sequence
< Any
>& OutParam
)
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
);
1641 Any
IUnknownWrapper::invokeWithDispIdComTlb(FuncDesc
& aFuncDesc
,
1642 const OUString
& sFuncName
,
1643 const Sequence
< Any
>& Params
,
1644 Sequence
< sal_Int16
>& OutParamIndex
,
1645 Sequence
< Any
>& OutParam
)
1650 DISPPARAMS dispparams
= {nullptr, nullptr, 0, 0};
1651 CComVariant varResult
;
1652 ExcepInfo excepinfo
;
1653 unsigned int uArgErr
;
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;
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
;
1670 //Determine the number of named arguments
1671 for (int iParam
= 0; iParam
< nUnoArgs
; iParam
++)
1673 const Any
& curArg
= Params
[iParam
];
1674 if (curArg
.getValueType() == cppu::UnoType
<NamedArgument
>::get())
1675 dispparams
.cNamedArgs
++;
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
++;
1685 //Determine the number of all arguments and named arguments
1686 if (aFuncDesc
->cParamsOpt
== -1)
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
;
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
;
1699 dispparams
.cArgs
= aFuncDesc
->cParams
;
1702 //check if there are not too many arguments supplied
1703 if (::sal::static_int_cast
< sal_uInt32
, int >( nUnoArgs
) > dispparams
.cArgs
)
1705 throw IllegalArgumentException(
1706 "[automation bridge] There are too many arguments for this method",
1707 Reference
<XInterface
>(), static_cast<sal_Int16
>(dispparams
.cArgs
));
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
)))
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
1724 int nSizeAr
= dispparams
.cNamedArgs
+ 1;
1725 if (aFuncDesc
->invkind
== INVOKE_PROPERTYPUT
1726 || aFuncDesc
->invkind
== INVOKE_PROPERTYPUTREF
)
1728 nSizeAr
= dispparams
.cNamedArgs
; //counts the DISID_PROPERTYPUT
1731 std::unique_ptr
<OLECHAR
*[]> saNames(new OLECHAR
*[nSizeAr
]);
1732 OLECHAR
** arNames
= saNames
.get();
1733 arNames
[0] = const_cast<OLECHAR
*>(o3tl::toW(sFuncName
.getStr()));
1736 for (size_t iParams
= 0; iParams
< dispparams
.cArgs
; iParams
++)
1738 const Any
& curArg
= Params
[iParams
];
1739 if (auto v
= o3tl::tryAccess
<NamedArgument
>(curArg
))
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()));
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() );
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
)
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
;
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];
1779 else if (hr
== DISP_E_UNKNOWNNAME
)
1781 throw IllegalArgumentException(
1782 "[automation bridge]One of the named arguments is wrong!",
1783 Reference
<XInterface
>(), 0);
1787 throw InvocationTargetException(
1788 "[automation bridge] ITypeInfo::GetIDsOfNames returned error "
1789 + OUString::number(static_cast<sal_Int32
>(hr
), 16), Reference
<XInterface
>(), Any());
1794 ptrArgs
.reset(new CComVariant
[dispparams
.cArgs
]);
1795 ptrRefArgs
.reset(new CComVariant
[dispparams
.cArgs
]);
1796 arArgs
= ptrArgs
.get();
1797 arRefArgs
= ptrRefArgs
.get();
1800 for (i
= 0; i
< static_cast<sal_Int32
>(dispparams
.cArgs
); i
++)
1802 revIndex
= dispparams
.cArgs
- i
-1;
1803 arRefArgs
[revIndex
].byref
=nullptr;
1806 anyArg
= Params
.getConstArray()[i
];
1808 unsigned short paramFlags
= PARAMFLAG_FOPT
| PARAMFLAG_FIN
;
1809 VARTYPE varType
= VT_VARIANT
;
1810 if (aFuncDesc
->cParamsOpt
!= -1 || aFuncDesc
->cParams
!= (i
+ 1))
1812 paramFlags
= aFuncDesc
->lprgelemdescParam
[i
].paramdesc
.wParamFlags
;
1813 varType
= getElementTypeDesc(&aFuncDesc
->lprgelemdescParam
[i
].tdesc
);
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
))
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
));
1828 // Property Put arguments
1829 if (anyArg
.getValueType() == cppu::UnoType
<PropertyPutArgument
>::get())
1831 PropertyPutArgument arg
;
1836 if (anyArg
.getValueType() == cppu::UnoType
<NamedArgument
>::get())
1838 NamedArgument aNamedArgument
;
1839 anyArg
>>= aNamedArgument
;
1840 anyArg
= aNamedArgument
.Value
;
1843 if (paramFlags
& PARAMFLAG_FOUT
&&
1844 ! (paramFlags
& PARAMFLAG_FIN
) )
1846 VARTYPE type
= ::sal::static_int_cast
< VARTYPE
, int >( varType
^ VT_BYREF
);
1849 arRefArgs
[revIndex
].vt
= type
;
1854 arRefArgs
[revIndex
].vt
= VT_ERROR
;
1855 arRefArgs
[revIndex
].scode
= DISP_E_PARAMNOTFOUND
;
1857 if( type
== VT_VARIANT
)
1859 arArgs
[revIndex
].vt
= VT_VARIANT
| VT_BYREF
;
1860 arArgs
[revIndex
].byref
= &arRefArgs
[revIndex
];
1864 arArgs
[revIndex
].vt
= varType
;
1865 if (type
== VT_DECIMAL
)
1866 arArgs
[revIndex
].byref
= & arRefArgs
[revIndex
].decVal
;
1868 arArgs
[revIndex
].byref
= & arRefArgs
[revIndex
].byref
;
1871 // in/out + in byref params
1872 else if (varType
& VT_BYREF
)
1874 VARTYPE type
= ::sal::static_int_cast
< VARTYPE
, int >( varType
^ VT_BYREF
);
1877 if (i
< nUnoArgs
&& anyArg
.getValueTypeClass() != TypeClass_VOID
)
1879 anyToVariant( & arRefArgs
[revIndex
], anyArg
, type
);
1881 else if (paramFlags
& PARAMFLAG_FHASDEFAULT
)
1883 //optional arg with default
1884 VariantCopy( & arRefArgs
[revIndex
],
1885 & aFuncDesc
->lprgelemdescParam
[i
].paramdesc
.
1886 pparamdescex
->varDefaultValue
);
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
;
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
)
1903 arArgs
[revIndex
] = arRefArgs
[revIndex
];
1905 else if (type
== VT_DECIMAL
)
1907 arArgs
[revIndex
].byref
= & arRefArgs
[revIndex
].decVal
;
1909 else if (type
== VT_VARIANT
)
1911 if ( ! (paramFlags
& PARAMFLAG_FOUT
))
1912 arArgs
[revIndex
] = arRefArgs
[revIndex
];
1914 arArgs
[revIndex
].byref
= & arRefArgs
[revIndex
];
1918 arArgs
[revIndex
].byref
= & arRefArgs
[revIndex
].byref
;
1919 arArgs
[revIndex
].vt
= ::sal::static_int_cast
< VARTYPE
, int >( arRefArgs
[revIndex
].vt
| VT_BYREF
);
1923 // in parameter no VT_BYREF except for array, interfaces
1925 { // void any stands for optional param
1926 if (i
< nUnoArgs
&& anyArg
.getValueTypeClass() != TypeClass_VOID
)
1928 anyToVariant( & arArgs
[revIndex
], anyArg
, varType
);
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
)
1934 //optional arg with default either as direct arg : VT_XXX or
1935 VariantCopy( & arArgs
[revIndex
],
1936 & aFuncDesc
->lprgelemdescParam
[i
].paramdesc
.
1937 pparamdescex
->varDefaultValue
);
1939 else if (paramFlags
& PARAMFLAG_FOPT
)
1941 arArgs
[revIndex
].vt
= VT_ERROR
;
1942 arArgs
[revIndex
].scode
= DISP_E_PARAMNOTFOUND
;
1946 arArgs
[revIndex
].vt
= VT_EMPTY
;
1947 arArgs
[revIndex
].lVal
= 0;
1952 catch (IllegalArgumentException
& e
)
1954 e
.ArgumentPosition
= ::sal::static_int_cast
< sal_Int16
, sal_Int32
>( i
);
1957 catch (CannotConvertException
& e
)
1959 e
.ArgumentIndex
= i
;
1962 dispparams
.rgvarg
= arArgs
;
1963 // invoking OLE method
1964 result
= m_spDispatch
->Invoke(aFuncDesc
->memid
,
1966 LOCALE_USER_DEFAULT
,
1967 ::sal::static_int_cast
< WORD
, INVOKEKIND
>( aFuncDesc
->invkind
),
1973 // converting return value and out parameter back to UNO
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
++)
1981 if (aFuncDesc
->lprgelemdescParam
[j
].paramdesc
.wParamFlags
&
1986 OutParamIndex
.realloc(outParamsCount
);
1987 OutParam
.realloc(outParamsCount
);
1988 // Convert out params
1991 auto pOutParamIndex
= OutParamIndex
.getArray();
1992 auto pOutParam
= OutParam
.getArray();
1993 int outParamIndex
=0;
1994 for (int paramIndex
= 0; paramIndex
< nUnoArgs
; paramIndex
++)
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())
2002 //dispparams.rgdispidNamedArgs contains the mapping from index
2003 //of named args list to index of parameter list
2004 realParamIndex
= dispparams
.rgdispidNamedArgs
[revParamIndex
];
2007 // no named arg, always come before named args
2008 if (! (aFuncDesc
->lprgelemdescParam
[realParamIndex
].paramdesc
.wParamFlags
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.
2017 variantToAny( & arRefArgs
[revParamIndex
], outAny
, false );
2019 catch (IllegalArgumentException
& e
)
2021 e
.ArgumentPosition
= static_cast<sal_Int16
>(paramIndex
);
2024 catch (CannotConvertException
& e
)
2026 e
.ArgumentIndex
= paramIndex
;
2029 pOutParam
[outParamIndex
] = outAny
;
2030 pOutParamIndex
[outParamIndex
] = ::sal::static_int_cast
< sal_Int16
, int >( paramIndex
);
2033 OutParam
.realloc(outParamIndex
);
2034 OutParamIndex
.realloc(outParamIndex
);
2037 variantToAny(&varResult
, ret
, false);
2040 // map error codes to exceptions
2046 case DISP_E_BADPARAMCOUNT
:
2047 throw IllegalArgumentException("[automation bridge] Wrong "
2048 "number of arguments. Object returned DISP_E_BADPARAMCOUNT.",
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);
2056 case DISP_E_EXCEPTION
:
2057 message
= OUString::Concat("[automation bridge]: ")
2058 + std::u16string_view(o3tl::toU(excepinfo
.bstrDescription
),
2059 ::SysStringLen(excepinfo
.bstrDescription
));
2061 throw InvocationTargetException(message
, Reference
<XInterface
>(), Any());
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);
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
));
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
);
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
));
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
);
2089 case DISP_E_UNKNOWNINTERFACE
:
2090 throw RuntimeException("[automation bridge] Call failed. "
2091 "Object returned DISP_E_UNKNOWNINTERFACE.",nullptr);
2093 case DISP_E_UNKNOWNLCID
:
2094 throw RuntimeException("[automation bridge] Call failed. "
2095 "Object returned DISP_E_UNKNOWNLCID.",nullptr);
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
);
2104 throw RuntimeException();
2111 void IUnknownWrapper::getFuncDescForInvoke(const OUString
& sFuncName
,
2112 const Sequence
<Any
> & seqArgs
,
2113 FUNCDESC
** pFuncDesc
)
2115 int nUnoArgs
= seqArgs
.getLength();
2116 const Any
* arArgs
= seqArgs
.getConstArray();
2117 ITypeInfo
* pInfo
= getTypeInfo();
2119 //If the last of the positional arguments is a PropertyPutArgument
2120 //then obtain the type info for the property put operation.
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
2126 arArgs
[nUnoArgs
- 1].getValueType() == cppu::UnoType
<PropertyPutArgument
>::get())
2128 // DISPATCH_PROPERTYPUT
2129 FuncDesc
aDescGet(pInfo
);
2130 FuncDesc
aDescPut(pInfo
);
2131 VarDesc
aVarDesc(pInfo
);
2132 getPropDesc(sFuncName
, & aDescGet
, & aDescPut
, & aVarDesc
);
2135 throw IllegalArgumentException(
2136 "[automation bridge] The object does not have a writeable property: "
2137 + sFuncName
, Reference
<XInterface
>(), 0);
2139 *pFuncDesc
= aDescPut
.Detach();
2142 { // DISPATCH_METHOD
2143 FuncDesc
aFuncDesc(pInfo
);
2144 getFuncDesc(sFuncName
, & aFuncDesc
);
2147 // Fallback: DISPATCH_PROPERTYGET can mostly be called as
2149 ITypeInfo
* pTypeInfo
= getTypeInfo();
2150 FuncDesc
aDescPut(pTypeInfo
);
2151 VarDesc
aVarDesc(pTypeInfo
);
2152 getPropDesc(sFuncName
, & aFuncDesc
, & aDescPut
, & aVarDesc
);
2155 throw IllegalArgumentException(
2156 "[automation bridge] The object does not have a function"
2157 " or readable property \""
2158 + sFuncName
+ "\"", Reference
<XInterface
>(), 0);
2161 *pFuncDesc
= aFuncDesc
.Detach();
2164 bool IUnknownWrapper::getDispid(const OUString
& sFuncName
, DISPID
* id
)
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
);
2171 void IUnknownWrapper::getFuncDesc(const OUString
& sFuncName
, FUNCDESC
** pFuncDesc
)
2174 OSL_ASSERT( * pFuncDesc
== nullptr);
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())
2182 //try case insensitive with IDispatch::GetIDsOfNames
2184 if (getDispid(sFuncName
, &id
))
2186 CComBSTR memberName
;
2187 unsigned int pcNames
=0;
2188 // get the case sensitive name
2189 if( SUCCEEDED(getTypeInfo()->GetNames( id
, & memberName
, 1, &pcNames
)))
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
) ));
2204 m_mapComFunc
.find( sFuncName
);
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());
2214 for ( ;p
.first
!= p
.second
; p
.first
++, numEntries
++);
2215 OSL_ASSERT( ! (numEntries
> 3) );
2217 if( itIndex
!= m_mapComFunc
.end())
2219 ITypeInfo
* pType
= getTypeInfo();
2220 FUNCDESC
* pDesc
= nullptr;
2221 if (!SUCCEEDED(pType
->GetFuncDesc(itIndex
->second
, & pDesc
)))
2223 throw BridgeRuntimeError("[automation bridge] Could not get "
2224 "FUNCDESC for " + sFuncName
);
2226 if (pDesc
->invkind
== INVOKE_FUNC
)
2228 (*pFuncDesc
) = pDesc
;
2232 pType
->ReleaseFuncDesc(pDesc
);
2235 //else no entry found for sFuncName, pFuncDesc will not be filled in
2238 void IUnknownWrapper::getPropDesc(const OUString
& sFuncName
, FUNCDESC
** pFuncDescGet
,
2239 FUNCDESC
** pFuncDescPut
, VARDESC
** pVarDesc
)
2241 OSL_ASSERT( * pFuncDescGet
== nullptr && * pFuncDescPut
== nullptr);
2243 typedef TLBFuncIndexMap::const_iterator cit
;
2244 std::pair
<cit
, cit
> p
= m_mapComFunc
.equal_range(sFuncName
);
2245 if (p
.first
== m_mapComFunc
.end())
2247 //try case insensitive with IDispatch::GetIDsOfNames
2249 if (getDispid(sFuncName
, &id
))
2251 CComBSTR memberName
;
2252 unsigned int pcNames
=0;
2253 // get the case sensitive name
2254 if( SUCCEEDED(getTypeInfo()->GetNames( id
, & memberName
, 1, &pcNames
)))
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
))));
2264 for ( int i
= 0 ;p
.first
!= p
.second
; p
.first
++, i
++)
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
)))
2272 if (pFuncDesc
->invkind
== INVOKE_PROPERTYGET
)
2274 (*pFuncDescGet
) = pFuncDesc
;
2276 else if (pFuncDesc
->invkind
== INVOKE_PROPERTYPUT
||
2277 pFuncDesc
->invkind
== INVOKE_PROPERTYPUTREF
)
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
)
2284 //we already have found one
2285 pType
->ReleaseFuncDesc(pFuncDesc
);
2289 (*pFuncDescPut
) = pFuncDesc
;
2294 pType
->ReleaseFuncDesc(pFuncDesc
);
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
)))
2305 //else no entry for sFuncName, pFuncDesc will not be filled in
2308 VARTYPE
IUnknownWrapper::getUserDefinedElementType( ITypeInfo
* pTypeInfo
, const DWORD nHrefType
)
2310 VARTYPE
_type( VT_NULL
);
2313 CComPtr
<ITypeInfo
> spRefInfo
;
2314 pTypeInfo
->GetRefTypeInfo( nHrefType
, &spRefInfo
.p
);
2317 TypeAttr
attr( spRefInfo
);
2318 spRefInfo
->GetTypeAttr( &attr
);
2319 if ( attr
->typekind
== TKIND_ENUM
)
2321 // We use the type of the first enum value.
2322 if ( attr
->cVars
== 0 )
2324 throw BridgeRuntimeError("[automation bridge] Could not obtain type description");
2326 VarDesc
var( spRefInfo
);
2327 spRefInfo
->GetVarDesc( 0, &var
);
2328 _type
= var
->lpvarValue
->vt
;
2330 else if ( attr
->typekind
== TKIND_INTERFACE
)
2334 else if ( attr
->typekind
== TKIND_DISPATCH
)
2336 _type
= VT_DISPATCH
;
2338 else if ( attr
->typekind
== TKIND_ALIAS
)
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
);
2345 throw BridgeRuntimeError( "[automation bridge] Unhandled user defined type." );
2352 VARTYPE
IUnknownWrapper::getElementTypeDesc(const TYPEDESC
*desc
)
2354 VARTYPE
_type( VT_NULL
);
2356 if (desc
->vt
== VT_PTR
)
2358 _type
= getElementTypeDesc(desc
->lptdesc
);
2361 else if (desc
->vt
== VT_SAFEARRAY
)
2363 _type
= getElementTypeDesc(desc
->lptdesc
);
2366 else if (desc
->vt
== VT_USERDEFINED
)
2368 ITypeInfo
* thisInfo
= getTypeInfo(); //kept by this instance
2369 _type
= getUserDefinedElementType( thisInfo
, desc
->hreftype
);
2378 void IUnknownWrapper::buildComTlbIndex()
2380 if ( ! m_bComTlbIndexInit
)
2382 MutexGuard
guard(getBridgeMutex());
2384 if ( ! m_bComTlbIndexInit
)
2387 ITypeInfo
* pType
= getTypeInfo();
2388 TypeAttr
typeAttr(pType
);
2389 if( SUCCEEDED( pType
->GetTypeAttr( &typeAttr
)))
2391 for( WORD i
= 0; i
< typeAttr
->cFuncs
; i
++)
2393 FuncDesc
funcDesc(pType
);
2394 if( SUCCEEDED( pType
->GetFuncDesc( i
, &funcDesc
)))
2396 CComBSTR memberName
;
2397 unsigned int pcNames
=0;
2398 if( SUCCEEDED(pType
->GetNames( funcDesc
->memid
, & memberName
, 1, &pcNames
)))
2400 OUString
usName(o3tl::toU(LPCOLESTR(memberName
)));
2401 m_mapComFunc
.emplace(usName
, i
);
2405 sError
= "[automation bridge] IUnknownWrapper::buildComTlbIndex, "
2406 "ITypeInfo::GetNames failed.";
2410 sError
= "[automation bridge] IUnknownWrapper::buildComTlbIndex, "
2411 "ITypeInfo::GetFuncDesc failed.";
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
++)
2418 VarDesc
varDesc(pType
);
2419 if (SUCCEEDED(pType
->GetVarDesc(i
, & varDesc
)))
2421 CComBSTR memberName
;
2422 unsigned int pcNames
= 0;
2423 if (SUCCEEDED(pType
->GetNames(varDesc
->memid
, & memberName
, 1, &pcNames
)))
2425 if (varDesc
->varkind
== VAR_DISPATCH
)
2427 OUString
usName(o3tl::toU(LPCOLESTR(memberName
)));
2428 m_mapComFunc
.emplace(usName
, i
);
2433 sError
= "[automation bridge] IUnknownWrapper::buildComTlbIndex, "
2434 "ITypeInfo::GetNames failed.";
2438 sError
= "[automation bridge] IUnknownWrapper::buildComTlbIndex, "
2439 "ITypeInfo::GetVarDesc failed.";
2444 sError
= "[automation bridge] IUnknownWrapper::buildComTlbIndex, "
2445 "ITypeInfo::GetTypeAttr failed.";
2447 if (sError
.getLength())
2449 throw BridgeRuntimeError(sError
);
2452 m_bComTlbIndexInit
= true;
2458 ITypeInfo
* IUnknownWrapper::getTypeInfo()
2462 throw BridgeRuntimeError("The object has no IDispatch interface!");
2467 MutexGuard
guard(getBridgeMutex());
2470 CComPtr
< ITypeInfo
> spType
;
2471 if( !SUCCEEDED( m_spDispatch
->GetTypeInfo( 0, LOCALE_USER_DEFAULT
, &spType
.p
)))
2473 throw BridgeRuntimeError("[automation bridge]The dispatch object does not "
2474 "support ITypeInfo!");
2477 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
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
)))
2484 if (typeAttr
->typekind
== TKIND_INTERFACE
&&
2485 typeAttr
->wTypeFlags
& TYPEFLAG_FDUAL
)
2487 HREFTYPE refDispatch
;
2488 if (!SUCCEEDED(spType
->GetRefTypeOfImplType(::sal::static_int_cast
< UINT
, int >( -1 ), &refDispatch
)))
2490 throw BridgeRuntimeError(
2491 "[automation bridge] Could not obtain type information "
2492 "for dispatch interface." );
2494 CComPtr
<ITypeInfo
> spTypeDisp
;
2495 if (SUCCEEDED(spType
->GetRefTypeInfo(refDispatch
, & spTypeDisp
)))
2496 m_spTypeInfo
= spTypeDisp
;
2498 else if (typeAttr
->typekind
== TKIND_DISPATCH
)
2500 m_spTypeInfo
= spType
;
2504 throw BridgeRuntimeError(
2505 "[automation bridge] Automation object does not "
2506 "provide type information.");
2511 return m_spTypeInfo
;
2514 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */