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