Gtk-WARNING gtktreestore.c:1047: Invalid column number 1 added to iter
[LibreOffice.git] / extensions / source / ole / oleobjw.cxx
blobd9c0296110fd6c86315d604a256485cf06846ed6
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
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>
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>
42 #include <rtl/uuid.h>
43 #include <rtl/ustring.hxx>
45 #include "jscriptclasses.hxx"
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;
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
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;
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 );
99 #endif
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 )
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);
134 Reference<XIntrospectionAccess> SAL_CALL IUnknownWrapper::getIntrospection()
136 Reference<XIntrospectionAccess> ret;
138 return ret;
141 Any SAL_CALL IUnknownWrapper::invokeGetProperty( const OUString& aPropertyName, const Sequence< Any >& aParams, Sequence< sal_Int16 >& aOutParamIndex, Sequence< Any >& aOutParam )
143 Any aResult;
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 )
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 " +
165 e.Message,
166 nullptr, anyEx );
168 return aResult;
171 Any SAL_CALL IUnknownWrapper::invokePutProperty( const OUString& aPropertyName, const Sequence< Any >& aParams, Sequence< sal_Int16 >& aOutParamIndex, Sequence< Any >& aOutParam )
173 Any aResult;
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 )
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" +
195 e.Message,
196 nullptr, anyEx );
198 return aResult;
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");
212 Any ret;
216 o2u_attachCurrentThread();
218 TypeDescription methodDesc;
219 getMethodInfo(aFunctionName, methodDesc);
220 if( methodDesc.is())
222 ret = invokeWithDispIdUnoTlb(aFunctionName,
223 aParams,
224 aOutParamIndex,
225 aOutParam);
227 else
229 ret= invokeWithDispIdComTlb( aFunctionName,
230 aParams,
231 aOutParamIndex,
232 aOutParam);
235 catch (const IllegalArgumentException &)
237 throw;
239 catch (const CannotConvertException &)
241 throw;
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" +
252 e.Message,
253 nullptr, anyEx );
256 catch(...)
258 throw RuntimeException("[automation bridge] unexpected exception in "
259 "IUnknownWrapper::Invoke !");
261 return ret;
264 void SAL_CALL IUnknownWrapper::setValue( const OUString& aPropertyName,
265 const Any& aValue )
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) )
292 //read-only
293 SAL_WARN( "extensions.olebridge", "[automation bridge] Property " << aPropertyName << " is read-only");
294 // ignore silently
295 return;
298 HRESULT hr= S_OK;
299 DISPPARAMS dispparams;
300 CComVariant varArg;
301 CComVariant varRefArg;
302 CComVariant varResult;
303 ExcepInfo excepinfo;
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);
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)
322 vt = getElementTypeDesc(& aDescPut->lprgelemdescParam[0].tdesc);
323 dispid = aDescPut->memid;
324 invkind = aDescPut->invkind;
326 else
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
338 if (vt & VT_BYREF)
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;
349 else
351 anyToVariant(& varArg, aValue, vt);
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);
357 // lookup error code
358 switch (hr)
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;
404 catch (const CannotConvertException &)
406 throw;
408 catch (const UnknownPropertyException &)
410 throw;
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" +
421 e.Message,
422 nullptr, anyEx );
425 catch (...)
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");
440 Any ret;
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" )
456 if ( pInfo && m_sTypeName.getLength() == 0 )
458 m_sTypeName = "IDispatch";
459 CComBSTR sName;
461 if ( SUCCEEDED( pInfo->GetDocumentation( -1, &sName, nullptr, nullptr, nullptr ) ) )
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 )) )
472 if ( SUCCEEDED( pTypeLib->GetDocumentation( -1, &sName, nullptr, nullptr, nullptr ) ) )
474 OUString sLibName( o3tl::toU(LPCOLESTR(sName)));
475 m_sTypeName = sLibName + "." + sTmp;
482 ret <<= m_sTypeName;
483 return ret;
485 FuncDesc aDescGet(pInfo);
486 FuncDesc aDescPut(pInfo);
487 VarDesc aVarDesc(pInfo);
488 getPropDesc(aPropertyName, & aDescGet, & aDescPut, & aVarDesc);
489 if ( ! aDescGet && ! aDescPut && ! aVarDesc)
491 //property not found
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);
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;
512 hr = m_spDispatch->Invoke(dispid,
513 IID_NULL,
514 LOCALE_USER_DEFAULT,
515 DISPATCH_PROPERTYGET,
516 &dispparams,
517 &varResult,
518 &excepinfo,
519 &uArgErr);
521 // converting return value and out parameter back to UNO
522 if (hr == S_OK)
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);
534 // lookup error code
535 switch (hr)
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;
552 catch ( const UnknownPropertyException& )
554 throw;
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" +
565 e.Message,
566 nullptr, anyEx );
568 catch (...)
570 throw RuntimeException(
571 "[automation bridge] unexpected exception in "
572 "IUnknownWrapper::getValue !");
574 return ret;
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");
584 bool ret = false;
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)
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;
604 else
605 ret = true;
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" +
616 e.Message,
617 nullptr, anyEx );
619 catch (...)
621 throw RuntimeException("[automation bridge] unexpected exception in "
622 "IUnknownWrapper::hasMethod !");
624 return ret;
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");
634 bool ret = false;
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
651 if (aVarDesc
652 || aDescPut
653 || aDescGet )
655 ret = true;
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" +
667 e.Message,
668 nullptr, anyEx );
671 catch (...)
673 throw RuntimeException("[automation bridge] unexpected exception in "
674 "IUnknownWrapper::hasProperty !");
676 return ret;
679 Any SAL_CALL IUnknownWrapper::createBridge( const Any& modelDepObject,
680 const Sequence< sal_Int8 >& /*aProcessId*/, sal_Int16 sourceModelType,
681 sal_Int16 destModelType )
683 Any ret;
684 o2u_attachCurrentThread();
686 if (
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));
695 if (xInt == xSelf)
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();
707 else
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());
718 return ret;
720 /** @internal
721 @exception IllegalArgumentException
722 @exception CannotConvertException
723 @exception InvocationTargetException
724 @RuntimeException
726 Any IUnknownWrapper::invokeWithDispIdUnoTlb(const OUString& sFunctionName,
727 const Sequence< Any >& Params,
728 Sequence< sal_Int16 >& OutParamIndex,
729 Sequence< Any >& OutParam)
731 Any ret;
732 HRESULT hr= S_OK;
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;
748 bool bConvRet= true;
750 if( methodDesc.is())
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)
768 outParameterCount++;
771 if( !bJScriptObject)
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;
780 for( i= 0; i < parameterCount; i++)
782 // In parameter
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 )
790 CComVariant var;
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;
808 break;
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;
819 break;
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;
828 break;
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];
837 break;
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;
847 break;
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;
858 break;
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;
869 break;
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;
879 break;
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;
889 break;
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;
901 break;
903 default:
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];
913 outParamIndex++;
914 } // end else if
915 } // end for
917 catch (IllegalArgumentException & e)
919 e.ArgumentPosition = ::sal::static_int_cast< sal_Int16, int >( i );
920 throw;
922 catch (CannotConvertException & e)
924 e.ArgumentIndex = i;
925 throw;
928 else // it is a JScriptObject
930 int i = 0;
933 for( ; i< parameterCount; i++)
935 // In parameter
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 "
970 "param!");
976 catch (IllegalArgumentException & e)
978 e.ArgumentPosition = ::sal::static_int_cast< sal_Int16, int >( i );
979 throw;
981 catch (CannotConvertException & e)
983 e.ArgumentIndex = i;
984 throw;
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
992 //We should not run into this block, because invokeWithDispIdComTlb should
993 //have been called instead.
994 OSL_ASSERT(false);
998 CComVariant varResult;
999 ExcepInfo excepinfo;
1000 unsigned int uArgErr;
1001 DISPPARAMS dispparams= { pVarParams, nullptr, static_cast<UINT>(parameterCount), 0};
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);
1016 // converting return value and out parameter back to UNO
1017 if (hr == S_OK)
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;
1026 int i = 0;
1029 for( ; i < parameterCount; i++)
1031 if( pMethod->pParams[i].bOut )
1033 pOutParamIndex[outIndex]= static_cast<sal_Int16>(i);
1034 Any outAny;
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);
1046 if( pDisp)
1048 CComVariant varOut;
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;
1055 else
1056 bConvRet= false;
1058 else
1059 bConvRet= false;
1061 else
1062 bConvRet= false;
1065 if( !bConvRet) break;
1068 catch(IllegalArgumentException & e)
1070 e.ArgumentPosition = ::sal::static_int_cast< sal_Int16, int >( i );
1071 throw;
1073 catch(CannotConvertException & e)
1075 e.ArgumentIndex = i;
1076 throw;
1079 // return value, no type information available
1080 if ( bConvRet)
1084 if( pMethod )
1085 variantToAny(&varResult, ret, Type( pMethod->pReturnTypeRef), false);
1086 else
1087 variantToAny(&varResult, ret, false);
1089 catch (IllegalArgumentException & e)
1091 e.Message =
1092 "[automation bridge]IUnknownWrapper::invokeWithDispIdUnoTlb\n"
1093 "Could not convert return value! \n Message: \n" + e.Message;
1094 throw;
1096 catch (CannotConvertException & e)
1098 e.Message =
1099 "[automation bridge]IUnknownWrapper::invokeWithDispIdUnoTlb\n"
1100 "Could not convert return value! \n Message: \n" + e.Message;
1101 throw;
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)
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;
1157 return ret;
1161 // XInitialization
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& )
1189 if ( pType )
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 );
1207 if ( !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,
1235 nullptr, anyEx );
1241 // XDirectInvocation
1242 uno::Any SAL_CALL IUnknownWrapper::directInvoke( const OUString& aName, const uno::Sequence< uno::Any >& aParams )
1244 Any aResult;
1246 if ( !m_spDispatch )
1248 throw RuntimeException(
1249 "[automation bridge] The object does not have an IDispatch interface");
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);
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()));
1297 int cNamedArg = 0;
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;
1324 else
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);
1336 else
1338 throw InvocationTargetException(
1339 "[automation bridge] ITypeInfo::GetIDsOfNames returned error "
1340 + OUString::number(static_cast<sal_Int32>(hr), 16), Reference<XInterface>(), Any());
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();
1350 sal_Int32 nInd = 0;
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;
1358 Any anyArg;
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;
1366 anyArg >>= arg;
1367 anyArg = arg.Value;
1369 // named argument
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 );
1381 else
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 );
1391 throw;
1393 catch (CannotConvertException & e)
1395 e.ArgumentIndex = nInd;
1396 throw;
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);
1411 // converting return value and out parameter back to UNO
1412 if ( SUCCEEDED( hInvRes ) )
1413 variantToAny( &varResult, aResult, false );
1414 else
1416 // map error codes to exceptions
1417 OUString message;
1418 switch ( hInvRes )
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;
1484 return aResult;
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();
1496 DISPID dispid;
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);
1516 else
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);
1530 if( desc.is())
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);
1541 if( desc.is())
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());
1559 if( pInterface)
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;
1574 break;
1576 TYPELIB_DANGER_RELEASE( pDescMember);
1579 if( pMember)
1581 ret= &pMember->aBase;
1582 TYPELIB_DANGER_RELEASE( &pMember->aBase);
1585 if( ret.is())
1586 break;
1588 return ret;
1591 bool IUnknownWrapper::isJScriptObject()
1593 if( m_eJScript == JScriptUndefined)
1595 CComDispatchDriver disp( m_spDispatch);
1596 if( disp)
1598 CComVariant result;
1599 if( SUCCEEDED( disp.GetPropertyByName( JSCRIPT_ID_PROPERTY, &result)))
1601 if(result.vt == VT_BSTR)
1603 CComBSTR name( result.bstrVal);
1604 name.ToLower();
1605 if( name == CComBSTR(JSCRIPT_ID))
1606 m_eJScript= IsJScript;
1610 if( m_eJScript == JScriptUndefined)
1611 m_eJScript= NoJScript;
1614 return m_eJScript != NoJScript;
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
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)
1647 Any ret;
1648 HRESULT result;
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;
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;
1692 else
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;
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
1723 //args.
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()));
1735 int cNamedArg = 0;
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() );
1757 if (hr == S_OK)
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;
1771 else
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);
1785 else
1787 throw InvocationTargetException(
1788 "[automation bridge] ITypeInfo::GetIDsOfNames returned error "
1789 + OUString::number(static_cast<sal_Int32>(hr), 16), Reference<XInterface>(), Any());
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();
1800 for (i = 0; i < static_cast<sal_Int32>(dispparams.cArgs); i++)
1802 revIndex= dispparams.cArgs - i -1;
1803 arRefArgs[revIndex].byref=nullptr;
1804 Any anyArg;
1805 if ( i < nUnoArgs)
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;
1832 anyArg >>= arg;
1833 anyArg = arg.Value;
1835 // named argument
1836 if (anyArg.getValueType() == cppu::UnoType<NamedArgument>::get())
1838 NamedArgument aNamedArgument;
1839 anyArg >>= aNamedArgument;
1840 anyArg = aNamedArgument.Value;
1842 // out param
1843 if (paramFlags & PARAMFLAG_FOUT &&
1844 ! (paramFlags & PARAMFLAG_FIN) )
1846 VARTYPE type = ::sal::static_int_cast< VARTYPE, int >( varType ^ VT_BYREF );
1847 if (i < nUnoArgs)
1849 arRefArgs[revIndex].vt= type;
1851 else
1853 //optional arg
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];
1862 else
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;
1871 // in/out + in byref params
1872 else if (varType & VT_BYREF)
1874 VARTYPE type = ::sal::static_int_cast< VARTYPE, int >( varType ^ VT_BYREF );
1875 CComVariant var;
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);
1888 else
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;
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];
1913 else
1914 arArgs[revIndex].byref = & arRefArgs[revIndex];
1916 else
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
1924 else
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;
1944 else
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 );
1955 throw;
1957 catch (CannotConvertException & e)
1959 e.ArgumentIndex = i;
1960 throw;
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);
1973 // converting return value and out parameter back to UNO
1974 if (result == S_OK)
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 &
1982 PARAMFLAG_FOUT)
1983 outParamsCount++;
1986 OutParamIndex.realloc(outParamsCount);
1987 OutParam.realloc(outParamsCount);
1988 // Convert out params
1989 if (outParamsCount)
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
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.
2017 variantToAny( & arRefArgs[revParamIndex], outAny, false );
2019 catch (IllegalArgumentException & e)
2021 e.ArgumentPosition = static_cast<sal_Int16>(paramIndex);
2022 throw;
2024 catch (CannotConvertException & e)
2026 e.ArgumentIndex = paramIndex;
2027 throw;
2029 pOutParam[outParamIndex] = outAny;
2030 pOutParamIndex[outParamIndex] = ::sal::static_int_cast< sal_Int16, int >( paramIndex );
2031 outParamIndex++;
2033 OutParam.realloc(outParamIndex);
2034 OutParamIndex.realloc(outParamIndex);
2036 // Return value
2037 variantToAny(&varResult, ret, false);
2040 // map error codes to exceptions
2041 OUString message;
2042 switch (result)
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));
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;
2108 return ret;
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
2125 if (nUnoArgs > 0 &&
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);
2133 if ( ! aDescPut)
2135 throw IllegalArgumentException(
2136 "[automation bridge] The object does not have a writeable property: "
2137 + sFuncName, Reference<XInterface>(), 0);
2139 *pFuncDesc = aDescPut.Detach();
2141 else
2142 { // DISPATCH_METHOD
2143 FuncDesc aFuncDesc(pInfo);
2144 getFuncDesc(sFuncName, & aFuncDesc);
2145 if ( ! aFuncDesc)
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 )
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);
2169 return hr == S_OK;
2171 void IUnknownWrapper::getFuncDesc(const OUString & sFuncName, FUNCDESC ** pFuncDesc)
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())
2182 //try case insensitive with IDispatch::GetIDsOfNames
2183 DISPID id;
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 ) ));
2203 itIndex =
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());
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())
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;
2230 else
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);
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())
2247 //try case insensitive with IDispatch::GetIDsOfNames
2248 DISPID id;
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);
2287 else
2289 (*pFuncDescPut) = pFuncDesc;
2292 else
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)))
2303 (*pVarDesc) = 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 );
2311 if ( pTypeInfo )
2313 CComPtr<ITypeInfo> spRefInfo;
2314 pTypeInfo->GetRefTypeInfo( nHrefType, &spRefInfo.p );
2315 if ( spRefInfo )
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 )
2332 _type = VT_UNKNOWN;
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 );
2343 else
2345 throw BridgeRuntimeError( "[automation bridge] Unhandled user defined type." );
2349 return _type;
2352 VARTYPE IUnknownWrapper::getElementTypeDesc(const TYPEDESC *desc)
2354 VARTYPE _type( VT_NULL );
2356 if (desc->vt == VT_PTR)
2358 _type = getElementTypeDesc(desc->lptdesc);
2359 _type |= VT_BYREF;
2361 else if (desc->vt == VT_SAFEARRAY)
2363 _type = getElementTypeDesc(desc->lptdesc);
2364 _type |= VT_ARRAY;
2366 else if (desc->vt == VT_USERDEFINED)
2368 ITypeInfo* thisInfo = getTypeInfo(); //kept by this instance
2369 _type = getUserDefinedElementType( thisInfo, desc->hreftype );
2371 else
2373 _type = desc->vt;
2375 return _type;
2378 void IUnknownWrapper::buildComTlbIndex()
2380 if ( ! m_bComTlbIndexInit)
2382 MutexGuard guard(getBridgeMutex());
2384 if ( ! m_bComTlbIndexInit)
2386 OUString sError;
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);
2403 else
2405 sError = "[automation bridge] IUnknownWrapper::buildComTlbIndex, "
2406 "ITypeInfo::GetNames failed.";
2409 else
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);
2431 else
2433 sError = "[automation bridge] IUnknownWrapper::buildComTlbIndex, "
2434 "ITypeInfo::GetNames failed.";
2437 else
2438 sError = "[automation bridge] IUnknownWrapper::buildComTlbIndex, "
2439 "ITypeInfo::GetVarDesc failed.";
2443 else
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()
2460 if( !m_spDispatch)
2462 throw BridgeRuntimeError("The object has no IDispatch interface!");
2465 if( !m_spTypeInfo )
2467 MutexGuard guard(getBridgeMutex());
2468 if( ! m_spTypeInfo)
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;
2502 else
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: */