merged tag ooo/OOO330_m14
[LibreOffice.git] / extensions / source / ole / oleobjw.cxx
blob89cb5625bca34086843e97591e1bde9dc76c6b84
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
11 * OpenOffice.org is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License version 3
13 * only, as published by the Free Software Foundation.
15 * OpenOffice.org is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License version 3 for more details
19 * (a copy is included in the LICENSE file that accompanied this code).
21 * You should have received a copy of the GNU Lesser General Public License
22 * version 3 along with OpenOffice.org. If not, see
23 * <http://www.openoffice.org/license.html>
24 * for a copy of the LGPLv3 License.
26 ************************************************************************/
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_extensions.hxx"
30 #include "ole2uno.hxx"
31 #include "rtl/ustrbuf.hxx"
34 #include "osl/diagnose.h"
35 #include "osl/doublecheckedlocking.h"
36 #include "osl/thread.h"
38 #include "boost/scoped_array.hpp"
39 #include <com/sun/star/script/FailReason.hpp>
40 #include <com/sun/star/beans/XMaterialHolder.hpp>
41 #include <com/sun/star/script/XTypeConverter.hpp>
42 #include <com/sun/star/script/FinishEngineEvent.hpp>
43 #include <com/sun/star/script/InterruptReason.hpp>
44 #include <com/sun/star/script/XEngineListener.hpp>
45 #include <com/sun/star/script/XDebugging.hpp>
46 #include <com/sun/star/script/XInvocation.hpp>
47 #include <com/sun/star/script/ContextInformation.hpp>
48 #include <com/sun/star/script/FinishReason.hpp>
49 #include <com/sun/star/script/XEngine.hpp>
50 #include <com/sun/star/script/InterruptEngineEvent.hpp>
51 #include <com/sun/star/script/XLibraryAccess.hpp>
52 #include <com/sun/star/bridge/ModelDependent.hpp>
54 #include "com/sun/star/bridge/oleautomation/NamedArgument.hpp"
55 #include "com/sun/star/bridge/oleautomation/PropertyPutArgument.hpp"
57 #include <typelib/typedescription.hxx>
58 #include <rtl/uuid.h>
59 #include <rtl/memory.h>
60 #include <rtl/ustring.hxx>
62 #include "jscriptclasses.hxx"
64 #include "oleobjw.hxx"
65 #include "unoobjw.hxx"
66 #include <stdio.h>
67 using namespace std;
68 using namespace boost;
69 using namespace osl;
70 using namespace rtl;
71 using namespace cppu;
72 using namespace com::sun::star::script;
73 using namespace com::sun::star::lang;
74 using namespace com::sun::star::bridge;
75 using namespace com::sun::star::bridge::oleautomation;
76 using namespace com::sun::star::bridge::ModelDependent;
78 #define JSCRIPT_ID_PROPERTY L"_environment"
79 #define JSCRIPT_ID L"jscript"
80 namespace ole_adapter
84 // key: XInterface pointer created by Invocation Adapter Factory
85 // value: XInterface pointer to the wrapper class.
86 // Entries to the map are made within
87 // Any createOleObjectWrapper(IUnknown* pUnknown, const Type& aType);
88 // Entries are being deleted if the wrapper class's destructor has been
89 // called.
90 // Before UNO object is wrapped to COM object this map is checked
91 // to see if the UNO object is already a wrapper.
92 hash_map<sal_uInt32, sal_uInt32> AdapterToWrapperMap;
93 // key: XInterface of the wrapper object.
94 // value: XInterface of the Interface created by the Invocation Adapter Factory.
95 // A COM wrapper is responsible for removing the corresponding entry
96 // in AdapterToWrappperMap if it is being destroyed. Because the wrapper does not
97 // know about its adapted interface it uses WrapperToAdapterMap to get the
98 // adapted interface which is then used to locate the entry in AdapterToWrapperMap.
99 hash_map<sal_uInt32,sal_uInt32> WrapperToAdapterMap;
101 hash_map<sal_uInt32, WeakReference<XInterface> > ComPtrToWrapperMap;
102 /*****************************************************************************
104 class implementation IUnknownWrapper_Impl
106 *****************************************************************************/
108 IUnknownWrapper_Impl::IUnknownWrapper_Impl( Reference<XMultiServiceFactory>& xFactory,
109 sal_uInt8 unoWrapperClass, sal_uInt8 comWrapperClass):
110 UnoConversionUtilities<IUnknownWrapper_Impl>( xFactory, unoWrapperClass, comWrapperClass),
111 m_pxIdlClass( NULL), m_eJScript( JScriptUndefined),
112 m_bComTlbIndexInit(false), m_bHasDfltMethod(false), m_bHasDfltProperty(false)
117 IUnknownWrapper_Impl::~IUnknownWrapper_Impl()
119 o2u_attachCurrentThread();
120 MutexGuard guard(getBridgeMutex());
121 XInterface * xIntRoot = (OWeakObject *)this;
122 #if OSL_DEBUG_LEVEL > 0
123 acquire(); // make sure we don't delete us twice because of Reference
124 OSL_ASSERT( Reference<XInterface>( static_cast<XWeak*>(this), UNO_QUERY).get() == xIntRoot );
125 #endif
127 // remove entries in global maps
128 typedef hash_map<sal_uInt32, sal_uInt32>::iterator _IT;
129 _IT it= WrapperToAdapterMap.find( (sal_uInt32) xIntRoot);
130 if( it != WrapperToAdapterMap.end())
132 sal_uInt32 adapter= it->second;
134 AdapterToWrapperMap.erase( adapter);
135 WrapperToAdapterMap.erase( it);
138 IT_Com it_c= ComPtrToWrapperMap.find( (sal_uInt32) m_spUnknown.p);
139 if(it_c != ComPtrToWrapperMap.end())
140 ComPtrToWrapperMap.erase(it_c);
142 #if OSL_DEBUG_LEVEL > 0
143 fprintf(stderr,"[automation bridge] ComPtrToWrapperMap contains: %i \n",
144 ComPtrToWrapperMap.size());
145 #endif
148 Any IUnknownWrapper_Impl::queryInterface(const Type& t)
149 throw (RuntimeException)
151 if (t == getCppuType(static_cast<Reference<XDefaultMethod>*>( 0)) && !m_bHasDfltMethod )
152 return Any();
153 if (t == getCppuType(static_cast<Reference<XDefaultProperty>*>( 0)) && !m_bHasDfltProperty )
154 return Any();
155 if (t == getCppuType(static_cast<Reference<XInvocation>*>( 0)) && !m_spDispatch)
156 return Any();
158 return WeakImplHelper6<XInvocation, XBridgeSupplier2,
159 XInitialization, XAutomationObject, XDefaultProperty, XDefaultMethod>::queryInterface(t);
162 Reference<XIntrospectionAccess> SAL_CALL IUnknownWrapper_Impl::getIntrospection(void)
163 throw (RuntimeException )
165 Reference<XIntrospectionAccess> ret;
167 return ret;
172 Any SAL_CALL IUnknownWrapper_Impl::invoke( const OUString& aFunctionName,
173 const Sequence< Any >& aParams, Sequence< sal_Int16 >& aOutParamIndex,
174 Sequence< Any >& aOutParam )
175 throw(IllegalArgumentException, CannotConvertException, InvocationTargetException,
176 RuntimeException)
178 if ( ! m_spDispatch )
180 throw RuntimeException(
181 OUSTR("[automation bridge] The object does not have an IDispatch interface"),
182 Reference<XInterface>());
185 Any ret;
189 o2u_attachCurrentThread();
191 TypeDescription methodDesc;
192 getMethodInfo(aFunctionName, methodDesc);
193 if( methodDesc.is())
195 ret = invokeWithDispIdUnoTlb(aFunctionName,
196 aParams,
197 aOutParamIndex,
198 aOutParam);
200 else
202 ret= invokeWithDispIdComTlb( aFunctionName,
203 aParams,
204 aOutParamIndex,
205 aOutParam);
208 catch (IllegalArgumentException &)
210 throw;
212 catch (CannotConvertException &)
214 throw;
216 catch (BridgeRuntimeError & e)
218 throw RuntimeException(e.message, Reference<XInterface>());
220 catch (Exception & e)
222 throw RuntimeException(OUSTR("[automation bridge] unexpected exception in "
223 "IUnknownWrapper_Impl::invoke ! Message : \n") +
224 e.Message, Reference<XInterface>());
227 catch(...)
229 throw RuntimeException(
230 OUSTR("[automation bridge] unexpected exception in "
231 "IUnknownWrapper_Impl::Invoke !"), Reference<XInterface>());
233 return ret;
236 void SAL_CALL IUnknownWrapper_Impl::setValue( const OUString& aPropertyName,
237 const Any& aValue )
238 throw(UnknownPropertyException, CannotConvertException, InvocationTargetException,
239 RuntimeException)
241 if ( ! m_spDispatch )
243 throw RuntimeException(
244 OUSTR("[automation bridge] The object does not have an IDispatch interface"),
245 Reference<XInterface>());
249 o2u_attachCurrentThread();
251 ITypeInfo * pInfo = getTypeInfo();
252 FuncDesc aDescGet(pInfo);
253 FuncDesc aDescPut(pInfo);
254 VarDesc aVarDesc(pInfo);
255 getPropDesc(aPropertyName, & aDescGet, & aDescPut, & aVarDesc);
256 //check if there is such a property at all or if it is read only
257 if ( ! aDescPut && ! aDescGet && ! aVarDesc)
259 OUString msg(OUSTR("[automation bridge]Property \"") + aPropertyName +
260 OUSTR("\" is not supported"));
261 throw UnknownPropertyException(msg, Reference<XInterface>());
264 if ( (! aDescPut && aDescGet) || aVarDesc
265 && aVarDesc->wVarFlags == VARFLAG_FREADONLY )
267 //read-only
268 OUString msg(OUSTR("[automation bridge] Property ") + aPropertyName +
269 OUSTR(" is read-only"));
270 OString sMsg = OUStringToOString(msg, osl_getThreadTextEncoding());
271 OSL_ENSURE(0, sMsg.getStr());
272 // ignore silently
273 return;
276 HRESULT hr= S_OK;
277 DISPPARAMS dispparams;
278 CComVariant varArg;
279 CComVariant varRefArg;
280 CComVariant varResult;
281 ExcepInfo excepinfo;
282 unsigned int uArgErr;
284 // converting UNO value to OLE variant
285 DISPID dispidPut= DISPID_PROPERTYPUT;
286 dispparams.rgdispidNamedArgs = &dispidPut;
287 dispparams.cArgs = 1;
288 dispparams.cNamedArgs = 1;
289 dispparams.rgvarg = & varArg;
291 OSL_ASSERT(aDescPut || aVarDesc);
293 VARTYPE vt = 0;
294 DISPID dispid = 0;
295 INVOKEKIND invkind = INVOKE_PROPERTYPUT;
296 //determine the expected type, dispid, invoke kind (DISPATCH_PROPERTYPUT,
297 //DISPATCH_PROPERTYPUTREF)
298 if (aDescPut)
300 vt = getElementTypeDesc(& aDescPut->lprgelemdescParam[0].tdesc);
301 dispid = aDescPut->memid;
302 invkind = aDescPut->invkind;
304 else
306 vt = getElementTypeDesc( & aVarDesc->elemdescVar.tdesc);
307 dispid = aVarDesc->memid;
308 if (vt == VT_UNKNOWN || vt == VT_DISPATCH ||
309 (vt & VT_ARRAY) || (vt & VT_BYREF))
311 invkind = INVOKE_PROPERTYPUTREF;
315 // convert the uno argument
316 if (vt & VT_BYREF)
318 anyToVariant( & varRefArg, aValue, ::sal::static_int_cast< VARTYPE, int >( vt ^ VT_BYREF ) );
319 varArg.vt = vt;
320 if( (vt & VT_TYPEMASK) == VT_VARIANT)
321 varArg.byref = & varRefArg;
322 else if ((vt & VT_TYPEMASK) == VT_DECIMAL)
323 varArg.byref = & varRefArg.decVal;
324 else
325 varArg.byref = & varRefArg.byref;
327 else
329 anyToVariant(& varArg, aValue, vt);
331 // call to IDispatch
332 hr = m_spDispatch->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, ::sal::static_int_cast< WORD, INVOKEKIND >( invkind ),
333 &dispparams, & varResult, & excepinfo, &uArgErr);
335 // lookup error code
336 switch (hr)
338 case S_OK:
339 break;
340 case DISP_E_BADPARAMCOUNT:
341 throw RuntimeException();
342 break;
343 case DISP_E_BADVARTYPE:
344 throw RuntimeException();
345 break;
346 case DISP_E_EXCEPTION:
347 throw InvocationTargetException();
348 break;
349 case DISP_E_MEMBERNOTFOUND:
350 throw UnknownPropertyException();
351 break;
352 case DISP_E_NONAMEDARGS:
353 throw RuntimeException();
354 break;
355 case DISP_E_OVERFLOW:
356 throw CannotConvertException(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("call to OLE object failed")), static_cast<XInterface*>(
357 static_cast<XWeak*>(this)), TypeClass_UNKNOWN, FailReason::OUT_OF_RANGE, uArgErr);
358 break;
359 case DISP_E_PARAMNOTFOUND:
360 throw IllegalArgumentException(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("call to OLE object failed")), static_cast<XInterface*>(
361 static_cast<XWeak*>(this)), ::sal::static_int_cast< sal_Int16, unsigned int >( uArgErr )) ;
362 break;
363 case DISP_E_TYPEMISMATCH:
364 throw CannotConvertException(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("call to OLE object failed")), static_cast<XInterface*>(
365 static_cast<XWeak*>(this)), TypeClass_UNKNOWN, FailReason::UNKNOWN, ::sal::static_int_cast< sal_Int16, unsigned int >( uArgErr ));
366 break;
367 case DISP_E_UNKNOWNINTERFACE:
368 throw RuntimeException();
369 break;
370 case DISP_E_UNKNOWNLCID:
371 throw RuntimeException();
372 break;
373 case DISP_E_PARAMNOTOPTIONAL:
374 throw CannotConvertException(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("call to OLE object failed")),static_cast<XInterface*>(
375 static_cast<XWeak*>(this)) , TypeClass_UNKNOWN, FailReason::NO_DEFAULT_AVAILABLE, uArgErr);
376 break;
377 default:
378 throw RuntimeException();
379 break;
382 catch (CannotConvertException &)
384 throw;
386 catch (UnknownPropertyException &)
388 throw;
390 catch (BridgeRuntimeError& e)
392 throw RuntimeException(
393 e.message, Reference<XInterface>());
395 catch (Exception & e)
397 throw RuntimeException(OUSTR("[automation bridge] unexpected exception in "
398 "IUnknownWrapper_Impl::setValue ! Message : \n") +
399 e.Message, Reference<XInterface>());
402 catch (...)
404 throw RuntimeException(
405 OUSTR("[automation bridge] unexpected exception in "
406 "IUnknownWrapper_Impl::setValue !"), Reference<XInterface>());
410 Any SAL_CALL IUnknownWrapper_Impl::getValue( const OUString& aPropertyName )
411 throw(UnknownPropertyException, RuntimeException)
413 if ( ! m_spDispatch )
415 throw RuntimeException(
416 OUSTR("[automation bridge] The object does not have an IDispatch interface"),
417 Reference<XInterface>());
419 Any ret;
422 o2u_attachCurrentThread();
423 ITypeInfo * pInfo = getTypeInfo();
424 // I was going to implement an XServiceInfo interface to allow the type
425 // of the automation object to be exposed.. but it seems
426 // from looking at comments in the code that it is possible for
427 // this object to actually wrap an UNO object ( I guess if automation is
428 // used from MSO to create Openoffice objects ) Therefore, those objects
429 // will more than likely already have their own XServiceInfo interface.
430 // Instead here I chose a name that should be illegal both in COM and
431 // UNO ( from an IDL point of view ) therefore I think this is a safe
432 // hack
433 if ( aPropertyName.equals( rtl::OUString::createFromAscii("$GetTypeName") ))
435 if ( pInfo && m_sTypeName.getLength() == 0 )
437 m_sTypeName = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("IDispatch") );
438 CComBSTR sName;
440 if ( SUCCEEDED( pInfo->GetDocumentation( -1, &sName, NULL, NULL, NULL ) ) )
442 rtl::OUString sTmp( reinterpret_cast<const sal_Unicode*>(LPCOLESTR(sName)));
443 if ( sTmp.indexOf('_') == 0 )
444 sTmp = sTmp.copy(1);
445 // do we own the memory for pTypeLib, msdn doco is vague
446 // I'll assume we do
447 CComPtr< ITypeLib > pTypeLib;
448 unsigned int index;
449 if ( SUCCEEDED( pInfo->GetContainingTypeLib( &pTypeLib.p, &index )) )
451 if ( SUCCEEDED( pTypeLib->GetDocumentation( -1, &sName, NULL, NULL, NULL ) ) )
453 rtl::OUString sLibName( reinterpret_cast<const sal_Unicode*>(LPCOLESTR(sName)));
454 m_sTypeName = sLibName.concat( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(".") ) ).concat( sTmp );
461 ret <<= m_sTypeName;
462 return ret;
464 FuncDesc aDescGet(pInfo);
465 FuncDesc aDescPut(pInfo);
466 VarDesc aVarDesc(pInfo);
467 getPropDesc(aPropertyName, & aDescGet, & aDescPut, & aVarDesc);
468 if ( ! aDescGet && ! aDescPut && ! aVarDesc)
470 //property not found
471 OUString msg(OUSTR("[automation bridge]Property \"") + aPropertyName +
472 OUSTR("\" is not supported"));
473 throw UnknownPropertyException(msg, Reference<XInterface>());
475 // write-only should not be possible
476 OSL_ASSERT( aDescGet || ! aDescPut);
478 HRESULT hr;
479 DISPPARAMS dispparams = {0, 0, 0, 0};
480 CComVariant varResult;
481 ExcepInfo excepinfo;
482 unsigned int uArgErr;
483 DISPID dispid;
484 if (aDescGet)
485 dispid = aDescGet->memid;
486 else if (aVarDesc)
487 dispid = aVarDesc->memid;
488 else
489 dispid = aDescPut->memid;
491 hr = m_spDispatch->Invoke(dispid,
492 IID_NULL,
493 LOCALE_USER_DEFAULT,
494 DISPATCH_PROPERTYGET,
495 &dispparams,
496 &varResult,
497 &excepinfo,
498 &uArgErr);
500 // converting return value and out parameter back to UNO
501 if (hr == S_OK)
503 // If the com object implements uno interfaces then we have
504 // to convert the attribute into the expected type.
505 TypeDescription attrInfo;
506 getAttributeInfo(aPropertyName, attrInfo);
507 if( attrInfo.is() )
508 variantToAny( &varResult, ret, Type( attrInfo.get()->pWeakRef));
509 else
510 variantToAny(&varResult, ret);
513 // lookup error code
514 switch (hr)
516 case S_OK:
517 break;
518 case DISP_E_BADPARAMCOUNT:
519 throw RuntimeException(OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription)),
520 Reference<XInterface>());
521 break;
522 case DISP_E_BADVARTYPE:
523 throw RuntimeException(OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription)),
524 Reference<XInterface>());
525 break;
526 case DISP_E_EXCEPTION:
527 throw RuntimeException(OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription)),
528 Reference<XInterface>());
529 break;
530 case DISP_E_MEMBERNOTFOUND:
531 throw UnknownPropertyException(OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription)),
532 Reference<XInterface>());
533 break;
534 case DISP_E_NONAMEDARGS:
535 throw RuntimeException(OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription)),
536 Reference<XInterface>());
537 break;
538 case DISP_E_OVERFLOW:
539 throw RuntimeException(OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription)),
540 Reference<XInterface>());
541 break;
542 case DISP_E_PARAMNOTFOUND:
543 throw RuntimeException(OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription)),
544 Reference<XInterface>());
545 break;
546 case DISP_E_TYPEMISMATCH:
547 throw RuntimeException(OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription)),
548 Reference<XInterface>());
549 break;
550 case DISP_E_UNKNOWNINTERFACE:
551 throw RuntimeException(OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription)),
552 Reference<XInterface>());
553 break;
554 case DISP_E_UNKNOWNLCID:
555 throw RuntimeException(OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription)),
556 Reference<XInterface>());
557 break;
558 case DISP_E_PARAMNOTOPTIONAL:
559 throw RuntimeException(OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription)),
560 Reference<XInterface>());
561 break;
562 default:
563 throw RuntimeException(OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription)),
564 Reference<XInterface>());
565 break;
568 catch (UnknownPropertyException& )
570 throw;
572 catch (BridgeRuntimeError& e)
574 throw RuntimeException(
575 e.message, Reference<XInterface>());
577 catch (Exception & e)
579 throw RuntimeException(OUSTR("[automation bridge] unexpected exception in "
580 "IUnknownWrapper_Impl::getValue ! Message : \n") +
581 e.Message, Reference<XInterface>());
583 catch (...)
585 throw RuntimeException(
586 OUSTR("[automation bridge] unexpected exception in "
587 "IUnknownWrapper_Impl::getValue !"), Reference<XInterface>());
589 return ret;
592 sal_Bool SAL_CALL IUnknownWrapper_Impl::hasMethod( const OUString& aName )
593 throw(RuntimeException)
595 if ( ! m_spDispatch )
597 throw RuntimeException(
598 OUSTR("[automation bridge] The object does not have an IDispatch interface"),
599 Reference<XInterface>());
601 sal_Bool ret = sal_False;
605 o2u_attachCurrentThread();
606 ITypeInfo* pInfo = getTypeInfo();
607 FuncDesc aDesc(pInfo);
608 getFuncDesc(aName, & aDesc);
609 // Automation properties can have arguments. Those are treated as methods and
610 //are called through XInvocation::invoke.
611 if ( ! aDesc)
613 FuncDesc aDescGet(pInfo);
614 FuncDesc aDescPut(pInfo);
615 VarDesc aVarDesc(pInfo);
616 getPropDesc( aName, & aDescGet, & aDescPut, & aVarDesc);
617 if (aDescGet && aDescGet->cParams > 0
618 || aDescPut && aDescPut->cParams > 0)
619 ret = sal_True;
621 else
622 ret = sal_True;
624 catch (BridgeRuntimeError& e)
626 throw RuntimeException(e.message, Reference<XInterface>());
628 catch (Exception & e)
630 throw RuntimeException(OUSTR("[automation bridge] unexpected exception in "
631 "IUnknownWrapper_Impl::hasMethod ! Message : \n") +
632 e.Message, Reference<XInterface>());
634 catch (...)
636 throw RuntimeException(OUSTR("[automation bridge] unexpected exception in "
637 "IUnknownWrapper_Impl::hasMethod !"), Reference<XInterface>());;
639 return ret;
642 sal_Bool SAL_CALL IUnknownWrapper_Impl::hasProperty( const OUString& aName )
643 throw(RuntimeException)
645 if ( ! m_spDispatch )
647 throw RuntimeException(OUSTR("[automation bridge] The object does not have an "
648 "IDispatch interface"), Reference<XInterface>());
649 return sal_False;
651 sal_Bool ret = sal_False;
654 o2u_attachCurrentThread();
656 ITypeInfo * pInfo = getTypeInfo();
657 FuncDesc aDescGet(pInfo);
658 FuncDesc aDescPut(pInfo);
659 VarDesc aVarDesc(pInfo);
660 getPropDesc(aName, & aDescGet, & aDescPut, & aVarDesc);
661 // Automation properties can have parameters. If so, we access them through
662 // XInvocation::invoke. Thas is, hasProperty must return false for such a
663 // property
664 if (aVarDesc
665 || aDescPut && aDescPut->cParams == 0
666 || aDescGet && aDescGet->cParams == 0)
668 ret = sal_True;
671 catch (BridgeRuntimeError& e)
673 throw RuntimeException(e.message, Reference<XInterface>());
675 catch (Exception & e)
677 throw RuntimeException(OUSTR("[automation bridge] unexpected exception in "
678 "IUnknownWrapper_Impl::hasProperty ! Message : \n") +
679 e.Message, Reference<XInterface>());
682 catch (...)
684 throw RuntimeException(OUSTR("[automation bridge] unexpected exception in "
685 "IUnknownWrapper_Impl::hasProperty !"), Reference<XInterface>());
687 return ret;
690 Any SAL_CALL IUnknownWrapper_Impl::createBridge( const Any& modelDepObject,
691 const Sequence< sal_Int8 >& /*aProcessId*/, sal_Int16 sourceModelType,
692 sal_Int16 destModelType )
693 throw( IllegalArgumentException, RuntimeException)
695 Any ret;
696 o2u_attachCurrentThread();
698 if (
699 (sourceModelType == UNO) &&
700 (destModelType == OLE) &&
701 (modelDepObject.getValueTypeClass() == TypeClass_INTERFACE)
704 Reference<XInterface> xInt( *(XInterface**) modelDepObject.getValue());
705 Reference<XInterface> xSelf( (OWeakObject*)this);
707 if (xInt == xSelf)
709 VARIANT* pVariant = (VARIANT*) CoTaskMemAlloc(sizeof(VARIANT));
711 VariantInit(pVariant);
712 if (m_bOriginalDispatch == sal_True)
714 pVariant->vt = VT_DISPATCH;
715 pVariant->pdispVal = m_spDispatch;
716 pVariant->pdispVal->AddRef();
718 else
720 pVariant->vt = VT_UNKNOWN;
721 pVariant->punkVal = m_spUnknown;
722 pVariant->punkVal->AddRef();
725 ret.setValue((void*)&pVariant, getCppuType( (sal_uInt32*) 0));
729 return ret;
731 /** @internal
732 @exception IllegalArgumentException
733 @exception CannotConvertException
734 @exception InvocationTargetException
735 @RuntimeException
737 Any IUnknownWrapper_Impl::invokeWithDispIdUnoTlb(const OUString& sFunctionName,
738 const Sequence< Any >& Params,
739 Sequence< sal_Int16 >& OutParamIndex,
740 Sequence< Any >& OutParam)
742 Any ret;
743 HRESULT hr= S_OK;
745 sal_Int32 parameterCount= Params.getLength();
746 sal_Int32 outParameterCount= 0;
747 typelib_InterfaceMethodTypeDescription* pMethod= NULL;
748 TypeDescription methodDesc;
749 getMethodInfo(sFunctionName, methodDesc);
751 // We need to know whether the IDispatch is from a JScript object.
752 // Then out and in/out parameters have to be treated differently than
753 // with common COM objects.
754 sal_Bool bJScriptObject= isJScriptObject();
755 scoped_array<CComVariant> sarParams;
756 scoped_array<CComVariant> sarParamsRef;
757 CComVariant *pVarParams= NULL;
758 CComVariant *pVarParamsRef= NULL;
759 sal_Bool bConvRet= sal_True;
761 if( methodDesc.is())
763 pMethod = (typelib_InterfaceMethodTypeDescription* )methodDesc.get();
764 parameterCount = pMethod->nParams;
765 // Create the Array for the array being passed in DISPPARAMS
766 // the array also contains the outparameter (but not the values)
767 if( pMethod->nParams > 0)
769 sarParams.reset(new CComVariant[ parameterCount]);
770 pVarParams = sarParams.get();
773 // Create the Array for the out an in/out parameter. These values
774 // are referenced by the VT_BYREF VARIANTs in DISPPARAMS.
775 // We need to find out the number of out and in/out parameter.
776 for( sal_Int32 i=0; i < parameterCount; i++)
778 if( pMethod->pParams[i].bOut)
779 outParameterCount++;
782 if( !bJScriptObject)
784 sarParamsRef.reset(new CComVariant[outParameterCount]);
785 pVarParamsRef = sarParamsRef.get();
786 // build up the parameters for IDispatch::Invoke
787 sal_Int32 outParamIndex=0;
788 int i = 0;
791 for( i= 0; i < parameterCount; i++)
793 // In parameter
794 if( pMethod->pParams[i].bIn == sal_True && ! pMethod->pParams[i].bOut)
796 anyToVariant( &pVarParams[parameterCount - i -1], Params.getConstArray()[i]);
798 // Out parameter + in/out parameter
799 else if( pMethod->pParams[i].bOut == sal_True)
801 CComVariant var;
802 if(pMethod->pParams[i].bIn)
804 anyToVariant( & var,Params[i]);
805 pVarParamsRef[outParamIndex] = var;
808 switch( pMethod->pParams[i].pTypeRef->eTypeClass)
810 case TypeClass_INTERFACE:
811 case TypeClass_STRUCT:
812 if( ! pMethod->pParams[i].bIn)
814 pVarParamsRef[ outParamIndex].vt= VT_DISPATCH;
815 pVarParamsRef[ outParamIndex].pdispVal= 0;
817 pVarParams[parameterCount - i -1].vt = VT_DISPATCH | VT_BYREF;
818 pVarParams[parameterCount - i -1].ppdispVal= &pVarParamsRef[outParamIndex].pdispVal;
819 break;
820 case TypeClass_ENUM:
821 case TypeClass_LONG:
822 case TypeClass_UNSIGNED_LONG:
823 if( ! pMethod->pParams[i].bIn)
825 pVarParamsRef[ outParamIndex].vt = VT_I4;
826 pVarParamsRef[ outParamIndex].lVal = 0;
828 pVarParams[parameterCount - i -1].vt = VT_I4 | VT_BYREF;
829 pVarParams[parameterCount - i -1].plVal= &pVarParamsRef[outParamIndex].lVal;
830 break;
831 case TypeClass_SEQUENCE:
832 if( ! pMethod->pParams[i].bIn)
834 pVarParamsRef[ outParamIndex].vt = VT_ARRAY| VT_VARIANT;
835 pVarParamsRef[ outParamIndex].parray= NULL;
837 pVarParams[parameterCount - i -1].vt = VT_ARRAY| VT_BYREF | VT_VARIANT;
838 pVarParams[parameterCount - i -1].pparray= &pVarParamsRef[outParamIndex].parray;
839 break;
840 case TypeClass_ANY:
841 if( ! pMethod->pParams[i].bIn)
843 pVarParamsRef[ outParamIndex].vt = VT_EMPTY;
844 pVarParamsRef[ outParamIndex].lVal = 0;
846 pVarParams[parameterCount - i -1].vt = VT_VARIANT | VT_BYREF;
847 pVarParams[parameterCount - i -1].pvarVal = &pVarParamsRef[outParamIndex];
848 break;
849 case TypeClass_BOOLEAN:
850 if( ! pMethod->pParams[i].bIn)
852 pVarParamsRef[ outParamIndex].vt = VT_BOOL;
853 pVarParamsRef[ outParamIndex].boolVal = 0;
855 pVarParams[parameterCount - i -1].vt = VT_BOOL| VT_BYREF;
856 pVarParams[parameterCount - i -1].pboolVal =
857 & pVarParamsRef[outParamIndex].boolVal;
858 break;
860 case TypeClass_STRING:
861 if( ! pMethod->pParams[i].bIn)
863 pVarParamsRef[ outParamIndex].vt = VT_BSTR;
864 pVarParamsRef[ outParamIndex].bstrVal= 0;
866 pVarParams[parameterCount - i -1].vt = VT_BSTR| VT_BYREF;
867 pVarParams[parameterCount - i -1].pbstrVal=
868 & pVarParamsRef[outParamIndex].bstrVal;
869 break;
871 case TypeClass_FLOAT:
872 if( ! pMethod->pParams[i].bIn)
874 pVarParamsRef[ outParamIndex].vt = VT_R4;
875 pVarParamsRef[ outParamIndex].fltVal= 0;
877 pVarParams[parameterCount - i -1].vt = VT_R4| VT_BYREF;
878 pVarParams[parameterCount - i -1].pfltVal =
879 & pVarParamsRef[outParamIndex].fltVal;
880 break;
881 case TypeClass_DOUBLE:
882 if( ! pMethod->pParams[i].bIn)
884 pVarParamsRef[ outParamIndex].vt = VT_R8;
885 pVarParamsRef[ outParamIndex].dblVal= 0;
887 pVarParams[parameterCount - i -1].vt = VT_R8| VT_BYREF;
888 pVarParams[parameterCount - i -1].pdblVal=
889 & pVarParamsRef[outParamIndex].dblVal;
890 break;
891 case TypeClass_BYTE:
892 if( ! pMethod->pParams[i].bIn)
894 pVarParamsRef[ outParamIndex].vt = VT_UI1;
895 pVarParamsRef[ outParamIndex].bVal= 0;
897 pVarParams[parameterCount - i -1].vt = VT_UI1| VT_BYREF;
898 pVarParams[parameterCount - i -1].pbVal=
899 & pVarParamsRef[outParamIndex].bVal;
900 break;
901 case TypeClass_CHAR:
902 case TypeClass_SHORT:
903 case TypeClass_UNSIGNED_SHORT:
904 if( ! pMethod->pParams[i].bIn)
906 pVarParamsRef[ outParamIndex].vt = VT_I2;
907 pVarParamsRef[ outParamIndex].iVal = 0;
909 pVarParams[parameterCount - i -1].vt = VT_I2| VT_BYREF;
910 pVarParams[parameterCount - i -1].piVal=
911 & pVarParamsRef[outParamIndex].iVal;
912 break;
914 default:
915 if( ! pMethod->pParams[i].bIn)
917 pVarParamsRef[ outParamIndex].vt = VT_EMPTY;
918 pVarParamsRef[ outParamIndex].lVal = 0;
920 pVarParams[parameterCount - i -1].vt = VT_VARIANT | VT_BYREF;
921 pVarParams[parameterCount - i -1].pvarVal =
922 & pVarParamsRef[outParamIndex];
924 outParamIndex++;
925 } // end else if
926 } // end for
928 catch (IllegalArgumentException & e)
930 e.ArgumentPosition = ::sal::static_int_cast< sal_Int16, int >( i );
931 throw;
933 catch (CannotConvertException & e)
935 e.ArgumentIndex = i;
936 throw;
939 else // it is an JScriptObject
941 int i = 0;
944 for( ; i< parameterCount; i++)
946 // In parameter
947 if( pMethod->pParams[i].bIn == sal_True && ! pMethod->pParams[i].bOut)
949 anyToVariant( &pVarParams[parameterCount - i -1], Params.getConstArray()[i]);
951 // Out parameter + in/out parameter
952 else if( pMethod->pParams[i].bOut == sal_True)
954 CComObject<JScriptOutParam>* pParamObject;
955 if( SUCCEEDED( CComObject<JScriptOutParam>::CreateInstance( &pParamObject)))
957 CComPtr<IUnknown> pUnk(pParamObject->GetUnknown());
958 #ifdef __MINGW32__
959 CComQIPtr<IDispatch, &__uuidof(IDispatch)> pDisp( pUnk);
960 #else
961 CComQIPtr<IDispatch> pDisp( pUnk);
962 #endif
964 pVarParams[ parameterCount - i -1].vt= VT_DISPATCH;
965 pVarParams[ parameterCount - i -1].pdispVal= pDisp;
966 pVarParams[ parameterCount - i -1].pdispVal->AddRef();
967 // if the param is in/out then put the parameter on index 0
968 if( pMethod->pParams[i].bIn == sal_True ) // in / out
970 CComVariant varParam;
971 anyToVariant( &varParam, Params.getConstArray()[i]);
972 CComDispatchDriver dispDriver( pDisp);
973 if(FAILED( dispDriver.PutPropertyByName( L"0", &varParam)))
974 throw BridgeRuntimeError(
975 OUSTR("[automation bridge]IUnknownWrapper_Impl::"
976 "invokeWithDispIdUnoTlb\n"
977 "Could not set property \"0\" for the in/out "
978 "param!"));
982 else
984 throw BridgeRuntimeError(
985 OUSTR("[automation bridge]IUnknownWrapper_Impl::"
986 "invokeWithDispIdUnoTlb\n"
987 "Could not create out parameter at index: ") +
988 OUString::valueOf((sal_Int32) i));
994 catch (IllegalArgumentException & e)
996 e.ArgumentPosition = ::sal::static_int_cast< sal_Int16, int >( i );
997 throw;
999 catch (CannotConvertException & e)
1001 e.ArgumentIndex = i;
1002 throw;
1006 // No type description Available, that is we have to deal with a COM component,
1007 // that does not implements UNO interfaces ( IDispatch based)
1008 else
1010 //We should not run into this block, because invokeWithDispIdComTlb should
1011 //have been called instead.
1012 OSL_ASSERT(0);
1016 CComVariant varResult;
1017 ExcepInfo excepinfo;
1018 unsigned int uArgErr;
1019 DISPPARAMS dispparams= { pVarParams, NULL, parameterCount, 0};
1020 // Get the DISPID
1021 FuncDesc aDesc(getTypeInfo());
1022 getFuncDesc(sFunctionName, & aDesc);
1023 // invoking OLE method
1024 hr = m_spDispatch->Invoke(aDesc->memid,
1025 IID_NULL,
1026 LOCALE_USER_DEFAULT,
1027 DISPATCH_METHOD,
1028 &dispparams,
1029 &varResult,
1030 &excepinfo,
1031 &uArgErr);
1033 // converting return value and out parameter back to UNO
1034 if (hr == S_OK)
1036 if( outParameterCount && pMethod)
1038 OutParamIndex.realloc( outParameterCount);
1039 OutParam.realloc( outParameterCount);
1040 sal_Int32 outIndex=0;
1041 int i = 0;
1044 for( ; i < parameterCount; i++)
1046 if( pMethod->pParams[i].bOut )
1048 OutParamIndex[outIndex]= (sal_Int16) i;
1049 Any outAny;
1050 if( !bJScriptObject)
1052 variantToAny( &pVarParamsRef[outIndex], outAny,
1053 Type(pMethod->pParams[i].pTypeRef), sal_False);
1054 OutParam[outIndex++]= outAny;
1056 else //JScriptObject
1058 if( pVarParams[i].vt == VT_DISPATCH)
1060 CComDispatchDriver pDisp( pVarParams[i].pdispVal);
1061 if( pDisp)
1063 CComVariant varOut;
1064 if( SUCCEEDED( pDisp.GetPropertyByName( L"0", &varOut)))
1066 variantToAny( &varOut, outAny,
1067 Type(pMethod->pParams[parameterCount - 1 - i].pTypeRef), sal_False);
1068 OutParam[outParameterCount - 1 - outIndex++]= outAny;
1070 else
1071 bConvRet= sal_False;
1073 else
1074 bConvRet= sal_False;
1076 else
1077 bConvRet= sal_False;
1080 if( !bConvRet) break;
1083 catch(IllegalArgumentException & e)
1085 e.ArgumentPosition = ::sal::static_int_cast< sal_Int16, int >( i );
1086 throw;
1088 catch(CannotConvertException & e)
1090 e.ArgumentIndex = i;
1091 throw;
1094 // return value, no type information available
1095 if ( bConvRet)
1099 if( pMethod )
1100 variantToAny(&varResult, ret, Type( pMethod->pReturnTypeRef), sal_False);
1101 else
1102 variantToAny(&varResult, ret, sal_False);
1104 catch (IllegalArgumentException & e)
1106 e.Message =
1107 OUSTR("[automation bridge]IUnknownWrapper_Impl::invokeWithDispIdUnoTlb\n"
1108 "Could not convert return value! \n Message: \n") + e.Message;
1109 throw;
1111 catch (CannotConvertException & e)
1113 e.Message =
1114 OUSTR("[automation bridge]IUnknownWrapper_Impl::invokeWithDispIdUnoTlb\n"
1115 "Could not convert return value! \n Message: \n") + e.Message;
1116 throw;
1121 if( !bConvRet) // conversion of return or out parameter failed
1122 throw CannotConvertException( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Call to COM object failed. Conversion of return or out value failed")),
1123 Reference<XInterface>( static_cast<XWeak*>(this), UNO_QUERY ), TypeClass_UNKNOWN,
1124 FailReason::UNKNOWN, 0);// lookup error code
1125 // conversion of return or out parameter failed
1126 switch (hr)
1128 case S_OK:
1129 break;
1130 case DISP_E_BADPARAMCOUNT:
1131 throw IllegalArgumentException();
1132 break;
1133 case DISP_E_BADVARTYPE:
1134 throw RuntimeException();
1135 break;
1136 case DISP_E_EXCEPTION:
1137 throw InvocationTargetException();
1138 break;
1139 case DISP_E_MEMBERNOTFOUND:
1140 throw IllegalArgumentException();
1141 break;
1142 case DISP_E_NONAMEDARGS:
1143 throw IllegalArgumentException();
1144 break;
1145 case DISP_E_OVERFLOW:
1146 throw CannotConvertException(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("call to OLE object failed")), static_cast<XInterface*>(
1147 static_cast<XWeak*>(this)), TypeClass_UNKNOWN, FailReason::OUT_OF_RANGE, uArgErr);
1148 break;
1149 case DISP_E_PARAMNOTFOUND:
1150 throw IllegalArgumentException(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("call to OLE object failed")), static_cast<XInterface*>(
1151 static_cast<XWeak*>(this)), ::sal::static_int_cast< sal_Int16, unsigned int >( uArgErr ));
1152 break;
1153 case DISP_E_TYPEMISMATCH:
1154 throw CannotConvertException(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("call to OLE object failed")),static_cast<XInterface*>(
1155 static_cast<XWeak*>(this)) , TypeClass_UNKNOWN, FailReason::UNKNOWN, uArgErr);
1156 break;
1157 case DISP_E_UNKNOWNINTERFACE:
1158 throw RuntimeException() ;
1159 break;
1160 case DISP_E_UNKNOWNLCID:
1161 throw RuntimeException() ;
1162 break;
1163 case DISP_E_PARAMNOTOPTIONAL:
1164 throw CannotConvertException(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("call to OLE object failed")), static_cast<XInterface*>(
1165 static_cast<XWeak*>(this)), TypeClass_UNKNOWN, FailReason::NO_DEFAULT_AVAILABLE, uArgErr);
1166 break;
1167 default:
1168 throw RuntimeException();
1169 break;
1172 return ret;
1177 // --------------------------
1178 // XInitialization
1179 void SAL_CALL IUnknownWrapper_Impl::initialize( const Sequence< Any >& aArguments ) throw(Exception, RuntimeException)
1181 // 1.parameter is IUnknown
1182 // 2.parameter is a boolean which indicates if the the COM pointer was a IUnknown or IDispatch
1183 // 3.parameter is a Sequence<Type>
1184 o2u_attachCurrentThread();
1185 OSL_ASSERT(aArguments.getLength() == 3);
1187 m_spUnknown= *(IUnknown**) aArguments[0].getValue();
1188 #ifdef __MINGW32__
1189 m_spUnknown->QueryInterface(IID_IDispatch, reinterpret_cast<LPVOID*>( & m_spDispatch.p));
1190 #else
1191 m_spUnknown.QueryInterface( & m_spDispatch.p);
1192 #endif
1194 aArguments[1] >>= m_bOriginalDispatch;
1195 aArguments[2] >>= m_seqTypes;
1197 ITypeInfo* pType = NULL;
1200 // a COM object implementation that has no TypeInfo is still a legal COM object;
1201 // such objects can at least be transported through UNO using the bridge
1202 // so we should allow to create wrappers for them as well
1203 pType = getTypeInfo();
1205 catch( BridgeRuntimeError& )
1207 catch( Exception& )
1210 if ( pType )
1214 // Get Default member
1215 CComBSTR defaultMemberName;
1216 if ( SUCCEEDED( pType->GetDocumentation(0, &defaultMemberName, 0, 0, 0 ) ) )
1218 OUString usName(reinterpret_cast<const sal_Unicode*>(LPCOLESTR(defaultMemberName)));
1219 FuncDesc aDescGet(pType);
1220 FuncDesc aDescPut(pType);
1221 VarDesc aVarDesc(pType);
1222 // see if this is a property first ( more likely to be a property then a method )
1223 getPropDesc( usName, & aDescGet, & aDescPut, & aVarDesc);
1225 if ( !aDescGet && !aDescPut )
1227 getFuncDesc( usName, &aDescGet );
1228 if ( !aDescGet )
1229 throw BridgeRuntimeError( OUSTR("[automation bridge]IUnknownWrapper_Impl::initialize() Failed to get Function or Property desc. for " ) + usName );
1231 // now for some funny heuristics to make basic understand what to do
1232 // a single aDescGet ( that doesn't take any params ) would be
1233 // a read only ( defaultmember ) property e.g. this object
1234 // should implement XDefaultProperty
1235 // a single aDescGet ( that *does* ) take params is basically a
1236 // default method e.g. implement XDefaultMethod
1238 // 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 )
1239 if ( aDescPut || ( aDescGet && aDescGet->cParams == 0 ) )
1240 m_bHasDfltProperty = true;
1241 if ( aDescGet->cParams > 0 )
1242 m_bHasDfltMethod = true;
1243 if ( m_bHasDfltProperty || m_bHasDfltMethod )
1244 m_sDefaultMember = usName;
1247 catch ( BridgeRuntimeError & e )
1249 throw RuntimeException( e.message, Reference<XInterface>() );
1251 catch( Exception& e )
1253 throw RuntimeException(
1254 OUSTR("[automation bridge] unexpected exception in IUnknownWrapper_Impl::initialiase() error message: \n") + e.Message,
1255 Reference<XInterface>() );
1260 // UnoConversionUtilities --------------------------------------------------------------------------------
1261 Reference< XInterface > IUnknownWrapper_Impl::createUnoWrapperInstance()
1263 if( m_nUnoWrapperClass == INTERFACE_OLE_WRAPPER_IMPL)
1265 Reference<XWeak> xWeak= static_cast<XWeak*>( new InterfaceOleWrapper_Impl(
1266 m_smgr, m_nUnoWrapperClass, m_nComWrapperClass));
1267 return Reference<XInterface>( xWeak, UNO_QUERY);
1269 else if( m_nUnoWrapperClass == UNO_OBJECT_WRAPPER_REMOTE_OPT)
1271 Reference<XWeak> xWeak= static_cast<XWeak*>( new UnoObjectWrapperRemoteOpt(
1272 m_smgr, m_nUnoWrapperClass, m_nComWrapperClass));
1273 return Reference<XInterface>( xWeak, UNO_QUERY);
1275 else
1276 return Reference<XInterface>();
1278 Reference<XInterface> IUnknownWrapper_Impl::createComWrapperInstance()
1280 Reference<XWeak> xWeak= static_cast<XWeak*>( new IUnknownWrapper_Impl(
1281 m_smgr, m_nUnoWrapperClass, m_nComWrapperClass));
1282 return Reference<XInterface>( xWeak, UNO_QUERY);
1287 void IUnknownWrapper_Impl::getMethodInfo(const OUString& sName, TypeDescription& methodInfo)
1289 TypeDescription desc= getInterfaceMemberDescOfCurrentCall(sName);
1290 if( desc.is())
1292 typelib_TypeDescription* pMember= desc.get();
1293 if( pMember->eTypeClass == TypeClass_INTERFACE_METHOD )
1294 methodInfo= pMember;
1298 void IUnknownWrapper_Impl::getAttributeInfo(const OUString& sName, TypeDescription& attributeInfo)
1300 TypeDescription desc= getInterfaceMemberDescOfCurrentCall(sName);
1301 if( desc.is())
1303 typelib_TypeDescription* pMember= desc.get();
1304 if( pMember->eTypeClass == TypeClass_INTERFACE_ATTRIBUTE )
1306 attributeInfo= ((typelib_InterfaceAttributeTypeDescription*)pMember)->pAttributeTypeRef;
1310 TypeDescription IUnknownWrapper_Impl::getInterfaceMemberDescOfCurrentCall(const OUString& sName)
1312 TypeDescription ret;
1314 for( sal_Int32 i=0; i < m_seqTypes.getLength(); i++)
1316 TypeDescription _curDesc( m_seqTypes[i]);
1317 _curDesc.makeComplete();
1318 typelib_InterfaceTypeDescription * pInterface= (typelib_InterfaceTypeDescription*) _curDesc.get();
1319 if( pInterface)
1321 typelib_InterfaceMemberTypeDescription* pMember= NULL;
1322 //find the member description of the current call
1323 for( int i=0; i < pInterface->nAllMembers; i++)
1325 typelib_TypeDescriptionReference* pTypeRefMember = pInterface->ppAllMembers[i];
1326 typelib_TypeDescription* pDescMember= NULL;
1327 TYPELIB_DANGER_GET( &pDescMember, pTypeRefMember)
1329 typelib_InterfaceMemberTypeDescription* pInterfaceMember=
1330 (typelib_InterfaceMemberTypeDescription*) pDescMember;
1331 if( OUString( pInterfaceMember->pMemberName) == sName)
1333 pMember= pInterfaceMember;
1334 break;
1336 TYPELIB_DANGER_RELEASE( pDescMember)
1339 if( pMember)
1341 ret= (typelib_TypeDescription*)pMember;
1342 TYPELIB_DANGER_RELEASE( (typelib_TypeDescription*)pMember);
1345 if( ret.is())
1346 break;
1348 return ret;
1351 sal_Bool IUnknownWrapper_Impl::isJScriptObject()
1353 if( m_eJScript == JScriptUndefined)
1355 CComDispatchDriver disp( m_spDispatch);
1356 if( disp)
1358 CComVariant result;
1359 if( SUCCEEDED( disp.GetPropertyByName( JSCRIPT_ID_PROPERTY, &result)))
1361 if(result.vt == VT_BSTR)
1363 CComBSTR name( result.bstrVal);
1364 name.ToLower();
1365 if( name == CComBSTR(JSCRIPT_ID))
1366 m_eJScript= IsJScript;
1370 if( m_eJScript == JScriptUndefined)
1371 m_eJScript= NoJScript;
1374 return m_eJScript == NoJScript ? sal_False : sal_True;
1379 /** @internal
1380 The function ultimately calls IDispatch::Invoke on the wrapped COM object.
1381 The COM object does not implement UNO Interfaces ( via IDispatch). This
1382 is the case when the OleObjectFactory service has been used to create a
1383 component.
1384 @exception IllegalArgumentException
1385 @exception CannotConvertException
1386 @InvocationTargetException
1387 @RuntimeException
1388 @BridgeRuntimeError
1390 Any IUnknownWrapper_Impl::invokeWithDispIdComTlb(const OUString& sFuncName,
1391 const Sequence< Any >& Params,
1392 Sequence< sal_Int16 >& OutParamIndex,
1393 Sequence< Any >& OutParam)
1395 Any ret;
1396 HRESULT result;
1398 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1399 CComVariant varResult;
1400 ExcepInfo excepinfo;
1401 unsigned int uArgErr;
1402 sal_Int32 i = 0;
1403 sal_Int32 nUnoArgs = Params.getLength();
1404 DISPID idPropertyPut = DISPID_PROPERTYPUT;
1405 scoped_array<DISPID> arDispidNamedArgs;
1406 scoped_array<CComVariant> ptrArgs;
1407 scoped_array<CComVariant> ptrRefArgs; // referenced arguments
1408 CComVariant * arArgs = NULL;
1409 CComVariant * arRefArgs = NULL;
1410 sal_Int32 revIndex = 0;
1411 bool bVarargParam = false;
1413 // Get type info for the call. It can be a method call or property put or
1414 // property get operation.
1415 FuncDesc aFuncDesc(getTypeInfo());
1416 getFuncDescForInvoke(sFuncName, Params, & aFuncDesc);
1418 //Set the array of DISPIDs for named args if it is a property put operation.
1419 //If there are other named arguments another array is set later on.
1420 if (aFuncDesc->invkind == INVOKE_PROPERTYPUT
1421 || aFuncDesc->invkind == INVOKE_PROPERTYPUTREF)
1422 dispparams.rgdispidNamedArgs = & idPropertyPut;
1424 //Determine the number of named arguments
1425 for (int iParam = 0; iParam < nUnoArgs; iParam ++)
1427 const Any & curArg = Params[iParam];
1428 if (curArg.getValueType() == getCppuType((NamedArgument*) 0))
1429 dispparams.cNamedArgs ++;
1431 //In a property put operation a property value is a named argument (DISPID_PROPERTYPUT).
1432 //Therefore the number of named arguments is increased by one.
1433 //Although named, the argument is not named in a actual language, such as Basic,
1434 //therefore it is never a com.sun.star.bridge.oleautomation.NamedArgument
1435 if (aFuncDesc->invkind == DISPATCH_PROPERTYPUT
1436 || aFuncDesc->invkind == DISPATCH_PROPERTYPUTREF)
1437 dispparams.cNamedArgs ++;
1439 //Determine the number of all arguments and named arguments
1440 if (aFuncDesc->cParamsOpt == -1)
1442 //Attribute vararg is set on this method. "Unlimited" number of args
1443 //supported. There can be no optional or defaultvalue on any of the arguments.
1444 dispparams.cArgs = nUnoArgs;
1446 else
1448 //If there are namesd arguments, then the dispparams.cArgs
1449 //is the number of supplied args, otherwise it is the expected number.
1450 if (dispparams.cNamedArgs)
1451 dispparams.cArgs = nUnoArgs;
1452 else
1453 dispparams.cArgs = aFuncDesc->cParams;
1456 //check if there are not to many arguments supplied
1457 if (::sal::static_int_cast< sal_uInt32, int >( nUnoArgs ) > dispparams.cArgs)
1459 OUStringBuffer buf(256);
1460 buf.appendAscii("[automation bridge] There are too many arguments for this method");
1461 throw IllegalArgumentException( buf.makeStringAndClear(),
1462 Reference<XInterface>(), (sal_Int16) dispparams.cArgs);
1465 //Set up the array of DISPIDs (DISPPARAMS::rgdispidNamedArgs)
1466 //for the named arguments.
1467 //If there is only one named arg and if it is because of a property put
1468 //operation, then we need not set up the DISPID array.
1469 if (dispparams.cNamedArgs > 0 &&
1470 ! (dispparams.cNamedArgs == 1 &&
1471 (aFuncDesc->invkind == INVOKE_PROPERTYPUT ||
1472 aFuncDesc->invkind == INVOKE_PROPERTYPUT)))
1474 //set up an array containing the member and parameter names
1475 //which is then used in ITypeInfo::GetIDsOfNames
1476 //First determine the size of the array of names which is passed to
1477 //ITypeInfo::GetIDsOfNames. It must hold the method names + the named
1478 //args.
1479 int nSizeAr = dispparams.cNamedArgs + 1;
1480 if (aFuncDesc->invkind == INVOKE_PROPERTYPUT
1481 || aFuncDesc->invkind == INVOKE_PROPERTYPUTREF)
1483 nSizeAr = dispparams.cNamedArgs; //counts the DISID_PROPERTYPUT
1486 scoped_array<OLECHAR*> saNames(new OLECHAR*[nSizeAr]);
1487 OLECHAR ** arNames = saNames.get();
1488 arNames[0] = const_cast<OLECHAR*>(reinterpret_cast<LPCOLESTR>(sFuncName.getStr()));
1490 int cNamedArg = 0;
1491 for (size_t iParams = 0; iParams < dispparams.cArgs; iParams ++)
1493 const Any & curArg = Params[iParams];
1494 if (curArg.getValueType() == getCppuType((NamedArgument*) 0))
1496 const NamedArgument& arg = *(NamedArgument const*) curArg.getValue();
1497 //We put the parameter names in reverse order into the array,
1498 //so we can use the DISPID array for DISPPARAMS::rgdispidNamedArgs
1499 //The first name in the array is the method name
1500 arNames[nSizeAr - 1 - cNamedArg++] = const_cast<OLECHAR*>(reinterpret_cast<LPCOLESTR>(arg.Name.getStr()));
1504 //Prepare the array of DISPIDs for ITypeInfo::GetIDsOfNames
1505 //it must be big enough to contain the DISPIDs of the member + parameters
1506 arDispidNamedArgs.reset(new DISPID[nSizeAr]);
1507 HRESULT hr = getTypeInfo()->GetIDsOfNames(arNames, nSizeAr,
1508 arDispidNamedArgs.get());
1509 if ( hr == E_NOTIMPL )
1510 hr = m_spDispatch->GetIDsOfNames(IID_NULL, arNames, nSizeAr, LOCALE_USER_DEFAULT, arDispidNamedArgs.get() );
1512 if (hr == S_OK)
1514 // In a "property put" operation, the property value is a named param with the
1515 //special DISPID DISPID_PROPERTYPUT
1516 if (aFuncDesc->invkind == DISPATCH_PROPERTYPUT
1517 || aFuncDesc->invkind == DISPATCH_PROPERTYPUTREF)
1519 //Element at index 0 in the DISPID array must be DISPID_PROPERTYPUT
1520 //The first item in the array arDispidNamedArgs is the DISPID for
1521 //the method. We replace it with DISPID_PROPERTYPUT.
1522 DISPID* arIDs = arDispidNamedArgs.get();
1523 arIDs[0] = DISPID_PROPERTYPUT;
1524 dispparams.rgdispidNamedArgs = arIDs;
1526 else
1528 //The first item in the array arDispidNamedArgs is the DISPID for
1529 //the method. It must be removed
1530 DISPID* arIDs = arDispidNamedArgs.get();
1531 dispparams.rgdispidNamedArgs = & arIDs[1];
1534 else if (hr == DISP_E_UNKNOWNNAME)
1536 throw IllegalArgumentException(
1537 OUSTR("[automation bridge]One of the named arguments is wrong!"),
1538 Reference<XInterface>(), 0);
1540 else
1542 throw InvocationTargetException(
1543 OUSTR("[automation bridge] ITypeInfo::GetIDsOfNames returned error ")
1544 + OUString::valueOf((sal_Int32) hr, 16), Reference<XInterface>(), Any());
1548 //Convert arguments
1549 ptrArgs.reset(new CComVariant[dispparams.cArgs]);
1550 ptrRefArgs.reset(new CComVariant[dispparams.cArgs]);
1551 arArgs = ptrArgs.get();
1552 arRefArgs = ptrRefArgs.get();
1555 for (i = 0; i < (sal_Int32) dispparams.cArgs; i++)
1557 revIndex= dispparams.cArgs - i -1;
1558 arRefArgs[revIndex].byref=0;
1559 Any anyArg;
1560 if ( i < nUnoArgs)
1561 anyArg= Params.getConstArray()[i];
1563 //Test if the current parameter is a "vararg" parameter.
1564 if (bVarargParam || (aFuncDesc->cParamsOpt == -1 &&
1565 aFuncDesc->cParams == (i + 1)))
1566 { //This parameter is from the variable argument list. There is no
1567 //type info available, except that it must be a VARIANT
1568 bVarargParam = true;
1571 unsigned short paramFlags = PARAMFLAG_FOPT | PARAMFLAG_FIN;
1572 VARTYPE varType = VT_VARIANT;
1573 if ( ! bVarargParam)
1575 paramFlags =
1576 aFuncDesc->lprgelemdescParam[i].paramdesc.wParamFlags;
1577 varType = getElementTypeDesc(
1578 & aFuncDesc->lprgelemdescParam[i].tdesc);
1580 //Make sure that there is a UNO parameter for every
1581 // expected parameter. If there is no UNO parameter where the
1582 // called function expects one, then it must be optional. Otherwise
1583 // its a UNO programming error.
1584 if (i >= nUnoArgs && !(paramFlags & PARAMFLAG_FOPT))
1586 OUStringBuffer buf(256);
1587 buf.appendAscii("ole automation bridge: The called function expects an argument at"
1588 "position: "); //a different number of arguments")),
1589 buf.append(OUString::valueOf((sal_Int32) i));
1590 buf.appendAscii(" (index starting at 0).");
1591 throw IllegalArgumentException( buf.makeStringAndClear(),
1592 Reference<XInterface>(), (sal_Int16) i);
1594 //make sure we get no void any for an in parameter. In StarBasic
1595 //this may be caused by
1596 // Dim arg
1597 // obj.func(arg)
1598 //A void any is allowed if the parameter is optional
1599 if ( ! (aFuncDesc->lprgelemdescParam[i].paramdesc.wParamFlags & PARAMFLAG_FOPT)
1600 && (i < nUnoArgs) && (paramFlags & PARAMFLAG_FIN) &&
1601 Params.getConstArray()[i].getValueTypeClass() == TypeClass_VOID)
1603 OUStringBuffer buf(256);
1604 buf.appendAscii("ole automation bridge: The argument at position: ");
1605 buf.append(OUString::valueOf((sal_Int32) i));
1606 buf.appendAscii(" (index starts with 0) is uninitialized.");
1607 throw IllegalArgumentException( buf.makeStringAndClear(),
1608 Reference<XInterface>(), (sal_Int16) i);
1611 // Property Put arguments
1612 if (anyArg.getValueType() == getCppuType((PropertyPutArgument*)0))
1614 PropertyPutArgument arg;
1615 anyArg >>= arg;
1616 anyArg <<= arg.Value;
1618 // named argument
1619 if (anyArg.getValueType() == getCppuType((NamedArgument*) 0))
1621 NamedArgument aNamedArgument;
1622 anyArg >>= aNamedArgument;
1623 anyArg <<= aNamedArgument.Value;
1625 // out param
1626 if (paramFlags & PARAMFLAG_FOUT &&
1627 ! (paramFlags & PARAMFLAG_FIN) )
1629 VARTYPE type = ::sal::static_int_cast< VARTYPE, int >( varType ^ VT_BYREF );
1630 if (i < nUnoArgs)
1632 arRefArgs[revIndex].vt= type;
1634 else
1636 //optional arg
1637 arRefArgs[revIndex].vt = VT_ERROR;
1638 arRefArgs[revIndex].scode = DISP_E_PARAMNOTFOUND;
1640 if( type == VT_VARIANT )
1642 arArgs[revIndex].vt= VT_VARIANT | VT_BYREF;
1643 arArgs[revIndex].byref= &arRefArgs[revIndex];
1645 else
1647 arArgs[revIndex].vt= varType;
1648 if (type == VT_DECIMAL)
1649 arArgs[revIndex].byref= & arRefArgs[revIndex].decVal;
1650 else
1651 arArgs[revIndex].byref= & arRefArgs[revIndex].byref;
1654 // in/out + in byref params
1655 else if (varType & VT_BYREF)
1657 VARTYPE type = ::sal::static_int_cast< VARTYPE, int >( varType ^ VT_BYREF );
1658 CComVariant var;
1660 if (i < nUnoArgs && anyArg.getValueTypeClass() != TypeClass_VOID)
1662 anyToVariant( & arRefArgs[revIndex], anyArg, type);
1664 else if (paramFlags & PARAMFLAG_FHASDEFAULT)
1666 //optional arg with default
1667 VariantCopy( & arRefArgs[revIndex],
1668 & aFuncDesc->lprgelemdescParam[i].paramdesc.
1669 pparamdescex->varDefaultValue);
1671 else
1673 //optional arg
1674 //e.g: call func(x) in basic : func() ' no arg supplied
1675 OSL_ASSERT(paramFlags & PARAMFLAG_FOPT);
1676 arRefArgs[revIndex].vt = VT_ERROR;
1677 arRefArgs[revIndex].scode = DISP_E_PARAMNOTFOUND;
1680 // Set the converted arguments in the array which will be
1681 // DISPPARAMS::rgvarg
1682 // byref arg VT_XXX |VT_BYREF
1683 arArgs[revIndex].vt = varType;
1684 if (revIndex == 0 && aFuncDesc->invkind == INVOKE_PROPERTYPUT)
1686 arArgs[revIndex] = arRefArgs[revIndex];
1688 else if (type == VT_DECIMAL)
1690 arArgs[revIndex].byref= & arRefArgs[revIndex].decVal;
1692 else if (type == VT_VARIANT)
1694 if ( ! (paramFlags & PARAMFLAG_FOUT))
1695 arArgs[revIndex] = arRefArgs[revIndex];
1696 else
1697 arArgs[revIndex].byref = & arRefArgs[revIndex];
1699 else
1701 arArgs[revIndex].byref = & arRefArgs[revIndex].byref;
1702 arArgs[revIndex].vt = ::sal::static_int_cast< VARTYPE, int >( arRefArgs[revIndex].vt | VT_BYREF );
1706 // in parameter no VT_BYREF except for array, interfaces
1707 else
1708 { // void any stands for optional param
1709 if (i < nUnoArgs && anyArg.getValueTypeClass() != TypeClass_VOID)
1711 anyToVariant( & arArgs[revIndex], anyArg, varType);
1713 //optional arg but no void any supplied
1714 //Basic: obj.func() ' first parameter left out because it is optional
1715 else if (paramFlags & PARAMFLAG_FHASDEFAULT)
1717 //optional arg with defaulteithter as direct arg : VT_XXX or
1718 VariantCopy( & arArgs[revIndex],
1719 & aFuncDesc->lprgelemdescParam[i].paramdesc.
1720 pparamdescex->varDefaultValue);
1722 else
1724 OSL_ASSERT(paramFlags & PARAMFLAG_FOPT);
1725 arArgs[revIndex].vt = VT_ERROR;
1726 arArgs[revIndex].scode = DISP_E_PARAMNOTFOUND;
1731 catch (IllegalArgumentException & e)
1733 e.ArgumentPosition = ::sal::static_int_cast< sal_Int16, sal_Int32 >( i );
1734 throw;
1736 catch (CannotConvertException & e)
1738 e.ArgumentIndex = i;
1739 throw;
1741 dispparams.rgvarg= arArgs;
1742 // invoking OLE method
1743 DWORD localeId = LOCALE_USER_DEFAULT;
1744 result = m_spDispatch->Invoke(aFuncDesc->memid,
1745 IID_NULL,
1746 localeId,
1747 ::sal::static_int_cast< WORD, INVOKEKIND >( aFuncDesc->invkind ),
1748 &dispparams,
1749 &varResult,
1750 &excepinfo,
1751 &uArgErr);
1753 // converting return value and out parameter back to UNO
1754 if (result == S_OK)
1757 // allocate space for the out param Sequence and indices Sequence
1758 int outParamsCount= 0; // includes in/out parameter
1759 for (int i = 0; i < aFuncDesc->cParams; i++)
1761 if (aFuncDesc->lprgelemdescParam[i].paramdesc.wParamFlags &
1762 PARAMFLAG_FOUT)
1763 outParamsCount++;
1766 OutParamIndex.realloc(outParamsCount);
1767 OutParam.realloc(outParamsCount);
1768 // Convert out params
1769 if (outParamsCount)
1771 int outParamIndex=0;
1772 for (int paramIndex = 0; paramIndex < nUnoArgs; paramIndex ++)
1774 //Determine the index within the method sinature
1775 int realParamIndex = paramIndex;
1776 int revParamIndex = dispparams.cArgs - paramIndex - 1;
1777 if (Params[paramIndex].getValueType()
1778 == getCppuType((NamedArgument*) 0))
1780 //dispparams.rgdispidNamedArgs contains the mapping from index
1781 //of named args list to index of parameter list
1782 realParamIndex = dispparams.rgdispidNamedArgs[revParamIndex];
1785 // no named arg, always come before named args
1786 if (! (aFuncDesc->lprgelemdescParam[realParamIndex].paramdesc.wParamFlags
1787 & PARAMFLAG_FOUT))
1788 continue;
1789 Any outAny;
1790 // variantToAny is called with the "reduce range" parameter set to sal_False.
1791 // That causes VT_I4 values not to be converted down to a "lower" type. That
1792 // feature exist for JScript only because it only uses VT_I4 for integer types.
1795 variantToAny( & arRefArgs[revParamIndex], outAny, sal_False );
1797 catch (IllegalArgumentException & e)
1799 e.ArgumentPosition = (sal_Int16)paramIndex;
1800 throw;
1802 catch (CannotConvertException & e)
1804 e.ArgumentIndex = paramIndex;
1805 throw;
1807 OutParam[outParamIndex] = outAny;
1808 OutParamIndex[outParamIndex] = ::sal::static_int_cast< sal_Int16, int >( paramIndex );
1809 outParamIndex++;
1811 OutParam.realloc(outParamIndex);
1812 OutParamIndex.realloc(outParamIndex);
1814 // Return value
1815 variantToAny(&varResult, ret, sal_False);
1818 // map error codes to exceptions
1819 OUString message;
1820 switch (result)
1822 case S_OK:
1823 break;
1824 case DISP_E_BADPARAMCOUNT:
1825 throw IllegalArgumentException(OUSTR("[automation bridge] Wrong "
1826 "number of arguments. Object returned DISP_E_BADPARAMCOUNT."),
1827 0, 0);
1828 break;
1829 case DISP_E_BADVARTYPE:
1830 throw RuntimeException(OUSTR("[automation bridge] One or more "
1831 "arguments have the wrong type. Object returned "
1832 "DISP_E_BADVARTYPE."), 0);
1833 break;
1834 case DISP_E_EXCEPTION:
1835 message = OUSTR("[automation bridge]: ");
1836 message += OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription),
1837 ::SysStringLen(excepinfo.bstrDescription));
1838 throw InvocationTargetException(message, Reference<XInterface>(), Any());
1839 break;
1840 case DISP_E_MEMBERNOTFOUND:
1841 message = OUSTR("[automation bridge]: A function with the name \"")
1842 + sFuncName + OUSTR("\" is not supported. Object returned "
1843 "DISP_E_MEMBERNOTFOUND.");
1844 throw IllegalArgumentException(message, 0, 0);
1845 break;
1846 case DISP_E_NONAMEDARGS:
1847 throw IllegalArgumentException(OUSTR("[automation bridge] Object "
1848 "returned DISP_E_NONAMEDARGS"),0, ::sal::static_int_cast< sal_Int16, unsigned int >( uArgErr ));
1849 break;
1850 case DISP_E_OVERFLOW:
1851 throw CannotConvertException(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("[automation bridge] Call failed.")),
1852 static_cast<XInterface*>(
1853 static_cast<XWeak*>(this)), TypeClass_UNKNOWN, FailReason::OUT_OF_RANGE, uArgErr);
1854 break;
1855 case DISP_E_PARAMNOTFOUND:
1856 throw IllegalArgumentException(OUSTR("[automation bridge]Call failed."
1857 "Object returned DISP_E_PARAMNOTFOUND."),
1858 0, ::sal::static_int_cast< sal_Int16, unsigned int >( uArgErr ));
1859 break;
1860 case DISP_E_TYPEMISMATCH:
1861 throw CannotConvertException(OUSTR("[automation bridge] Call failed. "
1862 "Object returned DISP_E_TYPEMISMATCH"),
1863 static_cast<XInterface*>(
1864 static_cast<XWeak*>(this)) , TypeClass_UNKNOWN, FailReason::UNKNOWN, uArgErr);
1865 break;
1866 case DISP_E_UNKNOWNINTERFACE:
1867 throw RuntimeException(OUSTR("[automation bridge] Call failed. "
1868 "Object returned DISP_E_UNKNOWNINTERFACE."),0);
1869 break;
1870 case DISP_E_UNKNOWNLCID:
1871 throw RuntimeException(OUSTR("[automation bridge] Call failed. "
1872 "Object returned DISP_E_UNKNOWNLCID."),0);
1873 break;
1874 case DISP_E_PARAMNOTOPTIONAL:
1875 throw CannotConvertException(OUSTR("[automation bridge] Call failed."
1876 "Object returned DISP_E_PARAMNOTOPTIONAL"),
1877 static_cast<XInterface*>(static_cast<XWeak*>(this)),
1878 TypeClass_UNKNOWN, FailReason::NO_DEFAULT_AVAILABLE, uArgErr);
1879 break;
1880 default:
1881 throw RuntimeException();
1882 break;
1885 return ret;
1888 void IUnknownWrapper_Impl::getFuncDescForInvoke(const OUString & sFuncName,
1889 const Sequence<Any> & seqArgs,
1890 FUNCDESC** pFuncDesc)
1892 int nUnoArgs = seqArgs.getLength();
1893 const Any * arArgs = seqArgs.getConstArray();
1894 ITypeInfo* pInfo = getTypeInfo();
1896 //If the last of the positional arguments is a PropertyPutArgument
1897 //then obtain the type info for the property put operation.
1899 //The property value is always the last argument, in a positional argument list
1900 //or in a list of named arguments. A PropertyPutArgument is actually a named argument
1901 //hence it must not be put in an extra NamedArgument structure
1902 if (nUnoArgs > 0 &&
1903 arArgs[nUnoArgs - 1].getValueType() == getCppuType((PropertyPutArgument*) 0))
1905 // DISPATCH_PROPERTYPUT
1906 FuncDesc aDescGet(pInfo);
1907 FuncDesc aDescPut(pInfo);
1908 VarDesc aVarDesc(pInfo);
1909 getPropDesc(sFuncName, & aDescGet, & aDescPut, & aVarDesc);
1910 if ( ! aDescPut)
1912 throw IllegalArgumentException(
1913 OUSTR("[automation bridge] The object does not have a writeable property: ")
1914 + sFuncName, Reference<XInterface>(), 0);
1916 *pFuncDesc = aDescPut.Detach();
1918 else
1919 { // DISPATCH_METHOD
1920 FuncDesc aFuncDesc(pInfo);
1921 getFuncDesc(sFuncName, & aFuncDesc);
1922 if ( ! aFuncDesc)
1924 // Fallback: DISPATCH_PROPERTYGET can mostly be called as
1925 // DISPATCH_METHOD
1926 ITypeInfo * pInfo = getTypeInfo();
1927 FuncDesc aDescPut(pInfo);
1928 VarDesc aVarDesc(pInfo);
1929 getPropDesc(sFuncName, & aFuncDesc, & aDescPut, & aVarDesc);
1930 if ( ! aFuncDesc )
1932 throw IllegalArgumentException(
1933 OUSTR("[automation bridge] The object does not have a function"
1934 "or readable property \"")
1935 + sFuncName, Reference<XInterface>(), 0);
1938 *pFuncDesc = aFuncDesc.Detach();
1941 bool IUnknownWrapper_Impl::getDispid(const OUString& sFuncName, DISPID * id)
1943 OSL_ASSERT(m_spDispatch);
1944 LPOLESTR lpsz = const_cast<LPOLESTR> (reinterpret_cast<LPCOLESTR>(sFuncName.getStr()));
1945 HRESULT hr = m_spDispatch->GetIDsOfNames(IID_NULL, &lpsz, 1, LOCALE_USER_DEFAULT, id);
1946 return hr == S_OK ? true : false;
1948 void IUnknownWrapper_Impl::getFuncDesc(const OUString & sFuncName, FUNCDESC ** pFuncDesc)
1951 OSL_ASSERT( * pFuncDesc == 0);
1952 buildComTlbIndex();
1953 typedef TLBFuncIndexMap::const_iterator cit;
1954 typedef TLBFuncIndexMap::iterator it;
1955 //We assume there is only one entry with the function name. A property
1956 //would have two entries.
1957 cit itIndex= m_mapComFunc.find(sFuncName);
1958 if (itIndex == m_mapComFunc.end())
1960 //try case insensive with IDispatch::GetIDsOfNames
1961 DISPID id;
1962 if (getDispid(sFuncName, &id))
1964 CComBSTR memberName;
1965 unsigned int pcNames=0;
1966 // get the case sensitive name
1967 if( SUCCEEDED(getTypeInfo()->GetNames( id, & memberName, 1, &pcNames)))
1969 //get the associated index and add an entry to the map
1970 //with the name sFuncName which differs in the casing of the letters to
1971 //the actual name as obtained from ITypeInfo
1972 cit itOrg = m_mapComFunc.find(OUString(reinterpret_cast<const sal_Unicode*>(LPCOLESTR(memberName))));
1973 OSL_ASSERT(itOrg != m_mapComFunc.end());
1974 itIndex =
1975 m_mapComFunc.insert( TLBFuncIndexMap::value_type
1976 ( make_pair(sFuncName, itOrg->second ) ));
1981 #if OSL_DEBUG_LEVEL >= 1
1982 // There must only be one entry if sFuncName represents a function or two
1983 // if it is a property
1984 pair<cit, cit> p = m_mapComFunc.equal_range(sFuncName.toAsciiLowerCase());
1985 int numEntries = 0;
1986 for ( ;p.first != p.second; p.first ++, numEntries ++);
1987 OSL_ASSERT( ! (numEntries > 3) );
1988 #endif
1989 if( itIndex != m_mapComFunc.end())
1991 ITypeInfo* pType= getTypeInfo();
1992 FUNCDESC * pDesc = NULL;
1993 if (SUCCEEDED(pType->GetFuncDesc(itIndex->second, & pDesc)))
1995 if (pDesc->invkind == INVOKE_FUNC)
1997 (*pFuncDesc) = pDesc;
1999 else
2001 pType->ReleaseFuncDesc(pDesc);
2004 else
2006 throw BridgeRuntimeError(OUSTR("[automation bridge] Could not get "
2007 "FUNCDESC for ") + sFuncName);
2010 //else no entry found for sFuncName, pFuncDesc will not be filled in
2013 void IUnknownWrapper_Impl::getPropDesc(const OUString & sFuncName, FUNCDESC ** pFuncDescGet,
2014 FUNCDESC** pFuncDescPut, VARDESC** pVarDesc)
2016 OSL_ASSERT( * pFuncDescGet == 0 && * pFuncDescPut == 0);
2017 buildComTlbIndex();
2018 typedef TLBFuncIndexMap::const_iterator cit;
2019 pair<cit, cit> p = m_mapComFunc.equal_range(sFuncName);
2020 if (p.first == m_mapComFunc.end())
2022 //try case insensive with IDispatch::GetIDsOfNames
2023 DISPID id;
2024 if (getDispid(sFuncName, &id))
2026 CComBSTR memberName;
2027 unsigned int pcNames=0;
2028 // get the case sensitive name
2029 if( SUCCEEDED(getTypeInfo()->GetNames( id, & memberName, 1, &pcNames)))
2031 //As opposed to getFuncDesc, we do not add the value because we would
2032 // need to find the get and set description for the property. This would
2033 //mean to iterate over all FUNCDESCs again.
2034 p = m_mapComFunc.equal_range(OUString(reinterpret_cast<const sal_Unicode*>(LPCOLESTR(memberName))));
2039 for ( int i = 0 ;p.first != p.second; p.first ++, i ++)
2041 // There are a maximum of two entries, property put and property get
2042 OSL_ASSERT( ! (i > 2) );
2043 ITypeInfo* pType= getTypeInfo();
2044 FUNCDESC * pFuncDesc = NULL;
2045 if (SUCCEEDED( pType->GetFuncDesc(p.first->second, & pFuncDesc)))
2047 if (pFuncDesc->invkind == INVOKE_PROPERTYGET)
2049 (*pFuncDescGet) = pFuncDesc;
2051 else if (pFuncDesc->invkind == INVOKE_PROPERTYPUT ||
2052 pFuncDesc->invkind == INVOKE_PROPERTYPUTREF)
2054 //a property can have 3 entries, put, put ref, get
2055 // If INVOKE_PROPERTYPUTREF or INVOKE_PROPERTYPUT is used
2056 //depends on what is found first.
2057 if ( * pFuncDescPut)
2059 //we already have found one
2060 pType->ReleaseFuncDesc(pFuncDesc);
2062 else
2064 (*pFuncDescPut) = pFuncDesc;
2067 else
2069 pType->ReleaseFuncDesc(pFuncDesc);
2072 //ITypeInfo::GetFuncDesc may even provide a funcdesc for a VARDESC
2073 // with invkind = INVOKE_FUNC. Since this function should only return
2074 //a value for a real property (XInvokation::hasMethod, ..::hasProperty
2075 //we need to make sure that sFuncName represents a real property.
2076 VARDESC * pVD = NULL;
2077 if (SUCCEEDED(pType->GetVarDesc(p.first->second, & pVD)))
2078 (*pVarDesc) = pVD;
2080 //else no entry for sFuncName, pFuncDesc will not be filled in
2083 VARTYPE IUnknownWrapper_Impl::getElementTypeDesc(const TYPEDESC *desc)
2085 VARTYPE _type( VT_NULL );
2087 if (desc->vt == VT_PTR)
2089 _type = getElementTypeDesc(desc->lptdesc);
2090 _type |= VT_BYREF;
2092 else if (desc->vt == VT_SAFEARRAY)
2094 _type = getElementTypeDesc(desc->lptdesc);
2095 _type |= VT_ARRAY;
2097 else if (desc->vt == VT_USERDEFINED)
2099 ITypeInfo* thisInfo = getTypeInfo(); //kept by this instance
2100 CComPtr<ITypeInfo> spRefInfo;
2101 thisInfo->GetRefTypeInfo(desc->hreftype, & spRefInfo.p);
2102 if (spRefInfo)
2104 TypeAttr attr(spRefInfo);
2105 spRefInfo->GetTypeAttr( & attr);
2106 if (attr->typekind == TKIND_ENUM)
2108 //We use the type of the first enum value.
2109 if (attr->cVars == 0)
2111 throw BridgeRuntimeError(OUSTR("[automation bridge] Could "
2112 "not obtain type description"));
2114 VarDesc var(spRefInfo);
2115 spRefInfo->GetVarDesc(0, & var);
2116 _type = var->lpvarValue->vt;
2118 else if (attr->typekind == TKIND_INTERFACE)
2120 _type = VT_UNKNOWN;
2122 else if (attr->typekind == TKIND_DISPATCH)
2124 _type = VT_DISPATCH;
2126 else
2128 throw BridgeRuntimeError(OUSTR("[automation bridge] "
2129 "Unhandled user defined type."));
2133 else
2135 _type = desc->vt;
2137 return _type;
2140 void IUnknownWrapper_Impl::buildComTlbIndex()
2142 if ( ! m_bComTlbIndexInit)
2144 MutexGuard guard(getBridgeMutex());
2146 if ( ! m_bComTlbIndexInit)
2148 OUString sError;
2149 ITypeInfo* pType= getTypeInfo();
2150 TypeAttr typeAttr(pType);
2151 if( SUCCEEDED( pType->GetTypeAttr( &typeAttr)))
2153 for( long i= 0; i < typeAttr->cFuncs; i++)
2155 FuncDesc funcDesc(pType);
2156 if( SUCCEEDED( pType->GetFuncDesc( i, &funcDesc)))
2158 CComBSTR memberName;
2159 unsigned int pcNames=0;
2160 if( SUCCEEDED(pType->GetNames( funcDesc->memid, & memberName, 1, &pcNames)))
2162 OUString usName(reinterpret_cast<const sal_Unicode*>(LPCOLESTR(memberName)));
2163 m_mapComFunc.insert( TLBFuncIndexMap::value_type( usName, i));
2165 else
2167 sError = OUSTR("[automation bridge] IUnknownWrapper_Impl::buildComTlbIndex, " \
2168 "ITypeInfo::GetNames failed.");
2171 else
2172 sError = OUSTR("[automation bridge] IUnknownWrapper_Impl::buildComTlbIndex, " \
2173 "ITypeInfo::GetFuncDesc failed.");
2176 //If we create an Object in JScript and a a property then it
2177 //has VARDESC instead of FUNCDESC
2178 for (long i = 0; i < typeAttr->cVars; i++)
2180 VarDesc varDesc(pType);
2181 if (SUCCEEDED(pType->GetVarDesc(i, & varDesc)))
2183 CComBSTR memberName;
2184 unsigned int pcNames = 0;
2185 if (SUCCEEDED(pType->GetNames(varDesc->memid, & memberName, 1, &pcNames)))
2187 if (varDesc->varkind == VAR_DISPATCH)
2189 OUString usName(reinterpret_cast<const sal_Unicode*>(LPCOLESTR(memberName)));
2190 m_mapComFunc.insert(TLBFuncIndexMap::value_type(
2191 usName, i));
2194 else
2196 sError = OUSTR("[automation bridge] IUnknownWrapper_Impl::buildComTlbIndex, " \
2197 "ITypeInfo::GetNames failed.");
2200 else
2201 sError = OUSTR("[automation bridge] IUnknownWrapper_Impl::buildComTlbIndex, " \
2202 "ITypeInfo::GetVarDesc failed.");
2206 else
2207 sError = OUSTR("[automation bridge] IUnknownWrapper_Impl::buildComTlbIndex, " \
2208 "ITypeInfo::GetTypeAttr failed.");
2210 if (sError.getLength())
2212 throw BridgeRuntimeError(sError);
2215 m_bComTlbIndexInit = true;
2221 ITypeInfo* IUnknownWrapper_Impl::getTypeInfo()
2223 if( !m_spDispatch)
2225 throw BridgeRuntimeError(OUSTR("The object has no IDispatch interface!"));
2228 if( !m_spTypeInfo )
2230 MutexGuard guard(getBridgeMutex());
2231 if( ! m_spTypeInfo)
2233 CComPtr< ITypeInfo > spType;
2234 if( SUCCEEDED( m_spDispatch->GetTypeInfo( 0, LOCALE_USER_DEFAULT, &spType.p)))
2237 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
2239 //If this is a dual interface then TYPEATTR::typekind is usually TKIND_INTERFACE
2240 //We need to get the type description for TKIND_DISPATCH
2241 TypeAttr typeAttr(spType.p);
2242 if( SUCCEEDED(spType->GetTypeAttr( &typeAttr)))
2244 if (typeAttr->typekind == TKIND_INTERFACE &&
2245 typeAttr->wTypeFlags & TYPEFLAG_FDUAL)
2247 HREFTYPE refDispatch;
2248 if (SUCCEEDED(spType->GetRefTypeOfImplType(::sal::static_int_cast< UINT, int >( -1 ), &refDispatch)))
2250 CComPtr<ITypeInfo> spTypeDisp;
2251 if (SUCCEEDED(spType->GetRefTypeInfo(refDispatch, & spTypeDisp)))
2252 m_spTypeInfo= spTypeDisp;
2254 else
2256 throw BridgeRuntimeError(
2257 OUSTR("[automation bridge] Could not obtain type information "
2258 "for dispatch interface." ));
2261 else if (typeAttr->typekind == TKIND_DISPATCH)
2263 m_spTypeInfo= spType;
2265 else
2267 throw BridgeRuntimeError(
2268 OUSTR("[automation bridge] Automation object does not "
2269 "provide type information."));
2273 else
2275 throw BridgeRuntimeError(OUSTR("[automation bridge]The dispatch object does not "
2276 "support ITypeInfo!"));
2280 return m_spTypeInfo;
2283 } // end namespace