xref: /core/basic/source/classes/sbunoobj.cxx (revision fbc038cc)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <sal/config.h>
21 
22 #include <o3tl/any.hxx>
23 #include <osl/mutex.hxx>
24 #include <vcl/svapp.hxx>
25 #include <vcl/errcode.hxx>
26 #include <svl/hint.hxx>
27 
28 #include <cppuhelper/implbase.hxx>
29 #include <cppuhelper/exc_hlp.hxx>
30 #include <cppuhelper/typeprovider.hxx>
31 #include <comphelper/interfacecontainer2.hxx>
32 #include <comphelper/extract.hxx>
33 #include <comphelper/processfactory.hxx>
34 #include <cppuhelper/weakref.hxx>
35 
36 #include <rtl/instance.hxx>
37 #include <rtl/strbuf.hxx>
38 #include <rtl/ustrbuf.hxx>
39 
40 #include <com/sun/star/script/ArrayWrapper.hpp>
41 #include <com/sun/star/script/CannotConvertException.hpp>
42 #include <com/sun/star/script/NativeObjectWrapper.hpp>
43 
44 #include <com/sun/star/uno/XComponentContext.hpp>
45 #include <com/sun/star/uno/DeploymentException.hpp>
46 #include <com/sun/star/lang/XTypeProvider.hpp>
47 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
48 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
49 #include <com/sun/star/lang/XServiceInfo.hpp>
50 #include <com/sun/star/beans/PropertyAttribute.hpp>
51 #include <com/sun/star/beans/PropertyConcept.hpp>
52 #include <com/sun/star/beans/MethodConcept.hpp>
53 #include <com/sun/star/beans/XPropertySet.hpp>
54 #include <com/sun/star/beans/theIntrospection.hpp>
55 #include <com/sun/star/script/BasicErrorException.hpp>
56 #include <com/sun/star/script/InvocationAdapterFactory.hpp>
57 #include <com/sun/star/script/XAllListener.hpp>
58 #include <com/sun/star/script/XInvocationAdapterFactory.hpp>
59 #include <com/sun/star/script/Converter.hpp>
60 #include <com/sun/star/script/XDefaultProperty.hpp>
61 #include <com/sun/star/script/XDirectInvocation.hpp>
62 #include <com/sun/star/container/XNameAccess.hpp>
63 #include <com/sun/star/container/XHierarchicalNameAccess.hpp>
64 #include <com/sun/star/reflection/XIdlArray.hpp>
65 #include <com/sun/star/reflection/XIdlReflection.hpp>
66 #include <com/sun/star/reflection/XServiceConstructorDescription.hpp>
67 #include <com/sun/star/reflection/theCoreReflection.hpp>
68 #include <com/sun/star/bridge/oleautomation/NamedArgument.hpp>
69 #include <com/sun/star/bridge/oleautomation/Date.hpp>
70 #include <com/sun/star/bridge/oleautomation/Decimal.hpp>
71 #include <com/sun/star/bridge/oleautomation/Currency.hpp>
72 #include <com/sun/star/bridge/oleautomation/XAutomationObject.hpp>
73 #include <com/sun/star/script/XAutomationInvocation.hpp>
74 #include <basic/codecompletecache.hxx>
75 
76 #include <rtlproto.hxx>
77 
78 #include <basic/sbstar.hxx>
79 #include <basic/sbuno.hxx>
80 #include <basic/sberrors.hxx>
81 #include <sbunoobj.hxx>
82 #include <sbjsmod.hxx>
83 #include <basic/basmgr.hxx>
84 #include <sbintern.hxx>
85 #include <runtime.hxx>
86 
87 #include <math.h>
88 #include <memory>
89 #include <unordered_map>
90 #include <com/sun/star/reflection/XTypeDescriptionEnumerationAccess.hpp>
91 #include <com/sun/star/reflection/XConstantsTypeDescription.hpp>
92 
93 using com::sun::star::uno::Reference;
94 using namespace com::sun::star::uno;
95 using namespace com::sun::star::lang;
96 using namespace com::sun::star::reflection;
97 using namespace com::sun::star::beans;
98 using namespace com::sun::star::script;
99 using namespace com::sun::star::container;
100 using namespace com::sun::star::bridge;
101 using namespace cppu;
102 
103 
104 // Identifiers for creating the strings for dbg_Properties
105 static char const ID_DBG_SUPPORTEDINTERFACES[] = "Dbg_SupportedInterfaces";
106 static char const ID_DBG_PROPERTIES[] = "Dbg_Properties";
107 static char const ID_DBG_METHODS[] = "Dbg_Methods";
108 
109 static char const aSeqLevelStr[] = "[]";
110 
111 // Gets the default property for a uno object. Note: There is some
112 // redirection built in. The property name specifies the name
113 // of the default property.
114 
115 bool SbUnoObject::getDefaultPropName( SbUnoObject const * pUnoObj, OUString& sDfltProp )
116 {
117     bool bResult = false;
118     Reference< XDefaultProperty> xDefaultProp( pUnoObj->maTmpUnoObj, UNO_QUERY );
119     if ( xDefaultProp.is() )
120     {
121         sDfltProp = xDefaultProp->getDefaultPropertyName();
122         if ( !sDfltProp.isEmpty() )
123             bResult = true;
124     }
125     return bResult;
126 }
127 
128 SbxVariable* getDefaultProp( SbxVariable* pRef )
129 {
130     SbxVariable* pDefaultProp = nullptr;
131     if ( pRef->GetType() == SbxOBJECT )
132     {
133         SbxObject* pObj = dynamic_cast<SbxObject*>(pRef);
134         if (!pObj)
135         {
136             SbxBase* pObjVarObj = pRef->GetObject();
137             pObj = dynamic_cast<SbxObject*>( pObjVarObj );
138         }
139         if (SbUnoObject* pUnoObj = dynamic_cast<SbUnoObject*>(pObj))
140         {
141             pDefaultProp = pUnoObj->GetDfltProperty();
142         }
143     }
144     return pDefaultProp;
145 }
146 
147 void SetSbUnoObjectDfltPropName( SbxObject* pObj )
148 {
149     SbUnoObject* pUnoObj = dynamic_cast<SbUnoObject*>( pObj );
150     if ( pUnoObj )
151     {
152         OUString sDfltPropName;
153 
154         if ( SbUnoObject::getDefaultPropName( pUnoObj, sDfltPropName ) )
155         {
156             pUnoObj->SetDfltProperty( sDfltPropName );
157         }
158     }
159 }
160 
161 // save CoreReflection statically
162 static Reference< XIdlReflection > getCoreReflection_Impl()
163 {
164     return css::reflection::theCoreReflection::get(
165         comphelper::getProcessComponentContext());
166 }
167 
168 // save CoreReflection statically
169 static Reference< XHierarchicalNameAccess > const & getCoreReflection_HierarchicalNameAccess_Impl()
170 {
171     static Reference< XHierarchicalNameAccess > xCoreReflection_HierarchicalNameAccess;
172 
173     if( !xCoreReflection_HierarchicalNameAccess.is() )
174     {
175         Reference< XIdlReflection > xCoreReflection = getCoreReflection_Impl();
176         if( xCoreReflection.is() )
177         {
178             xCoreReflection_HierarchicalNameAccess =
179                 Reference< XHierarchicalNameAccess >( xCoreReflection, UNO_QUERY );
180         }
181     }
182     return xCoreReflection_HierarchicalNameAccess;
183 }
184 
185 // Hold TypeProvider statically
186 static Reference< XHierarchicalNameAccess > const & getTypeProvider_Impl()
187 {
188     static Reference< XHierarchicalNameAccess > xAccess;
189 
190     // Do we have already CoreReflection; if not obtain it
191     if( !xAccess.is() )
192     {
193         Reference< XComponentContext > xContext(
194             comphelper::getProcessComponentContext() );
195         if( xContext.is() )
196         {
197             xContext->getValueByName(
198                 "/singletons/com.sun.star.reflection.theTypeDescriptionManager" )
199                     >>= xAccess;
200             OSL_ENSURE( xAccess.is(), "### TypeDescriptionManager singleton not accessible!?" );
201         }
202         if( !xAccess.is() )
203         {
204             throw DeploymentException(
205                     "/singletons/com.sun.star.reflection.theTypeDescriptionManager singleton not accessible" );
206         }
207     }
208     return xAccess;
209 }
210 
211 // Hold TypeConverter statically
212 static Reference< XTypeConverter > const & getTypeConverter_Impl()
213 {
214     static Reference< XTypeConverter > xTypeConverter;
215 
216     // Do we have already CoreReflection; if not obtain it
217     if( !xTypeConverter.is() )
218     {
219         Reference< XComponentContext > xContext(
220             comphelper::getProcessComponentContext() );
221         if( xContext.is() )
222         {
223             xTypeConverter = Converter::create(xContext);
224         }
225         if( !xTypeConverter.is() )
226         {
227             throw DeploymentException(
228                 "com.sun.star.script.Converter service not accessible" );
229         }
230     }
231     return xTypeConverter;
232 }
233 
234 
235 // #111851 factory function to create an OLE object
236 SbUnoObject* createOLEObject_Impl( const OUString& aType )
237 {
238     static Reference< XMultiServiceFactory > xOLEFactory;
239     static bool bNeedsInit = true;
240 
241     if( bNeedsInit )
242     {
243         bNeedsInit = false;
244 
245         Reference< XComponentContext > xContext( comphelper::getProcessComponentContext() );
246         if( xContext.is() )
247         {
248             Reference<XMultiComponentFactory> xSMgr = xContext->getServiceManager();
249             xOLEFactory.set(
250                 xSMgr->createInstanceWithContext( "com.sun.star.bridge.OleObjectFactory", xContext ),
251                 UNO_QUERY );
252         }
253     }
254 
255     SbUnoObject* pUnoObj = nullptr;
256     if( xOLEFactory.is() )
257     {
258         // some type names available in VBA can not be directly used in COM
259         OUString aOLEType = aType;
260         if ( aOLEType == "SAXXMLReader30" )
261         {
262             aOLEType = "Msxml2.SAXXMLReader.3.0";
263         }
264         Reference< XInterface > xOLEObject = xOLEFactory->createInstance( aOLEType );
265         if( xOLEObject.is() )
266         {
267             pUnoObj = new SbUnoObject( aType, Any(xOLEObject) );
268             OUString sDfltPropName;
269 
270             if ( SbUnoObject::getDefaultPropName( pUnoObj, sDfltPropName ) )
271                 pUnoObj->SetDfltProperty( sDfltPropName );
272         }
273     }
274     return pUnoObj;
275 }
276 
277 
278 namespace
279 {
280     void lcl_indent( OUStringBuffer& _inout_rBuffer, sal_Int32 _nLevel )
281     {
282         while ( _nLevel-- > 0 )
283         {
284             _inout_rBuffer.append( "  " );
285         }
286     }
287 }
288 
289 static void implAppendExceptionMsg( OUStringBuffer& _inout_rBuffer, const Exception& _e, const OUString& _rExceptionType, sal_Int32 _nLevel )
290 {
291     _inout_rBuffer.append( "\n" );
292     lcl_indent( _inout_rBuffer, _nLevel );
293     _inout_rBuffer.append( "Type: " );
294 
295     if ( _rExceptionType.isEmpty() )
296         _inout_rBuffer.append( "Unknown" );
297     else
298         _inout_rBuffer.append( _rExceptionType );
299 
300     _inout_rBuffer.append( "\n" );
301     lcl_indent( _inout_rBuffer, _nLevel );
302     _inout_rBuffer.append( "Message: " );
303     _inout_rBuffer.append( _e.Message );
304 
305 }
306 
307 // construct an error message for the exception
308 static OUString implGetExceptionMsg( const Exception& e, const OUString& aExceptionType_ )
309 {
310     OUStringBuffer aMessageBuf;
311     implAppendExceptionMsg( aMessageBuf, e, aExceptionType_, 0 );
312     return aMessageBuf.makeStringAndClear();
313 }
314 
315 static OUString implGetExceptionMsg( const Any& _rCaughtException )
316 {
317     auto e = o3tl::tryAccess<Exception>(_rCaughtException);
318     OSL_PRECOND( e, "implGetExceptionMsg: illegal argument!" );
319     if ( !e )
320     {
321         return OUString();
322     }
323     return implGetExceptionMsg( *e, _rCaughtException.getValueTypeName() );
324 }
325 
326 static Any convertAny( const Any& rVal, const Type& aDestType )
327 {
328     Any aConvertedVal;
329     const Reference< XTypeConverter >& xConverter = getTypeConverter_Impl();
330     try
331     {
332         aConvertedVal = xConverter->convertTo( rVal, aDestType );
333     }
334     catch( const IllegalArgumentException& )
335     {
336         StarBASIC::Error( ERRCODE_BASIC_EXCEPTION,
337             implGetExceptionMsg( ::cppu::getCaughtException() ) );
338         return aConvertedVal;
339     }
340     catch( const CannotConvertException& e2 )
341     {
342         StarBASIC::Error( ERRCODE_BASIC_EXCEPTION,
343                           implGetExceptionMsg( e2, "com.sun.star.lang.IllegalArgumentException" ) );
344         return aConvertedVal;
345     }
346     return aConvertedVal;
347 }
348 
349 
350 // #105565 Special Object to wrap a strongly typed Uno Any
351 
352 
353 // TODO: source out later
354 static Reference<XIdlClass> TypeToIdlClass( const Type& rType )
355 {
356     return getCoreReflection_Impl()->forName(rType.getTypeName());
357 }
358 
359 // Exception type unknown
360 template< class EXCEPTION >
361 static OUString implGetExceptionMsg( const EXCEPTION& e )
362 {
363     return implGetExceptionMsg( e, cppu::UnoType<decltype(e)>::get().getTypeName() );
364 }
365 
366 static void implHandleBasicErrorException( BasicErrorException const & e )
367 {
368     ErrCode nError = StarBASIC::GetSfxFromVBError( static_cast<sal_uInt16>(e.ErrorCode) );
369     StarBASIC::Error( nError, e.ErrorMessageArgument );
370 }
371 
372 static void implHandleWrappedTargetException( const Any& _rWrappedTargetException )
373 {
374     Any aExamine( _rWrappedTargetException );
375 
376     // completely strip the first InvocationTargetException, its error message isn't of any
377     // interest to the user, it just says something like "invoking the UNO method went wrong.".
378     InvocationTargetException aInvocationError;
379     if ( aExamine >>= aInvocationError )
380         aExamine = aInvocationError.TargetException;
381 
382     BasicErrorException aBasicError;
383 
384     ErrCode nError( ERRCODE_BASIC_EXCEPTION );
385     OUStringBuffer aMessageBuf;
386 
387     // strip any other WrappedTargetException instances, but this time preserve the error messages.
388     WrappedTargetException aWrapped;
389     sal_Int32 nLevel = 0;
390     while ( aExamine >>= aWrapped )
391     {
392         // special handling for BasicErrorException errors
393         if ( aWrapped.TargetException >>= aBasicError )
394         {
395             nError = StarBASIC::GetSfxFromVBError( static_cast<sal_uInt16>(aBasicError.ErrorCode) );
396             aMessageBuf.append( aBasicError.ErrorMessageArgument );
397             aExamine.clear();
398             break;
399         }
400 
401         // append this round's message
402         implAppendExceptionMsg( aMessageBuf, aWrapped, aExamine.getValueTypeName(), nLevel );
403         if ( aWrapped.TargetException.getValueTypeClass() == TypeClass_EXCEPTION )
404             // there is a next chain element
405             aMessageBuf.append( "\nTargetException:" );
406 
407         // next round
408         aExamine = aWrapped.TargetException;
409         ++nLevel;
410     }
411 
412     if ( auto e = o3tl::tryAccess<Exception>(aExamine) )
413     {
414         // the last element in the chain is still an exception, but no WrappedTargetException
415         implAppendExceptionMsg( aMessageBuf, *e, aExamine.getValueTypeName(), nLevel );
416     }
417 
418     StarBASIC::Error( nError, aMessageBuf.makeStringAndClear() );
419 }
420 
421 static void implHandleAnyException( const Any& _rCaughtException )
422 {
423     BasicErrorException aBasicError;
424     WrappedTargetException aWrappedError;
425 
426     if ( _rCaughtException >>= aBasicError )
427     {
428         implHandleBasicErrorException( aBasicError );
429     }
430     else if ( _rCaughtException >>= aWrappedError )
431     {
432         implHandleWrappedTargetException( _rCaughtException );
433     }
434     else
435     {
436         StarBASIC::Error( ERRCODE_BASIC_EXCEPTION, implGetExceptionMsg( _rCaughtException ) );
437     }
438 }
439 
440 // NativeObjectWrapper handling
441 struct ObjectItem
442 {
443     SbxObjectRef    m_xNativeObj;
444 
445     explicit ObjectItem( SbxObject* pNativeObj )
446         : m_xNativeObj( pNativeObj )
447     {}
448 };
449 
450 typedef std::vector< ObjectItem > NativeObjectWrapperVector;
451 class GaNativeObjectWrapperVector : public rtl::Static<NativeObjectWrapperVector, GaNativeObjectWrapperVector> {};
452 
453 void clearNativeObjectWrapperVector()
454 {
455     GaNativeObjectWrapperVector::get().clear();
456 }
457 
458 static sal_uInt32 lcl_registerNativeObjectWrapper( SbxObject* pNativeObj )
459 {
460     NativeObjectWrapperVector &rNativeObjectWrapperVector = GaNativeObjectWrapperVector::get();
461     sal_uInt32 nIndex = rNativeObjectWrapperVector.size();
462     rNativeObjectWrapperVector.emplace_back( pNativeObj );
463     return nIndex;
464 }
465 
466 static SbxObject* lcl_getNativeObject( sal_uInt32 nIndex )
467 {
468     SbxObjectRef xRetObj;
469     NativeObjectWrapperVector &rNativeObjectWrapperVector = GaNativeObjectWrapperVector::get();
470     if( nIndex < rNativeObjectWrapperVector.size() )
471     {
472         ObjectItem& rItem = rNativeObjectWrapperVector[ nIndex ];
473         xRetObj = rItem.m_xNativeObj;
474     }
475     return xRetObj.get();
476 }
477 
478 // convert from Uno to Sbx
479 static SbxDataType unoToSbxType( TypeClass eType )
480 {
481     SbxDataType eRetType = SbxVOID;
482 
483     switch( eType )
484     {
485         case TypeClass_INTERFACE:
486         case TypeClass_TYPE:
487         case TypeClass_STRUCT:
488         case TypeClass_EXCEPTION:       eRetType = SbxOBJECT;   break;
489 
490         case TypeClass_ENUM:            eRetType = SbxLONG;     break;
491         case TypeClass_SEQUENCE:
492             eRetType = SbxDataType( SbxOBJECT | SbxARRAY );
493             break;
494 
495 
496         case TypeClass_ANY:             eRetType = SbxVARIANT;  break;
497         case TypeClass_BOOLEAN:         eRetType = SbxBOOL;     break;
498         case TypeClass_CHAR:            eRetType = SbxCHAR;     break;
499         case TypeClass_STRING:          eRetType = SbxSTRING;   break;
500         case TypeClass_FLOAT:           eRetType = SbxSINGLE;   break;
501         case TypeClass_DOUBLE:          eRetType = SbxDOUBLE;   break;
502         case TypeClass_BYTE:            eRetType = SbxINTEGER;  break;
503         case TypeClass_SHORT:           eRetType = SbxINTEGER;  break;
504         case TypeClass_LONG:            eRetType = SbxLONG;     break;
505         case TypeClass_HYPER:           eRetType = SbxSALINT64; break;
506         case TypeClass_UNSIGNED_SHORT:  eRetType = SbxUSHORT;   break;
507         case TypeClass_UNSIGNED_LONG:   eRetType = SbxULONG;    break;
508         case TypeClass_UNSIGNED_HYPER:  eRetType = SbxSALUINT64;break;
509         default: break;
510     }
511     return eRetType;
512 }
513 
514 static SbxDataType unoToSbxType( const Reference< XIdlClass >& xIdlClass )
515 {
516     SbxDataType eRetType = SbxVOID;
517     if( xIdlClass.is() )
518     {
519         TypeClass eType = xIdlClass->getTypeClass();
520         eRetType = unoToSbxType( eType );
521     }
522     return eRetType;
523 }
524 
525 static void implSequenceToMultiDimArray( SbxDimArray*& pArray, Sequence< sal_Int32 >& indices, Sequence< sal_Int32 >& sizes, const Any& aValue, sal_Int32 dimension, bool bIsZeroIndex, Type const * pType )
526 {
527     const Type& aType = aValue.getValueType();
528     TypeClass eTypeClass = aType.getTypeClass();
529 
530     sal_Int32 dimCopy = dimension;
531 
532     if ( eTypeClass == TypeClass_SEQUENCE )
533     {
534         Reference< XIdlClass > xIdlTargetClass = TypeToIdlClass( aType );
535         Reference< XIdlArray > xIdlArray = xIdlTargetClass->getArray();
536         typelib_TypeDescription * pTD = nullptr;
537         aType.getDescription( &pTD );
538         Type aElementType( reinterpret_cast<typelib_IndirectTypeDescription *>(pTD)->pType );
539         ::typelib_typedescription_release( pTD );
540 
541         sal_Int32 nLen = xIdlArray->getLen( aValue );
542         for ( sal_Int32 index = 0; index < nLen; ++index )
543         {
544             Any aElementAny = xIdlArray->get( aValue, static_cast<sal_uInt32>(index) );
545             // This detects the dimension were currently processing
546             if ( dimCopy == dimension )
547             {
548                 ++dimCopy;
549                 if ( sizes.getLength() < dimCopy )
550                 {
551                     sizes.realloc( sizes.getLength() + 1 );
552                     sizes[ sizes.getLength() - 1 ] = nLen;
553                     indices.realloc( indices.getLength() + 1 );
554                 }
555             }
556 
557             if ( bIsZeroIndex )
558                 indices[ dimCopy - 1 ] = index;
559             else
560                 indices[ dimCopy - 1] = index + 1;
561 
562             implSequenceToMultiDimArray( pArray, indices, sizes, aElementAny, dimCopy, bIsZeroIndex, &aElementType );
563         }
564 
565     }
566     else
567     {
568         if ( indices.getLength() < 1 )
569         {
570             // Should never ever get here ( indices.getLength()
571             // should equal number of dimensions in the array )
572             // And that should at least be 1 !
573             // #QUESTION is there a better error?
574             StarBASIC::Error( ERRCODE_BASIC_INVALID_OBJECT );
575             return;
576         }
577 
578         SbxDataType eSbxElementType = unoToSbxType( pType ? pType->getTypeClass() : aValue.getValueTypeClass() );
579         if ( !pArray )
580         {
581             pArray = new SbxDimArray( eSbxElementType );
582             sal_Int32 nIndexLen = indices.getLength();
583 
584             // Dimension the array
585             for ( sal_Int32 index = 0; index < nIndexLen; ++index )
586             {
587                 if ( bIsZeroIndex )
588                     pArray->unoAddDim32( 0, sizes[ index ] - 1);
589                 else
590                     pArray->unoAddDim32( 1, sizes[ index ] );
591 
592             }
593         }
594 
595         if ( pArray )
596         {
597             auto xVar = tools::make_ref<SbxVariable>( eSbxElementType );
598             unoToSbxValue( xVar.get(), aValue );
599 
600             sal_Int32* pIndices = indices.getArray();
601             pArray->Put32(  xVar.get(), pIndices );
602 
603         }
604     }
605 }
606 
607 void unoToSbxValue( SbxVariable* pVar, const Any& aValue )
608 {
609     const Type& aType = aValue.getValueType();
610     TypeClass eTypeClass = aType.getTypeClass();
611     switch( eTypeClass )
612     {
613         case TypeClass_TYPE:
614         {
615             // Map Type to IdlClass
616             Type aType_;
617             aValue >>= aType_;
618             Reference<XIdlClass> xClass = TypeToIdlClass( aType_ );
619             Any aClassAny;
620             aClassAny <<= xClass;
621 
622             // instantiate SbUnoObject
623             SbUnoObject* pSbUnoObject = new SbUnoObject( OUString(), aClassAny );
624             SbxObjectRef xWrapper = static_cast<SbxObject*>(pSbUnoObject);
625 
626             // If the object is invalid deliver null
627             if( !pSbUnoObject->getUnoAny().hasValue() )
628             {
629                 pVar->PutObject( nullptr );
630             }
631             else
632             {
633                 pVar->PutObject( xWrapper.get() );
634             }
635         }
636         break;
637         // Interfaces and Structs must be wrapped in a SbUnoObject
638         case TypeClass_INTERFACE:
639         case TypeClass_STRUCT:
640         case TypeClass_EXCEPTION:
641         {
642             if( eTypeClass == TypeClass_STRUCT )
643             {
644                 ArrayWrapper aWrap;
645                 NativeObjectWrapper aNativeObjectWrapper;
646                 if ( aValue >>= aWrap )
647                 {
648                     SbxDimArray* pArray = nullptr;
649                     Sequence< sal_Int32 > indices;
650                     Sequence< sal_Int32 > sizes;
651                     implSequenceToMultiDimArray( pArray, indices, sizes, aWrap.Array, /*dimension*/0, aWrap.IsZeroIndex, nullptr );
652                     if ( pArray )
653                     {
654                         SbxDimArrayRef xArray = pArray;
655                         SbxFlagBits nFlags = pVar->GetFlags();
656                         pVar->ResetFlag( SbxFlagBits::Fixed );
657                         pVar->PutObject( xArray.get() );
658                         pVar->SetFlags( nFlags );
659                     }
660                     else
661                         pVar->PutEmpty();
662                     break;
663                 }
664                 else if ( aValue >>= aNativeObjectWrapper )
665                 {
666                     sal_uInt32 nIndex = 0;
667                     if( aNativeObjectWrapper.ObjectId >>= nIndex )
668                     {
669                         SbxObject* pObj = lcl_getNativeObject( nIndex );
670                         pVar->PutObject( pObj );
671                     }
672                     else
673                         pVar->PutEmpty();
674                     break;
675                 }
676                 else
677                 {
678                     SbiInstance* pInst = GetSbData()->pInst;
679                     if( pInst && pInst->IsCompatibility() )
680                     {
681                         oleautomation::Date aDate;
682                         if( aValue >>= aDate )
683                         {
684                             pVar->PutDate( aDate.Value );
685                             break;
686                         }
687                         else
688                         {
689                             oleautomation::Decimal aDecimal;
690                             if( aValue >>= aDecimal )
691                             {
692                                 pVar->PutDecimal( aDecimal );
693                                 break;
694                             }
695                             else
696                             {
697                                 oleautomation::Currency aCurrency;
698                                 if( aValue >>= aCurrency )
699                                 {
700                                     pVar->PutCurrency( aCurrency.Value );
701                                     break;
702                                 }
703                             }
704                         }
705                     }
706                 }
707             }
708             // instantiate a SbUnoObject
709             SbUnoObject* pSbUnoObject = new SbUnoObject( OUString(), aValue );
710             //If this is called externally e.g. from the scripting
711             //framework then there is no 'active' runtime the default property will not be set up
712             //only a vba object will have XDefaultProp set anyway so... this
713             //test seems a bit of overkill
714             //if ( SbiRuntime::isVBAEnabled() )
715             {
716                 OUString sDfltPropName;
717 
718                 if ( SbUnoObject::getDefaultPropName( pSbUnoObject, sDfltPropName ) )
719                 {
720                     pSbUnoObject->SetDfltProperty( sDfltPropName );
721                 }
722             }
723             SbxObjectRef xWrapper = static_cast<SbxObject*>(pSbUnoObject);
724 
725             // If the object is invalid deliver null
726             if( !pSbUnoObject->getUnoAny().hasValue() )
727             {
728                 pVar->PutObject( nullptr );
729             }
730             else
731             {
732                 pVar->PutObject( xWrapper.get() );
733             }
734         }
735         break;
736 
737 
738         case TypeClass_ENUM:
739         {
740             sal_Int32 nEnum = 0;
741             enum2int( nEnum, aValue );
742             pVar->PutLong( nEnum );
743         }
744             break;
745 
746         case TypeClass_SEQUENCE:
747         {
748             Reference< XIdlClass > xIdlTargetClass = TypeToIdlClass( aType );
749             Reference< XIdlArray > xIdlArray = xIdlTargetClass->getArray();
750             sal_Int32 i, nLen = xIdlArray->getLen( aValue );
751 
752             typelib_TypeDescription * pTD = nullptr;
753             aType.getDescription( &pTD );
754             OSL_ASSERT( pTD && pTD->eTypeClass == typelib_TypeClass_SEQUENCE );
755             Type aElementType( reinterpret_cast<typelib_IndirectTypeDescription *>(pTD)->pType );
756             ::typelib_typedescription_release( pTD );
757 
758             // build an Array in Basic
759             SbxDimArrayRef xArray;
760             SbxDataType eSbxElementType = unoToSbxType( aElementType.getTypeClass() );
761             xArray = new SbxDimArray( eSbxElementType );
762             if( nLen > 0 )
763             {
764                 xArray->unoAddDim32( 0, nLen - 1 );
765 
766                 // register the elements as variables
767                 for( i = 0 ; i < nLen ; i++ )
768                 {
769                     // convert elements
770                     Any aElementAny = xIdlArray->get( aValue, static_cast<sal_uInt32>(i) );
771                     auto xVar = tools::make_ref<SbxVariable>( eSbxElementType );
772                     unoToSbxValue( xVar.get(), aElementAny );
773 
774                     // put into the Array
775                     xArray->Put32( xVar.get(), &i );
776                 }
777             }
778             else
779             {
780                 xArray->unoAddDim( 0, -1 );
781             }
782 
783             // return the Array
784             SbxFlagBits nFlags = pVar->GetFlags();
785             pVar->ResetFlag( SbxFlagBits::Fixed );
786             pVar->PutObject( xArray.get() );
787             pVar->SetFlags( nFlags );
788 
789         }
790         break;
791 
792 
793         case TypeClass_BOOLEAN:         pVar->PutBool( *o3tl::forceAccess<bool>(aValue) ); break;
794         case TypeClass_CHAR:
795         {
796             pVar->PutChar( *o3tl::forceAccess<sal_Unicode>(aValue) );
797             break;
798         }
799         case TypeClass_STRING:          { OUString val; aValue >>= val; pVar->PutString( val ); }  break;
800         case TypeClass_FLOAT:           { float val = 0; aValue >>= val; pVar->PutSingle( val ); } break;
801         case TypeClass_DOUBLE:          { double val = 0; aValue >>= val; pVar->PutDouble( val ); } break;
802         case TypeClass_BYTE:            { sal_Int8 val = 0; aValue >>= val; pVar->PutInteger( val ); } break;
803         case TypeClass_SHORT:           { sal_Int16 val = 0; aValue >>= val; pVar->PutInteger( val ); } break;
804         case TypeClass_LONG:            { sal_Int32 val = 0; aValue >>= val; pVar->PutLong( val ); } break;
805         case TypeClass_HYPER:           { sal_Int64 val = 0; aValue >>= val; pVar->PutInt64( val ); } break;
806         case TypeClass_UNSIGNED_SHORT:  { sal_uInt16 val = 0; aValue >>= val; pVar->PutUShort( val ); } break;
807         case TypeClass_UNSIGNED_LONG:   { sal_uInt32 val = 0; aValue >>= val; pVar->PutULong( val ); } break;
808         case TypeClass_UNSIGNED_HYPER:  { sal_uInt64 val = 0; aValue >>= val; pVar->PutUInt64( val ); } break;
809         default:                        pVar->PutEmpty();                       break;
810     }
811 }
812 
813 // Deliver the reflection for Sbx types
814 static Type getUnoTypeForSbxBaseType( SbxDataType eType )
815 {
816     Type aRetType = cppu::UnoType<void>::get();
817     switch( eType )
818     {
819         case SbxNULL:       aRetType = cppu::UnoType<XInterface>::get(); break;
820         case SbxINTEGER:    aRetType = cppu::UnoType<sal_Int16>::get(); break;
821         case SbxLONG:       aRetType = cppu::UnoType<sal_Int32>::get(); break;
822         case SbxSINGLE:     aRetType = cppu::UnoType<float>::get(); break;
823         case SbxDOUBLE:     aRetType = cppu::UnoType<double>::get(); break;
824         case SbxCURRENCY:   aRetType = cppu::UnoType<oleautomation::Currency>::get(); break;
825         case SbxDECIMAL:    aRetType = cppu::UnoType<oleautomation::Decimal>::get(); break;
826         case SbxDATE:       {
827                             SbiInstance* pInst = GetSbData()->pInst;
828                             if( pInst && pInst->IsCompatibility() )
829                                 aRetType = cppu::UnoType<double>::get();
830                             else
831                                 aRetType = cppu::UnoType<oleautomation::Date>::get();
832                             }
833                             break;
834         case SbxSTRING:     aRetType = cppu::UnoType<OUString>::get(); break;
835         case SbxBOOL:       aRetType = cppu::UnoType<sal_Bool>::get(); break;
836         case SbxVARIANT:    aRetType = cppu::UnoType<Any>::get(); break;
837         case SbxCHAR:       aRetType = cppu::UnoType<cppu::UnoCharType>::get(); break;
838         case SbxBYTE:       aRetType = cppu::UnoType<sal_Int8>::get(); break;
839         case SbxUSHORT:     aRetType = cppu::UnoType<cppu::UnoUnsignedShortType>::get(); break;
840         case SbxULONG:      aRetType = ::cppu::UnoType<sal_uInt32>::get(); break;
841         // map machine-dependent ones to long for consistency
842         case SbxINT:        aRetType = ::cppu::UnoType<sal_Int32>::get(); break;
843         case SbxUINT:       aRetType = ::cppu::UnoType<sal_uInt32>::get(); break;
844         default: break;
845     }
846     return aRetType;
847 }
848 
849 // Converting of Sbx to Uno without a know target class for TypeClass_ANY
850 static Type getUnoTypeForSbxValue( const SbxValue* pVal )
851 {
852     Type aRetType = cppu::UnoType<void>::get();
853     if( !pVal )
854         return aRetType;
855 
856     // convert SbxType to Uno
857     SbxDataType eBaseType = pVal->SbxValue::GetType();
858     if( eBaseType == SbxOBJECT )
859     {
860         SbxBaseRef xObj = pVal->GetObject();
861         if( !xObj.is() )
862         {
863             aRetType = cppu::UnoType<XInterface>::get();
864             return aRetType;
865         }
866 
867         if( auto pArray = dynamic_cast<SbxDimArray*>( xObj.get() ) )
868         {
869             short nDims = pArray->GetDims();
870             Type aElementType = getUnoTypeForSbxBaseType( static_cast<SbxDataType>(pArray->GetType() & 0xfff) );
871             TypeClass eElementTypeClass = aElementType.getTypeClass();
872 
873             // Normal case: One dimensional array
874             sal_Int32 nLower, nUpper;
875             if( nDims == 1 && pArray->GetDim32( 1, nLower, nUpper ) )
876             {
877                 if( eElementTypeClass == TypeClass_VOID || eElementTypeClass == TypeClass_ANY )
878                 {
879                     // If all elements of the arrays are from the same type, take
880                     // this one - otherwise the whole will be considered as Any-Sequence
881                     bool bNeedsInit = true;
882 
883                     for (sal_Int32 aIdx[1] = { nLower }; aIdx[0] <= nUpper; ++aIdx[0])
884                     {
885                         SbxVariableRef xVar = pArray->Get32(aIdx);
886                         Type aType = getUnoTypeForSbxValue( xVar.get() );
887                         if( bNeedsInit )
888                         {
889                             if( aType.getTypeClass() == TypeClass_VOID )
890                             {
891                                 // if only first element is void: different types  -> []any
892                                 // if all elements are void: []void is not allowed -> []any
893                                 aElementType = cppu::UnoType<Any>::get();
894                                 break;
895                             }
896                             aElementType = aType;
897                             bNeedsInit = false;
898                         }
899                         else if( aElementType != aType )
900                         {
901                             // different types -> AnySequence
902                             aElementType = cppu::UnoType<Any>::get();
903                             break;
904                         }
905                     }
906                 }
907 
908                 OUString aSeqTypeName = aSeqLevelStr + aElementType.getTypeName();
909                 aRetType = Type( TypeClass_SEQUENCE, aSeqTypeName );
910             }
911             // #i33795 Map also multi dimensional arrays to corresponding sequences
912             else if( nDims > 1 )
913             {
914                 if( eElementTypeClass == TypeClass_VOID || eElementTypeClass == TypeClass_ANY )
915                 {
916                     // For this check the array's dim structure does not matter
917                     sal_uInt32 nFlatArraySize = pArray->Count32();
918 
919                     bool bNeedsInit = true;
920                     for( sal_uInt32 i = 0 ; i < nFlatArraySize ; i++ )
921                     {
922                         SbxVariableRef xVar = pArray->SbxArray::Get32( i );
923                         Type aType = getUnoTypeForSbxValue( xVar.get() );
924                         if( bNeedsInit )
925                         {
926                             if( aType.getTypeClass() == TypeClass_VOID )
927                             {
928                                 // if only first element is void: different types  -> []any
929                                 // if all elements are void: []void is not allowed -> []any
930                                 aElementType = cppu::UnoType<Any>::get();
931                                 break;
932                             }
933                             aElementType = aType;
934                             bNeedsInit = false;
935                         }
936                         else if( aElementType != aType )
937                         {
938                             // different types -> AnySequence
939                             aElementType = cppu::UnoType<Any>::get();
940                             break;
941                         }
942                     }
943                 }
944 
945                 OUStringBuffer aSeqTypeName;
946                 for( short iDim = 0 ; iDim < nDims ; iDim++ )
947                 {
948                     aSeqTypeName.append(aSeqLevelStr);
949                 }
950                 aSeqTypeName.append(aElementType.getTypeName());
951                 aRetType = Type( TypeClass_SEQUENCE, aSeqTypeName.makeStringAndClear() );
952             }
953         }
954         // No array, but ...
955         else if( auto obj = dynamic_cast<SbUnoObject*>( xObj.get() ) )
956         {
957             aRetType = obj->getUnoAny().getValueType();
958         }
959         // SbUnoAnyObject?
960         else if( auto any = dynamic_cast<SbUnoAnyObject*>( xObj.get() ) )
961         {
962             aRetType = any->getValue().getValueType();
963         }
964         // Otherwise it is a No-Uno-Basic-Object -> default==deliver void
965     }
966     // No object, convert basic type
967     else
968     {
969         aRetType = getUnoTypeForSbxBaseType( eBaseType );
970     }
971     return aRetType;
972 }
973 
974 // converting of Sbx to Uno without known target class for TypeClass_ANY
975 static Any sbxToUnoValueImpl( const SbxValue* pVar, bool bBlockConversionToSmallestType = false )
976 {
977     SbxDataType eBaseType = pVar->SbxValue::GetType();
978     if( eBaseType == SbxOBJECT )
979     {
980         SbxBaseRef xObj = pVar->GetObject();
981         if( xObj.is() )
982         {
983             if( auto obj = dynamic_cast<SbUnoAnyObject*>( xObj.get() ) )
984                 return obj->getValue();
985             if( auto pClassModuleObj = dynamic_cast<SbClassModuleObject*>( xObj.get() ) )
986             {
987                 Any aRetAny;
988                 SbModule* pClassModule = pClassModuleObj->getClassModule();
989                 if( pClassModule->createCOMWrapperForIface( aRetAny, pClassModuleObj ) )
990                     return aRetAny;
991             }
992             if( dynamic_cast<const SbUnoObject*>( xObj.get() ) == nullptr )
993             {
994                 // Create NativeObjectWrapper to identify object in case of callbacks
995                 SbxObject* pObj = dynamic_cast<SbxObject*>( pVar->GetObject() );
996                 if( pObj != nullptr )
997                 {
998                     NativeObjectWrapper aNativeObjectWrapper;
999                     sal_uInt32 nIndex = lcl_registerNativeObjectWrapper( pObj );
1000                     aNativeObjectWrapper.ObjectId <<= nIndex;
1001                     Any aRetAny;
1002                     aRetAny <<= aNativeObjectWrapper;
1003                     return aRetAny;
1004                 }
1005             }
1006         }
1007     }
1008 
1009     Type aType = getUnoTypeForSbxValue( pVar );
1010     TypeClass eType = aType.getTypeClass();
1011 
1012     if( !bBlockConversionToSmallestType )
1013     {
1014         // #79615 Choose "smallest" represention for int values
1015         // because up cast is allowed, downcast not
1016         switch( eType )
1017         {
1018             case TypeClass_FLOAT:
1019             case TypeClass_DOUBLE:
1020             {
1021                 double d = pVar->GetDouble();
1022                 if( rtl::math::approxEqual(d, floor( d )) )
1023                 {
1024                     if( d >= -128 && d <= 127 )
1025                         aType = ::cppu::UnoType<sal_Int8>::get();
1026                     else if( d >= SbxMININT && d <= SbxMAXINT )
1027                         aType = ::cppu::UnoType<sal_Int16>::get();
1028                     else if( d >= -SbxMAXLNG && d <= SbxMAXLNG )
1029                         aType = ::cppu::UnoType<sal_Int32>::get();
1030                 }
1031                 break;
1032             }
1033             case TypeClass_SHORT:
1034             {
1035                 sal_Int16 n = pVar->GetInteger();
1036                 if( n >= -128 && n <= 127 )
1037                     aType = ::cppu::UnoType<sal_Int8>::get();
1038                 break;
1039             }
1040             case TypeClass_LONG:
1041             {
1042                 sal_Int32 n = pVar->GetLong();
1043                 if( n >= -128 && n <= 127 )
1044                     aType = ::cppu::UnoType<sal_Int8>::get();
1045                 else if( n >= SbxMININT && n <= SbxMAXINT )
1046                     aType = ::cppu::UnoType<sal_Int16>::get();
1047                 break;
1048             }
1049             case TypeClass_UNSIGNED_SHORT:
1050             {
1051                 sal_uInt16 n = pVar->GetUShort();
1052                 if( n <= 255 )
1053                     aType = cppu::UnoType<sal_uInt8>::get();
1054                 break;
1055             }
1056             case TypeClass_UNSIGNED_LONG:
1057             {
1058                 sal_uInt32 n = pVar->GetLong();
1059                 if( n <= 255 )
1060                     aType = cppu::UnoType<sal_uInt8>::get();
1061                 else if( n <= SbxMAXUINT )
1062                     aType = cppu::UnoType<cppu::UnoUnsignedShortType>::get();
1063                 break;
1064             }
1065             // TODO: need to add hyper types ?
1066             default: break;
1067         }
1068     }
1069 
1070     return sbxToUnoValue( pVar, aType );
1071 }
1072 
1073 
1074 // Helper function for StepREDIMP
1075 static Any implRekMultiDimArrayToSequence( SbxDimArray* pArray,
1076     const Type& aElemType, short nMaxDimIndex, short nActualDim,
1077     sal_Int32* pActualIndices, sal_Int32* pLowerBounds, sal_Int32* pUpperBounds )
1078 {
1079     sal_Int32 nSeqLevel = nMaxDimIndex - nActualDim + 1;
1080     OUStringBuffer aSeqTypeName;
1081     sal_Int32 i;
1082     for( i = 0 ; i < nSeqLevel ; i++ )
1083     {
1084         aSeqTypeName.append(aSeqLevelStr);
1085     }
1086     aSeqTypeName.append(aElemType.getTypeName());
1087     Type aSeqType( TypeClass_SEQUENCE, aSeqTypeName.makeStringAndClear() );
1088 
1089     // Create Sequence instance
1090     Any aRetVal;
1091     Reference< XIdlClass > xIdlTargetClass = TypeToIdlClass( aSeqType );
1092     xIdlTargetClass->createObject( aRetVal );
1093 
1094     // Alloc sequence according to array bounds
1095     sal_Int32 nUpper = pUpperBounds[nActualDim];
1096     sal_Int32 nLower = pLowerBounds[nActualDim];
1097     sal_Int32 nSeqSize = nUpper - nLower + 1;
1098     Reference< XIdlArray > xArray = xIdlTargetClass->getArray();
1099     xArray->realloc( aRetVal, nSeqSize );
1100 
1101     sal_Int32& ri = pActualIndices[nActualDim];
1102 
1103     for( ri = nLower,i = 0 ; ri <= nUpper ; ri++,i++ )
1104     {
1105         Any aElementVal;
1106 
1107         if( nActualDim < nMaxDimIndex )
1108         {
1109             aElementVal = implRekMultiDimArrayToSequence( pArray, aElemType,
1110                 nMaxDimIndex, nActualDim + 1, pActualIndices, pLowerBounds, pUpperBounds );
1111         }
1112         else
1113         {
1114             SbxVariable* pSource = pArray->Get32( pActualIndices );
1115             aElementVal = sbxToUnoValue( pSource, aElemType );
1116         }
1117 
1118         try
1119         {
1120             // transfer to the sequence
1121             xArray->set( aRetVal, i, aElementVal );
1122         }
1123         catch( const IllegalArgumentException& )
1124         {
1125             StarBASIC::Error( ERRCODE_BASIC_EXCEPTION,
1126                 implGetExceptionMsg( ::cppu::getCaughtException() ) );
1127         }
1128         catch (const IndexOutOfBoundsException&)
1129         {
1130             StarBASIC::Error( ERRCODE_BASIC_OUT_OF_RANGE );
1131         }
1132     }
1133     return aRetVal;
1134 }
1135 
1136 // Map old interface
1137 Any sbxToUnoValue( const SbxValue* pVar )
1138 {
1139     return sbxToUnoValueImpl( pVar );
1140 }
1141 
1142 // function to find a global identifier in
1143 // the UnoScope and to wrap it for Sbx
1144 static bool implGetTypeByName( const OUString& rName, Type& rRetType )
1145 {
1146     bool bSuccess = false;
1147 
1148     const Reference< XHierarchicalNameAccess >& xTypeAccess = getTypeProvider_Impl();
1149     if( xTypeAccess->hasByHierarchicalName( rName ) )
1150     {
1151         Any aRet = xTypeAccess->getByHierarchicalName( rName );
1152         Reference< XTypeDescription > xTypeDesc;
1153         aRet >>= xTypeDesc;
1154 
1155         if( xTypeDesc.is() )
1156         {
1157             rRetType = Type( xTypeDesc->getTypeClass(), xTypeDesc->getName() );
1158             bSuccess = true;
1159         }
1160     }
1161     return bSuccess;
1162 }
1163 
1164 
1165 // converting of Sbx to Uno with known target class
1166 Any sbxToUnoValue( const SbxValue* pVar, const Type& rType, Property const * pUnoProperty )
1167 {
1168     Any aRetVal;
1169 
1170     // #94560 No conversion of empty/void for MAYBE_VOID properties
1171     if( pUnoProperty && pUnoProperty->Attributes & PropertyAttribute::MAYBEVOID )
1172     {
1173         if( pVar->IsEmpty() )
1174             return aRetVal;
1175     }
1176 
1177     SbxDataType eBaseType = pVar->SbxValue::GetType();
1178     if( eBaseType == SbxOBJECT )
1179     {
1180         SbxBaseRef xObj = pVar->GetObject();
1181         if ( auto obj = dynamic_cast<SbUnoAnyObject*>( xObj.get() ) )
1182         {
1183             return obj->getValue();
1184         }
1185     }
1186 
1187     TypeClass eType = rType.getTypeClass();
1188     switch( eType )
1189     {
1190         case TypeClass_INTERFACE:
1191         case TypeClass_STRUCT:
1192         case TypeClass_EXCEPTION:
1193         {
1194             Reference< XIdlClass > xIdlTargetClass = TypeToIdlClass( rType );
1195 
1196             // null reference?
1197             if( pVar->IsNull() && eType == TypeClass_INTERFACE )
1198             {
1199                 Reference< XInterface > xRef;
1200                 OUString aClassName = xIdlTargetClass->getName();
1201                 Type aClassType( xIdlTargetClass->getTypeClass(), aClassName );
1202                 aRetVal.setValue( &xRef, aClassType );
1203             }
1204             else
1205             {
1206                 // #112368 Special conversion for Decimal, Currency and Date
1207                 if( eType == TypeClass_STRUCT )
1208                 {
1209                     SbiInstance* pInst = GetSbData()->pInst;
1210                     if( pInst && pInst->IsCompatibility() )
1211                     {
1212                         if( rType == cppu::UnoType<oleautomation::Decimal>::get())
1213                         {
1214                             oleautomation::Decimal aDecimal;
1215                             pVar->fillAutomationDecimal( aDecimal );
1216                             aRetVal <<= aDecimal;
1217                             break;
1218                         }
1219                         else if( rType == cppu::UnoType<oleautomation::Currency>::get())
1220                         {
1221                             // assumes per previous code that ole Currency is Int64
1222                             aRetVal <<= pVar->GetInt64();
1223                             break;
1224                         }
1225                         else if( rType == cppu::UnoType<oleautomation::Date>::get())
1226                         {
1227                             oleautomation::Date aDate;
1228                             aDate.Value = pVar->GetDate();
1229                             aRetVal <<= aDate;
1230                             break;
1231                         }
1232                     }
1233                 }
1234 
1235                 SbxBaseRef pObj = pVar->GetObject();
1236                 if( auto obj = dynamic_cast<SbUnoObject*>( pObj.get() ) )
1237                 {
1238                     aRetVal = obj->getUnoAny();
1239                 }
1240                 else if( auto structRef = dynamic_cast<SbUnoStructRefObject*>( pObj.get() ) )
1241                 {
1242                     aRetVal = structRef->getUnoAny();
1243                 }
1244                 else
1245                 {
1246                     // null object -> null XInterface
1247                     Reference<XInterface> xInt;
1248                     aRetVal <<= xInt;
1249                 }
1250             }
1251         }
1252         break;
1253 
1254         case TypeClass_TYPE:
1255         {
1256             if( eBaseType == SbxOBJECT )
1257             {
1258                 // XIdlClass?
1259                 Reference< XIdlClass > xIdlClass;
1260 
1261                 SbxBaseRef pObj = pVar->GetObject();
1262                 if( auto obj = dynamic_cast<SbUnoObject*>( pObj.get() ) )
1263                 {
1264                     Any aUnoAny = obj->getUnoAny();
1265                     aUnoAny >>= xIdlClass;
1266                 }
1267 
1268                 if( xIdlClass.is() )
1269                 {
1270                     OUString aClassName = xIdlClass->getName();
1271                     Type aType( xIdlClass->getTypeClass(), aClassName );
1272                     aRetVal <<= aType;
1273                 }
1274             }
1275             else if( eBaseType == SbxSTRING )
1276             {
1277                 OUString aTypeName = pVar->GetOUString();
1278                 Type aType;
1279                 bool bSuccess = implGetTypeByName( aTypeName, aType );
1280                 if( bSuccess )
1281                 {
1282                     aRetVal <<= aType;
1283                 }
1284             }
1285         }
1286         break;
1287 
1288 
1289         case TypeClass_ENUM:
1290         {
1291             aRetVal = int2enum( pVar->GetLong(), rType );
1292         }
1293         break;
1294 
1295         case TypeClass_SEQUENCE:
1296         {
1297             SbxBaseRef xObj = pVar->GetObject();
1298             if( auto pArray = dynamic_cast<SbxDimArray*>( xObj.get() ) )
1299             {
1300                 short nDims = pArray->GetDims();
1301 
1302                 // Normal case: One dimensional array
1303                 sal_Int32 nLower, nUpper;
1304                 if( nDims == 1 && pArray->GetDim32( 1, nLower, nUpper ) )
1305                 {
1306                     sal_Int32 nSeqSize = nUpper - nLower + 1;
1307 
1308                     // create the instance of the required sequence
1309                     Reference< XIdlClass > xIdlTargetClass = TypeToIdlClass( rType );
1310                     xIdlTargetClass->createObject( aRetVal );
1311                     Reference< XIdlArray > xArray = xIdlTargetClass->getArray();
1312                     xArray->realloc( aRetVal, nSeqSize );
1313 
1314                     // Element-Type
1315                     OUString aClassName = xIdlTargetClass->getName();
1316                     typelib_TypeDescription * pSeqTD = nullptr;
1317                     typelib_typedescription_getByName( &pSeqTD, aClassName.pData );
1318                     OSL_ASSERT( pSeqTD );
1319                     Type aElemType( reinterpret_cast<typelib_IndirectTypeDescription *>(pSeqTD)->pType );
1320 
1321                     // convert all array member and register them
1322                     sal_Int32 aIdx[1];
1323                     aIdx[0] = nLower;
1324                     for (sal_Int32 i = 0 ; i < nSeqSize; ++i, ++aIdx[0])
1325                     {
1326                         SbxVariableRef xVar = pArray->Get32(aIdx);
1327 
1328                         // Convert the value of Sbx to Uno
1329                         Any aAnyValue = sbxToUnoValue( xVar.get(), aElemType );
1330 
1331                         try
1332                         {
1333                             // insert in the sequence
1334                             xArray->set( aRetVal, i, aAnyValue );
1335                         }
1336                         catch( const IllegalArgumentException& )
1337                         {
1338                             StarBASIC::Error( ERRCODE_BASIC_EXCEPTION,
1339                                 implGetExceptionMsg( ::cppu::getCaughtException() ) );
1340                         }
1341                         catch (const IndexOutOfBoundsException&)
1342                         {
1343                             StarBASIC::Error( ERRCODE_BASIC_OUT_OF_RANGE );
1344                         }
1345                     }
1346                 }
1347                 // #i33795 Map also multi dimensional arrays to corresponding sequences
1348                 else if( nDims > 1 )
1349                 {
1350                     // Element-Type
1351                     typelib_TypeDescription * pSeqTD = nullptr;
1352                     Type aCurType( rType );
1353                     sal_Int32 nSeqLevel = 0;
1354                     Type aElemType;
1355                     do
1356                     {
1357                         OUString aTypeName = aCurType.getTypeName();
1358                         typelib_typedescription_getByName( &pSeqTD, aTypeName.pData );
1359                         OSL_ASSERT( pSeqTD );
1360                         if( pSeqTD->eTypeClass == typelib_TypeClass_SEQUENCE )
1361                         {
1362                             aCurType = Type( reinterpret_cast<typelib_IndirectTypeDescription *>(pSeqTD)->pType );
1363                             nSeqLevel++;
1364                         }
1365                         else
1366                         {
1367                             aElemType = aCurType;
1368                             break;
1369                         }
1370                     }
1371                     while( true );
1372 
1373                     if( nSeqLevel == nDims )
1374                     {
1375                         std::unique_ptr<sal_Int32[]> pLowerBounds(new sal_Int32[nDims]);
1376                         std::unique_ptr<sal_Int32[]> pUpperBounds(new sal_Int32[nDims]);
1377                         std::unique_ptr<sal_Int32[]> pActualIndices(new sal_Int32[nDims]);
1378                         for( short i = 1 ; i <= nDims ; i++ )
1379                         {
1380                             sal_Int32 lBound, uBound;
1381                             pArray->GetDim32( i, lBound, uBound );
1382 
1383                             short j = i - 1;
1384                             pActualIndices[j] = pLowerBounds[j] = lBound;
1385                             pUpperBounds[j] = uBound;
1386                         }
1387 
1388                         aRetVal = implRekMultiDimArrayToSequence( pArray, aElemType,
1389                             nDims - 1, 0, pActualIndices.get(), pLowerBounds.get(), pUpperBounds.get() );
1390                     }
1391                 }
1392             }
1393         }
1394         break;
1395 
1396 
1397         // for Any use the class independent converting routine
1398         case TypeClass_ANY:
1399         {
1400             aRetVal = sbxToUnoValueImpl( pVar );
1401         }
1402         break;
1403 
1404         case TypeClass_BOOLEAN:
1405         {
1406             aRetVal <<= pVar->GetBool();
1407             break;
1408         }
1409         case TypeClass_CHAR:
1410         {
1411             aRetVal <<= pVar->GetChar();
1412             break;
1413         }
1414         case TypeClass_STRING:          aRetVal <<= pVar->GetOUString(); break;
1415         case TypeClass_FLOAT:           aRetVal <<= pVar->GetSingle(); break;
1416         case TypeClass_DOUBLE:          aRetVal <<= pVar->GetDouble(); break;
1417 
1418         case TypeClass_BYTE:
1419         {
1420             sal_Int16 nVal = pVar->GetInteger();
1421             bool bOverflow = false;
1422             if( nVal < -128 )
1423             {
1424                 bOverflow = true;
1425                 nVal = -128;
1426             }
1427             else if( nVal > 255 ) // 128..255 map to -128..-1
1428             {
1429                 bOverflow = true;
1430                 nVal = 127;
1431             }
1432             if( bOverflow )
1433                    StarBASIC::Error( ERRCODE_BASIC_MATH_OVERFLOW );
1434 
1435             sal_Int8 nByteVal = static_cast<sal_Int8>(nVal);
1436             aRetVal <<= nByteVal;
1437             break;
1438         }
1439         case TypeClass_SHORT:           aRetVal <<= pVar->GetInteger();  break;
1440         case TypeClass_LONG:            aRetVal <<= pVar->GetLong();     break;
1441         case TypeClass_HYPER:           aRetVal <<= pVar->GetInt64();    break;
1442         case TypeClass_UNSIGNED_SHORT:  aRetVal <<= pVar->GetUShort();  break;
1443         case TypeClass_UNSIGNED_LONG:   aRetVal <<= pVar->GetULong();   break;
1444         case TypeClass_UNSIGNED_HYPER:  aRetVal <<= pVar->GetUInt64();  break;
1445         default: break;
1446     }
1447 
1448     return aRetVal;
1449 }
1450 
1451 static void processAutomationParams( SbxArray* pParams, Sequence< Any >& args, sal_uInt32 nParamCount )
1452 {
1453     AutomationNamedArgsSbxArray* pArgNamesArray = dynamic_cast<AutomationNamedArgsSbxArray*>( pParams );
1454 
1455     args.realloc( nParamCount );
1456     Any* pAnyArgs = args.getArray();
1457     bool bBlockConversionToSmallestType = GetSbData()->pInst->IsCompatibility();
1458     sal_uInt32 i = 0;
1459     if( pArgNamesArray )
1460     {
1461         Sequence< OUString >& rNameSeq = pArgNamesArray->getNames();
1462         OUString* pNames = rNameSeq.getArray();
1463         Any aValAny;
1464         for( i = 0 ; i < nParamCount ; i++ )
1465         {
1466             sal_uInt16 iSbx = static_cast<sal_uInt16>(i+1);
1467 
1468             aValAny = sbxToUnoValueImpl( pParams->Get( iSbx ),
1469             bBlockConversionToSmallestType );
1470 
1471             OUString aParamName = pNames[iSbx];
1472             if( !aParamName.isEmpty() )
1473             {
1474                 oleautomation::NamedArgument aNamedArgument;
1475                 aNamedArgument.Name = aParamName;
1476                 aNamedArgument.Value = aValAny;
1477                 pAnyArgs[i] <<= aNamedArgument;
1478             }
1479             else
1480             {
1481                 pAnyArgs[i] = aValAny;
1482             }
1483         }
1484     }
1485     else
1486     {
1487         for( i = 0 ; i < nParamCount ; i++ )
1488         {
1489             pAnyArgs[i] = sbxToUnoValueImpl( pParams->Get( static_cast<sal_uInt16>(i+1) ),
1490             bBlockConversionToSmallestType );
1491         }
1492     }
1493 
1494 }
1495 enum class INVOKETYPE
1496 {
1497    GetProp = 0,
1498    Func
1499 };
1500 static Any invokeAutomationMethod( const OUString& Name, Sequence< Any > const & args, SbxArray* pParams, sal_uInt32 nParamCount, Reference< XInvocation > const & rxInvocation, INVOKETYPE invokeType )
1501 {
1502     Sequence< sal_Int16 > OutParamIndex;
1503     Sequence< Any > OutParam;
1504 
1505     Any aRetAny;
1506     switch( invokeType )
1507     {
1508         case INVOKETYPE::Func:
1509             aRetAny = rxInvocation->invoke( Name, args, OutParamIndex, OutParam );
1510             break;
1511         case INVOKETYPE::GetProp:
1512             {
1513                 Reference< XAutomationInvocation > xAutoInv( rxInvocation, UNO_QUERY );
1514                 aRetAny = xAutoInv->invokeGetProperty( Name, args, OutParamIndex, OutParam );
1515                 break;
1516             }
1517         default:
1518             assert(false); break;
1519 
1520     }
1521     const sal_Int16* pIndices = OutParamIndex.getConstArray();
1522     sal_uInt32 nLen = OutParamIndex.getLength();
1523     if( nLen )
1524     {
1525         const Any* pNewValues = OutParam.getConstArray();
1526         for( sal_uInt32 j = 0 ; j < nLen ; j++ )
1527         {
1528             sal_Int16 iTarget = pIndices[ j ];
1529             if( iTarget >= static_cast<sal_Int16>(nParamCount) )
1530                 break;
1531             unoToSbxValue( pParams->Get( static_cast<sal_uInt16>(j+1) ), pNewValues[ j ] );
1532         }
1533     }
1534     return aRetAny;
1535 }
1536 
1537 // Debugging help method to readout the imlemented interfaces of an object
1538 static OUString Impl_GetInterfaceInfo( const Reference< XInterface >& x, const Reference< XIdlClass >& xClass, sal_uInt16 nRekLevel )
1539 {
1540     Type aIfaceType = cppu::UnoType<XInterface>::get();
1541     static Reference< XIdlClass > xIfaceClass = TypeToIdlClass( aIfaceType );
1542 
1543     OUStringBuffer aRetStr;
1544     for( sal_uInt16 i = 0 ; i < nRekLevel ; i++ )
1545         aRetStr.append( "    " );
1546     aRetStr.append( xClass->getName() );
1547     OUString aClassName = xClass->getName();
1548     Type aClassType( xClass->getTypeClass(), aClassName );
1549 
1550     // checking if the interface is really supported
1551     if( !x->queryInterface( aClassType ).hasValue() )
1552     {
1553         aRetStr.append( " (ERROR: Not really supported!)\n" );
1554     }
1555     // Are there super interfaces?
1556     else
1557     {
1558         aRetStr.append( "\n" );
1559 
1560         // get the super interfaces
1561         Sequence< Reference< XIdlClass > > aSuperClassSeq = xClass->getSuperclasses();
1562         const Reference< XIdlClass >* pClasses = aSuperClassSeq.getConstArray();
1563         sal_uInt32 nSuperIfaceCount = aSuperClassSeq.getLength();
1564         for( sal_uInt32 j = 0 ; j < nSuperIfaceCount ; j++ )
1565         {
1566             const Reference< XIdlClass >& rxIfaceClass = pClasses[j];
1567             if( !rxIfaceClass->equals( xIfaceClass ) )
1568                 aRetStr.append( Impl_GetInterfaceInfo( x, rxIfaceClass, nRekLevel + 1 ) );
1569         }
1570     }
1571     return aRetStr.makeStringAndClear();
1572 }
1573 
1574 static OUString getDbgObjectNameImpl(SbUnoObject& rUnoObj)
1575 {
1576     OUString aName = rUnoObj.GetClassName();
1577     if( aName.isEmpty() )
1578     {
1579         Any aToInspectObj = rUnoObj.getUnoAny();
1580         Reference< XInterface > xObj(aToInspectObj, css::uno::UNO_QUERY);
1581         if( xObj.is() )
1582         {
1583             Reference< XServiceInfo > xServiceInfo( xObj, UNO_QUERY );
1584             if( xServiceInfo.is() )
1585                 aName = xServiceInfo->getImplementationName();
1586         }
1587     }
1588     return aName;
1589 }
1590 
1591 static OUString getDbgObjectName(SbUnoObject& rUnoObj)
1592 {
1593     OUString aName = getDbgObjectNameImpl(rUnoObj);
1594     if( aName.isEmpty() )
1595         aName += "Unknown";
1596 
1597     OUStringBuffer aRet;
1598     if( aName.getLength() > 20 )
1599     {
1600         aRet.append( "\n" );
1601     }
1602     aRet.append( "\"" );
1603     aRet.append( aName );
1604     aRet.append( "\":" );
1605     return aRet.makeStringAndClear();
1606 }
1607 
1608 OUString getBasicObjectTypeName( SbxObject* pObj )
1609 {
1610     if (pObj)
1611     {
1612         if (SbUnoObject* pUnoObj = dynamic_cast<SbUnoObject*>(pObj))
1613         {
1614             return getDbgObjectNameImpl(*pUnoObj);
1615         }
1616         else if (SbUnoStructRefObject* pUnoStructObj = dynamic_cast<SbUnoStructRefObject*>(pObj))
1617         {
1618             return pUnoStructObj->GetClassName();
1619         }
1620     }
1621     return OUString();
1622 }
1623 
1624 bool checkUnoObjectType(SbUnoObject& rUnoObj, const OUString& rClass)
1625 {
1626     Any aToInspectObj = rUnoObj.getUnoAny();
1627 
1628     // Return true for XInvocation based objects as interface type names don't count then
1629     Reference< XInvocation > xInvocation( aToInspectObj, UNO_QUERY );
1630     if( xInvocation.is() )
1631     {
1632         return true;
1633     }
1634     bool bResult = false;
1635     Reference< XTypeProvider > xTypeProvider( aToInspectObj, UNO_QUERY );
1636     if( xTypeProvider.is() )
1637     {
1638         /*  Although interfaces in the ooo.vba namespace obey the IDL rules and
1639             have a leading 'X', in Basic we want to be able to do something
1640             like 'Dim wb As Workbooks' or 'Dim lb As MSForms.Label'. Here we
1641             add a leading 'X' to the class name and a leading dot to the entire
1642             type name. This results e.g. in '.XWorkbooks' or '.MSForms.XLabel'
1643             which matches the interface names 'ooo.vba.excel.XWorkbooks' or
1644             'ooo.vba.msforms.XLabel'.
1645          */
1646         OUString aClassName;
1647         if ( SbiRuntime::isVBAEnabled() )
1648         {
1649             aClassName = ".";
1650             sal_Int32 nClassNameDot = rClass.lastIndexOf( '.' );
1651             if( nClassNameDot >= 0 )
1652             {
1653                 aClassName += rClass.copy( 0, nClassNameDot + 1 ) + "X" + rClass.copy( nClassNameDot + 1 );
1654             }
1655             else
1656             {
1657                 aClassName += "X" + rClass;
1658             }
1659         }
1660         else // assume extended type declaration support for basic ( can't get here
1661              // otherwise.
1662             aClassName = rClass;
1663 
1664         Sequence< Type > aTypeSeq = xTypeProvider->getTypes();
1665         const Type* pTypeArray = aTypeSeq.getConstArray();
1666         sal_uInt32 nIfaceCount = aTypeSeq.getLength();
1667         for( sal_uInt32 j = 0 ; j < nIfaceCount ; j++ )
1668         {
1669             const Type& rType = pTypeArray[j];
1670 
1671             Reference<XIdlClass> xClass = TypeToIdlClass( rType );
1672             if( !xClass.is() )
1673             {
1674                 OSL_FAIL("failed to get XIdlClass for type");
1675                 break;
1676             }
1677             OUString aInterfaceName = xClass->getName();
1678             if ( aInterfaceName == "com.sun.star.bridge.oleautomation.XAutomationObject" )
1679             {
1680                 // there is a hack in the extensions/source/ole/oleobj.cxx  to return the typename of the automation object, lets check if it
1681                 // matches
1682                 Reference< XInvocation > xInv( aToInspectObj, UNO_QUERY );
1683                 if ( xInv.is() )
1684                 {
1685                     OUString sTypeName;
1686                     xInv->getValue( "$GetTypeName" ) >>= sTypeName;
1687                     if ( sTypeName.isEmpty() || sTypeName == "IDispatch" )
1688                     {
1689                         // can't check type, leave it pass
1690                         bResult = true;
1691                     }
1692                     else
1693                     {
1694                         bResult = sTypeName == rClass;
1695                     }
1696                 }
1697                 break; // finished checking automation object
1698             }
1699 
1700             // match interface name with passed class name
1701             if ( (aClassName.getLength() <= aInterfaceName.getLength()) &&
1702                     aInterfaceName.endsWithIgnoreAsciiCase( aClassName ) )
1703             {
1704                 bResult = true;
1705                 break;
1706             }
1707         }
1708     }
1709     return bResult;
1710 }
1711 
1712 // Debugging help method to readout the imlemented interfaces of an object
1713 static OUString Impl_GetSupportedInterfaces(SbUnoObject& rUnoObj)
1714 {
1715     Any aToInspectObj = rUnoObj.getUnoAny();
1716 
1717     // allow only TypeClass interface
1718     OUStringBuffer aRet;
1719     auto x = o3tl::tryAccess<Reference<XInterface>>(aToInspectObj);
1720     if( !x )
1721     {
1722         aRet.append( ID_DBG_SUPPORTEDINTERFACES );
1723         aRet.append( " not available.\n(TypeClass is not TypeClass_INTERFACE)\n" );
1724     }
1725     else
1726     {
1727         Reference< XTypeProvider > xTypeProvider( *x, UNO_QUERY );
1728 
1729         aRet.append( "Supported interfaces by object " );
1730         aRet.append(getDbgObjectName(rUnoObj));
1731         aRet.append( "\n" );
1732         if( xTypeProvider.is() )
1733         {
1734             // get the interfaces of the implementation
1735             Sequence< Type > aTypeSeq = xTypeProvider->getTypes();
1736             const Type* pTypeArray = aTypeSeq.getConstArray();
1737             sal_uInt32 nIfaceCount = aTypeSeq.getLength();
1738             for( sal_uInt32 j = 0 ; j < nIfaceCount ; j++ )
1739             {
1740                 const Type& rType = pTypeArray[j];
1741 
1742                 Reference<XIdlClass> xClass = TypeToIdlClass( rType );
1743                 if( xClass.is() )
1744                 {
1745                     aRet.append( Impl_GetInterfaceInfo( *x, xClass, 1 ) );
1746                 }
1747                 else
1748                 {
1749                     typelib_TypeDescription * pTD = nullptr;
1750                     rType.getDescription( &pTD );
1751 
1752                     aRet.append( "*** ERROR: No IdlClass for type \"" );
1753                     aRet.append( pTD->pTypeName );
1754                     aRet.append( "\"\n*** Please check type library\n" );
1755                 }
1756             }
1757         }
1758     }
1759     return aRet.makeStringAndClear();
1760 }
1761 
1762 
1763 // Debugging help method SbxDataType -> String
1764 static OUString Dbg_SbxDataType2String( SbxDataType eType )
1765 {
1766     OUStringBuffer aRet;
1767     switch( +eType )
1768     {
1769         case SbxEMPTY:      aRet.append("SbxEMPTY"); break;
1770         case SbxNULL:       aRet.append("SbxNULL"); break;
1771         case SbxINTEGER:    aRet.append("SbxINTEGER"); break;
1772         case SbxLONG:       aRet.append("SbxLONG"); break;
1773         case SbxSINGLE:     aRet.append("SbxSINGLE"); break;
1774         case SbxDOUBLE:     aRet.append("SbxDOUBLE"); break;
1775         case SbxCURRENCY:   aRet.append("SbxCURRENCY"); break;
1776         case SbxDECIMAL:    aRet.append("SbxDECIMAL"); break;
1777         case SbxDATE:       aRet.append("SbxDATE"); break;
1778         case SbxSTRING:     aRet.append("SbxSTRING"); break;
1779         case SbxOBJECT:     aRet.append("SbxOBJECT"); break;
1780         case SbxERROR:      aRet.append("SbxERROR"); break;
1781         case SbxBOOL:       aRet.append("SbxBOOL"); break;
1782         case SbxVARIANT:    aRet.append("SbxVARIANT"); break;
1783         case SbxDATAOBJECT: aRet.append("SbxDATAOBJECT"); break;
1784         case SbxCHAR:       aRet.append("SbxCHAR"); break;
1785         case SbxBYTE:       aRet.append("SbxBYTE"); break;
1786         case SbxUSHORT:     aRet.append("SbxUSHORT"); break;
1787         case SbxULONG:      aRet.append("SbxULONG"); break;
1788         case SbxSALINT64:   aRet.append("SbxINT64"); break;
1789         case SbxSALUINT64:  aRet.append("SbxUINT64"); break;
1790         case SbxINT:        aRet.append("SbxINT"); break;
1791         case SbxUINT:       aRet.append("SbxUINT"); break;
1792         case SbxVOID:       aRet.append("SbxVOID"); break;
1793         case SbxHRESULT:    aRet.append("SbxHRESULT"); break;
1794         case SbxPOINTER:    aRet.append("SbxPOINTER"); break;
1795         case SbxDIMARRAY:   aRet.append("SbxDIMARRAY"); break;
1796         case SbxCARRAY:     aRet.append("SbxCARRAY"); break;
1797         case SbxUSERDEF:    aRet.append("SbxUSERDEF"); break;
1798         case SbxLPSTR:      aRet.append("SbxLPSTR"); break;
1799         case SbxLPWSTR:     aRet.append("SbxLPWSTR"); break;
1800         case SbxCoreSTRING: aRet.append("SbxCoreSTRING"); break;
1801         case SbxOBJECT | SbxARRAY: aRet.append("SbxARRAY"); break;
1802         default: aRet.append("Unknown Sbx-Type!");break;
1803     }
1804     return aRet.makeStringAndClear();
1805 }
1806 
1807 // Debugging help method to display the properties of a SbUnoObjects
1808 static OUString Impl_DumpProperties(SbUnoObject& rUnoObj)
1809 {
1810     OUStringBuffer aRet;
1811     aRet.append("Properties of object ");
1812     aRet.append(getDbgObjectName(rUnoObj));
1813 
1814     // analyse the Uno-Infos to recognise the arrays
1815     Reference< XIntrospectionAccess > xAccess = rUnoObj.getIntrospectionAccess();
1816     if( !xAccess.is() )
1817     {
1818         Reference< XInvocation > xInvok = rUnoObj.getInvocation();
1819         if( xInvok.is() )
1820             xAccess = xInvok->getIntrospection();
1821     }
1822     if( !xAccess.is() )
1823     {
1824         aRet.append( "\nUnknown, no introspection available\n" );
1825         return aRet.makeStringAndClear();
1826     }
1827 
1828     Sequence<Property> props = xAccess->getProperties( PropertyConcept::ALL - PropertyConcept::DANGEROUS );
1829     sal_uInt32 nUnoPropCount = props.getLength();
1830     const Property* pUnoProps = props.getConstArray();
1831 
1832     SbxArray* pProps = rUnoObj.GetProperties();
1833     sal_uInt16 nPropCount = pProps->Count();
1834     sal_uInt16 nPropsPerLine = 1 + nPropCount / 30;
1835     for( sal_uInt16 i = 0; i < nPropCount; i++ )
1836     {
1837         SbxVariable* pVar = pProps->Get( i );
1838         if( pVar )
1839         {
1840             OUStringBuffer aPropStr;
1841             if( (i % nPropsPerLine) == 0 )
1842                 aPropStr.append( "\n" );
1843 
1844             // output the type and name
1845             // Is it in Uno a sequence?
1846             SbxDataType eType = pVar->GetFullType();
1847 
1848             bool bMaybeVoid = false;
1849             if( i < nUnoPropCount )
1850             {
1851                 const Property& rProp = pUnoProps[ i ];
1852 
1853                 // For MAYBEVOID freshly convert the type from Uno,
1854                 // so not just SbxEMPTY is returned.
1855                 if( rProp.Attributes & PropertyAttribute::MAYBEVOID )
1856                 {
1857                     eType = unoToSbxType( rProp.Type.getTypeClass() );
1858                     bMaybeVoid = true;
1859                 }
1860                 if( eType == SbxOBJECT )
1861                 {
1862                     Type aType = rProp.Type;
1863                     if( aType.getTypeClass() == TypeClass_SEQUENCE )
1864                         eType = SbxDataType( SbxOBJECT | SbxARRAY );
1865                 }
1866             }
1867             aPropStr.append( Dbg_SbxDataType2String( eType ) );
1868             if( bMaybeVoid )
1869                 aPropStr.append( "/void" );
1870             aPropStr.append( " " );
1871             aPropStr.append( pVar->GetName() );
1872 
1873             if( i == nPropCount - 1 )
1874                 aPropStr.append( "\n" );
1875             else
1876                 aPropStr.append( "; " );
1877 
1878             aRet.append( aPropStr.makeStringAndClear() );
1879         }
1880     }
1881     return aRet.makeStringAndClear();
1882 }
1883 
1884 // Debugging help method to display the methods of an SbUnoObjects
1885 static OUString Impl_DumpMethods(SbUnoObject& rUnoObj)
1886 {
1887     OUStringBuffer aRet;
1888     aRet.append("Methods of object ");
1889     aRet.append(getDbgObjectName(rUnoObj));
1890 
1891     // XIntrospectionAccess, so that the types of the parameter could be outputted
1892     Reference< XIntrospectionAccess > xAccess = rUnoObj.getIntrospectionAccess();
1893     if( !xAccess.is() )
1894     {
1895         Reference< XInvocation > xInvok = rUnoObj.getInvocation();
1896         if( xInvok.is() )
1897             xAccess = xInvok->getIntrospection();
1898     }
1899     if( !xAccess.is() )
1900     {
1901         aRet.append( "\nUnknown, no introspection available\n" );
1902         return aRet.makeStringAndClear();
1903     }
1904     Sequence< Reference< XIdlMethod > > methods = xAccess->getMethods
1905         ( MethodConcept::ALL - MethodConcept::DANGEROUS );
1906     const Reference< XIdlMethod >* pUnoMethods = methods.getConstArray();
1907 
1908     SbxArray* pMethods = rUnoObj.GetMethods();
1909     sal_uInt16 nMethodCount = pMethods->Count();
1910     if( !nMethodCount )
1911     {
1912         aRet.append( "\nNo methods found\n" );
1913         return aRet.makeStringAndClear();
1914     }
1915     sal_uInt16 nPropsPerLine = 1 + nMethodCount / 30;
1916     for( sal_uInt16 i = 0; i < nMethodCount; i++ )
1917     {
1918         SbxVariable* pVar = pMethods->Get( i );
1919         if( pVar )
1920         {
1921             if( (i % nPropsPerLine) == 0 )
1922                 aRet.append( "\n" );
1923 
1924             // address the method
1925             const Reference< XIdlMethod >& rxMethod = pUnoMethods[i];
1926 
1927             // Is it in Uno a sequence?
1928             SbxDataType eType = pVar->GetFullType();
1929             if( eType == SbxOBJECT )
1930             {
1931                 Reference< XIdlClass > xClass = rxMethod->getReturnType();
1932                 if( xClass.is() && xClass->getTypeClass() == TypeClass_SEQUENCE )
1933                     eType = SbxDataType( SbxOBJECT | SbxARRAY );
1934             }
1935             // output the name and the type
1936             aRet.append( Dbg_SbxDataType2String( eType ) );
1937             aRet.append( " " );
1938             aRet.append ( pVar->GetName() );
1939             aRet.append( " ( " );
1940 
1941             // the get-method mustn't have a parameter
1942             Sequence< Reference< XIdlClass > > aParamsSeq = rxMethod->getParameterTypes();
1943             sal_uInt32 nParamCount = aParamsSeq.getLength();
1944             const Reference< XIdlClass >* pParams = aParamsSeq.getConstArray();
1945 
1946             if( nParamCount > 0 )
1947             {
1948                 for( sal_uInt32 j = 0; j < nParamCount; j++ )
1949                 {
1950                     aRet.append ( Dbg_SbxDataType2String( unoToSbxType( pParams[ j ] ) ) );
1951                     if( j < nParamCount - 1 )
1952                         aRet.append( ", " );
1953                 }
1954             }
1955             else
1956                 aRet.append( "void" );
1957 
1958             aRet.append( " ) " );
1959 
1960             if( i == nMethodCount - 1 )
1961                 aRet.append( "\n" );
1962             else
1963                 aRet.append( "; " );
1964         }
1965     }
1966     return aRet.makeStringAndClear();
1967 }
1968 
1969 
1970 // Implementation SbUnoObject
1971 void SbUnoObject::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
1972 {
1973     if( bNeedIntrospection )
1974         doIntrospection();
1975 
1976     const SbxHint* pHint = dynamic_cast<const SbxHint*>(&rHint);
1977     if( pHint )
1978     {
1979         SbxVariable* pVar = pHint->GetVar();
1980         SbxArray* pParams = pVar->GetParameters();
1981         SbUnoProperty* pProp = dynamic_cast<SbUnoProperty*>( pVar );
1982         SbUnoMethod* pMeth = dynamic_cast<SbUnoMethod*>( pVar );
1983         if( pProp )
1984         {
1985             bool bInvocation = pProp->isInvocationBased();
1986             if( pHint->GetId() == SfxHintId::BasicDataWanted )
1987             {
1988                 // Test-Properties
1989                 sal_Int32 nId = pProp->nId;
1990                 if( nId < 0 )
1991                 {
1992                     // Id == -1: Display implemented interfaces according the ClassProvider
1993                     if( nId == -1 )     // Property ID_DBG_SUPPORTEDINTERFACES"
1994                     {
1995                         OUString aRetStr = Impl_GetSupportedInterfaces(*this);
1996                         pVar->PutString( aRetStr );
1997                     }
1998                     // Id == -2: output properties
1999                     else if( nId == -2 )        // Property ID_DBG_PROPERTIES
2000                     {
2001                         // now all properties must be created
2002                         implCreateAll();
2003                         OUString aRetStr = Impl_DumpProperties(*this);
2004                         pVar->PutString( aRetStr );
2005                     }
2006                     // Id == -3: output the methods
2007                     else if( nId == -3 )        // Property ID_DBG_METHODS
2008                     {
2009                         // now all properties must be created
2010                         implCreateAll();
2011                         OUString aRetStr = Impl_DumpMethods(*this);
2012                         pVar->PutString( aRetStr );
2013                     }
2014                     return;
2015                 }
2016 
2017                 if( !bInvocation && mxUnoAccess.is() )
2018                 {
2019                     try
2020                     {
2021                         if ( maStructInfo.get()  )
2022                         {
2023                             StructRefInfo aMember = maStructInfo->getStructMember( pProp->GetName() );
2024                             if ( aMember.isEmpty() )
2025                             {
2026                                  StarBASIC::Error( ERRCODE_BASIC_PROPERTY_NOT_FOUND );
2027                             }
2028                             else
2029                             {
2030                                 if ( pProp->isUnoStruct() )
2031                                 {
2032                                     SbUnoStructRefObject* pSbUnoObject = new SbUnoStructRefObject( pProp->GetName(), aMember );
2033                                     SbxObjectRef xWrapper = static_cast<SbxObject*>(pSbUnoObject);
2034                                     pVar->PutObject( xWrapper.get() );
2035                                 }
2036                                 else
2037                                 {
2038                                     Any aRetAny = aMember.getValue();
2039                                     // take over the value from Uno to Sbx
2040                                     unoToSbxValue( pVar, aRetAny );
2041                                 }
2042                                 return;
2043                             }
2044                         }
2045                         // get the value
2046                         Reference< XPropertySet > xPropSet( mxUnoAccess->queryAdapter( cppu::UnoType<XPropertySet>::get()), UNO_QUERY );
2047                         Any aRetAny = xPropSet->getPropertyValue( pProp->GetName() );
2048                         // The use of getPropertyValue (instead of using the index) is
2049                         // suboptimal, but the refactoring to XInvocation is already pending
2050                         // Otherwise it is possible to use FastPropertySet
2051 
2052                         // take over the value from Uno to Sbx
2053                         unoToSbxValue( pVar, aRetAny );
2054                     }
2055                     catch( const Exception& )
2056                     {
2057                         implHandleAnyException( ::cppu::getCaughtException() );
2058                     }
2059                 }
2060                 else if( bInvocation && mxInvocation.is() )
2061                 {
2062                     try
2063                     {
2064                         sal_uInt32 nParamCount = pParams ? (static_cast<sal_uInt32>(pParams->Count()) - 1) : 0;
2065                         bool bCanBeConsideredAMethod = mxInvocation->hasMethod( pProp->GetName() );
2066                         Any aRetAny;
2067                         if ( bCanBeConsideredAMethod && nParamCount )
2068                         {
2069                             // Automation properties have methods, so.. we need to invoke this through
2070                             // XInvocation
2071                             Sequence<Any> args;
2072                             processAutomationParams( pParams, args, nParamCount );
2073                             aRetAny = invokeAutomationMethod( pProp->GetName(), args, pParams, nParamCount, mxInvocation, INVOKETYPE::GetProp );
2074                         }
2075                         else
2076                             aRetAny = mxInvocation->getValue( pProp->GetName() );
2077                         // take over the value from Uno to Sbx
2078                         unoToSbxValue( pVar, aRetAny );
2079                         if( pParams && bCanBeConsideredAMethod )
2080                             pVar->SetParameters( nullptr );
2081 
2082                     }
2083                     catch( const Exception& )
2084                     {
2085                         implHandleAnyException( ::cppu::getCaughtException() );
2086                     }
2087                 }
2088             }
2089             else if( pHint->GetId() == SfxHintId::BasicDataChanged )
2090             {
2091                 if( !bInvocation && mxUnoAccess.is() )
2092                 {
2093                     if( pProp->aUnoProp.Attributes & PropertyAttribute::READONLY )
2094                     {
2095                         StarBASIC::Error( ERRCODE_BASIC_PROP_READONLY );
2096                         return;
2097                     }
2098                     if (  maStructInfo.get()  )
2099                     {
2100                         StructRefInfo aMember = maStructInfo->getStructMember( pProp->GetName() );
2101                         if ( aMember.isEmpty() )
2102                         {
2103                             StarBASIC::Error( ERRCODE_BASIC_PROPERTY_NOT_FOUND );
2104                         }
2105                         else
2106                         {
2107                             Any aAnyValue = sbxToUnoValue( pVar, pProp->aUnoProp.Type, &pProp->aUnoProp );
2108                             aMember.setValue( aAnyValue );
2109                         }
2110                         return;
2111                    }
2112                     // take over the value from Uno to Sbx
2113                     Any aAnyValue = sbxToUnoValue( pVar, pProp->aUnoProp.Type, &pProp->aUnoProp );
2114                     try
2115                     {
2116                         // set the value
2117                         Reference< XPropertySet > xPropSet( mxUnoAccess->queryAdapter( cppu::UnoType<XPropertySet>::get()), UNO_QUERY );
2118                         xPropSet->setPropertyValue( pProp->GetName(), aAnyValue );
2119                         // The use of getPropertyValue (instead of using the index) is
2120                         // suboptimal, but the refactoring to XInvocation is already pending
2121                         // Otherwise it is possible to use FastPropertySet
2122                     }
2123                     catch( const Exception& )
2124                     {
2125                         implHandleAnyException( ::cppu::getCaughtException() );
2126                     }
2127                 }
2128                 else if( bInvocation && mxInvocation.is() )
2129                 {
2130                     // take over the value from Uno to Sbx
2131                     Any aAnyValue = sbxToUnoValueImpl( pVar );
2132                     try
2133                     {
2134                         // set the value
2135                         mxInvocation->setValue( pProp->GetName(), aAnyValue );
2136                     }
2137                     catch( const Exception& )
2138                     {
2139                         implHandleAnyException( ::cppu::getCaughtException() );
2140                     }
2141                 }
2142             }
2143         }
2144         else if( pMeth )
2145         {
2146             bool bInvocation = pMeth->isInvocationBased();
2147             if( pHint->GetId() == SfxHintId::BasicDataWanted )
2148             {
2149                 // number of Parameter -1 because of Param0 == this
2150                 sal_uInt32 nParamCount = pParams ? (static_cast<sal_uInt32>(pParams->Count()) - 1) : 0;
2151                 Sequence<Any> args;
2152                 bool bOutParams = false;
2153 
2154                 if( !bInvocation && mxUnoAccess.is() )
2155                 {
2156                     // get info
2157                     const Sequence<ParamInfo>& rInfoSeq = pMeth->getParamInfos();
2158                     const ParamInfo* pParamInfos = rInfoSeq.getConstArray();
2159                     sal_uInt32 nUnoParamCount = rInfoSeq.getLength();
2160                     sal_uInt32 nAllocParamCount = nParamCount;
2161 
2162                     // ignore surplus parameter; alternative: throw an error
2163                     if( nParamCount > nUnoParamCount )
2164                     {
2165                         nParamCount = nUnoParamCount;
2166                         nAllocParamCount = nParamCount;
2167                     }
2168                     else if( nParamCount < nUnoParamCount )
2169                     {
2170                         SbiInstance* pInst = GetSbData()->pInst;
2171                         if( pInst && pInst->IsCompatibility() )
2172                         {
2173                             // Check types
2174                             bool bError = false;
2175                             for( sal_uInt32 i = nParamCount ; i < nUnoParamCount ; i++ )
2176                             {
2177                                 const ParamInfo& rInfo = pParamInfos[i];
2178                                 const Reference< XIdlClass >& rxClass = rInfo.aType;
2179                                 if( rxClass->getTypeClass() != TypeClass_ANY )
2180                                 {
2181                                     bError = true;
2182                                     StarBASIC::Error( ERRCODE_BASIC_NOT_OPTIONAL );
2183                                 }
2184                             }
2185                             if( !bError )
2186                                 nAllocParamCount = nUnoParamCount;
2187                         }
2188                     }
2189 
2190                     if( nAllocParamCount > 0 )
2191                     {
2192                         args.realloc( nAllocParamCount );
2193                         Any* pAnyArgs = args.getArray();
2194                         for( sal_uInt32 i = 0 ; i < nParamCount ; i++ )
2195                         {
2196                             const ParamInfo& rInfo = pParamInfos[i];
2197                             const Reference< XIdlClass >& rxClass = rInfo.aType;
2198 
2199                             css::uno::Type aType( rxClass->getTypeClass(), rxClass->getName() );
2200 
2201                             // ATTENTION: Don't forget for Sbx-Parameter the offset!
2202                             pAnyArgs[i] = sbxToUnoValue( pParams->Get( static_cast<sal_uInt16>(i+1) ), aType );
2203 
2204                             // If it is not certain check whether the out-parameter are available.
2205                             if( !bOutParams )
2206                             {
2207                                 ParamMode aParamMode = rInfo.aMode;
2208                                 if( aParamMode != ParamMode_IN )
2209                                     bOutParams = true;
2210                             }
2211                         }
2212                     }
2213                 }
2214                 else if( bInvocation && pParams && mxInvocation.is() )
2215                 {
2216                     processAutomationParams( pParams, args, nParamCount );
2217                 }
2218 
2219                 // call the method
2220                 GetSbData()->bBlockCompilerError = true;  // #106433 Block compiler errors for API calls
2221                 try
2222                 {
2223                     if( !bInvocation && mxUnoAccess.is() )
2224                     {
2225                         Any aRetAny = pMeth->m_xUnoMethod->invoke( getUnoAny(), args );
2226 
2227                         // take over the value from Uno to Sbx
2228                         unoToSbxValue( pVar, aRetAny );
2229 
2230                         // Did we to copy back the Out-Parameter?
2231                         if( bOutParams )
2232                         {
2233                             const Any* pAnyArgs = args.getConstArray();
2234 
2235                             // get info
2236                             const Sequence<ParamInfo>& rInfoSeq = pMeth->getParamInfos();
2237                             const ParamInfo* pParamInfos = rInfoSeq.getConstArray();
2238 
2239                             sal_uInt32 j;
2240                             for( j = 0 ; j < nParamCount ; j++ )
2241                             {
2242                                 const ParamInfo& rInfo = pParamInfos[j];
2243                                 ParamMode aParamMode = rInfo.aMode;
2244                                 if( aParamMode != ParamMode_IN )
2245                                     unoToSbxValue( pParams->Get( static_cast<sal_uInt16>(j+1) ), pAnyArgs[ j ] );
2246                             }
2247                         }
2248                     }
2249                     else if( bInvocation && mxInvocation.is() )
2250                     {
2251                         Any aRetAny = invokeAutomationMethod( pMeth->GetName(), args, pParams, nParamCount, mxInvocation, INVOKETYPE::Func );
2252                         unoToSbxValue( pVar, aRetAny );
2253                         }
2254 
2255                     // remove parameter here, because this was not done anymore in unoToSbxValue()
2256                     // for arrays
2257                     if( pParams )
2258                         pVar->SetParameters( nullptr );
2259                 }
2260                 catch( const Exception& )
2261                 {
2262                     implHandleAnyException( ::cppu::getCaughtException() );
2263                 }
2264                 GetSbData()->bBlockCompilerError = false;  // #106433 Unblock compiler errors
2265             }
2266         }
2267         else
2268             SbxObject::Notify( rBC, rHint );
2269     }
2270 }
2271 
2272 
2273 SbUnoObject::SbUnoObject( const OUString& aName_, const Any& aUnoObj_ )
2274     : SbxObject( aName_ )
2275     , bNeedIntrospection( true )
2276     , bNativeCOMObject( false )
2277 {
2278     // beat out again the default properties of Sbx
2279     Remove( "Name", SbxClassType::DontCare );
2280     Remove( "Parent", SbxClassType::DontCare );
2281 
2282     // check the type of the objects
2283     TypeClass eType = aUnoObj_.getValueType().getTypeClass();
2284     Reference< XInterface > x;
2285     if( eType == TypeClass_INTERFACE )
2286     {
2287         // get the interface from the Any
2288         aUnoObj_ >>= x;
2289         if( !x.is() )
2290             return;
2291     }
2292 
2293     Reference< XTypeProvider > xTypeProvider;
2294     // Did the object have an invocation itself?
2295     mxInvocation.set( x, UNO_QUERY );
2296 
2297     xTypeProvider.set( x, UNO_QUERY );
2298 
2299     if( mxInvocation.is() )
2300     {
2301 
2302         // get the ExactName
2303         mxExactNameInvocation.set( mxInvocation, UNO_QUERY );
2304 
2305         // The remainder refers only to the introspection
2306         if( !xTypeProvider.is() )
2307         {
2308             bNeedIntrospection = false;
2309             return;
2310         }
2311 
2312         // Ignore introspection based members for COM objects to avoid
2313         // hiding of equally named COM symbols, e.g. XInvocation::getValue
2314         Reference< oleautomation::XAutomationObject > xAutomationObject( aUnoObj_, UNO_QUERY );
2315         if( xAutomationObject.is() )
2316             bNativeCOMObject = true;
2317     }
2318 
2319     maTmpUnoObj = aUnoObj_;
2320 
2321 
2322     //*** Define the name ***
2323     bool bFatalError = true;
2324 
2325     // Is it an interface or a struct?
2326     bool bSetClassName = false;
2327     OUString aClassName_;
2328     if( eType == TypeClass_STRUCT || eType == TypeClass_EXCEPTION )
2329     {
2330         // Struct is Ok
2331         bFatalError = false;
2332 
2333         // insert the real name of the class
2334         if( aName_.isEmpty() )
2335         {
2336             aClassName_ = aUnoObj_.getValueType().getTypeName();
2337             bSetClassName = true;
2338         }
2339         StructRefInfo aThisStruct( maTmpUnoObj, maTmpUnoObj.getValueType(), 0 );
2340         maStructInfo.reset( new SbUnoStructRefObject( GetName(), aThisStruct ) );
2341     }
2342     else if( eType == TypeClass_INTERFACE )
2343     {
2344         // Interface works always through the type in the Any
2345         bFatalError = false;
2346     }
2347     if( bSetClassName )
2348         SetClassName( aClassName_ );
2349 
2350     // Neither interface nor Struct -> FatalError
2351     if( bFatalError )
2352     {
2353         StarBASIC::FatalError( ERRCODE_BASIC_EXCEPTION );
2354         return;
2355     }
2356 
2357     // pass the introspection primal on demand
2358 }
2359 
2360 SbUnoObject::~SbUnoObject()
2361 {
2362 }
2363 
2364 
2365 // pass the introspection on Demand
2366 void SbUnoObject::doIntrospection()
2367 {
2368     if( !bNeedIntrospection )
2369         return;
2370 
2371     Reference<XComponentContext> xContext = comphelper::getProcessComponentContext();
2372 
2373     if (!xContext.is())
2374         return;
2375 
2376 
2377     // get the introspection service
2378     Reference<XIntrospection> xIntrospection;
2379 
2380     try
2381     {
2382         xIntrospection = theIntrospection::get(xContext);
2383     }
2384     catch ( const css::uno::DeploymentException& )
2385     {
2386     }
2387 
2388     if (!xIntrospection.is())
2389         return;
2390 
2391     bNeedIntrospection = false;
2392 
2393     // pass the introspection
2394     try
2395     {
2396         mxUnoAccess = xIntrospection->inspect( maTmpUnoObj );
2397     }
2398     catch( const RuntimeException& e )
2399     {
2400         StarBASIC::Error( ERRCODE_BASIC_EXCEPTION, implGetExceptionMsg( e ) );
2401     }
2402 
2403     if( !mxUnoAccess.is() )
2404     {
2405         // #51475 mark to indicate an invalid object (no mxMaterialHolder)
2406         return;
2407     }
2408 
2409     // get MaterialHolder from access
2410     mxMaterialHolder.set( mxUnoAccess, UNO_QUERY );
2411 
2412     // get ExactName from access
2413     mxExactName.set( mxUnoAccess, UNO_QUERY );
2414 }
2415 
2416 
2417 // Start of a list of all SbUnoMethod-Instances
2418 static SbUnoMethod* pFirst = nullptr;
2419 
2420 void clearUnoMethodsForBasic( StarBASIC const * pBasic )
2421 {
2422     SbUnoMethod* pMeth = pFirst;
2423     while( pMeth )
2424     {
2425         SbxObject* pObject = pMeth->GetParent();
2426         if ( pObject )
2427         {
2428             StarBASIC* pModBasic = dynamic_cast< StarBASIC* >( pObject->GetParent() );
2429             if ( pModBasic == pBasic )
2430             {
2431                 // for now the solution is to remove the method from the list and to clear it,
2432                 // but in case the element should be correctly transferred to another StarBASIC,
2433                 // we should either set module parent to NULL without clearing it, or even
2434                 // set the new StarBASIC as the parent of the module
2435                 // pObject->SetParent( NULL );
2436 
2437                 if( pMeth == pFirst )
2438                     pFirst = pMeth->pNext;
2439                 else if( pMeth->pPrev )
2440                     pMeth->pPrev->pNext = pMeth->pNext;
2441                 if( pMeth->pNext )
2442                     pMeth->pNext->pPrev = pMeth->pPrev;
2443 
2444                 pMeth->pPrev = nullptr;
2445                 pMeth->pNext = nullptr;
2446 
2447                 pMeth->SbxValue::Clear();
2448                 pObject->SbxValue::Clear();
2449 
2450                 // start from the beginning after object clearing, the cycle will end since the method is removed each time
2451                 pMeth = pFirst;
2452             }
2453             else
2454                 pMeth = pMeth->pNext;
2455         }
2456         else
2457             pMeth = pMeth->pNext;
2458     }
2459 }
2460 
2461 void clearUnoMethods()
2462 {
2463     SbUnoMethod* pMeth = pFirst;
2464     while( pMeth )
2465     {
2466         pMeth->SbxValue::Clear();
2467         pMeth = pMeth->pNext;
2468     }
2469 }
2470 
2471 
2472 SbUnoMethod::SbUnoMethod
2473 (
2474     const OUString& aName_,
2475     SbxDataType eSbxType,
2476     Reference< XIdlMethod > const & xUnoMethod_,
2477     bool bInvocation
2478 )
2479     : SbxMethod( aName_, eSbxType )
2480     , mbInvocation( bInvocation )
2481 {
2482     m_xUnoMethod = xUnoMethod_;
2483     pParamInfoSeq = nullptr;
2484 
2485     // enregister the method in a list
2486     pNext = pFirst;
2487     pPrev = nullptr;
2488     pFirst = this;
2489     if( pNext )
2490         pNext->pPrev = this;
2491 }
2492 
2493 SbUnoMethod::~SbUnoMethod()
2494 {
2495     pParamInfoSeq.reset();
2496 
2497     if( this == pFirst )
2498         pFirst = pNext;
2499     else if( pPrev )
2500         pPrev->pNext = pNext;
2501     if( pNext )
2502         pNext->pPrev = pPrev;
2503 }
2504 
2505 SbxInfo* SbUnoMethod::GetInfo()
2506 {
2507     if( !pInfo.is() && m_xUnoMethod.is() )
2508     {
2509         SbiInstance* pInst = GetSbData()->pInst;
2510         if( pInst && pInst->IsCompatibility() )
2511         {
2512             pInfo = new SbxInfo();
2513 
2514             const Sequence<ParamInfo>& rInfoSeq = getParamInfos();
2515             const ParamInfo* pParamInfos = rInfoSeq.getConstArray();
2516             sal_uInt32 nParamCount = rInfoSeq.getLength();
2517 
2518             for( sal_uInt32 i = 0 ; i < nParamCount ; i++ )
2519             {
2520                 const ParamInfo& rInfo = pParamInfos[i];
2521                 OUString aParamName = rInfo.aName;
2522 
2523                 pInfo->AddParam( aParamName, SbxVARIANT, SbxFlagBits::Read );
2524             }
2525         }
2526     }
2527     return pInfo.get();
2528 }
2529 
2530 const Sequence<ParamInfo>& SbUnoMethod::getParamInfos()
2531 {
2532     if (!pParamInfoSeq)
2533     {
2534         Sequence<ParamInfo> aTmp;
2535         if (m_xUnoMethod.is())
2536             aTmp = m_xUnoMethod->getParameterInfos();
2537         pParamInfoSeq.reset( new Sequence<ParamInfo>(aTmp) );
2538     }
2539     return *pParamInfoSeq;
2540 }
2541 
2542 SbUnoProperty::SbUnoProperty
2543 (
2544     const OUString& aName_,
2545     SbxDataType eSbxType,
2546     SbxDataType eRealSbxType,
2547     const Property& aUnoProp_,
2548     sal_Int32 nId_,
2549     bool bInvocation,
2550     bool bUnoStruct
2551 )
2552     : SbxProperty( aName_, eSbxType )
2553     , aUnoProp( aUnoProp_ )
2554     , nId( nId_ )
2555     , mbInvocation( bInvocation )
2556     , mRealType( eRealSbxType )
2557     , mbUnoStruct( bUnoStruct )
2558 {
2559     // as needed establish a dummy array so that SbiRuntime::CheckArray() works
2560     static SbxArrayRef xDummyArray = new SbxArray( SbxVARIANT );
2561     if( eSbxType & SbxARRAY )
2562         PutObject( xDummyArray.get() );
2563 }
2564 
2565 SbUnoProperty::~SbUnoProperty()
2566 {}
2567 
2568 
2569 SbxVariable* SbUnoObject::Find( const OUString& rName, SbxClassType t )
2570 {
2571     static Reference< XIdlMethod > xDummyMethod;
2572     static Property aDummyProp;
2573 
2574     SbxVariable* pRes = SbxObject::Find( rName, t );
2575 
2576     if( bNeedIntrospection )
2577         doIntrospection();
2578 
2579     // New 1999-03-04: Create properties on demand. Therefore search now via
2580     // IntrospectionAccess if a property or a method of the required name exist
2581     if( !pRes )
2582     {
2583         OUString aUName( rName );
2584         if( mxUnoAccess.is() && !bNativeCOMObject )
2585         {
2586             if( mxExactName.is() )
2587             {
2588                 OUString aUExactName = mxExactName->getExactName( aUName );
2589                 if( !aUExactName.isEmpty() )
2590                 {
2591                     aUName = aUExactName;
2592                 }
2593             }
2594             if( mxUnoAccess->hasProperty( aUName, PropertyConcept::ALL - PropertyConcept::DANGEROUS ) )
2595             {
2596                 const Property& rProp = mxUnoAccess->
2597                     getProperty( aUName, PropertyConcept::ALL - PropertyConcept::DANGEROUS );
2598 
2599                 // If the property could be void the type had to be set to Variant
2600                 SbxDataType eSbxType;
2601                 if( rProp.Attributes & PropertyAttribute::MAYBEVOID )
2602                     eSbxType = SbxVARIANT;
2603                 else
2604                     eSbxType = unoToSbxType( rProp.Type.getTypeClass() );
2605 
2606                 SbxDataType eRealSbxType = ( ( rProp.Attributes & PropertyAttribute::MAYBEVOID ) ? unoToSbxType( rProp.Type.getTypeClass() ) : eSbxType );
2607                 // create the property and superimpose it
2608                 auto pProp = tools::make_ref<SbUnoProperty>( rProp.Name, eSbxType, eRealSbxType, rProp, 0, false, ( rProp.Type.getTypeClass() ==  css::uno::TypeClass_STRUCT  ) );
2609                 QuickInsert( pProp.get() );
2610                 pRes = pProp.get();
2611             }
2612             else if( mxUnoAccess->hasMethod( aUName,
2613                 MethodConcept::ALL - MethodConcept::DANGEROUS ) )
2614             {
2615                 // address the method
2616                 const Reference< XIdlMethod >& rxMethod = mxUnoAccess->
2617                     getMethod( aUName, MethodConcept::ALL - MethodConcept::DANGEROUS );
2618 
2619                 // create SbUnoMethod and superimpose it
2620                 auto xMethRef = tools::make_ref<SbUnoMethod>( rxMethod->getName(),
2621                     unoToSbxType( rxMethod->getReturnType() ), rxMethod, false );
2622                 QuickInsert( xMethRef.get() );
2623                 pRes = xMethRef.get();
2624             }
2625 
2626             // If nothing was found check via XNameAccess
2627             if( !pRes )
2628             {
2629                 try
2630                 {
2631                     Reference< XNameAccess > xNameAccess( mxUnoAccess->queryAdapter( cppu::UnoType<XPropertySet>::get()), UNO_QUERY );
2632 
2633                     if( xNameAccess.is() && xNameAccess->hasByName( rName ) )
2634                     {
2635                         Any aAny = xNameAccess->getByName( rName );
2636 
2637                         // ATTENTION: Because of XNameAccess, the variable generated here
2638                         // may not be included as a fixed property in the object and therefore
2639                         // won't be stored anywhere.
2640                         // If this leads to problems, it has to be created
2641                         // synthetically or a class SbUnoNameAccessProperty,
2642                         // which checks the existence on access and which
2643                         // is disposed if the name is not found anymore.
2644                         pRes = new SbxVariable( SbxVARIANT );
2645                         unoToSbxValue( pRes, aAny );
2646                     }
2647                 }
2648                 catch( const NoSuchElementException& e )
2649                 {
2650                     StarBASIC::Error( ERRCODE_BASIC_EXCEPTION, implGetExceptionMsg( e ) );
2651                 }
2652                 catch( const Exception& )
2653                 {
2654                     // Establish so that the exception error will not be overwritten
2655                     if( !pRes )
2656                         pRes = new SbxVariable( SbxVARIANT );
2657 
2658                     implHandleAnyException( ::cppu::getCaughtException() );
2659                 }
2660             }
2661         }
2662         if( !pRes && mxInvocation.is() )
2663         {
2664             if( mxExactNameInvocation.is() )
2665             {
2666                 OUString aUExactName = mxExactNameInvocation->getExactName( aUName );
2667                 if( !aUExactName.isEmpty() )
2668                 {
2669                     aUName = aUExactName;
2670                 }
2671             }
2672 
2673             try
2674             {
2675                 if( mxInvocation->hasProperty( aUName ) )
2676                 {
2677                     // create a property and superimpose it
2678                     auto xVarRef = tools::make_ref<SbUnoProperty>( aUName, SbxVARIANT, SbxVARIANT, aDummyProp, 0, true, false );
2679                     QuickInsert( xVarRef.get() );
2680                     pRes = xVarRef.get();
2681                 }
2682                 else if( mxInvocation->hasMethod( aUName ) )
2683                 {
2684                     // create SbUnoMethode and superimpose it
2685                     auto xMethRef = tools::make_ref<SbUnoMethod>( aUName, SbxVARIANT, xDummyMethod, true );
2686                     QuickInsert( xMethRef.get() );
2687                     pRes = xMethRef.get();
2688                 }
2689                 else
2690                 {
2691                     Reference< XDirectInvocation > xDirectInvoke( mxInvocation, UNO_QUERY );
2692                     if ( xDirectInvoke.is() && xDirectInvoke->hasMember( aUName ) )
2693                     {
2694                         auto xMethRef = tools::make_ref<SbUnoMethod>( aUName, SbxVARIANT, xDummyMethod, true );
2695                         QuickInsert( xMethRef.get() );
2696                         pRes = xMethRef.get();
2697                     }
2698 
2699                 }
2700             }
2701             catch( const RuntimeException& e )
2702             {
2703                 // Establish so that the exception error will not be overwritten
2704                 if( !pRes )
2705                     pRes = new SbxVariable( SbxVARIANT );
2706 
2707                 StarBASIC::Error( ERRCODE_BASIC_EXCEPTION, implGetExceptionMsg( e ) );
2708             }
2709         }
2710     }
2711 
2712     // At the very end checking if the Dbg_-Properties are meant
2713 
2714     if( !pRes )
2715     {
2716         if( rName.equalsIgnoreAsciiCase(ID_DBG_SUPPORTEDINTERFACES) ||
2717             rName.equalsIgnoreAsciiCase(ID_DBG_PROPERTIES) ||
2718             rName.equalsIgnoreAsciiCase(ID_DBG_METHODS) )
2719         {
2720             // Create
2721             implCreateDbgProperties();
2722 
2723             // Now they have to be found regular
2724             pRes = SbxObject::Find( rName, SbxClassType::DontCare );
2725         }
2726     }
2727     return pRes;
2728 }
2729 
2730 
2731 // help method to create the dbg_-Properties
2732 void SbUnoObject::implCreateDbgProperties()
2733 {
2734     Property aProp;
2735 
2736     // Id == -1: display the implemented interfaces corresponding the ClassProvider
2737     auto xVarRef = tools::make_ref<SbUnoProperty>( OUString(ID_DBG_SUPPORTEDINTERFACES), SbxSTRING, SbxSTRING, aProp, -1, false, false );
2738     QuickInsert( xVarRef.get() );
2739 
2740     // Id == -2: output the properties
2741     xVarRef = tools::make_ref<SbUnoProperty>( OUString(ID_DBG_PROPERTIES), SbxSTRING, SbxSTRING, aProp, -2, false, false );
2742     QuickInsert( xVarRef.get() );
2743 
2744     // Id == -3: output the Methods
2745     xVarRef = tools::make_ref<SbUnoProperty>( OUString(ID_DBG_METHODS), SbxSTRING, SbxSTRING, aProp, -3, false, false );
2746     QuickInsert( xVarRef.get() );
2747 }
2748 
2749 void SbUnoObject::implCreateAll()
2750 {
2751     // throw away all existing methods and properties
2752     pMethods   = tools::make_ref<SbxArray>();
2753     pProps     = tools::make_ref<SbxArray>();
2754 
2755     if( bNeedIntrospection ) doIntrospection();
2756 
2757     // get introspection
2758     Reference< XIntrospectionAccess > xAccess = mxUnoAccess;
2759     if( !xAccess.is() || bNativeCOMObject )
2760     {
2761         if( mxInvocation.is() )
2762             xAccess = mxInvocation->getIntrospection();
2763         else if( bNativeCOMObject )
2764             return;
2765     }
2766     if( !xAccess.is() )
2767         return;
2768 
2769     // Establish properties
2770     Sequence<Property> props = xAccess->getProperties( PropertyConcept::ALL - PropertyConcept::DANGEROUS );
2771     sal_uInt32 nPropCount = props.getLength();
2772     const Property* pProps_ = props.getConstArray();
2773 
2774     sal_uInt32 i;
2775     for( i = 0 ; i < nPropCount ; i++ )
2776     {
2777         const Property& rProp = pProps_[ i ];
2778 
2779         // If the property could be void the type had to be set to Variant
2780         SbxDataType eSbxType;
2781         if( rProp.Attributes & PropertyAttribute::MAYBEVOID )
2782             eSbxType = SbxVARIANT;
2783         else
2784             eSbxType = unoToSbxType( rProp.Type.getTypeClass() );
2785 
2786         SbxDataType eRealSbxType = ( ( rProp.Attributes & PropertyAttribute::MAYBEVOID ) ? unoToSbxType( rProp.Type.getTypeClass() ) : eSbxType );
2787         // Create property and superimpose it
2788         auto xVarRef = tools::make_ref<SbUnoProperty>( rProp.Name, eSbxType, eRealSbxType, rProp, i, false, ( rProp.Type.getTypeClass() == css::uno::TypeClass_STRUCT   ) );
2789         QuickInsert( xVarRef.get() );
2790     }
2791 
2792     // Create Dbg_-Properties
2793     implCreateDbgProperties();
2794 
2795     // Create methods
2796     Sequence< Reference< XIdlMethod > > aMethodSeq = xAccess->getMethods
2797         ( MethodConcept::ALL - MethodConcept::DANGEROUS );
2798     sal_uInt32 nMethCount = aMethodSeq.getLength();
2799     const Reference< XIdlMethod >* pMethods_ = aMethodSeq.getConstArray();
2800     for( i = 0 ; i < nMethCount ; i++ )
2801     {
2802         // address method
2803         const Reference< XIdlMethod >& rxMethod = pMethods_[i];
2804 
2805         // Create SbUnoMethod and superimpose it
2806         auto xMethRef = tools::make_ref<SbUnoMethod>
2807             ( rxMethod->getName(), unoToSbxType( rxMethod->getReturnType() ), rxMethod, false );
2808         QuickInsert( xMethRef.get() );
2809     }
2810 }
2811 
2812 
2813 // output the value
2814 Any SbUnoObject::getUnoAny()
2815 {
2816     Any aRetAny;
2817     if( bNeedIntrospection ) doIntrospection();
2818     if ( maStructInfo.get() )
2819        aRetAny = maTmpUnoObj;
2820     else if( mxMaterialHolder.is() )
2821         aRetAny = mxMaterialHolder->getMaterial();
2822     else if( mxInvocation.is() )
2823         aRetAny <<= mxInvocation;
2824     return aRetAny;
2825 }
2826 
2827 // help method to create a Uno-Struct per CoreReflection
2828 static SbUnoObject* Impl_CreateUnoStruct( const OUString& aClassName )
2829 {
2830     // get CoreReflection
2831     Reference< XIdlReflection > xCoreReflection = getCoreReflection_Impl();
2832     if( !xCoreReflection.is() )
2833         return nullptr;
2834 
2835     // search for the class
2836     Reference< XIdlClass > xClass;
2837     const Reference< XHierarchicalNameAccess >& xHarryName =
2838         getCoreReflection_HierarchicalNameAccess_Impl();
2839     if( xHarryName.is() && xHarryName->hasByHierarchicalName( aClassName ) )
2840         xClass = xCoreReflection->forName( aClassName );
2841     if( !xClass.is() )
2842         return nullptr;
2843 
2844     // Is it really a struct?
2845     TypeClass eType = xClass->getTypeClass();
2846     if ( ( eType != TypeClass_STRUCT ) && ( eType != TypeClass_EXCEPTION ) )
2847         return nullptr;
2848 
2849     // create an instance
2850     Any aNewAny;
2851     xClass->createObject( aNewAny );
2852     // make a SbUnoObject out of it
2853     SbUnoObject* pUnoObj = new SbUnoObject( aClassName, aNewAny );
2854     return pUnoObj;
2855 }
2856 
2857 
2858 // Factory-Class to create Uno-Structs per DIM AS NEW
2859 SbxBase* SbUnoFactory::Create( sal_uInt16, sal_uInt32 )
2860 {
2861     // Via SbxId nothing works in Uno
2862     return nullptr;
2863 }
2864 
2865 SbxObject* SbUnoFactory::CreateObject( const OUString& rClassName )
2866 {
2867     return Impl_CreateUnoStruct( rClassName );
2868 }
2869 
2870 
2871 // Provisional interface for the UNO-Connection
2872 // Deliver a SbxObject, that wrap a Uno-Interface
2873 SbxObjectRef GetSbUnoObject( const OUString& aName, const Any& aUnoObj_ )
2874 {
2875     return new SbUnoObject( aName, aUnoObj_ );
2876 }
2877 
2878 // Force creation of all properties for debugging
2879 void createAllObjectProperties( SbxObject* pObj )
2880 {
2881     if( !pObj )
2882         return;
2883 
2884     SbUnoObject* pUnoObj = dynamic_cast<SbUnoObject*>( pObj );
2885     SbUnoStructRefObject* pUnoStructObj = dynamic_cast<SbUnoStructRefObject*>( pObj );
2886     if( pUnoObj )
2887     {
2888         pUnoObj->createAllProperties();
2889     }
2890     else if ( pUnoStructObj )
2891     {
2892         pUnoStructObj->createAllProperties();
2893     }
2894 }
2895 
2896 
2897 void RTL_Impl_CreateUnoStruct( SbxArray& rPar )
2898 {
2899     // We need 1 parameter minimum
2900     if ( rPar.Count() < 2 )
2901     {
2902         StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
2903         return;
2904     }
2905 
2906     // get the name of the class of the struct
2907     OUString aClassName = rPar.Get(1)->GetOUString();
2908 
2909     // try to create Struct with the same name
2910     SbUnoObjectRef xUnoObj = Impl_CreateUnoStruct( aClassName );
2911     if( !xUnoObj.is() )
2912     {
2913         return;
2914     }
2915     // return the object
2916     SbxVariableRef refVar = rPar.Get(0);
2917     refVar->PutObject( xUnoObj.get() );
2918 }
2919 
2920 void RTL_Impl_CreateUnoService( SbxArray& rPar )
2921 {
2922     // We need 1 Parameter minimum
2923     if ( rPar.Count() < 2 )
2924     {
2925         StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
2926         return;
2927     }
2928 
2929     // get the name of the class of the struct
2930     OUString aServiceName = rPar.Get(1)->GetOUString();
2931 
2932     // search for the service and instantiate it
2933     Reference< XMultiServiceFactory > xFactory( comphelper::getProcessServiceFactory() );
2934     Reference< XInterface > xInterface;
2935     try
2936     {
2937         xInterface = xFactory->createInstance( aServiceName );
2938     }
2939     catch( const Exception& )
2940     {
2941         implHandleAnyException( ::cppu::getCaughtException() );
2942     }
2943 
2944     SbxVariableRef refVar = rPar.Get(0);
2945     if( xInterface.is() )
2946     {
2947         // Create a SbUnoObject out of it and return it
2948         SbUnoObjectRef xUnoObj = new SbUnoObject( aServiceName, Any(xInterface) );
2949         if( xUnoObj->getUnoAny().hasValue() )
2950         {
2951             // return the object
2952             refVar->PutObject( xUnoObj.get() );
2953         }
2954         else
2955         {
2956             refVar->PutObject( nullptr );
2957         }
2958     }
2959     else
2960     {
2961         refVar->PutObject( nullptr );
2962     }
2963 }
2964 
2965 void RTL_Impl_CreateUnoServiceWithArguments( SbxArray& rPar )
2966 {
2967     // We need 2 parameter minimum
2968     if ( rPar.Count() < 3 )
2969     {
2970         StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
2971         return;
2972     }
2973 
2974     // get the name of the class of the struct
2975     OUString aServiceName = rPar.Get(1)->GetOUString();
2976     Any aArgAsAny = sbxToUnoValue( rPar.Get(2),
2977                 cppu::UnoType<Sequence<Any>>::get() );
2978     Sequence< Any > aArgs;
2979     aArgAsAny >>= aArgs;
2980 
2981     // search for the service and instantiate it
2982     Reference< XMultiServiceFactory > xFactory( comphelper::getProcessServiceFactory() );
2983     Reference< XInterface > xInterface;
2984     try
2985     {
2986         xInterface = xFactory->createInstanceWithArguments( aServiceName, aArgs );
2987     }
2988     catch( const Exception& )
2989     {
2990         implHandleAnyException( ::cppu::getCaughtException() );
2991     }
2992 
2993     SbxVariableRef refVar = rPar.Get(0);
2994     if( xInterface.is() )
2995     {
2996         // Create a SbUnoObject out of it and return it
2997         SbUnoObjectRef xUnoObj = new SbUnoObject( aServiceName, Any(xInterface) );
2998         if( xUnoObj->getUnoAny().hasValue() )
2999         {
3000             // return the object
3001             refVar->PutObject( xUnoObj.get() );
3002         }
3003         else
3004         {
3005             refVar->PutObject( nullptr );
3006         }
3007     }
3008     else
3009     {
3010         refVar->PutObject( nullptr );
3011     }
3012 }
3013 
3014 void RTL_Impl_GetProcessServiceManager( SbxArray& rPar )
3015 {
3016     SbxVariableRef refVar = rPar.Get(0);
3017 
3018     // get the global service manager
3019     Reference< XMultiServiceFactory > xFactory( comphelper::getProcessServiceFactory() );
3020 
3021     // Create a SbUnoObject out of it and return it
3022     SbUnoObjectRef xUnoObj = new SbUnoObject( "ProcessServiceManager", Any(xFactory) );
3023     refVar->PutObject( xUnoObj.get() );
3024 }
3025 
3026 void RTL_Impl_HasInterfaces( SbxArray& rPar )
3027 {
3028     // We need 2 parameter minimum
3029     sal_uInt16 nParCount = rPar.Count();
3030     if( nParCount < 3 )
3031     {
3032         StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
3033         return;
3034     }
3035 
3036     // variable for the return value
3037     SbxVariableRef refVar = rPar.Get(0);
3038     refVar->PutBool( false );
3039 
3040     // get the Uno-Object
3041     SbxBaseRef pObj = rPar.Get( 1 )->GetObject();
3042     auto obj = dynamic_cast<SbUnoObject*>( pObj.get() );
3043     if( obj == nullptr )
3044     {
3045         return;
3046     }
3047     Any aAny = obj->getUnoAny();
3048     auto x = o3tl::tryAccess<Reference<XInterface>>(aAny);
3049     if( !x )
3050     {
3051         return;
3052     }
3053 
3054     // get CoreReflection
3055     Reference< XIdlReflection > xCoreReflection = getCoreReflection_Impl();
3056     if( !xCoreReflection.is() )
3057     {
3058         return;
3059     }
3060     for( sal_uInt16 i = 2 ; i < nParCount ; i++ )
3061     {
3062         // get the name of the interface of the struct
3063         OUString aIfaceName = rPar.Get( i )->GetOUString();
3064 
3065         // search for the class
3066         Reference< XIdlClass > xClass = xCoreReflection->forName( aIfaceName );
3067         if( !xClass.is() )
3068         {
3069             return;
3070         }
3071         // check if the interface will be supported
3072         OUString aClassName = xClass->getName();
3073         Type aClassType( xClass->getTypeClass(), aClassName );
3074         if( !(*x)->queryInterface( aClassType ).hasValue() )
3075         {
3076             return;
3077         }
3078     }
3079 
3080     // Everything works; then return TRUE
3081     refVar->PutBool( true );
3082 }
3083 
3084 void RTL_Impl_IsUnoStruct( SbxArray& rPar )
3085 {
3086     // We need 1 parameter minimum
3087     if ( rPar.Count() < 2 )
3088     {
3089         StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
3090         return;
3091     }
3092 
3093     // variable for the return value
3094     SbxVariableRef refVar = rPar.Get(0);
3095     refVar->PutBool( false );
3096 
3097     // get the Uno-Object
3098     SbxVariableRef xParam = rPar.Get( 1 );
3099     if( !xParam->IsObject() )
3100     {
3101         return;
3102     }
3103     SbxBaseRef pObj = rPar.Get( 1 )->GetObject();
3104     auto obj = dynamic_cast<SbUnoObject*>( pObj.get() );
3105     if( obj == nullptr )
3106     {
3107         return;
3108     }
3109     Any aAny = obj->getUnoAny();
3110     TypeClass eType = aAny.getValueType().getTypeClass();
3111     if( eType == TypeClass_STRUCT )
3112     {
3113         refVar->PutBool( true );
3114     }
3115 }
3116 
3117 
3118 void RTL_Impl_EqualUnoObjects( SbxArray& rPar )
3119 {
3120     if ( rPar.Count() < 3 )
3121     {
3122         StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
3123         return;
3124     }
3125 
3126     // variable for the return value
3127     SbxVariableRef refVar = rPar.Get(0);
3128     refVar->PutBool( false );
3129 
3130     // get the Uno-Objects
3131     SbxVariableRef xParam1 = rPar.Get( 1 );
3132     if( !xParam1->IsObject() )
3133     {
3134         return;
3135     }
3136     SbxBaseRef pObj1 = xParam1->GetObject();
3137     auto obj1 = dynamic_cast<SbUnoObject*>( pObj1.get() );
3138     if( obj1 == nullptr )
3139     {
3140         return;
3141     }
3142     Any aAny1 = obj1->getUnoAny();
3143     TypeClass eType1 = aAny1.getValueType().getTypeClass();
3144     if( eType1 != TypeClass_INTERFACE )
3145     {
3146         return;
3147     }
3148     Reference< XInterface > x1;
3149     aAny1 >>= x1;
3150 
3151     SbxVariableRef xParam2 = rPar.Get( 2 );
3152     if( !xParam2->IsObject() )
3153     {
3154         return;
3155     }
3156     SbxBaseRef pObj2 = xParam2->GetObject();
3157     auto obj2 = dynamic_cast<SbUnoObject*>( pObj2.get() );
3158     if( obj2 == nullptr )
3159     {
3160         return;
3161     }
3162     Any aAny2 = obj2->getUnoAny();
3163     TypeClass eType2 = aAny2.getValueType().getTypeClass();
3164     if( eType2 != TypeClass_INTERFACE )
3165     {
3166         return;
3167     }
3168     Reference< XInterface > x2;
3169     aAny2 >>= x2;
3170 
3171     if( x1 == x2 )
3172     {
3173         refVar->PutBool( true );
3174     }
3175 }
3176 
3177 
3178 // helper wrapper function to interact with TypeProvider and
3179 // XTypeDescriptionEnumerationAccess.
3180 // if it fails for whatever reason
3181 // returned Reference<> be null e.g. .is() will be false
3182 
3183 static Reference< XTypeDescriptionEnumeration > getTypeDescriptorEnumeration( const OUString& sSearchRoot,
3184                                                                        const Sequence< TypeClass >& types,
3185                                                                        TypeDescriptionSearchDepth depth )
3186 {
3187     Reference< XTypeDescriptionEnumeration > xEnum;
3188     Reference< XTypeDescriptionEnumerationAccess> xTypeEnumAccess( getTypeProvider_Impl(), UNO_QUERY );
3189     if ( xTypeEnumAccess.is() )
3190     {
3191         try
3192         {
3193             xEnum = xTypeEnumAccess->createTypeDescriptionEnumeration(
3194                 sSearchRoot, types, depth );
3195         }
3196         catch(const NoSuchTypeNameException& /*nstne*/ ) {}
3197         catch(const InvalidTypeNameException& /*nstne*/ ) {}
3198     }
3199     return xEnum;
3200 }
3201 
3202 VBAConstantHelper&
3203 VBAConstantHelper::instance()
3204 {
3205     static VBAConstantHelper aHelper;
3206     return aHelper;
3207 }
3208 
3209 void VBAConstantHelper::init()
3210 {
3211     if ( !isInited )
3212     {
3213         Sequence< TypeClass > types(1);
3214         types[ 0 ] = TypeClass_CONSTANTS;
3215         Reference< XTypeDescriptionEnumeration > xEnum = getTypeDescriptorEnumeration( "ooo.vba", types, TypeDescriptionSearchDepth_INFINITE  );
3216 
3217         if ( !xEnum.is())
3218         {
3219             return; //NULL;
3220         }
3221         while ( xEnum->hasMoreElements() )
3222         {
3223             Reference< XConstantsTypeDescription > xConstants( xEnum->nextElement(), UNO_QUERY );
3224             if ( xConstants.is() )
3225             {
3226                 // store constant group name
3227                 OUString sFullName = xConstants->getName();
3228                 sal_Int32 indexLastDot = sFullName.lastIndexOf('.');
3229                 OUString sLeafName( sFullName );
3230                 if ( indexLastDot > -1 )
3231                 {
3232                     sLeafName = sFullName.copy( indexLastDot + 1);
3233                 }
3234                 aConstCache.push_back( sLeafName ); // assume constant group names are unique
3235                 Sequence< Reference< XConstantTypeDescription > > aConsts = xConstants->getConstants();
3236                 for (sal_Int32 i = 0; i != aConsts.getLength(); ++i)
3237                 {
3238                     // store constant member name
3239                     sFullName = aConsts[i]->getName();
3240                     indexLastDot = sFullName.lastIndexOf('.');
3241                     sLeafName = sFullName;
3242                     if ( indexLastDot > -1 )
3243                     {
3244                         sLeafName = sFullName.copy( indexLastDot + 1);
3245                     }
3246                     aConstHash[ sLeafName.toAsciiLowerCase() ] = aConsts[i]->getConstantValue();
3247                 }
3248             }
3249         }
3250         isInited = true;
3251     }
3252 }
3253 
3254 bool
3255 VBAConstantHelper::isVBAConstantType( const OUString& rName )
3256 {
3257     init();
3258     bool bConstant = false;
3259 
3260     for (auto const& elem : aConstCache)
3261     {
3262         if( rName.equalsIgnoreAsciiCase(elem) )
3263         {
3264             bConstant = true;
3265             break;
3266         }
3267     }
3268     return bConstant;
3269 }
3270 
3271 SbxVariable*
3272 VBAConstantHelper::getVBAConstant( const OUString& rName )
3273 {
3274     SbxVariable* pConst = nullptr;
3275     init();
3276 
3277     auto it = aConstHash.find( rName.toAsciiLowerCase() );
3278 
3279     if ( it != aConstHash.end() )
3280     {
3281         pConst = new SbxVariable( SbxVARIANT );
3282         pConst->SetName( rName );
3283         unoToSbxValue( pConst, it->second );
3284     }
3285 
3286     return pConst;
3287 }
3288 
3289 // Function to search for a global identifier in the
3290 // UnoScope and to wrap it for Sbx
3291 SbUnoClass* findUnoClass( const OUString& rName )
3292 {
3293     // #105550 Check if module exists
3294     SbUnoClass* pUnoClass = nullptr;
3295 
3296     const Reference< XHierarchicalNameAccess >& xTypeAccess = getTypeProvider_Impl();
3297     if( xTypeAccess->hasByHierarchicalName( rName ) )
3298     {
3299         Any aRet = xTypeAccess->getByHierarchicalName( rName );
3300         Reference< XTypeDescription > xTypeDesc;
3301         aRet >>= xTypeDesc;
3302 
3303         if( xTypeDesc.is() )
3304         {
3305             TypeClass eTypeClass = xTypeDesc->getTypeClass();
3306             if( eTypeClass == TypeClass_MODULE || eTypeClass == TypeClass_CONSTANTS )
3307             {
3308                 pUnoClass = new SbUnoClass( rName );
3309             }
3310         }
3311     }
3312     return pUnoClass;
3313 }
3314 
3315 SbxVariable* SbUnoClass::Find( const OUString& rName, SbxClassType )
3316 {
3317     SbxVariable* pRes = SbxObject::Find( rName, SbxClassType::Variable );
3318 
3319     // If nothing were located the submodule isn't known yet
3320     if( !pRes )
3321     {
3322         // If it is already a class, ask for the field
3323         if( m_xClass.is() )
3324         {
3325             // Is it a field(?)
3326             Reference< XIdlField > xField = m_xClass->getField( rName );
3327             if( xField.is() )
3328             {
3329                 try
3330                 {
3331                     Any aAny = xField->get( {} ); //TODO: does this make sense?
3332 
3333                     // Convert to Sbx
3334                     pRes = new SbxVariable( SbxVARIANT );
3335                     pRes->SetName( rName );
3336                     unoToSbxValue( pRes, aAny );
3337                 }
3338                 catch( const Exception& )
3339                 {
3340                     implHandleAnyException( ::cppu::getCaughtException() );
3341                 }
3342             }
3343         }
3344         else
3345         {
3346             // expand fully qualified name
3347             OUString aNewName = GetName()
3348                               + "."
3349                               + rName;
3350 
3351             // get CoreReflection
3352             Reference< XIdlReflection > xCoreReflection = getCoreReflection_Impl();
3353             if( xCoreReflection.is() )
3354             {
3355                 // Is it a constant?
3356                 Reference< XHierarchicalNameAccess > xHarryName( xCoreReflection, UNO_QUERY );
3357                 if( xHarryName.is() )
3358                 {
3359                     try
3360                     {
3361                         Any aValue = xHarryName->getByHierarchicalName( aNewName );
3362                         TypeClass eType = aValue.getValueType().getTypeClass();
3363 
3364                         // Interface located? Then it is a class
3365                         if( eType == TypeClass_INTERFACE )
3366                         {
3367                             Reference< XIdlClass > xClass( aValue, UNO_QUERY );
3368                             if( xClass.is() )
3369                             {
3370                                 pRes = new SbxVariable( SbxVARIANT );
3371                                 SbxObjectRef xWrapper = static_cast<SbxObject*>(new SbUnoClass( aNewName, xClass ));
3372                                 pRes->PutObject( xWrapper.get() );
3373                             }
3374                         }
3375                         else
3376                         {
3377                             pRes = new SbxVariable( SbxVARIANT );
3378                             unoToSbxValue( pRes, aValue );
3379                         }
3380                     }
3381                     catch( const NoSuchElementException& )
3382                     {
3383                     }
3384                 }
3385 
3386                 // Otherwise take it again as class
3387                 if( !pRes )
3388                 {
3389                     SbUnoClass* pNewClass = findUnoClass( aNewName );
3390                     if( pNewClass )
3391                     {
3392                         pRes = new SbxVariable( SbxVARIANT );
3393                         SbxObjectRef xWrapper = static_cast<SbxObject*>(pNewClass);
3394                         pRes->PutObject( xWrapper.get() );
3395                     }
3396                 }
3397 
3398                 // A UNO service?
3399                 if( !pRes )
3400                 {
3401                     SbUnoService* pUnoService = findUnoService( aNewName );
3402                     if( pUnoService )
3403                     {
3404                         pRes = new SbxVariable( SbxVARIANT );
3405                         SbxObjectRef xWrapper = static_cast<SbxObject*>(pUnoService);
3406                         pRes->PutObject( xWrapper.get() );
3407                     }
3408                 }
3409 
3410                 // A UNO singleton?
3411                 if( !pRes )
3412                 {
3413                     SbUnoSingleton* pUnoSingleton = findUnoSingleton( aNewName );
3414                     if( pUnoSingleton )
3415                     {
3416                         pRes = new SbxVariable( SbxVARIANT );
3417                         SbxObjectRef xWrapper = static_cast<SbxObject*>(pUnoSingleton);
3418                         pRes->PutObject( xWrapper.get() );
3419                     }
3420                 }
3421             }
3422         }
3423 
3424         if( pRes )
3425         {
3426             pRes->SetName( rName );
3427 
3428             // Insert variable, so that it could be found later
3429             QuickInsert( pRes );
3430 
3431             // Take us out as listener at once,
3432             // the values are all constant
3433             if( pRes->IsBroadcaster() )
3434                 EndListening( pRes->GetBroadcaster(), true );
3435         }
3436     }
3437     return pRes;
3438 }
3439 
3440 
3441 SbUnoService* findUnoService( const OUString& rName )
3442 {
3443     SbUnoService* pSbUnoService = nullptr;
3444 
3445     const Reference< XHierarchicalNameAccess >& xTypeAccess = getTypeProvider_Impl();
3446     if( xTypeAccess->hasByHierarchicalName( rName ) )
3447     {
3448         Any aRet = xTypeAccess->getByHierarchicalName( rName );
3449         Reference< XTypeDescription > xTypeDesc;
3450         aRet >>= xTypeDesc;
3451 
3452         if( xTypeDesc.is() )
3453         {
3454             TypeClass eTypeClass = xTypeDesc->getTypeClass();
3455             if( eTypeClass == TypeClass_SERVICE )
3456             {
3457                 Reference< XServiceTypeDescription2 > xServiceTypeDesc( xTypeDesc, UNO_QUERY );
3458                 if( xServiceTypeDesc.is() )
3459                     pSbUnoService = new SbUnoService( rName, xServiceTypeDesc );
3460             }
3461         }
3462     }
3463     return pSbUnoService;
3464 }
3465 
3466 SbxVariable* SbUnoService::Find( const OUString& rName, SbxClassType )
3467 {
3468     SbxVariable* pRes = SbxObject::Find( rName, SbxClassType::Method );
3469 
3470     if( !pRes )
3471     {
3472         // If it is already a class ask for a field
3473         if( m_bNeedsInit && m_xServiceTypeDesc.is() )
3474         {
3475             m_bNeedsInit = false;
3476 
3477             Sequence< Reference< XServiceConstructorDescription > > aSCDSeq = m_xServiceTypeDesc->getConstructors();
3478             const Reference< XServiceConstructorDescription >* pCtorSeq = aSCDSeq.getConstArray();
3479             int nCtorCount = aSCDSeq.getLength();
3480             for( int i = 0 ; i < nCtorCount ; ++i )
3481             {
3482                 Reference< XServiceConstructorDescription > xCtor = pCtorSeq[i];
3483 
3484                 OUString aName( xCtor->getName() );
3485                 if( aName.isEmpty() )
3486                 {
3487                     if( xCtor->isDefaultConstructor() )
3488                     {
3489                         aName = "create";
3490                     }
3491                 }
3492 
3493                 if( !aName.isEmpty() )
3494                 {
3495                     // Create and insert SbUnoServiceCtor
3496                     SbxVariableRef xSbCtorRef = new SbUnoServiceCtor( aName, xCtor );
3497                     QuickInsert( xSbCtorRef.get() );
3498                 }
3499             }
3500             pRes = SbxObject::Find( rName, SbxClassType::Method );
3501         }
3502     }
3503 
3504     return pRes;
3505 }
3506 
3507 void SbUnoService::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
3508 {
3509     const SbxHint* pHint = dynamic_cast<const SbxHint*>(&rHint);
3510     if( pHint )
3511     {
3512         SbxVariable* pVar = pHint->GetVar();
3513         SbxArray* pParams = pVar->GetParameters();
3514         SbUnoServiceCtor* pUnoCtor = dynamic_cast<SbUnoServiceCtor*>( pVar );
3515         if( pUnoCtor && pHint->GetId() == SfxHintId::BasicDataWanted )
3516         {
3517             // Parameter count -1 because of Param0 == this
3518             sal_uInt32 nParamCount = pParams ? (static_cast<sal_uInt32>(pParams->Count()) - 1) : 0;
3519             Sequence<Any> args;
3520 
3521             Reference< XServiceConstructorDescription > xCtor = pUnoCtor->getServiceCtorDesc();
3522             Sequence< Reference< XParameter > > aParameterSeq = xCtor->getParameters();
3523             const Reference< XParameter >* pParameterSeq = aParameterSeq.getConstArray();
3524             sal_uInt32 nUnoParamCount = aParameterSeq.getLength();
3525 
3526             // Default: Ignore not needed parameters
3527             bool bParameterError = false;
3528 
3529             // Is the last parameter a rest parameter?
3530             bool bRestParameterMode = false;
3531             if( nUnoParamCount > 0 )
3532             {
3533                 Reference< XParameter > xLastParam = pParameterSeq[ nUnoParamCount - 1 ];
3534                 if( xLastParam.is() )
3535                 {
3536                     if( xLastParam->isRestParameter() )
3537                         bRestParameterMode = true;
3538                 }
3539             }
3540 
3541             // Too many parameters with context as first parameter?
3542             sal_uInt16 nSbxParameterOffset = 1;
3543             sal_uInt16 nParameterOffsetByContext = 0;
3544             Reference < XComponentContext > xFirstParamContext;
3545             if( nParamCount > nUnoParamCount )
3546             {
3547                 // Check if first parameter is a context and use it
3548                 // then in createInstanceWithArgumentsAndContext
3549                 Any aArg0 = sbxToUnoValue( pParams->Get( nSbxParameterOffset ) );
3550                 if( (aArg0 >>= xFirstParamContext) && xFirstParamContext.is() )
3551                     nParameterOffsetByContext = 1;
3552             }
3553 
3554             sal_uInt32 nEffectiveParamCount = nParamCount - nParameterOffsetByContext;
3555             sal_uInt32 nAllocParamCount = nEffectiveParamCount;
3556             if( nEffectiveParamCount > nUnoParamCount )
3557             {
3558                 if( !bRestParameterMode )
3559                 {
3560                     nEffectiveParamCount = nUnoParamCount;
3561                     nAllocParamCount = nUnoParamCount;
3562                 }
3563             }
3564             // Not enough parameters?
3565             else if( nUnoParamCount > nEffectiveParamCount )
3566             {
3567                 // RestParameterMode only helps if one (the last) parameter is missing
3568                 int nDiff = nUnoParamCount - nEffectiveParamCount;
3569                 if( !bRestParameterMode || nDiff > 1 )
3570                 {
3571                     bParameterError = true;
3572                     StarBASIC::Error( ERRCODE_BASIC_NOT_OPTIONAL );
3573                 }
3574             }
3575 
3576             if( !bParameterError )
3577             {
3578                 bool bOutParams = false;
3579                 if( nAllocParamCount > 0 )
3580                 {
3581                     args.realloc( nAllocParamCount );
3582                     Any* pAnyArgs = args.getArray();
3583                     for( sal_uInt32 i = 0 ; i < nEffectiveParamCount ; i++ )
3584                     {
3585                         sal_uInt16 iSbx = static_cast<sal_uInt16>(i + nSbxParameterOffset + nParameterOffsetByContext);
3586 
3587                         // bRestParameterMode allows nEffectiveParamCount > nUnoParamCount
3588                         Reference< XParameter > xParam;
3589                         if( i < nUnoParamCount )
3590                         {
3591                             xParam = pParameterSeq[i];
3592                             if( !xParam.is() )
3593                                 continue;
3594 
3595                             Reference< XTypeDescription > xParamTypeDesc = xParam->getType();
3596                             if( !xParamTypeDesc.is() )
3597                                 continue;
3598                             css::uno::Type aType( xParamTypeDesc->getTypeClass(), xParamTypeDesc->getName() );
3599 
3600                             // sbx parameter needs offset 1
3601                             pAnyArgs[i] = sbxToUnoValue( pParams->Get( iSbx ), aType );
3602 
3603                             // Check for out parameter if not already done
3604                             if( !bOutParams && xParam->isOut() )
3605                                 bOutParams = true;
3606                         }
3607                         else
3608                         {
3609                             pAnyArgs[i] = sbxToUnoValue( pParams->Get( iSbx ) );
3610                         }
3611                     }
3612                 }
3613 
3614                 // "Call" ctor using createInstanceWithArgumentsAndContext
3615                 Reference < XComponentContext > xContext(
3616                     xFirstParamContext.is()
3617                     ? xFirstParamContext
3618                     : comphelper::getProcessComponentContext() );
3619                 Reference< XMultiComponentFactory > xServiceMgr( xContext->getServiceManager() );
3620 
3621                 Any aRetAny;
3622                 OUString aServiceName = GetName();
3623                 Reference < XInterface > xRet;
3624                 try
3625                 {
3626                     xRet = xServiceMgr->createInstanceWithArgumentsAndContext( aServiceName, args, xContext );
3627                 }
3628                 catch( const Exception& )
3629                 {
3630                     implHandleAnyException( ::cppu::getCaughtException() );
3631                 }
3632                 aRetAny <<= xRet;
3633                 unoToSbxValue( pVar, aRetAny );
3634 
3635                 // Copy back out parameters?
3636                 if( bOutParams )
3637                 {
3638                     const Any* pAnyArgs = args.getConstArray();
3639 
3640                     for( sal_uInt32 j = 0 ; j < nUnoParamCount ; j++ )
3641                     {
3642                         Reference< XParameter > xParam = pParameterSeq[j];
3643                         if( !xParam.is() )
3644                             continue;
3645 
3646                         if( xParam->isOut() )
3647                             unoToSbxValue( pParams->Get( static_cast<sal_uInt16>(j+1) ), pAnyArgs[ j ] );
3648                     }
3649                 }
3650             }
3651         }
3652         else
3653             SbxObject::Notify( rBC, rHint );
3654     }
3655 }
3656 
3657 
3658 SbUnoServiceCtor::SbUnoServiceCtor( const OUString& aName_, Reference< XServiceConstructorDescription > const & xServiceCtorDesc )
3659     : SbxMethod( aName_, SbxOBJECT )
3660     , m_xServiceCtorDesc( xServiceCtorDesc )
3661 {
3662 }
3663 
3664 SbUnoServiceCtor::~SbUnoServiceCtor()
3665 {
3666 }
3667 
3668 SbxInfo* SbUnoServiceCtor::GetInfo()
3669 {
3670     SbxInfo* pRet = nullptr;
3671 
3672     return pRet;
3673 }
3674 
3675 
3676 SbUnoSingleton* findUnoSingleton( const OUString& rName )
3677 {
3678     SbUnoSingleton* pSbUnoSingleton = nullptr;
3679 
3680     const Reference< XHierarchicalNameAccess >& xTypeAccess = getTypeProvider_Impl();
3681     if( xTypeAccess->hasByHierarchicalName( rName ) )
3682     {
3683         Any aRet = xTypeAccess->getByHierarchicalName( rName );
3684         Reference< XTypeDescription > xTypeDesc;
3685         aRet >>= xTypeDesc;
3686 
3687         if( xTypeDesc.is() )
3688         {
3689             TypeClass eTypeClass = xTypeDesc->getTypeClass();
3690             if( eTypeClass == TypeClass_SINGLETON )
3691             {
3692                 Reference< XSingletonTypeDescription > xSingletonTypeDesc( xTypeDesc, UNO_QUERY );
3693                 if( xSingletonTypeDesc.is() )
3694                     pSbUnoSingleton = new SbUnoSingleton( rName );
3695             }
3696         }
3697     }
3698     return pSbUnoSingleton;
3699 }
3700 
3701 SbUnoSingleton::SbUnoSingleton( const OUString& aName_ )
3702         : SbxObject( aName_ )
3703 {
3704     SbxVariableRef xGetMethodRef = new SbxMethod( "get", SbxOBJECT );
3705     QuickInsert( xGetMethodRef.get() );
3706 }
3707 
3708 void SbUnoSingleton::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
3709 {
3710     const SbxHint* pHint = dynamic_cast<const SbxHint*>(&rHint);
3711     if( pHint )
3712     {
3713         SbxVariable* pVar = pHint->GetVar();
3714         SbxArray* pParams = pVar->GetParameters();
3715         sal_uInt32 nParamCount = pParams ? (static_cast<sal_uInt32>(pParams->Count()) - 1) : 0;
3716         sal_uInt32 nAllowedParamCount = 1;
3717 
3718         Reference < XComponentContext > xContextToUse;
3719         if( nParamCount > 0 )
3720         {
3721             // Check if first parameter is a context and use it then
3722             Reference < XComponentContext > xFirstParamContext;
3723             Any aArg1 = sbxToUnoValue( pParams->Get( 1 ) );
3724             if( (aArg1 >>= xFirstParamContext) && xFirstParamContext.is() )
3725                 xContextToUse = xFirstParamContext;
3726         }
3727 
3728         if( !xContextToUse.is() )
3729         {
3730             xContextToUse = comphelper::getProcessComponentContext();
3731             --nAllowedParamCount;
3732         }
3733 
3734         if( nParamCount > nAllowedParamCount )
3735         {
3736             StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
3737             return;
3738         }
3739 
3740         Any aRetAny;
3741         if( xContextToUse.is() )
3742         {
3743             OUString aSingletonName = "/singletons/"
3744                                     + GetName();
3745             Reference < XInterface > xRet;
3746             xContextToUse->getValueByName( aSingletonName ) >>= xRet;
3747             aRetAny <<= xRet;
3748         }
3749         unoToSbxValue( pVar, aRetAny );
3750     }
3751     else
3752     {
3753         SbxObject::Notify( rBC, rHint );
3754     }
3755 }
3756 
3757 
3758 // Implementation of an EventAttacher-drawn AllListener, which
3759 // solely transmits several events to a general AllListener
3760 class BasicAllListener_Impl : public WeakImplHelper< XAllListener >
3761 {
3762     void firing_impl(const AllEventObject& Event, Any* pRet);
3763 
3764 public:
3765     SbxObjectRef    xSbxObj;
3766     OUString        aPrefixName;
3767 
3768     explicit BasicAllListener_Impl( const OUString& aPrefixName );
3769 
3770     // Methods of XAllListener
3771     virtual void SAL_CALL firing(const AllEventObject& Event) override;
3772     virtual Any SAL_CALL approveFiring(const AllEventObject& Event) override;
3773 
3774     // Methods of XEventListener
3775     virtual void SAL_CALL disposing(const EventObject& Source) override;
3776 };
3777 
3778 
3779 BasicAllListener_Impl::BasicAllListener_Impl(const OUString& aPrefixName_)
3780     : aPrefixName( aPrefixName_ )
3781 {
3782 }
3783 
3784 void BasicAllListener_Impl::firing_impl( const AllEventObject& Event, Any* pRet )
3785 {
3786     SolarMutexGuard guard;
3787 
3788     if( xSbxObj.is() )
3789     {
3790         OUString aMethodName = aPrefixName + Event.MethodName;
3791 
3792         SbxVariable * pP = xSbxObj.get();
3793         while( pP->GetParent() )
3794         {
3795             pP = pP->GetParent();
3796             StarBASIC * pLib = dynamic_cast<StarBASIC*>( pP );
3797             if( pLib )
3798             {
3799                 // Create in a Basic Array
3800                 SbxArrayRef xSbxArray = new SbxArray( SbxVARIANT );
3801                 const Any * pArgs = Event.Arguments.getConstArray();
3802                 sal_Int32 nCount = Event.Arguments.getLength();
3803                 for( sal_Int32 i = 0; i < nCount; i++ )
3804                 {
3805                     // Convert elements
3806                     SbxVariableRef xVar = new SbxVariable( SbxVARIANT );
3807                     unoToSbxValue( xVar.get(), pArgs[i] );
3808                     xSbxArray->Put( xVar.get(), sal::static_int_cast< sal_uInt16 >(i+1) );
3809                 }
3810 
3811                 pLib->Call( aMethodName, xSbxArray.get() );
3812 
3813                 // get the return value from the Param-Array, if requested
3814                 if( pRet )
3815                 {
3816                     SbxVariable* pVar = xSbxArray->Get( 0 );
3817                     if( pVar )
3818                     {
3819                         // #95792 Avoid a second call
3820                         SbxFlagBits nFlags = pVar->GetFlags();
3821                         pVar->SetFlag( SbxFlagBits::NoBroadcast );
3822                         *pRet = sbxToUnoValueImpl( pVar );
3823                         pVar->SetFlags( nFlags );
3824                     }
3825                 }
3826                 break;
3827             }
3828         }
3829     }
3830 }
3831 
3832 
3833 // Methods of Listener
3834 void BasicAllListener_Impl::firing( const AllEventObject& Event )
3835 {
3836     firing_impl( Event, nullptr );
3837 }
3838 
3839 Any BasicAllListener_Impl::approveFiring( const AllEventObject& Event )
3840 {
3841     Any aRetAny;
3842     firing_impl( Event, &aRetAny );
3843     return aRetAny;
3844 }
3845 
3846 
3847 // Methods of XEventListener
3848 void BasicAllListener_Impl ::disposing(const EventObject& )
3849 {
3850     SolarMutexGuard guard;
3851 
3852     xSbxObj.clear();
3853 }
3854 
3855 
3856 //  class InvocationToAllListenerMapper
3857 //  helper class to map XInvocation to XAllListener (also in project eventattacher!)
3858 
3859 class InvocationToAllListenerMapper : public WeakImplHelper< XInvocation >
3860 {
3861 public:
3862     InvocationToAllListenerMapper( const Reference< XIdlClass >& ListenerType,
3863         const Reference< XAllListener >& AllListener, const Any& Helper );
3864 
3865     // XInvocation
3866     virtual Reference< XIntrospectionAccess > SAL_CALL getIntrospection() override;
3867     virtual Any SAL_CALL invoke(const OUString& FunctionName, const Sequence< Any >& Params, Sequence< sal_Int16 >& OutParamIndex, Sequence< Any >& OutParam) override;
3868     virtual void SAL_CALL setValue(const OUString& PropertyName, const Any& Value) override;
3869     virtual Any SAL_CALL getValue(const OUString& PropertyName) override;
3870     virtual sal_Bool SAL_CALL hasMethod(const OUString& Name) override;
3871     virtual sal_Bool SAL_CALL hasProperty(const OUString& Name) override;
3872 
3873 private:
3874     Reference< XAllListener >    m_xAllListener;
3875     Reference< XIdlClass >       m_xListenerType;
3876     Any                          m_Helper;
3877 };
3878 
3879 
3880 // Function to replace AllListenerAdapterService::createAllListerAdapter
3881 static Reference< XInterface > createAllListenerAdapter
3882 (
3883     const Reference< XInvocationAdapterFactory2 >& xInvocationAdapterFactory,
3884     const Reference< XIdlClass >& xListenerType,
3885     const Reference< XAllListener >& xListener,
3886     const Any& Helper
3887 )
3888 {
3889     Reference< XInterface > xAdapter;
3890     if( xInvocationAdapterFactory.is() && xListenerType.is() && xListener.is() )
3891     {
3892         Reference< XInvocation > xInvocationToAllListenerMapper =
3893             new InvocationToAllListenerMapper(xListenerType, xListener, Helper);
3894         Type aListenerType( xListenerType->getTypeClass(), xListenerType->getName() );
3895         Sequence<Type> arg2(1);
3896         arg2[0] = aListenerType;
3897         xAdapter = xInvocationAdapterFactory->createAdapter( xInvocationToAllListenerMapper, arg2 );
3898     }
3899     return xAdapter;
3900 }
3901 
3902 
3903 // InvocationToAllListenerMapper
3904 InvocationToAllListenerMapper::InvocationToAllListenerMapper
3905     ( const Reference< XIdlClass >& ListenerType, const Reference< XAllListener >& AllListener, const Any& Helper )
3906         : m_xAllListener( AllListener )
3907         , m_xListenerType( ListenerType )
3908         , m_Helper( Helper )
3909 {
3910 }
3911 
3912 
3913 Reference< XIntrospectionAccess > SAL_CALL InvocationToAllListenerMapper::getIntrospection()
3914 {
3915     return Reference< XIntrospectionAccess >();
3916 }
3917 
3918 
3919 Any SAL_CALL InvocationToAllListenerMapper::invoke(const OUString& FunctionName, const Sequence< Any >& Params,
3920     Sequence< sal_Int16 >&, Sequence< Any >&)
3921 {
3922     Any aRet;
3923 
3924     // Check if to firing or approveFiring has to be called
3925     Reference< XIdlMethod > xMethod = m_xListenerType->getMethod( FunctionName );
3926     bool bApproveFiring = false;
3927     if( !xMethod.is() )
3928         return aRet;
3929     Reference< XIdlClass > xReturnType = xMethod->getReturnType();
3930     Sequence< Reference< XIdlClass > > aExceptionSeq = xMethod->getExceptionTypes();
3931     if( ( xReturnType.is() && xReturnType->getTypeClass() != TypeClass_VOID ) ||
3932         aExceptionSeq.getLength() > 0 )
3933     {
3934         bApproveFiring = true;
3935     }
3936     else
3937     {
3938         Sequence< ParamInfo > aParamSeq = xMethod->getParameterInfos();
3939         sal_uInt32 nParamCount = aParamSeq.getLength();
3940         if( nParamCount > 1 )
3941         {
3942             const ParamInfo* pInfo = aParamSeq.getConstArray();
3943             for( sal_uInt32 i = 0 ; i < nParamCount ; i++ )
3944             {
3945                 if( pInfo[ i ].aMode != ParamMode_IN )
3946                 {
3947                     bApproveFiring = true;
3948                     break;
3949                 }
3950             }
3951         }
3952     }
3953 
3954     AllEventObject aAllEvent;
3955     aAllEvent.Source = static_cast<OWeakObject*>(this);
3956     aAllEvent.Helper = m_Helper;
3957     aAllEvent.ListenerType = Type(m_xListenerType->getTypeClass(), m_xListenerType->getName() );
3958     aAllEvent.MethodName = FunctionName;
3959     aAllEvent.Arguments = Params;
3960     if( bApproveFiring )
3961         aRet = m_xAllListener->approveFiring( aAllEvent );
3962     else
3963         m_xAllListener->firing( aAllEvent );
3964     return aRet;
3965 }
3966 
3967 
3968 void SAL_CALL InvocationToAllListenerMapper::setValue(const OUString&, const Any&)
3969 {}
3970 
3971 
3972 Any SAL_CALL InvocationToAllListenerMapper::getValue(const OUString&)
3973 {
3974     return Any();
3975 }
3976 
3977 
3978 sal_Bool SAL_CALL InvocationToAllListenerMapper::hasMethod(const OUString& Name)
3979 {
3980     Reference< XIdlMethod > xMethod = m_xListenerType->getMethod( Name );
3981     return xMethod.is();
3982 }
3983 
3984 
3985 sal_Bool SAL_CALL InvocationToAllListenerMapper::hasProperty(const OUString& Name)
3986 {
3987     Reference< XIdlField > xField = m_xListenerType->getField( Name );
3988     return xField.is();
3989 }
3990 
3991 
3992 // create Uno-Service
3993 // 1. Parameter == Prefix-Name of the macro
3994 // 2. Parameter == fully qualified name of the listener
3995 void SbRtl_CreateUnoListener(StarBASIC * pBasic, SbxArray & rPar, bool)
3996 {
3997     // We need 2 parameters
3998     if ( rPar.Count() != 3 )
3999     {
4000         StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
4001         return;
4002     }
4003 
4004     // get the name of the class of the struct
4005     OUString aPrefixName = rPar.Get(1)->GetOUString();
4006     OUString aListenerClassName = rPar.Get(2)->GetOUString();
4007 
4008     // get the CoreReflection
4009     Reference< XIdlReflection > xCoreReflection = getCoreReflection_Impl();
4010     if( !xCoreReflection.is() )
4011         return;
4012 
4013     // get the AllListenerAdapterService
4014     Reference< XComponentContext > xContext( comphelper::getProcessComponentContext() );
4015 
4016     // search the class
4017     Reference< XIdlClass > xClass = xCoreReflection->forName( aListenerClassName );
4018     if( !xClass.is() )
4019         return;
4020 
4021     // From 1999-11-30: get the InvocationAdapterFactory
4022     Reference< XInvocationAdapterFactory2 > xInvocationAdapterFactory =
4023          InvocationAdapterFactory::create( xContext );
4024 
4025     BasicAllListener_Impl * p;
4026     Reference< XAllListener > xAllLst = p = new BasicAllListener_Impl( aPrefixName );
4027     Any aTmp;
4028     Reference< XInterface > xLst = createAllListenerAdapter( xInvocationAdapterFactory, xClass, xAllLst, aTmp );
4029     if( !xLst.is() )
4030         return;
4031 
4032     OUString aClassName = xClass->getName();
4033     Type aClassType( xClass->getTypeClass(), aClassName );
4034     aTmp = xLst->queryInterface( aClassType );
4035     if( !aTmp.hasValue() )
4036         return;
4037 
4038     SbUnoObject* pUnoObj = new SbUnoObject( aListenerClassName, aTmp );
4039     p->xSbxObj = pUnoObj;
4040     p->xSbxObj->SetParent( pBasic );
4041 
4042     // #100326 Register listener object to set Parent NULL in Dtor
4043     SbxArrayRef xBasicUnoListeners = pBasic->getUnoListeners();
4044     xBasicUnoListeners->Insert( pUnoObj, xBasicUnoListeners->Count() );
4045 
4046     // return the object
4047     SbxVariableRef refVar = rPar.Get(0);
4048     refVar->PutObject( p->xSbxObj.get() );
4049 }
4050 
4051 
4052 // Represents the DefaultContext property of the ProcessServiceManager
4053 // in the Basic runtime system.
4054 void RTL_Impl_GetDefaultContext( SbxArray& rPar )
4055 {
4056     SbxVariableRef refVar = rPar.Get(0);
4057 
4058     Any aContextAny( comphelper::getProcessComponentContext() );
4059 
4060     SbUnoObjectRef xUnoObj = new SbUnoObject( "DefaultContext", aContextAny );
4061     refVar->PutObject( xUnoObj.get() );
4062 }
4063 
4064 
4065 // Creates a Basic wrapper object for a strongly typed Uno value
4066 // 1. parameter: Uno type as full qualified type name, e.g. "byte[]"
4067 void RTL_Impl_CreateUnoValue( SbxArray& rPar )
4068 {
4069     // 2 parameters needed
4070     if ( rPar.Count() != 3 )
4071     {
4072         StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
4073         return;
4074     }
4075 
4076     // get the name of the class of the struct
4077     OUString aTypeName = rPar.Get(1)->GetOUString();
4078     SbxVariable* pVal = rPar.Get(2);
4079 
4080     if( aTypeName == "type" )
4081     {
4082         SbxDataType eBaseType = pVal->SbxValue::GetType();
4083         OUString aValTypeName;
4084         if( eBaseType == SbxSTRING )
4085         {
4086             aValTypeName = pVal->GetOUString();
4087         }
4088         else if( eBaseType == SbxOBJECT )
4089         {
4090             // XIdlClass?
4091             Reference< XIdlClass > xIdlClass;
4092 
4093             SbxBaseRef pObj = pVal->GetObject();
4094             if( auto obj = dynamic_cast<SbUnoObject*>( pObj.get() ) )
4095             {
4096                 Any aUnoAny = obj->getUnoAny();
4097                 aUnoAny >>= xIdlClass;
4098             }
4099 
4100             if( xIdlClass.is() )
4101             {
4102                 aValTypeName = xIdlClass->getName();
4103             }
4104         }
4105         Type aType;
4106         bool bSuccess = implGetTypeByName( aValTypeName, aType );
4107         if( bSuccess )
4108         {
4109             Any aTypeAny( aType );
4110             SbxVariableRef refVar = rPar.Get(0);
4111             SbxObjectRef xUnoAnyObject = new SbUnoAnyObject( aTypeAny );
4112             refVar->PutObject( xUnoAnyObject.get() );
4113         }
4114         return;
4115     }
4116 
4117     // Check the type
4118     const Reference< XHierarchicalNameAccess >& xTypeAccess = getTypeProvider_Impl();
4119     Any aRet;
4120     try
4121     {
4122         aRet = xTypeAccess->getByHierarchicalName( aTypeName );
4123     }
4124     catch( const NoSuchElementException& e1 )
4125     {
4126         StarBASIC::Error( ERRCODE_BASIC_EXCEPTION,
4127             implGetExceptionMsg( e1, "com.sun.star.container.NoSuchElementException" ) );
4128         return;
4129     }
4130     Reference< XTypeDescription > xTypeDesc;
4131     aRet >>= xTypeDesc;
4132     TypeClass eTypeClass = xTypeDesc->getTypeClass();
4133     Type aDestType( eTypeClass, aTypeName );
4134 
4135 
4136     // Preconvert value
4137     Any aVal = sbxToUnoValueImpl( pVal );
4138     Any aConvertedVal = convertAny( aVal, aDestType );
4139 
4140     SbxVariableRef refVar = rPar.Get(0);
4141     SbxObjectRef xUnoAnyObject = new SbUnoAnyObject( aConvertedVal );
4142     refVar->PutObject( xUnoAnyObject.get() );
4143 }
4144 
4145 
4146 class ModuleInvocationProxy : public WeakImplHelper< XInvocation, XComponent >
4147 {
4148     ::osl::Mutex        m_aMutex;
4149     OUString            m_aPrefix;
4150     SbxObjectRef        m_xScopeObj;
4151     bool                m_bProxyIsClassModuleObject;
4152 
4153     ::comphelper::OInterfaceContainerHelper2 m_aListeners;
4154 
4155 public:
4156     ModuleInvocationProxy( OUString const & aPrefix, SbxObjectRef const & xScopeObj );
4157 
4158     // XInvocation
4159     virtual Reference< XIntrospectionAccess > SAL_CALL getIntrospection() override;
4160     virtual void SAL_CALL setValue( const OUString& rProperty, const Any& rValue ) override;
4161     virtual Any SAL_CALL getValue( const OUString& rProperty ) override;
4162     virtual sal_Bool SAL_CALL hasMethod( const OUString& rName ) override;
4163     virtual sal_Bool SAL_CALL hasProperty( const OUString& rProp ) override;
4164 
4165     virtual Any SAL_CALL invoke( const OUString& rFunction,
4166                                  const Sequence< Any >& rParams,
4167                                  Sequence< sal_Int16 >& rOutParamIndex,
4168                                  Sequence< Any >& rOutParam ) override;
4169 
4170     // XComponent
4171     virtual void SAL_CALL dispose() override;
4172     virtual void SAL_CALL addEventListener( const Reference< XEventListener >& xListener ) override;
4173     virtual void SAL_CALL removeEventListener( const Reference< XEventListener >& aListener ) override;
4174 };
4175 
4176 ModuleInvocationProxy::ModuleInvocationProxy( OUString const & aPrefix, SbxObjectRef const & xScopeObj )
4177     : m_aMutex()
4178     , m_aPrefix( aPrefix + "_" )
4179     , m_xScopeObj( xScopeObj )
4180     , m_aListeners( m_aMutex )
4181 {
4182     m_bProxyIsClassModuleObject = xScopeObj.is() && dynamic_cast<const SbClassModuleObject*>( xScopeObj.get() ) != nullptr;
4183 }
4184 
4185 Reference< XIntrospectionAccess > SAL_CALL ModuleInvocationProxy::getIntrospection()
4186 {
4187     return Reference< XIntrospectionAccess >();
4188 }
4189 
4190 void SAL_CALL ModuleInvocationProxy::setValue(const OUString& rProperty, const Any& rValue)
4191 {
4192     if( !m_bProxyIsClassModuleObject )
4193         throw UnknownPropertyException();
4194 
4195     SolarMutexGuard guard;
4196 
4197     OUString aPropertyFunctionName = "Property Set "
4198                                    + m_aPrefix
4199                                    + rProperty;
4200 
4201     SbxVariable* p = m_xScopeObj->Find( aPropertyFunctionName, SbxClassType::Method );
4202     SbMethod* pMeth = dynamic_cast<SbMethod*>( p );
4203     if( pMeth == nullptr )
4204     {
4205         // TODO: Check vba behavior concerning missing function
4206         //StarBASIC::Error( ERRCODE_BASIC_NO_METHOD, aFunctionName );
4207         throw UnknownPropertyException();
4208     }
4209 
4210     // Setup parameter
4211     SbxArrayRef xArray = new SbxArray;
4212     SbxVariableRef xVar = new SbxVariable( SbxVARIANT );
4213     unoToSbxValue( xVar.get(), rValue );
4214     xArray->Put( xVar.get(), 1 );
4215 
4216     // Call property method
4217     SbxVariableRef xValue = new SbxVariable;
4218     pMeth->SetParameters( xArray.get() );
4219     pMeth->Call( xValue.get() );
4220     pMeth->SetParameters( nullptr );
4221 
4222     // TODO: OutParameter?
4223 
4224 
4225 }
4226 
4227 Any SAL_CALL ModuleInvocationProxy::getValue(const OUString& rProperty)
4228 {
4229     if( !m_bProxyIsClassModuleObject )
4230     {
4231         throw UnknownPropertyException();
4232     }
4233     SolarMutexGuard guard;
4234 
4235     OUString aPropertyFunctionName = "Property Get "
4236                                    + m_aPrefix
4237                                    + rProperty;
4238 
4239     SbxVariable* p = m_xScopeObj->Find( aPropertyFunctionName, SbxClassType::Method );
4240     SbMethod* pMeth = dynamic_cast<SbMethod*>( p );
4241     if( pMeth == nullptr )
4242     {
4243         // TODO: Check vba behavior concerning missing function
4244         //StarBASIC::Error( ERRCODE_BASIC_NO_METHOD, aFunctionName );
4245         throw UnknownPropertyException();
4246     }
4247 
4248     // Call method
4249     SbxVariableRef xValue = new SbxVariable;
4250     pMeth->Call( xValue.get() );
4251     Any aRet = sbxToUnoValue( xValue.get() );
4252     return aRet;
4253 }
4254 
4255 sal_Bool SAL_CALL ModuleInvocationProxy::hasMethod( const OUString& )
4256 {
4257     return false;
4258 }
4259 
4260 sal_Bool SAL_CALL ModuleInvocationProxy::hasProperty( const OUString& )
4261 {
4262     return false;
4263 }
4264 
4265 Any SAL_CALL ModuleInvocationProxy::invoke( const OUString& rFunction,
4266                                             const Sequence< Any >& rParams,
4267                                             Sequence< sal_Int16 >&,
4268                                             Sequence< Any >& )
4269 {
4270     SolarMutexGuard guard;
4271 
4272     Any aRet;
4273     SbxObjectRef xScopeObj = m_xScopeObj;
4274     if( !xScopeObj.is() )
4275     {
4276         return aRet;
4277     }
4278     OUString aFunctionName = m_aPrefix
4279                            + rFunction;
4280 
4281     bool bSetRescheduleBack = false;
4282     bool bOldReschedule = true;
4283     SbiInstance* pInst = GetSbData()->pInst;
4284     if( pInst && pInst->IsCompatibility() )
4285     {
4286         bOldReschedule = pInst->IsReschedule();
4287         if ( bOldReschedule )
4288         {
4289             pInst->EnableReschedule( false );
4290             bSetRescheduleBack = true;
4291         }
4292     }
4293 
4294     SbxVariable* p = xScopeObj->Find( aFunctionName, SbxClassType::Method );
4295     SbMethod* pMeth = dynamic_cast<SbMethod*>( p );
4296     if( pMeth == nullptr )
4297     {
4298         // TODO: Check vba behavior concerning missing function
4299         //StarBASIC::Error( ERRCODE_BASIC_NO_METHOD, aFunctionName );
4300         return aRet;
4301     }
4302 
4303     // Setup parameters
4304     SbxArrayRef xArray;
4305     sal_Int32 nParamCount = rParams.getLength();
4306     if( nParamCount )
4307     {
4308         xArray = new SbxArray;
4309         const Any *pArgs = rParams.getConstArray();
4310         for( sal_Int32 i = 0 ; i < nParamCount ; i++ )
4311         {
4312             SbxVariableRef xVar = new SbxVariable( SbxVARIANT );
4313             unoToSbxValue( xVar.get(), pArgs[i] );
4314             xArray->Put( xVar.get(), sal::static_int_cast< sal_uInt16 >(i+1) );
4315         }
4316     }
4317 
4318     // Call method
4319     SbxVariableRef xValue = new SbxVariable;
4320     if( xArray.is() )
4321         pMeth->SetParameters( xArray.get() );
4322     pMeth->Call( xValue.get() );
4323     aRet = sbxToUnoValue( xValue.get() );
4324     pMeth->SetParameters( nullptr );
4325 
4326     if( bSetRescheduleBack )
4327         pInst->EnableReschedule( bOldReschedule );
4328 
4329     // TODO: OutParameter?
4330 
4331     return aRet;
4332 }
4333 
4334 void SAL_CALL ModuleInvocationProxy::dispose()
4335 {
4336     ::osl::MutexGuard aGuard( m_aMutex );
4337 
4338     EventObject aEvent( static_cast<XComponent*>(this) );
4339     m_aListeners.disposeAndClear( aEvent );
4340 
4341     m_xScopeObj = nullptr;
4342 }
4343 
4344 void SAL_CALL ModuleInvocationProxy::addEventListener( const Reference< XEventListener >& xListener )
4345 {
4346     m_aListeners.addInterface( xListener );
4347 }
4348 
4349 void SAL_CALL ModuleInvocationProxy::removeEventListener( const Reference< XEventListener >& xListener )
4350 {
4351     m_aListeners.removeInterface( xListener );
4352 }
4353 
4354 
4355 Reference< XInterface > createComListener( const Any& aControlAny, const OUString& aVBAType,
4356                                            const OUString& aPrefix, const SbxObjectRef& xScopeObj )
4357 {
4358     Reference< XInterface > xRet;
4359 
4360     Reference< XComponentContext > xContext(
4361         comphelper::getProcessComponentContext() );
4362     Reference< XMultiComponentFactory > xServiceMgr( xContext->getServiceManager() );
4363 
4364     Reference< XInvocation > xProxy = new ModuleInvocationProxy( aPrefix, xScopeObj );
4365 
4366     Sequence<Any> args( 3 );
4367     args[0] = aControlAny;
4368     args[1] <<= aVBAType;
4369     args[2] <<= xProxy;
4370 
4371     try
4372     {
4373         xRet = xServiceMgr->createInstanceWithArgumentsAndContext(
4374             "com.sun.star.custom.UnoComListener",
4375             args, xContext );
4376     }
4377     catch( const Exception& )
4378     {
4379         implHandleAnyException( ::cppu::getCaughtException() );
4380     }
4381 
4382     return xRet;
4383 }
4384 
4385 typedef std::vector< WeakReference< XComponent > >  ComponentRefVector;
4386 
4387 struct StarBasicDisposeItem
4388 {
4389     StarBASIC*              m_pBasic;
4390     SbxArrayRef             m_pRegisteredVariables;
4391     ComponentRefVector      m_vComImplementsObjects;
4392 
4393     explicit StarBasicDisposeItem( StarBASIC* pBasic )
4394         : m_pBasic( pBasic )
4395         , m_pRegisteredVariables(new SbxArray())
4396     {
4397     }
4398 };
4399 
4400 typedef std::vector< StarBasicDisposeItem* > DisposeItemVector;
4401 
4402 static DisposeItemVector GaDisposeItemVector;
4403 
4404 static DisposeItemVector::iterator lcl_findItemForBasic( StarBASIC const * pBasic )
4405 {
4406     return std::find_if(GaDisposeItemVector.begin(), GaDisposeItemVector.end(),
4407         [&pBasic](StarBasicDisposeItem* pItem) { return pItem->m_pBasic == pBasic; });
4408 }
4409 
4410 static StarBasicDisposeItem* lcl_getOrCreateItemForBasic( StarBASIC* pBasic )
4411 {
4412     DisposeItemVector::iterator it = lcl_findItemForBasic( pBasic );
4413     StarBasicDisposeItem* pItem = (it != GaDisposeItemVector.end()) ? *it : nullptr;
4414     if( pItem == nullptr )
4415     {
4416         pItem = new StarBasicDisposeItem( pBasic );
4417         GaDisposeItemVector.push_back( pItem );
4418     }
4419     return pItem;
4420 }
4421 
4422 void registerComponentToBeDisposedForBasic
4423     ( const Reference< XComponent >& xComponent, StarBASIC* pBasic )
4424 {
4425     StarBasicDisposeItem* pItem = lcl_getOrCreateItemForBasic( pBasic );
4426     pItem->m_vComImplementsObjects.emplace_back(xComponent );
4427 }
4428 
4429 void registerComListenerVariableForBasic( SbxVariable* pVar, StarBASIC* pBasic )
4430 {
4431     StarBasicDisposeItem* pItem = lcl_getOrCreateItemForBasic( pBasic );
4432     SbxArray* pArray = pItem->m_pRegisteredVariables.get();
4433     pArray->Put( pVar, pArray->Count() );
4434 }
4435 
4436 void disposeComVariablesForBasic( StarBASIC const * pBasic )
4437 {
4438     DisposeItemVector::iterator it = lcl_findItemForBasic( pBasic );
4439     if( it != GaDisposeItemVector.end() )
4440     {
4441         StarBasicDisposeItem* pItem = *it;
4442 
4443         SbxArray* pArray = pItem->m_pRegisteredVariables.get();
4444         sal_uInt16 nCount = pArray->Count();
4445         for( sal_uInt16 i = 0 ; i < nCount ; ++i )
4446         {
4447             SbxVariable* pVar = pArray->Get( i );
4448             pVar->ClearComListener();
4449         }
4450 
4451         ComponentRefVector& rv = pItem->m_vComImplementsObjects;
4452         for (auto const& elem : rv)
4453         {
4454             Reference< XComponent > xComponent( elem.get(), UNO_QUERY );
4455             if (xComponent.is())
4456                 xComponent->dispose();
4457         }
4458 
4459         delete pItem;
4460         GaDisposeItemVector.erase( it );
4461     }
4462 }
4463 
4464 
4465 // Handle module implements mechanism for OLE types
4466 bool SbModule::createCOMWrapperForIface( Any& o_rRetAny, SbClassModuleObject* pProxyClassModuleObject )
4467 {
4468     // For now: Take first interface that allows to instantiate COM wrapper
4469     // TODO: Check if support for multiple interfaces is needed
4470 
4471     Reference< XComponentContext > xContext(
4472         comphelper::getProcessComponentContext() );
4473     Reference< XMultiComponentFactory > xServiceMgr( xContext->getServiceManager() );
4474     Reference< XSingleServiceFactory > xComImplementsFactory
4475     (
4476         xServiceMgr->createInstanceWithContext( "com.sun.star.custom.ComImplementsFactory", xContext ),
4477         UNO_QUERY
4478     );
4479     if( !xComImplementsFactory.is() )
4480         return false;
4481 
4482     bool bSuccess = false;
4483 
4484     SbxArray* pModIfaces = pClassData->mxIfaces.get();
4485     sal_uInt16 nCount = pModIfaces->Count();
4486     for( sal_uInt16 i = 0 ; i < nCount ; ++i )
4487     {
4488         SbxVariable* pVar = pModIfaces->Get( i );
4489         const OUString& aIfaceName = pVar->GetName();
4490 
4491         if( !aIfaceName.isEmpty() )
4492         {
4493             OUString aPureIfaceName = aIfaceName;
4494             sal_Int32 indexLastDot = aIfaceName.lastIndexOf('.');
4495             if ( indexLastDot > -1 )
4496             {
4497                 aPureIfaceName = aIfaceName.copy( indexLastDot + 1 );
4498             }
4499             Reference< XInvocation > xProxy = new ModuleInvocationProxy( aPureIfaceName, pProxyClassModuleObject );
4500 
4501             Sequence<Any> args( 2 );
4502             args[0] <<= aIfaceName;
4503             args[1] <<= xProxy;
4504 
4505             Reference< XInterface > xRet;
4506             try
4507             {
4508                 xRet = xComImplementsFactory->createInstanceWithArguments( args );
4509                 bSuccess = true;
4510             }
4511             catch( const Exception& )
4512             {
4513                 implHandleAnyException( ::cppu::getCaughtException() );
4514             }
4515 
4516             if( bSuccess )
4517             {
4518                 Reference< XComponent > xComponent( xProxy, UNO_QUERY );
4519                 if( xComponent.is() )
4520                 {
4521                     StarBASIC* pParentBasic = nullptr;
4522                     SbxObject* pCurObject = this;
4523                     do
4524                     {
4525                         SbxObject* pObjParent = pCurObject->GetParent();
4526                         pParentBasic = dynamic_cast<StarBASIC*>( pObjParent  );
4527                         pCurObject = pObjParent;
4528                     }
4529                     while( pParentBasic == nullptr && pCurObject != nullptr );
4530 
4531                     OSL_ASSERT( pParentBasic != nullptr );
4532                     registerComponentToBeDisposedForBasic( xComponent, pParentBasic );
4533                 }
4534 
4535                 o_rRetAny <<= xRet;
4536                 break;
4537             }
4538         }
4539      }
4540 
4541     return bSuccess;
4542 }
4543 
4544 
4545 // Due to an incorrect behavior IE returns an object instead of a string
4546 // in some scenarios. Calling toString at the object may correct this.
4547 // Helper function used in sbxvalue.cxx
4548 bool handleToStringForCOMObjects( SbxObject* pObj, SbxValue* pVal )
4549 {
4550     bool bSuccess = false;
4551 
4552     if( auto pUnoObj = dynamic_cast<SbUnoObject*>( pObj) )
4553     {
4554         // Only for native COM objects
4555         if( pUnoObj->isNativeCOMObject() )
4556         {
4557             SbxVariableRef pMeth = pObj->Find( "toString", SbxClassType::Method );
4558             if ( pMeth.is() )
4559             {
4560                 SbxValues aRes;
4561                 pMeth->Get( aRes );
4562                 pVal->Put( aRes );
4563                 bSuccess = true;
4564             }
4565         }
4566     }
4567     return bSuccess;
4568 }
4569 
4570 Any StructRefInfo::getValue()
4571 {
4572     Any aRet;
4573     uno_any_destruct(
4574         &aRet, reinterpret_cast< uno_ReleaseFunc >(cpp_release) );
4575     typelib_TypeDescription * pTD = nullptr;
4576     maType.getDescription(&pTD);
4577     uno_any_construct(
4578         &aRet, getInst(), pTD,
4579                 reinterpret_cast< uno_AcquireFunc >(cpp_acquire) );
4580     typelib_typedescription_release(pTD);
4581     return aRet;
4582 }
4583 
4584 void StructRefInfo::setValue( const Any& rValue )
4585 {
4586     bool bSuccess = uno_type_assignData( getInst(),
4587        maType.getTypeLibType(),
4588        const_cast<void*>(rValue.getValue()),
4589        rValue.getValueTypeRef(),
4590        reinterpret_cast< uno_QueryInterfaceFunc >(cpp_queryInterface),
4591        reinterpret_cast< uno_AcquireFunc >(cpp_acquire),
4592        reinterpret_cast< uno_ReleaseFunc >(cpp_release) );
4593     OSL_ENSURE(bSuccess,
4594         "StructRefInfo::setValue: ooops .... the value could not be assigned!");
4595 }
4596 
4597 OUString StructRefInfo::getTypeName() const
4598 {
4599     return maType.getTypeName();
4600 }
4601 
4602 void* StructRefInfo::getInst()
4603 {
4604     return const_cast<char *>(static_cast<char const *>(maAny.getValue()) + mnPos);
4605 }
4606 
4607 TypeClass StructRefInfo::getTypeClass() const
4608 {
4609     return maType.getTypeClass();
4610 }
4611 
4612 SbUnoStructRefObject::SbUnoStructRefObject( const OUString& aName_, const StructRefInfo& rMemberInfo ) :  SbxObject( aName_ ), maMemberInfo( rMemberInfo ), mbMemberCacheInit( false )
4613 {
4614    SetClassName( maMemberInfo.getTypeName() );
4615 }
4616 
4617 SbUnoStructRefObject::~SbUnoStructRefObject()
4618 {
4619 }
4620 
4621 void SbUnoStructRefObject::initMemberCache()
4622 {
4623     if ( mbMemberCacheInit )
4624         return;
4625     typelib_TypeDescription * pTD = nullptr;
4626     maMemberInfo.getType().getDescription(&pTD);
4627     typelib_CompoundTypeDescription * pCompTypeDescr = reinterpret_cast<typelib_CompoundTypeDescription *>(pTD);
4628     for ( pCompTypeDescr = reinterpret_cast<typelib_CompoundTypeDescription *>(pTD); pCompTypeDescr;
4629         pCompTypeDescr = pCompTypeDescr->pBaseTypeDescription )
4630     {
4631         typelib_TypeDescriptionReference ** ppTypeRefs = pCompTypeDescr->ppTypeRefs;
4632         rtl_uString ** ppNames                         = pCompTypeDescr->ppMemberNames;
4633         sal_Int32 * pMemberOffsets                     = pCompTypeDescr->pMemberOffsets;
4634         for ( sal_Int32 nPos = pCompTypeDescr->nMembers; nPos--; )
4635         {
4636             OUString aName( ppNames[nPos] );
4637             maFields[ aName ] = std::make_unique<StructRefInfo>( maMemberInfo.getRootAnyRef(), ppTypeRefs[nPos], maMemberInfo.getPos() + pMemberOffsets[nPos] );
4638         }
4639     }
4640     typelib_typedescription_release(pTD);
4641     mbMemberCacheInit = true;
4642 }
4643 
4644 SbxVariable* SbUnoStructRefObject::Find( const OUString& rName, SbxClassType t )
4645 {
4646     SbxVariable* pRes = SbxObject::Find( rName, t );
4647     if ( !pRes )
4648     {
4649         if ( !mbMemberCacheInit )
4650             initMemberCache();
4651         StructFieldInfo::iterator it = maFields.find( rName );
4652         if ( it != maFields.end() )
4653         {
4654             SbxDataType eSbxType;
4655             eSbxType = unoToSbxType( it->second->getTypeClass() );
4656             SbxDataType eRealSbxType = eSbxType;
4657             Property aProp;
4658             aProp.Name = rName;
4659             aProp.Type = css::uno::Type( it->second->getTypeClass(), it->second->getTypeName() );
4660             SbUnoProperty* pProp = new SbUnoProperty( rName, eSbxType, eRealSbxType, aProp, 0, false, ( aProp.Type.getTypeClass() == css::uno::TypeClass_STRUCT) );
4661             SbxVariableRef xVarRef = pProp;
4662             QuickInsert( xVarRef.get() );
4663             pRes = xVarRef.get();
4664         }
4665     }
4666 
4667     if( !pRes )
4668     {
4669         if( rName.equalsIgnoreAsciiCase(ID_DBG_SUPPORTEDINTERFACES) ||
4670             rName.equalsIgnoreAsciiCase(ID_DBG_PROPERTIES) ||
4671             rName.equalsIgnoreAsciiCase(ID_DBG_METHODS) )
4672         {
4673             // Create
4674             implCreateDbgProperties();
4675 
4676             // Now they have to be found regular
4677             pRes = SbxObject::Find( rName, SbxClassType::DontCare );
4678         }
4679     }
4680 
4681     return pRes;
4682 }
4683 
4684 // help method to create the dbg_-Properties
4685 void SbUnoStructRefObject::implCreateDbgProperties()
4686 {
4687     Property aProp;
4688 
4689     // Id == -1: display the implemented interfaces corresponding the ClassProvider
4690     SbxVariableRef xVarRef = new SbUnoProperty( ID_DBG_SUPPORTEDINTERFACES, SbxSTRING, SbxSTRING, aProp, -1, false, false );
4691     QuickInsert( xVarRef.get() );
4692 
4693     // Id == -2: output the properties
4694     xVarRef = new SbUnoProperty( ID_DBG_PROPERTIES, SbxSTRING, SbxSTRING, aProp, -2, false, false );
4695     QuickInsert( xVarRef.get() );
4696 
4697     // Id == -3: output the Methods
4698     xVarRef = new SbUnoProperty( ID_DBG_METHODS, SbxSTRING, SbxSTRING, aProp, -3, false, false );
4699     QuickInsert( xVarRef.get() );
4700 }
4701 
4702 void SbUnoStructRefObject::implCreateAll()
4703 {
4704      // throw away all existing methods and properties
4705     pMethods   = new SbxArray;
4706     pProps     = new SbxArray;
4707 
4708     if (!mbMemberCacheInit)
4709         initMemberCache();
4710 
4711     for (auto const& field : maFields)
4712     {
4713         const OUString& rName = field.first;
4714         SbxDataType eSbxType;
4715         eSbxType = unoToSbxType( field.second->getTypeClass() );
4716         SbxDataType eRealSbxType = eSbxType;
4717         Property aProp;
4718         aProp.Name = rName;
4719         aProp.Type = css::uno::Type( field.second->getTypeClass(), field.second->getTypeName() );
4720         SbUnoProperty* pProp = new SbUnoProperty( rName, eSbxType, eRealSbxType, aProp, 0, false, ( aProp.Type.getTypeClass() == css::uno::TypeClass_STRUCT) );
4721         SbxVariableRef xVarRef = pProp;
4722         QuickInsert( xVarRef.get() );
4723     }
4724 
4725     // Create Dbg_-Properties
4726     implCreateDbgProperties();
4727 }
4728 
4729  // output the value
4730 Any SbUnoStructRefObject::getUnoAny()
4731 {
4732     return maMemberInfo.getValue();
4733 }
4734 
4735 OUString SbUnoStructRefObject::Impl_DumpProperties()
4736 {
4737     OUStringBuffer aRet;
4738     aRet.append("Properties of object ");
4739     aRet.append( getDbgObjectName() );
4740 
4741     sal_uInt16 nPropCount = pProps->Count();
4742     sal_uInt16 nPropsPerLine = 1 + nPropCount / 30;
4743     for( sal_uInt16 i = 0; i < nPropCount; i++ )
4744     {
4745         SbxVariable* pVar = pProps->Get( i );
4746         if( pVar )
4747         {
4748             OUStringBuffer aPropStr;
4749             if( (i % nPropsPerLine) == 0 )
4750             {
4751                 aPropStr.append( "\n" );
4752             }
4753             // output the type and name
4754             // Is it in Uno a sequence?
4755             SbxDataType eType = pVar->GetFullType();
4756 
4757             const OUString& aName( pVar->GetName() );
4758             StructFieldInfo::iterator it = maFields.find( aName );
4759 
4760             if ( it != maFields.end() )
4761             {
4762                 const StructRefInfo& rPropInfo = *it->second;
4763 
4764                 if( eType == SbxOBJECT )
4765                 {
4766                     if( rPropInfo.getTypeClass() == TypeClass_SEQUENCE )
4767                     {
4768                         eType = SbxDataType( SbxOBJECT | SbxARRAY );
4769                     }
4770                 }
4771             }
4772             aPropStr.append( Dbg_SbxDataType2String( eType ) );
4773 
4774             aPropStr.append( " " );
4775             aPropStr.append( pVar->GetName() );
4776 
4777             if( i == nPropCount - 1 )
4778             {
4779                 aPropStr.append( "\n" );
4780             }
4781             else
4782             {
4783                 aPropStr.append( "; " );
4784             }
4785             aRet.append( aPropStr.makeStringAndClear() );
4786         }
4787     }
4788     return aRet.makeStringAndClear();
4789 }
4790 
4791 void SbUnoStructRefObject::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
4792 {
4793     if ( !mbMemberCacheInit )
4794         initMemberCache();
4795     const SbxHint* pHint = dynamic_cast<const SbxHint*>(&rHint);
4796     if( pHint )
4797     {
4798         SbxVariable* pVar = pHint->GetVar();
4799         SbUnoProperty* pProp = dynamic_cast<SbUnoProperty*>( pVar );
4800         if( pProp )
4801         {
4802             StructFieldInfo::iterator it =  maFields.find(  pProp->GetName() );
4803             // handle get/set of members of struct
4804             if( pHint->GetId() == SfxHintId::BasicDataWanted )
4805             {
4806                 // Test-Properties
4807                 sal_Int32 nId = pProp->nId;
4808                 if( nId < 0 )
4809                 {
4810                     // Id == -1: Display implemented interfaces according the ClassProvider
4811                     if( nId == -1 )     // Property ID_DBG_SUPPORTEDINTERFACES"
4812                     {
4813                         OUString aRet = OUStringLiteral( ID_DBG_SUPPORTEDINTERFACES )
4814                                       + " not available.\n(TypeClass is not TypeClass_INTERFACE)\n";
4815 
4816                         pVar->PutString( aRet );
4817                     }
4818                     // Id == -2: output properties
4819                     else if( nId == -2 )        // Property ID_DBG_PROPERTIES
4820                     {
4821                         // by now all properties must be established
4822                         implCreateAll();
4823                         OUString aRetStr = Impl_DumpProperties();
4824                         pVar->PutString( aRetStr );
4825                     }
4826                     // Id == -3: output the methods
4827                     else if( nId == -3 )        // Property ID_DBG_METHODS
4828                     {
4829                         // by now all properties must be established
4830                         implCreateAll();
4831                         OUString aRet = "Methods of object "
4832                                       + getDbgObjectName()
4833                                       + "\nNo methods found\n";
4834                         pVar->PutString( aRet );
4835                     }
4836                     return;
4837                 }
4838 
4839                 if ( it != maFields.end() )
4840                 {
4841                     Any aRetAny = it->second->getValue();
4842                     unoToSbxValue( pVar, aRetAny );
4843                 }
4844                 else
4845                     StarBASIC::Error( ERRCODE_BASIC_PROPERTY_NOT_FOUND );
4846             }
4847             else if( pHint->GetId() == SfxHintId::BasicDataChanged )
4848             {
4849                 if ( it != maFields.end() )
4850                 {
4851                     // take over the value from Uno to Sbx
4852                     Any aAnyValue = sbxToUnoValue( pVar, pProp->aUnoProp.Type, &pProp->aUnoProp );
4853                     it->second->setValue( aAnyValue );
4854                 }
4855                 else
4856                     StarBASIC::Error( ERRCODE_BASIC_PROPERTY_NOT_FOUND );
4857             }
4858         }
4859         else
4860            SbxObject::Notify( rBC, rHint );
4861     }
4862 }
4863 
4864 StructRefInfo SbUnoStructRefObject::getStructMember( const OUString& rMemberName )
4865 {
4866     if (!mbMemberCacheInit)
4867     {
4868         initMemberCache();
4869     }
4870     StructFieldInfo::iterator it = maFields.find( rMemberName );
4871 
4872     css::uno::Type aFoundType;
4873     sal_Int32 nFoundPos = -1;
4874 
4875     if ( it != maFields.end() )
4876     {
4877         aFoundType = it->second->getType();
4878         nFoundPos = it->second->getPos();
4879     }
4880     StructRefInfo aRet( maMemberInfo.getRootAnyRef(), aFoundType, nFoundPos );
4881     return aRet;
4882 }
4883 
4884 OUString SbUnoStructRefObject::getDbgObjectName()
4885 {
4886     OUString aName = GetClassName();
4887     if( aName.isEmpty() )
4888     {
4889         aName += "Unknown";
4890     }
4891     OUStringBuffer aRet;
4892     if( aName.getLength() > 20 )
4893     {
4894         aRet.append( "\n" );
4895     }
4896     aRet.append( "\"" );
4897     aRet.append( aName );
4898     aRet.append( "\":" );
4899     return aRet.makeStringAndClear();
4900 }
4901 
4902 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
4903