tdf#153109 Use any_of to check for match in gciterator.cxx
[LibreOffice.git] / basic / source / classes / sbunoobj.cxx
blob25a395e7a6bfe809c8fba48e34e256833eeb4d75
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
22 #include <osl/diagnose.h>
23 #include <o3tl/any.hxx>
24 #include <o3tl/safeint.hxx>
25 #include <utility>
26 #include <vcl/svapp.hxx>
27 #include <comphelper/errcode.hxx>
28 #include <svl/hint.hxx>
30 #include <cppuhelper/implbase.hxx>
31 #include <cppuhelper/exc_hlp.hxx>
32 #include <comphelper/interfacecontainer4.hxx>
33 #include <comphelper/extract.hxx>
34 #include <comphelper/processfactory.hxx>
35 #include <cppuhelper/weakref.hxx>
37 #include <rtl/math.hxx>
38 #include <rtl/ustrbuf.hxx>
40 #include <com/sun/star/script/ArrayWrapper.hpp>
41 #include <com/sun/star/script/CannotConvertException.hpp>
42 #include <com/sun/star/script/NativeObjectWrapper.hpp>
43 #include <com/sun/star/sheet/XSheetCellCursor.hpp>
45 #include <com/sun/star/uno/XComponentContext.hpp>
46 #include <com/sun/star/uno/DeploymentException.hpp>
47 #include <com/sun/star/lang/XTypeProvider.hpp>
48 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
49 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
50 #include <com/sun/star/lang/XServiceInfo.hpp>
51 #include <com/sun/star/beans/PropertyAttribute.hpp>
52 #include <com/sun/star/beans/PropertyConcept.hpp>
53 #include <com/sun/star/beans/MethodConcept.hpp>
54 #include <com/sun/star/beans/XPropertySet.hpp>
55 #include <com/sun/star/beans/theIntrospection.hpp>
56 #include <com/sun/star/script/BasicErrorException.hpp>
57 #include <com/sun/star/script/InvocationAdapterFactory.hpp>
58 #include <com/sun/star/script/XAllListener.hpp>
59 #include <com/sun/star/script/Converter.hpp>
60 #include <com/sun/star/script/XDefaultProperty.hpp>
61 #include <com/sun/star/script/XDirectInvocation.hpp>
62 #include <com/sun/star/container/XNameAccess.hpp>
63 #include <com/sun/star/container/XHierarchicalNameAccess.hpp>
64 #include <com/sun/star/reflection/XIdlArray.hpp>
65 #include <com/sun/star/reflection/XIdlReflection.hpp>
66 #include <com/sun/star/reflection/XServiceConstructorDescription.hpp>
67 #include <com/sun/star/reflection/XSingletonTypeDescription.hpp>
68 #include <com/sun/star/reflection/theCoreReflection.hpp>
69 #include <com/sun/star/bridge/oleautomation/NamedArgument.hpp>
70 #include <com/sun/star/bridge/oleautomation/Date.hpp>
71 #include <com/sun/star/bridge/oleautomation/Decimal.hpp>
72 #include <com/sun/star/bridge/oleautomation/Currency.hpp>
73 #include <com/sun/star/bridge/oleautomation/XAutomationObject.hpp>
74 #include <com/sun/star/script/XAutomationInvocation.hpp>
76 #include <rtlproto.hxx>
78 #include <basic/sbstar.hxx>
79 #include <basic/sbuno.hxx>
80 #include <basic/sberrors.hxx>
81 #include <sbunoobj.hxx>
82 #include <sbintern.hxx>
83 #include <runtime.hxx>
85 #include <algorithm>
86 #include <math.h>
87 #include <memory>
88 #include <string_view>
89 #include <unordered_map>
90 #include <com/sun/star/reflection/XTypeDescriptionEnumerationAccess.hpp>
91 #include <com/sun/star/reflection/XConstantsTypeDescription.hpp>
93 using com::sun::star::uno::Reference;
94 using namespace com::sun::star::uno;
95 using namespace com::sun::star::lang;
96 using namespace com::sun::star::reflection;
97 using namespace com::sun::star::beans;
98 using namespace com::sun::star::script;
99 using namespace com::sun::star::container;
100 using namespace com::sun::star::bridge;
101 using namespace cppu;
104 // Identifiers for creating the strings for dbg_Properties
105 constexpr OUString ID_DBG_SUPPORTEDINTERFACES = u"Dbg_SupportedInterfaces"_ustr;
106 constexpr OUString ID_DBG_PROPERTIES = u"Dbg_Properties"_ustr;
107 constexpr OUString ID_DBG_METHODS = u"Dbg_Methods"_ustr;
109 char const aSeqLevelStr[] = "[]";
111 // Gets the default property for a uno object. Note: There is some
112 // redirection built in. The property name specifies the name
113 // of the default property.
115 bool SbUnoObject::getDefaultPropName( SbUnoObject const * pUnoObj, OUString& sDfltProp )
117 bool bResult = false;
118 Reference< XDefaultProperty> xDefaultProp( pUnoObj->maTmpUnoObj, UNO_QUERY );
119 if ( xDefaultProp.is() )
121 sDfltProp = xDefaultProp->getDefaultPropertyName();
122 if ( !sDfltProp.isEmpty() )
123 bResult = true;
125 return bResult;
128 SbxVariable* getDefaultProp( SbxVariable* pRef )
130 SbxVariable* pDefaultProp = nullptr;
131 if ( pRef->GetType() == SbxOBJECT )
133 SbxObject* pObj = dynamic_cast<SbxObject*>(pRef);
134 if (!pObj)
136 SbxBase* pObjVarObj = pRef->GetObject();
137 pObj = dynamic_cast<SbxObject*>( pObjVarObj );
139 if (SbUnoObject* pUnoObj = dynamic_cast<SbUnoObject*>(pObj))
141 pDefaultProp = pUnoObj->GetDfltProperty();
144 return pDefaultProp;
147 void SetSbUnoObjectDfltPropName( SbxObject* pObj )
149 SbUnoObject* pUnoObj = dynamic_cast<SbUnoObject*>( pObj );
150 if ( pUnoObj )
152 OUString sDfltPropName;
154 if ( SbUnoObject::getDefaultPropName( pUnoObj, sDfltPropName ) )
156 pUnoObj->SetDfltProperty( sDfltPropName );
161 // save CoreReflection statically
162 static Reference< XIdlReflection > getCoreReflection_Impl()
164 return css::reflection::theCoreReflection::get(
165 comphelper::getProcessComponentContext());
168 // save CoreReflection statically
169 static Reference< XHierarchicalNameAccess > const & getCoreReflection_HierarchicalNameAccess_Impl()
171 static Reference< XHierarchicalNameAccess > xCoreReflection_HierarchicalNameAccess;
173 if( !xCoreReflection_HierarchicalNameAccess.is() )
175 Reference< XIdlReflection > xCoreReflection = getCoreReflection_Impl();
176 if( xCoreReflection.is() )
178 xCoreReflection_HierarchicalNameAccess =
179 Reference< XHierarchicalNameAccess >( xCoreReflection, UNO_QUERY );
182 return xCoreReflection_HierarchicalNameAccess;
185 // Hold TypeProvider statically
186 static Reference< XHierarchicalNameAccess > const & getTypeProvider_Impl()
188 static Reference< XHierarchicalNameAccess > xAccess;
190 // Do we have already CoreReflection; if not obtain it
191 if( !xAccess.is() )
193 const Reference< XComponentContext >& xContext(
194 comphelper::getProcessComponentContext() );
195 if( xContext.is() )
197 xContext->getValueByName(
198 u"/singletons/com.sun.star.reflection.theTypeDescriptionManager"_ustr )
199 >>= xAccess;
200 OSL_ENSURE( xAccess.is(), "### TypeDescriptionManager singleton not accessible!?" );
202 if( !xAccess.is() )
204 throw DeploymentException(
205 u"/singletons/com.sun.star.reflection.theTypeDescriptionManager singleton not accessible"_ustr );
208 return xAccess;
211 // Hold TypeConverter statically
212 static Reference< XTypeConverter > const & getTypeConverter_Impl()
214 static Reference< XTypeConverter > xTypeConverter;
216 // Do we have already CoreReflection; if not obtain it
217 if( !xTypeConverter.is() )
219 const Reference< XComponentContext >& xContext(
220 comphelper::getProcessComponentContext() );
221 if( xContext.is() )
223 xTypeConverter = Converter::create(xContext);
225 if( !xTypeConverter.is() )
227 throw DeploymentException(
228 u"com.sun.star.script.Converter service not accessible"_ustr );
231 return xTypeConverter;
235 // #111851 factory function to create an OLE object
236 SbUnoObject* createOLEObject_Impl( const OUString& aType )
238 static const Reference<XMultiServiceFactory> xOLEFactory = [] {
239 Reference<XMultiServiceFactory> xFactory;
240 const Reference< XComponentContext >& xContext( comphelper::getProcessComponentContext() );
241 if( xContext.is() )
243 Reference<XMultiComponentFactory> xSMgr = xContext->getServiceManager();
244 xFactory.set(
245 xSMgr->createInstanceWithContext( u"com.sun.star.bridge.OleObjectFactory"_ustr, xContext ),
246 UNO_QUERY );
248 return xFactory;
249 }();
251 SbUnoObject* pUnoObj = nullptr;
252 if( xOLEFactory.is() )
254 // some type names available in VBA can not be directly used in COM
255 OUString aOLEType = aType;
256 if ( aOLEType == "SAXXMLReader30" )
258 aOLEType = "Msxml2.SAXXMLReader.3.0";
260 Reference< XInterface > xOLEObject = xOLEFactory->createInstance( aOLEType );
261 if( xOLEObject.is() )
263 pUnoObj = new SbUnoObject( aType, Any(xOLEObject) );
264 OUString sDfltPropName;
266 if ( SbUnoObject::getDefaultPropName( pUnoObj, sDfltPropName ) )
267 pUnoObj->SetDfltProperty( sDfltPropName );
270 return pUnoObj;
274 namespace
276 void lcl_indent( OUStringBuffer& _inout_rBuffer, sal_Int32 _nLevel )
278 while ( _nLevel-- > 0 )
280 _inout_rBuffer.append( " " );
285 static void implAppendExceptionMsg( OUStringBuffer& _inout_rBuffer, const Exception& _e, std::u16string_view _rExceptionType, sal_Int32 _nLevel )
287 _inout_rBuffer.append( "\n" );
288 lcl_indent( _inout_rBuffer, _nLevel );
289 _inout_rBuffer.append( "Type: " );
291 if ( _rExceptionType.empty() )
292 _inout_rBuffer.append( "Unknown" );
293 else
294 _inout_rBuffer.append( _rExceptionType );
296 _inout_rBuffer.append( "\n" );
297 lcl_indent( _inout_rBuffer, _nLevel );
298 _inout_rBuffer.append( "Message: " );
299 _inout_rBuffer.append( _e.Message );
303 // construct an error message for the exception
304 static OUString implGetExceptionMsg( const Exception& e, std::u16string_view aExceptionType_ )
306 OUStringBuffer aMessageBuf;
307 implAppendExceptionMsg( aMessageBuf, e, aExceptionType_, 0 );
308 return aMessageBuf.makeStringAndClear();
311 static OUString implGetExceptionMsg( const Any& _rCaughtException )
313 auto e = o3tl::tryAccess<Exception>(_rCaughtException);
314 OSL_PRECOND( e, "implGetExceptionMsg: illegal argument!" );
315 if ( !e )
317 return OUString();
319 return implGetExceptionMsg( *e, _rCaughtException.getValueTypeName() );
322 static Any convertAny( const Any& rVal, const Type& aDestType )
324 Any aConvertedVal;
325 const Reference< XTypeConverter >& xConverter = getTypeConverter_Impl();
328 aConvertedVal = xConverter->convertTo( rVal, aDestType );
330 catch( const IllegalArgumentException& )
332 StarBASIC::Error( ERRCODE_BASIC_EXCEPTION,
333 implGetExceptionMsg( ::cppu::getCaughtException() ) );
334 return aConvertedVal;
336 catch( const CannotConvertException& e2 )
338 StarBASIC::Error( ERRCODE_BASIC_EXCEPTION,
339 implGetExceptionMsg( e2, u"com.sun.star.lang.IllegalArgumentException" ) );
340 return aConvertedVal;
342 return aConvertedVal;
346 // #105565 Special Object to wrap a strongly typed Uno Any
349 // TODO: source out later
350 static Reference<XIdlClass> TypeToIdlClass( const Type& rType )
352 return getCoreReflection_Impl()->forName(rType.getTypeName());
355 // Exception type unknown
356 template< class EXCEPTION >
357 static OUString implGetExceptionMsg( const EXCEPTION& e )
359 return implGetExceptionMsg( e, cppu::UnoType<decltype(e)>::get().getTypeName() );
362 static void implHandleBasicErrorException( BasicErrorException const & e )
364 ErrCode nError = StarBASIC::GetSfxFromVBError( static_cast<sal_uInt16>(e.ErrorCode) );
365 StarBASIC::Error( nError, e.ErrorMessageArgument );
368 static void implHandleWrappedTargetException( const Any& _rWrappedTargetException )
370 Any aExamine( _rWrappedTargetException );
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;
378 BasicErrorException aBasicError;
380 ErrCode nError( ERRCODE_BASIC_EXCEPTION );
381 OUStringBuffer aMessageBuf;
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 )
388 // special handling for BasicErrorException errors
389 if ( aWrapped.TargetException >>= aBasicError )
391 nError = StarBASIC::GetSfxFromVBError( static_cast<sal_uInt16>(aBasicError.ErrorCode) );
392 aMessageBuf.append( aBasicError.ErrorMessageArgument );
393 aExamine.clear();
394 break;
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:" );
403 // next round
404 aExamine = aWrapped.TargetException;
405 ++nLevel;
408 if ( auto e = o3tl::tryAccess<Exception>(aExamine) )
410 // the last element in the chain is still an exception, but no WrappedTargetException
411 implAppendExceptionMsg( aMessageBuf, *e, aExamine.getValueTypeName(), nLevel );
414 StarBASIC::Error( nError, aMessageBuf.makeStringAndClear() );
417 static void implHandleAnyException( const Any& _rCaughtException )
419 BasicErrorException aBasicError;
420 WrappedTargetException aWrappedError;
422 if ( _rCaughtException >>= aBasicError )
424 implHandleBasicErrorException( aBasicError );
426 else if ( _rCaughtException >>= aWrappedError )
428 implHandleWrappedTargetException( _rCaughtException );
430 else
432 StarBASIC::Error( ERRCODE_BASIC_EXCEPTION, implGetExceptionMsg( _rCaughtException ) );
436 namespace {
438 // NativeObjectWrapper handling
439 struct ObjectItem
441 SbxObjectRef m_xNativeObj;
443 explicit ObjectItem( SbxObject* pNativeObj )
444 : m_xNativeObj( pNativeObj )
450 typedef std::vector< ObjectItem > NativeObjectWrapperVector;
452 namespace {
454 NativeObjectWrapperVector gaNativeObjectWrapperVector;
458 void clearNativeObjectWrapperVector()
460 gaNativeObjectWrapperVector.clear();
463 static sal_uInt32 lcl_registerNativeObjectWrapper( SbxObject* pNativeObj )
465 sal_uInt32 nIndex = gaNativeObjectWrapperVector.size();
466 gaNativeObjectWrapperVector.emplace_back( pNativeObj );
467 return nIndex;
470 static SbxObject* lcl_getNativeObject( sal_uInt32 nIndex )
472 SbxObjectRef xRetObj;
473 if( nIndex < gaNativeObjectWrapperVector.size() )
475 ObjectItem& rItem = gaNativeObjectWrapperVector[ nIndex ];
476 xRetObj = rItem.m_xNativeObj;
478 return xRetObj.get();
481 // convert from Uno to Sbx
482 static SbxDataType unoToSbxType( TypeClass eType )
484 SbxDataType eRetType = SbxVOID;
486 switch( eType )
488 case TypeClass_INTERFACE:
489 case TypeClass_TYPE:
490 case TypeClass_STRUCT:
491 case TypeClass_EXCEPTION: eRetType = SbxOBJECT; break;
493 case TypeClass_ENUM: eRetType = SbxLONG; break;
494 case TypeClass_SEQUENCE:
495 eRetType = SbxDataType( SbxOBJECT | SbxARRAY );
496 break;
499 case TypeClass_ANY: eRetType = SbxVARIANT; break;
500 case TypeClass_BOOLEAN: eRetType = SbxBOOL; break;
501 case TypeClass_CHAR: eRetType = SbxCHAR; break;
502 case TypeClass_STRING: eRetType = SbxSTRING; break;
503 case TypeClass_FLOAT: eRetType = SbxSINGLE; break;
504 case TypeClass_DOUBLE: eRetType = SbxDOUBLE; break;
505 case TypeClass_BYTE: eRetType = SbxINTEGER; break;
506 case TypeClass_SHORT: eRetType = SbxINTEGER; break;
507 case TypeClass_LONG: eRetType = SbxLONG; break;
508 case TypeClass_HYPER: eRetType = SbxSALINT64; break;
509 case TypeClass_UNSIGNED_SHORT: eRetType = SbxUSHORT; break;
510 case TypeClass_UNSIGNED_LONG: eRetType = SbxULONG; break;
511 case TypeClass_UNSIGNED_HYPER: eRetType = SbxSALUINT64;break;
512 default: break;
514 return eRetType;
517 static SbxDataType unoToSbxType( const Reference< XIdlClass >& xIdlClass )
519 SbxDataType eRetType = SbxVOID;
520 if( xIdlClass.is() )
522 TypeClass eType = xIdlClass->getTypeClass();
523 eRetType = unoToSbxType( eType );
525 return eRetType;
528 static void implSequenceToMultiDimArray( SbxDimArray*& pArray, Sequence< sal_Int32 >& indices, Sequence< sal_Int32 >& sizes, const Any& aValue, sal_Int32 dimension, bool bIsZeroIndex, Type const * pType )
530 const Type& aType = aValue.getValueType();
531 TypeClass eTypeClass = aType.getTypeClass();
533 sal_Int32 dimCopy = dimension;
535 if ( eTypeClass == TypeClass_SEQUENCE )
537 Reference< XIdlClass > xIdlTargetClass = TypeToIdlClass( aType );
538 Reference< XIdlArray > xIdlArray = xIdlTargetClass->getArray();
539 typelib_TypeDescription * pTD = nullptr;
540 aType.getDescription( &pTD );
541 Type aElementType( reinterpret_cast<typelib_IndirectTypeDescription *>(pTD)->pType );
542 ::typelib_typedescription_release( pTD );
544 sal_Int32 nLen = xIdlArray->getLen( aValue );
545 for ( sal_Int32 index = 0; index < nLen; ++index )
547 auto pindices = indices.getArray();
548 Any aElementAny = xIdlArray->get( aValue, static_cast<sal_uInt32>(index) );
549 // This detects the dimension were currently processing
550 if ( dimCopy == dimension )
552 ++dimCopy;
553 if ( sizes.getLength() < dimCopy )
555 sizes.realloc( sizes.getLength() + 1 );
556 sizes.getArray()[ sizes.getLength() - 1 ] = nLen;
557 indices.realloc( indices.getLength() + 1 );
558 pindices = indices.getArray();
562 if ( bIsZeroIndex )
563 pindices[ dimCopy - 1 ] = index;
564 else
565 pindices[ dimCopy - 1] = index + 1;
567 implSequenceToMultiDimArray( pArray, indices, sizes, aElementAny, dimCopy, bIsZeroIndex, &aElementType );
571 else
573 if ( !indices.hasElements() )
575 // Should never ever get here ( indices.getLength()
576 // should equal number of dimensions in the array )
577 // And that should at least be 1 !
578 // #QUESTION is there a better error?
579 StarBASIC::Error( ERRCODE_BASIC_INVALID_OBJECT );
580 return;
583 SbxDataType eSbxElementType = unoToSbxType( pType ? pType->getTypeClass() : aValue.getValueTypeClass() );
584 if ( !pArray )
586 pArray = new SbxDimArray( eSbxElementType );
587 sal_Int32 nIndexLen = indices.getLength();
589 // Dimension the array
590 for ( sal_Int32 index = 0; index < nIndexLen; ++index )
592 if ( bIsZeroIndex )
593 pArray->unoAddDim(0, sizes[index] - 1);
594 else
595 pArray->unoAddDim(1, sizes[index]);
600 if ( pArray )
602 auto xVar = tools::make_ref<SbxVariable>( eSbxElementType );
603 unoToSbxValue( xVar.get(), aValue );
605 sal_Int32* pIndices = indices.getArray();
606 pArray->Put(xVar.get(), pIndices);
612 void unoToSbxValue( SbxVariable* pVar, const Any& aValue )
614 const Type& aType = aValue.getValueType();
615 TypeClass eTypeClass = aType.getTypeClass();
616 switch( eTypeClass )
618 case TypeClass_TYPE:
620 // Map Type to IdlClass
621 Type aType_;
622 aValue >>= aType_;
623 Reference<XIdlClass> xClass = TypeToIdlClass( aType_ );
624 Any aClassAny;
625 aClassAny <<= xClass;
627 // instantiate SbUnoObject
628 SbUnoObject* pSbUnoObject = new SbUnoObject( OUString(), aClassAny );
629 SbxObjectRef xWrapper = static_cast<SbxObject*>(pSbUnoObject);
631 // If the object is invalid deliver null
632 if( !pSbUnoObject->getUnoAny().hasValue() )
634 pVar->PutObject( nullptr );
636 else
638 pVar->PutObject( xWrapper.get() );
641 break;
642 // Interfaces and Structs must be wrapped in a SbUnoObject
643 case TypeClass_INTERFACE:
644 case TypeClass_STRUCT:
645 case TypeClass_EXCEPTION:
647 if( eTypeClass == TypeClass_STRUCT )
649 ArrayWrapper aWrap;
650 NativeObjectWrapper aNativeObjectWrapper;
651 if ( aValue >>= aWrap )
653 SbxDimArray* pArray = nullptr;
654 Sequence< sal_Int32 > indices;
655 Sequence< sal_Int32 > sizes;
656 implSequenceToMultiDimArray( pArray, indices, sizes, aWrap.Array, /*dimension*/0, aWrap.IsZeroIndex, nullptr );
657 if ( pArray )
659 SbxDimArrayRef xArray = pArray;
660 SbxFlagBits nFlags = pVar->GetFlags();
661 pVar->ResetFlag( SbxFlagBits::Fixed );
662 pVar->PutObject( xArray.get() );
663 pVar->SetFlags( nFlags );
665 else
666 pVar->PutEmpty();
667 break;
669 else if ( aValue >>= aNativeObjectWrapper )
671 sal_uInt32 nIndex = 0;
672 if( aNativeObjectWrapper.ObjectId >>= nIndex )
674 SbxObject* pObj = lcl_getNativeObject( nIndex );
675 pVar->PutObject( pObj );
677 else
678 pVar->PutEmpty();
679 break;
681 else
683 SbiInstance* pInst = GetSbData()->pInst;
684 if( pInst && pInst->IsCompatibility() )
686 oleautomation::Date aDate;
687 if( aValue >>= aDate )
689 pVar->PutDate( aDate.Value );
690 break;
692 else
694 oleautomation::Decimal aDecimal;
695 if( aValue >>= aDecimal )
697 pVar->PutDecimal( aDecimal );
698 break;
700 else
702 oleautomation::Currency aCurrency;
703 if( aValue >>= aCurrency )
705 pVar->PutCurrency( aCurrency.Value );
706 break;
713 // instantiate a SbUnoObject
714 SbUnoObject* pSbUnoObject = new SbUnoObject( OUString(), aValue );
715 //If this is called externally e.g. from the scripting
716 //framework then there is no 'active' runtime the default property will not be set up
717 //only a vba object will have XDefaultProp set anyway so... this
718 //test seems a bit of overkill
719 //if ( SbiRuntime::isVBAEnabled() )
721 OUString sDfltPropName;
723 if ( SbUnoObject::getDefaultPropName( pSbUnoObject, sDfltPropName ) )
725 pSbUnoObject->SetDfltProperty( sDfltPropName );
728 SbxObjectRef xWrapper = static_cast<SbxObject*>(pSbUnoObject);
730 // If the object is invalid deliver null
731 if( !pSbUnoObject->getUnoAny().hasValue() )
733 pVar->PutObject( nullptr );
735 else
737 pVar->PutObject( xWrapper.get() );
740 break;
743 case TypeClass_ENUM:
745 sal_Int32 nEnum = 0;
746 enum2int( nEnum, aValue );
747 pVar->PutLong( nEnum );
749 break;
751 case TypeClass_SEQUENCE:
753 Reference< XIdlClass > xIdlTargetClass = TypeToIdlClass( aType );
754 Reference< XIdlArray > xIdlArray = xIdlTargetClass->getArray();
755 sal_Int32 i, nLen = xIdlArray->getLen( aValue );
757 typelib_TypeDescription * pTD = nullptr;
758 aType.getDescription( &pTD );
759 assert( pTD && pTD->eTypeClass == typelib_TypeClass_SEQUENCE );
760 Type aElementType( reinterpret_cast<typelib_IndirectTypeDescription *>(pTD)->pType );
761 ::typelib_typedescription_release( pTD );
763 // build an Array in Basic
764 SbxDimArrayRef xArray;
765 SbxDataType eSbxElementType = unoToSbxType( aElementType.getTypeClass() );
766 xArray = new SbxDimArray( eSbxElementType );
767 if( nLen > 0 )
769 xArray->unoAddDim(0, nLen - 1);
771 // register the elements as variables
772 for( i = 0 ; i < nLen ; i++ )
774 // convert elements
775 Any aElementAny = xIdlArray->get( aValue, static_cast<sal_uInt32>(i) );
776 auto xVar = tools::make_ref<SbxVariable>( eSbxElementType );
777 unoToSbxValue( xVar.get(), aElementAny );
779 // put into the Array
780 xArray->Put(xVar.get(), &i);
783 else
785 xArray->unoAddDim(0, -1);
788 // return the Array
789 SbxFlagBits nFlags = pVar->GetFlags();
790 pVar->ResetFlag( SbxFlagBits::Fixed );
791 pVar->PutObject( xArray.get() );
792 pVar->SetFlags( nFlags );
795 break;
798 case TypeClass_BOOLEAN: pVar->PutBool( *o3tl::forceAccess<bool>(aValue) ); break;
799 case TypeClass_CHAR:
801 pVar->PutChar( *o3tl::forceAccess<sal_Unicode>(aValue) );
802 break;
804 case TypeClass_STRING: { OUString val; aValue >>= val; pVar->PutString( val ); } break;
805 case TypeClass_FLOAT: { float val = 0; aValue >>= val; pVar->PutSingle( val ); } break;
806 case TypeClass_DOUBLE: { double val = 0; aValue >>= val; pVar->PutDouble( val ); } break;
807 case TypeClass_BYTE: { sal_Int8 val = 0; aValue >>= val; pVar->PutInteger( val ); } break;
808 case TypeClass_SHORT: { sal_Int16 val = 0; aValue >>= val; pVar->PutInteger( val ); } break;
809 case TypeClass_LONG: { sal_Int32 val = 0; aValue >>= val; pVar->PutLong( val ); } break;
810 case TypeClass_HYPER: { sal_Int64 val = 0; aValue >>= val; pVar->PutInt64( val ); } break;
811 case TypeClass_UNSIGNED_SHORT: { sal_uInt16 val = 0; aValue >>= val; pVar->PutUShort( val ); } break;
812 case TypeClass_UNSIGNED_LONG: { sal_uInt32 val = 0; aValue >>= val; pVar->PutULong( val ); } break;
813 case TypeClass_UNSIGNED_HYPER: { sal_uInt64 val = 0; aValue >>= val; pVar->PutUInt64( val ); } break;
814 default: pVar->PutEmpty(); break;
818 // Deliver the reflection for Sbx types
819 static Type getUnoTypeForSbxBaseType( SbxDataType eType )
821 Type aRetType = cppu::UnoType<void>::get();
822 switch( eType )
824 case SbxNULL: aRetType = cppu::UnoType<XInterface>::get(); break;
825 case SbxINTEGER: aRetType = cppu::UnoType<sal_Int16>::get(); break;
826 case SbxLONG: aRetType = cppu::UnoType<sal_Int32>::get(); break;
827 case SbxSINGLE: aRetType = cppu::UnoType<float>::get(); break;
828 case SbxDOUBLE: aRetType = cppu::UnoType<double>::get(); break;
829 case SbxCURRENCY: aRetType = cppu::UnoType<oleautomation::Currency>::get(); break;
830 case SbxDECIMAL: aRetType = cppu::UnoType<oleautomation::Decimal>::get(); break;
831 case SbxDATE: {
832 SbiInstance* pInst = GetSbData()->pInst;
833 if( pInst && pInst->IsCompatibility() )
834 aRetType = cppu::UnoType<double>::get();
835 else
836 aRetType = cppu::UnoType<oleautomation::Date>::get();
838 break;
839 case SbxSTRING: aRetType = cppu::UnoType<OUString>::get(); break;
840 case SbxBOOL: aRetType = cppu::UnoType<sal_Bool>::get(); break;
841 case SbxVARIANT: aRetType = cppu::UnoType<Any>::get(); break;
842 case SbxCHAR: aRetType = cppu::UnoType<cppu::UnoCharType>::get(); break;
843 case SbxBYTE: aRetType = cppu::UnoType<sal_Int8>::get(); break;
844 case SbxUSHORT: aRetType = cppu::UnoType<cppu::UnoUnsignedShortType>::get(); break;
845 case SbxULONG: aRetType = ::cppu::UnoType<sal_uInt32>::get(); break;
846 // map machine-dependent ones to long for consistency
847 case SbxINT: aRetType = ::cppu::UnoType<sal_Int32>::get(); break;
848 case SbxUINT: aRetType = ::cppu::UnoType<sal_uInt32>::get(); break;
849 default: break;
851 return aRetType;
854 // Converting of Sbx to Uno without a know target class for TypeClass_ANY
855 static Type getUnoTypeForSbxValue( const SbxValue* pVal )
857 Type aRetType = cppu::UnoType<void>::get();
858 if( !pVal )
859 return aRetType;
861 // convert SbxType to Uno
862 SbxDataType eBaseType = pVal->SbxValue::GetType();
863 if( eBaseType == SbxOBJECT )
865 SbxBaseRef xObj = pVal->GetObject();
866 if( !xObj.is() )
868 aRetType = cppu::UnoType<XInterface>::get();
869 return aRetType;
872 if( auto pArray = dynamic_cast<SbxDimArray*>( xObj.get() ) )
874 sal_Int32 nDims = pArray->GetDims();
875 Type aElementType = getUnoTypeForSbxBaseType( static_cast<SbxDataType>(pArray->GetType() & 0xfff) );
876 TypeClass eElementTypeClass = aElementType.getTypeClass();
878 // Normal case: One dimensional array
879 sal_Int32 nLower, nUpper;
880 if (nDims == 1 && pArray->GetDim(1, nLower, nUpper))
882 if( eElementTypeClass == TypeClass_VOID || eElementTypeClass == TypeClass_ANY )
884 // If all elements of the arrays are from the same type, take
885 // this one - otherwise the whole will be considered as Any-Sequence
886 bool bNeedsInit = true;
888 for (sal_Int32 aIdx[1] = { nLower }; aIdx[0] <= nUpper; ++aIdx[0])
890 SbxVariableRef xVar = pArray->Get(aIdx);
891 Type aType = getUnoTypeForSbxValue( xVar.get() );
892 if( bNeedsInit )
894 if( aType.getTypeClass() == TypeClass_VOID )
896 // if only first element is void: different types -> []any
897 // if all elements are void: []void is not allowed -> []any
898 aElementType = cppu::UnoType<Any>::get();
899 break;
901 aElementType = std::move(aType);
902 bNeedsInit = false;
904 else if( aElementType != aType )
906 // different types -> AnySequence
907 aElementType = cppu::UnoType<Any>::get();
908 break;
913 OUString aSeqTypeName = aSeqLevelStr + aElementType.getTypeName();
914 aRetType = Type( TypeClass_SEQUENCE, aSeqTypeName );
916 // #i33795 Map also multi dimensional arrays to corresponding sequences
917 else if( nDims > 1 )
919 if( eElementTypeClass == TypeClass_VOID || eElementTypeClass == TypeClass_ANY )
921 // For this check the array's dim structure does not matter
922 sal_uInt32 nFlatArraySize = pArray->Count();
924 bool bNeedsInit = true;
925 for( sal_uInt32 i = 0 ; i < nFlatArraySize ; i++ )
927 SbxVariableRef xVar = pArray->SbxArray::Get(i);
928 Type aType = getUnoTypeForSbxValue( xVar.get() );
929 if( bNeedsInit )
931 if( aType.getTypeClass() == TypeClass_VOID )
933 // if only first element is void: different types -> []any
934 // if all elements are void: []void is not allowed -> []any
935 aElementType = cppu::UnoType<Any>::get();
936 break;
938 aElementType = std::move(aType);
939 bNeedsInit = false;
941 else if( aElementType != aType )
943 // different types -> AnySequence
944 aElementType = cppu::UnoType<Any>::get();
945 break;
950 OUStringBuffer aSeqTypeName;
951 for(sal_Int32 iDim = 0 ; iDim < nDims ; iDim++ )
953 aSeqTypeName.append(aSeqLevelStr);
955 aSeqTypeName.append(aElementType.getTypeName());
956 aRetType = Type( TypeClass_SEQUENCE, aSeqTypeName.makeStringAndClear() );
959 // No array, but ...
960 else if( auto obj = dynamic_cast<SbUnoObject*>( xObj.get() ) )
962 aRetType = obj->getUnoAny().getValueType();
964 // SbUnoAnyObject?
965 else if( auto any = dynamic_cast<SbUnoAnyObject*>( xObj.get() ) )
967 aRetType = any->getValue().getValueType();
969 // Otherwise it is a No-Uno-Basic-Object -> default==deliver void
971 // No object, convert basic type
972 else
974 if (eBaseType == SbxBYTE && pVal->GetByte() > 127)
976 // Basic Byte type is unsigned; cppu::UnoType<sal_uInt8> corresponds to UNO boolean,
977 // so values 128-255 are only representable starting with UNO short types
978 eBaseType = SbxUSHORT;
980 aRetType = getUnoTypeForSbxBaseType( eBaseType );
982 return aRetType;
985 // converting of Sbx to Uno without known target class for TypeClass_ANY
986 static Any sbxToUnoValueImpl( const SbxValue* pVar, bool bBlockConversionToSmallestType = false )
988 SbxDataType eBaseType = pVar->SbxValue::GetType();
989 if( eBaseType == SbxOBJECT )
991 SbxBaseRef xObj = pVar->GetObject();
992 if( xObj.is() )
994 if( auto obj = dynamic_cast<SbUnoAnyObject*>( xObj.get() ) )
995 return obj->getValue();
996 if( auto pClassModuleObj = dynamic_cast<SbClassModuleObject*>( xObj.get() ) )
998 Any aRetAny;
999 SbModule& rClassModule = pClassModuleObj->getClassModule();
1000 if (rClassModule.createCOMWrapperForIface(aRetAny, pClassModuleObj))
1001 return aRetAny;
1003 if( dynamic_cast<const SbUnoObject*>( xObj.get() ) == nullptr )
1005 // Create NativeObjectWrapper to identify object in case of callbacks
1006 SbxObject* pObj = dynamic_cast<SbxObject*>( pVar->GetObject() );
1007 if( pObj != nullptr )
1009 NativeObjectWrapper aNativeObjectWrapper;
1010 sal_uInt32 nIndex = lcl_registerNativeObjectWrapper( pObj );
1011 aNativeObjectWrapper.ObjectId <<= nIndex;
1012 Any aRetAny;
1013 aRetAny <<= aNativeObjectWrapper;
1014 return aRetAny;
1020 Type aType = getUnoTypeForSbxValue( pVar );
1021 TypeClass eType = aType.getTypeClass();
1023 if( !bBlockConversionToSmallestType )
1025 // #79615 Choose "smallest" representation for int values
1026 // because up cast is allowed, downcast not
1027 switch( eType )
1029 case TypeClass_FLOAT:
1030 case TypeClass_DOUBLE:
1032 double d = pVar->GetDouble();
1033 if( rtl::math::approxEqual(d, floor( d )) )
1035 if( d >= -128 && d <= 127 )
1036 aType = ::cppu::UnoType<sal_Int8>::get();
1037 else if( d >= SbxMININT && d <= SbxMAXINT )
1038 aType = ::cppu::UnoType<sal_Int16>::get();
1039 else if( d >= -SbxMAXLNG && d <= SbxMAXLNG )
1040 aType = ::cppu::UnoType<sal_Int32>::get();
1042 break;
1044 case TypeClass_SHORT:
1046 sal_Int16 n = pVar->GetInteger();
1047 if( n >= -128 && n <= 127 )
1048 aType = ::cppu::UnoType<sal_Int8>::get();
1049 break;
1051 case TypeClass_LONG:
1053 sal_Int32 n = pVar->GetLong();
1054 if( n >= -128 && n <= 127 )
1055 aType = ::cppu::UnoType<sal_Int8>::get();
1056 else if( n >= SbxMININT && n <= SbxMAXINT )
1057 aType = ::cppu::UnoType<sal_Int16>::get();
1058 break;
1060 case TypeClass_UNSIGNED_LONG:
1062 sal_uInt32 n = pVar->GetLong();
1063 if( n <= SbxMAXUINT )
1064 aType = cppu::UnoType<cppu::UnoUnsignedShortType>::get();
1065 break;
1067 // TODO: need to add hyper types ?
1068 default: break;
1072 return sbxToUnoValue( pVar, aType );
1076 // Helper function for StepREDIMP
1077 static Any implRekMultiDimArrayToSequence( SbxDimArray* pArray,
1078 const Type& aElemType, sal_Int32 nMaxDimIndex, sal_Int32 nActualDim,
1079 sal_Int32* pActualIndices, sal_Int32* pLowerBounds, sal_Int32* pUpperBounds )
1081 sal_Int32 nSeqLevel = nMaxDimIndex - nActualDim + 1;
1082 OUStringBuffer aSeqTypeName;
1083 sal_Int32 i;
1084 for( i = 0 ; i < nSeqLevel ; i++ )
1086 aSeqTypeName.append(aSeqLevelStr);
1088 aSeqTypeName.append(aElemType.getTypeName());
1089 Type aSeqType( TypeClass_SEQUENCE, aSeqTypeName.makeStringAndClear() );
1091 // Create Sequence instance
1092 Any aRetVal;
1093 Reference< XIdlClass > xIdlTargetClass = TypeToIdlClass( aSeqType );
1094 xIdlTargetClass->createObject( aRetVal );
1096 // Alloc sequence according to array bounds
1097 sal_Int32 nUpper = pUpperBounds[nActualDim];
1098 sal_Int32 nLower = pLowerBounds[nActualDim];
1099 sal_Int32 nSeqSize = nUpper - nLower + 1;
1100 Reference< XIdlArray > xArray = xIdlTargetClass->getArray();
1101 xArray->realloc( aRetVal, nSeqSize );
1103 sal_Int32& ri = pActualIndices[nActualDim];
1105 for( ri = nLower,i = 0 ; ri <= nUpper ; ri++,i++ )
1107 Any aElementVal;
1109 if( nActualDim < nMaxDimIndex )
1111 aElementVal = implRekMultiDimArrayToSequence( pArray, aElemType,
1112 nMaxDimIndex, nActualDim + 1, pActualIndices, pLowerBounds, pUpperBounds );
1114 else
1116 SbxVariable* pSource = pArray->Get(pActualIndices);
1117 aElementVal = sbxToUnoValue( pSource, aElemType );
1122 // transfer to the sequence
1123 xArray->set( aRetVal, i, aElementVal );
1125 catch( const IllegalArgumentException& )
1127 StarBASIC::Error( ERRCODE_BASIC_EXCEPTION,
1128 implGetExceptionMsg( ::cppu::getCaughtException() ) );
1130 catch (const IndexOutOfBoundsException&)
1132 StarBASIC::Error( ERRCODE_BASIC_OUT_OF_RANGE );
1135 return aRetVal;
1138 // Map old interface
1139 Any sbxToUnoValue( const SbxValue* pVar )
1141 return sbxToUnoValueImpl( pVar );
1144 // function to find a global identifier in
1145 // the UnoScope and to wrap it for Sbx
1146 static bool implGetTypeByName( const OUString& rName, Type& rRetType )
1148 bool bSuccess = false;
1150 const Reference< XHierarchicalNameAccess >& xTypeAccess = getTypeProvider_Impl();
1151 if( xTypeAccess->hasByHierarchicalName( rName ) )
1153 Any aRet = xTypeAccess->getByHierarchicalName( rName );
1154 Reference< XTypeDescription > xTypeDesc;
1155 aRet >>= xTypeDesc;
1157 if( xTypeDesc.is() )
1159 rRetType = Type( xTypeDesc->getTypeClass(), xTypeDesc->getName() );
1160 bSuccess = true;
1163 return bSuccess;
1167 // converting of Sbx to Uno with known target class
1168 Any sbxToUnoValue( const SbxValue* pVar, const Type& rType, Property const * pUnoProperty )
1170 Any aRetVal;
1172 // #94560 No conversion of empty/void for MAYBE_VOID properties
1173 if( pUnoProperty && pUnoProperty->Attributes & PropertyAttribute::MAYBEVOID )
1175 if( pVar->IsEmpty() )
1176 return aRetVal;
1179 SbxDataType eBaseType = pVar->SbxValue::GetType();
1180 if( eBaseType == SbxOBJECT )
1182 SbxBaseRef xObj = pVar->GetObject();
1183 if ( auto obj = dynamic_cast<SbUnoAnyObject*>( xObj.get() ) )
1185 return obj->getValue();
1189 TypeClass eType = rType.getTypeClass();
1191 // tdf#162431 - check for missing parameters
1192 if (eType != TypeClass_ANY && eType != TypeClass_VOID && pVar->GetType() == SbxERROR)
1194 SbxVariable* paSbxVariable = dynamic_cast<SbxVariable*>(const_cast<SbxValue*>(pVar));
1195 if (paSbxVariable && SbiRuntime::IsMissing(paSbxVariable, 1))
1196 StarBASIC::Error(ERRCODE_BASIC_NOT_OPTIONAL);
1199 switch( eType )
1201 case TypeClass_INTERFACE:
1202 case TypeClass_STRUCT:
1203 case TypeClass_EXCEPTION:
1205 Reference< XIdlClass > xIdlTargetClass = TypeToIdlClass( rType );
1207 // null reference?
1208 if( pVar->IsNull() && eType == TypeClass_INTERFACE )
1210 Reference< XInterface > xRef;
1211 OUString aClassName = xIdlTargetClass->getName();
1212 Type aClassType( xIdlTargetClass->getTypeClass(), aClassName );
1213 aRetVal.setValue( &xRef, aClassType );
1215 else
1217 // #112368 Special conversion for Decimal, Currency and Date
1218 if( eType == TypeClass_STRUCT )
1220 SbiInstance* pInst = GetSbData()->pInst;
1221 if( pInst && pInst->IsCompatibility() )
1223 if( rType == cppu::UnoType<oleautomation::Decimal>::get())
1225 oleautomation::Decimal aDecimal;
1226 pVar->fillAutomationDecimal( aDecimal );
1227 aRetVal <<= aDecimal;
1228 break;
1230 else if( rType == cppu::UnoType<oleautomation::Currency>::get())
1232 // assumes per previous code that ole Currency is Int64
1233 aRetVal <<= pVar->GetInt64();
1234 break;
1236 else if( rType == cppu::UnoType<oleautomation::Date>::get())
1238 oleautomation::Date aDate;
1239 aDate.Value = pVar->GetDate();
1240 aRetVal <<= aDate;
1241 break;
1246 SbxBaseRef pObj = pVar->GetObject();
1247 if( auto obj = dynamic_cast<SbUnoObject*>( pObj.get() ) )
1249 aRetVal = obj->getUnoAny();
1251 else if( auto structRef = dynamic_cast<SbUnoStructRefObject*>( pObj.get() ) )
1253 aRetVal = structRef->getUnoAny();
1255 else
1257 // null object -> null XInterface
1258 Reference<XInterface> xInt;
1259 aRetVal <<= xInt;
1263 break;
1265 case TypeClass_TYPE:
1267 if( eBaseType == SbxOBJECT )
1269 // XIdlClass?
1270 Reference< XIdlClass > xIdlClass;
1272 SbxBaseRef pObj = pVar->GetObject();
1273 if( auto obj = dynamic_cast<SbUnoObject*>( pObj.get() ) )
1275 Any aUnoAny = obj->getUnoAny();
1276 aUnoAny >>= xIdlClass;
1279 if( xIdlClass.is() )
1281 OUString aClassName = xIdlClass->getName();
1282 Type aType( xIdlClass->getTypeClass(), aClassName );
1283 aRetVal <<= aType;
1286 else if( eBaseType == SbxSTRING )
1288 OUString aTypeName = pVar->GetOUString();
1289 Type aType;
1290 bool bSuccess = implGetTypeByName( aTypeName, aType );
1291 if( bSuccess )
1293 aRetVal <<= aType;
1297 break;
1300 case TypeClass_ENUM:
1302 aRetVal = int2enum( pVar->GetLong(), rType );
1304 break;
1306 case TypeClass_SEQUENCE:
1308 SbxBaseRef xObj = pVar->GetObject();
1309 if( auto pArray = dynamic_cast<SbxDimArray*>( xObj.get() ) )
1311 sal_Int32 nDims = pArray->GetDims();
1313 // Normal case: One dimensional array
1314 sal_Int32 nLower, nUpper;
1315 if (nDims == 1 && pArray->GetDim(1, nLower, nUpper))
1317 sal_Int32 nSeqSize = nUpper - nLower + 1;
1319 // create the instance of the required sequence
1320 Reference< XIdlClass > xIdlTargetClass = TypeToIdlClass( rType );
1321 xIdlTargetClass->createObject( aRetVal );
1322 Reference< XIdlArray > xArray = xIdlTargetClass->getArray();
1323 xArray->realloc( aRetVal, nSeqSize );
1325 // Element-Type
1326 OUString aClassName = xIdlTargetClass->getName();
1327 typelib_TypeDescription * pSeqTD = nullptr;
1328 typelib_typedescription_getByName( &pSeqTD, aClassName.pData );
1329 assert( pSeqTD );
1330 Type aElemType( reinterpret_cast<typelib_IndirectTypeDescription *>(pSeqTD)->pType );
1332 // convert all array member and register them
1333 sal_Int32 aIdx[1];
1334 aIdx[0] = nLower;
1335 for (sal_Int32 i = 0 ; i < nSeqSize; ++i, ++aIdx[0])
1337 SbxVariableRef xVar = pArray->Get(aIdx);
1339 // Convert the value of Sbx to Uno
1340 Any aAnyValue = sbxToUnoValue( xVar.get(), aElemType );
1344 // insert in the sequence
1345 xArray->set( aRetVal, i, aAnyValue );
1347 catch( const IllegalArgumentException& )
1349 StarBASIC::Error( ERRCODE_BASIC_EXCEPTION,
1350 implGetExceptionMsg( ::cppu::getCaughtException() ) );
1352 catch (const IndexOutOfBoundsException&)
1354 StarBASIC::Error( ERRCODE_BASIC_OUT_OF_RANGE );
1358 // #i33795 Map also multi dimensional arrays to corresponding sequences
1359 else if( nDims > 1 )
1361 // Element-Type
1362 typelib_TypeDescription * pSeqTD = nullptr;
1363 Type aCurType( rType );
1364 sal_Int32 nSeqLevel = 0;
1365 Type aElemType;
1368 OUString aTypeName = aCurType.getTypeName();
1369 typelib_typedescription_getByName( &pSeqTD, aTypeName.pData );
1370 assert( pSeqTD );
1371 if( pSeqTD->eTypeClass == typelib_TypeClass_SEQUENCE )
1373 aCurType = Type( reinterpret_cast<typelib_IndirectTypeDescription *>(pSeqTD)->pType );
1374 nSeqLevel++;
1376 else
1378 aElemType = aCurType;
1379 break;
1382 while( true );
1384 if( nSeqLevel == nDims )
1386 std::unique_ptr<sal_Int32[]> pLowerBounds(new sal_Int32[nDims]);
1387 std::unique_ptr<sal_Int32[]> pUpperBounds(new sal_Int32[nDims]);
1388 std::unique_ptr<sal_Int32[]> pActualIndices(new sal_Int32[nDims]);
1389 for(sal_Int32 i = 1 ; i <= nDims ; i++ )
1391 sal_Int32 lBound, uBound;
1392 pArray->GetDim(i, lBound, uBound);
1394 sal_Int32 j = i - 1;
1395 pActualIndices[j] = pLowerBounds[j] = lBound;
1396 pUpperBounds[j] = uBound;
1399 aRetVal = implRekMultiDimArrayToSequence( pArray, aElemType,
1400 nDims - 1, 0, pActualIndices.get(), pLowerBounds.get(), pUpperBounds.get() );
1405 break;
1408 // for Any use the class independent converting routine
1409 case TypeClass_ANY:
1411 aRetVal = sbxToUnoValueImpl( pVar );
1413 break;
1415 case TypeClass_BOOLEAN:
1417 aRetVal <<= pVar->GetBool();
1418 break;
1420 case TypeClass_CHAR:
1422 aRetVal <<= pVar->GetChar();
1423 break;
1425 case TypeClass_STRING: aRetVal <<= pVar->GetOUString(); break;
1426 case TypeClass_FLOAT: aRetVal <<= pVar->GetSingle(); break;
1427 case TypeClass_DOUBLE: aRetVal <<= pVar->GetDouble(); break;
1429 case TypeClass_BYTE:
1431 sal_Int16 nVal = pVar->GetInteger();
1432 bool bOverflow = false;
1433 if( nVal < -128 )
1435 bOverflow = true;
1436 nVal = -128;
1438 else if( nVal > 255 ) // 128..255 map to -128..-1
1440 bOverflow = true;
1441 nVal = 127;
1443 if( bOverflow )
1444 StarBASIC::Error( ERRCODE_BASIC_MATH_OVERFLOW );
1446 sal_Int8 nByteVal = static_cast<sal_Int8>(nVal);
1447 aRetVal <<= nByteVal;
1448 break;
1450 case TypeClass_SHORT: aRetVal <<= pVar->GetInteger(); break;
1451 case TypeClass_LONG: aRetVal <<= pVar->GetLong(); break;
1452 case TypeClass_HYPER: aRetVal <<= pVar->GetInt64(); break;
1453 case TypeClass_UNSIGNED_SHORT: aRetVal <<= pVar->GetUShort(); break;
1454 case TypeClass_UNSIGNED_LONG: aRetVal <<= pVar->GetULong(); break;
1455 case TypeClass_UNSIGNED_HYPER: aRetVal <<= pVar->GetUInt64(); break;
1456 default: break;
1459 return aRetVal;
1462 static void processAutomationParams( SbxArray* pParams, Sequence< Any >& args, sal_uInt32 nParamCount )
1464 AutomationNamedArgsSbxArray* pArgNamesArray = dynamic_cast<AutomationNamedArgsSbxArray*>( pParams );
1466 args.realloc( nParamCount );
1467 Any* pAnyArgs = args.getArray();
1468 bool bBlockConversionToSmallestType = GetSbData()->pInst->IsCompatibility();
1469 sal_uInt32 i = 0;
1470 if( pArgNamesArray )
1472 Sequence< OUString >& rNameSeq = pArgNamesArray->getNames();
1473 OUString* pNames = rNameSeq.getArray();
1474 Any aValAny;
1475 for( i = 0 ; i < nParamCount ; i++ )
1477 sal_uInt32 iSbx = i + 1;
1479 aValAny = sbxToUnoValueImpl(pParams->Get(iSbx),
1480 bBlockConversionToSmallestType );
1482 OUString aParamName = pNames[iSbx];
1483 if( !aParamName.isEmpty() )
1485 oleautomation::NamedArgument aNamedArgument;
1486 aNamedArgument.Name = aParamName;
1487 aNamedArgument.Value = aValAny;
1488 pAnyArgs[i] <<= aNamedArgument;
1490 else
1492 pAnyArgs[i] = aValAny;
1496 else
1498 for( i = 0 ; i < nParamCount ; i++ )
1500 pAnyArgs[i] = sbxToUnoValueImpl(pParams->Get(i + 1),
1501 bBlockConversionToSmallestType );
1507 namespace {
1509 enum class INVOKETYPE
1511 GetProp = 0,
1512 Func
1517 static Any invokeAutomationMethod( const OUString& Name, Sequence< Any > const & args, SbxArray* pParams, sal_uInt32 nParamCount, Reference< XInvocation > const & rxInvocation, INVOKETYPE invokeType )
1519 Sequence< sal_Int16 > OutParamIndex;
1520 Sequence< Any > OutParam;
1522 Any aRetAny;
1523 switch( invokeType )
1525 case INVOKETYPE::Func:
1526 aRetAny = rxInvocation->invoke( Name, args, OutParamIndex, OutParam );
1527 break;
1528 case INVOKETYPE::GetProp:
1530 Reference< XAutomationInvocation > xAutoInv( rxInvocation, UNO_QUERY );
1531 aRetAny = xAutoInv->invokeGetProperty( Name, args, OutParamIndex, OutParam );
1532 break;
1534 default:
1535 assert(false); break;
1538 const sal_Int16* pIndices = OutParamIndex.getConstArray();
1539 sal_uInt32 nLen = OutParamIndex.getLength();
1540 if( nLen )
1542 const Any* pNewValues = OutParam.getConstArray();
1543 for( sal_uInt32 j = 0 ; j < nLen ; j++ )
1545 sal_Int16 iTarget = pIndices[ j ];
1546 if( o3tl::make_unsigned(iTarget) >= nParamCount )
1547 break;
1548 unoToSbxValue(pParams->Get(j + 1), pNewValues[j]);
1551 return aRetAny;
1554 // Debugging help method to readout the implemented interfaces of an object
1555 static OUString Impl_GetInterfaceInfo( const Reference< XInterface >& x, const Reference< XIdlClass >& xClass, sal_uInt16 nRekLevel )
1557 Type aIfaceType = cppu::UnoType<XInterface>::get();
1558 static Reference< XIdlClass > xIfaceClass = TypeToIdlClass( aIfaceType );
1560 OUStringBuffer aRetStr;
1561 for( sal_uInt16 i = 0 ; i < nRekLevel ; i++ )
1562 aRetStr.append( " " );
1563 aRetStr.append( xClass->getName() );
1564 OUString aClassName = xClass->getName();
1565 Type aClassType( xClass->getTypeClass(), aClassName );
1567 // checking if the interface is really supported
1568 if( !x->queryInterface( aClassType ).hasValue() )
1570 aRetStr.append( " (ERROR: Not really supported!)\n" );
1572 // Are there super interfaces?
1573 else
1575 aRetStr.append( "\n" );
1577 // get the super interfaces
1578 Sequence< Reference< XIdlClass > > aSuperClassSeq = xClass->getSuperclasses();
1579 const Reference< XIdlClass >* pClasses = aSuperClassSeq.getConstArray();
1580 sal_uInt32 nSuperIfaceCount = aSuperClassSeq.getLength();
1581 for( sal_uInt32 j = 0 ; j < nSuperIfaceCount ; j++ )
1583 const Reference< XIdlClass >& rxIfaceClass = pClasses[j];
1584 if( !rxIfaceClass->equals( xIfaceClass ) )
1585 aRetStr.append( Impl_GetInterfaceInfo( x, rxIfaceClass, nRekLevel + 1 ) );
1588 return aRetStr.makeStringAndClear();
1591 static OUString getDbgObjectNameImpl(SbUnoObject& rUnoObj)
1593 OUString aName = rUnoObj.GetClassName();
1594 if( aName.isEmpty() )
1596 Any aToInspectObj = rUnoObj.getUnoAny();
1597 Reference< XInterface > xObj(aToInspectObj, css::uno::UNO_QUERY);
1598 if( xObj.is() )
1600 Reference< XServiceInfo > xServiceInfo( xObj, UNO_QUERY );
1601 if( xServiceInfo.is() )
1602 aName = xServiceInfo->getImplementationName();
1605 return aName;
1608 static OUString getDbgObjectName(SbUnoObject& rUnoObj)
1610 OUString aName = getDbgObjectNameImpl(rUnoObj);
1611 if( aName.isEmpty() )
1612 aName += "Unknown";
1614 OUStringBuffer aRet;
1615 if( aName.getLength() > 20 )
1617 aRet.append( "\n" );
1619 aRet.append( "\"" + aName + "\":" );
1620 return aRet.makeStringAndClear();
1623 OUString getBasicObjectTypeName( SbxObject* pObj )
1625 if (pObj)
1627 if (SbUnoObject* pUnoObj = dynamic_cast<SbUnoObject*>(pObj))
1629 return getDbgObjectNameImpl(*pUnoObj);
1631 else if (SbUnoStructRefObject* pUnoStructObj = dynamic_cast<SbUnoStructRefObject*>(pObj))
1633 return pUnoStructObj->GetClassName();
1636 return OUString();
1639 namespace {
1641 bool matchesBasicTypeName(
1642 css::uno::Reference<css::reflection::XIdlClass> const & unoType, OUString const & basicTypeName)
1644 if (unoType->getName().endsWithIgnoreAsciiCase(basicTypeName)) {
1645 return true;
1647 auto const sups = unoType->getSuperclasses();
1648 return std::any_of(
1649 sups.begin(), sups.end(),
1650 [&basicTypeName](auto const & t) { return matchesBasicTypeName(t, basicTypeName); });
1655 bool checkUnoObjectType(SbUnoObject& rUnoObj, const OUString& rClass)
1657 Any aToInspectObj = rUnoObj.getUnoAny();
1659 // Return true for XInvocation based objects as interface type names don't count then
1660 Reference< XInvocation > xInvocation( aToInspectObj, UNO_QUERY );
1661 if( xInvocation.is() )
1663 return true;
1665 bool bResult = false;
1666 Reference< XTypeProvider > xTypeProvider( aToInspectObj, UNO_QUERY );
1667 if( xTypeProvider.is() )
1669 /* Although interfaces in the ooo.vba namespace obey the IDL rules and
1670 have a leading 'X', in Basic we want to be able to do something
1671 like 'Dim wb As Workbooks' or 'Dim lb As MSForms.Label'. Here we
1672 add a leading 'X' to the class name and a leading dot to the entire
1673 type name. This results e.g. in '.XWorkbooks' or '.MSForms.XLabel'
1674 which matches the interface names 'ooo.vba.excel.XWorkbooks' or
1675 'ooo.vba.msforms.XLabel'.
1677 OUString aClassName;
1678 if ( SbiRuntime::isVBAEnabled() )
1680 aClassName = ".";
1681 sal_Int32 nClassNameDot = rClass.lastIndexOf( '.' );
1682 if( nClassNameDot >= 0 )
1684 aClassName += OUString::Concat(rClass.subView( 0, nClassNameDot + 1 )) + "X" + rClass.subView( nClassNameDot + 1 );
1686 else
1688 aClassName += "X" + rClass;
1691 else // assume extended type declaration support for basic ( can't get here
1692 // otherwise.
1693 aClassName = rClass;
1695 Sequence< Type > aTypeSeq = xTypeProvider->getTypes();
1696 const Type* pTypeArray = aTypeSeq.getConstArray();
1697 sal_uInt32 nIfaceCount = aTypeSeq.getLength();
1698 for( sal_uInt32 j = 0 ; j < nIfaceCount ; j++ )
1700 const Type& rType = pTypeArray[j];
1702 Reference<XIdlClass> xClass = TypeToIdlClass( rType );
1703 if( !xClass.is() )
1705 OSL_FAIL("failed to get XIdlClass for type");
1706 break;
1708 OUString aInterfaceName = xClass->getName();
1709 if ( aInterfaceName == "com.sun.star.bridge.oleautomation.XAutomationObject" )
1711 // there is a hack in the extensions/source/ole/oleobj.cxx
1712 // to return the typename of the automation object, let's
1713 // check if it matches
1714 Reference< XInvocation > xInv( aToInspectObj, UNO_QUERY );
1715 if ( xInv.is() )
1717 OUString sTypeName;
1718 xInv->getValue( u"$GetTypeName"_ustr ) >>= sTypeName;
1719 if ( sTypeName.isEmpty() || sTypeName == "IDispatch" )
1721 // can't check type, leave it pass
1722 bResult = true;
1724 else
1726 bResult = sTypeName == rClass;
1729 break; // finished checking automation object
1732 if ( matchesBasicTypeName(xClass, aClassName) )
1734 bResult = true;
1735 break;
1739 return bResult;
1742 // Debugging help method to readout the implemented interfaces of an object
1743 static OUString Impl_GetSupportedInterfaces(SbUnoObject& rUnoObj)
1745 Any aToInspectObj = rUnoObj.getUnoAny();
1747 // allow only TypeClass interface
1748 OUStringBuffer aRet;
1749 auto x = o3tl::tryAccess<Reference<XInterface>>(aToInspectObj);
1750 if( !x )
1752 aRet.append( ID_DBG_SUPPORTEDINTERFACES
1753 + " not available.\n(TypeClass is not TypeClass_INTERFACE)\n" );
1755 else
1757 Reference< XTypeProvider > xTypeProvider( *x, UNO_QUERY );
1759 aRet.append( "Supported interfaces by object "
1760 + getDbgObjectName(rUnoObj)
1761 + "\n" );
1762 if( xTypeProvider.is() )
1764 // get the interfaces of the implementation
1765 Sequence< Type > aTypeSeq = xTypeProvider->getTypes();
1766 const Type* pTypeArray = aTypeSeq.getConstArray();
1767 sal_uInt32 nIfaceCount = aTypeSeq.getLength();
1768 for( sal_uInt32 j = 0 ; j < nIfaceCount ; j++ )
1770 const Type& rType = pTypeArray[j];
1772 Reference<XIdlClass> xClass = TypeToIdlClass( rType );
1773 if( xClass.is() )
1775 aRet.append( Impl_GetInterfaceInfo( *x, xClass, 1 ) );
1777 else
1779 typelib_TypeDescription * pTD = nullptr;
1780 rType.getDescription( &pTD );
1782 aRet.append( OUString::Concat("*** ERROR: No IdlClass for type \"")
1783 + OUString::unacquired(&pTD->pTypeName)
1784 + "\"\n*** Please check type library\n" );
1789 return aRet.makeStringAndClear();
1793 // Debugging help method SbxDataType -> String
1794 static OUString Dbg_SbxDataType2String( SbxDataType eType )
1796 OUStringBuffer aRet;
1797 switch( +eType )
1799 case SbxEMPTY: aRet.append("SbxEMPTY"); break;
1800 case SbxNULL: aRet.append("SbxNULL"); break;
1801 case SbxINTEGER: aRet.append("SbxINTEGER"); break;
1802 case SbxLONG: aRet.append("SbxLONG"); break;
1803 case SbxSINGLE: aRet.append("SbxSINGLE"); break;
1804 case SbxDOUBLE: aRet.append("SbxDOUBLE"); break;
1805 case SbxCURRENCY: aRet.append("SbxCURRENCY"); break;
1806 case SbxDECIMAL: aRet.append("SbxDECIMAL"); break;
1807 case SbxDATE: aRet.append("SbxDATE"); break;
1808 case SbxSTRING: aRet.append("SbxSTRING"); break;
1809 case SbxOBJECT: aRet.append("SbxOBJECT"); break;
1810 case SbxERROR: aRet.append("SbxERROR"); break;
1811 case SbxBOOL: aRet.append("SbxBOOL"); break;
1812 case SbxVARIANT: aRet.append("SbxVARIANT"); break;
1813 case SbxDATAOBJECT: aRet.append("SbxDATAOBJECT"); break;
1814 case SbxCHAR: aRet.append("SbxCHAR"); break;
1815 case SbxBYTE: aRet.append("SbxBYTE"); break;
1816 case SbxUSHORT: aRet.append("SbxUSHORT"); break;
1817 case SbxULONG: aRet.append("SbxULONG"); break;
1818 case SbxSALINT64: aRet.append("SbxINT64"); break;
1819 case SbxSALUINT64: aRet.append("SbxUINT64"); break;
1820 case SbxINT: aRet.append("SbxINT"); break;
1821 case SbxUINT: aRet.append("SbxUINT"); break;
1822 case SbxVOID: aRet.append("SbxVOID"); break;
1823 case SbxHRESULT: aRet.append("SbxHRESULT"); break;
1824 case SbxPOINTER: aRet.append("SbxPOINTER"); break;
1825 case SbxDIMARRAY: aRet.append("SbxDIMARRAY"); break;
1826 case SbxCARRAY: aRet.append("SbxCARRAY"); break;
1827 case SbxUSERDEF: aRet.append("SbxUSERDEF"); break;
1828 case SbxLPSTR: aRet.append("SbxLPSTR"); break;
1829 case SbxLPWSTR: aRet.append("SbxLPWSTR"); break;
1830 case SbxCoreSTRING: aRet.append("SbxCoreSTRING"); break;
1831 case SbxOBJECT | SbxARRAY: aRet.append("SbxARRAY"); break;
1832 default: aRet.append("Unknown Sbx-Type!");break;
1834 return aRet.makeStringAndClear();
1837 // Debugging help method to display the properties of a SbUnoObjects
1838 static OUString Impl_DumpProperties(SbUnoObject& rUnoObj)
1840 OUStringBuffer aRet("Properties of object " + getDbgObjectName(rUnoObj));
1842 // analyse the Uno-Infos to recognise the arrays
1843 Reference< XIntrospectionAccess > xAccess = rUnoObj.getIntrospectionAccess();
1844 if( !xAccess.is() )
1846 const Reference< XInvocation >& xInvok = rUnoObj.getInvocation();
1847 if( xInvok.is() )
1848 xAccess = xInvok->getIntrospection();
1850 if( !xAccess.is() )
1852 aRet.append( "\nUnknown, no introspection available\n" );
1853 return aRet.makeStringAndClear();
1856 Sequence<Property> props = xAccess->getProperties( PropertyConcept::ALL - PropertyConcept::DANGEROUS );
1857 sal_uInt32 nUnoPropCount = props.getLength();
1858 const Property* pUnoProps = props.getConstArray();
1860 SbxArray* pProps = rUnoObj.GetProperties();
1861 sal_uInt32 nPropCount = pProps->Count();
1862 sal_uInt32 nPropsPerLine = 1 + nPropCount / 30;
1863 for( sal_uInt32 i = 0; i < nPropCount; i++ )
1865 SbxVariable* pVar = pProps->Get(i);
1866 if( pVar )
1868 OUStringBuffer aPropStr;
1869 if( (i % nPropsPerLine) == 0 )
1870 aPropStr.append( "\n" );
1872 // output the type and name
1873 // Is it in Uno a sequence?
1874 SbxDataType eType = pVar->GetFullType();
1876 bool bMaybeVoid = false;
1877 if( i < nUnoPropCount )
1879 const Property& rProp = pUnoProps[ i ];
1881 // For MAYBEVOID freshly convert the type from Uno,
1882 // so not just SbxEMPTY is returned.
1883 if( rProp.Attributes & PropertyAttribute::MAYBEVOID )
1885 eType = unoToSbxType( rProp.Type.getTypeClass() );
1886 bMaybeVoid = true;
1888 if( eType == SbxOBJECT )
1890 Type aType = rProp.Type;
1891 if( aType.getTypeClass() == TypeClass_SEQUENCE )
1892 eType = SbxDataType( SbxOBJECT | SbxARRAY );
1895 aPropStr.append( Dbg_SbxDataType2String( eType ) );
1896 if( bMaybeVoid )
1897 aPropStr.append( "/void" );
1898 aPropStr.append( " " + pVar->GetName() );
1900 if( i == nPropCount - 1 )
1901 aPropStr.append( "\n" );
1902 else
1903 aPropStr.append( "; " );
1905 aRet.append( aPropStr );
1908 return aRet.makeStringAndClear();
1911 // Debugging help method to display the methods of an SbUnoObjects
1912 static OUString Impl_DumpMethods(SbUnoObject& rUnoObj)
1914 OUStringBuffer aRet("Methods of object " + getDbgObjectName(rUnoObj));
1916 // XIntrospectionAccess, so that the types of the parameter could be outputted
1917 Reference< XIntrospectionAccess > xAccess = rUnoObj.getIntrospectionAccess();
1918 if( !xAccess.is() )
1920 const Reference< XInvocation >& xInvok = rUnoObj.getInvocation();
1921 if( xInvok.is() )
1922 xAccess = xInvok->getIntrospection();
1924 if( !xAccess.is() )
1926 aRet.append( "\nUnknown, no introspection available\n" );
1927 return aRet.makeStringAndClear();
1929 Sequence< Reference< XIdlMethod > > methods = xAccess->getMethods
1930 ( MethodConcept::ALL - MethodConcept::DANGEROUS );
1931 const Reference< XIdlMethod >* pUnoMethods = methods.getConstArray();
1933 SbxArray* pMethods = rUnoObj.GetMethods();
1934 sal_uInt32 nMethodCount = pMethods->Count();
1935 if( !nMethodCount )
1937 aRet.append( "\nNo methods found\n" );
1938 return aRet.makeStringAndClear();
1940 sal_uInt32 nPropsPerLine = 1 + nMethodCount / 30;
1941 for( sal_uInt32 i = 0; i < nMethodCount; i++ )
1943 SbxVariable* pVar = pMethods->Get(i);
1944 if( pVar )
1946 if( (i % nPropsPerLine) == 0 )
1947 aRet.append( "\n" );
1949 // address the method
1950 const Reference< XIdlMethod >& rxMethod = pUnoMethods[i];
1952 // Is it in Uno a sequence?
1953 SbxDataType eType = pVar->GetFullType();
1954 if( eType == SbxOBJECT )
1956 Reference< XIdlClass > xClass = rxMethod->getReturnType();
1957 if( xClass.is() && xClass->getTypeClass() == TypeClass_SEQUENCE )
1958 eType = SbxDataType( SbxOBJECT | SbxARRAY );
1960 // output the name and the type
1961 aRet.append( Dbg_SbxDataType2String( eType )
1962 + " " + pVar->GetName() + " ( " );
1964 // the get-method mustn't have a parameter
1965 Sequence< Reference< XIdlClass > > aParamsSeq = rxMethod->getParameterTypes();
1966 sal_uInt32 nParamCount = aParamsSeq.getLength();
1967 const Reference< XIdlClass >* pParams = aParamsSeq.getConstArray();
1969 if( nParamCount > 0 )
1971 for( sal_uInt32 j = 0; j < nParamCount; j++ )
1973 aRet.append ( Dbg_SbxDataType2String( unoToSbxType( pParams[ j ] ) ) );
1974 if( j < nParamCount - 1 )
1975 aRet.append( ", " );
1978 else
1979 aRet.append( "void" );
1981 aRet.append( " ) " );
1983 if( i == nMethodCount - 1 )
1984 aRet.append( "\n" );
1985 else
1986 aRet.append( "; " );
1989 return aRet.makeStringAndClear();
1993 // Implementation SbUnoObject
1994 void SbUnoObject::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
1996 if( bNeedIntrospection )
1997 doIntrospection();
1999 const SbxHint* pHint = dynamic_cast<const SbxHint*>(&rHint);
2000 if( !pHint )
2001 return;
2003 SbxVariable* pVar = pHint->GetVar();
2004 SbxArray* pParams = pVar->GetParameters();
2005 SbUnoProperty* pProp = dynamic_cast<SbUnoProperty*>( pVar );
2006 SbUnoMethod* pMeth = dynamic_cast<SbUnoMethod*>( pVar );
2007 if( pProp )
2009 bool bInvocation = pProp->isInvocationBased();
2010 if( pHint->GetId() == SfxHintId::BasicDataWanted )
2012 // Test-Properties
2013 sal_Int32 nId = pProp->nId;
2014 if( nId < 0 )
2016 // Id == -1: Display implemented interfaces according the ClassProvider
2017 if( nId == -1 ) // Property ID_DBG_SUPPORTEDINTERFACES"
2019 OUString aRetStr = Impl_GetSupportedInterfaces(*this);
2020 pVar->PutString( aRetStr );
2022 // Id == -2: output properties
2023 else if( nId == -2 ) // Property ID_DBG_PROPERTIES
2025 // now all properties must be created
2026 implCreateAll();
2027 OUString aRetStr = Impl_DumpProperties(*this);
2028 pVar->PutString( aRetStr );
2030 // Id == -3: output the methods
2031 else if( nId == -3 ) // Property ID_DBG_METHODS
2033 // now all properties must be created
2034 implCreateAll();
2035 OUString aRetStr = Impl_DumpMethods(*this);
2036 pVar->PutString( aRetStr );
2038 return;
2041 if( !bInvocation && mxUnoAccess.is() )
2045 if ( maStructInfo )
2047 StructRefInfo aMember = maStructInfo->getStructMember( pProp->GetName() );
2048 if ( aMember.isEmpty() )
2050 StarBASIC::Error( ERRCODE_BASIC_PROPERTY_NOT_FOUND );
2052 else
2054 if ( pProp->isUnoStruct() )
2056 SbUnoStructRefObject* pSbUnoObject = new SbUnoStructRefObject( pProp->GetName(), std::move(aMember) );
2057 SbxObjectRef xWrapper = static_cast<SbxObject*>(pSbUnoObject);
2058 pVar->PutObject( xWrapper.get() );
2060 else
2062 Any aRetAny = aMember.getValue();
2063 // take over the value from Uno to Sbx
2064 unoToSbxValue( pVar, aRetAny );
2066 return;
2069 // get the value
2070 Reference< XPropertySet > xPropSet( mxUnoAccess->queryAdapter( cppu::UnoType<XPropertySet>::get()), UNO_QUERY );
2071 Any aRetAny = xPropSet->getPropertyValue( pProp->GetName() );
2072 // The use of getPropertyValue (instead of using the index) is
2073 // suboptimal, but the refactoring to XInvocation is already pending
2074 // Otherwise it is possible to use FastPropertySet
2076 // take over the value from Uno to Sbx
2077 unoToSbxValue( pVar, aRetAny );
2079 catch( const Exception& )
2081 implHandleAnyException( ::cppu::getCaughtException() );
2084 else if( bInvocation && mxInvocation.is() )
2088 sal_uInt32 nParamCount = pParams ? (pParams->Count() - 1) : 0;
2089 bool bCanBeConsideredAMethod = mxInvocation->hasMethod( pProp->GetName() );
2090 Any aRetAny;
2091 if ( bCanBeConsideredAMethod && nParamCount )
2093 // Automation properties have methods, so... we need to invoke this through
2094 // XInvocation
2095 Sequence<Any> args;
2096 processAutomationParams( pParams, args, nParamCount );
2097 aRetAny = invokeAutomationMethod( pProp->GetName(), args, pParams, nParamCount, mxInvocation, INVOKETYPE::GetProp );
2099 else
2100 aRetAny = mxInvocation->getValue( pProp->GetName() );
2101 // take over the value from Uno to Sbx
2102 unoToSbxValue( pVar, aRetAny );
2103 if( pParams && bCanBeConsideredAMethod )
2104 pVar->SetParameters( nullptr );
2107 catch( const Exception& )
2109 implHandleAnyException( ::cppu::getCaughtException() );
2113 else if( pHint->GetId() == SfxHintId::BasicDataChanged )
2115 if( !bInvocation && mxUnoAccess.is() )
2117 if( pProp->aUnoProp.Attributes & PropertyAttribute::READONLY )
2119 StarBASIC::Error( ERRCODE_BASIC_PROP_READONLY );
2120 return;
2122 if ( maStructInfo )
2124 StructRefInfo aMember = maStructInfo->getStructMember( pProp->GetName() );
2125 if ( aMember.isEmpty() )
2127 StarBASIC::Error( ERRCODE_BASIC_PROPERTY_NOT_FOUND );
2129 else
2131 Any aAnyValue = sbxToUnoValue( pVar, pProp->aUnoProp.Type, &pProp->aUnoProp );
2132 aMember.setValue( aAnyValue );
2134 return;
2136 // take over the value from Uno to Sbx
2137 Any aAnyValue = sbxToUnoValue( pVar, pProp->aUnoProp.Type, &pProp->aUnoProp );
2140 // set the value
2141 Reference< XPropertySet > xPropSet( mxUnoAccess->queryAdapter( cppu::UnoType<XPropertySet>::get()), UNO_QUERY );
2142 xPropSet->setPropertyValue( pProp->GetName(), aAnyValue );
2143 // The use of getPropertyValue (instead of using the index) is
2144 // suboptimal, but the refactoring to XInvocation is already pending
2145 // Otherwise it is possible to use FastPropertySet
2147 catch( const Exception& )
2149 implHandleAnyException( ::cppu::getCaughtException() );
2152 else if( bInvocation && mxInvocation.is() )
2154 // take over the value from Uno to Sbx
2155 Any aAnyValue = sbxToUnoValueImpl( pVar );
2158 // set the value
2159 mxInvocation->setValue( pProp->GetName(), aAnyValue );
2161 catch( const Exception& )
2163 implHandleAnyException( ::cppu::getCaughtException() );
2168 else if( pMeth )
2170 bool bInvocation = pMeth->isInvocationBased();
2171 if( pHint->GetId() == SfxHintId::BasicDataWanted )
2173 // number of Parameter -1 because of Param0 == this
2174 sal_uInt32 nParamCount = pParams ? (pParams->Count() - 1) : 0;
2175 Sequence<Any> args;
2176 bool bOutParams = false;
2178 if( !bInvocation && mxUnoAccess.is() )
2180 // get info
2181 const Sequence<ParamInfo>& rInfoSeq = pMeth->getParamInfos();
2182 const ParamInfo* pParamInfos = rInfoSeq.getConstArray();
2183 sal_uInt32 nUnoParamCount = rInfoSeq.getLength();
2184 sal_uInt32 nAllocParamCount = nParamCount;
2186 // ignore surplus parameter; alternative: throw an error
2187 if( nParamCount > nUnoParamCount )
2189 nParamCount = nUnoParamCount;
2190 nAllocParamCount = nParamCount;
2192 else if( nParamCount < nUnoParamCount )
2194 SbiInstance* pInst = GetSbData()->pInst;
2195 if( pInst && pInst->IsCompatibility() )
2197 // Check types
2198 bool bError = false;
2199 for( sal_uInt32 i = nParamCount ; i < nUnoParamCount ; i++ )
2201 const ParamInfo& rInfo = pParamInfos[i];
2202 const Reference< XIdlClass >& rxClass = rInfo.aType;
2203 if( rxClass->getTypeClass() != TypeClass_ANY )
2205 bError = true;
2206 StarBASIC::Error( ERRCODE_BASIC_NOT_OPTIONAL );
2209 if( !bError )
2210 nAllocParamCount = nUnoParamCount;
2214 if( nAllocParamCount > 0 )
2216 args.realloc( nAllocParamCount );
2217 Any* pAnyArgs = args.getArray();
2218 for( sal_uInt32 i = 0 ; i < nParamCount ; i++ )
2220 const ParamInfo& rInfo = pParamInfos[i];
2221 const Reference< XIdlClass >& rxClass = rInfo.aType;
2223 css::uno::Type aType( rxClass->getTypeClass(), rxClass->getName() );
2225 // ATTENTION: Don't forget for Sbx-Parameter the offset!
2226 pAnyArgs[i] = sbxToUnoValue(pParams->Get(i + 1), aType);
2228 // If it is not certain check whether the out-parameter are available.
2229 if( !bOutParams )
2231 ParamMode aParamMode = rInfo.aMode;
2232 if( aParamMode != ParamMode_IN )
2233 bOutParams = true;
2238 else if( bInvocation && pParams && mxInvocation.is() )
2240 processAutomationParams( pParams, args, nParamCount );
2243 // call the method
2244 GetSbData()->bBlockCompilerError = true; // #106433 Block compiler errors for API calls
2247 if( !bInvocation && mxUnoAccess.is() )
2249 Any aRetAny = pMeth->m_xUnoMethod->invoke( getUnoAny(), args );
2251 // take over the value from Uno to Sbx
2252 unoToSbxValue( pVar, aRetAny );
2254 // Did we to copy back the Out-Parameter?
2255 if( bOutParams )
2257 const Any* pAnyArgs = args.getConstArray();
2259 // get info
2260 const Sequence<ParamInfo>& rInfoSeq = pMeth->getParamInfos();
2261 const ParamInfo* pParamInfos = rInfoSeq.getConstArray();
2263 sal_uInt32 j;
2264 for( j = 0 ; j < nParamCount ; j++ )
2266 const ParamInfo& rInfo = pParamInfos[j];
2267 ParamMode aParamMode = rInfo.aMode;
2268 if( aParamMode != ParamMode_IN )
2269 unoToSbxValue(pParams->Get(j + 1), pAnyArgs[j]);
2273 else if( bInvocation && mxInvocation.is() )
2275 Any aRetAny = invokeAutomationMethod( pMeth->GetName(), args, pParams, nParamCount, mxInvocation, INVOKETYPE::Func );
2276 unoToSbxValue( pVar, aRetAny );
2279 // remove parameter here, because this was not done anymore in unoToSbxValue()
2280 // for arrays
2281 if( pParams )
2282 pVar->SetParameters( nullptr );
2284 catch( const Exception& )
2286 implHandleAnyException( ::cppu::getCaughtException() );
2288 GetSbData()->bBlockCompilerError = false; // #106433 Unblock compiler errors
2291 else
2292 SbxObject::Notify( rBC, rHint );
2296 SbUnoObject::SbUnoObject( const OUString& aName_, const Any& aUnoObj_ )
2297 : SbxObject( aName_ )
2298 , bNeedIntrospection( true )
2299 , bNativeCOMObject( false )
2301 // beat out again the default properties of Sbx
2302 Remove( u"Name"_ustr, SbxClassType::DontCare );
2303 Remove( u"Parent"_ustr, SbxClassType::DontCare );
2305 // check the type of the objects
2306 TypeClass eType = aUnoObj_.getValueTypeClass();
2307 Reference< XInterface > x;
2308 if( eType == TypeClass_INTERFACE )
2310 // get the interface from the Any
2311 aUnoObj_ >>= x;
2312 if( !x.is() )
2313 return;
2316 // Did the object have an invocation itself?
2317 mxInvocation.set( x, UNO_QUERY );
2319 if( mxInvocation.is() )
2322 // get the ExactName
2323 mxExactNameInvocation.set( mxInvocation, UNO_QUERY );
2325 // The remainder refers only to the introspection
2326 Reference< XTypeProvider > xTypeProvider( x, UNO_QUERY );
2327 if( !xTypeProvider.is() )
2329 bNeedIntrospection = false;
2330 return;
2333 // Ignore introspection based members for COM objects to avoid
2334 // hiding of equally named COM symbols, e.g. XInvocation::getValue
2335 Reference< oleautomation::XAutomationObject > xAutomationObject( aUnoObj_, UNO_QUERY );
2336 if( xAutomationObject.is() )
2337 bNativeCOMObject = true;
2340 maTmpUnoObj = aUnoObj_;
2343 //*** Define the name ***
2344 bool bFatalError = true;
2346 // Is it an interface or a struct?
2347 bool bSetClassName = false;
2348 OUString aClassName_;
2349 if( eType == TypeClass_STRUCT || eType == TypeClass_EXCEPTION )
2351 // Struct is Ok
2352 bFatalError = false;
2354 // insert the real name of the class
2355 if( aName_.isEmpty() )
2357 aClassName_ = aUnoObj_.getValueTypeName();
2358 bSetClassName = true;
2360 StructRefInfo aThisStruct( maTmpUnoObj, maTmpUnoObj.getValueType(), 0 );
2361 maStructInfo = std::make_shared<SbUnoStructRefObject>( GetName(), aThisStruct );
2363 else if( eType == TypeClass_INTERFACE )
2365 // Interface works always through the type in the Any
2366 bFatalError = false;
2368 if( bSetClassName )
2369 SetClassName( aClassName_ );
2371 // Neither interface nor Struct -> FatalError
2372 if( bFatalError )
2374 StarBASIC::FatalError( ERRCODE_BASIC_EXCEPTION );
2375 return;
2378 // pass the introspection primal on demand
2381 SbUnoObject::~SbUnoObject()
2386 // pass the introspection on Demand
2387 void SbUnoObject::doIntrospection()
2389 if( !bNeedIntrospection )
2390 return;
2392 const Reference<XComponentContext>& xContext = comphelper::getProcessComponentContext();
2394 if (!xContext.is())
2395 return;
2398 // get the introspection service
2399 Reference<XIntrospection> xIntrospection;
2403 xIntrospection = theIntrospection::get(xContext);
2405 catch ( const css::uno::DeploymentException& )
2409 if (!xIntrospection.is())
2410 return;
2412 bNeedIntrospection = false;
2414 // pass the introspection
2417 mxUnoAccess = xIntrospection->inspect( maTmpUnoObj );
2419 catch( const RuntimeException& e )
2421 StarBASIC::Error( ERRCODE_BASIC_EXCEPTION, implGetExceptionMsg( e ) );
2424 if( !mxUnoAccess.is() )
2426 // #51475 mark to indicate an invalid object (no mxMaterialHolder)
2427 return;
2430 // get MaterialHolder from access
2431 mxMaterialHolder.set( mxUnoAccess, UNO_QUERY );
2433 // get ExactName from access
2434 mxExactName.set( mxUnoAccess, UNO_QUERY );
2438 // Start of a list of all SbUnoMethod-Instances
2439 static SbUnoMethod* s_pFirst = nullptr;
2441 void clearUnoMethodsForBasic( StarBASIC const * pBasic )
2443 SbUnoMethod* pMeth = s_pFirst;
2444 while( pMeth )
2446 SbxObject* pObject = pMeth->GetParent();
2447 if ( pObject )
2449 StarBASIC* pModBasic = dynamic_cast< StarBASIC* >( pObject->GetParent() );
2450 if ( pModBasic == pBasic )
2452 // for now the solution is to remove the method from the list and to clear it,
2453 // but in case the element should be correctly transferred to another StarBASIC,
2454 // we should either set module parent to NULL without clearing it, or even
2455 // set the new StarBASIC as the parent of the module
2456 // pObject->SetParent( NULL );
2458 if( pMeth == s_pFirst )
2459 s_pFirst = pMeth->pNext;
2460 else if( pMeth->pPrev )
2461 pMeth->pPrev->pNext = pMeth->pNext;
2462 if( pMeth->pNext )
2463 pMeth->pNext->pPrev = pMeth->pPrev;
2465 pMeth->pPrev = nullptr;
2466 pMeth->pNext = nullptr;
2468 pMeth->SbxValue::Clear();
2469 pObject->SbxValue::Clear();
2471 // start from the beginning after object clearing, the cycle will end since the method is removed each time
2472 pMeth = s_pFirst;
2474 else
2475 pMeth = pMeth->pNext;
2477 else
2478 pMeth = pMeth->pNext;
2482 void clearUnoMethods()
2484 SbUnoMethod* pMeth = s_pFirst;
2485 while( pMeth )
2487 pMeth->SbxValue::Clear();
2488 pMeth = pMeth->pNext;
2493 SbUnoMethod::SbUnoMethod
2495 const OUString& aName_,
2496 SbxDataType eSbxType,
2497 Reference< XIdlMethod > const & xUnoMethod_,
2498 bool bInvocation
2500 : SbxMethod( aName_, eSbxType )
2501 , mbInvocation( bInvocation )
2503 m_xUnoMethod = xUnoMethod_;
2504 pParamInfoSeq = nullptr;
2506 // enregister the method in a list
2507 pNext = s_pFirst;
2508 pPrev = nullptr;
2509 s_pFirst = this;
2510 if( pNext )
2511 pNext->pPrev = this;
2514 SbUnoMethod::~SbUnoMethod()
2516 pParamInfoSeq.reset();
2518 if( this == s_pFirst )
2519 s_pFirst = pNext;
2520 else if( pPrev )
2521 pPrev->pNext = pNext;
2522 if( pNext )
2523 pNext->pPrev = pPrev;
2526 SbxInfo* SbUnoMethod::GetInfo()
2528 if( !pInfo.is() && m_xUnoMethod.is() )
2530 SbiInstance* pInst = GetSbData()->pInst;
2531 if( pInst && pInst->IsCompatibility() )
2533 pInfo = new SbxInfo();
2535 const Sequence<ParamInfo>& rInfoSeq = getParamInfos();
2536 const ParamInfo* pParamInfos = rInfoSeq.getConstArray();
2537 sal_uInt32 nParamCount = rInfoSeq.getLength();
2539 for( sal_uInt32 i = 0 ; i < nParamCount ; i++ )
2541 const ParamInfo& rInfo = pParamInfos[i];
2542 OUString aParamName = rInfo.aName;
2544 pInfo->AddParam( aParamName, SbxVARIANT, SbxFlagBits::Read );
2548 return pInfo.get();
2551 const Sequence<ParamInfo>& SbUnoMethod::getParamInfos()
2553 if (!pParamInfoSeq)
2555 Sequence<ParamInfo> aTmp;
2556 if (m_xUnoMethod.is())
2557 aTmp = m_xUnoMethod->getParameterInfos();
2558 pParamInfoSeq.reset( new Sequence<ParamInfo>(aTmp) );
2560 return *pParamInfoSeq;
2563 SbUnoProperty::SbUnoProperty
2565 const OUString& aName_,
2566 SbxDataType eSbxType,
2567 SbxDataType eRealSbxType,
2568 Property aUnoProp_,
2569 sal_Int32 nId_,
2570 bool bInvocation,
2571 bool bUnoStruct
2573 : SbxProperty( aName_, eSbxType )
2574 , aUnoProp(std::move( aUnoProp_ ))
2575 , nId( nId_ )
2576 , mbInvocation( bInvocation )
2577 , mRealType( eRealSbxType )
2578 , mbUnoStruct( bUnoStruct )
2580 // as needed establish a dummy array so that SbiRuntime::CheckArray() works
2581 static SbxArrayRef xDummyArray = new SbxArray( SbxVARIANT );
2582 if( eSbxType & SbxARRAY )
2583 PutObject( xDummyArray.get() );
2586 SbUnoProperty::~SbUnoProperty()
2589 bool isVeryLargeUnoProperty(SbxVariable const * pVar)
2591 auto pUnoVar = dynamic_cast<const SbUnoProperty*>(pVar);
2592 if (!pUnoVar)
2593 return false;
2594 // The ScCellRangeObj methods will attempt to generate massive strings,
2595 // which will use up massive amounts of RAM and also lock of the program
2596 // for some time.
2597 const OUString & aUnoName = pUnoVar->getUnoName();
2598 if (aUnoName == "DataArray" || aUnoName == "FormulaArray")
2600 auto pParent = dynamic_cast<const SbUnoObject*>(pUnoVar->GetParent());
2601 if (!pParent)
2602 return false;
2603 css::uno::Any aAny = const_cast<SbUnoObject*>(pParent)->getUnoAny();
2604 css::uno::Reference<css::sheet::XSheetCellCursor> xCursor = aAny.query<css::sheet::XSheetCellCursor>();
2605 if (xCursor)
2606 return true;
2608 return false;
2611 SbxVariable* SbUnoObject::Find( const OUString& rName, SbxClassType t )
2613 static Reference< XIdlMethod > xDummyMethod;
2614 static Property aDummyProp;
2616 SbxVariable* pRes = SbxObject::Find( rName, t );
2618 if( bNeedIntrospection )
2619 doIntrospection();
2621 // New 1999-03-04: Create properties on demand. Therefore search now via
2622 // IntrospectionAccess if a property or a method of the required name exist
2623 if( !pRes )
2625 OUString aUName( rName );
2626 if( mxUnoAccess.is() && !bNativeCOMObject )
2628 if( mxExactName.is() )
2630 OUString aUExactName = mxExactName->getExactName( aUName );
2631 if( !aUExactName.isEmpty() )
2633 aUName = aUExactName;
2636 if( mxUnoAccess->hasProperty( aUName, PropertyConcept::ALL - PropertyConcept::DANGEROUS ) )
2638 const Property aProp = mxUnoAccess->
2639 getProperty( aUName, PropertyConcept::ALL - PropertyConcept::DANGEROUS );
2641 // If the property could be void the type had to be set to Variant
2642 SbxDataType eSbxType;
2643 if( aProp.Attributes & PropertyAttribute::MAYBEVOID )
2644 eSbxType = SbxVARIANT;
2645 else
2646 eSbxType = unoToSbxType( aProp.Type.getTypeClass() );
2648 SbxDataType eRealSbxType = ( ( aProp.Attributes & PropertyAttribute::MAYBEVOID ) ? unoToSbxType( aProp.Type.getTypeClass() ) : eSbxType );
2649 // create the property and superimpose it
2650 auto pProp = tools::make_ref<SbUnoProperty>( aProp.Name, eSbxType, eRealSbxType, aProp, 0, false, ( aProp.Type.getTypeClass() == css::uno::TypeClass_STRUCT ) );
2651 QuickInsert( pProp.get() );
2652 pRes = pProp.get();
2654 else if( mxUnoAccess->hasMethod( aUName,
2655 MethodConcept::ALL - MethodConcept::DANGEROUS ) )
2657 // address the method
2658 const Reference< XIdlMethod > xMethod = mxUnoAccess->
2659 getMethod( aUName, MethodConcept::ALL - MethodConcept::DANGEROUS );
2661 // create SbUnoMethod and superimpose it
2662 auto xMethRef = tools::make_ref<SbUnoMethod>( xMethod->getName(),
2663 unoToSbxType( xMethod->getReturnType() ), xMethod, false );
2664 QuickInsert( xMethRef.get() );
2665 pRes = xMethRef.get();
2668 // If nothing was found check via XNameAccess
2669 if( !pRes )
2673 Reference< XNameAccess > xNameAccess( mxUnoAccess->queryAdapter( cppu::UnoType<XPropertySet>::get()), UNO_QUERY );
2675 if( xNameAccess.is() && xNameAccess->hasByName( rName ) )
2677 Any aAny = xNameAccess->getByName( rName );
2679 // ATTENTION: Because of XNameAccess, the variable generated here
2680 // may not be included as a fixed property in the object and therefore
2681 // won't be stored anywhere.
2682 // If this leads to problems, it has to be created
2683 // synthetically or a class SbUnoNameAccessProperty,
2684 // which checks the existence on access and which
2685 // is disposed if the name is not found anymore.
2686 pRes = new SbxVariable( SbxVARIANT );
2687 unoToSbxValue( pRes, aAny );
2690 catch( const NoSuchElementException& e )
2692 StarBASIC::Error( ERRCODE_BASIC_EXCEPTION, implGetExceptionMsg( e ) );
2694 catch( const Exception& )
2696 // Establish so that the exception error will not be overwritten
2697 if( !pRes )
2698 pRes = new SbxVariable( SbxVARIANT );
2700 implHandleAnyException( ::cppu::getCaughtException() );
2704 if( !pRes && mxInvocation.is() )
2706 if( mxExactNameInvocation.is() )
2708 OUString aUExactName = mxExactNameInvocation->getExactName( aUName );
2709 if( !aUExactName.isEmpty() )
2711 aUName = aUExactName;
2717 if( mxInvocation->hasProperty( aUName ) )
2719 // create a property and superimpose it
2720 auto xVarRef = tools::make_ref<SbUnoProperty>( aUName, SbxVARIANT, SbxVARIANT, aDummyProp, 0, true, false );
2721 QuickInsert( xVarRef.get() );
2722 pRes = xVarRef.get();
2724 else if( mxInvocation->hasMethod( aUName ) )
2726 // create SbUnoMethode and superimpose it
2727 auto xMethRef = tools::make_ref<SbUnoMethod>( aUName, SbxVARIANT, xDummyMethod, true );
2728 QuickInsert( xMethRef.get() );
2729 pRes = xMethRef.get();
2731 else
2733 Reference< XDirectInvocation > xDirectInvoke( mxInvocation, UNO_QUERY );
2734 if ( xDirectInvoke.is() && xDirectInvoke->hasMember( aUName ) )
2736 auto xMethRef = tools::make_ref<SbUnoMethod>( aUName, SbxVARIANT, xDummyMethod, true );
2737 QuickInsert( xMethRef.get() );
2738 pRes = xMethRef.get();
2743 catch( const RuntimeException& e )
2745 // Establish so that the exception error will not be overwritten
2746 if( !pRes )
2747 pRes = new SbxVariable( SbxVARIANT );
2749 StarBASIC::Error( ERRCODE_BASIC_EXCEPTION, implGetExceptionMsg( e ) );
2754 // At the very end checking if the Dbg_-Properties are meant
2756 if( !pRes )
2758 if( rName.equalsIgnoreAsciiCase(ID_DBG_SUPPORTEDINTERFACES) ||
2759 rName.equalsIgnoreAsciiCase(ID_DBG_PROPERTIES) ||
2760 rName.equalsIgnoreAsciiCase(ID_DBG_METHODS) )
2762 // Create
2763 implCreateDbgProperties();
2765 // Now they have to be found regular
2766 pRes = SbxObject::Find( rName, SbxClassType::DontCare );
2769 return pRes;
2773 // help method to create the dbg_-Properties
2774 void SbUnoObject::implCreateDbgProperties()
2776 Property aProp;
2778 // Id == -1: display the implemented interfaces corresponding the ClassProvider
2779 auto xVarRef = tools::make_ref<SbUnoProperty>( ID_DBG_SUPPORTEDINTERFACES, SbxSTRING, SbxSTRING, aProp, -1, false, false );
2780 QuickInsert( xVarRef.get() );
2782 // Id == -2: output the properties
2783 xVarRef = tools::make_ref<SbUnoProperty>( ID_DBG_PROPERTIES, SbxSTRING, SbxSTRING, aProp, -2, false, false );
2784 QuickInsert( xVarRef.get() );
2786 // Id == -3: output the Methods
2787 xVarRef = tools::make_ref<SbUnoProperty>( ID_DBG_METHODS, SbxSTRING, SbxSTRING, aProp, -3, false, false );
2788 QuickInsert( xVarRef.get() );
2791 void SbUnoObject::implCreateAll()
2793 // throw away all existing methods and properties
2794 pMethods = tools::make_ref<SbxArray>();
2795 pProps = tools::make_ref<SbxArray>();
2797 if( bNeedIntrospection ) doIntrospection();
2799 // get introspection
2800 Reference< XIntrospectionAccess > xAccess = mxUnoAccess;
2801 if( !xAccess.is() || bNativeCOMObject )
2803 if( mxInvocation.is() )
2804 xAccess = mxInvocation->getIntrospection();
2805 else if( bNativeCOMObject )
2806 return;
2808 if( !xAccess.is() )
2809 return;
2811 // Establish properties
2812 Sequence<Property> props = xAccess->getProperties( PropertyConcept::ALL - PropertyConcept::DANGEROUS );
2813 sal_uInt32 nPropCount = props.getLength();
2814 const Property* pProps_ = props.getConstArray();
2816 sal_uInt32 i;
2817 for( i = 0 ; i < nPropCount ; i++ )
2819 const Property& rProp = pProps_[ i ];
2821 // If the property could be void the type had to be set to Variant
2822 SbxDataType eSbxType;
2823 if( rProp.Attributes & PropertyAttribute::MAYBEVOID )
2824 eSbxType = SbxVARIANT;
2825 else
2826 eSbxType = unoToSbxType( rProp.Type.getTypeClass() );
2828 SbxDataType eRealSbxType = ( ( rProp.Attributes & PropertyAttribute::MAYBEVOID ) ? unoToSbxType( rProp.Type.getTypeClass() ) : eSbxType );
2829 // Create property and superimpose it
2830 auto xVarRef = tools::make_ref<SbUnoProperty>( rProp.Name, eSbxType, eRealSbxType, rProp, i, false, ( rProp.Type.getTypeClass() == css::uno::TypeClass_STRUCT ) );
2831 QuickInsert( xVarRef.get() );
2834 // Create Dbg_-Properties
2835 implCreateDbgProperties();
2837 // Create methods
2838 Sequence< Reference< XIdlMethod > > aMethodSeq = xAccess->getMethods
2839 ( MethodConcept::ALL - MethodConcept::DANGEROUS );
2840 sal_uInt32 nMethCount = aMethodSeq.getLength();
2841 const Reference< XIdlMethod >* pMethods_ = aMethodSeq.getConstArray();
2842 for( i = 0 ; i < nMethCount ; i++ )
2844 // address method
2845 const Reference< XIdlMethod >& rxMethod = pMethods_[i];
2847 // Create SbUnoMethod and superimpose it
2848 auto xMethRef = tools::make_ref<SbUnoMethod>
2849 ( rxMethod->getName(), unoToSbxType( rxMethod->getReturnType() ), rxMethod, false );
2850 QuickInsert( xMethRef.get() );
2855 // output the value
2856 Any SbUnoObject::getUnoAny()
2858 Any aRetAny;
2859 if( bNeedIntrospection ) doIntrospection();
2860 if ( maStructInfo )
2861 aRetAny = maTmpUnoObj;
2862 else if( mxMaterialHolder.is() )
2863 aRetAny = mxMaterialHolder->getMaterial();
2864 else if( mxInvocation.is() )
2865 aRetAny <<= mxInvocation;
2866 return aRetAny;
2869 // help method to create a Uno-Struct per CoreReflection
2870 static SbUnoObjectRef Impl_CreateUnoStruct( const OUString& aClassName )
2872 // get CoreReflection
2873 Reference< XIdlReflection > xCoreReflection = getCoreReflection_Impl();
2874 if( !xCoreReflection.is() )
2875 return nullptr;
2877 // search for the class
2878 Reference< XIdlClass > xClass;
2879 const Reference< XHierarchicalNameAccess >& xHarryName =
2880 getCoreReflection_HierarchicalNameAccess_Impl();
2881 if( xHarryName.is() && xHarryName->hasByHierarchicalName( aClassName ) )
2882 xClass = xCoreReflection->forName( aClassName );
2883 if( !xClass.is() )
2884 return nullptr;
2886 // Is it really a struct?
2887 TypeClass eType = xClass->getTypeClass();
2888 if ( ( eType != TypeClass_STRUCT ) && ( eType != TypeClass_EXCEPTION ) )
2889 return nullptr;
2891 // create an instance
2892 Any aNewAny;
2893 xClass->createObject( aNewAny );
2894 // make a SbUnoObject out of it
2895 SbUnoObjectRef pUnoObj = new SbUnoObject( aClassName, aNewAny );
2896 return pUnoObj;
2900 // Factory-Class to create Uno-Structs per DIM AS NEW
2901 SbxBaseRef SbUnoFactory::Create( sal_uInt16, sal_uInt32 )
2903 // Via SbxId nothing works in Uno
2904 return nullptr;
2907 SbxObjectRef SbUnoFactory::CreateObject( const OUString& rClassName )
2909 return Impl_CreateUnoStruct( rClassName ).get();
2913 // Provisional interface for the UNO-Connection
2914 // Deliver a SbxObject, that wrap a Uno-Interface
2915 SbxObjectRef GetSbUnoObject( const OUString& aName, const Any& aUnoObj_ )
2917 return new SbUnoObject( aName, aUnoObj_ );
2920 // Force creation of all properties for debugging
2921 void createAllObjectProperties( SbxObject* pObj )
2923 if( !pObj )
2924 return;
2926 SbUnoObject* pUnoObj = dynamic_cast<SbUnoObject*>( pObj );
2927 SbUnoStructRefObject* pUnoStructObj = dynamic_cast<SbUnoStructRefObject*>( pObj );
2928 if( pUnoObj )
2930 pUnoObj->createAllProperties();
2932 else if ( pUnoStructObj )
2934 pUnoStructObj->createAllProperties();
2939 void RTL_Impl_CreateUnoStruct( SbxArray& rPar )
2941 // We need 1 parameter minimum
2942 if (rPar.Count() < 2)
2944 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
2945 return;
2948 // get the name of the class of the struct
2949 OUString aClassName = rPar.Get(1)->GetOUString();
2951 // try to create Struct with the same name
2952 SbUnoObjectRef xUnoObj = Impl_CreateUnoStruct( aClassName );
2953 if( !xUnoObj.is() )
2955 return;
2957 // return the object
2958 SbxVariableRef refVar = rPar.Get(0);
2959 refVar->PutObject( xUnoObj.get() );
2962 void RTL_Impl_CreateUnoService( SbxArray& rPar )
2964 // We need 1 Parameter minimum
2965 if (rPar.Count() < 2)
2967 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
2968 return;
2971 // get the name of the class of the struct
2972 OUString aServiceName = rPar.Get(1)->GetOUString();
2974 // search for the service and instantiate it
2975 Reference< XMultiServiceFactory > xFactory( comphelper::getProcessServiceFactory() );
2976 Reference< XInterface > xInterface;
2979 xInterface = xFactory->createInstance( aServiceName );
2981 catch( const Exception& )
2983 implHandleAnyException( ::cppu::getCaughtException() );
2986 SbxVariableRef refVar = rPar.Get(0);
2987 if( xInterface.is() )
2989 // Create a SbUnoObject out of it and return it
2990 SbUnoObjectRef xUnoObj = new SbUnoObject( aServiceName, Any(xInterface) );
2991 if( xUnoObj->getUnoAny().hasValue() )
2993 // return the object
2994 refVar->PutObject( xUnoObj.get() );
2996 else
2998 refVar->PutObject( nullptr );
3001 else
3003 refVar->PutObject( nullptr );
3007 void RTL_Impl_CreateUnoServiceWithArguments( SbxArray& rPar )
3009 // We need 2 parameter minimum
3010 if (rPar.Count() < 3)
3012 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
3013 return;
3016 // get the name of the class of the struct
3017 OUString aServiceName = rPar.Get(1)->GetOUString();
3018 Any aArgAsAny = sbxToUnoValue(rPar.Get(2),
3019 cppu::UnoType<Sequence<Any>>::get() );
3020 Sequence< Any > aArgs;
3021 aArgAsAny >>= aArgs;
3023 // search for the service and instantiate it
3024 Reference< XMultiServiceFactory > xFactory( comphelper::getProcessServiceFactory() );
3025 Reference< XInterface > xInterface;
3028 xInterface = xFactory->createInstanceWithArguments( aServiceName, aArgs );
3030 catch( const Exception& )
3032 implHandleAnyException( ::cppu::getCaughtException() );
3035 SbxVariableRef refVar = rPar.Get(0);
3036 if( xInterface.is() )
3038 // Create a SbUnoObject out of it and return it
3039 SbUnoObjectRef xUnoObj = new SbUnoObject( aServiceName, Any(xInterface) );
3040 if( xUnoObj->getUnoAny().hasValue() )
3042 // return the object
3043 refVar->PutObject( xUnoObj.get() );
3045 else
3047 refVar->PutObject( nullptr );
3050 else
3052 refVar->PutObject( nullptr );
3056 void RTL_Impl_GetProcessServiceManager( SbxArray& rPar )
3058 SbxVariableRef refVar = rPar.Get(0);
3060 // get the global service manager
3061 Reference< XMultiServiceFactory > xFactory( comphelper::getProcessServiceFactory() );
3063 // Create a SbUnoObject out of it and return it
3064 SbUnoObjectRef xUnoObj = new SbUnoObject( u"ProcessServiceManager"_ustr, Any(xFactory) );
3065 refVar->PutObject( xUnoObj.get() );
3068 void RTL_Impl_HasInterfaces( SbxArray& rPar )
3070 // We need 2 parameter minimum
3071 sal_uInt32 nParCount = rPar.Count();
3072 if( nParCount < 3 )
3074 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
3075 return;
3078 // variable for the return value
3079 SbxVariableRef refVar = rPar.Get(0);
3080 refVar->PutBool( false );
3082 // get the Uno-Object
3083 SbxBaseRef pObj = rPar.Get(1)->GetObject();
3084 auto obj = dynamic_cast<SbUnoObject*>( pObj.get() );
3085 if( obj == nullptr )
3087 return;
3089 Any aAny = obj->getUnoAny();
3090 auto x = o3tl::tryAccess<Reference<XInterface>>(aAny);
3091 if( !x )
3093 return;
3096 // get CoreReflection
3097 Reference< XIdlReflection > xCoreReflection = getCoreReflection_Impl();
3098 if( !xCoreReflection.is() )
3100 return;
3102 for( sal_uInt32 i = 2 ; i < nParCount ; i++ )
3104 // get the name of the interface of the struct
3105 OUString aIfaceName = rPar.Get(i)->GetOUString();
3107 // search for the class
3108 Reference< XIdlClass > xClass = xCoreReflection->forName( aIfaceName );
3109 if( !xClass.is() )
3111 return;
3113 // check if the interface will be supported
3114 OUString aClassName = xClass->getName();
3115 Type aClassType( xClass->getTypeClass(), aClassName );
3116 if( !(*x)->queryInterface( aClassType ).hasValue() )
3118 return;
3122 // Everything works; then return TRUE
3123 refVar->PutBool( true );
3126 void RTL_Impl_IsUnoStruct( SbxArray& rPar )
3128 // We need 1 parameter minimum
3129 if (rPar.Count() < 2)
3131 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
3132 return;
3135 // variable for the return value
3136 SbxVariableRef refVar = rPar.Get(0);
3137 refVar->PutBool( false );
3139 // get the Uno-Object
3140 SbxVariableRef xParam = rPar.Get(1);
3141 if( !xParam->IsObject() )
3143 return;
3145 SbxBaseRef pObj = xParam->GetObject();
3146 auto obj = dynamic_cast<SbUnoObject*>( pObj.get() );
3147 if( obj == nullptr )
3149 return;
3151 Any aAny = obj->getUnoAny();
3152 TypeClass eType = aAny.getValueTypeClass();
3153 if( eType == TypeClass_STRUCT )
3155 refVar->PutBool( true );
3160 void RTL_Impl_EqualUnoObjects( SbxArray& rPar )
3162 if (rPar.Count() < 3)
3164 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
3165 return;
3168 // variable for the return value
3169 SbxVariableRef refVar = rPar.Get(0);
3170 refVar->PutBool( false );
3172 // get the Uno-Objects
3173 SbxVariableRef xParam1 = rPar.Get(1);
3174 if( !xParam1->IsObject() )
3176 return;
3178 SbxBaseRef pObj1 = xParam1->GetObject();
3179 auto obj1 = dynamic_cast<SbUnoObject*>( pObj1.get() );
3180 if( obj1 == nullptr )
3182 return;
3184 Any aAny1 = obj1->getUnoAny();
3185 TypeClass eType1 = aAny1.getValueTypeClass();
3186 if( eType1 != TypeClass_INTERFACE )
3188 return;
3190 Reference< XInterface > x1;
3191 aAny1 >>= x1;
3193 SbxVariableRef xParam2 = rPar.Get(2);
3194 if( !xParam2->IsObject() )
3196 return;
3198 SbxBaseRef pObj2 = xParam2->GetObject();
3199 auto obj2 = dynamic_cast<SbUnoObject*>( pObj2.get() );
3200 if( obj2 == nullptr )
3202 return;
3204 Any aAny2 = obj2->getUnoAny();
3205 TypeClass eType2 = aAny2.getValueTypeClass();
3206 if( eType2 != TypeClass_INTERFACE )
3208 return;
3210 Reference< XInterface > x2;
3211 aAny2 >>= x2;
3213 if( x1 == x2 )
3215 refVar->PutBool( true );
3220 // helper wrapper function to interact with TypeProvider and
3221 // XTypeDescriptionEnumerationAccess.
3222 // if it fails for whatever reason
3223 // returned Reference<> be null e.g. .is() will be false
3225 static Reference< XTypeDescriptionEnumeration > getTypeDescriptorEnumeration( const OUString& sSearchRoot,
3226 const Sequence< TypeClass >& types,
3227 TypeDescriptionSearchDepth depth )
3229 Reference< XTypeDescriptionEnumeration > xEnum;
3230 Reference< XTypeDescriptionEnumerationAccess> xTypeEnumAccess( getTypeProvider_Impl(), UNO_QUERY );
3231 if ( xTypeEnumAccess.is() )
3235 xEnum = xTypeEnumAccess->createTypeDescriptionEnumeration(
3236 sSearchRoot, types, depth );
3238 catch(const NoSuchTypeNameException& /*nstne*/ ) {}
3239 catch(const InvalidTypeNameException& /*nstne*/ ) {}
3241 return xEnum;
3244 VBAConstantHelper&
3245 VBAConstantHelper::instance()
3247 static VBAConstantHelper aHelper;
3248 return aHelper;
3251 void VBAConstantHelper::init()
3253 if ( isInited )
3254 return;
3256 Reference< XTypeDescriptionEnumeration > xEnum = getTypeDescriptorEnumeration( u"ooo.vba"_ustr, {TypeClass_CONSTANTS}, TypeDescriptionSearchDepth_INFINITE );
3258 if ( !xEnum.is())
3260 return; //NULL;
3262 while ( xEnum->hasMoreElements() )
3264 Reference< XConstantsTypeDescription > xConstants( xEnum->nextElement(), UNO_QUERY );
3265 if ( xConstants.is() )
3267 // store constant group name
3268 OUString sFullName = xConstants->getName();
3269 sal_Int32 indexLastDot = sFullName.lastIndexOf('.');
3270 OUString sLeafName( sFullName );
3271 if ( indexLastDot > -1 )
3273 sLeafName = sFullName.copy( indexLastDot + 1);
3275 aConstCache.push_back( sLeafName ); // assume constant group names are unique
3276 const Sequence< Reference< XConstantTypeDescription > > aConsts = xConstants->getConstants();
3277 for (const auto& ctd : aConsts)
3279 // store constant member name
3280 sFullName = ctd->getName();
3281 indexLastDot = sFullName.lastIndexOf('.');
3282 sLeafName = sFullName;
3283 if ( indexLastDot > -1 )
3285 sLeafName = sFullName.copy( indexLastDot + 1);
3287 aConstHash[ sLeafName.toAsciiLowerCase() ] = ctd->getConstantValue();
3291 isInited = true;
3294 bool
3295 VBAConstantHelper::isVBAConstantType( std::u16string_view rName )
3297 init();
3298 bool bConstant = false;
3300 for (auto const& elem : aConstCache)
3302 if( o3tl::equalsIgnoreAsciiCase(rName, elem) )
3304 bConstant = true;
3305 break;
3308 return bConstant;
3311 SbxVariable*
3312 VBAConstantHelper::getVBAConstant( const OUString& rName )
3314 SbxVariable* pConst = nullptr;
3315 init();
3317 auto it = aConstHash.find( rName.toAsciiLowerCase() );
3319 if ( it != aConstHash.end() )
3321 pConst = new SbxVariable( SbxVARIANT );
3322 pConst->SetName( rName );
3323 unoToSbxValue( pConst, it->second );
3326 return pConst;
3329 // Function to search for a global identifier in the
3330 // UnoScope and to wrap it for Sbx
3331 SbUnoClass* findUnoClass( const OUString& rName )
3333 // #105550 Check if module exists
3334 SbUnoClass* pUnoClass = nullptr;
3336 const Reference< XHierarchicalNameAccess >& xTypeAccess = getTypeProvider_Impl();
3337 if( xTypeAccess->hasByHierarchicalName( rName ) )
3339 Any aRet = xTypeAccess->getByHierarchicalName( rName );
3340 Reference< XTypeDescription > xTypeDesc;
3341 aRet >>= xTypeDesc;
3343 if( xTypeDesc.is() )
3345 TypeClass eTypeClass = xTypeDesc->getTypeClass();
3346 if( eTypeClass == TypeClass_MODULE || eTypeClass == TypeClass_CONSTANTS )
3348 pUnoClass = new SbUnoClass( rName );
3352 return pUnoClass;
3355 SbxVariable* SbUnoClass::Find( const OUString& rName, SbxClassType )
3357 SbxVariable* pRes = SbxObject::Find( rName, SbxClassType::Variable );
3359 // If nothing were located the submodule isn't known yet
3360 if( !pRes )
3362 // If it is already a class, ask for the field
3363 if( m_xClass.is() )
3365 // Is it a field(?)
3366 Reference< XIdlField > xField = m_xClass->getField( rName );
3367 if( xField.is() )
3371 Any aAny = xField->get( {} ); //TODO: does this make sense?
3373 // Convert to Sbx
3374 pRes = new SbxVariable( SbxVARIANT );
3375 pRes->SetName( rName );
3376 unoToSbxValue( pRes, aAny );
3378 catch( const Exception& )
3380 implHandleAnyException( ::cppu::getCaughtException() );
3384 else
3386 // expand fully qualified name
3387 OUString aNewName = GetName()
3388 + "."
3389 + rName;
3391 // get CoreReflection
3392 Reference< XIdlReflection > xCoreReflection = getCoreReflection_Impl();
3393 if( xCoreReflection.is() )
3395 // Is it a constant?
3396 Reference< XHierarchicalNameAccess > xHarryName( xCoreReflection, UNO_QUERY );
3397 if( xHarryName.is() )
3401 Any aValue = xHarryName->getByHierarchicalName( aNewName );
3402 TypeClass eType = aValue.getValueTypeClass();
3404 // Interface located? Then it is a class
3405 if( eType == TypeClass_INTERFACE )
3407 Reference< XIdlClass > xClass( aValue, UNO_QUERY );
3408 if( xClass.is() )
3410 pRes = new SbxVariable( SbxVARIANT );
3411 SbxObjectRef xWrapper = static_cast<SbxObject*>(new SbUnoClass( aNewName, xClass ));
3412 pRes->PutObject( xWrapper.get() );
3415 else
3417 pRes = new SbxVariable( SbxVARIANT );
3418 unoToSbxValue( pRes, aValue );
3421 catch( const NoSuchElementException& )
3426 // Otherwise take it again as class
3427 if( !pRes )
3429 SbUnoClass* pNewClass = findUnoClass( aNewName );
3430 if( pNewClass )
3432 pRes = new SbxVariable( SbxVARIANT );
3433 SbxObjectRef xWrapper = static_cast<SbxObject*>(pNewClass);
3434 pRes->PutObject( xWrapper.get() );
3438 // A UNO service?
3439 if( !pRes )
3441 SbUnoService* pUnoService = findUnoService( aNewName );
3442 if( pUnoService )
3444 pRes = new SbxVariable( SbxVARIANT );
3445 SbxObjectRef xWrapper = static_cast<SbxObject*>(pUnoService);
3446 pRes->PutObject( xWrapper.get() );
3450 // A UNO singleton?
3451 if( !pRes )
3453 SbUnoSingleton* pUnoSingleton = findUnoSingleton( aNewName );
3454 if( pUnoSingleton )
3456 pRes = new SbxVariable( SbxVARIANT );
3457 SbxObjectRef xWrapper = static_cast<SbxObject*>(pUnoSingleton);
3458 pRes->PutObject( xWrapper.get() );
3464 if( pRes )
3466 pRes->SetName( rName );
3468 // Insert variable, so that it could be found later
3469 QuickInsert( pRes );
3471 // Take us out as listener at once,
3472 // the values are all constant
3473 if( pRes->IsBroadcaster() )
3474 EndListening( pRes->GetBroadcaster(), true );
3477 return pRes;
3481 SbUnoService* findUnoService( const OUString& rName )
3483 SbUnoService* pSbUnoService = nullptr;
3485 const Reference< XHierarchicalNameAccess >& xTypeAccess = getTypeProvider_Impl();
3486 if( xTypeAccess->hasByHierarchicalName( rName ) )
3488 Any aRet = xTypeAccess->getByHierarchicalName( rName );
3489 Reference< XTypeDescription > xTypeDesc;
3490 aRet >>= xTypeDesc;
3492 if( xTypeDesc.is() )
3494 TypeClass eTypeClass = xTypeDesc->getTypeClass();
3495 if( eTypeClass == TypeClass_SERVICE )
3497 Reference< XServiceTypeDescription2 > xServiceTypeDesc( xTypeDesc, UNO_QUERY );
3498 if( xServiceTypeDesc.is() )
3499 pSbUnoService = new SbUnoService( rName, xServiceTypeDesc );
3503 return pSbUnoService;
3506 SbxVariable* SbUnoService::Find( const OUString& rName, SbxClassType )
3508 SbxVariable* pRes = SbxObject::Find( rName, SbxClassType::Method );
3510 if( !pRes )
3512 // If it is already a class ask for a field
3513 if( m_bNeedsInit && m_xServiceTypeDesc.is() )
3515 m_bNeedsInit = false;
3517 Sequence< Reference< XServiceConstructorDescription > > aSCDSeq = m_xServiceTypeDesc->getConstructors();
3518 const Reference< XServiceConstructorDescription >* pCtorSeq = aSCDSeq.getConstArray();
3519 int nCtorCount = aSCDSeq.getLength();
3520 for( int i = 0 ; i < nCtorCount ; ++i )
3522 Reference< XServiceConstructorDescription > xCtor = pCtorSeq[i];
3524 OUString aName( xCtor->getName() );
3525 if( aName.isEmpty() )
3527 if( xCtor->isDefaultConstructor() )
3529 aName = "create";
3533 if( !aName.isEmpty() )
3535 // Create and insert SbUnoServiceCtor
3536 SbxVariableRef xSbCtorRef = new SbUnoServiceCtor( aName, xCtor );
3537 QuickInsert( xSbCtorRef.get() );
3540 pRes = SbxObject::Find( rName, SbxClassType::Method );
3544 return pRes;
3547 void SbUnoService::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
3549 const SbxHint* pHint = dynamic_cast<const SbxHint*>(&rHint);
3550 if( !pHint )
3551 return;
3553 SbxVariable* pVar = pHint->GetVar();
3554 SbxArray* pParams = pVar->GetParameters();
3555 SbUnoServiceCtor* pUnoCtor = dynamic_cast<SbUnoServiceCtor*>( pVar );
3556 if( pUnoCtor && pHint->GetId() == SfxHintId::BasicDataWanted )
3558 // Parameter count -1 because of Param0 == this
3559 sal_uInt32 nParamCount = pParams ? (pParams->Count() - 1) : 0;
3560 Sequence<Any> args;
3562 Reference< XServiceConstructorDescription > xCtor = pUnoCtor->getServiceCtorDesc();
3563 Sequence< Reference< XParameter > > aParameterSeq = xCtor->getParameters();
3564 const Reference< XParameter >* pParameterSeq = aParameterSeq.getConstArray();
3565 sal_uInt32 nUnoParamCount = aParameterSeq.getLength();
3567 // Default: Ignore not needed parameters
3568 bool bParameterError = false;
3570 // Is the last parameter a rest parameter?
3571 bool bRestParameterMode = false;
3572 if( nUnoParamCount > 0 )
3574 Reference< XParameter > xLastParam = pParameterSeq[ nUnoParamCount - 1 ];
3575 if( xLastParam.is() )
3577 if( xLastParam->isRestParameter() )
3578 bRestParameterMode = true;
3582 // Too many parameters with context as first parameter?
3583 sal_uInt32 nSbxParameterOffset = 1;
3584 sal_uInt32 nParameterOffsetByContext = 0;
3585 Reference < XComponentContext > xFirstParamContext;
3586 if( nParamCount > nUnoParamCount )
3588 // Check if first parameter is a context and use it
3589 // then in createInstanceWithArgumentsAndContext
3590 Any aArg0 = sbxToUnoValue(pParams->Get(nSbxParameterOffset));
3591 if( (aArg0 >>= xFirstParamContext) && xFirstParamContext.is() )
3592 nParameterOffsetByContext = 1;
3595 sal_uInt32 nEffectiveParamCount = nParamCount - nParameterOffsetByContext;
3596 sal_uInt32 nAllocParamCount = nEffectiveParamCount;
3597 if( nEffectiveParamCount > nUnoParamCount )
3599 if( !bRestParameterMode )
3601 nEffectiveParamCount = nUnoParamCount;
3602 nAllocParamCount = nUnoParamCount;
3605 // Not enough parameters?
3606 else if( nUnoParamCount > nEffectiveParamCount )
3608 // RestParameterMode only helps if one (the last) parameter is missing
3609 int nDiff = nUnoParamCount - nEffectiveParamCount;
3610 if( !bRestParameterMode || nDiff > 1 )
3612 bParameterError = true;
3613 StarBASIC::Error( ERRCODE_BASIC_NOT_OPTIONAL );
3617 if( !bParameterError )
3619 bool bOutParams = false;
3620 if( nAllocParamCount > 0 )
3622 args.realloc( nAllocParamCount );
3623 Any* pAnyArgs = args.getArray();
3624 for( sal_uInt32 i = 0 ; i < nEffectiveParamCount ; i++ )
3626 sal_uInt32 iSbx = i + nSbxParameterOffset + nParameterOffsetByContext;
3628 // bRestParameterMode allows nEffectiveParamCount > nUnoParamCount
3629 Reference< XParameter > xParam;
3630 if( i < nUnoParamCount )
3632 xParam = pParameterSeq[i];
3633 if( !xParam.is() )
3634 continue;
3636 Reference< XTypeDescription > xParamTypeDesc = xParam->getType();
3637 if( !xParamTypeDesc.is() )
3638 continue;
3639 css::uno::Type aType( xParamTypeDesc->getTypeClass(), xParamTypeDesc->getName() );
3641 // sbx parameter needs offset 1
3642 pAnyArgs[i] = sbxToUnoValue(pParams->Get(iSbx), aType);
3644 // Check for out parameter if not already done
3645 if( !bOutParams && xParam->isOut() )
3646 bOutParams = true;
3648 else
3650 pAnyArgs[i] = sbxToUnoValue(pParams->Get(iSbx));
3655 // "Call" ctor using createInstanceWithArgumentsAndContext
3656 Reference < XComponentContext > xContext(
3657 xFirstParamContext.is()
3658 ? xFirstParamContext
3659 : comphelper::getProcessComponentContext() );
3660 Reference< XMultiComponentFactory > xServiceMgr( xContext->getServiceManager() );
3662 Any aRetAny;
3663 OUString aServiceName = GetName();
3664 Reference < XInterface > xRet;
3667 xRet = xServiceMgr->createInstanceWithArgumentsAndContext( aServiceName, args, xContext );
3669 catch( const Exception& )
3671 implHandleAnyException( ::cppu::getCaughtException() );
3673 aRetAny <<= xRet;
3674 unoToSbxValue( pVar, aRetAny );
3676 // Copy back out parameters?
3677 if( bOutParams )
3679 const Any* pAnyArgs = args.getConstArray();
3681 for( sal_uInt32 j = 0 ; j < nUnoParamCount ; j++ )
3683 Reference< XParameter > xParam = pParameterSeq[j];
3684 if( !xParam.is() )
3685 continue;
3687 if( xParam->isOut() )
3688 unoToSbxValue(pParams->Get(j + 1), pAnyArgs[j]);
3693 else
3694 SbxObject::Notify( rBC, rHint );
3698 SbUnoServiceCtor::SbUnoServiceCtor( const OUString& aName_, Reference< XServiceConstructorDescription > const & xServiceCtorDesc )
3699 : SbxMethod( aName_, SbxOBJECT )
3700 , m_xServiceCtorDesc( xServiceCtorDesc )
3704 SbUnoServiceCtor::~SbUnoServiceCtor()
3708 SbxInfo* SbUnoServiceCtor::GetInfo()
3710 return nullptr;
3714 SbUnoSingleton* findUnoSingleton( const OUString& rName )
3716 SbUnoSingleton* pSbUnoSingleton = nullptr;
3718 const Reference< XHierarchicalNameAccess >& xTypeAccess = getTypeProvider_Impl();
3719 if( xTypeAccess->hasByHierarchicalName( rName ) )
3721 Any aRet = xTypeAccess->getByHierarchicalName( rName );
3722 Reference< XTypeDescription > xTypeDesc;
3723 aRet >>= xTypeDesc;
3725 if( xTypeDesc.is() )
3727 TypeClass eTypeClass = xTypeDesc->getTypeClass();
3728 if( eTypeClass == TypeClass_SINGLETON )
3730 Reference< XSingletonTypeDescription > xSingletonTypeDesc( xTypeDesc, UNO_QUERY );
3731 if( xSingletonTypeDesc.is() )
3732 pSbUnoSingleton = new SbUnoSingleton( rName );
3736 return pSbUnoSingleton;
3739 SbUnoSingleton::SbUnoSingleton( const OUString& aName_ )
3740 : SbxObject( aName_ )
3742 SbxVariableRef xGetMethodRef = new SbxMethod( u"get"_ustr, SbxOBJECT );
3743 QuickInsert( xGetMethodRef.get() );
3746 void SbUnoSingleton::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
3748 const SbxHint* pHint = dynamic_cast<const SbxHint*>(&rHint);
3749 if( pHint )
3751 SbxVariable* pVar = pHint->GetVar();
3752 SbxArray* pParams = pVar->GetParameters();
3753 sal_uInt32 nParamCount = pParams ? (pParams->Count() - 1) : 0;
3754 sal_uInt32 nAllowedParamCount = 1;
3756 Reference < XComponentContext > xContextToUse;
3757 if( nParamCount > 0 )
3759 // Check if first parameter is a context and use it then
3760 Reference < XComponentContext > xFirstParamContext;
3761 Any aArg1 = sbxToUnoValue(pParams->Get(1));
3762 if( (aArg1 >>= xFirstParamContext) && xFirstParamContext.is() )
3763 xContextToUse = std::move(xFirstParamContext);
3766 if( !xContextToUse.is() )
3768 xContextToUse = comphelper::getProcessComponentContext();
3769 --nAllowedParamCount;
3772 if( nParamCount > nAllowedParamCount )
3774 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
3775 return;
3778 Any aRetAny;
3779 if( xContextToUse.is() )
3781 OUString aSingletonName = "/singletons/"
3782 + GetName();
3783 Reference < XInterface > xRet;
3784 xContextToUse->getValueByName( aSingletonName ) >>= xRet;
3785 aRetAny <<= xRet;
3787 unoToSbxValue( pVar, aRetAny );
3789 else
3791 SbxObject::Notify( rBC, rHint );
3795 namespace {
3797 // Implementation of an EventAttacher-drawn AllListener, which
3798 // solely transmits several events to a general AllListener
3799 class BasicAllListener_Impl : public WeakImplHelper< XAllListener >
3801 void firing_impl(const AllEventObject& Event, Any* pRet);
3803 public:
3804 SbxObjectRef xSbxObj;
3805 OUString aPrefixName;
3807 explicit BasicAllListener_Impl( OUString aPrefixName );
3809 // Methods of XAllListener
3810 virtual void SAL_CALL firing(const AllEventObject& Event) override;
3811 virtual Any SAL_CALL approveFiring(const AllEventObject& Event) override;
3813 // Methods of XEventListener
3814 virtual void SAL_CALL disposing(const EventObject& Source) override;
3819 BasicAllListener_Impl::BasicAllListener_Impl(OUString aPrefixName_)
3820 : aPrefixName(std::move( aPrefixName_ ))
3824 void BasicAllListener_Impl::firing_impl( const AllEventObject& Event, Any* pRet )
3826 SolarMutexGuard guard;
3828 if( !xSbxObj.is() )
3829 return;
3831 OUString aMethodName = aPrefixName + Event.MethodName;
3833 SbxVariable * pP = xSbxObj.get();
3834 while( pP->GetParent() )
3836 pP = pP->GetParent();
3837 StarBASIC * pLib = dynamic_cast<StarBASIC*>( pP );
3838 if( pLib )
3840 // Create in a Basic Array
3841 SbxArrayRef xSbxArray = new SbxArray( SbxVARIANT );
3842 const Any * pArgs = Event.Arguments.getConstArray();
3843 sal_Int32 nCount = Event.Arguments.getLength();
3844 for( sal_Int32 i = 0; i < nCount; i++ )
3846 // Convert elements
3847 SbxVariableRef xVar = new SbxVariable( SbxVARIANT );
3848 unoToSbxValue( xVar.get(), pArgs[i] );
3849 xSbxArray->Put(xVar.get(), i + 1);
3852 pLib->Call( aMethodName, xSbxArray.get() );
3854 // get the return value from the Param-Array, if requested
3855 if( pRet )
3857 SbxVariable* pVar = xSbxArray->Get(0);
3858 if( pVar )
3860 // #95792 Avoid a second call
3861 SbxFlagBits nFlags = pVar->GetFlags();
3862 pVar->SetFlag( SbxFlagBits::NoBroadcast );
3863 *pRet = sbxToUnoValueImpl( pVar );
3864 pVar->SetFlags( nFlags );
3867 break;
3873 // Methods of Listener
3874 void BasicAllListener_Impl::firing( const AllEventObject& Event )
3876 firing_impl( Event, nullptr );
3879 Any BasicAllListener_Impl::approveFiring( const AllEventObject& Event )
3881 Any aRetAny;
3882 firing_impl( Event, &aRetAny );
3883 return aRetAny;
3887 // Methods of XEventListener
3888 void BasicAllListener_Impl ::disposing(const EventObject& )
3890 SolarMutexGuard guard;
3892 xSbxObj.clear();
3896 // class InvocationToAllListenerMapper
3897 // helper class to map XInvocation to XAllListener (also in project eventattacher!)
3899 namespace {
3901 class InvocationToAllListenerMapper : public WeakImplHelper< XInvocation >
3903 public:
3904 InvocationToAllListenerMapper( const Reference< XIdlClass >& ListenerType,
3905 const Reference< XAllListener >& AllListener, Any Helper );
3907 // XInvocation
3908 virtual Reference< XIntrospectionAccess > SAL_CALL getIntrospection() override;
3909 virtual Any SAL_CALL invoke(const OUString& FunctionName, const Sequence< Any >& Params, Sequence< sal_Int16 >& OutParamIndex, Sequence< Any >& OutParam) override;
3910 virtual void SAL_CALL setValue(const OUString& PropertyName, const Any& Value) override;
3911 virtual Any SAL_CALL getValue(const OUString& PropertyName) override;
3912 virtual sal_Bool SAL_CALL hasMethod(const OUString& Name) override;
3913 virtual sal_Bool SAL_CALL hasProperty(const OUString& Name) override;
3915 private:
3916 Reference< XAllListener > m_xAllListener;
3917 Reference< XIdlClass > m_xListenerType;
3918 Any m_Helper;
3923 // Function to replace AllListenerAdapterService::createAllListerAdapter
3924 static Reference< XInterface > createAllListenerAdapter
3926 const Reference< XInvocationAdapterFactory2 >& xInvocationAdapterFactory,
3927 const Reference< XIdlClass >& xListenerType,
3928 const Reference< XAllListener >& xListener,
3929 const Any& Helper
3932 Reference< XInterface > xAdapter;
3933 if( xInvocationAdapterFactory.is() && xListenerType.is() && xListener.is() )
3935 Reference< XInvocation > xInvocationToAllListenerMapper =
3936 new InvocationToAllListenerMapper(xListenerType, xListener, Helper);
3937 Type aListenerType( xListenerType->getTypeClass(), xListenerType->getName() );
3938 xAdapter = xInvocationAdapterFactory->createAdapter( xInvocationToAllListenerMapper, {aListenerType} );
3940 return xAdapter;
3944 // InvocationToAllListenerMapper
3945 InvocationToAllListenerMapper::InvocationToAllListenerMapper
3946 ( const Reference< XIdlClass >& ListenerType, const Reference< XAllListener >& AllListener, Any Helper )
3947 : m_xAllListener( AllListener )
3948 , m_xListenerType( ListenerType )
3949 , m_Helper(std::move( Helper ))
3954 Reference< XIntrospectionAccess > SAL_CALL InvocationToAllListenerMapper::getIntrospection()
3956 return Reference< XIntrospectionAccess >();
3960 Any SAL_CALL InvocationToAllListenerMapper::invoke(const OUString& FunctionName, const Sequence< Any >& Params,
3961 Sequence< sal_Int16 >&, Sequence< Any >&)
3963 Any aRet;
3965 // Check if to firing or approveFiring has to be called
3966 Reference< XIdlMethod > xMethod = m_xListenerType->getMethod( FunctionName );
3967 bool bApproveFiring = false;
3968 if( !xMethod.is() )
3969 return aRet;
3970 Reference< XIdlClass > xReturnType = xMethod->getReturnType();
3971 Sequence< Reference< XIdlClass > > aExceptionSeq = xMethod->getExceptionTypes();
3972 if( ( xReturnType.is() && xReturnType->getTypeClass() != TypeClass_VOID ) ||
3973 aExceptionSeq.hasElements() )
3975 bApproveFiring = true;
3977 else
3979 Sequence< ParamInfo > aParamSeq = xMethod->getParameterInfos();
3980 sal_uInt32 nParamCount = aParamSeq.getLength();
3981 if( nParamCount > 1 )
3983 const ParamInfo* pInfo = aParamSeq.getConstArray();
3984 for( sal_uInt32 i = 0 ; i < nParamCount ; i++ )
3986 if( pInfo[ i ].aMode != ParamMode_IN )
3988 bApproveFiring = true;
3989 break;
3995 AllEventObject aAllEvent;
3996 aAllEvent.Source = getXWeak();
3997 aAllEvent.Helper = m_Helper;
3998 aAllEvent.ListenerType = Type(m_xListenerType->getTypeClass(), m_xListenerType->getName() );
3999 aAllEvent.MethodName = FunctionName;
4000 aAllEvent.Arguments = Params;
4001 if( bApproveFiring )
4002 aRet = m_xAllListener->approveFiring( aAllEvent );
4003 else
4004 m_xAllListener->firing( aAllEvent );
4005 return aRet;
4009 void SAL_CALL InvocationToAllListenerMapper::setValue(const OUString&, const Any&)
4013 Any SAL_CALL InvocationToAllListenerMapper::getValue(const OUString&)
4015 return Any();
4019 sal_Bool SAL_CALL InvocationToAllListenerMapper::hasMethod(const OUString& Name)
4021 Reference< XIdlMethod > xMethod = m_xListenerType->getMethod( Name );
4022 return xMethod.is();
4026 sal_Bool SAL_CALL InvocationToAllListenerMapper::hasProperty(const OUString& Name)
4028 Reference< XIdlField > xField = m_xListenerType->getField( Name );
4029 return xField.is();
4033 // create Uno-Service
4034 // 1. Parameter == Prefix-Name of the macro
4035 // 2. Parameter == fully qualified name of the listener
4036 void SbRtl_CreateUnoListener(StarBASIC * pBasic, SbxArray & rPar, bool)
4038 // We need 2 parameters
4039 if (rPar.Count() != 3)
4041 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
4042 return;
4045 // get the name of the class of the struct
4046 OUString aPrefixName = rPar.Get(1)->GetOUString();
4047 OUString aListenerClassName = rPar.Get(2)->GetOUString();
4049 // get the CoreReflection
4050 Reference< XIdlReflection > xCoreReflection = getCoreReflection_Impl();
4051 if( !xCoreReflection.is() )
4052 return;
4054 // get the AllListenerAdapterService
4055 const Reference< XComponentContext >& xContext( comphelper::getProcessComponentContext() );
4057 // search the class
4058 Reference< XIdlClass > xClass = xCoreReflection->forName( aListenerClassName );
4059 if( !xClass.is() )
4060 return;
4062 // From 1999-11-30: get the InvocationAdapterFactory
4063 Reference< XInvocationAdapterFactory2 > xInvocationAdapterFactory =
4064 InvocationAdapterFactory::create( xContext );
4066 rtl::Reference<BasicAllListener_Impl> xAllLst = new BasicAllListener_Impl( aPrefixName );
4067 Any aTmp;
4068 Reference< XInterface > xLst = createAllListenerAdapter( xInvocationAdapterFactory, xClass, xAllLst, aTmp );
4069 if( !xLst.is() )
4070 return;
4072 OUString aClassName = xClass->getName();
4073 Type aClassType( xClass->getTypeClass(), aClassName );
4074 aTmp = xLst->queryInterface( aClassType );
4075 if( !aTmp.hasValue() )
4076 return;
4078 SbUnoObject* pUnoObj = new SbUnoObject( aListenerClassName, aTmp );
4079 xAllLst->xSbxObj = pUnoObj;
4080 xAllLst->xSbxObj->SetParent( pBasic );
4082 // #100326 Register listener object to set Parent NULL in Dtor
4083 SbxArrayRef xBasicUnoListeners = pBasic->getUnoListeners();
4084 xBasicUnoListeners->Insert(pUnoObj, xBasicUnoListeners->Count());
4086 // return the object
4087 SbxVariableRef refVar = rPar.Get(0);
4088 refVar->PutObject( xAllLst->xSbxObj.get() );
4092 // Represents the DefaultContext property of the ProcessServiceManager
4093 // in the Basic runtime system.
4094 void RTL_Impl_GetDefaultContext( SbxArray& rPar )
4096 SbxVariableRef refVar = rPar.Get(0);
4098 Any aContextAny( comphelper::getProcessComponentContext() );
4100 SbUnoObjectRef xUnoObj = new SbUnoObject( u"DefaultContext"_ustr, aContextAny );
4101 refVar->PutObject( xUnoObj.get() );
4105 // Creates a Basic wrapper object for a strongly typed Uno value
4106 // 1. parameter: Uno type as full qualified type name, e.g. "byte[]"
4107 void RTL_Impl_CreateUnoValue( SbxArray& rPar )
4109 // 2 parameters needed
4110 if (rPar.Count() != 3)
4112 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
4113 return;
4116 // get the name of the class of the struct
4117 OUString aTypeName = rPar.Get(1)->GetOUString();
4118 SbxVariable* pVal = rPar.Get(2);
4120 if( aTypeName == "type" )
4122 SbxDataType eBaseType = pVal->SbxValue::GetType();
4123 OUString aValTypeName;
4124 if( eBaseType == SbxSTRING )
4126 aValTypeName = pVal->GetOUString();
4128 else if( eBaseType == SbxOBJECT )
4130 // XIdlClass?
4131 Reference< XIdlClass > xIdlClass;
4133 SbxBaseRef pObj = pVal->GetObject();
4134 if( auto obj = dynamic_cast<SbUnoObject*>( pObj.get() ) )
4136 Any aUnoAny = obj->getUnoAny();
4137 aUnoAny >>= xIdlClass;
4140 if( xIdlClass.is() )
4142 aValTypeName = xIdlClass->getName();
4145 Type aType;
4146 bool bSuccess = implGetTypeByName( aValTypeName, aType );
4147 if( bSuccess )
4149 SbxVariableRef refVar = rPar.Get(0);
4150 SbxObjectRef xUnoAnyObject = new SbUnoAnyObject(Any(aType));
4151 refVar->PutObject( xUnoAnyObject.get() );
4153 return;
4156 // Check the type
4157 const Reference< XHierarchicalNameAccess >& xTypeAccess = getTypeProvider_Impl();
4158 Any aRet;
4161 aRet = xTypeAccess->getByHierarchicalName( aTypeName );
4163 catch( const NoSuchElementException& e1 )
4165 StarBASIC::Error( ERRCODE_BASIC_EXCEPTION,
4166 implGetExceptionMsg( e1, u"com.sun.star.container.NoSuchElementException" ) );
4167 return;
4169 Reference< XTypeDescription > xTypeDesc;
4170 aRet >>= xTypeDesc;
4171 TypeClass eTypeClass = xTypeDesc->getTypeClass();
4172 Type aDestType( eTypeClass, aTypeName );
4175 // Preconvert value
4176 Any aVal = sbxToUnoValueImpl( pVal );
4177 Any aConvertedVal = convertAny( aVal, aDestType );
4179 SbxVariableRef refVar = rPar.Get(0);
4180 SbxObjectRef xUnoAnyObject = new SbUnoAnyObject( aConvertedVal );
4181 refVar->PutObject( xUnoAnyObject.get() );
4184 namespace {
4186 class ModuleInvocationProxy : public WeakImplHelper< XInvocation, XComponent >
4188 std::mutex m_aMutex;
4189 OUString m_aPrefix;
4190 SbxObjectRef m_xScopeObj;
4191 bool m_bProxyIsClassModuleObject;
4193 ::comphelper::OInterfaceContainerHelper4<XEventListener> m_aListeners;
4195 public:
4196 ModuleInvocationProxy( std::u16string_view aPrefix, SbxObjectRef const & xScopeObj );
4198 // XInvocation
4199 virtual Reference< XIntrospectionAccess > SAL_CALL getIntrospection() override;
4200 virtual void SAL_CALL setValue( const OUString& rProperty, const Any& rValue ) override;
4201 virtual Any SAL_CALL getValue( const OUString& rProperty ) override;
4202 virtual sal_Bool SAL_CALL hasMethod( const OUString& rName ) override;
4203 virtual sal_Bool SAL_CALL hasProperty( const OUString& rProp ) override;
4205 virtual Any SAL_CALL invoke( const OUString& rFunction,
4206 const Sequence< Any >& rParams,
4207 Sequence< sal_Int16 >& rOutParamIndex,
4208 Sequence< Any >& rOutParam ) override;
4210 // XComponent
4211 virtual void SAL_CALL dispose() override;
4212 virtual void SAL_CALL addEventListener( const Reference< XEventListener >& xListener ) override;
4213 virtual void SAL_CALL removeEventListener( const Reference< XEventListener >& aListener ) override;
4218 ModuleInvocationProxy::ModuleInvocationProxy( std::u16string_view aPrefix, SbxObjectRef const & xScopeObj )
4219 : m_aPrefix( OUString::Concat(aPrefix) + "_" )
4220 , m_xScopeObj( xScopeObj )
4222 m_bProxyIsClassModuleObject = xScopeObj.is() && dynamic_cast<const SbClassModuleObject*>( xScopeObj.get() ) != nullptr;
4225 Reference< XIntrospectionAccess > SAL_CALL ModuleInvocationProxy::getIntrospection()
4227 return Reference< XIntrospectionAccess >();
4230 void SAL_CALL ModuleInvocationProxy::setValue(const OUString& rProperty, const Any& rValue)
4232 if( !m_bProxyIsClassModuleObject )
4233 throw UnknownPropertyException();
4235 SolarMutexGuard guard;
4237 OUString aPropertyFunctionName = "Property Set "
4238 + m_aPrefix
4239 + rProperty;
4241 SbxVariable* p = m_xScopeObj->Find( aPropertyFunctionName, SbxClassType::Method );
4242 SbMethod* pMeth = dynamic_cast<SbMethod*>( p );
4243 if( pMeth == nullptr )
4245 // TODO: Check vba behavior concerning missing function
4246 //StarBASIC::Error( ERRCODE_BASIC_NO_METHOD, aFunctionName );
4247 throw UnknownPropertyException(aPropertyFunctionName);
4250 // Setup parameter
4251 SbxArrayRef xArray = new SbxArray;
4252 SbxVariableRef xVar = new SbxVariable( SbxVARIANT );
4253 unoToSbxValue( xVar.get(), rValue );
4254 xArray->Put(xVar.get(), 1);
4256 // Call property method
4257 SbxVariableRef xValue = new SbxVariable;
4258 pMeth->SetParameters( xArray.get() );
4259 pMeth->Call( xValue.get() );
4260 pMeth->SetParameters( nullptr );
4262 // TODO: OutParameter?
4267 Any SAL_CALL ModuleInvocationProxy::getValue(const OUString& rProperty)
4269 if( !m_bProxyIsClassModuleObject )
4271 throw UnknownPropertyException();
4273 SolarMutexGuard guard;
4275 OUString aPropertyFunctionName = "Property Get "
4276 + m_aPrefix
4277 + rProperty;
4279 SbxVariable* p = m_xScopeObj->Find( aPropertyFunctionName, SbxClassType::Method );
4280 SbMethod* pMeth = dynamic_cast<SbMethod*>( p );
4281 if( pMeth == nullptr )
4283 // TODO: Check vba behavior concerning missing function
4284 //StarBASIC::Error( ERRCODE_BASIC_NO_METHOD, aFunctionName );
4285 throw UnknownPropertyException(aPropertyFunctionName);
4288 // Call method
4289 SbxVariableRef xValue = new SbxVariable;
4290 pMeth->Call( xValue.get() );
4291 Any aRet = sbxToUnoValue( xValue.get() );
4292 return aRet;
4295 sal_Bool SAL_CALL ModuleInvocationProxy::hasMethod( const OUString& )
4297 return false;
4300 sal_Bool SAL_CALL ModuleInvocationProxy::hasProperty( const OUString& )
4302 return false;
4305 Any SAL_CALL ModuleInvocationProxy::invoke( const OUString& rFunction,
4306 const Sequence< Any >& rParams,
4307 Sequence< sal_Int16 >&,
4308 Sequence< Any >& )
4310 SolarMutexGuard guard;
4312 Any aRet;
4313 SbxObjectRef xScopeObj = m_xScopeObj;
4314 if( !xScopeObj.is() )
4316 return aRet;
4318 OUString aFunctionName = m_aPrefix
4319 + rFunction;
4321 bool bOldReschedule = false;
4322 SbiInstance* pInst = GetSbData()->pInst;
4323 if( pInst && pInst->IsCompatibility() )
4325 bOldReschedule = pInst->IsReschedule();
4326 if ( bOldReschedule )
4327 pInst->EnableReschedule( false );
4330 SbxVariable* p = xScopeObj->Find( aFunctionName, SbxClassType::Method );
4331 SbMethod* pMeth = dynamic_cast<SbMethod*>( p );
4332 if( pMeth == nullptr )
4334 // TODO: Check vba behavior concerning missing function
4335 //StarBASIC::Error( ERRCODE_BASIC_NO_METHOD, aFunctionName );
4336 return aRet;
4339 // Setup parameters
4340 SbxArrayRef xArray;
4341 sal_Int32 nParamCount = rParams.getLength();
4342 if( nParamCount )
4344 xArray = new SbxArray;
4345 const Any *pArgs = rParams.getConstArray();
4346 for( sal_Int32 i = 0 ; i < nParamCount ; i++ )
4348 SbxVariableRef xVar = new SbxVariable( SbxVARIANT );
4349 unoToSbxValue( xVar.get(), pArgs[i] );
4350 xArray->Put(xVar.get(), sal::static_int_cast<sal_uInt16>(i + 1));
4354 // Call method
4355 SbxVariableRef xValue = new SbxVariable;
4356 if( xArray.is() )
4357 pMeth->SetParameters( xArray.get() );
4358 pMeth->Call( xValue.get() );
4359 aRet = sbxToUnoValue( xValue.get() );
4360 pMeth->SetParameters( nullptr );
4362 if (bOldReschedule)
4363 pInst->EnableReschedule( bOldReschedule );
4365 // TODO: OutParameter?
4367 return aRet;
4370 void SAL_CALL ModuleInvocationProxy::dispose()
4372 std::unique_lock aGuard( m_aMutex );
4374 EventObject aEvent( static_cast<XComponent*>(this) );
4375 m_aListeners.disposeAndClear( aGuard, aEvent );
4377 m_xScopeObj = nullptr;
4380 void SAL_CALL ModuleInvocationProxy::addEventListener( const Reference< XEventListener >& xListener )
4382 std::unique_lock aGuard( m_aMutex );
4383 m_aListeners.addInterface( aGuard, xListener );
4386 void SAL_CALL ModuleInvocationProxy::removeEventListener( const Reference< XEventListener >& xListener )
4388 std::unique_lock aGuard( m_aMutex );
4389 m_aListeners.removeInterface( aGuard, xListener );
4393 Reference< XInterface > createComListener( const Any& aControlAny, const OUString& aVBAType,
4394 std::u16string_view aPrefix,
4395 const SbxObjectRef& xScopeObj )
4397 Reference< XInterface > xRet;
4399 const Reference< XComponentContext >& xContext(
4400 comphelper::getProcessComponentContext() );
4401 Reference< XMultiComponentFactory > xServiceMgr( xContext->getServiceManager() );
4403 Reference< XInvocation > xProxy = new ModuleInvocationProxy( aPrefix, xScopeObj );
4405 Sequence<Any> args{ aControlAny, Any(aVBAType), Any(xProxy) };
4409 xRet = xServiceMgr->createInstanceWithArgumentsAndContext(
4410 u"com.sun.star.custom.UnoComListener"_ustr,
4411 args, xContext );
4413 catch( const Exception& )
4415 implHandleAnyException( ::cppu::getCaughtException() );
4418 return xRet;
4421 typedef std::vector< WeakReference< XComponent > > ComponentRefVector;
4423 namespace {
4425 struct StarBasicDisposeItem
4427 StarBASIC* m_pBasic;
4428 SbxArrayRef m_pRegisteredVariables;
4429 ComponentRefVector m_vComImplementsObjects;
4431 explicit StarBasicDisposeItem( StarBASIC* pBasic )
4432 : m_pBasic( pBasic )
4433 , m_pRegisteredVariables(new SbxArray())
4440 typedef std::vector< StarBasicDisposeItem* > DisposeItemVector;
4442 static DisposeItemVector GaDisposeItemVector;
4444 static DisposeItemVector::iterator lcl_findItemForBasic( StarBASIC const * pBasic )
4446 return std::find_if(GaDisposeItemVector.begin(), GaDisposeItemVector.end(),
4447 [&pBasic](StarBasicDisposeItem* pItem) { return pItem->m_pBasic == pBasic; });
4450 static StarBasicDisposeItem* lcl_getOrCreateItemForBasic( StarBASIC* pBasic )
4452 DisposeItemVector::iterator it = lcl_findItemForBasic( pBasic );
4453 StarBasicDisposeItem* pItem = (it != GaDisposeItemVector.end()) ? *it : nullptr;
4454 if( pItem == nullptr )
4456 pItem = new StarBasicDisposeItem( pBasic );
4457 GaDisposeItemVector.push_back( pItem );
4459 return pItem;
4462 void registerComponentToBeDisposedForBasic
4463 ( const Reference< XComponent >& xComponent, StarBASIC* pBasic )
4465 StarBasicDisposeItem* pItem = lcl_getOrCreateItemForBasic( pBasic );
4466 pItem->m_vComImplementsObjects.emplace_back(xComponent );
4469 void registerComListenerVariableForBasic( SbxVariable* pVar, StarBASIC* pBasic )
4471 StarBasicDisposeItem* pItem = lcl_getOrCreateItemForBasic( pBasic );
4472 SbxArray* pArray = pItem->m_pRegisteredVariables.get();
4473 pArray->Put(pVar, pArray->Count());
4476 void disposeComVariablesForBasic( StarBASIC const * pBasic )
4478 DisposeItemVector::iterator it = lcl_findItemForBasic( pBasic );
4479 if( it == GaDisposeItemVector.end() )
4480 return;
4482 StarBasicDisposeItem* pItem = *it;
4484 SbxArray* pArray = pItem->m_pRegisteredVariables.get();
4485 sal_uInt32 nCount = pArray->Count();
4486 for( sal_uInt32 i = 0 ; i < nCount ; ++i )
4488 SbxVariable* pVar = pArray->Get(i);
4489 pVar->ClearComListener();
4492 ComponentRefVector& rv = pItem->m_vComImplementsObjects;
4493 for (auto const& elem : rv)
4495 Reference< XComponent > xComponent( elem );
4496 if (xComponent.is())
4497 xComponent->dispose();
4500 delete pItem;
4501 GaDisposeItemVector.erase( it );
4505 // Handle module implements mechanism for OLE types
4506 bool SbModule::createCOMWrapperForIface( Any& o_rRetAny, SbClassModuleObject* pProxyClassModuleObject )
4508 // For now: Take first interface that allows to instantiate COM wrapper
4509 // TODO: Check if support for multiple interfaces is needed
4511 const Reference< XComponentContext >& xContext(
4512 comphelper::getProcessComponentContext() );
4513 Reference< XMultiComponentFactory > xServiceMgr( xContext->getServiceManager() );
4514 Reference< XSingleServiceFactory > xComImplementsFactory
4516 xServiceMgr->createInstanceWithContext( u"com.sun.star.custom.ComImplementsFactory"_ustr, xContext ),
4517 UNO_QUERY
4519 if( !xComImplementsFactory.is() )
4520 return false;
4522 bool bSuccess = false;
4524 SbxArray* pModIfaces = pClassData->mxIfaces.get();
4525 sal_uInt32 nCount = pModIfaces->Count();
4526 for( sal_uInt32 i = 0 ; i < nCount ; ++i )
4528 SbxVariable* pVar = pModIfaces->Get(i);
4529 const OUString& aIfaceName = pVar->GetName();
4531 if( !aIfaceName.isEmpty() )
4533 OUString aPureIfaceName = aIfaceName;
4534 sal_Int32 indexLastDot = aIfaceName.lastIndexOf('.');
4535 if ( indexLastDot > -1 )
4537 aPureIfaceName = aIfaceName.copy( indexLastDot + 1 );
4539 Reference< XInvocation > xProxy = new ModuleInvocationProxy( aPureIfaceName, pProxyClassModuleObject );
4541 Sequence<Any> args{ Any(aIfaceName), Any(xProxy) };
4543 Reference< XInterface > xRet;
4546 xRet = xComImplementsFactory->createInstanceWithArguments( args );
4547 bSuccess = true;
4549 catch( const Exception& )
4551 implHandleAnyException( ::cppu::getCaughtException() );
4554 if( bSuccess )
4556 Reference< XComponent > xComponent( xProxy, UNO_QUERY );
4557 if( xComponent.is() )
4559 StarBASIC* pParentBasic = nullptr;
4560 SbxObject* pCurObject = this;
4563 SbxObject* pObjParent = pCurObject->GetParent();
4564 pParentBasic = dynamic_cast<StarBASIC*>( pObjParent );
4565 pCurObject = pObjParent;
4567 while( pParentBasic == nullptr && pCurObject != nullptr );
4569 assert( pParentBasic != nullptr );
4570 registerComponentToBeDisposedForBasic( xComponent, pParentBasic );
4573 o_rRetAny <<= xRet;
4574 break;
4579 return bSuccess;
4583 // Due to an incorrect behavior IE returns an object instead of a string
4584 // in some scenarios. Calling toString at the object may correct this.
4585 // Helper function used in sbxvalue.cxx
4586 bool handleToStringForCOMObjects( SbxObject* pObj, SbxValue* pVal )
4588 bool bSuccess = false;
4590 if( auto pUnoObj = dynamic_cast<SbUnoObject*>( pObj) )
4592 // Only for native COM objects
4593 if( pUnoObj->isNativeCOMObject() )
4595 SbxVariableRef pMeth = pObj->Find( u"toString"_ustr, SbxClassType::Method );
4596 if ( pMeth.is() )
4598 SbxValues aRes;
4599 pMeth->Get( aRes );
4600 pVal->Put( aRes );
4601 bSuccess = true;
4605 return bSuccess;
4608 Any StructRefInfo::getValue()
4610 Any aRet;
4611 uno_any_destruct(
4612 &aRet, reinterpret_cast< uno_ReleaseFunc >(cpp_release) );
4613 typelib_TypeDescription * pTD = nullptr;
4614 maType.getDescription(&pTD);
4615 uno_any_construct(
4616 &aRet, getInst(), pTD,
4617 reinterpret_cast< uno_AcquireFunc >(cpp_acquire) );
4618 typelib_typedescription_release(pTD);
4619 return aRet;
4622 void StructRefInfo::setValue( const Any& rValue )
4624 bool bSuccess = uno_type_assignData( getInst(),
4625 maType.getTypeLibType(),
4626 const_cast<void*>(rValue.getValue()),
4627 rValue.getValueTypeRef(),
4628 reinterpret_cast< uno_QueryInterfaceFunc >(cpp_queryInterface),
4629 reinterpret_cast< uno_AcquireFunc >(cpp_acquire),
4630 reinterpret_cast< uno_ReleaseFunc >(cpp_release) );
4631 OSL_ENSURE(bSuccess,
4632 "StructRefInfo::setValue: ooops... the value could not be assigned!");
4635 OUString StructRefInfo::getTypeName() const
4637 return maType.getTypeName();
4640 void* StructRefInfo::getInst()
4642 return const_cast<char *>(static_cast<char const *>(maAny.getValue()) + mnPos);
4645 TypeClass StructRefInfo::getTypeClass() const
4647 return maType.getTypeClass();
4650 SbUnoStructRefObject::SbUnoStructRefObject( const OUString& aName_, StructRefInfo aMemberInfo ) : SbxObject( aName_ ), maMemberInfo(std::move( aMemberInfo )), mbMemberCacheInit( false )
4652 SetClassName( maMemberInfo.getTypeName() );
4655 SbUnoStructRefObject::~SbUnoStructRefObject()
4659 void SbUnoStructRefObject::initMemberCache()
4661 if ( mbMemberCacheInit )
4662 return;
4663 typelib_TypeDescription * pTD = nullptr;
4664 maMemberInfo.getType().getDescription(&pTD);
4665 for ( typelib_CompoundTypeDescription * pCompTypeDescr = reinterpret_cast<typelib_CompoundTypeDescription *>(pTD);
4666 pCompTypeDescr;
4667 pCompTypeDescr = pCompTypeDescr->pBaseTypeDescription )
4669 typelib_TypeDescriptionReference ** ppTypeRefs = pCompTypeDescr->ppTypeRefs;
4670 rtl_uString ** ppNames = pCompTypeDescr->ppMemberNames;
4671 sal_Int32 * pMemberOffsets = pCompTypeDescr->pMemberOffsets;
4672 for ( sal_Int32 nPos = pCompTypeDescr->nMembers; nPos--; )
4674 OUString aName( ppNames[nPos] );
4675 maFields[ aName ] = std::make_unique<StructRefInfo>( maMemberInfo.getRootAnyRef(), ppTypeRefs[nPos], maMemberInfo.getPos() + pMemberOffsets[nPos] );
4678 typelib_typedescription_release(pTD);
4679 mbMemberCacheInit = true;
4682 SbxVariable* SbUnoStructRefObject::Find( const OUString& rName, SbxClassType t )
4684 SbxVariable* pRes = SbxObject::Find( rName, t );
4685 if ( !pRes )
4687 if ( !mbMemberCacheInit )
4688 initMemberCache();
4689 StructFieldInfo::iterator it = maFields.find( rName );
4690 if ( it != maFields.end() )
4692 SbxDataType eSbxType;
4693 eSbxType = unoToSbxType( it->second->getTypeClass() );
4694 SbxDataType eRealSbxType = eSbxType;
4695 Property aProp;
4696 aProp.Name = rName;
4697 aProp.Type = css::uno::Type( it->second->getTypeClass(), it->second->getTypeName() );
4698 const bool bIsStruct = aProp.Type.getTypeClass() == css::uno::TypeClass_STRUCT;
4699 SbUnoProperty* pProp = new SbUnoProperty( rName, eSbxType, eRealSbxType, std::move(aProp), 0, false, bIsStruct );
4700 SbxVariableRef xVarRef = pProp;
4701 QuickInsert( xVarRef.get() );
4702 pRes = xVarRef.get();
4706 if( !pRes )
4708 if( rName.equalsIgnoreAsciiCase(ID_DBG_SUPPORTEDINTERFACES) ||
4709 rName.equalsIgnoreAsciiCase(ID_DBG_PROPERTIES) ||
4710 rName.equalsIgnoreAsciiCase(ID_DBG_METHODS) )
4712 // Create
4713 implCreateDbgProperties();
4715 // Now they have to be found regular
4716 pRes = SbxObject::Find( rName, SbxClassType::DontCare );
4720 return pRes;
4723 // help method to create the dbg_-Properties
4724 void SbUnoStructRefObject::implCreateDbgProperties()
4726 Property aProp;
4728 // Id == -1: display the implemented interfaces corresponding the ClassProvider
4729 SbxVariableRef xVarRef = new SbUnoProperty( ID_DBG_SUPPORTEDINTERFACES, SbxSTRING, SbxSTRING, aProp, -1, false, false );
4730 QuickInsert( xVarRef.get() );
4732 // Id == -2: output the properties
4733 xVarRef = new SbUnoProperty( ID_DBG_PROPERTIES, SbxSTRING, SbxSTRING, aProp, -2, false, false );
4734 QuickInsert( xVarRef.get() );
4736 // Id == -3: output the Methods
4737 xVarRef = new SbUnoProperty( ID_DBG_METHODS, SbxSTRING, SbxSTRING, std::move(aProp), -3, false, false );
4738 QuickInsert( xVarRef.get() );
4741 void SbUnoStructRefObject::implCreateAll()
4743 // throw away all existing methods and properties
4744 pMethods = new SbxArray;
4745 pProps = new SbxArray;
4747 if (!mbMemberCacheInit)
4748 initMemberCache();
4750 for (auto const& field : maFields)
4752 const OUString& rName = field.first;
4753 SbxDataType eSbxType;
4754 eSbxType = unoToSbxType( field.second->getTypeClass() );
4755 SbxDataType eRealSbxType = eSbxType;
4756 Property aProp;
4757 aProp.Name = rName;
4758 aProp.Type = css::uno::Type( field.second->getTypeClass(), field.second->getTypeName() );
4759 const bool bIsStruct = aProp.Type.getTypeClass() == css::uno::TypeClass_STRUCT;
4760 SbUnoProperty* pProp = new SbUnoProperty( rName, eSbxType, eRealSbxType, std::move(aProp), 0, false, bIsStruct );
4761 SbxVariableRef xVarRef = pProp;
4762 QuickInsert( xVarRef.get() );
4765 // Create Dbg_-Properties
4766 implCreateDbgProperties();
4769 // output the value
4770 Any SbUnoStructRefObject::getUnoAny()
4772 return maMemberInfo.getValue();
4775 OUString SbUnoStructRefObject::Impl_DumpProperties()
4777 OUStringBuffer aRet("Properties of object " + getDbgObjectName() );
4779 sal_uInt32 nPropCount = pProps->Count();
4780 sal_uInt32 nPropsPerLine = 1 + nPropCount / 30;
4781 for( sal_uInt32 i = 0; i < nPropCount; i++ )
4783 SbxVariable* pVar = pProps->Get(i);
4784 if( pVar )
4786 OUStringBuffer aPropStr;
4787 if( (i % nPropsPerLine) == 0 )
4789 aPropStr.append( "\n" );
4791 // output the type and name
4792 // Is it in Uno a sequence?
4793 SbxDataType eType = pVar->GetFullType();
4795 const OUString& aName( pVar->GetName() );
4796 StructFieldInfo::iterator it = maFields.find( aName );
4798 if ( it != maFields.end() )
4800 const StructRefInfo& rPropInfo = *it->second;
4802 if( eType == SbxOBJECT )
4804 if( rPropInfo.getTypeClass() == TypeClass_SEQUENCE )
4806 eType = SbxDataType( SbxOBJECT | SbxARRAY );
4810 aPropStr.append( Dbg_SbxDataType2String( eType )
4811 + " " + pVar->GetName() );
4813 if( i == nPropCount - 1 )
4815 aPropStr.append( "\n" );
4817 else
4819 aPropStr.append( "; " );
4821 aRet.append( aPropStr );
4824 return aRet.makeStringAndClear();
4827 void SbUnoStructRefObject::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
4829 if ( !mbMemberCacheInit )
4830 initMemberCache();
4831 const SbxHint* pHint = dynamic_cast<const SbxHint*>(&rHint);
4832 if( !pHint )
4833 return;
4835 SbxVariable* pVar = pHint->GetVar();
4836 SbUnoProperty* pProp = dynamic_cast<SbUnoProperty*>( pVar );
4837 if( pProp )
4839 StructFieldInfo::iterator it = maFields.find( pProp->GetName() );
4840 // handle get/set of members of struct
4841 if( pHint->GetId() == SfxHintId::BasicDataWanted )
4843 // Test-Properties
4844 sal_Int32 nId = pProp->nId;
4845 if( nId < 0 )
4847 // Id == -1: Display implemented interfaces according the ClassProvider
4848 if( nId == -1 ) // Property ID_DBG_SUPPORTEDINTERFACES"
4850 OUString aRet = OUString::Concat( ID_DBG_SUPPORTEDINTERFACES )
4851 + " not available.\n(TypeClass is not TypeClass_INTERFACE)\n";
4853 pVar->PutString( aRet );
4855 // Id == -2: output properties
4856 else if( nId == -2 ) // Property ID_DBG_PROPERTIES
4858 // by now all properties must be established
4859 implCreateAll();
4860 OUString aRetStr = Impl_DumpProperties();
4861 pVar->PutString( aRetStr );
4863 // Id == -3: output the methods
4864 else if( nId == -3 ) // Property ID_DBG_METHODS
4866 // by now all properties must be established
4867 implCreateAll();
4868 OUString aRet = "Methods of object "
4869 + getDbgObjectName()
4870 + "\nNo methods found\n";
4871 pVar->PutString( aRet );
4873 return;
4876 if ( it != maFields.end() )
4878 Any aRetAny = it->second->getValue();
4879 unoToSbxValue( pVar, aRetAny );
4881 else
4882 StarBASIC::Error( ERRCODE_BASIC_PROPERTY_NOT_FOUND );
4884 else if( pHint->GetId() == SfxHintId::BasicDataChanged )
4886 if ( it != maFields.end() )
4888 // take over the value from Uno to Sbx
4889 Any aAnyValue = sbxToUnoValue( pVar, pProp->aUnoProp.Type, &pProp->aUnoProp );
4890 it->second->setValue( aAnyValue );
4892 else
4893 StarBASIC::Error( ERRCODE_BASIC_PROPERTY_NOT_FOUND );
4896 else
4897 SbxObject::Notify( rBC, rHint );
4900 StructRefInfo SbUnoStructRefObject::getStructMember( const OUString& rMemberName )
4902 if (!mbMemberCacheInit)
4904 initMemberCache();
4906 StructFieldInfo::iterator it = maFields.find( rMemberName );
4908 css::uno::Type aFoundType;
4909 sal_Int32 nFoundPos = -1;
4911 if ( it != maFields.end() )
4913 aFoundType = it->second->getType();
4914 nFoundPos = it->second->getPos();
4916 StructRefInfo aRet( maMemberInfo.getRootAnyRef(), aFoundType, nFoundPos );
4917 return aRet;
4920 OUString SbUnoStructRefObject::getDbgObjectName() const
4922 OUString aName = GetClassName();
4923 if( aName.isEmpty() )
4925 aName += "Unknown";
4927 OUStringBuffer aRet;
4928 if( aName.getLength() > 20 )
4930 aRet.append( "\n" );
4932 aRet.append( "\"" + aName + "\":" );
4933 return aRet.makeStringAndClear();
4936 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */