bump product version to 5.0.4.1
[LibreOffice.git] / extensions / source / ole / oleobjw.cxx
blob01f8aa368596a5bb3923e55452bb5b790ce12078
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 "boost/scoped_array.hpp"
29 #include <com/sun/star/script/FailReason.hpp>
30 #include <com/sun/star/beans/XMaterialHolder.hpp>
31 #include <com/sun/star/script/XTypeConverter.hpp>
32 #include <com/sun/star/script/FinishEngineEvent.hpp>
33 #include <com/sun/star/script/InterruptReason.hpp>
34 #include <com/sun/star/script/XEngineListener.hpp>
35 #include <com/sun/star/script/XDebugging.hpp>
36 #include <com/sun/star/script/XInvocation.hpp>
37 #include <com/sun/star/script/ContextInformation.hpp>
38 #include <com/sun/star/script/FinishReason.hpp>
39 #include <com/sun/star/script/XEngine.hpp>
40 #include <com/sun/star/script/InterruptEngineEvent.hpp>
41 #include <com/sun/star/script/XLibraryAccess.hpp>
42 #include <com/sun/star/bridge/ModelDependent.hpp>
44 #include "com/sun/star/bridge/oleautomation/NamedArgument.hpp"
45 #include "com/sun/star/bridge/oleautomation/PropertyPutArgument.hpp"
47 #include <typelib/typedescription.hxx>
48 #include <rtl/uuid.h>
49 #include <rtl/ustring.hxx>
51 #include "jscriptclasses.hxx"
53 #include "oleobjw.hxx"
54 #include "unoobjw.hxx"
55 #include <stdio.h>
56 using namespace std;
57 using namespace boost;
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_uInt32, sal_uInt32> 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 AdapterToWrappperMap 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_uInt32,sal_uInt32> WrapperToAdapterMap;
91 std::unordered_map<sal_uInt32, 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( NULL), 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 = (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_uInt32, sal_uInt32>::iterator _IT;
119 _IT it= WrapperToAdapterMap.find( (sal_uInt32) xIntRoot);
120 if( it != WrapperToAdapterMap.end())
122 sal_uInt32 adapter= it->second;
124 AdapterToWrapperMap.erase( adapter);
125 WrapperToAdapterMap.erase( it);
128 IT_Com it_c= ComPtrToWrapperMap.find( (sal_uInt32) m_spUnknown.p);
129 if(it_c != ComPtrToWrapperMap.end())
130 ComPtrToWrapperMap.erase(it_c);
132 #if OSL_DEBUG_LEVEL > 0
133 fprintf(stderr,"[automation bridge] ComPtrToWrapperMap contains: %i \n",
134 ComPtrToWrapperMap.size());
135 #endif
138 Any IUnknownWrapper_Impl::queryInterface(const Type& t)
139 throw (RuntimeException)
141 if (t == cppu::UnoType<XDefaultMethod>::get() && !m_bHasDfltMethod )
142 return Any();
143 if (t == cppu::UnoType<XDefaultProperty>::get() && !m_bHasDfltProperty )
144 return Any();
145 if ( ( t == cppu::UnoType<XInvocation>::get() || t == cppu::UnoType<XAutomationInvocation>::get() ) && !m_spDispatch)
146 return Any();
147 // XDirectInvocation seems to be an oracle replacement for XAutomationInvocation, however it is flawed esecially wrt. assumptions about whether to invoke a
148 // 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.
149 // XAutomationInvocation provides separate calls for put& get
150 // 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.
151 // For the moment for ease of merging we will let the XDirectInvoke and XAuthomationInvocation interfaces stay side by side ( and for the momemnt at least I would prefer the basic
152 // runtime to call XAutomationInvocation instead of XDirectInvoke
153 return WeakImplHelper7<XBridgeSupplier2,
154 XInitialization, XAutomationObject, XDefaultProperty, XDefaultMethod, XDirectInvocation, XAutomationInvocation >::queryInterface(t);
157 Reference<XIntrospectionAccess> SAL_CALL IUnknownWrapper_Impl::getIntrospection()
158 throw (RuntimeException )
160 Reference<XIntrospectionAccess> ret;
162 return ret;
165 Any SAL_CALL IUnknownWrapper_Impl::invokeGetProperty( const OUString& aPropertyName, const Sequence< Any >& aParams, Sequence< sal_Int16 >& aOutParamIndex, Sequence< Any >& aOutParam )
167 Any aResult;
170 o2u_attachCurrentThread();
171 ITypeInfo * pInfo = getTypeInfo();
172 FuncDesc aDescGet(pInfo);
173 FuncDesc aDescPut(pInfo);
174 VarDesc aVarDesc(pInfo);
175 getPropDesc(aPropertyName, & aDescGet, & aDescPut, & aVarDesc);
176 if ( !aDescGet )
178 OUString msg("[automation bridge]Property \"" + aPropertyName +
179 "\" is not supported");
180 throw UnknownPropertyException(msg);
182 aResult = invokeWithDispIdComTlb( aDescGet, aPropertyName, aParams, aOutParamIndex, aOutParam );
184 catch ( const Exception& e )
186 throw RuntimeException("[automation bridge] unexpected exception in "
187 "IUnknownWrapper_Impl::invokeGetProperty ! Message : \n" +
188 e.Message);
190 return aResult;
193 Any SAL_CALL IUnknownWrapper_Impl::invokePutProperty( const OUString& aPropertyName, const Sequence< Any >& aParams, Sequence< sal_Int16 >& aOutParamIndex, Sequence< Any >& aOutParam )
195 Any aResult;
198 o2u_attachCurrentThread();
199 ITypeInfo * pInfo = getTypeInfo();
200 FuncDesc aDescGet(pInfo);
201 FuncDesc aDescPut(pInfo);
202 VarDesc aVarDesc(pInfo);
203 getPropDesc(aPropertyName, & aDescGet, & aDescPut, & aVarDesc);
204 if ( !aDescPut )
206 OUString msg("[automation bridge]Property \"" + aPropertyName +
207 "\" is not supported");
208 throw UnknownPropertyException(msg);
210 aResult = invokeWithDispIdComTlb( aDescPut, aPropertyName, aParams, aOutParamIndex, aOutParam );
212 catch ( const Exception& e )
214 throw RuntimeException("[automation bridge] unexpected exception in "
215 "IUnknownWrapper_Impl::invokePutProperty ! Message : \n" +
216 e.Message);
218 return aResult;
222 Any SAL_CALL IUnknownWrapper_Impl::invoke( const OUString& aFunctionName,
223 const Sequence< Any >& aParams, Sequence< sal_Int16 >& aOutParamIndex,
224 Sequence< Any >& aOutParam )
225 throw(IllegalArgumentException, CannotConvertException, InvocationTargetException,
226 RuntimeException)
228 if ( ! m_spDispatch )
230 throw RuntimeException(
231 "[automation bridge] The object does not have an IDispatch interface");
234 Any ret;
238 o2u_attachCurrentThread();
240 TypeDescription methodDesc;
241 getMethodInfo(aFunctionName, methodDesc);
242 if( methodDesc.is())
244 ret = invokeWithDispIdUnoTlb(aFunctionName,
245 aParams,
246 aOutParamIndex,
247 aOutParam);
249 else
251 ret= invokeWithDispIdComTlb( aFunctionName,
252 aParams,
253 aOutParamIndex,
254 aOutParam);
257 catch (const IllegalArgumentException &)
259 throw;
261 catch (const CannotConvertException &)
263 throw;
265 catch (const BridgeRuntimeError & e)
267 throw RuntimeException(e.message);
269 catch (const Exception & e)
271 throw RuntimeException("[automation bridge] unexpected exception in "
272 "IUnknownWrapper_Impl::invoke ! Message : \n" +
273 e.Message);
276 catch(...)
278 throw RuntimeException("[automation bridge] unexpected exception in "
279 "IUnknownWrapper_Impl::Invoke !");
281 return ret;
284 void SAL_CALL IUnknownWrapper_Impl::setValue( const OUString& aPropertyName,
285 const Any& aValue )
286 throw(UnknownPropertyException, CannotConvertException, InvocationTargetException,
287 RuntimeException)
289 if ( ! m_spDispatch )
291 throw RuntimeException(
292 "[automation bridge] The object does not have an IDispatch interface");
296 o2u_attachCurrentThread();
298 ITypeInfo * pInfo = getTypeInfo();
299 FuncDesc aDescGet(pInfo);
300 FuncDesc aDescPut(pInfo);
301 VarDesc aVarDesc(pInfo);
302 getPropDesc(aPropertyName, & aDescGet, & aDescPut, & aVarDesc);
303 //check if there is such a property at all or if it is read only
304 if ( ! aDescPut && ! aDescGet && ! aVarDesc)
306 OUString msg("[automation bridge]Property \"" + aPropertyName +
307 "\" is not supported");
308 throw UnknownPropertyException(msg);
311 if ( (! aDescPut && aDescGet) || aVarDesc
312 && aVarDesc->wVarFlags == VARFLAG_FREADONLY )
314 //read-only
315 OUString msg("[automation bridge] Property " + aPropertyName +
316 " is read-only");
317 OString sMsg = OUStringToOString(msg, osl_getThreadTextEncoding());
318 OSL_FAIL(sMsg.getStr());
319 // ignore silently
320 return;
323 HRESULT hr= S_OK;
324 DISPPARAMS dispparams;
325 CComVariant varArg;
326 CComVariant varRefArg;
327 CComVariant varResult;
328 ExcepInfo excepinfo;
329 unsigned int uArgErr;
331 // converting UNO value to OLE variant
332 DISPID dispidPut= DISPID_PROPERTYPUT;
333 dispparams.rgdispidNamedArgs = &dispidPut;
334 dispparams.cArgs = 1;
335 dispparams.cNamedArgs = 1;
336 dispparams.rgvarg = & varArg;
338 OSL_ASSERT(aDescPut || aVarDesc);
340 VARTYPE vt = 0;
341 DISPID dispid = 0;
342 INVOKEKIND invkind = INVOKE_PROPERTYPUT;
343 //determine the expected type, dispid, invoke kind (DISPATCH_PROPERTYPUT,
344 //DISPATCH_PROPERTYPUTREF)
345 if (aDescPut)
347 vt = getElementTypeDesc(& aDescPut->lprgelemdescParam[0].tdesc);
348 dispid = aDescPut->memid;
349 invkind = aDescPut->invkind;
351 else
353 vt = getElementTypeDesc( & aVarDesc->elemdescVar.tdesc);
354 dispid = aVarDesc->memid;
355 if (vt == VT_UNKNOWN || vt == VT_DISPATCH ||
356 (vt & VT_ARRAY) || (vt & VT_BYREF))
358 invkind = INVOKE_PROPERTYPUTREF;
362 // convert the uno argument
363 if (vt & VT_BYREF)
365 anyToVariant( & varRefArg, aValue, ::sal::static_int_cast< VARTYPE, int >( vt ^ VT_BYREF ) );
366 varArg.vt = vt;
367 if( (vt & VT_TYPEMASK) == VT_VARIANT)
368 varArg.byref = & varRefArg;
369 else if ((vt & VT_TYPEMASK) == VT_DECIMAL)
370 varArg.byref = & varRefArg.decVal;
371 else
372 varArg.byref = & varRefArg.byref;
374 else
376 anyToVariant(& varArg, aValue, vt);
378 // call to IDispatch
379 hr = m_spDispatch->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, ::sal::static_int_cast< WORD, INVOKEKIND >( invkind ),
380 &dispparams, & varResult, & excepinfo, &uArgErr);
382 // lookup error code
383 switch (hr)
385 case S_OK:
386 break;
387 case DISP_E_BADPARAMCOUNT:
388 throw RuntimeException();
389 break;
390 case DISP_E_BADVARTYPE:
391 throw RuntimeException();
392 break;
393 case DISP_E_EXCEPTION:
394 throw InvocationTargetException();
395 break;
396 case DISP_E_MEMBERNOTFOUND:
397 throw UnknownPropertyException();
398 break;
399 case DISP_E_NONAMEDARGS:
400 throw RuntimeException();
401 break;
402 case DISP_E_OVERFLOW:
403 throw CannotConvertException("call to OLE object failed", static_cast<XInterface*>(
404 static_cast<XWeak*>(this)), TypeClass_UNKNOWN, FailReason::OUT_OF_RANGE, uArgErr);
405 break;
406 case DISP_E_PARAMNOTFOUND:
407 throw IllegalArgumentException("call to OLE object failed", static_cast<XInterface*>(
408 static_cast<XWeak*>(this)), ::sal::static_int_cast< sal_Int16, unsigned int >( uArgErr )) ;
409 break;
410 case DISP_E_TYPEMISMATCH:
411 throw CannotConvertException("call to OLE object failed", static_cast<XInterface*>(
412 static_cast<XWeak*>(this)), TypeClass_UNKNOWN, FailReason::UNKNOWN, ::sal::static_int_cast< sal_Int16, unsigned int >( uArgErr ));
413 break;
414 case DISP_E_UNKNOWNINTERFACE:
415 throw RuntimeException();
416 break;
417 case DISP_E_UNKNOWNLCID:
418 throw RuntimeException();
419 break;
420 case DISP_E_PARAMNOTOPTIONAL:
421 throw CannotConvertException("call to OLE object failed",static_cast<XInterface*>(
422 static_cast<XWeak*>(this)) , TypeClass_UNKNOWN, FailReason::NO_DEFAULT_AVAILABLE, uArgErr);
423 break;
424 default:
425 throw RuntimeException();
426 break;
429 catch (const CannotConvertException &)
431 throw;
433 catch (const UnknownPropertyException &)
435 throw;
437 catch (const BridgeRuntimeError& e)
439 throw RuntimeException(e.message);
441 catch (const Exception & e)
443 throw RuntimeException("[automation bridge] unexpected exception in "
444 "IUnknownWrapper_Impl::setValue ! Message : \n" +
445 e.Message);
448 catch (...)
450 throw RuntimeException(
451 "[automation bridge] unexpected exception in "
452 "IUnknownWrapper_Impl::setValue !");
456 Any SAL_CALL IUnknownWrapper_Impl::getValue( const OUString& aPropertyName )
457 throw(UnknownPropertyException, RuntimeException)
459 if ( ! m_spDispatch )
461 throw RuntimeException(
462 "[automation bridge] The object does not have an IDispatch interface");
464 Any ret;
467 o2u_attachCurrentThread();
468 ITypeInfo * pInfo = getTypeInfo();
469 // I was going to implement an XServiceInfo interface to allow the type
470 // of the automation object to be exposed.. but it seems
471 // from looking at comments in the code that it is possible for
472 // this object to actually wrap an UNO object ( I guess if automation is
473 // used from MSO to create Openoffice objects ) Therefore, those objects
474 // will more than likely already have their own XServiceInfo interface.
475 // Instead here I chose a name that should be illegal both in COM and
476 // UNO ( from an IDL point of view ) therefore I think this is a safe
477 // hack
478 if ( aPropertyName == "$GetTypeName" )
480 if ( pInfo && m_sTypeName.getLength() == 0 )
482 m_sTypeName = "IDispatch";
483 CComBSTR sName;
485 if ( SUCCEEDED( pInfo->GetDocumentation( -1, &sName, NULL, NULL, NULL ) ) )
487 OUString sTmp( reinterpret_cast<const sal_Unicode*>(LPCOLESTR(sName)));
488 if ( sTmp.startsWith("_") )
489 sTmp = sTmp.copy(1);
490 // do we own the memory for pTypeLib, msdn doco is vague
491 // I'll assume we do
492 CComPtr< ITypeLib > pTypeLib;
493 unsigned int index;
494 if ( SUCCEEDED( pInfo->GetContainingTypeLib( &pTypeLib.p, &index )) )
496 if ( SUCCEEDED( pTypeLib->GetDocumentation( -1, &sName, NULL, NULL, NULL ) ) )
498 OUString sLibName( reinterpret_cast<const sal_Unicode*>(LPCOLESTR(sName)));
499 m_sTypeName = sLibName.concat( OUString(".") ).concat( sTmp );
506 ret <<= m_sTypeName;
507 return ret;
509 FuncDesc aDescGet(pInfo);
510 FuncDesc aDescPut(pInfo);
511 VarDesc aVarDesc(pInfo);
512 getPropDesc(aPropertyName, & aDescGet, & aDescPut, & aVarDesc);
513 if ( ! aDescGet && ! aDescPut && ! aVarDesc)
515 //property not found
516 OUString msg("[automation bridge]Property \"" + aPropertyName +
517 "\" is not supported");
518 throw UnknownPropertyException(msg);
520 // write-only should not be possible
521 OSL_ASSERT( aDescGet || ! aDescPut);
523 HRESULT hr;
524 DISPPARAMS dispparams = {0, 0, 0, 0};
525 CComVariant varResult;
526 ExcepInfo excepinfo;
527 unsigned int uArgErr;
528 DISPID dispid;
529 if (aDescGet)
530 dispid = aDescGet->memid;
531 else if (aVarDesc)
532 dispid = aVarDesc->memid;
533 else
534 dispid = aDescPut->memid;
536 hr = m_spDispatch->Invoke(dispid,
537 IID_NULL,
538 LOCALE_USER_DEFAULT,
539 DISPATCH_PROPERTYGET,
540 &dispparams,
541 &varResult,
542 &excepinfo,
543 &uArgErr);
545 // converting return value and out parameter back to UNO
546 if (hr == S_OK)
548 // If the com object implements uno interfaces then we have
549 // to convert the attribute into the expected type.
550 TypeDescription attrInfo;
551 getAttributeInfo(aPropertyName, attrInfo);
552 if( attrInfo.is() )
553 variantToAny( &varResult, ret, Type( attrInfo.get()->pWeakRef));
554 else
555 variantToAny(&varResult, ret);
558 // lookup error code
559 switch (hr)
561 case S_OK:
562 break;
563 case DISP_E_BADPARAMCOUNT:
564 case DISP_E_BADVARTYPE:
565 case DISP_E_EXCEPTION:
566 throw RuntimeException(OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription)));
567 break;
568 case DISP_E_MEMBERNOTFOUND:
569 throw UnknownPropertyException(OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription)));
570 break;
571 default:
572 throw RuntimeException(OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription)));
573 break;
576 catch ( const UnknownPropertyException& )
578 throw;
580 catch (const BridgeRuntimeError& e)
582 throw RuntimeException(e.message);
584 catch (const Exception & e)
586 throw RuntimeException("[automation bridge] unexpected exception in "
587 "IUnknownWrapper_Impl::getValue ! Message : \n" +
588 e.Message);
590 catch (...)
592 throw RuntimeException(
593 "[automation bridge] unexpected exception in "
594 "IUnknownWrapper_Impl::getValue !");
596 return ret;
599 sal_Bool SAL_CALL IUnknownWrapper_Impl::hasMethod( const OUString& aName )
600 throw(RuntimeException)
602 if ( ! m_spDispatch )
604 throw RuntimeException(
605 "[automation bridge] The object does not have an IDispatch interface");
607 sal_Bool ret = sal_False;
611 o2u_attachCurrentThread();
612 ITypeInfo* pInfo = getTypeInfo();
613 FuncDesc aDesc(pInfo);
614 getFuncDesc(aName, & aDesc);
615 // Automation properties can have arguments. Those are treated as methods and
616 //are called through XInvocation::invoke.
617 if ( ! aDesc)
619 FuncDesc aDescGet(pInfo);
620 FuncDesc aDescPut(pInfo);
621 VarDesc aVarDesc(pInfo);
622 getPropDesc( aName, & aDescGet, & aDescPut, & aVarDesc);
623 if (aDescGet && aDescGet->cParams > 0
624 || aDescPut && aDescPut->cParams > 0)
625 ret = sal_True;
627 else
628 ret = sal_True;
630 catch (const BridgeRuntimeError& e)
632 throw RuntimeException(e.message);
634 catch (const Exception & e)
636 throw RuntimeException("[automation bridge] unexpected exception in "
637 "IUnknownWrapper_Impl::hasMethod ! Message : \n" +
638 e.Message);
640 catch (...)
642 throw RuntimeException("[automation bridge] unexpected exception in "
643 "IUnknownWrapper_Impl::hasMethod !");
645 return ret;
648 sal_Bool SAL_CALL IUnknownWrapper_Impl::hasProperty( const OUString& aName )
649 throw(RuntimeException)
651 if ( ! m_spDispatch )
653 throw RuntimeException("[automation bridge] The object does not have an "
654 "IDispatch interface");
656 sal_Bool ret = sal_False;
659 o2u_attachCurrentThread();
661 ITypeInfo * pInfo = getTypeInfo();
662 FuncDesc aDescGet(pInfo);
663 FuncDesc aDescPut(pInfo);
664 VarDesc aVarDesc(pInfo);
665 getPropDesc(aName, & aDescGet, & aDescPut, & aVarDesc);
667 // we should probably just check the funckind
668 // basic has been modified to handle properties ( 'get' ) props at
669 // least with parameters
670 // additionally you can call invoke(Get|Set)Property on the bridge
671 // you can determine if a property has parameter is hasMethod
672 // returns true for the name
673 if (aVarDesc
674 || aDescPut
675 || aDescGet )
677 ret = sal_True;
680 catch (const BridgeRuntimeError& e)
682 throw RuntimeException(e.message);
684 catch (const Exception & e)
686 throw RuntimeException("[automation bridge] unexpected exception in "
687 "IUnknownWrapper_Impl::hasProperty ! Message : \n" +
688 e.Message);
691 catch (...)
693 throw RuntimeException("[automation bridge] unexpected exception in "
694 "IUnknownWrapper_Impl::hasProperty !");
696 return ret;
699 Any SAL_CALL IUnknownWrapper_Impl::createBridge( const Any& modelDepObject,
700 const Sequence< sal_Int8 >& /*aProcessId*/, sal_Int16 sourceModelType,
701 sal_Int16 destModelType )
702 throw( IllegalArgumentException, RuntimeException)
704 Any ret;
705 o2u_attachCurrentThread();
707 if (
708 (sourceModelType == UNO) &&
709 (destModelType == OLE) &&
710 (modelDepObject.getValueTypeClass() == TypeClass_INTERFACE)
713 Reference<XInterface> xInt( *(XInterface**) modelDepObject.getValue());
714 Reference<XInterface> xSelf( (OWeakObject*)this);
716 if (xInt == xSelf)
718 VARIANT* pVariant = (VARIANT*) CoTaskMemAlloc(sizeof(VARIANT));
720 VariantInit(pVariant);
721 if (m_bOriginalDispatch == sal_True)
723 pVariant->vt = VT_DISPATCH;
724 pVariant->pdispVal = m_spDispatch;
725 pVariant->pdispVal->AddRef();
727 else
729 pVariant->vt = VT_UNKNOWN;
730 pVariant->punkVal = m_spUnknown;
731 pVariant->punkVal->AddRef();
734 ret.setValue((void*)&pVariant, cppu::UnoType<sal_uInt32>::get());
738 return ret;
740 /** @internal
741 @exception IllegalArgumentException
742 @exception CannotConvertException
743 @exception InvocationTargetException
744 @RuntimeException
746 Any IUnknownWrapper_Impl::invokeWithDispIdUnoTlb(const OUString& sFunctionName,
747 const Sequence< Any >& Params,
748 Sequence< sal_Int16 >& OutParamIndex,
749 Sequence< Any >& OutParam)
751 Any ret;
752 HRESULT hr= S_OK;
754 sal_Int32 parameterCount= Params.getLength();
755 sal_Int32 outParameterCount= 0;
756 typelib_InterfaceMethodTypeDescription* pMethod= NULL;
757 TypeDescription methodDesc;
758 getMethodInfo(sFunctionName, methodDesc);
760 // We need to know whether the IDispatch is from a JScript object.
761 // Then out and in/out parameters have to be treated differently than
762 // with common COM objects.
763 sal_Bool bJScriptObject= isJScriptObject();
764 scoped_array<CComVariant> sarParams;
765 scoped_array<CComVariant> sarParamsRef;
766 CComVariant *pVarParams= NULL;
767 CComVariant *pVarParamsRef= NULL;
768 sal_Bool bConvRet= sal_True;
770 if( methodDesc.is())
772 pMethod = (typelib_InterfaceMethodTypeDescription* )methodDesc.get();
773 parameterCount = pMethod->nParams;
774 // Create the Array for the array being passed in DISPPARAMS
775 // the array also contains the outparameter (but not the values)
776 if( pMethod->nParams > 0)
778 sarParams.reset(new CComVariant[ parameterCount]);
779 pVarParams = sarParams.get();
782 // Create the Array for the out an in/out parameter. These values
783 // are referenced by the VT_BYREF VARIANTs in DISPPARAMS.
784 // We need to find out the number of out and in/out parameter.
785 for( sal_Int32 i=0; i < parameterCount; i++)
787 if( pMethod->pParams[i].bOut)
788 outParameterCount++;
791 if( !bJScriptObject)
793 sarParamsRef.reset(new CComVariant[outParameterCount]);
794 pVarParamsRef = sarParamsRef.get();
795 // build up the parameters for IDispatch::Invoke
796 sal_Int32 outParamIndex=0;
797 int i = 0;
800 for( i= 0; i < parameterCount; i++)
802 // In parameter
803 if( pMethod->pParams[i].bIn == sal_True && ! pMethod->pParams[i].bOut)
805 anyToVariant( &pVarParams[parameterCount - i -1], Params.getConstArray()[i]);
807 // Out parameter + in/out parameter
808 else if( pMethod->pParams[i].bOut == sal_True)
810 CComVariant var;
811 if(pMethod->pParams[i].bIn)
813 anyToVariant( & var,Params[i]);
814 pVarParamsRef[outParamIndex] = var;
817 switch( pMethod->pParams[i].pTypeRef->eTypeClass)
819 case TypeClass_INTERFACE:
820 case TypeClass_STRUCT:
821 if( ! pMethod->pParams[i].bIn)
823 pVarParamsRef[ outParamIndex].vt= VT_DISPATCH;
824 pVarParamsRef[ outParamIndex].pdispVal= 0;
826 pVarParams[parameterCount - i -1].vt = VT_DISPATCH | VT_BYREF;
827 pVarParams[parameterCount - i -1].ppdispVal= &pVarParamsRef[outParamIndex].pdispVal;
828 break;
829 case TypeClass_ENUM:
830 case TypeClass_LONG:
831 case TypeClass_UNSIGNED_LONG:
832 if( ! pMethod->pParams[i].bIn)
834 pVarParamsRef[ outParamIndex].vt = VT_I4;
835 pVarParamsRef[ outParamIndex].lVal = 0;
837 pVarParams[parameterCount - i -1].vt = VT_I4 | VT_BYREF;
838 pVarParams[parameterCount - i -1].plVal= &pVarParamsRef[outParamIndex].lVal;
839 break;
840 case TypeClass_SEQUENCE:
841 if( ! pMethod->pParams[i].bIn)
843 pVarParamsRef[ outParamIndex].vt = VT_ARRAY| VT_VARIANT;
844 pVarParamsRef[ outParamIndex].parray= NULL;
846 pVarParams[parameterCount - i -1].vt = VT_ARRAY| VT_BYREF | VT_VARIANT;
847 pVarParams[parameterCount - i -1].pparray= &pVarParamsRef[outParamIndex].parray;
848 break;
849 case TypeClass_ANY:
850 if( ! pMethod->pParams[i].bIn)
852 pVarParamsRef[ outParamIndex].vt = VT_EMPTY;
853 pVarParamsRef[ outParamIndex].lVal = 0;
855 pVarParams[parameterCount - i -1].vt = VT_VARIANT | VT_BYREF;
856 pVarParams[parameterCount - i -1].pvarVal = &pVarParamsRef[outParamIndex];
857 break;
858 case TypeClass_BOOLEAN:
859 if( ! pMethod->pParams[i].bIn)
861 pVarParamsRef[ outParamIndex].vt = VT_BOOL;
862 pVarParamsRef[ outParamIndex].boolVal = 0;
864 pVarParams[parameterCount - i -1].vt = VT_BOOL| VT_BYREF;
865 pVarParams[parameterCount - i -1].pboolVal =
866 & pVarParamsRef[outParamIndex].boolVal;
867 break;
869 case TypeClass_STRING:
870 if( ! pMethod->pParams[i].bIn)
872 pVarParamsRef[ outParamIndex].vt = VT_BSTR;
873 pVarParamsRef[ outParamIndex].bstrVal= 0;
875 pVarParams[parameterCount - i -1].vt = VT_BSTR| VT_BYREF;
876 pVarParams[parameterCount - i -1].pbstrVal=
877 & pVarParamsRef[outParamIndex].bstrVal;
878 break;
880 case TypeClass_FLOAT:
881 if( ! pMethod->pParams[i].bIn)
883 pVarParamsRef[ outParamIndex].vt = VT_R4;
884 pVarParamsRef[ outParamIndex].fltVal= 0;
886 pVarParams[parameterCount - i -1].vt = VT_R4| VT_BYREF;
887 pVarParams[parameterCount - i -1].pfltVal =
888 & pVarParamsRef[outParamIndex].fltVal;
889 break;
890 case TypeClass_DOUBLE:
891 if( ! pMethod->pParams[i].bIn)
893 pVarParamsRef[ outParamIndex].vt = VT_R8;
894 pVarParamsRef[ outParamIndex].dblVal= 0;
896 pVarParams[parameterCount - i -1].vt = VT_R8| VT_BYREF;
897 pVarParams[parameterCount - i -1].pdblVal=
898 & pVarParamsRef[outParamIndex].dblVal;
899 break;
900 case TypeClass_BYTE:
901 if( ! pMethod->pParams[i].bIn)
903 pVarParamsRef[ outParamIndex].vt = VT_UI1;
904 pVarParamsRef[ outParamIndex].bVal= 0;
906 pVarParams[parameterCount - i -1].vt = VT_UI1| VT_BYREF;
907 pVarParams[parameterCount - i -1].pbVal=
908 & pVarParamsRef[outParamIndex].bVal;
909 break;
910 case TypeClass_CHAR:
911 case TypeClass_SHORT:
912 case TypeClass_UNSIGNED_SHORT:
913 if( ! pMethod->pParams[i].bIn)
915 pVarParamsRef[ outParamIndex].vt = VT_I2;
916 pVarParamsRef[ outParamIndex].iVal = 0;
918 pVarParams[parameterCount - i -1].vt = VT_I2| VT_BYREF;
919 pVarParams[parameterCount - i -1].piVal=
920 & pVarParamsRef[outParamIndex].iVal;
921 break;
923 default:
924 if( ! pMethod->pParams[i].bIn)
926 pVarParamsRef[ outParamIndex].vt = VT_EMPTY;
927 pVarParamsRef[ outParamIndex].lVal = 0;
929 pVarParams[parameterCount - i -1].vt = VT_VARIANT | VT_BYREF;
930 pVarParams[parameterCount - i -1].pvarVal =
931 & pVarParamsRef[outParamIndex];
933 outParamIndex++;
934 } // end else if
935 } // end for
937 catch (IllegalArgumentException & e)
939 e.ArgumentPosition = ::sal::static_int_cast< sal_Int16, int >( i );
940 throw;
942 catch (CannotConvertException & e)
944 e.ArgumentIndex = i;
945 throw;
948 else // it is an JScriptObject
950 int i = 0;
953 for( ; i< parameterCount; i++)
955 // In parameter
956 if( pMethod->pParams[i].bIn == sal_True && ! pMethod->pParams[i].bOut)
958 anyToVariant( &pVarParams[parameterCount - i -1], Params.getConstArray()[i]);
960 // Out parameter + in/out parameter
961 else if( pMethod->pParams[i].bOut == sal_True)
963 CComObject<JScriptOutParam>* pParamObject;
964 if( SUCCEEDED( CComObject<JScriptOutParam>::CreateInstance( &pParamObject)))
966 CComPtr<IUnknown> pUnk(pParamObject->GetUnknown());
967 #ifdef __MINGW32__
968 CComQIPtr<IDispatch, &__uuidof(IDispatch)> pDisp( pUnk);
969 #else
970 CComQIPtr<IDispatch> pDisp( pUnk);
971 #endif
973 pVarParams[ parameterCount - i -1].vt= VT_DISPATCH;
974 pVarParams[ parameterCount - i -1].pdispVal= pDisp;
975 pVarParams[ parameterCount - i -1].pdispVal->AddRef();
976 // if the param is in/out then put the parameter on index 0
977 if( pMethod->pParams[i].bIn == sal_True ) // in / out
979 CComVariant varParam;
980 anyToVariant( &varParam, Params.getConstArray()[i]);
981 CComDispatchDriver dispDriver( pDisp);
982 if(FAILED( dispDriver.PutPropertyByName( L"0", &varParam)))
983 throw BridgeRuntimeError(
984 "[automation bridge]IUnknownWrapper_Impl::"
985 "invokeWithDispIdUnoTlb\n"
986 "Could not set property \"0\" for the in/out "
987 "param!");
991 else
993 throw BridgeRuntimeError(
994 "[automation bridge]IUnknownWrapper_Impl::"
995 "invokeWithDispIdUnoTlb\n"
996 "Could not create out parameter at index: " +
997 OUString::number((sal_Int32) i));
1003 catch (IllegalArgumentException & e)
1005 e.ArgumentPosition = ::sal::static_int_cast< sal_Int16, int >( i );
1006 throw;
1008 catch (CannotConvertException & e)
1010 e.ArgumentIndex = i;
1011 throw;
1015 // No type description Available, that is we have to deal with a COM component,
1016 // that does not implements UNO interfaces ( IDispatch based)
1017 else
1019 //We should not run into this block, because invokeWithDispIdComTlb should
1020 //have been called instead.
1021 OSL_ASSERT(0);
1025 CComVariant varResult;
1026 ExcepInfo excepinfo;
1027 unsigned int uArgErr;
1028 DISPPARAMS dispparams= { pVarParams, NULL, parameterCount, 0};
1029 // Get the DISPID
1030 FuncDesc aDesc(getTypeInfo());
1031 getFuncDesc(sFunctionName, & aDesc);
1032 // invoking OLE method
1033 hr = m_spDispatch->Invoke(aDesc->memid,
1034 IID_NULL,
1035 LOCALE_USER_DEFAULT,
1036 DISPATCH_METHOD,
1037 &dispparams,
1038 &varResult,
1039 &excepinfo,
1040 &uArgErr);
1042 // converting return value and out parameter back to UNO
1043 if (hr == S_OK)
1045 if( outParameterCount && pMethod)
1047 OutParamIndex.realloc( outParameterCount);
1048 OutParam.realloc( outParameterCount);
1049 sal_Int32 outIndex=0;
1050 int i = 0;
1053 for( ; i < parameterCount; i++)
1055 if( pMethod->pParams[i].bOut )
1057 OutParamIndex[outIndex]= (sal_Int16) i;
1058 Any outAny;
1059 if( !bJScriptObject)
1061 variantToAny( &pVarParamsRef[outIndex], outAny,
1062 Type(pMethod->pParams[i].pTypeRef), sal_False);
1063 OutParam[outIndex++]= outAny;
1065 else //JScriptObject
1067 if( pVarParams[i].vt == VT_DISPATCH)
1069 CComDispatchDriver pDisp( pVarParams[i].pdispVal);
1070 if( pDisp)
1072 CComVariant varOut;
1073 if( SUCCEEDED( pDisp.GetPropertyByName( L"0", &varOut)))
1075 variantToAny( &varOut, outAny,
1076 Type(pMethod->pParams[parameterCount - 1 - i].pTypeRef), sal_False);
1077 OutParam[outParameterCount - 1 - outIndex++]= outAny;
1079 else
1080 bConvRet= sal_False;
1082 else
1083 bConvRet= sal_False;
1085 else
1086 bConvRet= sal_False;
1089 if( !bConvRet) break;
1092 catch(IllegalArgumentException & e)
1094 e.ArgumentPosition = ::sal::static_int_cast< sal_Int16, int >( i );
1095 throw;
1097 catch(CannotConvertException & e)
1099 e.ArgumentIndex = i;
1100 throw;
1103 // return value, no type information available
1104 if ( bConvRet)
1108 if( pMethod )
1109 variantToAny(&varResult, ret, Type( pMethod->pReturnTypeRef), sal_False);
1110 else
1111 variantToAny(&varResult, ret, sal_False);
1113 catch (IllegalArgumentException & e)
1115 e.Message =
1116 "[automation bridge]IUnknownWrapper_Impl::invokeWithDispIdUnoTlb\n"
1117 "Could not convert return value! \n Message: \n" + e.Message;
1118 throw;
1120 catch (CannotConvertException & e)
1122 e.Message =
1123 "[automation bridge]IUnknownWrapper_Impl::invokeWithDispIdUnoTlb\n"
1124 "Could not convert return value! \n Message: \n" + e.Message;
1125 throw;
1130 if( !bConvRet) // conversion of return or out parameter failed
1131 throw CannotConvertException("Call to COM object failed. Conversion of return or out value failed",
1132 Reference<XInterface>( static_cast<XWeak*>(this), UNO_QUERY ), TypeClass_UNKNOWN,
1133 FailReason::UNKNOWN, 0);// lookup error code
1134 // conversion of return or out parameter failed
1135 switch (hr)
1137 case S_OK:
1138 break;
1139 case DISP_E_BADPARAMCOUNT:
1140 throw IllegalArgumentException();
1141 break;
1142 case DISP_E_BADVARTYPE:
1143 throw RuntimeException();
1144 break;
1145 case DISP_E_EXCEPTION:
1146 throw InvocationTargetException();
1147 break;
1148 case DISP_E_MEMBERNOTFOUND:
1149 throw IllegalArgumentException();
1150 break;
1151 case DISP_E_NONAMEDARGS:
1152 throw IllegalArgumentException();
1153 break;
1154 case DISP_E_OVERFLOW:
1155 throw CannotConvertException("call to OLE object failed", static_cast<XInterface*>(
1156 static_cast<XWeak*>(this)), TypeClass_UNKNOWN, FailReason::OUT_OF_RANGE, uArgErr);
1157 break;
1158 case DISP_E_PARAMNOTFOUND:
1159 throw IllegalArgumentException("call to OLE object failed", static_cast<XInterface*>(
1160 static_cast<XWeak*>(this)), ::sal::static_int_cast< sal_Int16, unsigned int >( uArgErr ));
1161 break;
1162 case DISP_E_TYPEMISMATCH:
1163 throw CannotConvertException("call to OLE object failed",static_cast<XInterface*>(
1164 static_cast<XWeak*>(this)) , TypeClass_UNKNOWN, FailReason::UNKNOWN, uArgErr);
1165 break;
1166 case DISP_E_UNKNOWNINTERFACE:
1167 throw RuntimeException() ;
1168 break;
1169 case DISP_E_UNKNOWNLCID:
1170 throw RuntimeException() ;
1171 break;
1172 case DISP_E_PARAMNOTOPTIONAL:
1173 throw CannotConvertException("call to OLE object failed", static_cast<XInterface*>(
1174 static_cast<XWeak*>(this)), TypeClass_UNKNOWN, FailReason::NO_DEFAULT_AVAILABLE, uArgErr);
1175 break;
1176 default:
1177 throw RuntimeException();
1178 break;
1181 return ret;
1187 // XInitialization
1188 void SAL_CALL IUnknownWrapper_Impl::initialize( const Sequence< Any >& aArguments ) throw(Exception, RuntimeException)
1190 // 1.parameter is IUnknown
1191 // 2.parameter is a boolean which indicates if the COM pointer was a IUnknown or IDispatch
1192 // 3.parameter is a Sequence<Type>
1193 o2u_attachCurrentThread();
1194 OSL_ASSERT(aArguments.getLength() == 3);
1196 m_spUnknown= *(IUnknown**) aArguments[0].getValue();
1197 #ifdef __MINGW32__
1198 m_spUnknown->QueryInterface(IID_IDispatch, reinterpret_cast<LPVOID*>( & m_spDispatch.p));
1199 #else
1200 m_spUnknown.QueryInterface( & m_spDispatch.p);
1201 #endif
1203 aArguments[1] >>= m_bOriginalDispatch;
1204 aArguments[2] >>= m_seqTypes;
1206 ITypeInfo* pType = NULL;
1209 // a COM object implementation that has no TypeInfo is still a legal COM object;
1210 // such objects can at least be transported through UNO using the bridge
1211 // so we should allow to create wrappers for them as well
1212 pType = getTypeInfo();
1214 catch( const BridgeRuntimeError& )
1216 catch( const Exception& )
1219 if ( pType )
1223 // Get Default member
1224 CComBSTR defaultMemberName;
1225 if ( SUCCEEDED( pType->GetDocumentation(0, &defaultMemberName, 0, 0, 0 ) ) )
1227 OUString usName(reinterpret_cast<const sal_Unicode*>(LPCOLESTR(defaultMemberName)));
1228 FuncDesc aDescGet(pType);
1229 FuncDesc aDescPut(pType);
1230 VarDesc aVarDesc(pType);
1231 // see if this is a property first ( more likely to be a property then a method )
1232 getPropDesc( usName, & aDescGet, & aDescPut, & aVarDesc);
1234 if ( !aDescGet && !aDescPut )
1236 getFuncDesc( usName, &aDescGet );
1237 if ( !aDescGet )
1238 throw BridgeRuntimeError( "[automation bridge]IUnknownWrapper_Impl::initialize() Failed to get Function or Property desc. for " + usName );
1240 // now for some funny heuristics to make basic understand what to do
1241 // a single aDescGet ( that doesn't take any params ) would be
1242 // a read only ( defaultmember ) property e.g. this object
1243 // should implement XDefaultProperty
1244 // a single aDescGet ( that *does* ) take params is basically a
1245 // default method e.g. implement XDefaultMethod
1247 // 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 )
1248 if ( aDescPut || ( aDescGet && aDescGet->cParams == 0 ) )
1249 m_bHasDfltProperty = true;
1250 if ( aDescGet->cParams > 0 )
1251 m_bHasDfltMethod = true;
1252 if ( m_bHasDfltProperty || m_bHasDfltMethod )
1253 m_sDefaultMember = usName;
1256 catch ( const BridgeRuntimeError & e )
1258 throw RuntimeException( e.message );
1260 catch( const Exception& e )
1262 throw RuntimeException(
1263 "[automation bridge] unexpected exception in IUnknownWrapper_Impl::initialiase() error message: \n" + e.Message );
1269 // XDirectInvocation
1270 uno::Any SAL_CALL IUnknownWrapper_Impl::directInvoke( const OUString& aName, const uno::Sequence< uno::Any >& aParams )
1271 throw (lang::IllegalArgumentException, script::CannotConvertException, reflection::InvocationTargetException, uno::RuntimeException)
1273 Any aResult;
1275 if ( !m_spDispatch )
1277 throw RuntimeException(
1278 "[automation bridge] The object does not have an IDispatch interface");
1281 o2u_attachCurrentThread();
1282 DISPID dispid;
1283 if ( !getDispid( aName, &dispid ) )
1284 throw IllegalArgumentException(
1285 "[automation bridge] The object does not have a function or property "
1286 + aName, Reference<XInterface>(), 0);
1288 CComVariant varResult;
1289 ExcepInfo excepinfo;
1290 unsigned int uArgErr = 0;
1291 INVOKEKIND pInvkinds[2];
1292 pInvkinds[0] = INVOKE_FUNC;
1293 pInvkinds[1] = aParams.getLength() ? INVOKE_PROPERTYPUT : INVOKE_PROPERTYGET;
1294 HRESULT hInvRes = E_FAIL;
1296 // try Invoke first, if it does not work, try put/get property
1297 for ( sal_Int32 nStep = 0; FAILED( hInvRes ) && nStep < 2; nStep++ )
1299 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1301 scoped_array<DISPID> arDispidNamedArgs;
1302 scoped_array<CComVariant> ptrArgs;
1303 scoped_array<CComVariant> ptrRefArgs; // referenced arguments
1304 CComVariant * arArgs = NULL;
1305 CComVariant * arRefArgs = NULL;
1307 dispparams.cArgs = aParams.getLength();
1309 // Determine the number of named arguments
1310 for ( sal_Int32 nInd = 0; nInd < aParams.getLength(); nInd++ )
1311 if ( aParams[nInd].getValueType() == cppu::UnoType<NamedArgument>::get() )
1312 dispparams.cNamedArgs ++;
1314 // fill the named arguments
1315 if ( dispparams.cNamedArgs > 0
1316 && !( dispparams.cNamedArgs == 1 && pInvkinds[nStep] == INVOKE_PROPERTYPUT ) )
1318 int nSizeAr = dispparams.cNamedArgs + 1;
1319 if ( pInvkinds[nStep] == INVOKE_PROPERTYPUT )
1320 nSizeAr = dispparams.cNamedArgs;
1322 scoped_array<OLECHAR*> saNames(new OLECHAR*[nSizeAr]);
1323 OLECHAR ** pNames = saNames.get();
1324 pNames[0] = const_cast<OLECHAR*>(reinterpret_cast<LPCOLESTR>(aName.getStr()));
1326 int cNamedArg = 0;
1327 for ( size_t nInd = 0; nInd < dispparams.cArgs; nInd++ )
1329 if ( aParams[nInd].getValueType() == cppu::UnoType<NamedArgument>::get())
1331 const NamedArgument& arg = *(NamedArgument const*)aParams[nInd].getValue();
1333 //We put the parameter names in reverse order into the array,
1334 //so we can use the DISPID array for DISPPARAMS::rgdispidNamedArgs
1335 //The first name in the array is the method name
1336 pNames[nSizeAr - 1 - cNamedArg++] = const_cast<OLECHAR*>(reinterpret_cast<LPCOLESTR>(arg.Name.getStr()));
1340 arDispidNamedArgs.reset( new DISPID[nSizeAr] );
1341 HRESULT hr = getTypeInfo()->GetIDsOfNames( pNames, nSizeAr, arDispidNamedArgs.get() );
1342 if ( hr == E_NOTIMPL )
1343 hr = m_spDispatch->GetIDsOfNames(IID_NULL, pNames, nSizeAr, LOCALE_USER_DEFAULT, arDispidNamedArgs.get() );
1345 if ( SUCCEEDED( hr ) )
1347 if ( pInvkinds[nStep] == DISPATCH_PROPERTYPUT )
1349 DISPID* arIDs = arDispidNamedArgs.get();
1350 arIDs[0] = DISPID_PROPERTYPUT;
1351 dispparams.rgdispidNamedArgs = arIDs;
1353 else
1355 DISPID* arIDs = arDispidNamedArgs.get();
1356 dispparams.rgdispidNamedArgs = & arIDs[1];
1359 else if (hr == DISP_E_UNKNOWNNAME)
1361 throw IllegalArgumentException(
1362 "[automation bridge]One of the named arguments is wrong!",
1363 Reference<XInterface>(), 0);
1365 else
1367 throw InvocationTargetException(
1368 "[automation bridge] ITypeInfo::GetIDsOfNames returned error "
1369 + OUString::number((sal_Int32) hr, 16), Reference<XInterface>(), Any());
1373 //Convert arguments
1374 ptrArgs.reset(new CComVariant[dispparams.cArgs]);
1375 ptrRefArgs.reset(new CComVariant[dispparams.cArgs]);
1376 arArgs = ptrArgs.get();
1377 arRefArgs = ptrRefArgs.get();
1379 sal_Int32 nInd = 0;
1382 sal_Int32 revIndex = 0;
1383 for ( nInd = 0; nInd < sal_Int32(dispparams.cArgs); nInd++)
1385 revIndex = dispparams.cArgs - nInd - 1;
1386 arRefArgs[revIndex].byref = 0;
1387 Any anyArg;
1388 if ( nInd < aParams.getLength() )
1389 anyArg = aParams.getConstArray()[nInd];
1391 // Property Put arguments
1392 if ( anyArg.getValueType() == cppu::UnoType<PropertyPutArgument>::get() )
1394 PropertyPutArgument arg;
1395 anyArg >>= arg;
1396 anyArg <<= arg.Value;
1398 // named argument
1399 if (anyArg.getValueType() == cppu::UnoType<NamedArgument>::get())
1401 NamedArgument aNamedArgument;
1402 anyArg >>= aNamedArgument;
1403 anyArg <<= aNamedArgument.Value;
1406 if ( nInd < aParams.getLength() && anyArg.getValueTypeClass() != TypeClass_VOID )
1408 anyToVariant( &arArgs[revIndex], anyArg, VT_VARIANT );
1410 else
1412 arArgs[revIndex].vt = VT_ERROR;
1413 arArgs[revIndex].scode = DISP_E_PARAMNOTFOUND;
1417 catch (IllegalArgumentException & e)
1419 e.ArgumentPosition = ::sal::static_int_cast< sal_Int16, sal_Int32 >( nInd );
1420 throw;
1422 catch (CannotConvertException & e)
1424 e.ArgumentIndex = nInd;
1425 throw;
1428 dispparams.rgvarg = arArgs;
1429 // invoking OLE method
1430 DWORD localeId = LOCALE_USER_DEFAULT;
1431 hInvRes = m_spDispatch->Invoke( dispid,
1432 IID_NULL,
1433 localeId,
1434 ::sal::static_int_cast< WORD, INVOKEKIND >( pInvkinds[nStep] ),
1435 &dispparams,
1436 &varResult,
1437 &excepinfo,
1438 &uArgErr);
1441 // converting return value and out parameter back to UNO
1442 if ( SUCCEEDED( hInvRes ) )
1443 variantToAny( &varResult, aResult, sal_False );
1444 else
1446 // map error codes to exceptions
1447 OUString message;
1448 switch ( hInvRes )
1450 case S_OK:
1451 break;
1452 case DISP_E_BADPARAMCOUNT:
1453 throw IllegalArgumentException("[automation bridge] Wrong "
1454 "number of arguments. Object returned DISP_E_BADPARAMCOUNT.",
1455 0, 0);
1456 break;
1457 case DISP_E_BADVARTYPE:
1458 throw RuntimeException("[automation bridge] One or more "
1459 "arguments have the wrong type. Object returned "
1460 "DISP_E_BADVARTYPE.", 0);
1461 break;
1462 case DISP_E_EXCEPTION:
1463 message = "[automation bridge]: ";
1464 message += OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription),
1465 ::SysStringLen(excepinfo.bstrDescription));
1466 throw InvocationTargetException(message, Reference<XInterface>(), Any());
1467 break;
1468 case DISP_E_MEMBERNOTFOUND:
1469 message = "[automation bridge]: A function with the name \""
1470 + aName + "\" is not supported. Object returned "
1471 "DISP_E_MEMBERNOTFOUND.";
1472 throw IllegalArgumentException(message, 0, 0);
1473 break;
1474 case DISP_E_NONAMEDARGS:
1475 throw IllegalArgumentException("[automation bridge] Object "
1476 "returned DISP_E_NONAMEDARGS",0, ::sal::static_int_cast< sal_Int16, unsigned int >( uArgErr ));
1477 break;
1478 case DISP_E_OVERFLOW:
1479 throw CannotConvertException("[automation bridge] Call failed.",
1480 static_cast<XInterface*>(
1481 static_cast<XWeak*>(this)), TypeClass_UNKNOWN, FailReason::OUT_OF_RANGE, uArgErr);
1482 break;
1483 case DISP_E_PARAMNOTFOUND:
1484 throw IllegalArgumentException("[automation bridge]Call failed."
1485 "Object returned DISP_E_PARAMNOTFOUND.",
1486 0, ::sal::static_int_cast< sal_Int16, unsigned int >( uArgErr ));
1487 break;
1488 case DISP_E_TYPEMISMATCH:
1489 throw CannotConvertException("[automation bridge] Call failed. "
1490 "Object returned DISP_E_TYPEMISMATCH",
1491 static_cast<XInterface*>(
1492 static_cast<XWeak*>(this)) , TypeClass_UNKNOWN, FailReason::UNKNOWN, uArgErr);
1493 break;
1494 case DISP_E_UNKNOWNINTERFACE:
1495 throw RuntimeException("[automation bridge] Call failed. "
1496 "Object returned DISP_E_UNKNOWNINTERFACE.",0);
1497 break;
1498 case DISP_E_UNKNOWNLCID:
1499 throw RuntimeException("[automation bridge] Call failed. "
1500 "Object returned DISP_E_UNKNOWNLCID.",0);
1501 break;
1502 case DISP_E_PARAMNOTOPTIONAL:
1503 throw CannotConvertException("[automation bridge] Call failed."
1504 "Object returned DISP_E_PARAMNOTOPTIONAL",
1505 static_cast<XInterface*>(static_cast<XWeak*>(this)),
1506 TypeClass_UNKNOWN, FailReason::NO_DEFAULT_AVAILABLE, uArgErr);
1507 break;
1508 default:
1509 throw RuntimeException();
1510 break;
1514 return aResult;
1517 sal_Bool SAL_CALL IUnknownWrapper_Impl::hasMember( const OUString& aName )
1518 throw (uno::RuntimeException)
1520 if ( ! m_spDispatch )
1522 throw RuntimeException(
1523 "[automation bridge] The object does not have an IDispatch interface");
1526 o2u_attachCurrentThread();
1527 DISPID dispid;
1528 return getDispid( aName, &dispid );
1532 // UnoConversionUtilities --------------------------------------------------------------------------------
1533 Reference< XInterface > IUnknownWrapper_Impl::createUnoWrapperInstance()
1535 if( m_nUnoWrapperClass == INTERFACE_OLE_WRAPPER_IMPL)
1537 Reference<XWeak> xWeak= static_cast<XWeak*>( new InterfaceOleWrapper_Impl(
1538 m_smgr, m_nUnoWrapperClass, m_nComWrapperClass));
1539 return Reference<XInterface>( xWeak, UNO_QUERY);
1541 else if( m_nUnoWrapperClass == UNO_OBJECT_WRAPPER_REMOTE_OPT)
1543 Reference<XWeak> xWeak= static_cast<XWeak*>( new UnoObjectWrapperRemoteOpt(
1544 m_smgr, m_nUnoWrapperClass, m_nComWrapperClass));
1545 return Reference<XInterface>( xWeak, UNO_QUERY);
1547 else
1548 return Reference<XInterface>();
1550 Reference<XInterface> IUnknownWrapper_Impl::createComWrapperInstance()
1552 Reference<XWeak> xWeak= static_cast<XWeak*>( new IUnknownWrapper_Impl(
1553 m_smgr, m_nUnoWrapperClass, m_nComWrapperClass));
1554 return Reference<XInterface>( xWeak, UNO_QUERY);
1559 void IUnknownWrapper_Impl::getMethodInfo(const OUString& sName, TypeDescription& methodInfo)
1561 TypeDescription desc= getInterfaceMemberDescOfCurrentCall(sName);
1562 if( desc.is())
1564 typelib_TypeDescription* pMember= desc.get();
1565 if( pMember->eTypeClass == TypeClass_INTERFACE_METHOD )
1566 methodInfo= pMember;
1570 void IUnknownWrapper_Impl::getAttributeInfo(const OUString& sName, TypeDescription& attributeInfo)
1572 TypeDescription desc= getInterfaceMemberDescOfCurrentCall(sName);
1573 if( desc.is())
1575 typelib_TypeDescription* pMember= desc.get();
1576 if( pMember->eTypeClass == TypeClass_INTERFACE_ATTRIBUTE )
1578 attributeInfo= ((typelib_InterfaceAttributeTypeDescription*)pMember)->pAttributeTypeRef;
1582 TypeDescription IUnknownWrapper_Impl::getInterfaceMemberDescOfCurrentCall(const OUString& sName)
1584 TypeDescription ret;
1586 for( sal_Int32 i=0; i < m_seqTypes.getLength(); i++)
1588 TypeDescription _curDesc( m_seqTypes[i]);
1589 _curDesc.makeComplete();
1590 typelib_InterfaceTypeDescription * pInterface= (typelib_InterfaceTypeDescription*) _curDesc.get();
1591 if( pInterface)
1593 typelib_InterfaceMemberTypeDescription* pMember= NULL;
1594 //find the member description of the current call
1595 for( int i=0; i < pInterface->nAllMembers; i++)
1597 typelib_TypeDescriptionReference* pTypeRefMember = pInterface->ppAllMembers[i];
1598 typelib_TypeDescription* pDescMember= NULL;
1599 TYPELIB_DANGER_GET( &pDescMember, pTypeRefMember);
1601 typelib_InterfaceMemberTypeDescription* pInterfaceMember=
1602 (typelib_InterfaceMemberTypeDescription*) pDescMember;
1603 if( OUString( pInterfaceMember->pMemberName) == sName)
1605 pMember= pInterfaceMember;
1606 break;
1608 TYPELIB_DANGER_RELEASE( pDescMember);
1611 if( pMember)
1613 ret= (typelib_TypeDescription*)pMember;
1614 TYPELIB_DANGER_RELEASE( (typelib_TypeDescription*)pMember);
1617 if( ret.is())
1618 break;
1620 return ret;
1623 sal_Bool IUnknownWrapper_Impl::isJScriptObject()
1625 if( m_eJScript == JScriptUndefined)
1627 CComDispatchDriver disp( m_spDispatch);
1628 if( disp)
1630 CComVariant result;
1631 if( SUCCEEDED( disp.GetPropertyByName( JSCRIPT_ID_PROPERTY, &result)))
1633 if(result.vt == VT_BSTR)
1635 CComBSTR name( result.bstrVal);
1636 name.ToLower();
1637 if( name == CComBSTR(JSCRIPT_ID))
1638 m_eJScript= IsJScript;
1642 if( m_eJScript == JScriptUndefined)
1643 m_eJScript= NoJScript;
1646 return m_eJScript == NoJScript ? sal_False : sal_True;
1651 /** @internal
1652 The function ultimately calls IDispatch::Invoke on the wrapped COM object.
1653 The COM object does not implement UNO Interfaces ( via IDispatch). This
1654 is the case when the OleObjectFactory service has been used to create a
1655 component.
1656 @exception IllegalArgumentException
1657 @exception CannotConvertException
1658 @InvocationTargetException
1659 @RuntimeException
1660 @BridgeRuntimeError
1662 Any IUnknownWrapper_Impl::invokeWithDispIdComTlb(const OUString& sFuncName,
1663 const Sequence< Any >& Params,
1664 Sequence< sal_Int16 >& OutParamIndex,
1665 Sequence< Any >& OutParam)
1667 // Get type info for the call. It can be a method call or property put or
1668 // property get operation.
1669 FuncDesc aFuncDesc(getTypeInfo());
1670 getFuncDescForInvoke(sFuncName, Params, & aFuncDesc);
1671 return invokeWithDispIdComTlb( aFuncDesc, sFuncName, Params, OutParamIndex, OutParam );
1674 Any IUnknownWrapper_Impl::invokeWithDispIdComTlb(FuncDesc& aFuncDesc,
1675 const OUString& sFuncName,
1676 const Sequence< Any >& Params,
1677 Sequence< sal_Int16 >& OutParamIndex,
1678 Sequence< Any >& OutParam)
1680 Any ret;
1681 HRESULT result;
1683 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1684 CComVariant varResult;
1685 ExcepInfo excepinfo;
1686 unsigned int uArgErr;
1687 sal_Int32 i = 0;
1688 sal_Int32 nUnoArgs = Params.getLength();
1689 DISPID idPropertyPut = DISPID_PROPERTYPUT;
1690 scoped_array<DISPID> arDispidNamedArgs;
1691 scoped_array<CComVariant> ptrArgs;
1692 scoped_array<CComVariant> ptrRefArgs; // referenced arguments
1693 CComVariant * arArgs = NULL;
1694 CComVariant * arRefArgs = NULL;
1695 sal_Int32 revIndex = 0;
1697 //Set the array of DISPIDs for named args if it is a property put operation.
1698 //If there are other named arguments another array is set later on.
1699 if (aFuncDesc->invkind == INVOKE_PROPERTYPUT
1700 || aFuncDesc->invkind == INVOKE_PROPERTYPUTREF)
1701 dispparams.rgdispidNamedArgs = & idPropertyPut;
1703 //Determine the number of named arguments
1704 for (int iParam = 0; iParam < nUnoArgs; iParam ++)
1706 const Any & curArg = Params[iParam];
1707 if (curArg.getValueType() == cppu::UnoType<NamedArgument>::get())
1708 dispparams.cNamedArgs ++;
1710 //In a property put operation a property value is a named argument (DISPID_PROPERTYPUT).
1711 //Therefore the number of named arguments is increased by one.
1712 //Although named, the argument is not named in an actual language, such as Basic,
1713 //therefore it is never a com.sun.star.bridge.oleautomation.NamedArgument
1714 if (aFuncDesc->invkind == DISPATCH_PROPERTYPUT
1715 || aFuncDesc->invkind == DISPATCH_PROPERTYPUTREF)
1716 dispparams.cNamedArgs ++;
1718 //Determine the number of all arguments and named arguments
1719 if (aFuncDesc->cParamsOpt == -1)
1721 //Attribute vararg is set on this method. "Unlimited" number of args
1722 //supported. There can be no optional or defaultvalue on any of the arguments.
1723 dispparams.cArgs = nUnoArgs;
1725 else
1727 //If there are namesd arguments, then the dispparams.cArgs
1728 //is the number of supplied args, otherwise it is the expected number.
1729 if (dispparams.cNamedArgs)
1730 dispparams.cArgs = nUnoArgs;
1731 else
1732 dispparams.cArgs = aFuncDesc->cParams;
1735 //check if there are not to many arguments supplied
1736 if (::sal::static_int_cast< sal_uInt32, int >( nUnoArgs ) > dispparams.cArgs)
1738 OUStringBuffer buf(256);
1739 buf.appendAscii("[automation bridge] There are too many arguments for this method");
1740 throw IllegalArgumentException( buf.makeStringAndClear(),
1741 Reference<XInterface>(), (sal_Int16) dispparams.cArgs);
1744 //Set up the array of DISPIDs (DISPPARAMS::rgdispidNamedArgs)
1745 //for the named arguments.
1746 //If there is only one named arg and if it is because of a property put
1747 //operation, then we need not set up the DISPID array.
1748 if (dispparams.cNamedArgs > 0 &&
1749 ! (dispparams.cNamedArgs == 1 &&
1750 (aFuncDesc->invkind == INVOKE_PROPERTYPUT ||
1751 aFuncDesc->invkind == INVOKE_PROPERTYPUTREF)))
1753 //set up an array containing the member and parameter names
1754 //which is then used in ITypeInfo::GetIDsOfNames
1755 //First determine the size of the array of names which is passed to
1756 //ITypeInfo::GetIDsOfNames. It must hold the method names + the named
1757 //args.
1758 int nSizeAr = dispparams.cNamedArgs + 1;
1759 if (aFuncDesc->invkind == INVOKE_PROPERTYPUT
1760 || aFuncDesc->invkind == INVOKE_PROPERTYPUTREF)
1762 nSizeAr = dispparams.cNamedArgs; //counts the DISID_PROPERTYPUT
1765 scoped_array<OLECHAR*> saNames(new OLECHAR*[nSizeAr]);
1766 OLECHAR ** arNames = saNames.get();
1767 arNames[0] = const_cast<OLECHAR*>(reinterpret_cast<LPCOLESTR>(sFuncName.getStr()));
1769 int cNamedArg = 0;
1770 for (size_t iParams = 0; iParams < dispparams.cArgs; iParams ++)
1772 const Any & curArg = Params[iParams];
1773 if (curArg.getValueType() == cppu::UnoType<NamedArgument>::get())
1775 const NamedArgument& arg = *(NamedArgument const*) curArg.getValue();
1776 //We put the parameter names in reverse order into the array,
1777 //so we can use the DISPID array for DISPPARAMS::rgdispidNamedArgs
1778 //The first name in the array is the method name
1779 arNames[nSizeAr - 1 - cNamedArg++] = const_cast<OLECHAR*>(reinterpret_cast<LPCOLESTR>(arg.Name.getStr()));
1783 //Prepare the array of DISPIDs for ITypeInfo::GetIDsOfNames
1784 //it must be big enough to contain the DISPIDs of the member + parameters
1785 arDispidNamedArgs.reset(new DISPID[nSizeAr]);
1786 HRESULT hr = getTypeInfo()->GetIDsOfNames(arNames, nSizeAr,
1787 arDispidNamedArgs.get());
1788 if ( hr == E_NOTIMPL )
1789 hr = m_spDispatch->GetIDsOfNames(IID_NULL, arNames, nSizeAr, LOCALE_USER_DEFAULT, arDispidNamedArgs.get() );
1791 if (hr == S_OK)
1793 // In a "property put" operation, the property value is a named param with the
1794 //special DISPID DISPID_PROPERTYPUT
1795 if (aFuncDesc->invkind == DISPATCH_PROPERTYPUT
1796 || aFuncDesc->invkind == DISPATCH_PROPERTYPUTREF)
1798 //Element at index 0 in the DISPID array must be DISPID_PROPERTYPUT
1799 //The first item in the array arDispidNamedArgs is the DISPID for
1800 //the method. We replace it with DISPID_PROPERTYPUT.
1801 DISPID* arIDs = arDispidNamedArgs.get();
1802 arIDs[0] = DISPID_PROPERTYPUT;
1803 dispparams.rgdispidNamedArgs = arIDs;
1805 else
1807 //The first item in the array arDispidNamedArgs is the DISPID for
1808 //the method. It must be removed
1809 DISPID* arIDs = arDispidNamedArgs.get();
1810 dispparams.rgdispidNamedArgs = & arIDs[1];
1813 else if (hr == DISP_E_UNKNOWNNAME)
1815 throw IllegalArgumentException(
1816 "[automation bridge]One of the named arguments is wrong!",
1817 Reference<XInterface>(), 0);
1819 else
1821 throw InvocationTargetException(
1822 "[automation bridge] ITypeInfo::GetIDsOfNames returned error "
1823 + OUString::number((sal_Int32) hr, 16), Reference<XInterface>(), Any());
1827 //Convert arguments
1828 ptrArgs.reset(new CComVariant[dispparams.cArgs]);
1829 ptrRefArgs.reset(new CComVariant[dispparams.cArgs]);
1830 arArgs = ptrArgs.get();
1831 arRefArgs = ptrRefArgs.get();
1834 for (i = 0; i < (sal_Int32) dispparams.cArgs; i++)
1836 revIndex= dispparams.cArgs - i -1;
1837 arRefArgs[revIndex].byref=0;
1838 Any anyArg;
1839 if ( i < nUnoArgs)
1840 anyArg= Params.getConstArray()[i];
1842 unsigned short paramFlags = PARAMFLAG_FOPT | PARAMFLAG_FIN;
1843 VARTYPE varType = VT_VARIANT;
1844 if (aFuncDesc->cParamsOpt != -1 || aFuncDesc->cParams != (i + 1))
1846 paramFlags = aFuncDesc->lprgelemdescParam[i].paramdesc.wParamFlags;
1847 varType = getElementTypeDesc(&aFuncDesc->lprgelemdescParam[i].tdesc);
1850 // Make sure that there is a UNO parameter for every
1851 // expected parameter. If there is no UNO parameter where the
1852 // called function expects one, then it must be optional. Otherwise
1853 // it's a UNO programming error.
1854 if (i >= nUnoArgs && !(paramFlags & PARAMFLAG_FOPT))
1856 OUStringBuffer buf(256);
1857 buf.appendAscii("ole automation bridge: The called function expects an argument at"
1858 "position: "); //a different number of arguments")),
1859 buf.append(OUString::number((sal_Int32) i));
1860 buf.appendAscii(" (index starting at 0).");
1861 throw IllegalArgumentException( buf.makeStringAndClear(),
1862 Reference<XInterface>(), (sal_Int16) i);
1865 // Property Put arguments
1866 if (anyArg.getValueType() == cppu::UnoType<PropertyPutArgument>::get())
1868 PropertyPutArgument arg;
1869 anyArg >>= arg;
1870 anyArg <<= arg.Value;
1872 // named argument
1873 if (anyArg.getValueType() == cppu::UnoType<NamedArgument>::get())
1875 NamedArgument aNamedArgument;
1876 anyArg >>= aNamedArgument;
1877 anyArg <<= aNamedArgument.Value;
1879 // out param
1880 if (paramFlags & PARAMFLAG_FOUT &&
1881 ! (paramFlags & PARAMFLAG_FIN) )
1883 VARTYPE type = ::sal::static_int_cast< VARTYPE, int >( varType ^ VT_BYREF );
1884 if (i < nUnoArgs)
1886 arRefArgs[revIndex].vt= type;
1888 else
1890 //optional arg
1891 arRefArgs[revIndex].vt = VT_ERROR;
1892 arRefArgs[revIndex].scode = DISP_E_PARAMNOTFOUND;
1894 if( type == VT_VARIANT )
1896 arArgs[revIndex].vt= VT_VARIANT | VT_BYREF;
1897 arArgs[revIndex].byref= &arRefArgs[revIndex];
1899 else
1901 arArgs[revIndex].vt= varType;
1902 if (type == VT_DECIMAL)
1903 arArgs[revIndex].byref= & arRefArgs[revIndex].decVal;
1904 else
1905 arArgs[revIndex].byref= & arRefArgs[revIndex].byref;
1908 // in/out + in byref params
1909 else if (varType & VT_BYREF)
1911 VARTYPE type = ::sal::static_int_cast< VARTYPE, int >( varType ^ VT_BYREF );
1912 CComVariant var;
1914 if (i < nUnoArgs && anyArg.getValueTypeClass() != TypeClass_VOID)
1916 anyToVariant( & arRefArgs[revIndex], anyArg, type);
1918 else if (paramFlags & PARAMFLAG_FHASDEFAULT)
1920 //optional arg with default
1921 VariantCopy( & arRefArgs[revIndex],
1922 & aFuncDesc->lprgelemdescParam[i].paramdesc.
1923 pparamdescex->varDefaultValue);
1925 else
1927 //optional arg
1928 //e.g: call func(x) in basic : func() ' no arg supplied
1929 OSL_ASSERT(paramFlags & PARAMFLAG_FOPT);
1930 arRefArgs[revIndex].vt = VT_ERROR;
1931 arRefArgs[revIndex].scode = DISP_E_PARAMNOTFOUND;
1934 // Set the converted arguments in the array which will be
1935 // DISPPARAMS::rgvarg
1936 // byref arg VT_XXX |VT_BYREF
1937 arArgs[revIndex].vt = varType;
1938 if (revIndex == 0 && aFuncDesc->invkind == INVOKE_PROPERTYPUT)
1940 arArgs[revIndex] = arRefArgs[revIndex];
1942 else if (type == VT_DECIMAL)
1944 arArgs[revIndex].byref= & arRefArgs[revIndex].decVal;
1946 else if (type == VT_VARIANT)
1948 if ( ! (paramFlags & PARAMFLAG_FOUT))
1949 arArgs[revIndex] = arRefArgs[revIndex];
1950 else
1951 arArgs[revIndex].byref = & arRefArgs[revIndex];
1953 else
1955 arArgs[revIndex].byref = & arRefArgs[revIndex].byref;
1956 arArgs[revIndex].vt = ::sal::static_int_cast< VARTYPE, int >( arRefArgs[revIndex].vt | VT_BYREF );
1960 // in parameter no VT_BYREF except for array, interfaces
1961 else
1962 { // void any stands for optional param
1963 if (i < nUnoArgs && anyArg.getValueTypeClass() != TypeClass_VOID)
1965 anyToVariant( & arArgs[revIndex], anyArg, varType);
1967 //optional arg but no void any supplied
1968 //Basic: obj.func() ' first parameter left out because it is optional
1969 else if (paramFlags & PARAMFLAG_FHASDEFAULT)
1971 //optional arg with defaulteithter as direct arg : VT_XXX or
1972 VariantCopy( & arArgs[revIndex],
1973 & aFuncDesc->lprgelemdescParam[i].paramdesc.
1974 pparamdescex->varDefaultValue);
1976 else if (paramFlags & PARAMFLAG_FOPT)
1978 arArgs[revIndex].vt = VT_ERROR;
1979 arArgs[revIndex].scode = DISP_E_PARAMNOTFOUND;
1981 else
1983 arArgs[revIndex].vt = VT_EMPTY;
1984 arArgs[revIndex].lVal = 0;
1989 catch (IllegalArgumentException & e)
1991 e.ArgumentPosition = ::sal::static_int_cast< sal_Int16, sal_Int32 >( i );
1992 throw;
1994 catch (CannotConvertException & e)
1996 e.ArgumentIndex = i;
1997 throw;
1999 dispparams.rgvarg= arArgs;
2000 // invoking OLE method
2001 DWORD localeId = LOCALE_USER_DEFAULT;
2002 result = m_spDispatch->Invoke(aFuncDesc->memid,
2003 IID_NULL,
2004 localeId,
2005 ::sal::static_int_cast< WORD, INVOKEKIND >( aFuncDesc->invkind ),
2006 &dispparams,
2007 &varResult,
2008 &excepinfo,
2009 &uArgErr);
2011 // converting return value and out parameter back to UNO
2012 if (result == S_OK)
2015 // allocate space for the out param Sequence and indices Sequence
2016 int outParamsCount= 0; // includes in/out parameter
2017 for (int i = 0; i < aFuncDesc->cParams; i++)
2019 if (aFuncDesc->lprgelemdescParam[i].paramdesc.wParamFlags &
2020 PARAMFLAG_FOUT)
2021 outParamsCount++;
2024 OutParamIndex.realloc(outParamsCount);
2025 OutParam.realloc(outParamsCount);
2026 // Convert out params
2027 if (outParamsCount)
2029 int outParamIndex=0;
2030 for (int paramIndex = 0; paramIndex < nUnoArgs; paramIndex ++)
2032 //Determine the index within the method sinature
2033 int realParamIndex = paramIndex;
2034 int revParamIndex = dispparams.cArgs - paramIndex - 1;
2035 if (Params[paramIndex].getValueType()
2036 == cppu::UnoType<NamedArgument>::get())
2038 //dispparams.rgdispidNamedArgs contains the mapping from index
2039 //of named args list to index of parameter list
2040 realParamIndex = dispparams.rgdispidNamedArgs[revParamIndex];
2043 // no named arg, always come before named args
2044 if (! (aFuncDesc->lprgelemdescParam[realParamIndex].paramdesc.wParamFlags
2045 & PARAMFLAG_FOUT))
2046 continue;
2047 Any outAny;
2048 // variantToAny is called with the "reduce range" parameter set to sal_False.
2049 // That causes VT_I4 values not to be converted down to a "lower" type. That
2050 // feature exist for JScript only because it only uses VT_I4 for integer types.
2053 variantToAny( & arRefArgs[revParamIndex], outAny, sal_False );
2055 catch (IllegalArgumentException & e)
2057 e.ArgumentPosition = (sal_Int16)paramIndex;
2058 throw;
2060 catch (CannotConvertException & e)
2062 e.ArgumentIndex = paramIndex;
2063 throw;
2065 OutParam[outParamIndex] = outAny;
2066 OutParamIndex[outParamIndex] = ::sal::static_int_cast< sal_Int16, int >( paramIndex );
2067 outParamIndex++;
2069 OutParam.realloc(outParamIndex);
2070 OutParamIndex.realloc(outParamIndex);
2072 // Return value
2073 variantToAny(&varResult, ret, sal_False);
2076 // map error codes to exceptions
2077 OUString message;
2078 switch (result)
2080 case S_OK:
2081 break;
2082 case DISP_E_BADPARAMCOUNT:
2083 throw IllegalArgumentException("[automation bridge] Wrong "
2084 "number of arguments. Object returned DISP_E_BADPARAMCOUNT.",
2085 0, 0);
2086 break;
2087 case DISP_E_BADVARTYPE:
2088 throw RuntimeException("[automation bridge] One or more "
2089 "arguments have the wrong type. Object returned "
2090 "DISP_E_BADVARTYPE.", 0);
2091 break;
2092 case DISP_E_EXCEPTION:
2093 message = "[automation bridge]: ";
2094 message += OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription),
2095 ::SysStringLen(excepinfo.bstrDescription));
2097 throw InvocationTargetException(message, Reference<XInterface>(), Any());
2098 break;
2099 case DISP_E_MEMBERNOTFOUND:
2100 message = "[automation bridge]: A function with the name \""
2101 + sFuncName + "\" is not supported. Object returned "
2102 "DISP_E_MEMBERNOTFOUND.";
2103 throw IllegalArgumentException(message, 0, 0);
2104 break;
2105 case DISP_E_NONAMEDARGS:
2106 throw IllegalArgumentException("[automation bridge] Object "
2107 "returned DISP_E_NONAMEDARGS",0, ::sal::static_int_cast< sal_Int16, unsigned int >( uArgErr ));
2108 break;
2109 case DISP_E_OVERFLOW:
2110 throw CannotConvertException("[automation bridge] Call failed.",
2111 static_cast<XInterface*>(
2112 static_cast<XWeak*>(this)), TypeClass_UNKNOWN, FailReason::OUT_OF_RANGE, uArgErr);
2113 break;
2114 case DISP_E_PARAMNOTFOUND:
2115 throw IllegalArgumentException("[automation bridge]Call failed."
2116 "Object returned DISP_E_PARAMNOTFOUND.",
2117 0, ::sal::static_int_cast< sal_Int16, unsigned int >( uArgErr ));
2118 break;
2119 case DISP_E_TYPEMISMATCH:
2120 throw CannotConvertException("[automation bridge] Call failed. "
2121 "Object returned DISP_E_TYPEMISMATCH",
2122 static_cast<XInterface*>(
2123 static_cast<XWeak*>(this)) , TypeClass_UNKNOWN, FailReason::UNKNOWN, uArgErr);
2124 break;
2125 case DISP_E_UNKNOWNINTERFACE:
2126 throw RuntimeException("[automation bridge] Call failed. "
2127 "Object returned DISP_E_UNKNOWNINTERFACE.",0);
2128 break;
2129 case DISP_E_UNKNOWNLCID:
2130 throw RuntimeException("[automation bridge] Call failed. "
2131 "Object returned DISP_E_UNKNOWNLCID.",0);
2132 break;
2133 case DISP_E_PARAMNOTOPTIONAL:
2134 throw CannotConvertException("[automation bridge] Call failed."
2135 "Object returned DISP_E_PARAMNOTOPTIONAL",
2136 static_cast<XInterface*>(static_cast<XWeak*>(this)),
2137 TypeClass_UNKNOWN, FailReason::NO_DEFAULT_AVAILABLE, uArgErr);
2138 break;
2139 default:
2140 throw RuntimeException();
2141 break;
2144 return ret;
2147 void IUnknownWrapper_Impl::getFuncDescForInvoke(const OUString & sFuncName,
2148 const Sequence<Any> & seqArgs,
2149 FUNCDESC** pFuncDesc)
2151 int nUnoArgs = seqArgs.getLength();
2152 const Any * arArgs = seqArgs.getConstArray();
2153 ITypeInfo* pInfo = getTypeInfo();
2155 //If the last of the positional arguments is a PropertyPutArgument
2156 //then obtain the type info for the property put operation.
2158 //The property value is always the last argument, in a positional argument list
2159 //or in a list of named arguments. A PropertyPutArgument is actually a named argument
2160 //hence it must not be put in an extra NamedArgument structure
2161 if (nUnoArgs > 0 &&
2162 arArgs[nUnoArgs - 1].getValueType() == cppu::UnoType<PropertyPutArgument>::get())
2164 // DISPATCH_PROPERTYPUT
2165 FuncDesc aDescGet(pInfo);
2166 FuncDesc aDescPut(pInfo);
2167 VarDesc aVarDesc(pInfo);
2168 getPropDesc(sFuncName, & aDescGet, & aDescPut, & aVarDesc);
2169 if ( ! aDescPut)
2171 throw IllegalArgumentException(
2172 "[automation bridge] The object does not have a writeable property: "
2173 + sFuncName, Reference<XInterface>(), 0);
2175 *pFuncDesc = aDescPut.Detach();
2177 else
2178 { // DISPATCH_METHOD
2179 FuncDesc aFuncDesc(pInfo);
2180 getFuncDesc(sFuncName, & aFuncDesc);
2181 if ( ! aFuncDesc)
2183 // Fallback: DISPATCH_PROPERTYGET can mostly be called as
2184 // DISPATCH_METHOD
2185 ITypeInfo * pInfo = getTypeInfo();
2186 FuncDesc aDescPut(pInfo);
2187 VarDesc aVarDesc(pInfo);
2188 getPropDesc(sFuncName, & aFuncDesc, & aDescPut, & aVarDesc);
2189 if ( ! aFuncDesc )
2191 throw IllegalArgumentException(
2192 "[automation bridge] The object does not have a function"
2193 "or readable property \""
2194 + sFuncName, Reference<XInterface>(), 0);
2197 *pFuncDesc = aFuncDesc.Detach();
2200 bool IUnknownWrapper_Impl::getDispid(const OUString& sFuncName, DISPID * id)
2202 OSL_ASSERT(m_spDispatch);
2203 LPOLESTR lpsz = const_cast<LPOLESTR> (reinterpret_cast<LPCOLESTR>(sFuncName.getStr()));
2204 HRESULT hr = m_spDispatch->GetIDsOfNames(IID_NULL, &lpsz, 1, LOCALE_USER_DEFAULT, id);
2205 return hr == S_OK;
2207 void IUnknownWrapper_Impl::getFuncDesc(const OUString & sFuncName, FUNCDESC ** pFuncDesc)
2210 OSL_ASSERT( * pFuncDesc == 0);
2211 buildComTlbIndex();
2212 typedef TLBFuncIndexMap::const_iterator cit;
2213 typedef TLBFuncIndexMap::iterator it;
2214 //We assume there is only one entry with the function name. A property
2215 //would have two entries.
2216 cit itIndex= m_mapComFunc.find(sFuncName);
2217 if (itIndex == m_mapComFunc.end())
2219 //try case insensive with IDispatch::GetIDsOfNames
2220 DISPID id;
2221 if (getDispid(sFuncName, &id))
2223 CComBSTR memberName;
2224 unsigned int pcNames=0;
2225 // get the case sensitive name
2226 if( SUCCEEDED(getTypeInfo()->GetNames( id, & memberName, 1, &pcNames)))
2228 //get the associated index and add an entry to the map
2229 //with the name sFuncName which differs in the casing of the letters to
2230 //the actual name as obtained from ITypeInfo
2231 OUString sRealName(reinterpret_cast<const sal_Unicode*>(LPCOLESTR(memberName)));
2232 cit itOrg = m_mapComFunc.find(sRealName);
2233 OSL_ASSERT(itOrg != m_mapComFunc.end());
2234 // maybe this is a property, if so we need
2235 // to store either both id's ( put/get ) or
2236 // just the get. Storing both is more consistent
2237 pair<cit, cit> pItems = m_mapComFunc.equal_range( sRealName );
2238 for ( ;pItems.first != pItems.second; ++pItems.first )
2239 m_mapComFunc.insert( TLBFuncIndexMap::value_type ( make_pair(sFuncName, pItems.first->second ) ));
2240 itIndex =
2241 m_mapComFunc.find( sFuncName );
2246 #if OSL_DEBUG_LEVEL >= 1
2247 // There must only be one entry if sFuncName represents a function or two
2248 // if it is a property
2249 pair<cit, cit> p = m_mapComFunc.equal_range(sFuncName.toAsciiLowerCase());
2250 int numEntries = 0;
2251 for ( ;p.first != p.second; p.first ++, numEntries ++);
2252 OSL_ASSERT( ! (numEntries > 3) );
2253 #endif
2254 if( itIndex != m_mapComFunc.end())
2256 ITypeInfo* pType= getTypeInfo();
2257 FUNCDESC * pDesc = NULL;
2258 if (SUCCEEDED(pType->GetFuncDesc(itIndex->second, & pDesc)))
2260 if (pDesc->invkind == INVOKE_FUNC)
2262 (*pFuncDesc) = pDesc;
2264 else
2266 pType->ReleaseFuncDesc(pDesc);
2269 else
2271 throw BridgeRuntimeError("[automation bridge] Could not get "
2272 "FUNCDESC for " + sFuncName);
2275 //else no entry found for sFuncName, pFuncDesc will not be filled in
2278 void IUnknownWrapper_Impl::getPropDesc(const OUString & sFuncName, FUNCDESC ** pFuncDescGet,
2279 FUNCDESC** pFuncDescPut, VARDESC** pVarDesc)
2281 OSL_ASSERT( * pFuncDescGet == 0 && * pFuncDescPut == 0);
2282 buildComTlbIndex();
2283 typedef TLBFuncIndexMap::const_iterator cit;
2284 pair<cit, cit> p = m_mapComFunc.equal_range(sFuncName);
2285 if (p.first == m_mapComFunc.end())
2287 //try case insensive with IDispatch::GetIDsOfNames
2288 DISPID id;
2289 if (getDispid(sFuncName, &id))
2291 CComBSTR memberName;
2292 unsigned int pcNames=0;
2293 // get the case sensitive name
2294 if( SUCCEEDED(getTypeInfo()->GetNames( id, & memberName, 1, &pcNames)))
2296 //As opposed to getFuncDesc, we do not add the value because we would
2297 // need to find the get and set description for the property. This would
2298 //mean to iterate over all FUNCDESCs again.
2299 p = m_mapComFunc.equal_range(OUString(reinterpret_cast<const sal_Unicode*>(LPCOLESTR(memberName))));
2304 for ( int i = 0 ;p.first != p.second; p.first ++, i ++)
2306 // There are a maximum of two entries, property put and property get
2307 OSL_ASSERT( ! (i > 2) );
2308 ITypeInfo* pType= getTypeInfo();
2309 FUNCDESC * pFuncDesc = NULL;
2310 if (SUCCEEDED( pType->GetFuncDesc(p.first->second, & pFuncDesc)))
2312 if (pFuncDesc->invkind == INVOKE_PROPERTYGET)
2314 (*pFuncDescGet) = pFuncDesc;
2316 else if (pFuncDesc->invkind == INVOKE_PROPERTYPUT ||
2317 pFuncDesc->invkind == INVOKE_PROPERTYPUTREF)
2319 //a property can have 3 entries, put, put ref, get
2320 // If INVOKE_PROPERTYPUTREF or INVOKE_PROPERTYPUT is used
2321 //depends on what is found first.
2322 if ( * pFuncDescPut)
2324 //we already have found one
2325 pType->ReleaseFuncDesc(pFuncDesc);
2327 else
2329 (*pFuncDescPut) = pFuncDesc;
2332 else
2334 pType->ReleaseFuncDesc(pFuncDesc);
2337 //ITypeInfo::GetFuncDesc may even provide a funcdesc for a VARDESC
2338 // with invkind = INVOKE_FUNC. Since this function should only return
2339 //a value for a real property (XInvokation::hasMethod, ..::hasProperty
2340 //we need to make sure that sFuncName represents a real property.
2341 VARDESC * pVD = NULL;
2342 if (SUCCEEDED(pType->GetVarDesc(p.first->second, & pVD)))
2343 (*pVarDesc) = pVD;
2345 //else no entry for sFuncName, pFuncDesc will not be filled in
2348 VARTYPE IUnknownWrapper_Impl::getUserDefinedElementType( ITypeInfo* pTypeInfo, const DWORD nHrefType )
2350 VARTYPE _type( VT_NULL );
2351 if ( pTypeInfo )
2353 CComPtr<ITypeInfo> spRefInfo;
2354 pTypeInfo->GetRefTypeInfo( nHrefType, &spRefInfo.p );
2355 if ( spRefInfo )
2357 TypeAttr attr( spRefInfo );
2358 spRefInfo->GetTypeAttr( &attr );
2359 if ( attr->typekind == TKIND_ENUM )
2361 // We use the type of the first enum value.
2362 if ( attr->cVars == 0 )
2364 throw BridgeRuntimeError("[automation bridge] Could not obtain type description");
2366 VarDesc var( spRefInfo );
2367 spRefInfo->GetVarDesc( 0, &var );
2368 _type = var->lpvarValue->vt;
2370 else if ( attr->typekind == TKIND_INTERFACE )
2372 _type = VT_UNKNOWN;
2374 else if ( attr->typekind == TKIND_DISPATCH )
2376 _type = VT_DISPATCH;
2378 else if ( attr->typekind == TKIND_ALIAS )
2380 // TKIND_ALIAS is a type that is an alias for another type. So get that alias type.
2381 _type = getUserDefinedElementType( pTypeInfo, attr->tdescAlias.hreftype );
2383 else
2385 throw BridgeRuntimeError( "[automation bridge] Unhandled user defined type." );
2389 return _type;
2392 VARTYPE IUnknownWrapper_Impl::getElementTypeDesc(const TYPEDESC *desc)
2394 VARTYPE _type( VT_NULL );
2396 if (desc->vt == VT_PTR)
2398 _type = getElementTypeDesc(desc->lptdesc);
2399 _type |= VT_BYREF;
2401 else if (desc->vt == VT_SAFEARRAY)
2403 _type = getElementTypeDesc(desc->lptdesc);
2404 _type |= VT_ARRAY;
2406 else if (desc->vt == VT_USERDEFINED)
2408 ITypeInfo* thisInfo = getTypeInfo(); //kept by this instance
2409 _type = getUserDefinedElementType( thisInfo, desc->hreftype );
2411 else
2413 _type = desc->vt;
2415 return _type;
2418 void IUnknownWrapper_Impl::buildComTlbIndex()
2420 if ( ! m_bComTlbIndexInit)
2422 MutexGuard guard(getBridgeMutex());
2424 if ( ! m_bComTlbIndexInit)
2426 OUString sError;
2427 ITypeInfo* pType= getTypeInfo();
2428 TypeAttr typeAttr(pType);
2429 if( SUCCEEDED( pType->GetTypeAttr( &typeAttr)))
2431 for( long i= 0; i < typeAttr->cFuncs; i++)
2433 FuncDesc funcDesc(pType);
2434 if( SUCCEEDED( pType->GetFuncDesc( i, &funcDesc)))
2436 CComBSTR memberName;
2437 unsigned int pcNames=0;
2438 if( SUCCEEDED(pType->GetNames( funcDesc->memid, & memberName, 1, &pcNames)))
2440 OUString usName(reinterpret_cast<const sal_Unicode*>(LPCOLESTR(memberName)));
2441 m_mapComFunc.insert( TLBFuncIndexMap::value_type( 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::GetFuncDesc failed.";
2454 //If we create an Object in JScript and a property then it
2455 //has VARDESC instead of FUNCDESC
2456 for (long i = 0; i < typeAttr->cVars; i++)
2458 VarDesc varDesc(pType);
2459 if (SUCCEEDED(pType->GetVarDesc(i, & varDesc)))
2461 CComBSTR memberName;
2462 unsigned int pcNames = 0;
2463 if (SUCCEEDED(pType->GetNames(varDesc->memid, & memberName, 1, &pcNames)))
2465 if (varDesc->varkind == VAR_DISPATCH)
2467 OUString usName(reinterpret_cast<const sal_Unicode*>(LPCOLESTR(memberName)));
2468 m_mapComFunc.insert(TLBFuncIndexMap::value_type(
2469 usName, i));
2472 else
2474 sError = "[automation bridge] IUnknownWrapper_Impl::buildComTlbIndex, "
2475 "ITypeInfo::GetNames failed.";
2478 else
2479 sError = "[automation bridge] IUnknownWrapper_Impl::buildComTlbIndex, "
2480 "ITypeInfo::GetVarDesc failed.";
2484 else
2485 sError = "[automation bridge] IUnknownWrapper_Impl::buildComTlbIndex, "
2486 "ITypeInfo::GetTypeAttr failed.";
2488 if (sError.getLength())
2490 throw BridgeRuntimeError(sError);
2493 m_bComTlbIndexInit = true;
2499 ITypeInfo* IUnknownWrapper_Impl::getTypeInfo()
2501 if( !m_spDispatch)
2503 throw BridgeRuntimeError("The object has no IDispatch interface!");
2506 if( !m_spTypeInfo )
2508 MutexGuard guard(getBridgeMutex());
2509 if( ! m_spTypeInfo)
2511 CComPtr< ITypeInfo > spType;
2512 if( SUCCEEDED( m_spDispatch->GetTypeInfo( 0, LOCALE_USER_DEFAULT, &spType.p)))
2515 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
2517 //If this is a dual interface then TYPEATTR::typekind is usually TKIND_INTERFACE
2518 //We need to get the type description for TKIND_DISPATCH
2519 TypeAttr typeAttr(spType.p);
2520 if( SUCCEEDED(spType->GetTypeAttr( &typeAttr)))
2522 if (typeAttr->typekind == TKIND_INTERFACE &&
2523 typeAttr->wTypeFlags & TYPEFLAG_FDUAL)
2525 HREFTYPE refDispatch;
2526 if (SUCCEEDED(spType->GetRefTypeOfImplType(::sal::static_int_cast< UINT, int >( -1 ), &refDispatch)))
2528 CComPtr<ITypeInfo> spTypeDisp;
2529 if (SUCCEEDED(spType->GetRefTypeInfo(refDispatch, & spTypeDisp)))
2530 m_spTypeInfo= spTypeDisp;
2532 else
2534 throw BridgeRuntimeError(
2535 "[automation bridge] Could not obtain type information "
2536 "for dispatch interface." );
2539 else if (typeAttr->typekind == TKIND_DISPATCH)
2541 m_spTypeInfo= spType;
2543 else
2545 throw BridgeRuntimeError(
2546 "[automation bridge] Automation object does not "
2547 "provide type information.");
2551 else
2553 throw BridgeRuntimeError("[automation bridge]The dispatch object does not "
2554 "support ITypeInfo!");
2558 return m_spTypeInfo;
2561 } // end namespace
2563 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */