xref: /AOO41X/main/extensions/source/ole/oleobjw.cxx (revision 3033dfcf8c739242feb0ed220e2d080f454b8919)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_extensions.hxx"
26 #include "ole2uno.hxx"
27 #include "rtl/ustrbuf.hxx"
28 
29 
30 #include "osl/diagnose.h"
31 #include "osl/doublecheckedlocking.h"
32 #include "osl/thread.h"
33 
34 #include "boost/scoped_array.hpp"
35 #include <com/sun/star/script/FailReason.hpp>
36 #include <com/sun/star/beans/XMaterialHolder.hpp>
37 #include <com/sun/star/script/XTypeConverter.hpp>
38 #include <com/sun/star/script/FinishEngineEvent.hpp>
39 #include <com/sun/star/script/InterruptReason.hpp>
40 #include <com/sun/star/script/XEngineListener.hpp>
41 #include <com/sun/star/script/XDebugging.hpp>
42 #include <com/sun/star/script/XInvocation.hpp>
43 #include <com/sun/star/script/ContextInformation.hpp>
44 #include <com/sun/star/script/FinishReason.hpp>
45 #include <com/sun/star/script/XEngine.hpp>
46 #include <com/sun/star/script/InterruptEngineEvent.hpp>
47 #include <com/sun/star/script/XLibraryAccess.hpp>
48 #include <com/sun/star/bridge/ModelDependent.hpp>
49 
50 #include "com/sun/star/bridge/oleautomation/NamedArgument.hpp"
51 #include "com/sun/star/bridge/oleautomation/PropertyPutArgument.hpp"
52 
53 #include <typelib/typedescription.hxx>
54 #include <rtl/uuid.h>
55 #include <rtl/memory.h>
56 #include <rtl/ustring.hxx>
57 
58 #include "jscriptclasses.hxx"
59 
60 #include "oleobjw.hxx"
61 #include "unoobjw.hxx"
62 #include <stdio.h>
63 using namespace std;
64 using namespace boost;
65 using namespace osl;
66 using namespace rtl;
67 using namespace cppu;
68 using namespace com::sun::star::script;
69 using namespace com::sun::star::lang;
70 using namespace com::sun::star::bridge;
71 using namespace com::sun::star::bridge::oleautomation;
72 using namespace com::sun::star::bridge::ModelDependent;
73 using namespace ::com::sun::star;
74 
75 #define JSCRIPT_ID_PROPERTY L"_environment"
76 #define JSCRIPT_ID          L"jscript"
77 namespace ole_adapter
78 {
79 
80 
81 // key: XInterface pointer created by Invocation Adapter Factory
82 // value: XInterface pointer to the wrapper class.
83 // Entries to the map are made within
84 // Any createOleObjectWrapper(IUnknown* pUnknown, const Type& aType);
85 // Entries are being deleted if the wrapper class's destructor has been
86 // called.
87 // Before UNO object is wrapped to COM object this map is checked
88 // to see if the UNO object is already a wrapper.
89 hash_map<sal_uInt32, sal_uInt32> AdapterToWrapperMap;
90 // key: XInterface of the wrapper object.
91 // value: XInterface of the Interface created by the Invocation Adapter Factory.
92 // A COM wrapper is responsible for removing the corresponding entry
93 // in AdapterToWrappperMap if it is being destroyed. Because the wrapper does not
94 // know about its adapted interface it uses WrapperToAdapterMap to get the
95 // adapted interface which is then used to locate the entry in AdapterToWrapperMap.
96 hash_map<sal_uInt32,sal_uInt32> WrapperToAdapterMap;
97 
98 hash_map<sal_uInt32, WeakReference<XInterface> > ComPtrToWrapperMap;
99 /*****************************************************************************
100 
101     class implementation IUnknownWrapper_Impl
102 
103 *****************************************************************************/
104 
IUnknownWrapper_Impl(Reference<XMultiServiceFactory> & xFactory,sal_uInt8 unoWrapperClass,sal_uInt8 comWrapperClass)105 IUnknownWrapper_Impl::IUnknownWrapper_Impl( Reference<XMultiServiceFactory>& xFactory,
106                                            sal_uInt8 unoWrapperClass, sal_uInt8 comWrapperClass):
107     UnoConversionUtilities<IUnknownWrapper_Impl>( xFactory, unoWrapperClass, comWrapperClass),
108     m_pxIdlClass( NULL), m_eJScript( JScriptUndefined),
109     m_bComTlbIndexInit(false),  m_bHasDfltMethod(false), m_bHasDfltProperty(false)
110 {
111 }
112 
113 
~IUnknownWrapper_Impl()114 IUnknownWrapper_Impl::~IUnknownWrapper_Impl()
115 {
116     o2u_attachCurrentThread();
117     MutexGuard guard(getBridgeMutex());
118     XInterface * xIntRoot = (OWeakObject *)this;
119 #if OSL_DEBUG_LEVEL > 0
120     acquire(); // make sure we don't delete us twice because of Reference
121     OSL_ASSERT( Reference<XInterface>( static_cast<XWeak*>(this), UNO_QUERY).get() == xIntRoot );
122 #endif
123 
124     // remove entries in global maps
125     typedef hash_map<sal_uInt32, sal_uInt32>::iterator _IT;
126     _IT it= WrapperToAdapterMap.find( (sal_uInt32) xIntRoot);
127     if( it != WrapperToAdapterMap.end())
128     {
129         sal_uInt32 adapter= it->second;
130 
131         AdapterToWrapperMap.erase( adapter);
132         WrapperToAdapterMap.erase( it);
133     }
134 
135     IT_Com it_c= ComPtrToWrapperMap.find( (sal_uInt32) m_spUnknown.p);
136     if(it_c != ComPtrToWrapperMap.end())
137         ComPtrToWrapperMap.erase(it_c);
138 
139 #if OSL_DEBUG_LEVEL > 0
140     fprintf(stderr,"[automation bridge] ComPtrToWrapperMap  contains: %i \n",
141             ComPtrToWrapperMap.size());
142 #endif
143 }
144 
queryInterface(const Type & t)145 Any IUnknownWrapper_Impl::queryInterface(const Type& t)
146     throw (RuntimeException)
147 {
148     if (t == getCppuType(static_cast<Reference<XDefaultMethod>*>( 0)) && !m_bHasDfltMethod )
149         return Any();
150     if (t == getCppuType(static_cast<Reference<XDefaultProperty>*>( 0)) && !m_bHasDfltProperty )
151         return Any();
152     if (t == getCppuType(static_cast<Reference<XInvocation>*>( 0)) && !m_spDispatch)
153         return Any();
154 
155     return WeakImplHelper7<XInvocation, XBridgeSupplier2,
156         XInitialization, XAutomationObject, XDefaultProperty, XDefaultMethod, XDirectInvocation>::queryInterface(t);
157 }
158 
getIntrospection(void)159 Reference<XIntrospectionAccess> SAL_CALL IUnknownWrapper_Impl::getIntrospection(void)
160     throw (RuntimeException )
161 {
162     Reference<XIntrospectionAccess> ret;
163 
164     return ret;
165 }
166 
167 
168 
invoke(const OUString & aFunctionName,const Sequence<Any> & aParams,Sequence<sal_Int16> & aOutParamIndex,Sequence<Any> & aOutParam)169 Any SAL_CALL IUnknownWrapper_Impl::invoke( const OUString& aFunctionName,
170              const Sequence< Any >& aParams, Sequence< sal_Int16 >& aOutParamIndex,
171              Sequence< Any >& aOutParam )
172     throw(IllegalArgumentException, CannotConvertException, InvocationTargetException,
173           RuntimeException)
174 {
175     if ( ! m_spDispatch )
176     {
177         throw RuntimeException(
178             OUSTR("[automation bridge] The object does not have an IDispatch interface"),
179             Reference<XInterface>());
180     }
181 
182     Any ret;
183 
184     try
185     {
186         o2u_attachCurrentThread();
187 
188         TypeDescription methodDesc;
189         getMethodInfo(aFunctionName, methodDesc);
190         if( methodDesc.is())
191         {
192             ret = invokeWithDispIdUnoTlb(aFunctionName,
193                                          aParams,
194                                          aOutParamIndex,
195                                          aOutParam);
196         }
197         else
198         {
199             ret= invokeWithDispIdComTlb( aFunctionName,
200                                          aParams,
201                                          aOutParamIndex,
202                                          aOutParam);
203         }
204     }
205     catch (IllegalArgumentException &)
206     {
207         throw;
208     }
209     catch (CannotConvertException &)
210     {
211         throw;
212     }
213     catch (BridgeRuntimeError & e)
214     {
215          throw RuntimeException(e.message, Reference<XInterface>());
216     }
217     catch (Exception & e)
218     {
219         throw RuntimeException(OUSTR("[automation bridge] unexpected exception in "
220                                      "IUnknownWrapper_Impl::invoke ! Message : \n") +
221                                e.Message, Reference<XInterface>());
222 
223     }
224     catch(...)
225     {
226         throw RuntimeException(
227             OUSTR("[automation bridge] unexpected exception in "
228                   "IUnknownWrapper_Impl::Invoke !"), Reference<XInterface>());
229     }
230     return ret;
231 }
232 
setValue(const OUString & aPropertyName,const Any & aValue)233 void SAL_CALL IUnknownWrapper_Impl::setValue( const OUString& aPropertyName,
234                  const Any& aValue )
235     throw(UnknownPropertyException, CannotConvertException, InvocationTargetException,
236           RuntimeException)
237 {
238     if ( ! m_spDispatch )
239     {
240         throw RuntimeException(
241             OUSTR("[automation bridge] The object does not have an IDispatch interface"),
242             Reference<XInterface>());
243     }
244     try
245     {
246         o2u_attachCurrentThread();
247 
248         ITypeInfo * pInfo = getTypeInfo();
249         FuncDesc aDescGet(pInfo);
250         FuncDesc aDescPut(pInfo);
251         VarDesc aVarDesc(pInfo);
252         getPropDesc(aPropertyName, & aDescGet, & aDescPut, & aVarDesc);
253         //check if there is such a property at all or if it is read only
254         if ( ! aDescPut && ! aDescGet && ! aVarDesc)
255         {
256             OUString msg(OUSTR("[automation bridge]Property \"") + aPropertyName +
257                          OUSTR("\" is not supported"));
258             throw UnknownPropertyException(msg, Reference<XInterface>());
259         }
260 
261         if ( (! aDescPut && aDescGet) || aVarDesc
262              && aVarDesc->wVarFlags == VARFLAG_FREADONLY )
263         {
264             //read-only
265             OUString msg(OUSTR("[automation bridge] Property ") + aPropertyName +
266                          OUSTR(" is read-only"));
267             OString sMsg = OUStringToOString(msg, osl_getThreadTextEncoding());
268             OSL_ENSURE(0, sMsg.getStr());
269             // ignore silently
270             return;
271         }
272 
273         HRESULT hr= S_OK;
274         DISPPARAMS dispparams;
275         CComVariant varArg;
276         CComVariant varRefArg;
277         CComVariant varResult;
278         ExcepInfo excepinfo;
279         unsigned int uArgErr;
280 
281         // converting UNO value to OLE variant
282         DISPID dispidPut= DISPID_PROPERTYPUT;
283         dispparams.rgdispidNamedArgs = &dispidPut;
284         dispparams.cArgs = 1;
285         dispparams.cNamedArgs = 1;
286         dispparams.rgvarg = & varArg;
287 
288         OSL_ASSERT(aDescPut || aVarDesc);
289 
290         VARTYPE vt = 0;
291         DISPID dispid = 0;
292         INVOKEKIND invkind = INVOKE_PROPERTYPUT;
293         //determine the expected type, dispid, invoke kind (DISPATCH_PROPERTYPUT,
294         //DISPATCH_PROPERTYPUTREF)
295         if (aDescPut)
296         {
297             vt = getElementTypeDesc(& aDescPut->lprgelemdescParam[0].tdesc);
298             dispid = aDescPut->memid;
299             invkind = aDescPut->invkind;
300         }
301         else
302         {
303             vt = getElementTypeDesc( & aVarDesc->elemdescVar.tdesc);
304             dispid = aVarDesc->memid;
305             if (vt == VT_UNKNOWN || vt == VT_DISPATCH ||
306                 (vt & VT_ARRAY) || (vt & VT_BYREF))
307             {
308                 invkind = INVOKE_PROPERTYPUTREF;
309             }
310         }
311 
312         // convert the uno argument
313         if (vt & VT_BYREF)
314         {
315             anyToVariant( & varRefArg, aValue, ::sal::static_int_cast< VARTYPE, int >( vt ^ VT_BYREF ) );
316             varArg.vt = vt;
317             if( (vt & VT_TYPEMASK) == VT_VARIANT)
318                 varArg.byref = & varRefArg;
319             else if ((vt & VT_TYPEMASK) == VT_DECIMAL)
320                 varArg.byref = & varRefArg.decVal;
321             else
322                 varArg.byref = & varRefArg.byref;
323         }
324         else
325         {
326             anyToVariant(& varArg, aValue, vt);
327         }
328         // call to IDispatch
329         hr = m_spDispatch->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, ::sal::static_int_cast< WORD, INVOKEKIND >( invkind ),
330                                  &dispparams, & varResult, & excepinfo, &uArgErr);
331 
332         // lookup error code
333         switch (hr)
334         {
335         case S_OK:
336             break;
337         case DISP_E_BADPARAMCOUNT:
338             throw RuntimeException();
339             break;
340         case DISP_E_BADVARTYPE:
341             throw RuntimeException();
342             break;
343         case DISP_E_EXCEPTION:
344             throw InvocationTargetException();
345             break;
346         case DISP_E_MEMBERNOTFOUND:
347             throw UnknownPropertyException();
348             break;
349         case DISP_E_NONAMEDARGS:
350             throw RuntimeException();
351             break;
352         case DISP_E_OVERFLOW:
353             throw CannotConvertException(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("call to OLE object failed")), static_cast<XInterface*>(
354                                              static_cast<XWeak*>(this)), TypeClass_UNKNOWN, FailReason::OUT_OF_RANGE, uArgErr);
355             break;
356         case DISP_E_PARAMNOTFOUND:
357             throw IllegalArgumentException(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("call to OLE object failed")), static_cast<XInterface*>(
358                                             static_cast<XWeak*>(this)), ::sal::static_int_cast< sal_Int16, unsigned int >( uArgErr )) ;
359             break;
360         case DISP_E_TYPEMISMATCH:
361             throw CannotConvertException(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("call to OLE object failed")), static_cast<XInterface*>(
362                                              static_cast<XWeak*>(this)), TypeClass_UNKNOWN, FailReason::UNKNOWN, ::sal::static_int_cast< sal_Int16, unsigned int >( uArgErr ));
363             break;
364         case DISP_E_UNKNOWNINTERFACE:
365             throw RuntimeException();
366             break;
367         case DISP_E_UNKNOWNLCID:
368             throw RuntimeException();
369             break;
370         case DISP_E_PARAMNOTOPTIONAL:
371             throw CannotConvertException(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("call to OLE object failed")),static_cast<XInterface*>(
372                                              static_cast<XWeak*>(this)) , TypeClass_UNKNOWN, FailReason::NO_DEFAULT_AVAILABLE, uArgErr);
373             break;
374         default:
375             throw  RuntimeException();
376             break;
377         }
378     }
379     catch (CannotConvertException &)
380     {
381         throw;
382     }
383     catch (UnknownPropertyException &)
384     {
385         throw;
386     }
387     catch (BridgeRuntimeError& e)
388     {
389         throw RuntimeException(
390             e.message, Reference<XInterface>());
391     }
392     catch (Exception & e)
393     {
394         throw RuntimeException(OUSTR("[automation bridge] unexpected exception in "
395                                      "IUnknownWrapper_Impl::setValue ! Message : \n") +
396                                e.Message, Reference<XInterface>());
397 
398     }
399     catch (...)
400     {
401         throw RuntimeException(
402             OUSTR("[automation bridge] unexpected exception in "
403             "IUnknownWrapper_Impl::setValue !"), Reference<XInterface>());
404     }
405 }
406 
getValue(const OUString & aPropertyName)407 Any SAL_CALL IUnknownWrapper_Impl::getValue( const OUString& aPropertyName )
408         throw(UnknownPropertyException, RuntimeException)
409 {
410     if ( ! m_spDispatch )
411     {
412         throw RuntimeException(
413             OUSTR("[automation bridge] The object does not have an IDispatch interface"),
414             Reference<XInterface>());
415     }
416     Any ret;
417     try
418     {
419         o2u_attachCurrentThread();
420         ITypeInfo * pInfo = getTypeInfo();
421         // I was going to implement an XServiceInfo interface to allow the type
422         // of the automation object to be exposed.. but it seems
423         // from looking at comments in the code that it is possible for
424         // this object to actually wrap an UNO object ( I guess if automation is
425         // used from MSO to create Openoffice objects ) Therefore, those objects
426         // will more than likely already have their own XServiceInfo interface.
427         // Instead here I chose a name that should be illegal both in COM and
428         // UNO ( from an IDL point of view ) therefore I think this is a safe
429         // hack
430         if ( aPropertyName.equals( rtl::OUString::createFromAscii("$GetTypeName") ))
431         {
432             if ( pInfo && m_sTypeName.getLength() == 0 )
433             {
434                  m_sTypeName = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("IDispatch") );
435                 CComBSTR sName;
436 
437                 if ( SUCCEEDED( pInfo->GetDocumentation( -1, &sName, NULL, NULL, NULL  ) ) )
438                 {
439                     rtl::OUString sTmp( reinterpret_cast<const sal_Unicode*>(LPCOLESTR(sName)));
440                     if ( sTmp.indexOf('_')  == 0 )
441                        sTmp = sTmp.copy(1);
442                     // do we own the memory for pTypeLib, msdn doco is vague
443                     // I'll assume we do
444                     CComPtr< ITypeLib > pTypeLib;
445                     unsigned int index;
446                     if ( SUCCEEDED(  pInfo->GetContainingTypeLib(  &pTypeLib.p, &index )) )
447                     {
448                         if ( SUCCEEDED( pTypeLib->GetDocumentation( -1, &sName, NULL, NULL, NULL  ) ) )
449                         {
450                             rtl::OUString sLibName( reinterpret_cast<const sal_Unicode*>(LPCOLESTR(sName)));
451                             m_sTypeName = sLibName.concat( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(".") ) ).concat( sTmp );
452 
453                         }
454                     }
455                 }
456 
457             }
458             ret <<= m_sTypeName;
459             return ret;
460         }
461         FuncDesc aDescGet(pInfo);
462         FuncDesc aDescPut(pInfo);
463         VarDesc aVarDesc(pInfo);
464         getPropDesc(aPropertyName, & aDescGet, & aDescPut, & aVarDesc);
465         if ( ! aDescGet && ! aDescPut && ! aVarDesc)
466         {
467             //property not found
468             OUString msg(OUSTR("[automation bridge]Property \"") + aPropertyName +
469                          OUSTR("\" is not supported"));
470             throw UnknownPropertyException(msg, Reference<XInterface>());
471         }
472         // write-only should not be possible
473         OSL_ASSERT(  aDescGet  || ! aDescPut);
474 
475         HRESULT hr;
476         DISPPARAMS dispparams = {0, 0, 0, 0};
477         CComVariant varResult;
478         ExcepInfo excepinfo;
479         unsigned int uArgErr;
480         DISPID dispid;
481         if (aDescGet)
482             dispid = aDescGet->memid;
483         else if (aVarDesc)
484             dispid = aVarDesc->memid;
485         else
486             dispid = aDescPut->memid;
487 
488         hr = m_spDispatch->Invoke(dispid,
489                                  IID_NULL,
490                                  LOCALE_USER_DEFAULT,
491                                  DISPATCH_PROPERTYGET,
492                                  &dispparams,
493                                  &varResult,
494                                  &excepinfo,
495                                  &uArgErr);
496 
497         // converting return value and out parameter back to UNO
498         if (hr == S_OK)
499         {
500             // If the com object implements uno interfaces then we have
501             // to convert the attribute into the expected type.
502             TypeDescription attrInfo;
503             getAttributeInfo(aPropertyName, attrInfo);
504             if( attrInfo.is() )
505                 variantToAny( &varResult, ret, Type( attrInfo.get()->pWeakRef));
506             else
507                 variantToAny(&varResult, ret);
508         }
509 
510         // lookup error code
511         switch (hr)
512         {
513         case S_OK:
514             break;
515         case DISP_E_BADPARAMCOUNT:
516             throw RuntimeException(OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription)),
517                                    Reference<XInterface>());
518             break;
519         case DISP_E_BADVARTYPE:
520             throw RuntimeException(OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription)),
521                                    Reference<XInterface>());
522             break;
523         case DISP_E_EXCEPTION:
524             throw RuntimeException(OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription)),
525                                    Reference<XInterface>());
526             break;
527         case DISP_E_MEMBERNOTFOUND:
528             throw UnknownPropertyException(OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription)),
529                                    Reference<XInterface>());
530             break;
531         case DISP_E_NONAMEDARGS:
532             throw RuntimeException(OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription)),
533                                    Reference<XInterface>());
534             break;
535         case DISP_E_OVERFLOW:
536             throw RuntimeException(OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription)),
537                                    Reference<XInterface>());
538             break;
539         case DISP_E_PARAMNOTFOUND:
540             throw RuntimeException(OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription)),
541                                    Reference<XInterface>());
542             break;
543         case DISP_E_TYPEMISMATCH:
544             throw RuntimeException(OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription)),
545                                    Reference<XInterface>());
546             break;
547         case DISP_E_UNKNOWNINTERFACE:
548             throw RuntimeException(OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription)),
549                                    Reference<XInterface>());
550             break;
551         case DISP_E_UNKNOWNLCID:
552             throw RuntimeException(OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription)),
553                                    Reference<XInterface>());
554             break;
555         case DISP_E_PARAMNOTOPTIONAL:
556             throw RuntimeException(OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription)),
557                                    Reference<XInterface>());
558             break;
559         default:
560             throw RuntimeException(OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription)),
561                                    Reference<XInterface>());
562             break;
563         }
564     }
565     catch (UnknownPropertyException& )
566     {
567         throw;
568     }
569     catch (BridgeRuntimeError& e)
570     {
571         throw RuntimeException(
572             e.message, Reference<XInterface>());
573     }
574     catch (Exception & e)
575     {
576         throw RuntimeException(OUSTR("[automation bridge] unexpected exception in "
577                                      "IUnknownWrapper_Impl::getValue ! Message : \n") +
578                                e.Message, Reference<XInterface>());
579     }
580     catch (...)
581     {
582         throw RuntimeException(
583             OUSTR("[automation bridge] unexpected exception in "
584             "IUnknownWrapper_Impl::getValue !"), Reference<XInterface>());
585     }
586     return ret;
587 }
588 
hasMethod(const OUString & aName)589 sal_Bool SAL_CALL IUnknownWrapper_Impl::hasMethod( const OUString& aName )
590         throw(RuntimeException)
591 {
592     if ( ! m_spDispatch )
593     {
594         throw RuntimeException(
595             OUSTR("[automation bridge] The object does not have an IDispatch interface"),
596             Reference<XInterface>());
597     }
598     sal_Bool ret = sal_False;
599 
600     try
601     {
602         o2u_attachCurrentThread();
603         ITypeInfo* pInfo = getTypeInfo();
604         FuncDesc aDesc(pInfo);
605         getFuncDesc(aName, & aDesc);
606         // Automation properties can have arguments. Those are treated as methods and
607         //are called through XInvocation::invoke.
608         if ( ! aDesc)
609         {
610             FuncDesc aDescGet(pInfo);
611             FuncDesc aDescPut(pInfo);
612             VarDesc aVarDesc(pInfo);
613             getPropDesc( aName, & aDescGet, & aDescPut, & aVarDesc);
614             if (aDescGet  && aDescGet->cParams > 0
615                 || aDescPut && aDescPut->cParams > 0)
616                 ret = sal_True;
617         }
618         else
619             ret = sal_True;
620     }
621     catch (BridgeRuntimeError& e)
622     {
623         throw RuntimeException(e.message, Reference<XInterface>());
624     }
625     catch (Exception & e)
626     {
627         throw RuntimeException(OUSTR("[automation bridge] unexpected exception in "
628                                      "IUnknownWrapper_Impl::hasMethod ! Message : \n") +
629                                e.Message, Reference<XInterface>());
630     }
631     catch (...)
632     {
633         throw RuntimeException(OUSTR("[automation bridge] unexpected exception in "
634             "IUnknownWrapper_Impl::hasMethod !"), Reference<XInterface>());;
635     }
636     return ret;
637 }
638 
hasProperty(const OUString & aName)639 sal_Bool SAL_CALL IUnknownWrapper_Impl::hasProperty( const OUString& aName )
640         throw(RuntimeException)
641 {
642     if ( ! m_spDispatch )
643     {
644         throw RuntimeException(OUSTR("[automation bridge] The object does not have an "
645             "IDispatch interface"), Reference<XInterface>());
646         return sal_False;
647     }
648     sal_Bool ret = sal_False;
649     try
650     {
651         o2u_attachCurrentThread();
652 
653         ITypeInfo * pInfo = getTypeInfo();
654         FuncDesc aDescGet(pInfo);
655         FuncDesc aDescPut(pInfo);
656         VarDesc aVarDesc(pInfo);
657         getPropDesc(aName, & aDescGet, & aDescPut, & aVarDesc);
658         // Automation properties can have parameters. If so, we access them through
659         // XInvocation::invoke. Thas is, hasProperty must return false for such a
660         // property
661         if (aVarDesc
662             || aDescPut && aDescPut->cParams == 0
663             || aDescGet && aDescGet->cParams == 0)
664         {
665             ret = sal_True;
666         }
667     }
668     catch (BridgeRuntimeError& e)
669     {
670         throw RuntimeException(e.message, Reference<XInterface>());
671     }
672     catch (Exception & e)
673     {
674         throw RuntimeException(OUSTR("[automation bridge] unexpected exception in "
675                                      "IUnknownWrapper_Impl::hasProperty ! Message : \n") +
676                                e.Message, Reference<XInterface>());
677 
678     }
679     catch (...)
680     {
681         throw RuntimeException(OUSTR("[automation bridge] unexpected exception in "
682             "IUnknownWrapper_Impl::hasProperty !"), Reference<XInterface>());
683     }
684     return ret;
685 }
686 
createBridge(const Any & modelDepObject,const Sequence<sal_Int8> &,sal_Int16 sourceModelType,sal_Int16 destModelType)687 Any SAL_CALL IUnknownWrapper_Impl::createBridge( const Any& modelDepObject,
688                 const Sequence< sal_Int8 >& /*aProcessId*/, sal_Int16 sourceModelType,
689                  sal_Int16 destModelType )
690     throw( IllegalArgumentException, RuntimeException)
691 {
692     Any ret;
693     o2u_attachCurrentThread();
694 
695     if (
696         (sourceModelType == UNO) &&
697         (destModelType == OLE) &&
698         (modelDepObject.getValueTypeClass() == TypeClass_INTERFACE)
699        )
700     {
701         Reference<XInterface> xInt( *(XInterface**) modelDepObject.getValue());
702         Reference<XInterface> xSelf( (OWeakObject*)this);
703 
704         if (xInt == xSelf)
705         {
706             VARIANT* pVariant = (VARIANT*) CoTaskMemAlloc(sizeof(VARIANT));
707 
708             VariantInit(pVariant);
709             if (m_bOriginalDispatch == sal_True)
710             {
711                 pVariant->vt = VT_DISPATCH;
712                 pVariant->pdispVal = m_spDispatch;
713                 pVariant->pdispVal->AddRef();
714             }
715             else
716             {
717                 pVariant->vt = VT_UNKNOWN;
718                 pVariant->punkVal = m_spUnknown;
719                 pVariant->punkVal->AddRef();
720             }
721 
722             ret.setValue((void*)&pVariant, getCppuType( (sal_uInt32*) 0));
723         }
724     }
725 
726     return ret;
727 }
728 /** @internal
729     @exception IllegalArgumentException
730     @exception CannotConvertException
731     @exception InvocationTargetException
732     @RuntimeException
733 */
invokeWithDispIdUnoTlb(const OUString & sFunctionName,const Sequence<Any> & Params,Sequence<sal_Int16> & OutParamIndex,Sequence<Any> & OutParam)734 Any  IUnknownWrapper_Impl::invokeWithDispIdUnoTlb(const OUString& sFunctionName,
735                                                   const Sequence< Any >& Params,
736                                                   Sequence< sal_Int16 >& OutParamIndex,
737                                                   Sequence< Any >& OutParam)
738 {
739     Any ret;
740     HRESULT hr= S_OK;
741 
742     sal_Int32 parameterCount= Params.getLength();
743     sal_Int32 outParameterCount= 0;
744     typelib_InterfaceMethodTypeDescription* pMethod= NULL;
745     TypeDescription methodDesc;
746     getMethodInfo(sFunctionName, methodDesc);
747 
748     // We need to know whether the IDispatch is from a JScript object.
749     // Then out and in/out parameters have to be treated differently than
750     // with common COM objects.
751     sal_Bool bJScriptObject= isJScriptObject();
752     scoped_array<CComVariant> sarParams;
753     scoped_array<CComVariant> sarParamsRef;
754     CComVariant *pVarParams= NULL;
755     CComVariant *pVarParamsRef= NULL;
756     sal_Bool bConvRet= sal_True;
757 
758     if( methodDesc.is())
759     {
760         pMethod = (typelib_InterfaceMethodTypeDescription* )methodDesc.get();
761         parameterCount = pMethod->nParams;
762         // Create the Array for the array being passed in DISPPARAMS
763         // the array also contains the outparameter (but not the values)
764         if( pMethod->nParams > 0)
765         {
766             sarParams.reset(new CComVariant[ parameterCount]);
767             pVarParams = sarParams.get();
768         }
769 
770         // Create the Array for the out an in/out parameter. These values
771         // are referenced by the VT_BYREF VARIANTs in DISPPARAMS.
772         // We need to find out the number of out and in/out parameter.
773         for( sal_Int32 i=0; i < parameterCount; i++)
774         {
775             if( pMethod->pParams[i].bOut)
776                 outParameterCount++;
777         }
778 
779         if( !bJScriptObject)
780         {
781             sarParamsRef.reset(new CComVariant[outParameterCount]);
782             pVarParamsRef = sarParamsRef.get();
783             // build up the parameters for IDispatch::Invoke
784             sal_Int32 outParamIndex=0;
785             int i = 0;
786             try
787             {
788                 for( i= 0; i < parameterCount; i++)
789                 {
790                     // In parameter
791                     if( pMethod->pParams[i].bIn == sal_True && ! pMethod->pParams[i].bOut)
792                     {
793                         anyToVariant( &pVarParams[parameterCount - i -1], Params.getConstArray()[i]);
794                     }
795                     // Out parameter + in/out parameter
796                     else if( pMethod->pParams[i].bOut == sal_True)
797                     {
798                         CComVariant var;
799                         if(pMethod->pParams[i].bIn)
800                         {
801                             anyToVariant( & var,Params[i]);
802                             pVarParamsRef[outParamIndex] = var;
803                         }
804 
805                         switch( pMethod->pParams[i].pTypeRef->eTypeClass)
806                         {
807                         case TypeClass_INTERFACE:
808                         case TypeClass_STRUCT:
809                             if( ! pMethod->pParams[i].bIn)
810                             {
811                                 pVarParamsRef[ outParamIndex].vt= VT_DISPATCH;
812                                 pVarParamsRef[ outParamIndex].pdispVal= 0;
813                             }
814                             pVarParams[parameterCount - i -1].vt = VT_DISPATCH | VT_BYREF;
815                             pVarParams[parameterCount - i -1].ppdispVal= &pVarParamsRef[outParamIndex].pdispVal;
816                             break;
817                         case TypeClass_ENUM:
818                         case TypeClass_LONG:
819                         case TypeClass_UNSIGNED_LONG:
820                             if( ! pMethod->pParams[i].bIn)
821                             {
822                                 pVarParamsRef[ outParamIndex].vt = VT_I4;
823                                 pVarParamsRef[ outParamIndex].lVal = 0;
824                             }
825                             pVarParams[parameterCount - i -1].vt = VT_I4 | VT_BYREF;
826                             pVarParams[parameterCount - i -1].plVal= &pVarParamsRef[outParamIndex].lVal;
827                             break;
828                         case TypeClass_SEQUENCE:
829                             if( ! pMethod->pParams[i].bIn)
830                             {
831                                 pVarParamsRef[ outParamIndex].vt = VT_ARRAY| VT_VARIANT;
832                                 pVarParamsRef[ outParamIndex].parray= NULL;
833                             }
834                             pVarParams[parameterCount - i -1].vt = VT_ARRAY| VT_BYREF | VT_VARIANT;
835                             pVarParams[parameterCount - i -1].pparray= &pVarParamsRef[outParamIndex].parray;
836                             break;
837                         case TypeClass_ANY:
838                             if( ! pMethod->pParams[i].bIn)
839                             {
840                                 pVarParamsRef[ outParamIndex].vt = VT_EMPTY;
841                                 pVarParamsRef[ outParamIndex].lVal = 0;
842                             }
843                             pVarParams[parameterCount - i -1].vt = VT_VARIANT | VT_BYREF;
844                             pVarParams[parameterCount - i -1].pvarVal = &pVarParamsRef[outParamIndex];
845                             break;
846                         case TypeClass_BOOLEAN:
847                             if( ! pMethod->pParams[i].bIn)
848                             {
849                                 pVarParamsRef[ outParamIndex].vt = VT_BOOL;
850                                 pVarParamsRef[ outParamIndex].boolVal = 0;
851                             }
852                             pVarParams[parameterCount - i -1].vt = VT_BOOL| VT_BYREF;
853                             pVarParams[parameterCount - i -1].pboolVal =
854                                 & pVarParamsRef[outParamIndex].boolVal;
855                             break;
856 
857                         case TypeClass_STRING:
858                             if( ! pMethod->pParams[i].bIn)
859                             {
860                                 pVarParamsRef[ outParamIndex].vt = VT_BSTR;
861                                 pVarParamsRef[ outParamIndex].bstrVal= 0;
862                             }
863                             pVarParams[parameterCount - i -1].vt = VT_BSTR| VT_BYREF;
864                             pVarParams[parameterCount - i -1].pbstrVal=
865                                 & pVarParamsRef[outParamIndex].bstrVal;
866                             break;
867 
868                         case TypeClass_FLOAT:
869                             if( ! pMethod->pParams[i].bIn)
870                             {
871                                 pVarParamsRef[ outParamIndex].vt = VT_R4;
872                                 pVarParamsRef[ outParamIndex].fltVal= 0;
873                             }
874                             pVarParams[parameterCount - i -1].vt = VT_R4| VT_BYREF;
875                             pVarParams[parameterCount - i -1].pfltVal =
876                                 & pVarParamsRef[outParamIndex].fltVal;
877                             break;
878                         case TypeClass_DOUBLE:
879                             if( ! pMethod->pParams[i].bIn)
880                             {
881                                 pVarParamsRef[ outParamIndex].vt = VT_R8;
882                                 pVarParamsRef[ outParamIndex].dblVal= 0;
883                             }
884                             pVarParams[parameterCount - i -1].vt = VT_R8| VT_BYREF;
885                             pVarParams[parameterCount - i -1].pdblVal=
886                                 & pVarParamsRef[outParamIndex].dblVal;
887                             break;
888                         case TypeClass_BYTE:
889                             if( ! pMethod->pParams[i].bIn)
890                             {
891                                 pVarParamsRef[ outParamIndex].vt = VT_UI1;
892                                 pVarParamsRef[ outParamIndex].bVal= 0;
893                             }
894                             pVarParams[parameterCount - i -1].vt = VT_UI1| VT_BYREF;
895                             pVarParams[parameterCount - i -1].pbVal=
896                                 & pVarParamsRef[outParamIndex].bVal;
897                             break;
898                         case TypeClass_CHAR:
899                         case TypeClass_SHORT:
900                         case TypeClass_UNSIGNED_SHORT:
901                             if( ! pMethod->pParams[i].bIn)
902                             {
903                                 pVarParamsRef[ outParamIndex].vt = VT_I2;
904                                 pVarParamsRef[ outParamIndex].iVal = 0;
905                             }
906                             pVarParams[parameterCount - i -1].vt = VT_I2| VT_BYREF;
907                             pVarParams[parameterCount - i -1].piVal=
908                                 & pVarParamsRef[outParamIndex].iVal;
909                             break;
910 
911                         default:
912                             if( ! pMethod->pParams[i].bIn)
913                             {
914                                 pVarParamsRef[ outParamIndex].vt = VT_EMPTY;
915                                 pVarParamsRef[ outParamIndex].lVal = 0;
916                             }
917                             pVarParams[parameterCount - i -1].vt = VT_VARIANT | VT_BYREF;
918                             pVarParams[parameterCount - i -1].pvarVal =
919                                 & pVarParamsRef[outParamIndex];
920                         }
921                         outParamIndex++;
922                     } // end else if
923                 } // end for
924             }
925             catch (IllegalArgumentException & e)
926             {
927                 e.ArgumentPosition = ::sal::static_int_cast< sal_Int16, int >( i );
928                 throw;
929             }
930             catch (CannotConvertException & e)
931             {
932                 e.ArgumentIndex = i;
933                 throw;
934             }
935         }
936         else // it is an JScriptObject
937         {
938             int i = 0;
939             try
940             {
941                 for( ; i< parameterCount; i++)
942                 {
943                     // In parameter
944                     if( pMethod->pParams[i].bIn == sal_True && ! pMethod->pParams[i].bOut)
945                     {
946                         anyToVariant( &pVarParams[parameterCount - i -1], Params.getConstArray()[i]);
947                     }
948                     // Out parameter + in/out parameter
949                     else if( pMethod->pParams[i].bOut == sal_True)
950                     {
951                         CComObject<JScriptOutParam>* pParamObject;
952                         if( SUCCEEDED( CComObject<JScriptOutParam>::CreateInstance( &pParamObject)))
953                         {
954                             CComPtr<IUnknown> pUnk(pParamObject->GetUnknown());
955 #ifdef __MINGW32__
956                             CComQIPtr<IDispatch, &__uuidof(IDispatch)> pDisp( pUnk);
957 #else
958                             CComQIPtr<IDispatch> pDisp( pUnk);
959 #endif
960 
961                             pVarParams[ parameterCount - i -1].vt= VT_DISPATCH;
962                             pVarParams[ parameterCount - i -1].pdispVal= pDisp;
963                             pVarParams[ parameterCount - i -1].pdispVal->AddRef();
964                             // if the param is in/out then put the parameter on index 0
965                             if( pMethod->pParams[i].bIn == sal_True ) // in / out
966                             {
967                                 CComVariant varParam;
968                                 anyToVariant( &varParam, Params.getConstArray()[i]);
969                                 CComDispatchDriver dispDriver( pDisp);
970                                 if(FAILED( dispDriver.PutPropertyByName( L"0", &varParam)))
971                                     throw BridgeRuntimeError(
972                                         OUSTR("[automation bridge]IUnknownWrapper_Impl::"
973                                               "invokeWithDispIdUnoTlb\n"
974                                               "Could not set property \"0\" for the in/out "
975                                               "param!"));
976 
977                             }
978                         }
979                         else
980                         {
981                             throw BridgeRuntimeError(
982                                 OUSTR("[automation bridge]IUnknownWrapper_Impl::"
983                                       "invokeWithDispIdUnoTlb\n"
984                                       "Could not create out parameter at index: ") +
985                                 OUString::valueOf((sal_Int32) i));
986                         }
987 
988                     }
989                 }
990             }
991             catch (IllegalArgumentException & e)
992             {
993                 e.ArgumentPosition = ::sal::static_int_cast< sal_Int16, int >( i );
994                 throw;
995             }
996             catch (CannotConvertException & e)
997             {
998                 e.ArgumentIndex = i;
999                 throw;
1000             }
1001         }
1002     }
1003     // No type description Available, that is we have to deal with a COM component,
1004     // that does not implements UNO interfaces ( IDispatch based)
1005     else
1006     {
1007         //We should not run into this block, because invokeWithDispIdComTlb should
1008         //have been called instead.
1009         OSL_ASSERT(0);
1010     }
1011 
1012 
1013     CComVariant     varResult;
1014     ExcepInfo       excepinfo;
1015     unsigned int    uArgErr;
1016     DISPPARAMS dispparams= { pVarParams, NULL, parameterCount, 0};
1017     // Get the DISPID
1018     FuncDesc aDesc(getTypeInfo());
1019     getFuncDesc(sFunctionName, & aDesc);
1020     // invoking OLE method
1021     hr = m_spDispatch->Invoke(aDesc->memid,
1022                              IID_NULL,
1023                              LOCALE_USER_DEFAULT,
1024                              DISPATCH_METHOD,
1025                              &dispparams,
1026                              &varResult,
1027                              &excepinfo,
1028                              &uArgErr);
1029 
1030     // converting return value and out parameter back to UNO
1031     if (hr == S_OK)
1032     {
1033         if( outParameterCount && pMethod)
1034         {
1035             OutParamIndex.realloc( outParameterCount);
1036             OutParam.realloc( outParameterCount);
1037             sal_Int32 outIndex=0;
1038             int i = 0;
1039             try
1040             {
1041                 for( ; i < parameterCount; i++)
1042                 {
1043                     if( pMethod->pParams[i].bOut )
1044                     {
1045                         OutParamIndex[outIndex]= (sal_Int16) i;
1046                         Any outAny;
1047                         if( !bJScriptObject)
1048                         {
1049                             variantToAny( &pVarParamsRef[outIndex], outAny,
1050                                         Type(pMethod->pParams[i].pTypeRef), sal_False);
1051                             OutParam[outIndex++]= outAny;
1052                         }
1053                         else //JScriptObject
1054                         {
1055                             if( pVarParams[i].vt == VT_DISPATCH)
1056                             {
1057                                 CComDispatchDriver pDisp( pVarParams[i].pdispVal);
1058                                 if( pDisp)
1059                                 {
1060                                     CComVariant varOut;
1061                                     if( SUCCEEDED( pDisp.GetPropertyByName( L"0", &varOut)))
1062                                     {
1063                                         variantToAny( &varOut, outAny,
1064                                                     Type(pMethod->pParams[parameterCount - 1 - i].pTypeRef), sal_False);
1065                                         OutParam[outParameterCount - 1 - outIndex++]= outAny;
1066                                     }
1067                                     else
1068                                         bConvRet= sal_False;
1069                                 }
1070                                 else
1071                                     bConvRet= sal_False;
1072                             }
1073                             else
1074                                 bConvRet= sal_False;
1075                         }
1076                     }
1077                     if( !bConvRet) break;
1078                 }
1079             }
1080             catch(IllegalArgumentException & e)
1081             {
1082                 e.ArgumentPosition = ::sal::static_int_cast< sal_Int16, int >( i );
1083                 throw;
1084             }
1085             catch(CannotConvertException & e)
1086             {
1087                 e.ArgumentIndex = i;
1088                 throw;
1089             }
1090         }
1091         // return value, no type information available
1092         if ( bConvRet)
1093         {
1094             try
1095             {
1096                 if( pMethod )
1097                     variantToAny(&varResult, ret, Type( pMethod->pReturnTypeRef), sal_False);
1098                 else
1099                     variantToAny(&varResult, ret, sal_False);
1100             }
1101             catch (IllegalArgumentException & e)
1102             {
1103                 e.Message =
1104                     OUSTR("[automation bridge]IUnknownWrapper_Impl::invokeWithDispIdUnoTlb\n"
1105                     "Could not convert return value! \n Message: \n") + e.Message;
1106                 throw;
1107             }
1108             catch (CannotConvertException & e)
1109             {
1110                 e.Message =
1111                     OUSTR("[automation bridge]IUnknownWrapper_Impl::invokeWithDispIdUnoTlb\n"
1112                     "Could not convert return value! \n Message: \n") + e.Message;
1113                 throw;
1114             }
1115         }
1116     }
1117 
1118     if( !bConvRet) // conversion of return or out parameter failed
1119         throw CannotConvertException( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Call to COM object failed. Conversion of return or out value failed")),
1120                                       Reference<XInterface>( static_cast<XWeak*>(this), UNO_QUERY   ), TypeClass_UNKNOWN,
1121                                       FailReason::UNKNOWN, 0);// lookup error code
1122     // conversion of return or out parameter failed
1123     switch (hr)
1124     {
1125     case S_OK:
1126         break;
1127     case DISP_E_BADPARAMCOUNT:
1128         throw IllegalArgumentException();
1129         break;
1130     case DISP_E_BADVARTYPE:
1131         throw RuntimeException();
1132         break;
1133     case DISP_E_EXCEPTION:
1134         throw InvocationTargetException();
1135         break;
1136     case DISP_E_MEMBERNOTFOUND:
1137         throw IllegalArgumentException();
1138         break;
1139     case DISP_E_NONAMEDARGS:
1140         throw IllegalArgumentException();
1141         break;
1142     case DISP_E_OVERFLOW:
1143         throw CannotConvertException(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("call to OLE object failed")), static_cast<XInterface*>(
1144                                          static_cast<XWeak*>(this)), TypeClass_UNKNOWN, FailReason::OUT_OF_RANGE, uArgErr);
1145         break;
1146     case DISP_E_PARAMNOTFOUND:
1147         throw IllegalArgumentException(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("call to OLE object failed")), static_cast<XInterface*>(
1148                                            static_cast<XWeak*>(this)), ::sal::static_int_cast< sal_Int16, unsigned int >( uArgErr ));
1149         break;
1150     case DISP_E_TYPEMISMATCH:
1151         throw CannotConvertException(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("call to OLE object failed")),static_cast<XInterface*>(
1152                                          static_cast<XWeak*>(this)) , TypeClass_UNKNOWN, FailReason::UNKNOWN, uArgErr);
1153         break;
1154     case DISP_E_UNKNOWNINTERFACE:
1155         throw RuntimeException() ;
1156         break;
1157     case DISP_E_UNKNOWNLCID:
1158         throw RuntimeException() ;
1159         break;
1160     case DISP_E_PARAMNOTOPTIONAL:
1161         throw CannotConvertException(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("call to OLE object failed")), static_cast<XInterface*>(
1162                                          static_cast<XWeak*>(this)), TypeClass_UNKNOWN, FailReason::NO_DEFAULT_AVAILABLE, uArgErr);
1163                 break;
1164     default:
1165         throw RuntimeException();
1166         break;
1167     }
1168 
1169     return ret;
1170 }
1171 
1172 
1173 
1174 // --------------------------
1175 // XInitialization
initialize(const Sequence<Any> & aArguments)1176 void SAL_CALL IUnknownWrapper_Impl::initialize( const Sequence< Any >& aArguments ) throw(Exception, RuntimeException)
1177 {
1178     // 1.parameter is IUnknown
1179     // 2.parameter is a boolean which indicates if the the COM pointer was a IUnknown or IDispatch
1180     // 3.parameter is a Sequence<Type>
1181     o2u_attachCurrentThread();
1182     OSL_ASSERT(aArguments.getLength() == 3);
1183 
1184     m_spUnknown= *(IUnknown**) aArguments[0].getValue();
1185 #ifdef __MINGW32__
1186     m_spUnknown->QueryInterface(IID_IDispatch, reinterpret_cast<LPVOID*>( & m_spDispatch.p));
1187 #else
1188     m_spUnknown.QueryInterface( & m_spDispatch.p);
1189 #endif
1190 
1191     aArguments[1] >>= m_bOriginalDispatch;
1192     aArguments[2] >>= m_seqTypes;
1193 
1194     ITypeInfo* pType = NULL;
1195     try
1196     {
1197         // a COM object implementation that has no TypeInfo is still a legal COM object;
1198         // such objects can at least be transported through UNO using the bridge
1199         // so we should allow to create wrappers for them as well
1200         pType = getTypeInfo();
1201     }
1202     catch( BridgeRuntimeError& )
1203     {}
1204     catch( Exception& )
1205     {}
1206 
1207     if ( pType )
1208     {
1209         try
1210         {
1211             // Get Default member
1212             CComBSTR defaultMemberName;
1213             if ( SUCCEEDED( pType->GetDocumentation(0, &defaultMemberName, 0, 0, 0 ) ) )
1214             {
1215                 OUString usName(reinterpret_cast<const sal_Unicode*>(LPCOLESTR(defaultMemberName)));
1216                 FuncDesc aDescGet(pType);
1217                 FuncDesc aDescPut(pType);
1218                 VarDesc aVarDesc(pType);
1219                 // see if this is a property first ( more likely to be a property then a method )
1220                 getPropDesc( usName, & aDescGet, & aDescPut, & aVarDesc);
1221 
1222                 if ( !aDescGet && !aDescPut )
1223                 {
1224                     getFuncDesc( usName, &aDescGet );
1225                     if ( !aDescGet )
1226                         throw BridgeRuntimeError( OUSTR("[automation bridge]IUnknownWrapper_Impl::initialize() Failed to get Function or Property desc. for " ) + usName );
1227                 }
1228                 // now for some funny heuristics to make basic understand what to do
1229                 // a single aDescGet ( that doesn't take any params ) would be
1230                 // a read only ( defaultmember ) property e.g. this object
1231                 // should implement XDefaultProperty
1232                 // a single aDescGet ( that *does* ) take params is basically a
1233                 // default method e.g. implement XDefaultMethod
1234 
1235                 // 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 )
1236                 if ( aDescPut || ( aDescGet && aDescGet->cParams == 0 ) )
1237                     m_bHasDfltProperty = true;
1238                 if ( aDescGet->cParams > 0 )
1239                     m_bHasDfltMethod = true;
1240                 if ( m_bHasDfltProperty || m_bHasDfltMethod )
1241                     m_sDefaultMember = usName;
1242             }
1243         }
1244         catch ( BridgeRuntimeError & e )
1245         {
1246             throw RuntimeException( e.message, Reference<XInterface>() );
1247         }
1248         catch( Exception& e )
1249         {
1250             throw RuntimeException(
1251                     OUSTR("[automation bridge] unexpected exception in IUnknownWrapper_Impl::initialiase() error message: \n") + e.Message,
1252                     Reference<XInterface>() );
1253         }
1254     }
1255 }
1256 
1257 // --------------------------
1258 // XDirectInvocation
directInvoke(const::rtl::OUString & aName,const uno::Sequence<uno::Any> & aParams)1259 uno::Any SAL_CALL IUnknownWrapper_Impl::directInvoke( const ::rtl::OUString& aName, const uno::Sequence< uno::Any >& aParams )
1260     throw (lang::IllegalArgumentException, script::CannotConvertException, reflection::InvocationTargetException, uno::RuntimeException)
1261 {
1262     Any aResult;
1263 
1264     if ( !m_spDispatch )
1265     {
1266         throw RuntimeException(
1267             OUSTR("[automation bridge] The object does not have an IDispatch interface"),
1268             Reference<XInterface>());
1269     }
1270 
1271     o2u_attachCurrentThread();
1272     DISPID dispid;
1273     if ( !getDispid( aName, &dispid ) )
1274         throw IllegalArgumentException(
1275             OUSTR( "[automation bridge] The object does not have a function or property " )
1276             + aName, Reference<XInterface>(), 0);
1277 
1278     CComVariant     varResult;
1279     ExcepInfo       excepinfo;
1280     unsigned int    uArgErr = 0;
1281     INVOKEKIND pInvkinds[2];
1282     pInvkinds[0] = INVOKE_FUNC;
1283     pInvkinds[1] = aParams.getLength() ? INVOKE_PROPERTYPUT : INVOKE_PROPERTYGET;
1284     HRESULT hInvRes = E_FAIL;
1285 
1286     // try Invoke first, if it does not work, try put/get property
1287     for ( sal_Int32 nStep = 0; FAILED( hInvRes ) && nStep < 2; nStep++ )
1288     {
1289         DISPPARAMS      dispparams = {NULL, NULL, 0, 0};
1290 
1291         DISPID idPropertyPut = DISPID_PROPERTYPUT;
1292         scoped_array<DISPID> arDispidNamedArgs;
1293         scoped_array<CComVariant> ptrArgs;
1294         scoped_array<CComVariant> ptrRefArgs; // referenced arguments
1295         CComVariant * arArgs = NULL;
1296         CComVariant * arRefArgs = NULL;
1297         bool bVarargParam = false;
1298 
1299         dispparams.cArgs = aParams.getLength();
1300 
1301         // Determine the number of named arguments
1302         for ( sal_Int32 nInd = 0; nInd < aParams.getLength(); nInd++ )
1303             if ( aParams[nInd].getValueType() == getCppuType((NamedArgument*) 0) )
1304                 dispparams.cNamedArgs ++;
1305 
1306         // fill the named arguments
1307         if ( dispparams.cNamedArgs > 0
1308           && !( dispparams.cNamedArgs == 1 && pInvkinds[nStep] == INVOKE_PROPERTYPUT ) )
1309         {
1310             int nSizeAr = dispparams.cNamedArgs + 1;
1311             if ( pInvkinds[nStep] == INVOKE_PROPERTYPUT )
1312                 nSizeAr = dispparams.cNamedArgs;
1313 
1314             scoped_array<OLECHAR*> saNames(new OLECHAR*[nSizeAr]);
1315             OLECHAR ** pNames = saNames.get();
1316             pNames[0] = const_cast<OLECHAR*>(reinterpret_cast<LPCOLESTR>(aName.getStr()));
1317 
1318             int cNamedArg = 0;
1319             for ( size_t nInd = 0; nInd < dispparams.cArgs; nInd++ )
1320             {
1321                 if ( aParams[nInd].getValueType() == getCppuType((NamedArgument*) 0))
1322                 {
1323                     const NamedArgument& arg = *(NamedArgument const*)aParams[nInd].getValue();
1324 
1325                     //We put the parameter names in reverse order into the array,
1326                     //so we can use the DISPID array for DISPPARAMS::rgdispidNamedArgs
1327                     //The first name in the array is the method name
1328                     pNames[nSizeAr - 1 - cNamedArg++] = const_cast<OLECHAR*>(reinterpret_cast<LPCOLESTR>(arg.Name.getStr()));
1329                 }
1330             }
1331 
1332             arDispidNamedArgs.reset( new DISPID[nSizeAr] );
1333             HRESULT hr = getTypeInfo()->GetIDsOfNames( pNames, nSizeAr, arDispidNamedArgs.get() );
1334             if ( hr == E_NOTIMPL )
1335                 hr = m_spDispatch->GetIDsOfNames(IID_NULL, pNames, nSizeAr, LOCALE_USER_DEFAULT, arDispidNamedArgs.get() );
1336 
1337             if ( SUCCEEDED( hr ) )
1338             {
1339                 if ( pInvkinds[nStep] == DISPATCH_PROPERTYPUT )
1340                 {
1341                     DISPID*  arIDs = arDispidNamedArgs.get();
1342                     arIDs[0] = DISPID_PROPERTYPUT;
1343                     dispparams.rgdispidNamedArgs = arIDs;
1344                 }
1345                 else
1346                 {
1347                     DISPID*  arIDs = arDispidNamedArgs.get();
1348                     dispparams.rgdispidNamedArgs = & arIDs[1];
1349                 }
1350             }
1351             else if (hr == DISP_E_UNKNOWNNAME)
1352             {
1353                  throw IllegalArgumentException(
1354                      OUSTR("[automation bridge]One of the named arguments is wrong!"),
1355                      Reference<XInterface>(), 0);
1356             }
1357             else
1358             {
1359                 throw InvocationTargetException(
1360                     OUSTR("[automation bridge] ITypeInfo::GetIDsOfNames returned error ")
1361                     + OUString::valueOf((sal_Int32) hr, 16), Reference<XInterface>(), Any());
1362             }
1363         }
1364 
1365         //Convert arguments
1366         ptrArgs.reset(new CComVariant[dispparams.cArgs]);
1367         ptrRefArgs.reset(new CComVariant[dispparams.cArgs]);
1368         arArgs = ptrArgs.get();
1369         arRefArgs = ptrRefArgs.get();
1370 
1371         sal_Int32 nInd = 0;
1372         try
1373         {
1374             sal_Int32 revIndex = 0;
1375             for ( nInd = 0; nInd < sal_Int32(dispparams.cArgs); nInd++)
1376             {
1377                 revIndex = dispparams.cArgs - nInd - 1;
1378                 arRefArgs[revIndex].byref = 0;
1379                 Any  anyArg;
1380                 if ( nInd < aParams.getLength() )
1381                     anyArg = aParams.getConstArray()[nInd];
1382 
1383                 // Property Put arguments
1384                 if ( anyArg.getValueType() == getCppuType((PropertyPutArgument*)0) )
1385                 {
1386                     PropertyPutArgument arg;
1387                     anyArg >>= arg;
1388                     anyArg <<= arg.Value;
1389                 }
1390                 // named argument
1391                 if (anyArg.getValueType() == getCppuType((NamedArgument*) 0))
1392                 {
1393                     NamedArgument aNamedArgument;
1394                     anyArg >>= aNamedArgument;
1395                     anyArg <<= aNamedArgument.Value;
1396                 }
1397 
1398                 if ( nInd < aParams.getLength() && anyArg.getValueTypeClass() != TypeClass_VOID )
1399                 {
1400                     anyToVariant( &arArgs[revIndex], anyArg, VT_VARIANT );
1401                 }
1402                 else
1403                 {
1404                     arArgs[revIndex].vt = VT_ERROR;
1405                     arArgs[revIndex].scode = DISP_E_PARAMNOTFOUND;
1406                 }
1407             }
1408         }
1409         catch (IllegalArgumentException & e)
1410         {
1411             e.ArgumentPosition = ::sal::static_int_cast< sal_Int16, sal_Int32 >( nInd );
1412             throw;
1413         }
1414         catch (CannotConvertException & e)
1415         {
1416             e.ArgumentIndex = nInd;
1417             throw;
1418         }
1419 
1420         dispparams.rgvarg = arArgs;
1421         // invoking OLE method
1422         DWORD localeId = LOCALE_USER_DEFAULT;
1423         hInvRes = m_spDispatch->Invoke( dispid,
1424                                         IID_NULL,
1425                                         localeId,
1426                                         ::sal::static_int_cast< WORD, INVOKEKIND >( pInvkinds[nStep] ),
1427                                         &dispparams,
1428                                         &varResult,
1429                                         &excepinfo,
1430                                         &uArgErr);
1431     }
1432 
1433     // converting return value and out parameter back to UNO
1434     if ( SUCCEEDED( hInvRes ) )
1435         variantToAny( &varResult, aResult, sal_False );
1436     else
1437     {
1438         // map error codes to exceptions
1439         OUString message;
1440         switch ( hInvRes )
1441         {
1442             case S_OK:
1443                 break;
1444             case DISP_E_BADPARAMCOUNT:
1445                 throw IllegalArgumentException(OUSTR("[automation bridge] Wrong "
1446                       "number of arguments. Object returned DISP_E_BADPARAMCOUNT."),
1447                       0, 0);
1448                 break;
1449             case DISP_E_BADVARTYPE:
1450                 throw RuntimeException(OUSTR("[automation bridge] One or more "
1451                       "arguments have the wrong type. Object returned "
1452                       "DISP_E_BADVARTYPE."), 0);
1453                 break;
1454             case DISP_E_EXCEPTION:
1455                     message = OUSTR("[automation bridge]: ");
1456                     message += OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription),
1457                         ::SysStringLen(excepinfo.bstrDescription));
1458                     throw InvocationTargetException(message, Reference<XInterface>(), Any());
1459                     break;
1460             case DISP_E_MEMBERNOTFOUND:
1461                 message = OUSTR("[automation bridge]: A function with the name \"")
1462                     + aName + OUSTR("\" is not supported. Object returned "
1463                     "DISP_E_MEMBERNOTFOUND.");
1464                 throw IllegalArgumentException(message, 0, 0);
1465                 break;
1466             case DISP_E_NONAMEDARGS:
1467                 throw IllegalArgumentException(OUSTR("[automation bridge] Object "
1468                       "returned DISP_E_NONAMEDARGS"),0, ::sal::static_int_cast< sal_Int16, unsigned int >( uArgErr ));
1469                 break;
1470             case DISP_E_OVERFLOW:
1471                 throw CannotConvertException(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("[automation bridge] Call failed.")),
1472                                              static_cast<XInterface*>(
1473                     static_cast<XWeak*>(this)), TypeClass_UNKNOWN, FailReason::OUT_OF_RANGE, uArgErr);
1474                 break;
1475             case DISP_E_PARAMNOTFOUND:
1476                 throw IllegalArgumentException(OUSTR("[automation bridge]Call failed."
1477                                                      "Object returned DISP_E_PARAMNOTFOUND."),
1478                                                0, ::sal::static_int_cast< sal_Int16, unsigned int >( uArgErr ));
1479                 break;
1480             case DISP_E_TYPEMISMATCH:
1481                 throw CannotConvertException(OUSTR("[automation bridge] Call  failed. "
1482                                              "Object returned DISP_E_TYPEMISMATCH"),
1483                     static_cast<XInterface*>(
1484                     static_cast<XWeak*>(this)) , TypeClass_UNKNOWN, FailReason::UNKNOWN, uArgErr);
1485                 break;
1486             case DISP_E_UNKNOWNINTERFACE:
1487                 throw RuntimeException(OUSTR("[automation bridge] Call failed. "
1488                                            "Object returned DISP_E_UNKNOWNINTERFACE."),0);
1489                 break;
1490             case DISP_E_UNKNOWNLCID:
1491                 throw RuntimeException(OUSTR("[automation bridge] Call failed. "
1492                                            "Object returned DISP_E_UNKNOWNLCID."),0);
1493                 break;
1494             case DISP_E_PARAMNOTOPTIONAL:
1495                 throw CannotConvertException(OUSTR("[automation bridge] Call failed."
1496                       "Object returned DISP_E_PARAMNOTOPTIONAL"),
1497                             static_cast<XInterface*>(static_cast<XWeak*>(this)),
1498                                   TypeClass_UNKNOWN, FailReason::NO_DEFAULT_AVAILABLE, uArgErr);
1499                 break;
1500             default:
1501                 throw RuntimeException();
1502                 break;
1503         }
1504     }
1505 
1506     return aResult;
1507 }
1508 
hasMember(const::rtl::OUString & aName)1509 ::sal_Bool SAL_CALL IUnknownWrapper_Impl::hasMember( const ::rtl::OUString& aName )
1510     throw (uno::RuntimeException)
1511 {
1512     if ( ! m_spDispatch )
1513     {
1514         throw RuntimeException(
1515             OUSTR("[automation bridge] The object does not have an IDispatch interface"),
1516             Reference<XInterface>());
1517     }
1518 
1519     o2u_attachCurrentThread();
1520     DISPID dispid;
1521     return getDispid( aName, &dispid );
1522 }
1523 
1524 
1525 // UnoConversionUtilities --------------------------------------------------------------------------------
createUnoWrapperInstance()1526 Reference< XInterface > IUnknownWrapper_Impl::createUnoWrapperInstance()
1527 {
1528     if( m_nUnoWrapperClass == INTERFACE_OLE_WRAPPER_IMPL)
1529     {
1530         Reference<XWeak> xWeak= static_cast<XWeak*>( new InterfaceOleWrapper_Impl(
1531                                 m_smgr, m_nUnoWrapperClass, m_nComWrapperClass));
1532         return Reference<XInterface>( xWeak, UNO_QUERY);
1533     }
1534     else if( m_nUnoWrapperClass == UNO_OBJECT_WRAPPER_REMOTE_OPT)
1535     {
1536         Reference<XWeak> xWeak= static_cast<XWeak*>( new UnoObjectWrapperRemoteOpt(
1537                                 m_smgr, m_nUnoWrapperClass, m_nComWrapperClass));
1538         return Reference<XInterface>( xWeak, UNO_QUERY);
1539     }
1540     else
1541         return Reference<XInterface>();
1542 }
createComWrapperInstance()1543 Reference<XInterface> IUnknownWrapper_Impl::createComWrapperInstance()
1544 {
1545     Reference<XWeak> xWeak= static_cast<XWeak*>( new IUnknownWrapper_Impl(
1546                             m_smgr, m_nUnoWrapperClass, m_nComWrapperClass));
1547     return Reference<XInterface>( xWeak, UNO_QUERY);
1548 }
1549 
1550 
1551 
getMethodInfo(const OUString & sName,TypeDescription & methodInfo)1552 void IUnknownWrapper_Impl::getMethodInfo(const OUString& sName, TypeDescription& methodInfo)
1553 {
1554     TypeDescription desc= getInterfaceMemberDescOfCurrentCall(sName);
1555     if( desc.is())
1556     {
1557         typelib_TypeDescription* pMember= desc.get();
1558         if( pMember->eTypeClass == TypeClass_INTERFACE_METHOD )
1559             methodInfo= pMember;
1560     }
1561 }
1562 
getAttributeInfo(const OUString & sName,TypeDescription & attributeInfo)1563 void IUnknownWrapper_Impl::getAttributeInfo(const OUString& sName, TypeDescription& attributeInfo)
1564 {
1565     TypeDescription desc= getInterfaceMemberDescOfCurrentCall(sName);
1566     if( desc.is())
1567     {
1568         typelib_TypeDescription* pMember= desc.get();
1569         if( pMember->eTypeClass == TypeClass_INTERFACE_ATTRIBUTE )
1570         {
1571             attributeInfo= ((typelib_InterfaceAttributeTypeDescription*)pMember)->pAttributeTypeRef;
1572         }
1573     }
1574 }
getInterfaceMemberDescOfCurrentCall(const OUString & sName)1575 TypeDescription IUnknownWrapper_Impl::getInterfaceMemberDescOfCurrentCall(const OUString& sName)
1576 {
1577     TypeDescription ret;
1578 
1579     for( sal_Int32 i=0; i < m_seqTypes.getLength(); i++)
1580     {
1581         TypeDescription _curDesc( m_seqTypes[i]);
1582         _curDesc.makeComplete();
1583         typelib_InterfaceTypeDescription * pInterface= (typelib_InterfaceTypeDescription*) _curDesc.get();
1584         if( pInterface)
1585         {
1586             typelib_InterfaceMemberTypeDescription* pMember= NULL;
1587             //find the member description of the current call
1588             for( int i=0; i < pInterface->nAllMembers; i++)
1589             {
1590                 typelib_TypeDescriptionReference* pTypeRefMember = pInterface->ppAllMembers[i];
1591                 typelib_TypeDescription* pDescMember= NULL;
1592                 TYPELIB_DANGER_GET( &pDescMember, pTypeRefMember);
1593 
1594                 typelib_InterfaceMemberTypeDescription* pInterfaceMember=
1595                     (typelib_InterfaceMemberTypeDescription*) pDescMember;
1596                 if( OUString( pInterfaceMember->pMemberName) == sName)
1597                 {
1598                     pMember= pInterfaceMember;
1599                     break;
1600                 }
1601                 TYPELIB_DANGER_RELEASE( pDescMember);
1602             }
1603 
1604             if( pMember)
1605             {
1606                 ret= (typelib_TypeDescription*)pMember;
1607                 TYPELIB_DANGER_RELEASE( (typelib_TypeDescription*)pMember);
1608             }
1609         }
1610         if( ret.is())
1611             break;
1612     }
1613     return ret;
1614 }
1615 
isJScriptObject()1616 sal_Bool IUnknownWrapper_Impl::isJScriptObject()
1617 {
1618     if(  m_eJScript == JScriptUndefined)
1619     {
1620         CComDispatchDriver disp( m_spDispatch);
1621         if( disp)
1622         {
1623             CComVariant result;
1624             if( SUCCEEDED(  disp.GetPropertyByName( JSCRIPT_ID_PROPERTY, &result)))
1625             {
1626                 if(result.vt == VT_BSTR)
1627                 {
1628                     CComBSTR name( result.bstrVal);
1629                     name.ToLower();
1630                     if( name == CComBSTR(JSCRIPT_ID))
1631                         m_eJScript= IsJScript;
1632                 }
1633             }
1634         }
1635         if( m_eJScript == JScriptUndefined)
1636             m_eJScript= NoJScript;
1637     }
1638 
1639     return m_eJScript == NoJScript ? sal_False : sal_True;
1640 }
1641 
1642 
1643 
1644 /** @internal
1645     The function ultimately calls IDispatch::Invoke on the wrapped COM object.
1646     The COM object does not implement UNO Interfaces ( via IDispatch). This
1647     is the case when the OleObjectFactory service has been used to create a
1648     component.
1649     @exception IllegalArgumentException
1650     @exception CannotConvertException
1651     @InvocationTargetException
1652     @RuntimeException
1653     @BridgeRuntimeError
1654 */
invokeWithDispIdComTlb(const OUString & sFuncName,const Sequence<Any> & Params,Sequence<sal_Int16> & OutParamIndex,Sequence<Any> & OutParam)1655 Any  IUnknownWrapper_Impl::invokeWithDispIdComTlb(const OUString& sFuncName,
1656                                                   const Sequence< Any >& Params,
1657                                                   Sequence< sal_Int16 >& OutParamIndex,
1658                                                   Sequence< Any >& OutParam)
1659 {
1660     Any ret;
1661     HRESULT result;
1662 
1663     DISPPARAMS      dispparams = {NULL, NULL, 0, 0};
1664     CComVariant     varResult;
1665     ExcepInfo       excepinfo;
1666     unsigned int    uArgErr;
1667     sal_Int32       i = 0;
1668     sal_Int32 nUnoArgs = Params.getLength();
1669     DISPID idPropertyPut = DISPID_PROPERTYPUT;
1670     scoped_array<DISPID> arDispidNamedArgs;
1671     scoped_array<CComVariant> ptrArgs;
1672     scoped_array<CComVariant> ptrRefArgs; // referenced arguments
1673     CComVariant * arArgs = NULL;
1674     CComVariant * arRefArgs = NULL;
1675     sal_Int32 revIndex = 0;
1676     bool bVarargParam = false;
1677 
1678     // Get type info for the call. It can be a method call or property put or
1679     // property get operation.
1680     FuncDesc aFuncDesc(getTypeInfo());
1681     getFuncDescForInvoke(sFuncName, Params, & aFuncDesc);
1682 
1683     //Set the array of DISPIDs for named args if it is a property put operation.
1684     //If there are other named arguments another array is set later on.
1685     if (aFuncDesc->invkind == INVOKE_PROPERTYPUT
1686         || aFuncDesc->invkind == INVOKE_PROPERTYPUTREF)
1687         dispparams.rgdispidNamedArgs = & idPropertyPut;
1688 
1689     //Determine the number of named arguments
1690     for (int iParam = 0; iParam < nUnoArgs; iParam ++)
1691     {
1692         const Any & curArg = Params[iParam];
1693         if (curArg.getValueType() == getCppuType((NamedArgument*) 0))
1694             dispparams.cNamedArgs ++;
1695     }
1696     //In a property put operation a property value is a named argument (DISPID_PROPERTYPUT).
1697     //Therefore the number of named arguments is increased by one.
1698     //Although named, the argument is not named in a actual language, such as  Basic,
1699     //therefore it is never a com.sun.star.bridge.oleautomation.NamedArgument
1700     if (aFuncDesc->invkind == DISPATCH_PROPERTYPUT
1701         || aFuncDesc->invkind == DISPATCH_PROPERTYPUTREF)
1702         dispparams.cNamedArgs ++;
1703 
1704     //Determine the number of all arguments and named arguments
1705     if (aFuncDesc->cParamsOpt == -1)
1706     {
1707         //Attribute vararg is set on this method. "Unlimited" number of args
1708         //supported. There can be no optional or defaultvalue on any of the arguments.
1709         dispparams.cArgs = nUnoArgs;
1710     }
1711     else
1712     {
1713         //If there are namesd arguments, then the dispparams.cArgs
1714         //is the number of supplied args, otherwise it is the expected number.
1715         if (dispparams.cNamedArgs)
1716             dispparams.cArgs = nUnoArgs;
1717         else
1718             dispparams.cArgs = aFuncDesc->cParams;
1719     }
1720 
1721     //check if there are not to many arguments supplied
1722     if (::sal::static_int_cast< sal_uInt32, int >( nUnoArgs ) > dispparams.cArgs)
1723     {
1724         OUStringBuffer buf(256);
1725         buf.appendAscii("[automation bridge] There are too many arguments for this method");
1726         throw IllegalArgumentException( buf.makeStringAndClear(),
1727             Reference<XInterface>(), (sal_Int16) dispparams.cArgs);
1728     }
1729 
1730     //Set up the array of DISPIDs (DISPPARAMS::rgdispidNamedArgs)
1731     //for the named arguments.
1732     //If there is only one named arg and if it is because of a property put
1733     //operation, then we need not set up the DISPID array.
1734     if (dispparams.cNamedArgs > 0 &&
1735         ! (dispparams.cNamedArgs == 1 &&
1736            (aFuncDesc->invkind == INVOKE_PROPERTYPUT ||
1737             aFuncDesc->invkind == INVOKE_PROPERTYPUT)))
1738     {
1739         //set up an array containing the member and parameter names
1740         //which is then used in ITypeInfo::GetIDsOfNames
1741         //First determine the size of the array of names which is passed to
1742         //ITypeInfo::GetIDsOfNames. It must hold the method names + the named
1743         //args.
1744         int nSizeAr = dispparams.cNamedArgs + 1;
1745         if (aFuncDesc->invkind == INVOKE_PROPERTYPUT
1746             || aFuncDesc->invkind == INVOKE_PROPERTYPUTREF)
1747         {
1748             nSizeAr = dispparams.cNamedArgs; //counts the DISID_PROPERTYPUT
1749         }
1750 
1751         scoped_array<OLECHAR*> saNames(new OLECHAR*[nSizeAr]);
1752         OLECHAR ** arNames = saNames.get();
1753         arNames[0] = const_cast<OLECHAR*>(reinterpret_cast<LPCOLESTR>(sFuncName.getStr()));
1754 
1755         int cNamedArg = 0;
1756         for (size_t iParams = 0; iParams < dispparams.cArgs; iParams ++)
1757         {
1758             const Any &  curArg = Params[iParams];
1759             if (curArg.getValueType() == getCppuType((NamedArgument*) 0))
1760             {
1761                 const NamedArgument& arg = *(NamedArgument const*) curArg.getValue();
1762                 //We put the parameter names in reverse order into the array,
1763                 //so we can use the DISPID array for DISPPARAMS::rgdispidNamedArgs
1764                 //The first name in the array is the method name
1765                 arNames[nSizeAr - 1 - cNamedArg++] = const_cast<OLECHAR*>(reinterpret_cast<LPCOLESTR>(arg.Name.getStr()));
1766             }
1767         }
1768 
1769         //Prepare the array of DISPIDs for ITypeInfo::GetIDsOfNames
1770         //it must be big enough to contain the DISPIDs of the member + parameters
1771         arDispidNamedArgs.reset(new DISPID[nSizeAr]);
1772         HRESULT hr = getTypeInfo()->GetIDsOfNames(arNames, nSizeAr,
1773                                                   arDispidNamedArgs.get());
1774         if ( hr == E_NOTIMPL )
1775             hr = m_spDispatch->GetIDsOfNames(IID_NULL, arNames, nSizeAr, LOCALE_USER_DEFAULT, arDispidNamedArgs.get() );
1776 
1777         if (hr == S_OK)
1778         {
1779             // In a "property put" operation, the property value is a named param with the
1780             //special DISPID DISPID_PROPERTYPUT
1781             if (aFuncDesc->invkind == DISPATCH_PROPERTYPUT
1782                 || aFuncDesc->invkind == DISPATCH_PROPERTYPUTREF)
1783             {
1784                 //Element at index 0 in the DISPID array must be DISPID_PROPERTYPUT
1785                 //The first item in the array arDispidNamedArgs is the DISPID for
1786                 //the method. We replace it with DISPID_PROPERTYPUT.
1787                 DISPID*  arIDs = arDispidNamedArgs.get();
1788                 arIDs[0] = DISPID_PROPERTYPUT;
1789                 dispparams.rgdispidNamedArgs = arIDs;
1790             }
1791             else
1792             {
1793                 //The first item in the array arDispidNamedArgs is the DISPID for
1794                 //the method. It must be removed
1795                 DISPID*  arIDs = arDispidNamedArgs.get();
1796                 dispparams.rgdispidNamedArgs = & arIDs[1];
1797             }
1798         }
1799         else if (hr == DISP_E_UNKNOWNNAME)
1800         {
1801              throw IllegalArgumentException(
1802                  OUSTR("[automation bridge]One of the named arguments is wrong!"),
1803                  Reference<XInterface>(), 0);
1804         }
1805         else
1806         {
1807             throw InvocationTargetException(
1808                 OUSTR("[automation bridge] ITypeInfo::GetIDsOfNames returned error ")
1809                 + OUString::valueOf((sal_Int32) hr, 16), Reference<XInterface>(), Any());
1810         }
1811     }
1812 
1813     //Convert arguments
1814     ptrArgs.reset(new CComVariant[dispparams.cArgs]);
1815     ptrRefArgs.reset(new CComVariant[dispparams.cArgs]);
1816     arArgs = ptrArgs.get();
1817     arRefArgs = ptrRefArgs.get();
1818     try
1819     {
1820         for (i = 0; i < (sal_Int32) dispparams.cArgs; i++)
1821         {
1822             revIndex= dispparams.cArgs - i -1;
1823             arRefArgs[revIndex].byref=0;
1824             Any  anyArg;
1825             if ( i < nUnoArgs)
1826                 anyArg= Params.getConstArray()[i];
1827 
1828             //Test if the current parameter is a "vararg" parameter.
1829             if (bVarargParam || (aFuncDesc->cParamsOpt == -1 &&
1830                                 aFuncDesc->cParams == (i + 1)))
1831             {   //This parameter is from the variable argument list. There is no
1832                 //type info available, except that it must be a VARIANT
1833                 bVarargParam = true;
1834             }
1835 
1836             unsigned short paramFlags = PARAMFLAG_FOPT | PARAMFLAG_FIN;
1837             VARTYPE varType = VT_VARIANT;
1838             if ( ! bVarargParam)
1839             {
1840                 paramFlags =
1841                     aFuncDesc->lprgelemdescParam[i].paramdesc.wParamFlags;
1842                 varType = getElementTypeDesc(
1843                     & aFuncDesc->lprgelemdescParam[i].tdesc);
1844             }
1845             //Make sure that there is a UNO parameter for every
1846             // expected parameter. If there is no UNO parameter where the
1847             // called function expects one, then it must be optional. Otherwise
1848             // its a UNO programming error.
1849             if (i  >= nUnoArgs && !(paramFlags & PARAMFLAG_FOPT))
1850             {
1851                 OUStringBuffer buf(256);
1852                 buf.appendAscii("ole automation bridge: The called function expects an argument at"
1853                                 "position: "); //a different number of arguments")),
1854                 buf.append(OUString::valueOf((sal_Int32) i));
1855                 buf.appendAscii(" (index starting at 0).");
1856                 throw IllegalArgumentException( buf.makeStringAndClear(),
1857                                                 Reference<XInterface>(), (sal_Int16) i);
1858             }
1859 
1860             // Property Put arguments
1861             if (anyArg.getValueType() == getCppuType((PropertyPutArgument*)0))
1862             {
1863                 PropertyPutArgument arg;
1864                 anyArg >>= arg;
1865                 anyArg <<= arg.Value;
1866             }
1867             // named argument
1868             if (anyArg.getValueType() == getCppuType((NamedArgument*) 0))
1869             {
1870                 NamedArgument aNamedArgument;
1871                 anyArg >>= aNamedArgument;
1872                 anyArg <<= aNamedArgument.Value;
1873             }
1874             // out param
1875             if (paramFlags & PARAMFLAG_FOUT &&
1876                 ! (paramFlags & PARAMFLAG_FIN)  )
1877             {
1878                 VARTYPE type = ::sal::static_int_cast< VARTYPE, int >( varType ^ VT_BYREF );
1879                 if (i < nUnoArgs)
1880                 {
1881                     arRefArgs[revIndex].vt= type;
1882                 }
1883                 else
1884                 {
1885                     //optional arg
1886                     arRefArgs[revIndex].vt = VT_ERROR;
1887                     arRefArgs[revIndex].scode = DISP_E_PARAMNOTFOUND;
1888                 }
1889                 if( type == VT_VARIANT )
1890                 {
1891                     arArgs[revIndex].vt= VT_VARIANT | VT_BYREF;
1892                     arArgs[revIndex].byref= &arRefArgs[revIndex];
1893                 }
1894                 else
1895                 {
1896                     arArgs[revIndex].vt= varType;
1897                     if (type == VT_DECIMAL)
1898                         arArgs[revIndex].byref= & arRefArgs[revIndex].decVal;
1899                     else
1900                         arArgs[revIndex].byref= & arRefArgs[revIndex].byref;
1901                 }
1902             }
1903             // in/out  + in byref params
1904             else if (varType & VT_BYREF)
1905             {
1906                 VARTYPE type = ::sal::static_int_cast< VARTYPE, int >( varType ^ VT_BYREF );
1907                 CComVariant var;
1908 
1909                 if (i < nUnoArgs && anyArg.getValueTypeClass() != TypeClass_VOID)
1910                 {
1911                     anyToVariant( & arRefArgs[revIndex], anyArg, type);
1912                 }
1913                 else if (paramFlags & PARAMFLAG_FHASDEFAULT)
1914                 {
1915                     //optional arg with default
1916                     VariantCopy( & arRefArgs[revIndex],
1917                                 & aFuncDesc->lprgelemdescParam[i].paramdesc.
1918                                 pparamdescex->varDefaultValue);
1919                 }
1920                 else
1921                 {
1922                     //optional arg
1923                     //e.g: call func(x) in basic : func() ' no arg supplied
1924                     OSL_ASSERT(paramFlags & PARAMFLAG_FOPT);
1925                     arRefArgs[revIndex].vt = VT_ERROR;
1926                     arRefArgs[revIndex].scode = DISP_E_PARAMNOTFOUND;
1927                 }
1928 
1929                 // Set the converted arguments in the array which will be
1930                 // DISPPARAMS::rgvarg
1931                 // byref arg VT_XXX |VT_BYREF
1932                 arArgs[revIndex].vt = varType;
1933                 if (revIndex == 0 && aFuncDesc->invkind == INVOKE_PROPERTYPUT)
1934                 {
1935                     arArgs[revIndex] = arRefArgs[revIndex];
1936                 }
1937                 else if (type == VT_DECIMAL)
1938                 {
1939                     arArgs[revIndex].byref= & arRefArgs[revIndex].decVal;
1940                 }
1941                 else if (type == VT_VARIANT)
1942                 {
1943                     if ( ! (paramFlags & PARAMFLAG_FOUT))
1944                         arArgs[revIndex] = arRefArgs[revIndex];
1945                     else
1946                         arArgs[revIndex].byref = & arRefArgs[revIndex];
1947                 }
1948                 else
1949                 {
1950                     arArgs[revIndex].byref = & arRefArgs[revIndex].byref;
1951                     arArgs[revIndex].vt = ::sal::static_int_cast< VARTYPE, int >( arRefArgs[revIndex].vt | VT_BYREF );
1952                 }
1953 
1954             }
1955             // in parameter no VT_BYREF except for array, interfaces
1956             else
1957             {   // void any stands for optional param
1958                 if (i < nUnoArgs && anyArg.getValueTypeClass() != TypeClass_VOID)
1959                 {
1960                     anyToVariant( & arArgs[revIndex], anyArg, varType);
1961                 }
1962                 //optional arg but no void any supplied
1963                 //Basic:  obj.func() ' first parameter left out because it is optional
1964                 else if (paramFlags & PARAMFLAG_FHASDEFAULT)
1965                 {
1966                     //optional arg with defaulteithter as direct arg : VT_XXX or
1967                     VariantCopy( & arArgs[revIndex],
1968                         & aFuncDesc->lprgelemdescParam[i].paramdesc.
1969                             pparamdescex->varDefaultValue);
1970                 }
1971                 else if (paramFlags & PARAMFLAG_FOPT)
1972                 {
1973                     arArgs[revIndex].vt = VT_ERROR;
1974                     arArgs[revIndex].scode = DISP_E_PARAMNOTFOUND;
1975                 }
1976                 else
1977                 {
1978                     arArgs[revIndex].vt = VT_EMPTY;
1979                     arArgs[revIndex].lVal = 0;
1980                 }
1981             }
1982         }
1983     }
1984     catch (IllegalArgumentException & e)
1985     {
1986         e.ArgumentPosition = ::sal::static_int_cast< sal_Int16, sal_Int32 >( i );
1987         throw;
1988     }
1989     catch (CannotConvertException & e)
1990     {
1991         e.ArgumentIndex = i;
1992         throw;
1993     }
1994     dispparams.rgvarg= arArgs;
1995     // invoking OLE method
1996     DWORD localeId = LOCALE_USER_DEFAULT;
1997     result = m_spDispatch->Invoke(aFuncDesc->memid,
1998                                  IID_NULL,
1999                                  localeId,
2000                                  ::sal::static_int_cast< WORD, INVOKEKIND >( aFuncDesc->invkind ),
2001                                  &dispparams,
2002                                  &varResult,
2003                                  &excepinfo,
2004                                  &uArgErr);
2005 
2006     // converting return value and out parameter back to UNO
2007     if (result == S_OK)
2008     {
2009 
2010         // allocate space for the out param Sequence and indices Sequence
2011         int outParamsCount= 0; // includes in/out parameter
2012         for (int i = 0; i < aFuncDesc->cParams; i++)
2013         {
2014             if (aFuncDesc->lprgelemdescParam[i].paramdesc.wParamFlags &
2015                 PARAMFLAG_FOUT)
2016                 outParamsCount++;
2017         }
2018 
2019         OutParamIndex.realloc(outParamsCount);
2020         OutParam.realloc(outParamsCount);
2021         // Convert out params
2022         if (outParamsCount)
2023         {
2024             int outParamIndex=0;
2025             for (int paramIndex = 0; paramIndex < nUnoArgs; paramIndex ++)
2026             {
2027                 //Determine the index within the method sinature
2028                 int realParamIndex = paramIndex;
2029                 int revParamIndex = dispparams.cArgs - paramIndex - 1;
2030                 if (Params[paramIndex].getValueType()
2031                     == getCppuType((NamedArgument*) 0))
2032                 {
2033                     //dispparams.rgdispidNamedArgs contains the mapping from index
2034                     //of named args list to index of parameter list
2035                     realParamIndex = dispparams.rgdispidNamedArgs[revParamIndex];
2036                 }
2037 
2038                 // no named arg, always come before named args
2039                 if (! (aFuncDesc->lprgelemdescParam[realParamIndex].paramdesc.wParamFlags
2040                        & PARAMFLAG_FOUT))
2041                     continue;
2042                 Any outAny;
2043                 // variantToAny is called with the "reduce range" parameter set to sal_False.
2044                 // That causes VT_I4 values not to be converted down to a "lower" type. That
2045                 // feature exist for JScript only because it only uses VT_I4 for integer types.
2046                 try
2047                 {
2048                     variantToAny( & arRefArgs[revParamIndex], outAny, sal_False );
2049                 }
2050                 catch (IllegalArgumentException & e)
2051                 {
2052                     e.ArgumentPosition = (sal_Int16)paramIndex;
2053                     throw;
2054                 }
2055                 catch (CannotConvertException & e)
2056                 {
2057                     e.ArgumentIndex = paramIndex;
2058                     throw;
2059                 }
2060                 OutParam[outParamIndex] = outAny;
2061                 OutParamIndex[outParamIndex] = ::sal::static_int_cast< sal_Int16, int >( paramIndex );
2062                 outParamIndex++;
2063             }
2064             OutParam.realloc(outParamIndex);
2065             OutParamIndex.realloc(outParamIndex);
2066         }
2067         // Return value
2068         variantToAny(&varResult, ret, sal_False);
2069     }
2070 
2071     // map error codes to exceptions
2072     OUString message;
2073     switch (result)
2074     {
2075         case S_OK:
2076             break;
2077         case DISP_E_BADPARAMCOUNT:
2078             throw IllegalArgumentException(OUSTR("[automation bridge] Wrong "
2079                   "number of arguments. Object returned DISP_E_BADPARAMCOUNT."),
2080                   0, 0);
2081             break;
2082         case DISP_E_BADVARTYPE:
2083             throw RuntimeException(OUSTR("[automation bridge] One or more "
2084                   "arguments have the wrong type. Object returned "
2085                   "DISP_E_BADVARTYPE."), 0);
2086             break;
2087         case DISP_E_EXCEPTION:
2088                 message = OUSTR("[automation bridge]: ");
2089                 message += OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription),
2090                     ::SysStringLen(excepinfo.bstrDescription));
2091                 throw InvocationTargetException(message, Reference<XInterface>(), Any());
2092                 break;
2093         case DISP_E_MEMBERNOTFOUND:
2094             message = OUSTR("[automation bridge]: A function with the name \"")
2095                 + sFuncName + OUSTR("\" is not supported. Object returned "
2096                 "DISP_E_MEMBERNOTFOUND.");
2097             throw IllegalArgumentException(message, 0, 0);
2098             break;
2099         case DISP_E_NONAMEDARGS:
2100             throw IllegalArgumentException(OUSTR("[automation bridge] Object "
2101                   "returned DISP_E_NONAMEDARGS"),0, ::sal::static_int_cast< sal_Int16, unsigned int >( uArgErr ));
2102             break;
2103         case DISP_E_OVERFLOW:
2104             throw CannotConvertException(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("[automation bridge] Call failed.")),
2105                                          static_cast<XInterface*>(
2106                 static_cast<XWeak*>(this)), TypeClass_UNKNOWN, FailReason::OUT_OF_RANGE, uArgErr);
2107             break;
2108         case DISP_E_PARAMNOTFOUND:
2109             throw IllegalArgumentException(OUSTR("[automation bridge]Call failed."
2110                                                  "Object returned DISP_E_PARAMNOTFOUND."),
2111                                            0, ::sal::static_int_cast< sal_Int16, unsigned int >( uArgErr ));
2112             break;
2113         case DISP_E_TYPEMISMATCH:
2114             throw CannotConvertException(OUSTR("[automation bridge] Call  failed. "
2115                                          "Object returned DISP_E_TYPEMISMATCH"),
2116                 static_cast<XInterface*>(
2117                 static_cast<XWeak*>(this)) , TypeClass_UNKNOWN, FailReason::UNKNOWN, uArgErr);
2118             break;
2119         case DISP_E_UNKNOWNINTERFACE:
2120             throw RuntimeException(OUSTR("[automation bridge] Call failed. "
2121                                        "Object returned DISP_E_UNKNOWNINTERFACE."),0);
2122             break;
2123         case DISP_E_UNKNOWNLCID:
2124             throw RuntimeException(OUSTR("[automation bridge] Call failed. "
2125                                        "Object returned DISP_E_UNKNOWNLCID."),0);
2126             break;
2127         case DISP_E_PARAMNOTOPTIONAL:
2128             throw CannotConvertException(OUSTR("[automation bridge] Call failed."
2129                   "Object returned DISP_E_PARAMNOTOPTIONAL"),
2130                         static_cast<XInterface*>(static_cast<XWeak*>(this)),
2131                               TypeClass_UNKNOWN, FailReason::NO_DEFAULT_AVAILABLE, uArgErr);
2132             break;
2133         default:
2134             throw RuntimeException();
2135             break;
2136     }
2137 
2138     return ret;
2139 }
2140 
getFuncDescForInvoke(const OUString & sFuncName,const Sequence<Any> & seqArgs,FUNCDESC ** pFuncDesc)2141 void IUnknownWrapper_Impl::getFuncDescForInvoke(const OUString & sFuncName,
2142                                                 const Sequence<Any> & seqArgs,
2143                                                 FUNCDESC** pFuncDesc)
2144 {
2145     int nUnoArgs = seqArgs.getLength();
2146     const Any * arArgs = seqArgs.getConstArray();
2147     ITypeInfo* pInfo = getTypeInfo();
2148 
2149     //If the last of the positional arguments is a PropertyPutArgument
2150     //then obtain the type info for the property put operation.
2151 
2152     //The property value is always the last argument, in a positional argument list
2153     //or in a list of named arguments. A PropertyPutArgument is actually a named argument
2154     //hence it must not be put in an extra NamedArgument structure
2155     if (nUnoArgs > 0 &&
2156         arArgs[nUnoArgs - 1].getValueType() == getCppuType((PropertyPutArgument*) 0))
2157     {
2158         // DISPATCH_PROPERTYPUT
2159         FuncDesc aDescGet(pInfo);
2160         FuncDesc aDescPut(pInfo);
2161         VarDesc aVarDesc(pInfo);
2162         getPropDesc(sFuncName, & aDescGet, & aDescPut, & aVarDesc);
2163         if ( ! aDescPut)
2164         {
2165             throw IllegalArgumentException(
2166                 OUSTR("[automation bridge] The object does not have a writeable property: ")
2167                 + sFuncName, Reference<XInterface>(), 0);
2168         }
2169         *pFuncDesc = aDescPut.Detach();
2170     }
2171     else
2172     {   // DISPATCH_METHOD
2173         FuncDesc aFuncDesc(pInfo);
2174         getFuncDesc(sFuncName, & aFuncDesc);
2175         if ( ! aFuncDesc)
2176         {
2177             // Fallback: DISPATCH_PROPERTYGET can mostly be called as
2178             // DISPATCH_METHOD
2179             ITypeInfo * pInfo = getTypeInfo();
2180             FuncDesc aDescPut(pInfo);
2181             VarDesc aVarDesc(pInfo);
2182             getPropDesc(sFuncName, & aFuncDesc, & aDescPut, & aVarDesc);
2183             if ( ! aFuncDesc )
2184             {
2185                 throw IllegalArgumentException(
2186                     OUSTR("[automation bridge] The object does not have a function"
2187                           "or readable property \"")
2188                     + sFuncName, Reference<XInterface>(), 0);
2189             }
2190         }
2191         *pFuncDesc = aFuncDesc.Detach();
2192     }
2193 }
getDispid(const OUString & sFuncName,DISPID * id)2194 bool IUnknownWrapper_Impl::getDispid(const OUString& sFuncName, DISPID * id)
2195 {
2196     OSL_ASSERT(m_spDispatch);
2197     LPOLESTR lpsz = const_cast<LPOLESTR> (reinterpret_cast<LPCOLESTR>(sFuncName.getStr()));
2198     HRESULT hr = m_spDispatch->GetIDsOfNames(IID_NULL, &lpsz, 1, LOCALE_USER_DEFAULT, id);
2199     return hr == S_OK ? true : false;
2200 }
getFuncDesc(const OUString & sFuncName,FUNCDESC ** pFuncDesc)2201 void IUnknownWrapper_Impl::getFuncDesc(const OUString & sFuncName, FUNCDESC ** pFuncDesc)
2202 
2203 {
2204     OSL_ASSERT( * pFuncDesc == 0);
2205     buildComTlbIndex();
2206     typedef TLBFuncIndexMap::const_iterator cit;
2207         typedef TLBFuncIndexMap::iterator it;
2208     //We assume there is only one entry with the function name. A property
2209     //would have two entries.
2210     cit itIndex= m_mapComFunc.find(sFuncName);
2211     if (itIndex == m_mapComFunc.end())
2212     {
2213         //try case insensive with IDispatch::GetIDsOfNames
2214         DISPID id;
2215         if (getDispid(sFuncName, &id))
2216         {
2217             CComBSTR memberName;
2218             unsigned int pcNames=0;
2219             // get the case sensitive name
2220             if( SUCCEEDED(getTypeInfo()->GetNames( id, & memberName, 1, &pcNames)))
2221             {
2222                 //get the associated index and add an entry to the map
2223                 //with the name sFuncName which differs in the casing of the letters to
2224                 //the actual name as obtained from ITypeInfo
2225                 cit itOrg  = m_mapComFunc.find(OUString(reinterpret_cast<const sal_Unicode*>(LPCOLESTR(memberName))));
2226                 OSL_ASSERT(itOrg != m_mapComFunc.end());
2227                 itIndex =
2228                     m_mapComFunc.insert( TLBFuncIndexMap::value_type
2229                     ( make_pair(sFuncName, itOrg->second ) ));
2230             }
2231         }
2232     }
2233 
2234 #if OSL_DEBUG_LEVEL >= 1
2235     // There must only be one entry if sFuncName represents a function or two
2236     // if it is a property
2237     pair<cit, cit> p = m_mapComFunc.equal_range(sFuncName.toAsciiLowerCase());
2238     int numEntries = 0;
2239     for ( ;p.first != p.second; p.first ++, numEntries ++);
2240     OSL_ASSERT( ! (numEntries > 3) );
2241 #endif
2242     if( itIndex != m_mapComFunc.end())
2243     {
2244         ITypeInfo* pType= getTypeInfo();
2245         FUNCDESC * pDesc = NULL;
2246         if (SUCCEEDED(pType->GetFuncDesc(itIndex->second, & pDesc)))
2247         {
2248             if (pDesc->invkind == INVOKE_FUNC)
2249             {
2250                 (*pFuncDesc) = pDesc;
2251             }
2252             else
2253             {
2254                 pType->ReleaseFuncDesc(pDesc);
2255             }
2256         }
2257         else
2258         {
2259             throw BridgeRuntimeError(OUSTR("[automation bridge] Could not get "
2260                                            "FUNCDESC for ") + sFuncName);
2261         }
2262     }
2263    //else no entry found for sFuncName, pFuncDesc will not be filled in
2264 }
2265 
getPropDesc(const OUString & sFuncName,FUNCDESC ** pFuncDescGet,FUNCDESC ** pFuncDescPut,VARDESC ** pVarDesc)2266 void IUnknownWrapper_Impl::getPropDesc(const OUString & sFuncName, FUNCDESC ** pFuncDescGet,
2267                                        FUNCDESC** pFuncDescPut, VARDESC** pVarDesc)
2268 {
2269     OSL_ASSERT( * pFuncDescGet == 0 && * pFuncDescPut == 0);
2270     buildComTlbIndex();
2271     typedef TLBFuncIndexMap::const_iterator cit;
2272     pair<cit, cit> p = m_mapComFunc.equal_range(sFuncName);
2273     if (p.first == m_mapComFunc.end())
2274     {
2275         //try case insensive with IDispatch::GetIDsOfNames
2276         DISPID id;
2277         if (getDispid(sFuncName, &id))
2278         {
2279             CComBSTR memberName;
2280             unsigned int pcNames=0;
2281             // get the case sensitive name
2282             if( SUCCEEDED(getTypeInfo()->GetNames( id, & memberName, 1, &pcNames)))
2283             {
2284                 //As opposed to getFuncDesc, we do not add the value because we would
2285                 // need to find the get and set description for the property. This would
2286                 //mean to iterate over all FUNCDESCs again.
2287                 p = m_mapComFunc.equal_range(OUString(reinterpret_cast<const sal_Unicode*>(LPCOLESTR(memberName))));
2288             }
2289         }
2290     }
2291 
2292     for ( int i = 0 ;p.first != p.second; p.first ++, i ++)
2293     {
2294         // There are a maximum of two entries, property put and property get
2295         OSL_ASSERT( ! (i > 2) );
2296         ITypeInfo* pType= getTypeInfo();
2297         FUNCDESC * pFuncDesc = NULL;
2298         if (SUCCEEDED( pType->GetFuncDesc(p.first->second, & pFuncDesc)))
2299         {
2300             if (pFuncDesc->invkind == INVOKE_PROPERTYGET)
2301             {
2302                 (*pFuncDescGet) = pFuncDesc;
2303             }
2304             else if (pFuncDesc->invkind == INVOKE_PROPERTYPUT ||
2305                      pFuncDesc->invkind == INVOKE_PROPERTYPUTREF)
2306             {
2307                 //a property can have 3 entries, put, put ref, get
2308                 // If INVOKE_PROPERTYPUTREF or INVOKE_PROPERTYPUT is used
2309                 //depends on what is found first.
2310                 if ( * pFuncDescPut)
2311                 {
2312                     //we already have found one
2313                     pType->ReleaseFuncDesc(pFuncDesc);
2314                 }
2315                 else
2316                 {
2317                     (*pFuncDescPut) = pFuncDesc;
2318                 }
2319             }
2320             else
2321             {
2322                 pType->ReleaseFuncDesc(pFuncDesc);
2323             }
2324         }
2325         //ITypeInfo::GetFuncDesc may even provide a funcdesc for a VARDESC
2326         // with invkind = INVOKE_FUNC. Since this function should only return
2327         //a value for a real property (XInvokation::hasMethod, ..::hasProperty
2328         //we need to make sure that sFuncName represents a real property.
2329         VARDESC * pVD = NULL;
2330         if (SUCCEEDED(pType->GetVarDesc(p.first->second, & pVD)))
2331             (*pVarDesc) = pVD;
2332     }
2333    //else no entry for sFuncName, pFuncDesc will not be filled in
2334 }
2335 
lcl_getUserDefinedElementType(ITypeInfo * pTypeInfo,const DWORD nHrefType)2336 VARTYPE lcl_getUserDefinedElementType( ITypeInfo* pTypeInfo, const DWORD nHrefType )
2337 {
2338     VARTYPE _type( VT_NULL );
2339     if ( pTypeInfo )
2340     {
2341         CComPtr<ITypeInfo> spRefInfo;
2342         pTypeInfo->GetRefTypeInfo( nHrefType, &spRefInfo.p );
2343         if ( spRefInfo )
2344         {
2345             TypeAttr attr( spRefInfo );
2346             spRefInfo->GetTypeAttr( &attr );
2347             if ( attr->typekind == TKIND_ENUM )
2348             {
2349                 // We use the type of the first enum value.
2350                 if ( attr->cVars == 0 )
2351                 {
2352                     throw BridgeRuntimeError(OUSTR("[automation bridge] Could not obtain type description"));
2353                 }
2354                 VarDesc var( spRefInfo );
2355                 spRefInfo->GetVarDesc( 0, &var );
2356                 _type = var->lpvarValue->vt;
2357             }
2358             else if ( attr->typekind == TKIND_INTERFACE )
2359             {
2360                 _type = VT_UNKNOWN;
2361             }
2362             else if ( attr->typekind == TKIND_DISPATCH )
2363             {
2364                 _type = VT_DISPATCH;
2365             }
2366             else if ( attr->typekind == TKIND_ALIAS )
2367             {
2368                 // TKIND_ALIAS is a type that is an alias for another type. So get that alias type.
2369                 _type = lcl_getUserDefinedElementType( pTypeInfo, attr->tdescAlias.hreftype );
2370             }
2371             else
2372             {
2373                 throw BridgeRuntimeError( OUSTR("[automation bridge] Unhandled user defined type.") );
2374             }
2375         }
2376     }
2377     return _type;
2378 }
2379 
getElementTypeDesc(const TYPEDESC * desc)2380 VARTYPE IUnknownWrapper_Impl::getElementTypeDesc(const TYPEDESC *desc)
2381 {
2382     VARTYPE _type( VT_NULL );
2383 
2384     if (desc->vt == VT_PTR)
2385     {
2386         _type = getElementTypeDesc(desc->lptdesc);
2387         _type |= VT_BYREF;
2388     }
2389     else if (desc->vt == VT_SAFEARRAY)
2390     {
2391         _type = getElementTypeDesc(desc->lptdesc);
2392         _type |= VT_ARRAY;
2393     }
2394     else if (desc->vt == VT_USERDEFINED)
2395     {
2396         ITypeInfo* thisInfo = getTypeInfo(); //kept by this instance
2397         _type = lcl_getUserDefinedElementType( thisInfo, desc->hreftype );
2398     }
2399     else
2400     {
2401         _type = desc->vt;
2402     }
2403     return _type;
2404 }
2405 
buildComTlbIndex()2406 void IUnknownWrapper_Impl::buildComTlbIndex()
2407 {
2408     if ( ! m_bComTlbIndexInit)
2409     {
2410         MutexGuard guard(getBridgeMutex());
2411         {
2412             if ( ! m_bComTlbIndexInit)
2413             {
2414                 OUString sError;
2415                 ITypeInfo* pType= getTypeInfo();
2416                 TypeAttr typeAttr(pType);
2417                 if( SUCCEEDED( pType->GetTypeAttr( &typeAttr)))
2418                 {
2419                     for( long i= 0; i < typeAttr->cFuncs; i++)
2420                     {
2421                         FuncDesc funcDesc(pType);
2422                         if( SUCCEEDED( pType->GetFuncDesc( i, &funcDesc)))
2423                         {
2424                             CComBSTR memberName;
2425                             unsigned int pcNames=0;
2426                             if( SUCCEEDED(pType->GetNames( funcDesc->memid, & memberName, 1, &pcNames)))
2427                             {
2428                                 OUString usName(reinterpret_cast<const sal_Unicode*>(LPCOLESTR(memberName)));
2429                                 m_mapComFunc.insert( TLBFuncIndexMap::value_type( usName, i));
2430                             }
2431                             else
2432                             {
2433                                 sError = OUSTR("[automation bridge] IUnknownWrapper_Impl::buildComTlbIndex, " \
2434                                                 "ITypeInfo::GetNames failed.");
2435                             }
2436                         }
2437                         else
2438                             sError = OUSTR("[automation bridge] IUnknownWrapper_Impl::buildComTlbIndex, " \
2439                                             "ITypeInfo::GetFuncDesc failed.");
2440                     }
2441 
2442                     //If we create an Object in JScript and a a property then it
2443                     //has VARDESC instead of FUNCDESC
2444                     for (long i = 0; i < typeAttr->cVars; i++)
2445                     {
2446                         VarDesc varDesc(pType);
2447                         if (SUCCEEDED(pType->GetVarDesc(i, & varDesc)))
2448                         {
2449                             CComBSTR memberName;
2450                             unsigned int pcNames = 0;
2451                             if (SUCCEEDED(pType->GetNames(varDesc->memid, & memberName, 1, &pcNames)))
2452                             {
2453                                 if (varDesc->varkind == VAR_DISPATCH)
2454                                 {
2455                                     OUString usName(reinterpret_cast<const sal_Unicode*>(LPCOLESTR(memberName)));
2456                                     m_mapComFunc.insert(TLBFuncIndexMap::value_type(
2457                                                         usName, i));
2458                                 }
2459                             }
2460                             else
2461                             {
2462                                 sError = OUSTR("[automation bridge] IUnknownWrapper_Impl::buildComTlbIndex, " \
2463                                                 "ITypeInfo::GetNames failed.");
2464                             }
2465                         }
2466                         else
2467                             sError = OUSTR("[automation bridge] IUnknownWrapper_Impl::buildComTlbIndex, " \
2468                                            "ITypeInfo::GetVarDesc failed.");
2469 
2470                     }
2471                 }
2472                 else
2473                     sError = OUSTR("[automation bridge] IUnknownWrapper_Impl::buildComTlbIndex, " \
2474                                     "ITypeInfo::GetTypeAttr failed.");
2475 
2476                 if (sError.getLength())
2477                 {
2478                     throw BridgeRuntimeError(sError);
2479                 }
2480 
2481                 m_bComTlbIndexInit = true;
2482             }
2483         }
2484     }
2485 }
2486 
getTypeInfo()2487 ITypeInfo* IUnknownWrapper_Impl::getTypeInfo()
2488 {
2489     if( !m_spDispatch)
2490     {
2491         throw BridgeRuntimeError(OUSTR("The object has no IDispatch interface!"));
2492     }
2493 
2494     if( !m_spTypeInfo )
2495     {
2496         MutexGuard guard(getBridgeMutex());
2497         if( ! m_spTypeInfo)
2498         {
2499             CComPtr< ITypeInfo > spType;
2500             if( SUCCEEDED( m_spDispatch->GetTypeInfo( 0, LOCALE_USER_DEFAULT, &spType.p)))
2501 
2502             {
2503                 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
2504 
2505                 //If this is a dual interface then TYPEATTR::typekind is usually TKIND_INTERFACE
2506                 //We need to get the type description for TKIND_DISPATCH
2507                 TypeAttr typeAttr(spType.p);
2508                 if( SUCCEEDED(spType->GetTypeAttr( &typeAttr)))
2509                 {
2510                     if (typeAttr->typekind == TKIND_INTERFACE &&
2511                             typeAttr->wTypeFlags & TYPEFLAG_FDUAL)
2512                     {
2513                         HREFTYPE refDispatch;
2514                         if (SUCCEEDED(spType->GetRefTypeOfImplType(::sal::static_int_cast< UINT, int >( -1 ), &refDispatch)))
2515                         {
2516                             CComPtr<ITypeInfo> spTypeDisp;
2517                             if (SUCCEEDED(spType->GetRefTypeInfo(refDispatch, & spTypeDisp)))
2518                                 m_spTypeInfo= spTypeDisp;
2519                         }
2520                         else
2521                         {
2522                             throw BridgeRuntimeError(
2523                                 OUSTR("[automation bridge] Could not obtain type information "
2524                                 "for dispatch interface." ));
2525                         }
2526                     }
2527                     else if (typeAttr->typekind == TKIND_DISPATCH)
2528                     {
2529                         m_spTypeInfo= spType;
2530                     }
2531                     else
2532                     {
2533                         throw BridgeRuntimeError(
2534                             OUSTR("[automation bridge] Automation object does not "
2535                             "provide type information."));
2536                     }
2537                 }
2538             }
2539             else
2540             {
2541                 throw BridgeRuntimeError(OUSTR("[automation bridge]The dispatch object does not "
2542                                                "support ITypeInfo!"));
2543             }
2544         }
2545     }
2546     return m_spTypeInfo;
2547 }
2548 
2549 } // end namespace
2550 
2551