Version 5.4.3.2, tag libreoffice-5.4.3.2
[LibreOffice.git] / extensions / source / ole / oleobjw.cxx
blob43fc37670a53923b052015123f069cc9358c1f1e
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 "rtl/ustrbuf.hxx"
24 #include "osl/diagnose.h"
25 #include "osl/doublecheckedlocking.h"
26 #include "osl/thread.h"
28 #include <memory>
29 #include <com/sun/star/script/CannotConvertException.hpp>
30 #include <com/sun/star/script/FailReason.hpp>
31 #include <com/sun/star/beans/XMaterialHolder.hpp>
32 #include <com/sun/star/script/XTypeConverter.hpp>
33 #include <com/sun/star/script/FinishEngineEvent.hpp>
34 #include <com/sun/star/script/InterruptReason.hpp>
35 #include <com/sun/star/script/XEngineListener.hpp>
36 #include <com/sun/star/script/XDebugging.hpp>
37 #include <com/sun/star/script/XInvocation.hpp>
38 #include <com/sun/star/script/ContextInformation.hpp>
39 #include <com/sun/star/script/FinishReason.hpp>
40 #include <com/sun/star/script/XEngine.hpp>
41 #include <com/sun/star/script/InterruptEngineEvent.hpp>
42 #include <com/sun/star/script/XLibraryAccess.hpp>
43 #include <com/sun/star/bridge/ModelDependent.hpp>
45 #include "com/sun/star/bridge/oleautomation/NamedArgument.hpp"
46 #include "com/sun/star/bridge/oleautomation/PropertyPutArgument.hpp"
48 #include <typelib/typedescription.hxx>
49 #include <rtl/uuid.h>
50 #include <rtl/ustring.hxx>
52 #include "jscriptclasses.hxx"
54 #include "oleobjw.hxx"
55 #include "unoobjw.hxx"
56 #include <stdio.h>
57 using namespace std;
58 using namespace osl;
59 using namespace cppu;
60 using namespace com::sun::star::script;
61 using namespace com::sun::star::lang;
62 using namespace com::sun::star::bridge;
63 using namespace com::sun::star::bridge::oleautomation;
64 using namespace com::sun::star::bridge::ModelDependent;
65 using namespace ::com::sun::star;
68 #define JSCRIPT_ID_PROPERTY L"_environment"
69 #define JSCRIPT_ID L"jscript"
70 namespace ole_adapter
74 // key: XInterface pointer created by Invocation Adapter Factory
75 // value: XInterface pointer to the wrapper class.
76 // Entries to the map are made within
77 // Any createOleObjectWrapper(IUnknown* pUnknown, const Type& aType);
78 // Entries are being deleted if the wrapper class's destructor has been
79 // called.
80 // Before UNO object is wrapped to COM object this map is checked
81 // to see if the UNO object is already a wrapper.
82 std::unordered_map<sal_uIntPtr, sal_uIntPtr> AdapterToWrapperMap;
83 // key: XInterface of the wrapper object.
84 // value: XInterface of the Interface created by the Invocation Adapter Factory.
85 // A COM wrapper is responsible for removing the corresponding entry
86 // in AdapterToWrapperMap if it is being destroyed. Because the wrapper does not
87 // know about its adapted interface it uses WrapperToAdapterMap to get the
88 // adapted interface which is then used to locate the entry in AdapterToWrapperMap.
89 std::unordered_map<sal_uIntPtr,sal_uIntPtr> WrapperToAdapterMap;
91 std::unordered_map<sal_uIntPtr, WeakReference<XInterface> > ComPtrToWrapperMap;
92 /*****************************************************************************
94 class implementation IUnknownWrapper_Impl
96 *****************************************************************************/
98 IUnknownWrapper_Impl::IUnknownWrapper_Impl( Reference<XMultiServiceFactory>& xFactory,
99 sal_uInt8 unoWrapperClass, sal_uInt8 comWrapperClass):
100 UnoConversionUtilities<IUnknownWrapper_Impl>( xFactory, unoWrapperClass, comWrapperClass),
101 m_pxIdlClass( nullptr), m_eJScript( JScriptUndefined),
102 m_bComTlbIndexInit(false), m_bHasDfltMethod(false), m_bHasDfltProperty(false)
107 IUnknownWrapper_Impl::~IUnknownWrapper_Impl()
109 o2u_attachCurrentThread();
110 MutexGuard guard(getBridgeMutex());
111 XInterface * xIntRoot = static_cast<OWeakObject *>(this);
112 #if OSL_DEBUG_LEVEL > 0
113 acquire(); // make sure we don't delete us twice because of Reference
114 OSL_ASSERT( Reference<XInterface>( static_cast<XWeak*>(this), UNO_QUERY).get() == xIntRoot );
115 #endif
117 // remove entries in global maps
118 typedef std::unordered_map<sal_uIntPtr, sal_uIntPtr>::iterator IT;
119 IT it= WrapperToAdapterMap.find( reinterpret_cast<sal_uIntPtr>(xIntRoot));
120 if( it != WrapperToAdapterMap.end())
122 sal_uIntPtr adapter= it->second;
124 AdapterToWrapperMap.erase( adapter);
125 WrapperToAdapterMap.erase( it);
128 IT_Com it_c= ComPtrToWrapperMap.find( reinterpret_cast<sal_uIntPtr>(m_spUnknown.p));
129 if(it_c != ComPtrToWrapperMap.end())
130 ComPtrToWrapperMap.erase(it_c);
133 Any IUnknownWrapper_Impl::queryInterface(const Type& t)
135 if (t == cppu::UnoType<XDefaultMethod>::get() && !m_bHasDfltMethod )
136 return Any();
137 if (t == cppu::UnoType<XDefaultProperty>::get() && !m_bHasDfltProperty )
138 return Any();
139 if ( ( t == cppu::UnoType<XInvocation>::get() || t == cppu::UnoType<XAutomationInvocation>::get() ) && !m_spDispatch)
140 return Any();
141 // XDirectInvocation seems to be an oracle replacement for XAutomationInvocation, however it is flawed especially wrt. assumptions about whether to invoke a
142 // 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.
143 // XAutomationInvocation provides separate calls for put& get
144 // 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.
145 // 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
146 // runtime to call XAutomationInvocation instead of XDirectInvoke
147 return WeakImplHelper<XBridgeSupplier2,
148 XInitialization, XAutomationObject, XDefaultProperty, XDefaultMethod, XDirectInvocation, XAutomationInvocation >::queryInterface(t);
151 Reference<XIntrospectionAccess> SAL_CALL IUnknownWrapper_Impl::getIntrospection()
153 Reference<XIntrospectionAccess> ret;
155 return ret;
158 Any SAL_CALL IUnknownWrapper_Impl::invokeGetProperty( const OUString& aPropertyName, const Sequence< Any >& aParams, Sequence< sal_Int16 >& aOutParamIndex, Sequence< Any >& aOutParam )
160 Any aResult;
163 o2u_attachCurrentThread();
164 ITypeInfo * pInfo = getTypeInfo();
165 FuncDesc aDescGet(pInfo);
166 FuncDesc aDescPut(pInfo);
167 VarDesc aVarDesc(pInfo);
168 getPropDesc(aPropertyName, & aDescGet, & aDescPut, & aVarDesc);
169 if ( !aDescGet )
171 OUString msg("[automation bridge]Property \"" + aPropertyName +
172 "\" is not supported");
173 throw UnknownPropertyException(msg);
175 aResult = invokeWithDispIdComTlb( aDescGet, aPropertyName, aParams, aOutParamIndex, aOutParam );
177 catch ( const Exception& e )
179 throw RuntimeException("[automation bridge] unexpected exception in "
180 "IUnknownWrapper_Impl::invokeGetProperty ! Message : \n" +
181 e.Message);
183 return aResult;
186 Any SAL_CALL IUnknownWrapper_Impl::invokePutProperty( const OUString& aPropertyName, const Sequence< Any >& aParams, Sequence< sal_Int16 >& aOutParamIndex, Sequence< Any >& aOutParam )
188 Any aResult;
191 o2u_attachCurrentThread();
192 ITypeInfo * pInfo = getTypeInfo();
193 FuncDesc aDescGet(pInfo);
194 FuncDesc aDescPut(pInfo);
195 VarDesc aVarDesc(pInfo);
196 getPropDesc(aPropertyName, & aDescGet, & aDescPut, & aVarDesc);
197 if ( !aDescPut )
199 OUString msg("[automation bridge]Property \"" + aPropertyName +
200 "\" is not supported");
201 throw UnknownPropertyException(msg);
203 aResult = invokeWithDispIdComTlb( aDescPut, aPropertyName, aParams, aOutParamIndex, aOutParam );
205 catch ( const Exception& e )
207 throw RuntimeException("[automation bridge] unexpected exception in "
208 "IUnknownWrapper_Impl::invokePutProperty ! Message : \n" +
209 e.Message);
211 return aResult;
215 Any SAL_CALL IUnknownWrapper_Impl::invoke( const OUString& aFunctionName,
216 const Sequence< Any >& aParams, Sequence< sal_Int16 >& aOutParamIndex,
217 Sequence< Any >& aOutParam )
219 if ( ! m_spDispatch )
221 throw RuntimeException(
222 "[automation bridge] The object does not have an IDispatch interface");
225 Any ret;
229 o2u_attachCurrentThread();
231 TypeDescription methodDesc;
232 getMethodInfo(aFunctionName, methodDesc);
233 if( methodDesc.is())
235 ret = invokeWithDispIdUnoTlb(aFunctionName,
236 aParams,
237 aOutParamIndex,
238 aOutParam);
240 else
242 ret= invokeWithDispIdComTlb( aFunctionName,
243 aParams,
244 aOutParamIndex,
245 aOutParam);
248 catch (const IllegalArgumentException &)
250 throw;
252 catch (const CannotConvertException &)
254 throw;
256 catch (const BridgeRuntimeError & e)
258 throw RuntimeException(e.message);
260 catch (const Exception & e)
262 throw RuntimeException("[automation bridge] unexpected exception in "
263 "IUnknownWrapper_Impl::invoke ! Message : \n" +
264 e.Message);
267 catch(...)
269 throw RuntimeException("[automation bridge] unexpected exception in "
270 "IUnknownWrapper_Impl::Invoke !");
272 return ret;
275 void SAL_CALL IUnknownWrapper_Impl::setValue( const OUString& aPropertyName,
276 const Any& aValue )
278 if ( ! m_spDispatch )
280 throw RuntimeException(
281 "[automation bridge] The object does not have an IDispatch interface");
285 o2u_attachCurrentThread();
287 ITypeInfo * pInfo = getTypeInfo();
288 FuncDesc aDescGet(pInfo);
289 FuncDesc aDescPut(pInfo);
290 VarDesc aVarDesc(pInfo);
291 getPropDesc(aPropertyName, & aDescGet, & aDescPut, & aVarDesc);
292 //check if there is such a property at all or if it is read only
293 if ( ! aDescPut && ! aDescGet && ! aVarDesc)
295 OUString msg("[automation bridge]Property \"" + aPropertyName +
296 "\" is not supported");
297 throw UnknownPropertyException(msg);
300 if ( (! aDescPut && aDescGet)
301 || (aVarDesc && aVarDesc->wVarFlags == VARFLAG_FREADONLY) )
303 //read-only
304 OUString msg("[automation bridge] Property " + aPropertyName +
305 " is read-only");
306 OString sMsg = OUStringToOString(msg, osl_getThreadTextEncoding());
307 OSL_FAIL(sMsg.getStr());
308 // ignore silently
309 return;
312 HRESULT hr= S_OK;
313 DISPPARAMS dispparams;
314 CComVariant varArg;
315 CComVariant varRefArg;
316 CComVariant varResult;
317 ExcepInfo excepinfo;
318 unsigned int uArgErr;
320 // converting UNO value to OLE variant
321 DISPID dispidPut= DISPID_PROPERTYPUT;
322 dispparams.rgdispidNamedArgs = &dispidPut;
323 dispparams.cArgs = 1;
324 dispparams.cNamedArgs = 1;
325 dispparams.rgvarg = & varArg;
327 OSL_ASSERT(aDescPut || aVarDesc);
329 VARTYPE vt = 0;
330 DISPID dispid = 0;
331 INVOKEKIND invkind = INVOKE_PROPERTYPUT;
332 //determine the expected type, dispid, invoke kind (DISPATCH_PROPERTYPUT,
333 //DISPATCH_PROPERTYPUTREF)
334 if (aDescPut)
336 vt = getElementTypeDesc(& aDescPut->lprgelemdescParam[0].tdesc);
337 dispid = aDescPut->memid;
338 invkind = aDescPut->invkind;
340 else
342 vt = getElementTypeDesc( & aVarDesc->elemdescVar.tdesc);
343 dispid = aVarDesc->memid;
344 if (vt == VT_UNKNOWN || vt == VT_DISPATCH ||
345 (vt & VT_ARRAY) || (vt & VT_BYREF))
347 invkind = INVOKE_PROPERTYPUTREF;
351 // convert the uno argument
352 if (vt & VT_BYREF)
354 anyToVariant( & varRefArg, aValue, ::sal::static_int_cast< VARTYPE, int >( vt ^ VT_BYREF ) );
355 varArg.vt = vt;
356 if( (vt & VT_TYPEMASK) == VT_VARIANT)
357 varArg.byref = & varRefArg;
358 else if ((vt & VT_TYPEMASK) == VT_DECIMAL)
359 varArg.byref = & varRefArg.decVal;
360 else
361 varArg.byref = & varRefArg.byref;
363 else
365 anyToVariant(& varArg, aValue, vt);
367 // call to IDispatch
368 hr = m_spDispatch->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, ::sal::static_int_cast< WORD, INVOKEKIND >( invkind ),
369 &dispparams, & varResult, & excepinfo, &uArgErr);
371 // lookup error code
372 switch (hr)
374 case S_OK:
375 break;
376 case DISP_E_BADPARAMCOUNT:
377 throw RuntimeException();
378 break;
379 case DISP_E_BADVARTYPE:
380 throw RuntimeException();
381 break;
382 case DISP_E_EXCEPTION:
383 throw InvocationTargetException();
384 break;
385 case DISP_E_MEMBERNOTFOUND:
386 throw UnknownPropertyException();
387 break;
388 case DISP_E_NONAMEDARGS:
389 throw RuntimeException();
390 break;
391 case DISP_E_OVERFLOW:
392 throw CannotConvertException("call to OLE object failed", static_cast<XInterface*>(
393 static_cast<XWeak*>(this)), TypeClass_UNKNOWN, FailReason::OUT_OF_RANGE, uArgErr);
394 break;
395 case DISP_E_PARAMNOTFOUND:
396 throw IllegalArgumentException("call to OLE object failed", static_cast<XInterface*>(
397 static_cast<XWeak*>(this)), ::sal::static_int_cast< sal_Int16, unsigned int >( uArgErr )) ;
398 break;
399 case DISP_E_TYPEMISMATCH:
400 throw CannotConvertException("call to OLE object failed", static_cast<XInterface*>(
401 static_cast<XWeak*>(this)), TypeClass_UNKNOWN, FailReason::UNKNOWN, ::sal::static_int_cast< sal_Int16, unsigned int >( uArgErr ));
402 break;
403 case DISP_E_UNKNOWNINTERFACE:
404 throw RuntimeException();
405 break;
406 case DISP_E_UNKNOWNLCID:
407 throw RuntimeException();
408 break;
409 case DISP_E_PARAMNOTOPTIONAL:
410 throw CannotConvertException("call to OLE object failed",static_cast<XInterface*>(
411 static_cast<XWeak*>(this)) , TypeClass_UNKNOWN, FailReason::NO_DEFAULT_AVAILABLE, uArgErr);
412 break;
413 default:
414 throw RuntimeException();
415 break;
418 catch (const CannotConvertException &)
420 throw;
422 catch (const UnknownPropertyException &)
424 throw;
426 catch (const BridgeRuntimeError& e)
428 throw RuntimeException(e.message);
430 catch (const Exception & e)
432 throw RuntimeException("[automation bridge] unexpected exception in "
433 "IUnknownWrapper_Impl::setValue ! Message : \n" +
434 e.Message);
437 catch (...)
439 throw RuntimeException(
440 "[automation bridge] unexpected exception in "
441 "IUnknownWrapper_Impl::setValue !");
445 Any SAL_CALL IUnknownWrapper_Impl::getValue( const OUString& aPropertyName )
447 if ( ! m_spDispatch )
449 throw RuntimeException(
450 "[automation bridge] The object does not have an IDispatch interface");
452 Any ret;
455 o2u_attachCurrentThread();
456 ITypeInfo * pInfo = getTypeInfo();
457 // I was going to implement an XServiceInfo interface to allow the type
458 // of the automation object to be exposed.. but it seems
459 // from looking at comments in the code that it is possible for
460 // this object to actually wrap an UNO object ( I guess if automation is
461 // used from MSO to create Openoffice objects ) Therefore, those objects
462 // will more than likely already have their own XServiceInfo interface.
463 // Instead here I chose a name that should be illegal both in COM and
464 // UNO ( from an IDL point of view ) therefore I think this is a safe
465 // hack
466 if ( aPropertyName == "$GetTypeName" )
468 if ( pInfo && m_sTypeName.getLength() == 0 )
470 m_sTypeName = "IDispatch";
471 CComBSTR sName;
473 if ( SUCCEEDED( pInfo->GetDocumentation( -1, &sName, nullptr, nullptr, nullptr ) ) )
475 OUString sTmp( reinterpret_cast<const sal_Unicode*>(LPCOLESTR(sName)));
476 if ( sTmp.startsWith("_") )
477 sTmp = sTmp.copy(1);
478 // do we own the memory for pTypeLib, msdn doc is vague
479 // I'll assume we do
480 CComPtr< ITypeLib > pTypeLib;
481 unsigned int index;
482 if ( SUCCEEDED( pInfo->GetContainingTypeLib( &pTypeLib.p, &index )) )
484 if ( SUCCEEDED( pTypeLib->GetDocumentation( -1, &sName, nullptr, nullptr, nullptr ) ) )
486 OUString sLibName( reinterpret_cast<const sal_Unicode*>(LPCOLESTR(sName)));
487 m_sTypeName = sLibName.concat( "." ).concat( sTmp );
494 ret <<= m_sTypeName;
495 return ret;
497 FuncDesc aDescGet(pInfo);
498 FuncDesc aDescPut(pInfo);
499 VarDesc aVarDesc(pInfo);
500 getPropDesc(aPropertyName, & aDescGet, & aDescPut, & aVarDesc);
501 if ( ! aDescGet && ! aDescPut && ! aVarDesc)
503 //property not found
504 OUString msg("[automation bridge]Property \"" + aPropertyName +
505 "\" is not supported");
506 throw UnknownPropertyException(msg);
508 // write-only should not be possible
509 OSL_ASSERT( aDescGet || ! aDescPut);
511 HRESULT hr;
512 DISPPARAMS dispparams = {nullptr, nullptr, 0, 0};
513 CComVariant varResult;
514 ExcepInfo excepinfo;
515 unsigned int uArgErr;
516 DISPID dispid;
517 if (aDescGet)
518 dispid = aDescGet->memid;
519 else if (aVarDesc)
520 dispid = aVarDesc->memid;
521 else
522 dispid = aDescPut->memid;
524 hr = m_spDispatch->Invoke(dispid,
525 IID_NULL,
526 LOCALE_USER_DEFAULT,
527 DISPATCH_PROPERTYGET,
528 &dispparams,
529 &varResult,
530 &excepinfo,
531 &uArgErr);
533 // converting return value and out parameter back to UNO
534 if (hr == S_OK)
536 // If the com object implements uno interfaces then we have
537 // to convert the attribute into the expected type.
538 TypeDescription attrInfo;
539 getAttributeInfo(aPropertyName, attrInfo);
540 if( attrInfo.is() )
541 variantToAny( &varResult, ret, Type( attrInfo.get()->pWeakRef));
542 else
543 variantToAny(&varResult, ret);
546 // lookup error code
547 switch (hr)
549 case S_OK:
550 break;
551 case DISP_E_BADPARAMCOUNT:
552 case DISP_E_BADVARTYPE:
553 case DISP_E_EXCEPTION:
554 throw RuntimeException(OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription)));
555 break;
556 case DISP_E_MEMBERNOTFOUND:
557 throw UnknownPropertyException(OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription)));
558 break;
559 default:
560 throw RuntimeException(OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription)));
561 break;
564 catch ( const UnknownPropertyException& )
566 throw;
568 catch (const BridgeRuntimeError& e)
570 throw RuntimeException(e.message);
572 catch (const Exception & e)
574 throw RuntimeException("[automation bridge] unexpected exception in "
575 "IUnknownWrapper_Impl::getValue ! Message : \n" +
576 e.Message);
578 catch (...)
580 throw RuntimeException(
581 "[automation bridge] unexpected exception in "
582 "IUnknownWrapper_Impl::getValue !");
584 return ret;
587 sal_Bool SAL_CALL IUnknownWrapper_Impl::hasMethod( const OUString& aName )
589 if ( ! m_spDispatch )
591 throw RuntimeException(
592 "[automation bridge] The object does not have an IDispatch interface");
594 bool ret = false;
598 o2u_attachCurrentThread();
599 ITypeInfo* pInfo = getTypeInfo();
600 FuncDesc aDesc(pInfo);
601 getFuncDesc(aName, & aDesc);
602 // Automation properties can have arguments. Those are treated as methods and
603 //are called through XInvocation::invoke.
604 if ( ! aDesc)
606 FuncDesc aDescGet(pInfo);
607 FuncDesc aDescPut(pInfo);
608 VarDesc aVarDesc(pInfo);
609 getPropDesc( aName, & aDescGet, & aDescPut, & aVarDesc);
610 if ((aDescGet && aDescGet->cParams > 0)
611 || (aDescPut && aDescPut->cParams > 0))
612 ret = true;
614 else
615 ret = true;
617 catch (const BridgeRuntimeError& e)
619 throw RuntimeException(e.message);
621 catch (const Exception & e)
623 throw RuntimeException("[automation bridge] unexpected exception in "
624 "IUnknownWrapper_Impl::hasMethod ! Message : \n" +
625 e.Message);
627 catch (...)
629 throw RuntimeException("[automation bridge] unexpected exception in "
630 "IUnknownWrapper_Impl::hasMethod !");
632 return ret;
635 sal_Bool SAL_CALL IUnknownWrapper_Impl::hasProperty( const OUString& aName )
637 if ( ! m_spDispatch )
639 throw RuntimeException("[automation bridge] The object does not have an "
640 "IDispatch interface");
642 bool ret = false;
645 o2u_attachCurrentThread();
647 ITypeInfo * pInfo = getTypeInfo();
648 FuncDesc aDescGet(pInfo);
649 FuncDesc aDescPut(pInfo);
650 VarDesc aVarDesc(pInfo);
651 getPropDesc(aName, & aDescGet, & aDescPut, & aVarDesc);
653 // we should probably just check the func kind
654 // basic has been modified to handle properties ( 'get' ) props at
655 // least with parameters
656 // additionally you can call invoke(Get|Set)Property on the bridge
657 // you can determine if a property has parameter is hasMethod
658 // returns true for the name
659 if (aVarDesc
660 || aDescPut
661 || aDescGet )
663 ret = true;
666 catch (const BridgeRuntimeError& e)
668 throw RuntimeException(e.message);
670 catch (const Exception & e)
672 throw RuntimeException("[automation bridge] unexpected exception in "
673 "IUnknownWrapper_Impl::hasProperty ! Message : \n" +
674 e.Message);
677 catch (...)
679 throw RuntimeException("[automation bridge] unexpected exception in "
680 "IUnknownWrapper_Impl::hasProperty !");
682 return ret;
685 Any SAL_CALL IUnknownWrapper_Impl::createBridge( const Any& modelDepObject,
686 const Sequence< sal_Int8 >& /*aProcessId*/, sal_Int16 sourceModelType,
687 sal_Int16 destModelType )
689 Any ret;
690 o2u_attachCurrentThread();
692 if (
693 (sourceModelType == UNO) &&
694 (destModelType == OLE) &&
695 (modelDepObject.getValueTypeClass() == TypeClass_INTERFACE)
698 Reference<XInterface> xInt( *static_cast<XInterface* const *>(modelDepObject.getValue()));
699 Reference<XInterface> xSelf( static_cast<OWeakObject*>(this));
701 if (xInt == xSelf)
703 VARIANT* pVariant = static_cast<VARIANT*>(CoTaskMemAlloc(sizeof(VARIANT)));
705 VariantInit(pVariant);
706 if (m_bOriginalDispatch)
708 pVariant->vt = VT_DISPATCH;
709 pVariant->pdispVal = m_spDispatch;
710 pVariant->pdispVal->AddRef();
712 else
714 pVariant->vt = VT_UNKNOWN;
715 pVariant->punkVal = m_spUnknown;
716 pVariant->punkVal->AddRef();
719 ret.setValue(static_cast<void*>(&pVariant), cppu::UnoType<sal_uIntPtr>::get());
723 return ret;
725 /** @internal
726 @exception IllegalArgumentException
727 @exception CannotConvertException
728 @exception InvocationTargetException
729 @RuntimeException
731 Any IUnknownWrapper_Impl::invokeWithDispIdUnoTlb(const OUString& sFunctionName,
732 const Sequence< Any >& Params,
733 Sequence< sal_Int16 >& OutParamIndex,
734 Sequence< Any >& OutParam)
736 Any ret;
737 HRESULT hr= S_OK;
739 sal_Int32 parameterCount= Params.getLength();
740 sal_Int32 outParameterCount= 0;
741 typelib_InterfaceMethodTypeDescription* pMethod= nullptr;
742 TypeDescription methodDesc;
743 getMethodInfo(sFunctionName, methodDesc);
745 // We need to know whether the IDispatch is from a JScript object.
746 // Then out and in/out parameters have to be treated differently than
747 // with common COM objects.
748 bool bJScriptObject= isJScriptObject();
749 std::unique_ptr<CComVariant[]> sarParams;
750 std::unique_ptr<CComVariant[]> sarParamsRef;
751 CComVariant *pVarParams= nullptr;
752 CComVariant *pVarParamsRef= nullptr;
753 bool bConvRet= true;
755 if( methodDesc.is())
757 pMethod = reinterpret_cast<typelib_InterfaceMethodTypeDescription*>(methodDesc.get());
758 parameterCount = pMethod->nParams;
759 // Create the Array for the array being passed in DISPPARAMS
760 // the array also contains the outparameter (but not the values)
761 if( pMethod->nParams > 0)
763 sarParams.reset(new CComVariant[ parameterCount]);
764 pVarParams = sarParams.get();
767 // Create the Array for the out an in/out parameter. These values
768 // are referenced by the VT_BYREF VARIANTs in DISPPARAMS.
769 // We need to find out the number of out and in/out parameter.
770 for( sal_Int32 i=0; i < parameterCount; i++)
772 if( pMethod->pParams[i].bOut)
773 outParameterCount++;
776 if( !bJScriptObject)
778 sarParamsRef.reset(new CComVariant[outParameterCount]);
779 pVarParamsRef = sarParamsRef.get();
780 // build up the parameters for IDispatch::Invoke
781 sal_Int32 outParamIndex=0;
782 int i = 0;
785 for( i= 0; i < parameterCount; i++)
787 // In parameter
788 if( pMethod->pParams[i].bIn && ! pMethod->pParams[i].bOut)
790 anyToVariant( &pVarParams[parameterCount - i -1], Params.getConstArray()[i]);
792 // Out parameter + in/out parameter
793 else if( pMethod->pParams[i].bOut )
795 CComVariant var;
796 if(pMethod->pParams[i].bIn)
798 anyToVariant( & var,Params[i]);
799 pVarParamsRef[outParamIndex] = var;
802 switch( pMethod->pParams[i].pTypeRef->eTypeClass)
804 case typelib_TypeClass_INTERFACE:
805 case typelib_TypeClass_STRUCT:
806 if( ! pMethod->pParams[i].bIn)
808 pVarParamsRef[ outParamIndex].vt= VT_DISPATCH;
809 pVarParamsRef[ outParamIndex].pdispVal= nullptr;
811 pVarParams[parameterCount - i -1].vt = VT_DISPATCH | VT_BYREF;
812 pVarParams[parameterCount - i -1].ppdispVal= &pVarParamsRef[outParamIndex].pdispVal;
813 break;
814 case typelib_TypeClass_ENUM:
815 case typelib_TypeClass_LONG:
816 case typelib_TypeClass_UNSIGNED_LONG:
817 if( ! pMethod->pParams[i].bIn)
819 pVarParamsRef[ outParamIndex].vt = VT_I4;
820 pVarParamsRef[ outParamIndex].lVal = 0;
822 pVarParams[parameterCount - i -1].vt = VT_I4 | VT_BYREF;
823 pVarParams[parameterCount - i -1].plVal= &pVarParamsRef[outParamIndex].lVal;
824 break;
825 case typelib_TypeClass_SEQUENCE:
826 if( ! pMethod->pParams[i].bIn)
828 pVarParamsRef[ outParamIndex].vt = VT_ARRAY| VT_VARIANT;
829 pVarParamsRef[ outParamIndex].parray= nullptr;
831 pVarParams[parameterCount - i -1].vt = VT_ARRAY| VT_BYREF | VT_VARIANT;
832 pVarParams[parameterCount - i -1].pparray= &pVarParamsRef[outParamIndex].parray;
833 break;
834 case typelib_TypeClass_ANY:
835 if( ! pMethod->pParams[i].bIn)
837 pVarParamsRef[ outParamIndex].vt = VT_EMPTY;
838 pVarParamsRef[ outParamIndex].lVal = 0;
840 pVarParams[parameterCount - i -1].vt = VT_VARIANT | VT_BYREF;
841 pVarParams[parameterCount - i -1].pvarVal = &pVarParamsRef[outParamIndex];
842 break;
843 case typelib_TypeClass_BOOLEAN:
844 if( ! pMethod->pParams[i].bIn)
846 pVarParamsRef[ outParamIndex].vt = VT_BOOL;
847 pVarParamsRef[ outParamIndex].boolVal = 0;
849 pVarParams[parameterCount - i -1].vt = VT_BOOL| VT_BYREF;
850 pVarParams[parameterCount - i -1].pboolVal =
851 & pVarParamsRef[outParamIndex].boolVal;
852 break;
854 case typelib_TypeClass_STRING:
855 if( ! pMethod->pParams[i].bIn)
857 pVarParamsRef[ outParamIndex].vt = VT_BSTR;
858 pVarParamsRef[ outParamIndex].bstrVal= nullptr;
860 pVarParams[parameterCount - i -1].vt = VT_BSTR| VT_BYREF;
861 pVarParams[parameterCount - i -1].pbstrVal=
862 & pVarParamsRef[outParamIndex].bstrVal;
863 break;
865 case typelib_TypeClass_FLOAT:
866 if( ! pMethod->pParams[i].bIn)
868 pVarParamsRef[ outParamIndex].vt = VT_R4;
869 pVarParamsRef[ outParamIndex].fltVal= 0;
871 pVarParams[parameterCount - i -1].vt = VT_R4| VT_BYREF;
872 pVarParams[parameterCount - i -1].pfltVal =
873 & pVarParamsRef[outParamIndex].fltVal;
874 break;
875 case typelib_TypeClass_DOUBLE:
876 if( ! pMethod->pParams[i].bIn)
878 pVarParamsRef[ outParamIndex].vt = VT_R8;
879 pVarParamsRef[ outParamIndex].dblVal= 0;
881 pVarParams[parameterCount - i -1].vt = VT_R8| VT_BYREF;
882 pVarParams[parameterCount - i -1].pdblVal=
883 & pVarParamsRef[outParamIndex].dblVal;
884 break;
885 case typelib_TypeClass_BYTE:
886 if( ! pMethod->pParams[i].bIn)
888 pVarParamsRef[ outParamIndex].vt = VT_UI1;
889 pVarParamsRef[ outParamIndex].bVal= 0;
891 pVarParams[parameterCount - i -1].vt = VT_UI1| VT_BYREF;
892 pVarParams[parameterCount - i -1].pbVal=
893 & pVarParamsRef[outParamIndex].bVal;
894 break;
895 case typelib_TypeClass_CHAR:
896 case typelib_TypeClass_SHORT:
897 case typelib_TypeClass_UNSIGNED_SHORT:
898 if( ! pMethod->pParams[i].bIn)
900 pVarParamsRef[ outParamIndex].vt = VT_I2;
901 pVarParamsRef[ outParamIndex].iVal = 0;
903 pVarParams[parameterCount - i -1].vt = VT_I2| VT_BYREF;
904 pVarParams[parameterCount - i -1].piVal=
905 & pVarParamsRef[outParamIndex].iVal;
906 break;
908 default:
909 if( ! pMethod->pParams[i].bIn)
911 pVarParamsRef[ outParamIndex].vt = VT_EMPTY;
912 pVarParamsRef[ outParamIndex].lVal = 0;
914 pVarParams[parameterCount - i -1].vt = VT_VARIANT | VT_BYREF;
915 pVarParams[parameterCount - i -1].pvarVal =
916 & pVarParamsRef[outParamIndex];
918 outParamIndex++;
919 } // end else if
920 } // end for
922 catch (IllegalArgumentException & e)
924 e.ArgumentPosition = ::sal::static_int_cast< sal_Int16, int >( i );
925 throw;
927 catch (CannotConvertException & e)
929 e.ArgumentIndex = i;
930 throw;
933 else // it is an JScriptObject
935 int i = 0;
938 for( ; i< parameterCount; i++)
940 // In parameter
941 if( pMethod->pParams[i].bIn && ! pMethod->pParams[i].bOut)
943 anyToVariant( &pVarParams[parameterCount - i -1], Params.getConstArray()[i]);
945 // Out parameter + in/out parameter
946 else if( pMethod->pParams[i].bOut )
948 CComObject<JScriptOutParam>* pParamObject;
949 if( SUCCEEDED( CComObject<JScriptOutParam>::CreateInstance( &pParamObject)))
951 CComPtr<IUnknown> pUnk(pParamObject->GetUnknown());
952 CComQIPtr<IDispatch> pDisp( pUnk);
954 pVarParams[ parameterCount - i -1].vt= VT_DISPATCH;
955 pVarParams[ parameterCount - i -1].pdispVal= pDisp;
956 pVarParams[ parameterCount - i -1].pdispVal->AddRef();
957 // if the param is in/out then put the parameter on index 0
958 if( pMethod->pParams[i].bIn ) // in / out
960 CComVariant varParam;
961 anyToVariant( &varParam, Params.getConstArray()[i]);
962 CComDispatchDriver dispDriver( pDisp);
963 if(FAILED( dispDriver.PutPropertyByName( L"0", &varParam)))
964 throw BridgeRuntimeError(
965 "[automation bridge]IUnknownWrapper_Impl::"
966 "invokeWithDispIdUnoTlb\n"
967 "Could not set property \"0\" for the in/out "
968 "param!");
972 else
974 throw BridgeRuntimeError(
975 "[automation bridge]IUnknownWrapper_Impl::"
976 "invokeWithDispIdUnoTlb\n"
977 "Could not create out parameter at index: " +
978 OUString::number((sal_Int32) i));
984 catch (IllegalArgumentException & e)
986 e.ArgumentPosition = ::sal::static_int_cast< sal_Int16, int >( i );
987 throw;
989 catch (CannotConvertException & e)
991 e.ArgumentIndex = i;
992 throw;
996 // No type description Available, that is we have to deal with a COM component,
997 // that does not implements UNO interfaces ( IDispatch based)
998 else
1000 //We should not run into this block, because invokeWithDispIdComTlb should
1001 //have been called instead.
1002 OSL_ASSERT(false);
1006 CComVariant varResult;
1007 ExcepInfo excepinfo;
1008 unsigned int uArgErr;
1009 DISPPARAMS dispparams= { pVarParams, nullptr, static_cast<UINT>(parameterCount), 0};
1011 // Get the DISPID
1012 FuncDesc aDesc(getTypeInfo());
1013 getFuncDesc(sFunctionName, & aDesc);
1014 // invoking OLE method
1015 hr = m_spDispatch->Invoke(aDesc->memid,
1016 IID_NULL,
1017 LOCALE_USER_DEFAULT,
1018 DISPATCH_METHOD,
1019 &dispparams,
1020 &varResult,
1021 &excepinfo,
1022 &uArgErr);
1024 // converting return value and out parameter back to UNO
1025 if (hr == S_OK)
1027 if( outParameterCount && pMethod)
1029 OutParamIndex.realloc( outParameterCount);
1030 OutParam.realloc( outParameterCount);
1031 sal_Int32 outIndex=0;
1032 int i = 0;
1035 for( ; i < parameterCount; i++)
1037 if( pMethod->pParams[i].bOut )
1039 OutParamIndex[outIndex]= (sal_Int16) i;
1040 Any outAny;
1041 if( !bJScriptObject)
1043 variantToAny( &pVarParamsRef[outIndex], outAny,
1044 Type(pMethod->pParams[i].pTypeRef), false);
1045 OutParam[outIndex++]= outAny;
1047 else //JScriptObject
1049 if( pVarParams[i].vt == VT_DISPATCH)
1051 CComDispatchDriver pDisp( pVarParams[i].pdispVal);
1052 if( pDisp)
1054 CComVariant varOut;
1055 if( SUCCEEDED( pDisp.GetPropertyByName( L"0", &varOut)))
1057 variantToAny( &varOut, outAny,
1058 Type(pMethod->pParams[parameterCount - 1 - i].pTypeRef), false);
1059 OutParam[outParameterCount - 1 - outIndex++]= outAny;
1061 else
1062 bConvRet= false;
1064 else
1065 bConvRet= false;
1067 else
1068 bConvRet= false;
1071 if( !bConvRet) break;
1074 catch(IllegalArgumentException & e)
1076 e.ArgumentPosition = ::sal::static_int_cast< sal_Int16, int >( i );
1077 throw;
1079 catch(CannotConvertException & e)
1081 e.ArgumentIndex = i;
1082 throw;
1085 // return value, no type information available
1086 if ( bConvRet)
1090 if( pMethod )
1091 variantToAny(&varResult, ret, Type( pMethod->pReturnTypeRef), false);
1092 else
1093 variantToAny(&varResult, ret, false);
1095 catch (IllegalArgumentException & e)
1097 e.Message =
1098 "[automation bridge]IUnknownWrapper_Impl::invokeWithDispIdUnoTlb\n"
1099 "Could not convert return value! \n Message: \n" + e.Message;
1100 throw;
1102 catch (CannotConvertException & e)
1104 e.Message =
1105 "[automation bridge]IUnknownWrapper_Impl::invokeWithDispIdUnoTlb\n"
1106 "Could not convert return value! \n Message: \n" + e.Message;
1107 throw;
1112 if( !bConvRet) // conversion of return or out parameter failed
1113 throw CannotConvertException("Call to COM object failed. Conversion of return or out value failed",
1114 Reference<XInterface>( static_cast<XWeak*>(this), UNO_QUERY ), TypeClass_UNKNOWN,
1115 FailReason::UNKNOWN, 0);// lookup error code
1116 // conversion of return or out parameter failed
1117 switch (hr)
1119 case S_OK:
1120 break;
1121 case DISP_E_BADPARAMCOUNT:
1122 throw IllegalArgumentException();
1123 break;
1124 case DISP_E_BADVARTYPE:
1125 throw RuntimeException();
1126 break;
1127 case DISP_E_EXCEPTION:
1128 throw InvocationTargetException();
1129 break;
1130 case DISP_E_MEMBERNOTFOUND:
1131 throw IllegalArgumentException();
1132 break;
1133 case DISP_E_NONAMEDARGS:
1134 throw IllegalArgumentException();
1135 break;
1136 case DISP_E_OVERFLOW:
1137 throw CannotConvertException("call to OLE object failed", static_cast<XInterface*>(
1138 static_cast<XWeak*>(this)), TypeClass_UNKNOWN, FailReason::OUT_OF_RANGE, uArgErr);
1139 break;
1140 case DISP_E_PARAMNOTFOUND:
1141 throw IllegalArgumentException("call to OLE object failed", static_cast<XInterface*>(
1142 static_cast<XWeak*>(this)), ::sal::static_int_cast< sal_Int16, unsigned int >( uArgErr ));
1143 break;
1144 case DISP_E_TYPEMISMATCH:
1145 throw CannotConvertException("call to OLE object failed",static_cast<XInterface*>(
1146 static_cast<XWeak*>(this)) , TypeClass_UNKNOWN, FailReason::UNKNOWN, uArgErr);
1147 break;
1148 case DISP_E_UNKNOWNINTERFACE:
1149 throw RuntimeException() ;
1150 break;
1151 case DISP_E_UNKNOWNLCID:
1152 throw RuntimeException() ;
1153 break;
1154 case DISP_E_PARAMNOTOPTIONAL:
1155 throw CannotConvertException("call to OLE object failed", static_cast<XInterface*>(
1156 static_cast<XWeak*>(this)), TypeClass_UNKNOWN, FailReason::NO_DEFAULT_AVAILABLE, uArgErr);
1157 break;
1158 default:
1159 throw RuntimeException();
1160 break;
1163 return ret;
1167 // XInitialization
1168 void SAL_CALL IUnknownWrapper_Impl::initialize( const Sequence< Any >& aArguments )
1170 // 1.parameter is IUnknown
1171 // 2.parameter is a boolean which indicates if the COM pointer was a IUnknown or IDispatch
1172 // 3.parameter is a Sequence<Type>
1173 o2u_attachCurrentThread();
1174 OSL_ASSERT(aArguments.getLength() == 3);
1176 m_spUnknown= *static_cast<IUnknown* const *>(aArguments[0].getValue());
1177 m_spUnknown.QueryInterface( & m_spDispatch.p);
1179 aArguments[1] >>= m_bOriginalDispatch;
1180 aArguments[2] >>= m_seqTypes;
1182 ITypeInfo* pType = nullptr;
1185 // a COM object implementation that has no TypeInfo is still a legal COM object;
1186 // such objects can at least be transported through UNO using the bridge
1187 // so we should allow to create wrappers for them as well
1188 pType = getTypeInfo();
1190 catch( const BridgeRuntimeError& )
1192 catch( const Exception& )
1195 if ( pType )
1199 // Get Default member
1200 CComBSTR defaultMemberName;
1201 if ( SUCCEEDED( pType->GetDocumentation(0, &defaultMemberName, nullptr, nullptr, nullptr ) ) )
1203 OUString usName(reinterpret_cast<const sal_Unicode*>(LPCOLESTR(defaultMemberName)));
1204 FuncDesc aDescGet(pType);
1205 FuncDesc aDescPut(pType);
1206 VarDesc aVarDesc(pType);
1207 // see if this is a property first ( more likely to be a property then a method )
1208 getPropDesc( usName, & aDescGet, & aDescPut, & aVarDesc);
1210 if ( !aDescGet && !aDescPut )
1212 getFuncDesc( usName, &aDescGet );
1213 if ( !aDescGet )
1214 throw BridgeRuntimeError( "[automation bridge]IUnknownWrapper_Impl::initialize() Failed to get Function or Property desc. for " + usName );
1216 // now for some funny heuristics to make basic understand what to do
1217 // a single aDescGet ( that doesn't take any params ) would be
1218 // a read only ( defaultmember ) property e.g. this object
1219 // should implement XDefaultProperty
1220 // a single aDescGet ( that *does* ) take params is basically a
1221 // default method e.g. implement XDefaultMethod
1223 // 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 )
1224 if ( aDescPut || ( aDescGet && aDescGet->cParams == 0 ) )
1225 m_bHasDfltProperty = true;
1226 if ( aDescGet->cParams > 0 )
1227 m_bHasDfltMethod = true;
1228 if ( m_bHasDfltProperty || m_bHasDfltMethod )
1229 m_sDefaultMember = usName;
1232 catch ( const BridgeRuntimeError & e )
1234 throw RuntimeException( e.message );
1236 catch( const Exception& e )
1238 throw RuntimeException(
1239 "[automation bridge] unexpected exception in IUnknownWrapper_Impl::initialize() error message: \n" + e.Message );
1245 // XDirectInvocation
1246 uno::Any SAL_CALL IUnknownWrapper_Impl::directInvoke( const OUString& aName, const uno::Sequence< uno::Any >& aParams )
1248 Any aResult;
1250 if ( !m_spDispatch )
1252 throw RuntimeException(
1253 "[automation bridge] The object does not have an IDispatch interface");
1256 o2u_attachCurrentThread();
1257 DISPID dispid;
1258 if ( !getDispid( aName, &dispid ) )
1259 throw IllegalArgumentException(
1260 "[automation bridge] The object does not have a function or property "
1261 + aName, Reference<XInterface>(), 0);
1263 CComVariant varResult;
1264 ExcepInfo excepinfo;
1265 unsigned int uArgErr = 0;
1266 INVOKEKIND pInvkinds[2];
1267 pInvkinds[0] = INVOKE_FUNC;
1268 pInvkinds[1] = aParams.getLength() ? INVOKE_PROPERTYPUT : INVOKE_PROPERTYGET;
1269 HRESULT hInvRes = E_FAIL;
1271 // try Invoke first, if it does not work, try put/get property
1272 for ( sal_Int32 nStep = 0; FAILED( hInvRes ) && nStep < 2; nStep++ )
1274 DISPPARAMS dispparams = {nullptr, nullptr, 0, 0};
1276 std::unique_ptr<DISPID[]> arDispidNamedArgs;
1277 std::unique_ptr<CComVariant[]> ptrArgs;
1278 std::unique_ptr<CComVariant[]> ptrRefArgs; // referenced arguments
1279 CComVariant * arArgs = nullptr;
1280 CComVariant * arRefArgs = nullptr;
1282 dispparams.cArgs = aParams.getLength();
1284 // Determine the number of named arguments
1285 for ( sal_Int32 nInd = 0; nInd < aParams.getLength(); nInd++ )
1286 if ( aParams[nInd].getValueType() == cppu::UnoType<NamedArgument>::get() )
1287 dispparams.cNamedArgs ++;
1289 // fill the named arguments
1290 if ( dispparams.cNamedArgs > 0
1291 && !( dispparams.cNamedArgs == 1 && pInvkinds[nStep] == INVOKE_PROPERTYPUT ) )
1293 int nSizeAr = dispparams.cNamedArgs + 1;
1294 if ( pInvkinds[nStep] == INVOKE_PROPERTYPUT )
1295 nSizeAr = dispparams.cNamedArgs;
1297 std::unique_ptr<OLECHAR*[]> saNames(new OLECHAR*[nSizeAr]);
1298 OLECHAR ** pNames = saNames.get();
1299 pNames[0] = const_cast<OLECHAR*>(reinterpret_cast<LPCOLESTR>(aName.getStr()));
1301 int cNamedArg = 0;
1302 for ( size_t nInd = 0; nInd < dispparams.cArgs; nInd++ )
1304 if (auto v = o3tl::tryAccess<NamedArgument>(aParams[nInd]))
1306 const NamedArgument& arg = *v;
1308 //We put the parameter names in reverse order into the array,
1309 //so we can use the DISPID array for DISPPARAMS::rgdispidNamedArgs
1310 //The first name in the array is the method name
1311 pNames[nSizeAr - 1 - cNamedArg++] = const_cast<OLECHAR*>(reinterpret_cast<LPCOLESTR>(arg.Name.getStr()));
1315 arDispidNamedArgs.reset( new DISPID[nSizeAr] );
1316 HRESULT hr = getTypeInfo()->GetIDsOfNames( pNames, nSizeAr, arDispidNamedArgs.get() );
1317 if ( hr == E_NOTIMPL )
1318 hr = m_spDispatch->GetIDsOfNames(IID_NULL, pNames, nSizeAr, LOCALE_USER_DEFAULT, arDispidNamedArgs.get() );
1320 if ( SUCCEEDED( hr ) )
1322 if ( pInvkinds[nStep] == DISPATCH_PROPERTYPUT )
1324 DISPID* arIDs = arDispidNamedArgs.get();
1325 arIDs[0] = DISPID_PROPERTYPUT;
1326 dispparams.rgdispidNamedArgs = arIDs;
1328 else
1330 DISPID* arIDs = arDispidNamedArgs.get();
1331 dispparams.rgdispidNamedArgs = & arIDs[1];
1334 else if (hr == DISP_E_UNKNOWNNAME)
1336 throw IllegalArgumentException(
1337 "[automation bridge]One of the named arguments is wrong!",
1338 Reference<XInterface>(), 0);
1340 else
1342 throw InvocationTargetException(
1343 "[automation bridge] ITypeInfo::GetIDsOfNames returned error "
1344 + OUString::number((sal_Int32) hr, 16), Reference<XInterface>(), Any());
1348 //Convert arguments
1349 ptrArgs.reset(new CComVariant[dispparams.cArgs]);
1350 ptrRefArgs.reset(new CComVariant[dispparams.cArgs]);
1351 arArgs = ptrArgs.get();
1352 arRefArgs = ptrRefArgs.get();
1354 sal_Int32 nInd = 0;
1357 sal_Int32 revIndex = 0;
1358 for ( nInd = 0; nInd < sal_Int32(dispparams.cArgs); nInd++)
1360 revIndex = dispparams.cArgs - nInd - 1;
1361 arRefArgs[revIndex].byref = nullptr;
1362 Any anyArg;
1363 if ( nInd < aParams.getLength() )
1364 anyArg = aParams.getConstArray()[nInd];
1366 // Property Put arguments
1367 if ( anyArg.getValueType() == cppu::UnoType<PropertyPutArgument>::get() )
1369 PropertyPutArgument arg;
1370 anyArg >>= arg;
1371 anyArg = arg.Value;
1373 // named argument
1374 if (anyArg.getValueType() == cppu::UnoType<NamedArgument>::get())
1376 NamedArgument aNamedArgument;
1377 anyArg >>= aNamedArgument;
1378 anyArg = aNamedArgument.Value;
1381 if ( nInd < aParams.getLength() && anyArg.getValueTypeClass() != TypeClass_VOID )
1383 anyToVariant( &arArgs[revIndex], anyArg, VT_VARIANT );
1385 else
1387 arArgs[revIndex].vt = VT_ERROR;
1388 arArgs[revIndex].scode = DISP_E_PARAMNOTFOUND;
1392 catch (IllegalArgumentException & e)
1394 e.ArgumentPosition = ::sal::static_int_cast< sal_Int16, sal_Int32 >( nInd );
1395 throw;
1397 catch (CannotConvertException & e)
1399 e.ArgumentIndex = nInd;
1400 throw;
1403 dispparams.rgvarg = arArgs;
1404 // invoking OLE method
1405 DWORD localeId = LOCALE_USER_DEFAULT;
1406 hInvRes = m_spDispatch->Invoke( dispid,
1407 IID_NULL,
1408 localeId,
1409 ::sal::static_int_cast< WORD, INVOKEKIND >( pInvkinds[nStep] ),
1410 &dispparams,
1411 &varResult,
1412 &excepinfo,
1413 &uArgErr);
1416 // converting return value and out parameter back to UNO
1417 if ( SUCCEEDED( hInvRes ) )
1418 variantToAny( &varResult, aResult, false );
1419 else
1421 // map error codes to exceptions
1422 OUString message;
1423 switch ( hInvRes )
1425 case S_OK:
1426 break;
1427 case DISP_E_BADPARAMCOUNT:
1428 throw IllegalArgumentException("[automation bridge] Wrong "
1429 "number of arguments. Object returned DISP_E_BADPARAMCOUNT.",
1430 nullptr, 0);
1431 break;
1432 case DISP_E_BADVARTYPE:
1433 throw RuntimeException("[automation bridge] One or more "
1434 "arguments have the wrong type. Object returned "
1435 "DISP_E_BADVARTYPE.", nullptr);
1436 break;
1437 case DISP_E_EXCEPTION:
1438 message = "[automation bridge]: ";
1439 message += OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription),
1440 ::SysStringLen(excepinfo.bstrDescription));
1441 throw InvocationTargetException(message, Reference<XInterface>(), Any());
1442 break;
1443 case DISP_E_MEMBERNOTFOUND:
1444 message = "[automation bridge]: A function with the name \""
1445 + aName + "\" is not supported. Object returned "
1446 "DISP_E_MEMBERNOTFOUND.";
1447 throw IllegalArgumentException(message, nullptr, 0);
1448 break;
1449 case DISP_E_NONAMEDARGS:
1450 throw IllegalArgumentException("[automation bridge] Object "
1451 "returned DISP_E_NONAMEDARGS",nullptr, ::sal::static_int_cast< sal_Int16, unsigned int >( uArgErr ));
1452 break;
1453 case DISP_E_OVERFLOW:
1454 throw CannotConvertException("[automation bridge] Call failed.",
1455 static_cast<XInterface*>(
1456 static_cast<XWeak*>(this)), TypeClass_UNKNOWN, FailReason::OUT_OF_RANGE, uArgErr);
1457 break;
1458 case DISP_E_PARAMNOTFOUND:
1459 throw IllegalArgumentException("[automation bridge]Call failed."
1460 "Object returned DISP_E_PARAMNOTFOUND.",
1461 nullptr, ::sal::static_int_cast< sal_Int16, unsigned int >( uArgErr ));
1462 break;
1463 case DISP_E_TYPEMISMATCH:
1464 throw CannotConvertException("[automation bridge] Call failed. "
1465 "Object returned DISP_E_TYPEMISMATCH",
1466 static_cast<XInterface*>(
1467 static_cast<XWeak*>(this)) , TypeClass_UNKNOWN, FailReason::UNKNOWN, uArgErr);
1468 break;
1469 case DISP_E_UNKNOWNINTERFACE:
1470 throw RuntimeException("[automation bridge] Call failed. "
1471 "Object returned DISP_E_UNKNOWNINTERFACE.",nullptr);
1472 break;
1473 case DISP_E_UNKNOWNLCID:
1474 throw RuntimeException("[automation bridge] Call failed. "
1475 "Object returned DISP_E_UNKNOWNLCID.",nullptr);
1476 break;
1477 case DISP_E_PARAMNOTOPTIONAL:
1478 throw CannotConvertException("[automation bridge] Call failed."
1479 "Object returned DISP_E_PARAMNOTOPTIONAL",
1480 static_cast<XInterface*>(static_cast<XWeak*>(this)),
1481 TypeClass_UNKNOWN, FailReason::NO_DEFAULT_AVAILABLE, uArgErr);
1482 break;
1483 default:
1484 throw RuntimeException();
1485 break;
1489 return aResult;
1492 sal_Bool SAL_CALL IUnknownWrapper_Impl::hasMember( const OUString& aName )
1494 if ( ! m_spDispatch )
1496 throw RuntimeException(
1497 "[automation bridge] The object does not have an IDispatch interface");
1500 o2u_attachCurrentThread();
1501 DISPID dispid;
1502 return getDispid( aName, &dispid );
1506 // UnoConversionUtilities --------------------------------------------------------------------------------
1507 Reference< XInterface > IUnknownWrapper_Impl::createUnoWrapperInstance()
1509 if( m_nUnoWrapperClass == INTERFACE_OLE_WRAPPER_IMPL)
1511 Reference<XWeak> xWeak= static_cast<XWeak*>( new InterfaceOleWrapper_Impl(
1512 m_smgr, m_nUnoWrapperClass, m_nComWrapperClass));
1513 return Reference<XInterface>( xWeak, UNO_QUERY);
1515 else if( m_nUnoWrapperClass == UNO_OBJECT_WRAPPER_REMOTE_OPT)
1517 Reference<XWeak> xWeak= static_cast<XWeak*>( new UnoObjectWrapperRemoteOpt(
1518 m_smgr, m_nUnoWrapperClass, m_nComWrapperClass));
1519 return Reference<XInterface>( xWeak, UNO_QUERY);
1521 else
1522 return Reference<XInterface>();
1524 Reference<XInterface> IUnknownWrapper_Impl::createComWrapperInstance()
1526 Reference<XWeak> xWeak= static_cast<XWeak*>( new IUnknownWrapper_Impl(
1527 m_smgr, m_nUnoWrapperClass, m_nComWrapperClass));
1528 return Reference<XInterface>( xWeak, UNO_QUERY);
1532 void IUnknownWrapper_Impl::getMethodInfo(const OUString& sName, TypeDescription& methodInfo)
1534 TypeDescription desc= getInterfaceMemberDescOfCurrentCall(sName);
1535 if( desc.is())
1537 typelib_TypeDescription* pMember= desc.get();
1538 if( pMember->eTypeClass == typelib_TypeClass_INTERFACE_METHOD )
1539 methodInfo= pMember;
1543 void IUnknownWrapper_Impl::getAttributeInfo(const OUString& sName, TypeDescription& attributeInfo)
1545 TypeDescription desc= getInterfaceMemberDescOfCurrentCall(sName);
1546 if( desc.is())
1548 typelib_TypeDescription* pMember= desc.get();
1549 if( pMember->eTypeClass == typelib_TypeClass_INTERFACE_ATTRIBUTE )
1551 attributeInfo= reinterpret_cast<typelib_InterfaceAttributeTypeDescription*>(pMember)->pAttributeTypeRef;
1555 TypeDescription IUnknownWrapper_Impl::getInterfaceMemberDescOfCurrentCall(const OUString& sName)
1557 TypeDescription ret;
1559 for( sal_Int32 i=0; i < m_seqTypes.getLength(); i++)
1561 TypeDescription _curDesc( m_seqTypes[i]);
1562 _curDesc.makeComplete();
1563 typelib_InterfaceTypeDescription * pInterface= reinterpret_cast<typelib_InterfaceTypeDescription*>(_curDesc.get());
1564 if( pInterface)
1566 typelib_InterfaceMemberTypeDescription* pMember= nullptr;
1567 //find the member description of the current call
1568 for( int j=0; j < pInterface->nAllMembers; j++)
1570 typelib_TypeDescriptionReference* pTypeRefMember = pInterface->ppAllMembers[j];
1571 typelib_TypeDescription* pDescMember= nullptr;
1572 TYPELIB_DANGER_GET( &pDescMember, pTypeRefMember);
1574 typelib_InterfaceMemberTypeDescription* pInterfaceMember=
1575 reinterpret_cast<typelib_InterfaceMemberTypeDescription*>(pDescMember);
1576 if( OUString( pInterfaceMember->pMemberName) == sName)
1578 pMember= pInterfaceMember;
1579 break;
1581 TYPELIB_DANGER_RELEASE( pDescMember);
1584 if( pMember)
1586 ret= &pMember->aBase;
1587 TYPELIB_DANGER_RELEASE( &pMember->aBase);
1590 if( ret.is())
1591 break;
1593 return ret;
1596 bool IUnknownWrapper_Impl::isJScriptObject()
1598 if( m_eJScript == JScriptUndefined)
1600 CComDispatchDriver disp( m_spDispatch);
1601 if( disp)
1603 CComVariant result;
1604 if( SUCCEEDED( disp.GetPropertyByName( JSCRIPT_ID_PROPERTY, &result)))
1606 if(result.vt == VT_BSTR)
1608 CComBSTR name( result.bstrVal);
1609 name.ToLower();
1610 if( name == CComBSTR(JSCRIPT_ID))
1611 m_eJScript= IsJScript;
1615 if( m_eJScript == JScriptUndefined)
1616 m_eJScript= NoJScript;
1619 return m_eJScript != NoJScript;
1623 /** @internal
1624 The function ultimately calls IDispatch::Invoke on the wrapped COM object.
1625 The COM object does not implement UNO Interfaces ( via IDispatch). This
1626 is the case when the OleObjectFactory service has been used to create a
1627 component.
1628 @exception IllegalArgumentException
1629 @exception CannotConvertException
1630 @InvocationTargetException
1631 @RuntimeException
1632 @BridgeRuntimeError
1634 Any IUnknownWrapper_Impl::invokeWithDispIdComTlb(const OUString& sFuncName,
1635 const Sequence< Any >& Params,
1636 Sequence< sal_Int16 >& OutParamIndex,
1637 Sequence< Any >& OutParam)
1639 // Get type info for the call. It can be a method call or property put or
1640 // property get operation.
1641 FuncDesc aFuncDesc(getTypeInfo());
1642 getFuncDescForInvoke(sFuncName, Params, & aFuncDesc);
1643 return invokeWithDispIdComTlb( aFuncDesc, sFuncName, Params, OutParamIndex, OutParam );
1646 Any IUnknownWrapper_Impl::invokeWithDispIdComTlb(FuncDesc& aFuncDesc,
1647 const OUString& sFuncName,
1648 const Sequence< Any >& Params,
1649 Sequence< sal_Int16 >& OutParamIndex,
1650 Sequence< Any >& OutParam)
1652 Any ret;
1653 HRESULT result;
1655 DISPPARAMS dispparams = {nullptr, nullptr, 0, 0};
1656 CComVariant varResult;
1657 ExcepInfo excepinfo;
1658 unsigned int uArgErr;
1659 sal_Int32 i = 0;
1660 sal_Int32 nUnoArgs = Params.getLength();
1661 DISPID idPropertyPut = DISPID_PROPERTYPUT;
1662 std::unique_ptr<DISPID[]> arDispidNamedArgs;
1663 std::unique_ptr<CComVariant[]> ptrArgs;
1664 std::unique_ptr<CComVariant[]> ptrRefArgs; // referenced arguments
1665 CComVariant * arArgs = nullptr;
1666 CComVariant * arRefArgs = nullptr;
1667 sal_Int32 revIndex = 0;
1669 //Set the array of DISPIDs for named args if it is a property put operation.
1670 //If there are other named arguments another array is set later on.
1671 if (aFuncDesc->invkind == INVOKE_PROPERTYPUT
1672 || aFuncDesc->invkind == INVOKE_PROPERTYPUTREF)
1673 dispparams.rgdispidNamedArgs = & idPropertyPut;
1675 //Determine the number of named arguments
1676 for (int iParam = 0; iParam < nUnoArgs; iParam ++)
1678 const Any & curArg = Params[iParam];
1679 if (curArg.getValueType() == cppu::UnoType<NamedArgument>::get())
1680 dispparams.cNamedArgs ++;
1682 //In a property put operation a property value is a named argument (DISPID_PROPERTYPUT).
1683 //Therefore the number of named arguments is increased by one.
1684 //Although named, the argument is not named in an actual language, such as Basic,
1685 //therefore it is never a com.sun.star.bridge.oleautomation.NamedArgument
1686 if (aFuncDesc->invkind == DISPATCH_PROPERTYPUT
1687 || aFuncDesc->invkind == DISPATCH_PROPERTYPUTREF)
1688 dispparams.cNamedArgs ++;
1690 //Determine the number of all arguments and named arguments
1691 if (aFuncDesc->cParamsOpt == -1)
1693 //Attribute vararg is set on this method. "Unlimited" number of args
1694 //supported. There can be no optional or defaultvalue on any of the arguments.
1695 dispparams.cArgs = nUnoArgs;
1697 else
1699 //If there are named arguments, then the dispparams.cArgs
1700 //is the number of supplied args, otherwise it is the expected number.
1701 if (dispparams.cNamedArgs)
1702 dispparams.cArgs = nUnoArgs;
1703 else
1704 dispparams.cArgs = aFuncDesc->cParams;
1707 //check if there are not to many arguments supplied
1708 if (::sal::static_int_cast< sal_uInt32, int >( nUnoArgs ) > dispparams.cArgs)
1710 OUStringBuffer buf(256);
1711 buf.append("[automation bridge] There are too many arguments for this method");
1712 throw IllegalArgumentException( buf.makeStringAndClear(),
1713 Reference<XInterface>(), (sal_Int16) dispparams.cArgs);
1716 //Set up the array of DISPIDs (DISPPARAMS::rgdispidNamedArgs)
1717 //for the named arguments.
1718 //If there is only one named arg and if it is because of a property put
1719 //operation, then we need not set up the DISPID array.
1720 if (dispparams.cNamedArgs > 0 &&
1721 ! (dispparams.cNamedArgs == 1 &&
1722 (aFuncDesc->invkind == INVOKE_PROPERTYPUT ||
1723 aFuncDesc->invkind == INVOKE_PROPERTYPUTREF)))
1725 //set up an array containing the member and parameter names
1726 //which is then used in ITypeInfo::GetIDsOfNames
1727 //First determine the size of the array of names which is passed to
1728 //ITypeInfo::GetIDsOfNames. It must hold the method names + the named
1729 //args.
1730 int nSizeAr = dispparams.cNamedArgs + 1;
1731 if (aFuncDesc->invkind == INVOKE_PROPERTYPUT
1732 || aFuncDesc->invkind == INVOKE_PROPERTYPUTREF)
1734 nSizeAr = dispparams.cNamedArgs; //counts the DISID_PROPERTYPUT
1737 std::unique_ptr<OLECHAR*[]> saNames(new OLECHAR*[nSizeAr]);
1738 OLECHAR ** arNames = saNames.get();
1739 arNames[0] = const_cast<OLECHAR*>(reinterpret_cast<LPCOLESTR>(sFuncName.getStr()));
1741 int cNamedArg = 0;
1742 for (size_t iParams = 0; iParams < dispparams.cArgs; iParams ++)
1744 const Any & curArg = Params[iParams];
1745 if (auto v = o3tl::tryAccess<NamedArgument>(curArg))
1747 const NamedArgument& arg = *v;
1748 //We put the parameter names in reverse order into the array,
1749 //so we can use the DISPID array for DISPPARAMS::rgdispidNamedArgs
1750 //The first name in the array is the method name
1751 arNames[nSizeAr - 1 - cNamedArg++] = const_cast<OLECHAR*>(reinterpret_cast<LPCOLESTR>(arg.Name.getStr()));
1755 //Prepare the array of DISPIDs for ITypeInfo::GetIDsOfNames
1756 //it must be big enough to contain the DISPIDs of the member + parameters
1757 arDispidNamedArgs.reset(new DISPID[nSizeAr]);
1758 HRESULT hr = getTypeInfo()->GetIDsOfNames(arNames, nSizeAr,
1759 arDispidNamedArgs.get());
1760 if ( hr == E_NOTIMPL )
1761 hr = m_spDispatch->GetIDsOfNames(IID_NULL, arNames, nSizeAr, LOCALE_USER_DEFAULT, arDispidNamedArgs.get() );
1763 if (hr == S_OK)
1765 // In a "property put" operation, the property value is a named param with the
1766 //special DISPID DISPID_PROPERTYPUT
1767 if (aFuncDesc->invkind == DISPATCH_PROPERTYPUT
1768 || aFuncDesc->invkind == DISPATCH_PROPERTYPUTREF)
1770 //Element at index 0 in the DISPID array must be DISPID_PROPERTYPUT
1771 //The first item in the array arDispidNamedArgs is the DISPID for
1772 //the method. We replace it with DISPID_PROPERTYPUT.
1773 DISPID* arIDs = arDispidNamedArgs.get();
1774 arIDs[0] = DISPID_PROPERTYPUT;
1775 dispparams.rgdispidNamedArgs = arIDs;
1777 else
1779 //The first item in the array arDispidNamedArgs is the DISPID for
1780 //the method. It must be removed
1781 DISPID* arIDs = arDispidNamedArgs.get();
1782 dispparams.rgdispidNamedArgs = & arIDs[1];
1785 else if (hr == DISP_E_UNKNOWNNAME)
1787 throw IllegalArgumentException(
1788 "[automation bridge]One of the named arguments is wrong!",
1789 Reference<XInterface>(), 0);
1791 else
1793 throw InvocationTargetException(
1794 "[automation bridge] ITypeInfo::GetIDsOfNames returned error "
1795 + OUString::number((sal_Int32) hr, 16), Reference<XInterface>(), Any());
1799 //Convert arguments
1800 ptrArgs.reset(new CComVariant[dispparams.cArgs]);
1801 ptrRefArgs.reset(new CComVariant[dispparams.cArgs]);
1802 arArgs = ptrArgs.get();
1803 arRefArgs = ptrRefArgs.get();
1806 for (i = 0; i < (sal_Int32) dispparams.cArgs; i++)
1808 revIndex= dispparams.cArgs - i -1;
1809 arRefArgs[revIndex].byref=nullptr;
1810 Any anyArg;
1811 if ( i < nUnoArgs)
1812 anyArg= Params.getConstArray()[i];
1814 unsigned short paramFlags = PARAMFLAG_FOPT | PARAMFLAG_FIN;
1815 VARTYPE varType = VT_VARIANT;
1816 if (aFuncDesc->cParamsOpt != -1 || aFuncDesc->cParams != (i + 1))
1818 paramFlags = aFuncDesc->lprgelemdescParam[i].paramdesc.wParamFlags;
1819 varType = getElementTypeDesc(&aFuncDesc->lprgelemdescParam[i].tdesc);
1822 // Make sure that there is a UNO parameter for every
1823 // expected parameter. If there is no UNO parameter where the
1824 // called function expects one, then it must be optional. Otherwise
1825 // it's a UNO programming error.
1826 if (i >= nUnoArgs && !(paramFlags & PARAMFLAG_FOPT))
1828 OUStringBuffer buf(256);
1829 buf.append("ole automation bridge: The called function expects an argument at"
1830 "position: "); //a different number of arguments")),
1831 buf.append(OUString::number(i));
1832 buf.append(" (index starting at 0).");
1833 throw IllegalArgumentException( buf.makeStringAndClear(),
1834 Reference<XInterface>(), (sal_Int16) i);
1837 // Property Put arguments
1838 if (anyArg.getValueType() == cppu::UnoType<PropertyPutArgument>::get())
1840 PropertyPutArgument arg;
1841 anyArg >>= arg;
1842 anyArg = arg.Value;
1844 // named argument
1845 if (anyArg.getValueType() == cppu::UnoType<NamedArgument>::get())
1847 NamedArgument aNamedArgument;
1848 anyArg >>= aNamedArgument;
1849 anyArg = aNamedArgument.Value;
1851 // out param
1852 if (paramFlags & PARAMFLAG_FOUT &&
1853 ! (paramFlags & PARAMFLAG_FIN) )
1855 VARTYPE type = ::sal::static_int_cast< VARTYPE, int >( varType ^ VT_BYREF );
1856 if (i < nUnoArgs)
1858 arRefArgs[revIndex].vt= type;
1860 else
1862 //optional arg
1863 arRefArgs[revIndex].vt = VT_ERROR;
1864 arRefArgs[revIndex].scode = DISP_E_PARAMNOTFOUND;
1866 if( type == VT_VARIANT )
1868 arArgs[revIndex].vt= VT_VARIANT | VT_BYREF;
1869 arArgs[revIndex].byref= &arRefArgs[revIndex];
1871 else
1873 arArgs[revIndex].vt= varType;
1874 if (type == VT_DECIMAL)
1875 arArgs[revIndex].byref= & arRefArgs[revIndex].decVal;
1876 else
1877 arArgs[revIndex].byref= & arRefArgs[revIndex].byref;
1880 // in/out + in byref params
1881 else if (varType & VT_BYREF)
1883 VARTYPE type = ::sal::static_int_cast< VARTYPE, int >( varType ^ VT_BYREF );
1884 CComVariant var;
1886 if (i < nUnoArgs && anyArg.getValueTypeClass() != TypeClass_VOID)
1888 anyToVariant( & arRefArgs[revIndex], anyArg, type);
1890 else if (paramFlags & PARAMFLAG_FHASDEFAULT)
1892 //optional arg with default
1893 VariantCopy( & arRefArgs[revIndex],
1894 & aFuncDesc->lprgelemdescParam[i].paramdesc.
1895 pparamdescex->varDefaultValue);
1897 else
1899 //optional arg
1900 //e.g: call func(x) in basic : func() ' no arg supplied
1901 OSL_ASSERT(paramFlags & PARAMFLAG_FOPT);
1902 arRefArgs[revIndex].vt = VT_ERROR;
1903 arRefArgs[revIndex].scode = DISP_E_PARAMNOTFOUND;
1906 // Set the converted arguments in the array which will be
1907 // DISPPARAMS::rgvarg
1908 // byref arg VT_XXX |VT_BYREF
1909 arArgs[revIndex].vt = varType;
1910 if (revIndex == 0 && aFuncDesc->invkind == INVOKE_PROPERTYPUT)
1912 arArgs[revIndex] = arRefArgs[revIndex];
1914 else if (type == VT_DECIMAL)
1916 arArgs[revIndex].byref= & arRefArgs[revIndex].decVal;
1918 else if (type == VT_VARIANT)
1920 if ( ! (paramFlags & PARAMFLAG_FOUT))
1921 arArgs[revIndex] = arRefArgs[revIndex];
1922 else
1923 arArgs[revIndex].byref = & arRefArgs[revIndex];
1925 else
1927 arArgs[revIndex].byref = & arRefArgs[revIndex].byref;
1928 arArgs[revIndex].vt = ::sal::static_int_cast< VARTYPE, int >( arRefArgs[revIndex].vt | VT_BYREF );
1932 // in parameter no VT_BYREF except for array, interfaces
1933 else
1934 { // void any stands for optional param
1935 if (i < nUnoArgs && anyArg.getValueTypeClass() != TypeClass_VOID)
1937 anyToVariant( & arArgs[revIndex], anyArg, varType);
1939 //optional arg but no void any supplied
1940 //Basic: obj.func() ' first parameter left out because it is optional
1941 else if (paramFlags & PARAMFLAG_FHASDEFAULT)
1943 //optional arg with default either as direct arg : VT_XXX or
1944 VariantCopy( & arArgs[revIndex],
1945 & aFuncDesc->lprgelemdescParam[i].paramdesc.
1946 pparamdescex->varDefaultValue);
1948 else if (paramFlags & PARAMFLAG_FOPT)
1950 arArgs[revIndex].vt = VT_ERROR;
1951 arArgs[revIndex].scode = DISP_E_PARAMNOTFOUND;
1953 else
1955 arArgs[revIndex].vt = VT_EMPTY;
1956 arArgs[revIndex].lVal = 0;
1961 catch (IllegalArgumentException & e)
1963 e.ArgumentPosition = ::sal::static_int_cast< sal_Int16, sal_Int32 >( i );
1964 throw;
1966 catch (CannotConvertException & e)
1968 e.ArgumentIndex = i;
1969 throw;
1971 dispparams.rgvarg= arArgs;
1972 // invoking OLE method
1973 DWORD localeId = LOCALE_USER_DEFAULT;
1974 result = m_spDispatch->Invoke(aFuncDesc->memid,
1975 IID_NULL,
1976 localeId,
1977 ::sal::static_int_cast< WORD, INVOKEKIND >( aFuncDesc->invkind ),
1978 &dispparams,
1979 &varResult,
1980 &excepinfo,
1981 &uArgErr);
1983 // converting return value and out parameter back to UNO
1984 if (result == S_OK)
1987 // allocate space for the out param Sequence and indices Sequence
1988 int outParamsCount= 0; // includes in/out parameter
1989 for (int j = 0; j < aFuncDesc->cParams; j++)
1991 if (aFuncDesc->lprgelemdescParam[j].paramdesc.wParamFlags &
1992 PARAMFLAG_FOUT)
1993 outParamsCount++;
1996 OutParamIndex.realloc(outParamsCount);
1997 OutParam.realloc(outParamsCount);
1998 // Convert out params
1999 if (outParamsCount)
2001 int outParamIndex=0;
2002 for (int paramIndex = 0; paramIndex < nUnoArgs; paramIndex ++)
2004 //Determine the index within the method signature
2005 int realParamIndex = paramIndex;
2006 int revParamIndex = dispparams.cArgs - paramIndex - 1;
2007 if (Params[paramIndex].getValueType()
2008 == cppu::UnoType<NamedArgument>::get())
2010 //dispparams.rgdispidNamedArgs contains the mapping from index
2011 //of named args list to index of parameter list
2012 realParamIndex = dispparams.rgdispidNamedArgs[revParamIndex];
2015 // no named arg, always come before named args
2016 if (! (aFuncDesc->lprgelemdescParam[realParamIndex].paramdesc.wParamFlags
2017 & PARAMFLAG_FOUT))
2018 continue;
2019 Any outAny;
2020 // variantToAny is called with the "reduce range" parameter set to sal_False.
2021 // That causes VT_I4 values not to be converted down to a "lower" type. That
2022 // feature exist for JScript only because it only uses VT_I4 for integer types.
2025 variantToAny( & arRefArgs[revParamIndex], outAny, false );
2027 catch (IllegalArgumentException & e)
2029 e.ArgumentPosition = (sal_Int16)paramIndex;
2030 throw;
2032 catch (CannotConvertException & e)
2034 e.ArgumentIndex = paramIndex;
2035 throw;
2037 OutParam[outParamIndex] = outAny;
2038 OutParamIndex[outParamIndex] = ::sal::static_int_cast< sal_Int16, int >( paramIndex );
2039 outParamIndex++;
2041 OutParam.realloc(outParamIndex);
2042 OutParamIndex.realloc(outParamIndex);
2044 // Return value
2045 variantToAny(&varResult, ret, false);
2048 // map error codes to exceptions
2049 OUString message;
2050 switch (result)
2052 case S_OK:
2053 break;
2054 case DISP_E_BADPARAMCOUNT:
2055 throw IllegalArgumentException("[automation bridge] Wrong "
2056 "number of arguments. Object returned DISP_E_BADPARAMCOUNT.",
2057 nullptr, 0);
2058 break;
2059 case DISP_E_BADVARTYPE:
2060 throw RuntimeException("[automation bridge] One or more "
2061 "arguments have the wrong type. Object returned "
2062 "DISP_E_BADVARTYPE.", nullptr);
2063 break;
2064 case DISP_E_EXCEPTION:
2065 message = "[automation bridge]: ";
2066 message += OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription),
2067 ::SysStringLen(excepinfo.bstrDescription));
2069 throw InvocationTargetException(message, Reference<XInterface>(), Any());
2070 break;
2071 case DISP_E_MEMBERNOTFOUND:
2072 message = "[automation bridge]: A function with the name \""
2073 + sFuncName + "\" is not supported. Object returned "
2074 "DISP_E_MEMBERNOTFOUND.";
2075 throw IllegalArgumentException(message, nullptr, 0);
2076 break;
2077 case DISP_E_NONAMEDARGS:
2078 throw IllegalArgumentException("[automation bridge] Object "
2079 "returned DISP_E_NONAMEDARGS",nullptr, ::sal::static_int_cast< sal_Int16, unsigned int >( uArgErr ));
2080 break;
2081 case DISP_E_OVERFLOW:
2082 throw CannotConvertException("[automation bridge] Call failed.",
2083 static_cast<XInterface*>(
2084 static_cast<XWeak*>(this)), TypeClass_UNKNOWN, FailReason::OUT_OF_RANGE, uArgErr);
2085 break;
2086 case DISP_E_PARAMNOTFOUND:
2087 throw IllegalArgumentException("[automation bridge]Call failed."
2088 "Object returned DISP_E_PARAMNOTFOUND.",
2089 nullptr, ::sal::static_int_cast< sal_Int16, unsigned int >( uArgErr ));
2090 break;
2091 case DISP_E_TYPEMISMATCH:
2092 throw CannotConvertException("[automation bridge] Call failed. "
2093 "Object returned DISP_E_TYPEMISMATCH",
2094 static_cast<XInterface*>(
2095 static_cast<XWeak*>(this)) , TypeClass_UNKNOWN, FailReason::UNKNOWN, uArgErr);
2096 break;
2097 case DISP_E_UNKNOWNINTERFACE:
2098 throw RuntimeException("[automation bridge] Call failed. "
2099 "Object returned DISP_E_UNKNOWNINTERFACE.",nullptr);
2100 break;
2101 case DISP_E_UNKNOWNLCID:
2102 throw RuntimeException("[automation bridge] Call failed. "
2103 "Object returned DISP_E_UNKNOWNLCID.",nullptr);
2104 break;
2105 case DISP_E_PARAMNOTOPTIONAL:
2106 throw CannotConvertException("[automation bridge] Call failed."
2107 "Object returned DISP_E_PARAMNOTOPTIONAL",
2108 static_cast<XInterface*>(static_cast<XWeak*>(this)),
2109 TypeClass_UNKNOWN, FailReason::NO_DEFAULT_AVAILABLE, uArgErr);
2110 break;
2111 default:
2112 throw RuntimeException();
2113 break;
2116 return ret;
2119 void IUnknownWrapper_Impl::getFuncDescForInvoke(const OUString & sFuncName,
2120 const Sequence<Any> & seqArgs,
2121 FUNCDESC** pFuncDesc)
2123 int nUnoArgs = seqArgs.getLength();
2124 const Any * arArgs = seqArgs.getConstArray();
2125 ITypeInfo* pInfo = getTypeInfo();
2127 //If the last of the positional arguments is a PropertyPutArgument
2128 //then obtain the type info for the property put operation.
2130 //The property value is always the last argument, in a positional argument list
2131 //or in a list of named arguments. A PropertyPutArgument is actually a named argument
2132 //hence it must not be put in an extra NamedArgument structure
2133 if (nUnoArgs > 0 &&
2134 arArgs[nUnoArgs - 1].getValueType() == cppu::UnoType<PropertyPutArgument>::get())
2136 // DISPATCH_PROPERTYPUT
2137 FuncDesc aDescGet(pInfo);
2138 FuncDesc aDescPut(pInfo);
2139 VarDesc aVarDesc(pInfo);
2140 getPropDesc(sFuncName, & aDescGet, & aDescPut, & aVarDesc);
2141 if ( ! aDescPut)
2143 throw IllegalArgumentException(
2144 "[automation bridge] The object does not have a writeable property: "
2145 + sFuncName, Reference<XInterface>(), 0);
2147 *pFuncDesc = aDescPut.Detach();
2149 else
2150 { // DISPATCH_METHOD
2151 FuncDesc aFuncDesc(pInfo);
2152 getFuncDesc(sFuncName, & aFuncDesc);
2153 if ( ! aFuncDesc)
2155 // Fallback: DISPATCH_PROPERTYGET can mostly be called as
2156 // DISPATCH_METHOD
2157 ITypeInfo * pTypeInfo = getTypeInfo();
2158 FuncDesc aDescPut(pTypeInfo);
2159 VarDesc aVarDesc(pTypeInfo);
2160 getPropDesc(sFuncName, & aFuncDesc, & aDescPut, & aVarDesc);
2161 if ( ! aFuncDesc )
2163 throw IllegalArgumentException(
2164 "[automation bridge] The object does not have a function"
2165 "or readable property \""
2166 + sFuncName, Reference<XInterface>(), 0);
2169 *pFuncDesc = aFuncDesc.Detach();
2172 bool IUnknownWrapper_Impl::getDispid(const OUString& sFuncName, DISPID * id)
2174 OSL_ASSERT(m_spDispatch);
2175 LPOLESTR lpsz = const_cast<LPOLESTR> (reinterpret_cast<LPCOLESTR>(sFuncName.getStr()));
2176 HRESULT hr = m_spDispatch->GetIDsOfNames(IID_NULL, &lpsz, 1, LOCALE_USER_DEFAULT, id);
2177 return hr == S_OK;
2179 void IUnknownWrapper_Impl::getFuncDesc(const OUString & sFuncName, FUNCDESC ** pFuncDesc)
2182 OSL_ASSERT( * pFuncDesc == nullptr);
2183 buildComTlbIndex();
2184 typedef TLBFuncIndexMap::const_iterator cit;
2185 //We assume there is only one entry with the function name. A property
2186 //would have two entries.
2187 cit itIndex= m_mapComFunc.find(sFuncName);
2188 if (itIndex == m_mapComFunc.end())
2190 //try case insensitive with IDispatch::GetIDsOfNames
2191 DISPID id;
2192 if (getDispid(sFuncName, &id))
2194 CComBSTR memberName;
2195 unsigned int pcNames=0;
2196 // get the case sensitive name
2197 if( SUCCEEDED(getTypeInfo()->GetNames( id, & memberName, 1, &pcNames)))
2199 //get the associated index and add an entry to the map
2200 //with the name sFuncName which differs in the casing of the letters to
2201 //the actual name as obtained from ITypeInfo
2202 OUString sRealName(reinterpret_cast<const sal_Unicode*>(LPCOLESTR(memberName)));
2203 cit itOrg = m_mapComFunc.find(sRealName);
2204 OSL_ASSERT(itOrg != m_mapComFunc.end());
2205 // maybe this is a property, if so we need
2206 // to store either both id's ( put/get ) or
2207 // just the get. Storing both is more consistent
2208 pair<cit, cit> pItems = m_mapComFunc.equal_range( sRealName );
2209 for ( ;pItems.first != pItems.second; ++pItems.first )
2210 m_mapComFunc.insert( TLBFuncIndexMap::value_type ( make_pair(sFuncName, pItems.first->second ) ));
2211 itIndex =
2212 m_mapComFunc.find( sFuncName );
2217 #if OSL_DEBUG_LEVEL >= 1
2218 // There must only be one entry if sFuncName represents a function or two
2219 // if it is a property
2220 pair<cit, cit> p = m_mapComFunc.equal_range(sFuncName.toAsciiLowerCase());
2221 int numEntries = 0;
2222 for ( ;p.first != p.second; p.first ++, numEntries ++);
2223 OSL_ASSERT( ! (numEntries > 3) );
2224 #endif
2225 if( itIndex != m_mapComFunc.end())
2227 ITypeInfo* pType= getTypeInfo();
2228 FUNCDESC * pDesc = nullptr;
2229 if (SUCCEEDED(pType->GetFuncDesc(itIndex->second, & pDesc)))
2231 if (pDesc->invkind == INVOKE_FUNC)
2233 (*pFuncDesc) = pDesc;
2235 else
2237 pType->ReleaseFuncDesc(pDesc);
2240 else
2242 throw BridgeRuntimeError("[automation bridge] Could not get "
2243 "FUNCDESC for " + sFuncName);
2246 //else no entry found for sFuncName, pFuncDesc will not be filled in
2249 void IUnknownWrapper_Impl::getPropDesc(const OUString & sFuncName, FUNCDESC ** pFuncDescGet,
2250 FUNCDESC** pFuncDescPut, VARDESC** pVarDesc)
2252 OSL_ASSERT( * pFuncDescGet == nullptr && * pFuncDescPut == nullptr);
2253 buildComTlbIndex();
2254 typedef TLBFuncIndexMap::const_iterator cit;
2255 pair<cit, cit> p = m_mapComFunc.equal_range(sFuncName);
2256 if (p.first == m_mapComFunc.end())
2258 //try case insensitive with IDispatch::GetIDsOfNames
2259 DISPID id;
2260 if (getDispid(sFuncName, &id))
2262 CComBSTR memberName;
2263 unsigned int pcNames=0;
2264 // get the case sensitive name
2265 if( SUCCEEDED(getTypeInfo()->GetNames( id, & memberName, 1, &pcNames)))
2267 //As opposed to getFuncDesc, we do not add the value because we would
2268 // need to find the get and set description for the property. This would
2269 //mean to iterate over all FUNCDESCs again.
2270 p = m_mapComFunc.equal_range(OUString(reinterpret_cast<const sal_Unicode*>(LPCOLESTR(memberName))));
2275 for ( int i = 0 ;p.first != p.second; p.first ++, i ++)
2277 // There are a maximum of two entries, property put and property get
2278 OSL_ASSERT( ! (i > 2) );
2279 ITypeInfo* pType= getTypeInfo();
2280 FUNCDESC * pFuncDesc = nullptr;
2281 if (SUCCEEDED( pType->GetFuncDesc(p.first->second, & pFuncDesc)))
2283 if (pFuncDesc->invkind == INVOKE_PROPERTYGET)
2285 (*pFuncDescGet) = pFuncDesc;
2287 else if (pFuncDesc->invkind == INVOKE_PROPERTYPUT ||
2288 pFuncDesc->invkind == INVOKE_PROPERTYPUTREF)
2290 //a property can have 3 entries, put, put ref, get
2291 // If INVOKE_PROPERTYPUTREF or INVOKE_PROPERTYPUT is used
2292 //depends on what is found first.
2293 if ( * pFuncDescPut)
2295 //we already have found one
2296 pType->ReleaseFuncDesc(pFuncDesc);
2298 else
2300 (*pFuncDescPut) = pFuncDesc;
2303 else
2305 pType->ReleaseFuncDesc(pFuncDesc);
2308 //ITypeInfo::GetFuncDesc may even provide a funcdesc for a VARDESC
2309 // with invkind = INVOKE_FUNC. Since this function should only return
2310 //a value for a real property (XInvokation::hasMethod, ..::hasProperty
2311 //we need to make sure that sFuncName represents a real property.
2312 VARDESC * pVD = nullptr;
2313 if (SUCCEEDED(pType->GetVarDesc(p.first->second, & pVD)))
2314 (*pVarDesc) = pVD;
2316 //else no entry for sFuncName, pFuncDesc will not be filled in
2319 VARTYPE IUnknownWrapper_Impl::getUserDefinedElementType( ITypeInfo* pTypeInfo, const DWORD nHrefType )
2321 VARTYPE _type( VT_NULL );
2322 if ( pTypeInfo )
2324 CComPtr<ITypeInfo> spRefInfo;
2325 pTypeInfo->GetRefTypeInfo( nHrefType, &spRefInfo.p );
2326 if ( spRefInfo )
2328 TypeAttr attr( spRefInfo );
2329 spRefInfo->GetTypeAttr( &attr );
2330 if ( attr->typekind == TKIND_ENUM )
2332 // We use the type of the first enum value.
2333 if ( attr->cVars == 0 )
2335 throw BridgeRuntimeError("[automation bridge] Could not obtain type description");
2337 VarDesc var( spRefInfo );
2338 spRefInfo->GetVarDesc( 0, &var );
2339 _type = var->lpvarValue->vt;
2341 else if ( attr->typekind == TKIND_INTERFACE )
2343 _type = VT_UNKNOWN;
2345 else if ( attr->typekind == TKIND_DISPATCH )
2347 _type = VT_DISPATCH;
2349 else if ( attr->typekind == TKIND_ALIAS )
2351 // TKIND_ALIAS is a type that is an alias for another type. So get that alias type.
2352 _type = getUserDefinedElementType( pTypeInfo, attr->tdescAlias.hreftype );
2354 else
2356 throw BridgeRuntimeError( "[automation bridge] Unhandled user defined type." );
2360 return _type;
2363 VARTYPE IUnknownWrapper_Impl::getElementTypeDesc(const TYPEDESC *desc)
2365 VARTYPE _type( VT_NULL );
2367 if (desc->vt == VT_PTR)
2369 _type = getElementTypeDesc(desc->lptdesc);
2370 _type |= VT_BYREF;
2372 else if (desc->vt == VT_SAFEARRAY)
2374 _type = getElementTypeDesc(desc->lptdesc);
2375 _type |= VT_ARRAY;
2377 else if (desc->vt == VT_USERDEFINED)
2379 ITypeInfo* thisInfo = getTypeInfo(); //kept by this instance
2380 _type = getUserDefinedElementType( thisInfo, desc->hreftype );
2382 else
2384 _type = desc->vt;
2386 return _type;
2389 void IUnknownWrapper_Impl::buildComTlbIndex()
2391 if ( ! m_bComTlbIndexInit)
2393 MutexGuard guard(getBridgeMutex());
2395 if ( ! m_bComTlbIndexInit)
2397 OUString sError;
2398 ITypeInfo* pType= getTypeInfo();
2399 TypeAttr typeAttr(pType);
2400 if( SUCCEEDED( pType->GetTypeAttr( &typeAttr)))
2402 for( long i= 0; i < typeAttr->cFuncs; i++)
2404 FuncDesc funcDesc(pType);
2405 if( SUCCEEDED( pType->GetFuncDesc( i, &funcDesc)))
2407 CComBSTR memberName;
2408 unsigned int pcNames=0;
2409 if( SUCCEEDED(pType->GetNames( funcDesc->memid, & memberName, 1, &pcNames)))
2411 OUString usName(reinterpret_cast<const sal_Unicode*>(LPCOLESTR(memberName)));
2412 m_mapComFunc.insert( TLBFuncIndexMap::value_type( usName, i));
2414 else
2416 sError = "[automation bridge] IUnknownWrapper_Impl::buildComTlbIndex, "
2417 "ITypeInfo::GetNames failed.";
2420 else
2421 sError = "[automation bridge] IUnknownWrapper_Impl::buildComTlbIndex, "
2422 "ITypeInfo::GetFuncDesc failed.";
2425 //If we create an Object in JScript and a property then it
2426 //has VARDESC instead of FUNCDESC
2427 for (long i = 0; i < typeAttr->cVars; i++)
2429 VarDesc varDesc(pType);
2430 if (SUCCEEDED(pType->GetVarDesc(i, & varDesc)))
2432 CComBSTR memberName;
2433 unsigned int pcNames = 0;
2434 if (SUCCEEDED(pType->GetNames(varDesc->memid, & memberName, 1, &pcNames)))
2436 if (varDesc->varkind == VAR_DISPATCH)
2438 OUString usName(reinterpret_cast<const sal_Unicode*>(LPCOLESTR(memberName)));
2439 m_mapComFunc.insert(TLBFuncIndexMap::value_type(
2440 usName, i));
2443 else
2445 sError = "[automation bridge] IUnknownWrapper_Impl::buildComTlbIndex, "
2446 "ITypeInfo::GetNames failed.";
2449 else
2450 sError = "[automation bridge] IUnknownWrapper_Impl::buildComTlbIndex, "
2451 "ITypeInfo::GetVarDesc failed.";
2455 else
2456 sError = "[automation bridge] IUnknownWrapper_Impl::buildComTlbIndex, "
2457 "ITypeInfo::GetTypeAttr failed.";
2459 if (sError.getLength())
2461 throw BridgeRuntimeError(sError);
2464 m_bComTlbIndexInit = true;
2470 ITypeInfo* IUnknownWrapper_Impl::getTypeInfo()
2472 if( !m_spDispatch)
2474 throw BridgeRuntimeError("The object has no IDispatch interface!");
2477 if( !m_spTypeInfo )
2479 MutexGuard guard(getBridgeMutex());
2480 if( ! m_spTypeInfo)
2482 CComPtr< ITypeInfo > spType;
2483 if( SUCCEEDED( m_spDispatch->GetTypeInfo( 0, LOCALE_USER_DEFAULT, &spType.p)))
2486 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
2488 //If this is a dual interface then TYPEATTR::typekind is usually TKIND_INTERFACE
2489 //We need to get the type description for TKIND_DISPATCH
2490 TypeAttr typeAttr(spType.p);
2491 if( SUCCEEDED(spType->GetTypeAttr( &typeAttr)))
2493 if (typeAttr->typekind == TKIND_INTERFACE &&
2494 typeAttr->wTypeFlags & TYPEFLAG_FDUAL)
2496 HREFTYPE refDispatch;
2497 if (SUCCEEDED(spType->GetRefTypeOfImplType(::sal::static_int_cast< UINT, int >( -1 ), &refDispatch)))
2499 CComPtr<ITypeInfo> spTypeDisp;
2500 if (SUCCEEDED(spType->GetRefTypeInfo(refDispatch, & spTypeDisp)))
2501 m_spTypeInfo= spTypeDisp;
2503 else
2505 throw BridgeRuntimeError(
2506 "[automation bridge] Could not obtain type information "
2507 "for dispatch interface." );
2510 else if (typeAttr->typekind == TKIND_DISPATCH)
2512 m_spTypeInfo= spType;
2514 else
2516 throw BridgeRuntimeError(
2517 "[automation bridge] Automation object does not "
2518 "provide type information.");
2522 else
2524 throw BridgeRuntimeError("[automation bridge]The dispatch object does not "
2525 "support ITypeInfo!");
2529 return m_spTypeInfo;
2532 } // end namespace
2534 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */