summaryrefslogtreecommitdiffstats
path: root/basic/source/classes/sbunoobj.cxx
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
commited5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch)
tree7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /basic/source/classes/sbunoobj.cxx
parentInitial commit. (diff)
downloadlibreoffice-upstream/4%7.4.7.tar.xz
libreoffice-upstream/4%7.4.7.zip
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--basic/source/classes/sbunoobj.cxx4926
1 files changed, 4926 insertions, 0 deletions
diff --git a/basic/source/classes/sbunoobj.cxx b/basic/source/classes/sbunoobj.cxx
new file mode 100644
index 000000000..604ac8d86
--- /dev/null
+++ b/basic/source/classes/sbunoobj.cxx
@@ -0,0 +1,4926 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <o3tl/any.hxx>
+#include <o3tl/safeint.hxx>
+#include <utility>
+#include <vcl/svapp.hxx>
+#include <vcl/errcode.hxx>
+#include <svl/hint.hxx>
+
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <comphelper/interfacecontainer4.hxx>
+#include <comphelper/extract.hxx>
+#include <comphelper/processfactory.hxx>
+#include <cppuhelper/weakref.hxx>
+
+#include <rtl/math.hxx>
+#include <rtl/ustrbuf.hxx>
+
+#include <com/sun/star/script/ArrayWrapper.hpp>
+#include <com/sun/star/script/CannotConvertException.hpp>
+#include <com/sun/star/script/NativeObjectWrapper.hpp>
+
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/uno/DeploymentException.hpp>
+#include <com/sun/star/lang/XTypeProvider.hpp>
+#include <com/sun/star/lang/XSingleServiceFactory.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/beans/PropertyConcept.hpp>
+#include <com/sun/star/beans/MethodConcept.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/theIntrospection.hpp>
+#include <com/sun/star/script/BasicErrorException.hpp>
+#include <com/sun/star/script/InvocationAdapterFactory.hpp>
+#include <com/sun/star/script/XAllListener.hpp>
+#include <com/sun/star/script/Converter.hpp>
+#include <com/sun/star/script/XDefaultProperty.hpp>
+#include <com/sun/star/script/XDirectInvocation.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/container/XHierarchicalNameAccess.hpp>
+#include <com/sun/star/reflection/XIdlArray.hpp>
+#include <com/sun/star/reflection/XIdlReflection.hpp>
+#include <com/sun/star/reflection/XServiceConstructorDescription.hpp>
+#include <com/sun/star/reflection/XSingletonTypeDescription.hpp>
+#include <com/sun/star/reflection/theCoreReflection.hpp>
+#include <com/sun/star/bridge/oleautomation/NamedArgument.hpp>
+#include <com/sun/star/bridge/oleautomation/Date.hpp>
+#include <com/sun/star/bridge/oleautomation/Decimal.hpp>
+#include <com/sun/star/bridge/oleautomation/Currency.hpp>
+#include <com/sun/star/bridge/oleautomation/XAutomationObject.hpp>
+#include <com/sun/star/script/XAutomationInvocation.hpp>
+
+#include <rtlproto.hxx>
+
+#include <basic/sbstar.hxx>
+#include <basic/sbuno.hxx>
+#include <basic/sberrors.hxx>
+#include <sbunoobj.hxx>
+#include <sbintern.hxx>
+#include <runtime.hxx>
+
+#include <algorithm>
+#include <math.h>
+#include <memory>
+#include <string_view>
+#include <unordered_map>
+#include <com/sun/star/reflection/XTypeDescriptionEnumerationAccess.hpp>
+#include <com/sun/star/reflection/XConstantsTypeDescription.hpp>
+
+using com::sun::star::uno::Reference;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::reflection;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::script;
+using namespace com::sun::star::container;
+using namespace com::sun::star::bridge;
+using namespace cppu;
+
+
+// Identifiers for creating the strings for dbg_Properties
+constexpr OUStringLiteral ID_DBG_SUPPORTEDINTERFACES = u"Dbg_SupportedInterfaces";
+constexpr OUStringLiteral ID_DBG_PROPERTIES = u"Dbg_Properties";
+constexpr OUStringLiteral ID_DBG_METHODS = u"Dbg_Methods";
+
+char const aSeqLevelStr[] = "[]";
+
+// Gets the default property for a uno object. Note: There is some
+// redirection built in. The property name specifies the name
+// of the default property.
+
+bool SbUnoObject::getDefaultPropName( SbUnoObject const * pUnoObj, OUString& sDfltProp )
+{
+ bool bResult = false;
+ Reference< XDefaultProperty> xDefaultProp( pUnoObj->maTmpUnoObj, UNO_QUERY );
+ if ( xDefaultProp.is() )
+ {
+ sDfltProp = xDefaultProp->getDefaultPropertyName();
+ if ( !sDfltProp.isEmpty() )
+ bResult = true;
+ }
+ return bResult;
+}
+
+SbxVariable* getDefaultProp( SbxVariable* pRef )
+{
+ SbxVariable* pDefaultProp = nullptr;
+ if ( pRef->GetType() == SbxOBJECT )
+ {
+ SbxObject* pObj = dynamic_cast<SbxObject*>(pRef);
+ if (!pObj)
+ {
+ SbxBase* pObjVarObj = pRef->GetObject();
+ pObj = dynamic_cast<SbxObject*>( pObjVarObj );
+ }
+ if (SbUnoObject* pUnoObj = dynamic_cast<SbUnoObject*>(pObj))
+ {
+ pDefaultProp = pUnoObj->GetDfltProperty();
+ }
+ }
+ return pDefaultProp;
+}
+
+void SetSbUnoObjectDfltPropName( SbxObject* pObj )
+{
+ SbUnoObject* pUnoObj = dynamic_cast<SbUnoObject*>( pObj );
+ if ( pUnoObj )
+ {
+ OUString sDfltPropName;
+
+ if ( SbUnoObject::getDefaultPropName( pUnoObj, sDfltPropName ) )
+ {
+ pUnoObj->SetDfltProperty( sDfltPropName );
+ }
+ }
+}
+
+// save CoreReflection statically
+static Reference< XIdlReflection > getCoreReflection_Impl()
+{
+ return css::reflection::theCoreReflection::get(
+ comphelper::getProcessComponentContext());
+}
+
+// save CoreReflection statically
+static Reference< XHierarchicalNameAccess > const & getCoreReflection_HierarchicalNameAccess_Impl()
+{
+ static Reference< XHierarchicalNameAccess > xCoreReflection_HierarchicalNameAccess;
+
+ if( !xCoreReflection_HierarchicalNameAccess.is() )
+ {
+ Reference< XIdlReflection > xCoreReflection = getCoreReflection_Impl();
+ if( xCoreReflection.is() )
+ {
+ xCoreReflection_HierarchicalNameAccess =
+ Reference< XHierarchicalNameAccess >( xCoreReflection, UNO_QUERY );
+ }
+ }
+ return xCoreReflection_HierarchicalNameAccess;
+}
+
+// Hold TypeProvider statically
+static Reference< XHierarchicalNameAccess > const & getTypeProvider_Impl()
+{
+ static Reference< XHierarchicalNameAccess > xAccess;
+
+ // Do we have already CoreReflection; if not obtain it
+ if( !xAccess.is() )
+ {
+ Reference< XComponentContext > xContext(
+ comphelper::getProcessComponentContext() );
+ if( xContext.is() )
+ {
+ xContext->getValueByName(
+ "/singletons/com.sun.star.reflection.theTypeDescriptionManager" )
+ >>= xAccess;
+ OSL_ENSURE( xAccess.is(), "### TypeDescriptionManager singleton not accessible!?" );
+ }
+ if( !xAccess.is() )
+ {
+ throw DeploymentException(
+ "/singletons/com.sun.star.reflection.theTypeDescriptionManager singleton not accessible" );
+ }
+ }
+ return xAccess;
+}
+
+// Hold TypeConverter statically
+static Reference< XTypeConverter > const & getTypeConverter_Impl()
+{
+ static Reference< XTypeConverter > xTypeConverter;
+
+ // Do we have already CoreReflection; if not obtain it
+ if( !xTypeConverter.is() )
+ {
+ Reference< XComponentContext > xContext(
+ comphelper::getProcessComponentContext() );
+ if( xContext.is() )
+ {
+ xTypeConverter = Converter::create(xContext);
+ }
+ if( !xTypeConverter.is() )
+ {
+ throw DeploymentException(
+ "com.sun.star.script.Converter service not accessible" );
+ }
+ }
+ return xTypeConverter;
+}
+
+
+// #111851 factory function to create an OLE object
+SbUnoObject* createOLEObject_Impl( const OUString& aType )
+{
+ static const Reference<XMultiServiceFactory> xOLEFactory = [] {
+ Reference<XMultiServiceFactory> xFactory;
+ Reference< XComponentContext > xContext( comphelper::getProcessComponentContext() );
+ if( xContext.is() )
+ {
+ Reference<XMultiComponentFactory> xSMgr = xContext->getServiceManager();
+ xFactory.set(
+ xSMgr->createInstanceWithContext( "com.sun.star.bridge.OleObjectFactory", xContext ),
+ UNO_QUERY );
+ }
+ return xFactory;
+ }();
+
+ SbUnoObject* pUnoObj = nullptr;
+ if( xOLEFactory.is() )
+ {
+ // some type names available in VBA can not be directly used in COM
+ OUString aOLEType = aType;
+ if ( aOLEType == "SAXXMLReader30" )
+ {
+ aOLEType = "Msxml2.SAXXMLReader.3.0";
+ }
+ Reference< XInterface > xOLEObject = xOLEFactory->createInstance( aOLEType );
+ if( xOLEObject.is() )
+ {
+ pUnoObj = new SbUnoObject( aType, Any(xOLEObject) );
+ OUString sDfltPropName;
+
+ if ( SbUnoObject::getDefaultPropName( pUnoObj, sDfltPropName ) )
+ pUnoObj->SetDfltProperty( sDfltPropName );
+ }
+ }
+ return pUnoObj;
+}
+
+
+namespace
+{
+ void lcl_indent( OUStringBuffer& _inout_rBuffer, sal_Int32 _nLevel )
+ {
+ while ( _nLevel-- > 0 )
+ {
+ _inout_rBuffer.append( " " );
+ }
+ }
+}
+
+static void implAppendExceptionMsg( OUStringBuffer& _inout_rBuffer, const Exception& _e, std::u16string_view _rExceptionType, sal_Int32 _nLevel )
+{
+ _inout_rBuffer.append( "\n" );
+ lcl_indent( _inout_rBuffer, _nLevel );
+ _inout_rBuffer.append( "Type: " );
+
+ if ( _rExceptionType.empty() )
+ _inout_rBuffer.append( "Unknown" );
+ else
+ _inout_rBuffer.append( _rExceptionType );
+
+ _inout_rBuffer.append( "\n" );
+ lcl_indent( _inout_rBuffer, _nLevel );
+ _inout_rBuffer.append( "Message: " );
+ _inout_rBuffer.append( _e.Message );
+
+}
+
+// construct an error message for the exception
+static OUString implGetExceptionMsg( const Exception& e, std::u16string_view aExceptionType_ )
+{
+ OUStringBuffer aMessageBuf;
+ implAppendExceptionMsg( aMessageBuf, e, aExceptionType_, 0 );
+ return aMessageBuf.makeStringAndClear();
+}
+
+static OUString implGetExceptionMsg( const Any& _rCaughtException )
+{
+ auto e = o3tl::tryAccess<Exception>(_rCaughtException);
+ OSL_PRECOND( e, "implGetExceptionMsg: illegal argument!" );
+ if ( !e )
+ {
+ return OUString();
+ }
+ return implGetExceptionMsg( *e, _rCaughtException.getValueTypeName() );
+}
+
+static Any convertAny( const Any& rVal, const Type& aDestType )
+{
+ Any aConvertedVal;
+ const Reference< XTypeConverter >& xConverter = getTypeConverter_Impl();
+ try
+ {
+ aConvertedVal = xConverter->convertTo( rVal, aDestType );
+ }
+ catch( const IllegalArgumentException& )
+ {
+ StarBASIC::Error( ERRCODE_BASIC_EXCEPTION,
+ implGetExceptionMsg( ::cppu::getCaughtException() ) );
+ return aConvertedVal;
+ }
+ catch( const CannotConvertException& e2 )
+ {
+ StarBASIC::Error( ERRCODE_BASIC_EXCEPTION,
+ implGetExceptionMsg( e2, u"com.sun.star.lang.IllegalArgumentException" ) );
+ return aConvertedVal;
+ }
+ return aConvertedVal;
+}
+
+
+// #105565 Special Object to wrap a strongly typed Uno Any
+
+
+// TODO: source out later
+static Reference<XIdlClass> TypeToIdlClass( const Type& rType )
+{
+ return getCoreReflection_Impl()->forName(rType.getTypeName());
+}
+
+// Exception type unknown
+template< class EXCEPTION >
+static OUString implGetExceptionMsg( const EXCEPTION& e )
+{
+ return implGetExceptionMsg( e, cppu::UnoType<decltype(e)>::get().getTypeName() );
+}
+
+static void implHandleBasicErrorException( BasicErrorException const & e )
+{
+ ErrCode nError = StarBASIC::GetSfxFromVBError( static_cast<sal_uInt16>(e.ErrorCode) );
+ StarBASIC::Error( nError, e.ErrorMessageArgument );
+}
+
+static void implHandleWrappedTargetException( const Any& _rWrappedTargetException )
+{
+ Any aExamine( _rWrappedTargetException );
+
+ // completely strip the first InvocationTargetException, its error message isn't of any
+ // interest to the user, it just says something like "invoking the UNO method went wrong.".
+ InvocationTargetException aInvocationError;
+ if ( aExamine >>= aInvocationError )
+ aExamine = aInvocationError.TargetException;
+
+ BasicErrorException aBasicError;
+
+ ErrCode nError( ERRCODE_BASIC_EXCEPTION );
+ OUStringBuffer aMessageBuf;
+
+ // strip any other WrappedTargetException instances, but this time preserve the error messages.
+ WrappedTargetException aWrapped;
+ sal_Int32 nLevel = 0;
+ while ( aExamine >>= aWrapped )
+ {
+ // special handling for BasicErrorException errors
+ if ( aWrapped.TargetException >>= aBasicError )
+ {
+ nError = StarBASIC::GetSfxFromVBError( static_cast<sal_uInt16>(aBasicError.ErrorCode) );
+ aMessageBuf.append( aBasicError.ErrorMessageArgument );
+ aExamine.clear();
+ break;
+ }
+
+ // append this round's message
+ implAppendExceptionMsg( aMessageBuf, aWrapped, aExamine.getValueTypeName(), nLevel );
+ if ( aWrapped.TargetException.getValueTypeClass() == TypeClass_EXCEPTION )
+ // there is a next chain element
+ aMessageBuf.append( "\nTargetException:" );
+
+ // next round
+ aExamine = aWrapped.TargetException;
+ ++nLevel;
+ }
+
+ if ( auto e = o3tl::tryAccess<Exception>(aExamine) )
+ {
+ // the last element in the chain is still an exception, but no WrappedTargetException
+ implAppendExceptionMsg( aMessageBuf, *e, aExamine.getValueTypeName(), nLevel );
+ }
+
+ StarBASIC::Error( nError, aMessageBuf.makeStringAndClear() );
+}
+
+static void implHandleAnyException( const Any& _rCaughtException )
+{
+ BasicErrorException aBasicError;
+ WrappedTargetException aWrappedError;
+
+ if ( _rCaughtException >>= aBasicError )
+ {
+ implHandleBasicErrorException( aBasicError );
+ }
+ else if ( _rCaughtException >>= aWrappedError )
+ {
+ implHandleWrappedTargetException( _rCaughtException );
+ }
+ else
+ {
+ StarBASIC::Error( ERRCODE_BASIC_EXCEPTION, implGetExceptionMsg( _rCaughtException ) );
+ }
+}
+
+namespace {
+
+// NativeObjectWrapper handling
+struct ObjectItem
+{
+ SbxObjectRef m_xNativeObj;
+
+ explicit ObjectItem( SbxObject* pNativeObj )
+ : m_xNativeObj( pNativeObj )
+ {}
+};
+
+}
+
+typedef std::vector< ObjectItem > NativeObjectWrapperVector;
+
+namespace {
+
+NativeObjectWrapperVector gaNativeObjectWrapperVector;
+
+}
+
+void clearNativeObjectWrapperVector()
+{
+ gaNativeObjectWrapperVector.clear();
+}
+
+static sal_uInt32 lcl_registerNativeObjectWrapper( SbxObject* pNativeObj )
+{
+ sal_uInt32 nIndex = gaNativeObjectWrapperVector.size();
+ gaNativeObjectWrapperVector.emplace_back( pNativeObj );
+ return nIndex;
+}
+
+static SbxObject* lcl_getNativeObject( sal_uInt32 nIndex )
+{
+ SbxObjectRef xRetObj;
+ if( nIndex < gaNativeObjectWrapperVector.size() )
+ {
+ ObjectItem& rItem = gaNativeObjectWrapperVector[ nIndex ];
+ xRetObj = rItem.m_xNativeObj;
+ }
+ return xRetObj.get();
+}
+
+// convert from Uno to Sbx
+static SbxDataType unoToSbxType( TypeClass eType )
+{
+ SbxDataType eRetType = SbxVOID;
+
+ switch( eType )
+ {
+ case TypeClass_INTERFACE:
+ case TypeClass_TYPE:
+ case TypeClass_STRUCT:
+ case TypeClass_EXCEPTION: eRetType = SbxOBJECT; break;
+
+ case TypeClass_ENUM: eRetType = SbxLONG; break;
+ case TypeClass_SEQUENCE:
+ eRetType = SbxDataType( SbxOBJECT | SbxARRAY );
+ break;
+
+
+ case TypeClass_ANY: eRetType = SbxVARIANT; break;
+ case TypeClass_BOOLEAN: eRetType = SbxBOOL; break;
+ case TypeClass_CHAR: eRetType = SbxCHAR; break;
+ case TypeClass_STRING: eRetType = SbxSTRING; break;
+ case TypeClass_FLOAT: eRetType = SbxSINGLE; break;
+ case TypeClass_DOUBLE: eRetType = SbxDOUBLE; break;
+ case TypeClass_BYTE: eRetType = SbxINTEGER; break;
+ case TypeClass_SHORT: eRetType = SbxINTEGER; break;
+ case TypeClass_LONG: eRetType = SbxLONG; break;
+ case TypeClass_HYPER: eRetType = SbxSALINT64; break;
+ case TypeClass_UNSIGNED_SHORT: eRetType = SbxUSHORT; break;
+ case TypeClass_UNSIGNED_LONG: eRetType = SbxULONG; break;
+ case TypeClass_UNSIGNED_HYPER: eRetType = SbxSALUINT64;break;
+ default: break;
+ }
+ return eRetType;
+}
+
+static SbxDataType unoToSbxType( const Reference< XIdlClass >& xIdlClass )
+{
+ SbxDataType eRetType = SbxVOID;
+ if( xIdlClass.is() )
+ {
+ TypeClass eType = xIdlClass->getTypeClass();
+ eRetType = unoToSbxType( eType );
+ }
+ return eRetType;
+}
+
+static void implSequenceToMultiDimArray( SbxDimArray*& pArray, Sequence< sal_Int32 >& indices, Sequence< sal_Int32 >& sizes, const Any& aValue, sal_Int32 dimension, bool bIsZeroIndex, Type const * pType )
+{
+ const Type& aType = aValue.getValueType();
+ TypeClass eTypeClass = aType.getTypeClass();
+
+ sal_Int32 dimCopy = dimension;
+
+ if ( eTypeClass == TypeClass_SEQUENCE )
+ {
+ Reference< XIdlClass > xIdlTargetClass = TypeToIdlClass( aType );
+ Reference< XIdlArray > xIdlArray = xIdlTargetClass->getArray();
+ typelib_TypeDescription * pTD = nullptr;
+ aType.getDescription( &pTD );
+ Type aElementType( reinterpret_cast<typelib_IndirectTypeDescription *>(pTD)->pType );
+ ::typelib_typedescription_release( pTD );
+
+ sal_Int32 nLen = xIdlArray->getLen( aValue );
+ for ( sal_Int32 index = 0; index < nLen; ++index )
+ {
+ auto pindices = indices.getArray();
+ Any aElementAny = xIdlArray->get( aValue, static_cast<sal_uInt32>(index) );
+ // This detects the dimension were currently processing
+ if ( dimCopy == dimension )
+ {
+ ++dimCopy;
+ if ( sizes.getLength() < dimCopy )
+ {
+ sizes.realloc( sizes.getLength() + 1 );
+ sizes.getArray()[ sizes.getLength() - 1 ] = nLen;
+ indices.realloc( indices.getLength() + 1 );
+ pindices = indices.getArray();
+ }
+ }
+
+ if ( bIsZeroIndex )
+ pindices[ dimCopy - 1 ] = index;
+ else
+ pindices[ dimCopy - 1] = index + 1;
+
+ implSequenceToMultiDimArray( pArray, indices, sizes, aElementAny, dimCopy, bIsZeroIndex, &aElementType );
+ }
+
+ }
+ else
+ {
+ if ( !indices.hasElements() )
+ {
+ // Should never ever get here ( indices.getLength()
+ // should equal number of dimensions in the array )
+ // And that should at least be 1 !
+ // #QUESTION is there a better error?
+ StarBASIC::Error( ERRCODE_BASIC_INVALID_OBJECT );
+ return;
+ }
+
+ SbxDataType eSbxElementType = unoToSbxType( pType ? pType->getTypeClass() : aValue.getValueTypeClass() );
+ if ( !pArray )
+ {
+ pArray = new SbxDimArray( eSbxElementType );
+ sal_Int32 nIndexLen = indices.getLength();
+
+ // Dimension the array
+ for ( sal_Int32 index = 0; index < nIndexLen; ++index )
+ {
+ if ( bIsZeroIndex )
+ pArray->unoAddDim(0, sizes[index] - 1);
+ else
+ pArray->unoAddDim(1, sizes[index]);
+
+ }
+ }
+
+ if ( pArray )
+ {
+ auto xVar = tools::make_ref<SbxVariable>( eSbxElementType );
+ unoToSbxValue( xVar.get(), aValue );
+
+ sal_Int32* pIndices = indices.getArray();
+ pArray->Put(xVar.get(), pIndices);
+
+ }
+ }
+}
+
+void unoToSbxValue( SbxVariable* pVar, const Any& aValue )
+{
+ const Type& aType = aValue.getValueType();
+ TypeClass eTypeClass = aType.getTypeClass();
+ switch( eTypeClass )
+ {
+ case TypeClass_TYPE:
+ {
+ // Map Type to IdlClass
+ Type aType_;
+ aValue >>= aType_;
+ Reference<XIdlClass> xClass = TypeToIdlClass( aType_ );
+ Any aClassAny;
+ aClassAny <<= xClass;
+
+ // instantiate SbUnoObject
+ SbUnoObject* pSbUnoObject = new SbUnoObject( OUString(), aClassAny );
+ SbxObjectRef xWrapper = static_cast<SbxObject*>(pSbUnoObject);
+
+ // If the object is invalid deliver null
+ if( !pSbUnoObject->getUnoAny().hasValue() )
+ {
+ pVar->PutObject( nullptr );
+ }
+ else
+ {
+ pVar->PutObject( xWrapper.get() );
+ }
+ }
+ break;
+ // Interfaces and Structs must be wrapped in a SbUnoObject
+ case TypeClass_INTERFACE:
+ case TypeClass_STRUCT:
+ case TypeClass_EXCEPTION:
+ {
+ if( eTypeClass == TypeClass_STRUCT )
+ {
+ ArrayWrapper aWrap;
+ NativeObjectWrapper aNativeObjectWrapper;
+ if ( aValue >>= aWrap )
+ {
+ SbxDimArray* pArray = nullptr;
+ Sequence< sal_Int32 > indices;
+ Sequence< sal_Int32 > sizes;
+ implSequenceToMultiDimArray( pArray, indices, sizes, aWrap.Array, /*dimension*/0, aWrap.IsZeroIndex, nullptr );
+ if ( pArray )
+ {
+ SbxDimArrayRef xArray = pArray;
+ SbxFlagBits nFlags = pVar->GetFlags();
+ pVar->ResetFlag( SbxFlagBits::Fixed );
+ pVar->PutObject( xArray.get() );
+ pVar->SetFlags( nFlags );
+ }
+ else
+ pVar->PutEmpty();
+ break;
+ }
+ else if ( aValue >>= aNativeObjectWrapper )
+ {
+ sal_uInt32 nIndex = 0;
+ if( aNativeObjectWrapper.ObjectId >>= nIndex )
+ {
+ SbxObject* pObj = lcl_getNativeObject( nIndex );
+ pVar->PutObject( pObj );
+ }
+ else
+ pVar->PutEmpty();
+ break;
+ }
+ else
+ {
+ SbiInstance* pInst = GetSbData()->pInst;
+ if( pInst && pInst->IsCompatibility() )
+ {
+ oleautomation::Date aDate;
+ if( aValue >>= aDate )
+ {
+ pVar->PutDate( aDate.Value );
+ break;
+ }
+ else
+ {
+ oleautomation::Decimal aDecimal;
+ if( aValue >>= aDecimal )
+ {
+ pVar->PutDecimal( aDecimal );
+ break;
+ }
+ else
+ {
+ oleautomation::Currency aCurrency;
+ if( aValue >>= aCurrency )
+ {
+ pVar->PutCurrency( aCurrency.Value );
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ // instantiate a SbUnoObject
+ SbUnoObject* pSbUnoObject = new SbUnoObject( OUString(), aValue );
+ //If this is called externally e.g. from the scripting
+ //framework then there is no 'active' runtime the default property will not be set up
+ //only a vba object will have XDefaultProp set anyway so... this
+ //test seems a bit of overkill
+ //if ( SbiRuntime::isVBAEnabled() )
+ {
+ OUString sDfltPropName;
+
+ if ( SbUnoObject::getDefaultPropName( pSbUnoObject, sDfltPropName ) )
+ {
+ pSbUnoObject->SetDfltProperty( sDfltPropName );
+ }
+ }
+ SbxObjectRef xWrapper = static_cast<SbxObject*>(pSbUnoObject);
+
+ // If the object is invalid deliver null
+ if( !pSbUnoObject->getUnoAny().hasValue() )
+ {
+ pVar->PutObject( nullptr );
+ }
+ else
+ {
+ pVar->PutObject( xWrapper.get() );
+ }
+ }
+ break;
+
+
+ case TypeClass_ENUM:
+ {
+ sal_Int32 nEnum = 0;
+ enum2int( nEnum, aValue );
+ pVar->PutLong( nEnum );
+ }
+ break;
+
+ case TypeClass_SEQUENCE:
+ {
+ Reference< XIdlClass > xIdlTargetClass = TypeToIdlClass( aType );
+ Reference< XIdlArray > xIdlArray = xIdlTargetClass->getArray();
+ sal_Int32 i, nLen = xIdlArray->getLen( aValue );
+
+ typelib_TypeDescription * pTD = nullptr;
+ aType.getDescription( &pTD );
+ assert( pTD && pTD->eTypeClass == typelib_TypeClass_SEQUENCE );
+ Type aElementType( reinterpret_cast<typelib_IndirectTypeDescription *>(pTD)->pType );
+ ::typelib_typedescription_release( pTD );
+
+ // build an Array in Basic
+ SbxDimArrayRef xArray;
+ SbxDataType eSbxElementType = unoToSbxType( aElementType.getTypeClass() );
+ xArray = new SbxDimArray( eSbxElementType );
+ if( nLen > 0 )
+ {
+ xArray->unoAddDim(0, nLen - 1);
+
+ // register the elements as variables
+ for( i = 0 ; i < nLen ; i++ )
+ {
+ // convert elements
+ Any aElementAny = xIdlArray->get( aValue, static_cast<sal_uInt32>(i) );
+ auto xVar = tools::make_ref<SbxVariable>( eSbxElementType );
+ unoToSbxValue( xVar.get(), aElementAny );
+
+ // put into the Array
+ xArray->Put(xVar.get(), &i);
+ }
+ }
+ else
+ {
+ xArray->unoAddDim(0, -1);
+ }
+
+ // return the Array
+ SbxFlagBits nFlags = pVar->GetFlags();
+ pVar->ResetFlag( SbxFlagBits::Fixed );
+ pVar->PutObject( xArray.get() );
+ pVar->SetFlags( nFlags );
+
+ }
+ break;
+
+
+ case TypeClass_BOOLEAN: pVar->PutBool( *o3tl::forceAccess<bool>(aValue) ); break;
+ case TypeClass_CHAR:
+ {
+ pVar->PutChar( *o3tl::forceAccess<sal_Unicode>(aValue) );
+ break;
+ }
+ case TypeClass_STRING: { OUString val; aValue >>= val; pVar->PutString( val ); } break;
+ case TypeClass_FLOAT: { float val = 0; aValue >>= val; pVar->PutSingle( val ); } break;
+ case TypeClass_DOUBLE: { double val = 0; aValue >>= val; pVar->PutDouble( val ); } break;
+ case TypeClass_BYTE: { sal_Int8 val = 0; aValue >>= val; pVar->PutInteger( val ); } break;
+ case TypeClass_SHORT: { sal_Int16 val = 0; aValue >>= val; pVar->PutInteger( val ); } break;
+ case TypeClass_LONG: { sal_Int32 val = 0; aValue >>= val; pVar->PutLong( val ); } break;
+ case TypeClass_HYPER: { sal_Int64 val = 0; aValue >>= val; pVar->PutInt64( val ); } break;
+ case TypeClass_UNSIGNED_SHORT: { sal_uInt16 val = 0; aValue >>= val; pVar->PutUShort( val ); } break;
+ case TypeClass_UNSIGNED_LONG: { sal_uInt32 val = 0; aValue >>= val; pVar->PutULong( val ); } break;
+ case TypeClass_UNSIGNED_HYPER: { sal_uInt64 val = 0; aValue >>= val; pVar->PutUInt64( val ); } break;
+ default: pVar->PutEmpty(); break;
+ }
+}
+
+// Deliver the reflection for Sbx types
+static Type getUnoTypeForSbxBaseType( SbxDataType eType )
+{
+ Type aRetType = cppu::UnoType<void>::get();
+ switch( eType )
+ {
+ case SbxNULL: aRetType = cppu::UnoType<XInterface>::get(); break;
+ case SbxINTEGER: aRetType = cppu::UnoType<sal_Int16>::get(); break;
+ case SbxLONG: aRetType = cppu::UnoType<sal_Int32>::get(); break;
+ case SbxSINGLE: aRetType = cppu::UnoType<float>::get(); break;
+ case SbxDOUBLE: aRetType = cppu::UnoType<double>::get(); break;
+ case SbxCURRENCY: aRetType = cppu::UnoType<oleautomation::Currency>::get(); break;
+ case SbxDECIMAL: aRetType = cppu::UnoType<oleautomation::Decimal>::get(); break;
+ case SbxDATE: {
+ SbiInstance* pInst = GetSbData()->pInst;
+ if( pInst && pInst->IsCompatibility() )
+ aRetType = cppu::UnoType<double>::get();
+ else
+ aRetType = cppu::UnoType<oleautomation::Date>::get();
+ }
+ break;
+ case SbxSTRING: aRetType = cppu::UnoType<OUString>::get(); break;
+ case SbxBOOL: aRetType = cppu::UnoType<sal_Bool>::get(); break;
+ case SbxVARIANT: aRetType = cppu::UnoType<Any>::get(); break;
+ case SbxCHAR: aRetType = cppu::UnoType<cppu::UnoCharType>::get(); break;
+ case SbxBYTE: aRetType = cppu::UnoType<sal_Int8>::get(); break;
+ case SbxUSHORT: aRetType = cppu::UnoType<cppu::UnoUnsignedShortType>::get(); break;
+ case SbxULONG: aRetType = ::cppu::UnoType<sal_uInt32>::get(); break;
+ // map machine-dependent ones to long for consistency
+ case SbxINT: aRetType = ::cppu::UnoType<sal_Int32>::get(); break;
+ case SbxUINT: aRetType = ::cppu::UnoType<sal_uInt32>::get(); break;
+ default: break;
+ }
+ return aRetType;
+}
+
+// Converting of Sbx to Uno without a know target class for TypeClass_ANY
+static Type getUnoTypeForSbxValue( const SbxValue* pVal )
+{
+ Type aRetType = cppu::UnoType<void>::get();
+ if( !pVal )
+ return aRetType;
+
+ // convert SbxType to Uno
+ SbxDataType eBaseType = pVal->SbxValue::GetType();
+ if( eBaseType == SbxOBJECT )
+ {
+ SbxBaseRef xObj = pVal->GetObject();
+ if( !xObj.is() )
+ {
+ aRetType = cppu::UnoType<XInterface>::get();
+ return aRetType;
+ }
+
+ if( auto pArray = dynamic_cast<SbxDimArray*>( xObj.get() ) )
+ {
+ sal_Int32 nDims = pArray->GetDims();
+ Type aElementType = getUnoTypeForSbxBaseType( static_cast<SbxDataType>(pArray->GetType() & 0xfff) );
+ TypeClass eElementTypeClass = aElementType.getTypeClass();
+
+ // Normal case: One dimensional array
+ sal_Int32 nLower, nUpper;
+ if (nDims == 1 && pArray->GetDim(1, nLower, nUpper))
+ {
+ if( eElementTypeClass == TypeClass_VOID || eElementTypeClass == TypeClass_ANY )
+ {
+ // If all elements of the arrays are from the same type, take
+ // this one - otherwise the whole will be considered as Any-Sequence
+ bool bNeedsInit = true;
+
+ for (sal_Int32 aIdx[1] = { nLower }; aIdx[0] <= nUpper; ++aIdx[0])
+ {
+ SbxVariableRef xVar = pArray->Get(aIdx);
+ Type aType = getUnoTypeForSbxValue( xVar.get() );
+ if( bNeedsInit )
+ {
+ if( aType.getTypeClass() == TypeClass_VOID )
+ {
+ // if only first element is void: different types -> []any
+ // if all elements are void: []void is not allowed -> []any
+ aElementType = cppu::UnoType<Any>::get();
+ break;
+ }
+ aElementType = aType;
+ bNeedsInit = false;
+ }
+ else if( aElementType != aType )
+ {
+ // different types -> AnySequence
+ aElementType = cppu::UnoType<Any>::get();
+ break;
+ }
+ }
+ }
+
+ OUString aSeqTypeName = aSeqLevelStr + aElementType.getTypeName();
+ aRetType = Type( TypeClass_SEQUENCE, aSeqTypeName );
+ }
+ // #i33795 Map also multi dimensional arrays to corresponding sequences
+ else if( nDims > 1 )
+ {
+ if( eElementTypeClass == TypeClass_VOID || eElementTypeClass == TypeClass_ANY )
+ {
+ // For this check the array's dim structure does not matter
+ sal_uInt32 nFlatArraySize = pArray->Count();
+
+ bool bNeedsInit = true;
+ for( sal_uInt32 i = 0 ; i < nFlatArraySize ; i++ )
+ {
+ SbxVariableRef xVar = pArray->SbxArray::Get(i);
+ Type aType = getUnoTypeForSbxValue( xVar.get() );
+ if( bNeedsInit )
+ {
+ if( aType.getTypeClass() == TypeClass_VOID )
+ {
+ // if only first element is void: different types -> []any
+ // if all elements are void: []void is not allowed -> []any
+ aElementType = cppu::UnoType<Any>::get();
+ break;
+ }
+ aElementType = aType;
+ bNeedsInit = false;
+ }
+ else if( aElementType != aType )
+ {
+ // different types -> AnySequence
+ aElementType = cppu::UnoType<Any>::get();
+ break;
+ }
+ }
+ }
+
+ OUStringBuffer aSeqTypeName;
+ for(sal_Int32 iDim = 0 ; iDim < nDims ; iDim++ )
+ {
+ aSeqTypeName.append(aSeqLevelStr);
+ }
+ aSeqTypeName.append(aElementType.getTypeName());
+ aRetType = Type( TypeClass_SEQUENCE, aSeqTypeName.makeStringAndClear() );
+ }
+ }
+ // No array, but ...
+ else if( auto obj = dynamic_cast<SbUnoObject*>( xObj.get() ) )
+ {
+ aRetType = obj->getUnoAny().getValueType();
+ }
+ // SbUnoAnyObject?
+ else if( auto any = dynamic_cast<SbUnoAnyObject*>( xObj.get() ) )
+ {
+ aRetType = any->getValue().getValueType();
+ }
+ // Otherwise it is a No-Uno-Basic-Object -> default==deliver void
+ }
+ // No object, convert basic type
+ else
+ {
+ aRetType = getUnoTypeForSbxBaseType( eBaseType );
+ }
+ return aRetType;
+}
+
+// converting of Sbx to Uno without known target class for TypeClass_ANY
+static Any sbxToUnoValueImpl( const SbxValue* pVar, bool bBlockConversionToSmallestType = false )
+{
+ SbxDataType eBaseType = pVar->SbxValue::GetType();
+ if( eBaseType == SbxOBJECT )
+ {
+ SbxBaseRef xObj = pVar->GetObject();
+ if( xObj.is() )
+ {
+ if( auto obj = dynamic_cast<SbUnoAnyObject*>( xObj.get() ) )
+ return obj->getValue();
+ if( auto pClassModuleObj = dynamic_cast<SbClassModuleObject*>( xObj.get() ) )
+ {
+ Any aRetAny;
+ SbModule* pClassModule = pClassModuleObj->getClassModule();
+ if( pClassModule->createCOMWrapperForIface( aRetAny, pClassModuleObj ) )
+ return aRetAny;
+ }
+ if( dynamic_cast<const SbUnoObject*>( xObj.get() ) == nullptr )
+ {
+ // Create NativeObjectWrapper to identify object in case of callbacks
+ SbxObject* pObj = dynamic_cast<SbxObject*>( pVar->GetObject() );
+ if( pObj != nullptr )
+ {
+ NativeObjectWrapper aNativeObjectWrapper;
+ sal_uInt32 nIndex = lcl_registerNativeObjectWrapper( pObj );
+ aNativeObjectWrapper.ObjectId <<= nIndex;
+ Any aRetAny;
+ aRetAny <<= aNativeObjectWrapper;
+ return aRetAny;
+ }
+ }
+ }
+ }
+
+ Type aType = getUnoTypeForSbxValue( pVar );
+ TypeClass eType = aType.getTypeClass();
+
+ if( !bBlockConversionToSmallestType )
+ {
+ // #79615 Choose "smallest" representation for int values
+ // because up cast is allowed, downcast not
+ switch( eType )
+ {
+ case TypeClass_FLOAT:
+ case TypeClass_DOUBLE:
+ {
+ double d = pVar->GetDouble();
+ if( rtl::math::approxEqual(d, floor( d )) )
+ {
+ if( d >= -128 && d <= 127 )
+ aType = ::cppu::UnoType<sal_Int8>::get();
+ else if( d >= SbxMININT && d <= SbxMAXINT )
+ aType = ::cppu::UnoType<sal_Int16>::get();
+ else if( d >= -SbxMAXLNG && d <= SbxMAXLNG )
+ aType = ::cppu::UnoType<sal_Int32>::get();
+ }
+ break;
+ }
+ case TypeClass_SHORT:
+ {
+ sal_Int16 n = pVar->GetInteger();
+ if( n >= -128 && n <= 127 )
+ aType = ::cppu::UnoType<sal_Int8>::get();
+ break;
+ }
+ case TypeClass_LONG:
+ {
+ sal_Int32 n = pVar->GetLong();
+ if( n >= -128 && n <= 127 )
+ aType = ::cppu::UnoType<sal_Int8>::get();
+ else if( n >= SbxMININT && n <= SbxMAXINT )
+ aType = ::cppu::UnoType<sal_Int16>::get();
+ break;
+ }
+ case TypeClass_UNSIGNED_SHORT:
+ {
+ sal_uInt16 n = pVar->GetUShort();
+ if( n <= 255 )
+ aType = cppu::UnoType<sal_uInt8>::get();
+ break;
+ }
+ case TypeClass_UNSIGNED_LONG:
+ {
+ sal_uInt32 n = pVar->GetLong();
+ if( n <= 255 )
+ aType = cppu::UnoType<sal_uInt8>::get();
+ else if( n <= SbxMAXUINT )
+ aType = cppu::UnoType<cppu::UnoUnsignedShortType>::get();
+ break;
+ }
+ // TODO: need to add hyper types ?
+ default: break;
+ }
+ }
+
+ return sbxToUnoValue( pVar, aType );
+}
+
+
+// Helper function for StepREDIMP
+static Any implRekMultiDimArrayToSequence( SbxDimArray* pArray,
+ const Type& aElemType, sal_Int32 nMaxDimIndex, sal_Int32 nActualDim,
+ sal_Int32* pActualIndices, sal_Int32* pLowerBounds, sal_Int32* pUpperBounds )
+{
+ sal_Int32 nSeqLevel = nMaxDimIndex - nActualDim + 1;
+ OUStringBuffer aSeqTypeName;
+ sal_Int32 i;
+ for( i = 0 ; i < nSeqLevel ; i++ )
+ {
+ aSeqTypeName.append(aSeqLevelStr);
+ }
+ aSeqTypeName.append(aElemType.getTypeName());
+ Type aSeqType( TypeClass_SEQUENCE, aSeqTypeName.makeStringAndClear() );
+
+ // Create Sequence instance
+ Any aRetVal;
+ Reference< XIdlClass > xIdlTargetClass = TypeToIdlClass( aSeqType );
+ xIdlTargetClass->createObject( aRetVal );
+
+ // Alloc sequence according to array bounds
+ sal_Int32 nUpper = pUpperBounds[nActualDim];
+ sal_Int32 nLower = pLowerBounds[nActualDim];
+ sal_Int32 nSeqSize = nUpper - nLower + 1;
+ Reference< XIdlArray > xArray = xIdlTargetClass->getArray();
+ xArray->realloc( aRetVal, nSeqSize );
+
+ sal_Int32& ri = pActualIndices[nActualDim];
+
+ for( ri = nLower,i = 0 ; ri <= nUpper ; ri++,i++ )
+ {
+ Any aElementVal;
+
+ if( nActualDim < nMaxDimIndex )
+ {
+ aElementVal = implRekMultiDimArrayToSequence( pArray, aElemType,
+ nMaxDimIndex, nActualDim + 1, pActualIndices, pLowerBounds, pUpperBounds );
+ }
+ else
+ {
+ SbxVariable* pSource = pArray->Get(pActualIndices);
+ aElementVal = sbxToUnoValue( pSource, aElemType );
+ }
+
+ try
+ {
+ // transfer to the sequence
+ xArray->set( aRetVal, i, aElementVal );
+ }
+ catch( const IllegalArgumentException& )
+ {
+ StarBASIC::Error( ERRCODE_BASIC_EXCEPTION,
+ implGetExceptionMsg( ::cppu::getCaughtException() ) );
+ }
+ catch (const IndexOutOfBoundsException&)
+ {
+ StarBASIC::Error( ERRCODE_BASIC_OUT_OF_RANGE );
+ }
+ }
+ return aRetVal;
+}
+
+// Map old interface
+Any sbxToUnoValue( const SbxValue* pVar )
+{
+ return sbxToUnoValueImpl( pVar );
+}
+
+// function to find a global identifier in
+// the UnoScope and to wrap it for Sbx
+static bool implGetTypeByName( const OUString& rName, Type& rRetType )
+{
+ bool bSuccess = false;
+
+ const Reference< XHierarchicalNameAccess >& xTypeAccess = getTypeProvider_Impl();
+ if( xTypeAccess->hasByHierarchicalName( rName ) )
+ {
+ Any aRet = xTypeAccess->getByHierarchicalName( rName );
+ Reference< XTypeDescription > xTypeDesc;
+ aRet >>= xTypeDesc;
+
+ if( xTypeDesc.is() )
+ {
+ rRetType = Type( xTypeDesc->getTypeClass(), xTypeDesc->getName() );
+ bSuccess = true;
+ }
+ }
+ return bSuccess;
+}
+
+
+// converting of Sbx to Uno with known target class
+Any sbxToUnoValue( const SbxValue* pVar, const Type& rType, Property const * pUnoProperty )
+{
+ Any aRetVal;
+
+ // #94560 No conversion of empty/void for MAYBE_VOID properties
+ if( pUnoProperty && pUnoProperty->Attributes & PropertyAttribute::MAYBEVOID )
+ {
+ if( pVar->IsEmpty() )
+ return aRetVal;
+ }
+
+ SbxDataType eBaseType = pVar->SbxValue::GetType();
+ if( eBaseType == SbxOBJECT )
+ {
+ SbxBaseRef xObj = pVar->GetObject();
+ if ( auto obj = dynamic_cast<SbUnoAnyObject*>( xObj.get() ) )
+ {
+ return obj->getValue();
+ }
+ }
+
+ TypeClass eType = rType.getTypeClass();
+ switch( eType )
+ {
+ case TypeClass_INTERFACE:
+ case TypeClass_STRUCT:
+ case TypeClass_EXCEPTION:
+ {
+ Reference< XIdlClass > xIdlTargetClass = TypeToIdlClass( rType );
+
+ // null reference?
+ if( pVar->IsNull() && eType == TypeClass_INTERFACE )
+ {
+ Reference< XInterface > xRef;
+ OUString aClassName = xIdlTargetClass->getName();
+ Type aClassType( xIdlTargetClass->getTypeClass(), aClassName );
+ aRetVal.setValue( &xRef, aClassType );
+ }
+ else
+ {
+ // #112368 Special conversion for Decimal, Currency and Date
+ if( eType == TypeClass_STRUCT )
+ {
+ SbiInstance* pInst = GetSbData()->pInst;
+ if( pInst && pInst->IsCompatibility() )
+ {
+ if( rType == cppu::UnoType<oleautomation::Decimal>::get())
+ {
+ oleautomation::Decimal aDecimal;
+ pVar->fillAutomationDecimal( aDecimal );
+ aRetVal <<= aDecimal;
+ break;
+ }
+ else if( rType == cppu::UnoType<oleautomation::Currency>::get())
+ {
+ // assumes per previous code that ole Currency is Int64
+ aRetVal <<= pVar->GetInt64();
+ break;
+ }
+ else if( rType == cppu::UnoType<oleautomation::Date>::get())
+ {
+ oleautomation::Date aDate;
+ aDate.Value = pVar->GetDate();
+ aRetVal <<= aDate;
+ break;
+ }
+ }
+ }
+
+ SbxBaseRef pObj = pVar->GetObject();
+ if( auto obj = dynamic_cast<SbUnoObject*>( pObj.get() ) )
+ {
+ aRetVal = obj->getUnoAny();
+ }
+ else if( auto structRef = dynamic_cast<SbUnoStructRefObject*>( pObj.get() ) )
+ {
+ aRetVal = structRef->getUnoAny();
+ }
+ else
+ {
+ // null object -> null XInterface
+ Reference<XInterface> xInt;
+ aRetVal <<= xInt;
+ }
+ }
+ }
+ break;
+
+ case TypeClass_TYPE:
+ {
+ if( eBaseType == SbxOBJECT )
+ {
+ // XIdlClass?
+ Reference< XIdlClass > xIdlClass;
+
+ SbxBaseRef pObj = pVar->GetObject();
+ if( auto obj = dynamic_cast<SbUnoObject*>( pObj.get() ) )
+ {
+ Any aUnoAny = obj->getUnoAny();
+ aUnoAny >>= xIdlClass;
+ }
+
+ if( xIdlClass.is() )
+ {
+ OUString aClassName = xIdlClass->getName();
+ Type aType( xIdlClass->getTypeClass(), aClassName );
+ aRetVal <<= aType;
+ }
+ }
+ else if( eBaseType == SbxSTRING )
+ {
+ OUString aTypeName = pVar->GetOUString();
+ Type aType;
+ bool bSuccess = implGetTypeByName( aTypeName, aType );
+ if( bSuccess )
+ {
+ aRetVal <<= aType;
+ }
+ }
+ }
+ break;
+
+
+ case TypeClass_ENUM:
+ {
+ aRetVal = int2enum( pVar->GetLong(), rType );
+ }
+ break;
+
+ case TypeClass_SEQUENCE:
+ {
+ SbxBaseRef xObj = pVar->GetObject();
+ if( auto pArray = dynamic_cast<SbxDimArray*>( xObj.get() ) )
+ {
+ sal_Int32 nDims = pArray->GetDims();
+
+ // Normal case: One dimensional array
+ sal_Int32 nLower, nUpper;
+ if (nDims == 1 && pArray->GetDim(1, nLower, nUpper))
+ {
+ sal_Int32 nSeqSize = nUpper - nLower + 1;
+
+ // create the instance of the required sequence
+ Reference< XIdlClass > xIdlTargetClass = TypeToIdlClass( rType );
+ xIdlTargetClass->createObject( aRetVal );
+ Reference< XIdlArray > xArray = xIdlTargetClass->getArray();
+ xArray->realloc( aRetVal, nSeqSize );
+
+ // Element-Type
+ OUString aClassName = xIdlTargetClass->getName();
+ typelib_TypeDescription * pSeqTD = nullptr;
+ typelib_typedescription_getByName( &pSeqTD, aClassName.pData );
+ assert( pSeqTD );
+ Type aElemType( reinterpret_cast<typelib_IndirectTypeDescription *>(pSeqTD)->pType );
+
+ // convert all array member and register them
+ sal_Int32 aIdx[1];
+ aIdx[0] = nLower;
+ for (sal_Int32 i = 0 ; i < nSeqSize; ++i, ++aIdx[0])
+ {
+ SbxVariableRef xVar = pArray->Get(aIdx);
+
+ // Convert the value of Sbx to Uno
+ Any aAnyValue = sbxToUnoValue( xVar.get(), aElemType );
+
+ try
+ {
+ // insert in the sequence
+ xArray->set( aRetVal, i, aAnyValue );
+ }
+ catch( const IllegalArgumentException& )
+ {
+ StarBASIC::Error( ERRCODE_BASIC_EXCEPTION,
+ implGetExceptionMsg( ::cppu::getCaughtException() ) );
+ }
+ catch (const IndexOutOfBoundsException&)
+ {
+ StarBASIC::Error( ERRCODE_BASIC_OUT_OF_RANGE );
+ }
+ }
+ }
+ // #i33795 Map also multi dimensional arrays to corresponding sequences
+ else if( nDims > 1 )
+ {
+ // Element-Type
+ typelib_TypeDescription * pSeqTD = nullptr;
+ Type aCurType( rType );
+ sal_Int32 nSeqLevel = 0;
+ Type aElemType;
+ do
+ {
+ OUString aTypeName = aCurType.getTypeName();
+ typelib_typedescription_getByName( &pSeqTD, aTypeName.pData );
+ assert( pSeqTD );
+ if( pSeqTD->eTypeClass == typelib_TypeClass_SEQUENCE )
+ {
+ aCurType = Type( reinterpret_cast<typelib_IndirectTypeDescription *>(pSeqTD)->pType );
+ nSeqLevel++;
+ }
+ else
+ {
+ aElemType = aCurType;
+ break;
+ }
+ }
+ while( true );
+
+ if( nSeqLevel == nDims )
+ {
+ std::unique_ptr<sal_Int32[]> pLowerBounds(new sal_Int32[nDims]);
+ std::unique_ptr<sal_Int32[]> pUpperBounds(new sal_Int32[nDims]);
+ std::unique_ptr<sal_Int32[]> pActualIndices(new sal_Int32[nDims]);
+ for(sal_Int32 i = 1 ; i <= nDims ; i++ )
+ {
+ sal_Int32 lBound, uBound;
+ pArray->GetDim(i, lBound, uBound);
+
+ sal_Int32 j = i - 1;
+ pActualIndices[j] = pLowerBounds[j] = lBound;
+ pUpperBounds[j] = uBound;
+ }
+
+ aRetVal = implRekMultiDimArrayToSequence( pArray, aElemType,
+ nDims - 1, 0, pActualIndices.get(), pLowerBounds.get(), pUpperBounds.get() );
+ }
+ }
+ }
+ }
+ break;
+
+
+ // for Any use the class independent converting routine
+ case TypeClass_ANY:
+ {
+ aRetVal = sbxToUnoValueImpl( pVar );
+ }
+ break;
+
+ case TypeClass_BOOLEAN:
+ {
+ aRetVal <<= pVar->GetBool();
+ break;
+ }
+ case TypeClass_CHAR:
+ {
+ aRetVal <<= pVar->GetChar();
+ break;
+ }
+ case TypeClass_STRING: aRetVal <<= pVar->GetOUString(); break;
+ case TypeClass_FLOAT: aRetVal <<= pVar->GetSingle(); break;
+ case TypeClass_DOUBLE: aRetVal <<= pVar->GetDouble(); break;
+
+ case TypeClass_BYTE:
+ {
+ sal_Int16 nVal = pVar->GetInteger();
+ bool bOverflow = false;
+ if( nVal < -128 )
+ {
+ bOverflow = true;
+ nVal = -128;
+ }
+ else if( nVal > 255 ) // 128..255 map to -128..-1
+ {
+ bOverflow = true;
+ nVal = 127;
+ }
+ if( bOverflow )
+ StarBASIC::Error( ERRCODE_BASIC_MATH_OVERFLOW );
+
+ sal_Int8 nByteVal = static_cast<sal_Int8>(nVal);
+ aRetVal <<= nByteVal;
+ break;
+ }
+ case TypeClass_SHORT: aRetVal <<= pVar->GetInteger(); break;
+ case TypeClass_LONG: aRetVal <<= pVar->GetLong(); break;
+ case TypeClass_HYPER: aRetVal <<= pVar->GetInt64(); break;
+ case TypeClass_UNSIGNED_SHORT: aRetVal <<= pVar->GetUShort(); break;
+ case TypeClass_UNSIGNED_LONG: aRetVal <<= pVar->GetULong(); break;
+ case TypeClass_UNSIGNED_HYPER: aRetVal <<= pVar->GetUInt64(); break;
+ default: break;
+ }
+
+ return aRetVal;
+}
+
+static void processAutomationParams( SbxArray* pParams, Sequence< Any >& args, sal_uInt32 nParamCount )
+{
+ AutomationNamedArgsSbxArray* pArgNamesArray = dynamic_cast<AutomationNamedArgsSbxArray*>( pParams );
+
+ args.realloc( nParamCount );
+ Any* pAnyArgs = args.getArray();
+ bool bBlockConversionToSmallestType = GetSbData()->pInst->IsCompatibility();
+ sal_uInt32 i = 0;
+ if( pArgNamesArray )
+ {
+ Sequence< OUString >& rNameSeq = pArgNamesArray->getNames();
+ OUString* pNames = rNameSeq.getArray();
+ Any aValAny;
+ for( i = 0 ; i < nParamCount ; i++ )
+ {
+ sal_uInt32 iSbx = i + 1;
+
+ aValAny = sbxToUnoValueImpl(pParams->Get(iSbx),
+ bBlockConversionToSmallestType );
+
+ OUString aParamName = pNames[iSbx];
+ if( !aParamName.isEmpty() )
+ {
+ oleautomation::NamedArgument aNamedArgument;
+ aNamedArgument.Name = aParamName;
+ aNamedArgument.Value = aValAny;
+ pAnyArgs[i] <<= aNamedArgument;
+ }
+ else
+ {
+ pAnyArgs[i] = aValAny;
+ }
+ }
+ }
+ else
+ {
+ for( i = 0 ; i < nParamCount ; i++ )
+ {
+ pAnyArgs[i] = sbxToUnoValueImpl(pParams->Get(i + 1),
+ bBlockConversionToSmallestType );
+ }
+ }
+
+}
+
+namespace {
+
+enum class INVOKETYPE
+{
+ GetProp = 0,
+ Func
+};
+
+}
+
+static Any invokeAutomationMethod( const OUString& Name, Sequence< Any > const & args, SbxArray* pParams, sal_uInt32 nParamCount, Reference< XInvocation > const & rxInvocation, INVOKETYPE invokeType )
+{
+ Sequence< sal_Int16 > OutParamIndex;
+ Sequence< Any > OutParam;
+
+ Any aRetAny;
+ switch( invokeType )
+ {
+ case INVOKETYPE::Func:
+ aRetAny = rxInvocation->invoke( Name, args, OutParamIndex, OutParam );
+ break;
+ case INVOKETYPE::GetProp:
+ {
+ Reference< XAutomationInvocation > xAutoInv( rxInvocation, UNO_QUERY );
+ aRetAny = xAutoInv->invokeGetProperty( Name, args, OutParamIndex, OutParam );
+ break;
+ }
+ default:
+ assert(false); break;
+
+ }
+ const sal_Int16* pIndices = OutParamIndex.getConstArray();
+ sal_uInt32 nLen = OutParamIndex.getLength();
+ if( nLen )
+ {
+ const Any* pNewValues = OutParam.getConstArray();
+ for( sal_uInt32 j = 0 ; j < nLen ; j++ )
+ {
+ sal_Int16 iTarget = pIndices[ j ];
+ if( o3tl::make_unsigned(iTarget) >= nParamCount )
+ break;
+ unoToSbxValue(pParams->Get(j + 1), pNewValues[j]);
+ }
+ }
+ return aRetAny;
+}
+
+// Debugging help method to readout the implemented interfaces of an object
+static OUString Impl_GetInterfaceInfo( const Reference< XInterface >& x, const Reference< XIdlClass >& xClass, sal_uInt16 nRekLevel )
+{
+ Type aIfaceType = cppu::UnoType<XInterface>::get();
+ static Reference< XIdlClass > xIfaceClass = TypeToIdlClass( aIfaceType );
+
+ OUStringBuffer aRetStr;
+ for( sal_uInt16 i = 0 ; i < nRekLevel ; i++ )
+ aRetStr.append( " " );
+ aRetStr.append( xClass->getName() );
+ OUString aClassName = xClass->getName();
+ Type aClassType( xClass->getTypeClass(), aClassName );
+
+ // checking if the interface is really supported
+ if( !x->queryInterface( aClassType ).hasValue() )
+ {
+ aRetStr.append( " (ERROR: Not really supported!)\n" );
+ }
+ // Are there super interfaces?
+ else
+ {
+ aRetStr.append( "\n" );
+
+ // get the super interfaces
+ Sequence< Reference< XIdlClass > > aSuperClassSeq = xClass->getSuperclasses();
+ const Reference< XIdlClass >* pClasses = aSuperClassSeq.getConstArray();
+ sal_uInt32 nSuperIfaceCount = aSuperClassSeq.getLength();
+ for( sal_uInt32 j = 0 ; j < nSuperIfaceCount ; j++ )
+ {
+ const Reference< XIdlClass >& rxIfaceClass = pClasses[j];
+ if( !rxIfaceClass->equals( xIfaceClass ) )
+ aRetStr.append( Impl_GetInterfaceInfo( x, rxIfaceClass, nRekLevel + 1 ) );
+ }
+ }
+ return aRetStr.makeStringAndClear();
+}
+
+static OUString getDbgObjectNameImpl(SbUnoObject& rUnoObj)
+{
+ OUString aName = rUnoObj.GetClassName();
+ if( aName.isEmpty() )
+ {
+ Any aToInspectObj = rUnoObj.getUnoAny();
+ Reference< XInterface > xObj(aToInspectObj, css::uno::UNO_QUERY);
+ if( xObj.is() )
+ {
+ Reference< XServiceInfo > xServiceInfo( xObj, UNO_QUERY );
+ if( xServiceInfo.is() )
+ aName = xServiceInfo->getImplementationName();
+ }
+ }
+ return aName;
+}
+
+static OUString getDbgObjectName(SbUnoObject& rUnoObj)
+{
+ OUString aName = getDbgObjectNameImpl(rUnoObj);
+ if( aName.isEmpty() )
+ aName += "Unknown";
+
+ OUStringBuffer aRet;
+ if( aName.getLength() > 20 )
+ {
+ aRet.append( "\n" );
+ }
+ aRet.append( "\"" );
+ aRet.append( aName );
+ aRet.append( "\":" );
+ return aRet.makeStringAndClear();
+}
+
+OUString getBasicObjectTypeName( SbxObject* pObj )
+{
+ if (pObj)
+ {
+ if (SbUnoObject* pUnoObj = dynamic_cast<SbUnoObject*>(pObj))
+ {
+ return getDbgObjectNameImpl(*pUnoObj);
+ }
+ else if (SbUnoStructRefObject* pUnoStructObj = dynamic_cast<SbUnoStructRefObject*>(pObj))
+ {
+ return pUnoStructObj->GetClassName();
+ }
+ }
+ return OUString();
+}
+
+namespace {
+
+bool matchesBasicTypeName(
+ css::uno::Reference<css::reflection::XIdlClass> const & unoType, OUString const & basicTypeName)
+{
+ if (unoType->getName().endsWithIgnoreAsciiCase(basicTypeName)) {
+ return true;
+ }
+ auto const sups = unoType->getSuperclasses();
+ return std::any_of(
+ sups.begin(), sups.end(),
+ [&basicTypeName](auto const & t) { return matchesBasicTypeName(t, basicTypeName); });
+}
+
+}
+
+bool checkUnoObjectType(SbUnoObject& rUnoObj, const OUString& rClass)
+{
+ Any aToInspectObj = rUnoObj.getUnoAny();
+
+ // Return true for XInvocation based objects as interface type names don't count then
+ Reference< XInvocation > xInvocation( aToInspectObj, UNO_QUERY );
+ if( xInvocation.is() )
+ {
+ return true;
+ }
+ bool bResult = false;
+ Reference< XTypeProvider > xTypeProvider( aToInspectObj, UNO_QUERY );
+ if( xTypeProvider.is() )
+ {
+ /* Although interfaces in the ooo.vba namespace obey the IDL rules and
+ have a leading 'X', in Basic we want to be able to do something
+ like 'Dim wb As Workbooks' or 'Dim lb As MSForms.Label'. Here we
+ add a leading 'X' to the class name and a leading dot to the entire
+ type name. This results e.g. in '.XWorkbooks' or '.MSForms.XLabel'
+ which matches the interface names 'ooo.vba.excel.XWorkbooks' or
+ 'ooo.vba.msforms.XLabel'.
+ */
+ OUString aClassName;
+ if ( SbiRuntime::isVBAEnabled() )
+ {
+ aClassName = ".";
+ sal_Int32 nClassNameDot = rClass.lastIndexOf( '.' );
+ if( nClassNameDot >= 0 )
+ {
+ aClassName += OUString::Concat(rClass.subView( 0, nClassNameDot + 1 )) + "X" + rClass.subView( nClassNameDot + 1 );
+ }
+ else
+ {
+ aClassName += "X" + rClass;
+ }
+ }
+ else // assume extended type declaration support for basic ( can't get here
+ // otherwise.
+ aClassName = rClass;
+
+ Sequence< Type > aTypeSeq = xTypeProvider->getTypes();
+ const Type* pTypeArray = aTypeSeq.getConstArray();
+ sal_uInt32 nIfaceCount = aTypeSeq.getLength();
+ for( sal_uInt32 j = 0 ; j < nIfaceCount ; j++ )
+ {
+ const Type& rType = pTypeArray[j];
+
+ Reference<XIdlClass> xClass = TypeToIdlClass( rType );
+ if( !xClass.is() )
+ {
+ OSL_FAIL("failed to get XIdlClass for type");
+ break;
+ }
+ OUString aInterfaceName = xClass->getName();
+ if ( aInterfaceName == "com.sun.star.bridge.oleautomation.XAutomationObject" )
+ {
+ // there is a hack in the extensions/source/ole/oleobj.cxx to return the typename of the automation object, lets check if it
+ // matches
+ Reference< XInvocation > xInv( aToInspectObj, UNO_QUERY );
+ if ( xInv.is() )
+ {
+ OUString sTypeName;
+ xInv->getValue( "$GetTypeName" ) >>= sTypeName;
+ if ( sTypeName.isEmpty() || sTypeName == "IDispatch" )
+ {
+ // can't check type, leave it pass
+ bResult = true;
+ }
+ else
+ {
+ bResult = sTypeName == rClass;
+ }
+ }
+ break; // finished checking automation object
+ }
+
+ if ( matchesBasicTypeName(xClass, aClassName) )
+ {
+ bResult = true;
+ break;
+ }
+ }
+ }
+ return bResult;
+}
+
+// Debugging help method to readout the implemented interfaces of an object
+static OUString Impl_GetSupportedInterfaces(SbUnoObject& rUnoObj)
+{
+ Any aToInspectObj = rUnoObj.getUnoAny();
+
+ // allow only TypeClass interface
+ OUStringBuffer aRet;
+ auto x = o3tl::tryAccess<Reference<XInterface>>(aToInspectObj);
+ if( !x )
+ {
+ aRet.append( ID_DBG_SUPPORTEDINTERFACES );
+ aRet.append( " not available.\n(TypeClass is not TypeClass_INTERFACE)\n" );
+ }
+ else
+ {
+ Reference< XTypeProvider > xTypeProvider( *x, UNO_QUERY );
+
+ aRet.append( "Supported interfaces by object " );
+ aRet.append(getDbgObjectName(rUnoObj));
+ aRet.append( "\n" );
+ if( xTypeProvider.is() )
+ {
+ // get the interfaces of the implementation
+ Sequence< Type > aTypeSeq = xTypeProvider->getTypes();
+ const Type* pTypeArray = aTypeSeq.getConstArray();
+ sal_uInt32 nIfaceCount = aTypeSeq.getLength();
+ for( sal_uInt32 j = 0 ; j < nIfaceCount ; j++ )
+ {
+ const Type& rType = pTypeArray[j];
+
+ Reference<XIdlClass> xClass = TypeToIdlClass( rType );
+ if( xClass.is() )
+ {
+ aRet.append( Impl_GetInterfaceInfo( *x, xClass, 1 ) );
+ }
+ else
+ {
+ typelib_TypeDescription * pTD = nullptr;
+ rType.getDescription( &pTD );
+
+ aRet.append( "*** ERROR: No IdlClass for type \"" );
+ aRet.append( pTD->pTypeName );
+ aRet.append( "\"\n*** Please check type library\n" );
+ }
+ }
+ }
+ }
+ return aRet.makeStringAndClear();
+}
+
+
+// Debugging help method SbxDataType -> String
+static OUString Dbg_SbxDataType2String( SbxDataType eType )
+{
+ OUStringBuffer aRet;
+ switch( +eType )
+ {
+ case SbxEMPTY: aRet.append("SbxEMPTY"); break;
+ case SbxNULL: aRet.append("SbxNULL"); break;
+ case SbxINTEGER: aRet.append("SbxINTEGER"); break;
+ case SbxLONG: aRet.append("SbxLONG"); break;
+ case SbxSINGLE: aRet.append("SbxSINGLE"); break;
+ case SbxDOUBLE: aRet.append("SbxDOUBLE"); break;
+ case SbxCURRENCY: aRet.append("SbxCURRENCY"); break;
+ case SbxDECIMAL: aRet.append("SbxDECIMAL"); break;
+ case SbxDATE: aRet.append("SbxDATE"); break;
+ case SbxSTRING: aRet.append("SbxSTRING"); break;
+ case SbxOBJECT: aRet.append("SbxOBJECT"); break;
+ case SbxERROR: aRet.append("SbxERROR"); break;
+ case SbxBOOL: aRet.append("SbxBOOL"); break;
+ case SbxVARIANT: aRet.append("SbxVARIANT"); break;
+ case SbxDATAOBJECT: aRet.append("SbxDATAOBJECT"); break;
+ case SbxCHAR: aRet.append("SbxCHAR"); break;
+ case SbxBYTE: aRet.append("SbxBYTE"); break;
+ case SbxUSHORT: aRet.append("SbxUSHORT"); break;
+ case SbxULONG: aRet.append("SbxULONG"); break;
+ case SbxSALINT64: aRet.append("SbxINT64"); break;
+ case SbxSALUINT64: aRet.append("SbxUINT64"); break;
+ case SbxINT: aRet.append("SbxINT"); break;
+ case SbxUINT: aRet.append("SbxUINT"); break;
+ case SbxVOID: aRet.append("SbxVOID"); break;
+ case SbxHRESULT: aRet.append("SbxHRESULT"); break;
+ case SbxPOINTER: aRet.append("SbxPOINTER"); break;
+ case SbxDIMARRAY: aRet.append("SbxDIMARRAY"); break;
+ case SbxCARRAY: aRet.append("SbxCARRAY"); break;
+ case SbxUSERDEF: aRet.append("SbxUSERDEF"); break;
+ case SbxLPSTR: aRet.append("SbxLPSTR"); break;
+ case SbxLPWSTR: aRet.append("SbxLPWSTR"); break;
+ case SbxCoreSTRING: aRet.append("SbxCoreSTRING"); break;
+ case SbxOBJECT | SbxARRAY: aRet.append("SbxARRAY"); break;
+ default: aRet.append("Unknown Sbx-Type!");break;
+ }
+ return aRet.makeStringAndClear();
+}
+
+// Debugging help method to display the properties of a SbUnoObjects
+static OUString Impl_DumpProperties(SbUnoObject& rUnoObj)
+{
+ OUStringBuffer aRet;
+ aRet.append("Properties of object ");
+ aRet.append(getDbgObjectName(rUnoObj));
+
+ // analyse the Uno-Infos to recognise the arrays
+ Reference< XIntrospectionAccess > xAccess = rUnoObj.getIntrospectionAccess();
+ if( !xAccess.is() )
+ {
+ Reference< XInvocation > xInvok = rUnoObj.getInvocation();
+ if( xInvok.is() )
+ xAccess = xInvok->getIntrospection();
+ }
+ if( !xAccess.is() )
+ {
+ aRet.append( "\nUnknown, no introspection available\n" );
+ return aRet.makeStringAndClear();
+ }
+
+ Sequence<Property> props = xAccess->getProperties( PropertyConcept::ALL - PropertyConcept::DANGEROUS );
+ sal_uInt32 nUnoPropCount = props.getLength();
+ const Property* pUnoProps = props.getConstArray();
+
+ SbxArray* pProps = rUnoObj.GetProperties();
+ sal_uInt32 nPropCount = pProps->Count();
+ sal_uInt32 nPropsPerLine = 1 + nPropCount / 30;
+ for( sal_uInt32 i = 0; i < nPropCount; i++ )
+ {
+ SbxVariable* pVar = pProps->Get(i);
+ if( pVar )
+ {
+ OUStringBuffer aPropStr;
+ if( (i % nPropsPerLine) == 0 )
+ aPropStr.append( "\n" );
+
+ // output the type and name
+ // Is it in Uno a sequence?
+ SbxDataType eType = pVar->GetFullType();
+
+ bool bMaybeVoid = false;
+ if( i < nUnoPropCount )
+ {
+ const Property& rProp = pUnoProps[ i ];
+
+ // For MAYBEVOID freshly convert the type from Uno,
+ // so not just SbxEMPTY is returned.
+ if( rProp.Attributes & PropertyAttribute::MAYBEVOID )
+ {
+ eType = unoToSbxType( rProp.Type.getTypeClass() );
+ bMaybeVoid = true;
+ }
+ if( eType == SbxOBJECT )
+ {
+ Type aType = rProp.Type;
+ if( aType.getTypeClass() == TypeClass_SEQUENCE )
+ eType = SbxDataType( SbxOBJECT | SbxARRAY );
+ }
+ }
+ aPropStr.append( Dbg_SbxDataType2String( eType ) );
+ if( bMaybeVoid )
+ aPropStr.append( "/void" );
+ aPropStr.append( " " );
+ aPropStr.append( pVar->GetName() );
+
+ if( i == nPropCount - 1 )
+ aPropStr.append( "\n" );
+ else
+ aPropStr.append( "; " );
+
+ aRet.append( aPropStr );
+ }
+ }
+ return aRet.makeStringAndClear();
+}
+
+// Debugging help method to display the methods of an SbUnoObjects
+static OUString Impl_DumpMethods(SbUnoObject& rUnoObj)
+{
+ OUStringBuffer aRet;
+ aRet.append("Methods of object ");
+ aRet.append(getDbgObjectName(rUnoObj));
+
+ // XIntrospectionAccess, so that the types of the parameter could be outputted
+ Reference< XIntrospectionAccess > xAccess = rUnoObj.getIntrospectionAccess();
+ if( !xAccess.is() )
+ {
+ Reference< XInvocation > xInvok = rUnoObj.getInvocation();
+ if( xInvok.is() )
+ xAccess = xInvok->getIntrospection();
+ }
+ if( !xAccess.is() )
+ {
+ aRet.append( "\nUnknown, no introspection available\n" );
+ return aRet.makeStringAndClear();
+ }
+ Sequence< Reference< XIdlMethod > > methods = xAccess->getMethods
+ ( MethodConcept::ALL - MethodConcept::DANGEROUS );
+ const Reference< XIdlMethod >* pUnoMethods = methods.getConstArray();
+
+ SbxArray* pMethods = rUnoObj.GetMethods();
+ sal_uInt32 nMethodCount = pMethods->Count();
+ if( !nMethodCount )
+ {
+ aRet.append( "\nNo methods found\n" );
+ return aRet.makeStringAndClear();
+ }
+ sal_uInt32 nPropsPerLine = 1 + nMethodCount / 30;
+ for( sal_uInt32 i = 0; i < nMethodCount; i++ )
+ {
+ SbxVariable* pVar = pMethods->Get(i);
+ if( pVar )
+ {
+ if( (i % nPropsPerLine) == 0 )
+ aRet.append( "\n" );
+
+ // address the method
+ const Reference< XIdlMethod >& rxMethod = pUnoMethods[i];
+
+ // Is it in Uno a sequence?
+ SbxDataType eType = pVar->GetFullType();
+ if( eType == SbxOBJECT )
+ {
+ Reference< XIdlClass > xClass = rxMethod->getReturnType();
+ if( xClass.is() && xClass->getTypeClass() == TypeClass_SEQUENCE )
+ eType = SbxDataType( SbxOBJECT | SbxARRAY );
+ }
+ // output the name and the type
+ aRet.append( Dbg_SbxDataType2String( eType ) );
+ aRet.append( " " );
+ aRet.append ( pVar->GetName() );
+ aRet.append( " ( " );
+
+ // the get-method mustn't have a parameter
+ Sequence< Reference< XIdlClass > > aParamsSeq = rxMethod->getParameterTypes();
+ sal_uInt32 nParamCount = aParamsSeq.getLength();
+ const Reference< XIdlClass >* pParams = aParamsSeq.getConstArray();
+
+ if( nParamCount > 0 )
+ {
+ for( sal_uInt32 j = 0; j < nParamCount; j++ )
+ {
+ aRet.append ( Dbg_SbxDataType2String( unoToSbxType( pParams[ j ] ) ) );
+ if( j < nParamCount - 1 )
+ aRet.append( ", " );
+ }
+ }
+ else
+ aRet.append( "void" );
+
+ aRet.append( " ) " );
+
+ if( i == nMethodCount - 1 )
+ aRet.append( "\n" );
+ else
+ aRet.append( "; " );
+ }
+ }
+ return aRet.makeStringAndClear();
+}
+
+
+// Implementation SbUnoObject
+void SbUnoObject::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
+{
+ if( bNeedIntrospection )
+ doIntrospection();
+
+ const SbxHint* pHint = dynamic_cast<const SbxHint*>(&rHint);
+ if( !pHint )
+ return;
+
+ SbxVariable* pVar = pHint->GetVar();
+ SbxArray* pParams = pVar->GetParameters();
+ SbUnoProperty* pProp = dynamic_cast<SbUnoProperty*>( pVar );
+ SbUnoMethod* pMeth = dynamic_cast<SbUnoMethod*>( pVar );
+ if( pProp )
+ {
+ bool bInvocation = pProp->isInvocationBased();
+ if( pHint->GetId() == SfxHintId::BasicDataWanted )
+ {
+ // Test-Properties
+ sal_Int32 nId = pProp->nId;
+ if( nId < 0 )
+ {
+ // Id == -1: Display implemented interfaces according the ClassProvider
+ if( nId == -1 ) // Property ID_DBG_SUPPORTEDINTERFACES"
+ {
+ OUString aRetStr = Impl_GetSupportedInterfaces(*this);
+ pVar->PutString( aRetStr );
+ }
+ // Id == -2: output properties
+ else if( nId == -2 ) // Property ID_DBG_PROPERTIES
+ {
+ // now all properties must be created
+ implCreateAll();
+ OUString aRetStr = Impl_DumpProperties(*this);
+ pVar->PutString( aRetStr );
+ }
+ // Id == -3: output the methods
+ else if( nId == -3 ) // Property ID_DBG_METHODS
+ {
+ // now all properties must be created
+ implCreateAll();
+ OUString aRetStr = Impl_DumpMethods(*this);
+ pVar->PutString( aRetStr );
+ }
+ return;
+ }
+
+ if( !bInvocation && mxUnoAccess.is() )
+ {
+ try
+ {
+ if ( maStructInfo )
+ {
+ StructRefInfo aMember = maStructInfo->getStructMember( pProp->GetName() );
+ if ( aMember.isEmpty() )
+ {
+ StarBASIC::Error( ERRCODE_BASIC_PROPERTY_NOT_FOUND );
+ }
+ else
+ {
+ if ( pProp->isUnoStruct() )
+ {
+ SbUnoStructRefObject* pSbUnoObject = new SbUnoStructRefObject( pProp->GetName(), std::move(aMember) );
+ SbxObjectRef xWrapper = static_cast<SbxObject*>(pSbUnoObject);
+ pVar->PutObject( xWrapper.get() );
+ }
+ else
+ {
+ Any aRetAny = aMember.getValue();
+ // take over the value from Uno to Sbx
+ unoToSbxValue( pVar, aRetAny );
+ }
+ return;
+ }
+ }
+ // get the value
+ Reference< XPropertySet > xPropSet( mxUnoAccess->queryAdapter( cppu::UnoType<XPropertySet>::get()), UNO_QUERY );
+ Any aRetAny = xPropSet->getPropertyValue( pProp->GetName() );
+ // The use of getPropertyValue (instead of using the index) is
+ // suboptimal, but the refactoring to XInvocation is already pending
+ // Otherwise it is possible to use FastPropertySet
+
+ // take over the value from Uno to Sbx
+ unoToSbxValue( pVar, aRetAny );
+ }
+ catch( const Exception& )
+ {
+ implHandleAnyException( ::cppu::getCaughtException() );
+ }
+ }
+ else if( bInvocation && mxInvocation.is() )
+ {
+ try
+ {
+ sal_uInt32 nParamCount = pParams ? (pParams->Count() - 1) : 0;
+ bool bCanBeConsideredAMethod = mxInvocation->hasMethod( pProp->GetName() );
+ Any aRetAny;
+ if ( bCanBeConsideredAMethod && nParamCount )
+ {
+ // Automation properties have methods, so... we need to invoke this through
+ // XInvocation
+ Sequence<Any> args;
+ processAutomationParams( pParams, args, nParamCount );
+ aRetAny = invokeAutomationMethod( pProp->GetName(), args, pParams, nParamCount, mxInvocation, INVOKETYPE::GetProp );
+ }
+ else
+ aRetAny = mxInvocation->getValue( pProp->GetName() );
+ // take over the value from Uno to Sbx
+ unoToSbxValue( pVar, aRetAny );
+ if( pParams && bCanBeConsideredAMethod )
+ pVar->SetParameters( nullptr );
+
+ }
+ catch( const Exception& )
+ {
+ implHandleAnyException( ::cppu::getCaughtException() );
+ }
+ }
+ }
+ else if( pHint->GetId() == SfxHintId::BasicDataChanged )
+ {
+ if( !bInvocation && mxUnoAccess.is() )
+ {
+ if( pProp->aUnoProp.Attributes & PropertyAttribute::READONLY )
+ {
+ StarBASIC::Error( ERRCODE_BASIC_PROP_READONLY );
+ return;
+ }
+ if ( maStructInfo )
+ {
+ StructRefInfo aMember = maStructInfo->getStructMember( pProp->GetName() );
+ if ( aMember.isEmpty() )
+ {
+ StarBASIC::Error( ERRCODE_BASIC_PROPERTY_NOT_FOUND );
+ }
+ else
+ {
+ Any aAnyValue = sbxToUnoValue( pVar, pProp->aUnoProp.Type, &pProp->aUnoProp );
+ aMember.setValue( aAnyValue );
+ }
+ return;
+ }
+ // take over the value from Uno to Sbx
+ Any aAnyValue = sbxToUnoValue( pVar, pProp->aUnoProp.Type, &pProp->aUnoProp );
+ try
+ {
+ // set the value
+ Reference< XPropertySet > xPropSet( mxUnoAccess->queryAdapter( cppu::UnoType<XPropertySet>::get()), UNO_QUERY );
+ xPropSet->setPropertyValue( pProp->GetName(), aAnyValue );
+ // The use of getPropertyValue (instead of using the index) is
+ // suboptimal, but the refactoring to XInvocation is already pending
+ // Otherwise it is possible to use FastPropertySet
+ }
+ catch( const Exception& )
+ {
+ implHandleAnyException( ::cppu::getCaughtException() );
+ }
+ }
+ else if( bInvocation && mxInvocation.is() )
+ {
+ // take over the value from Uno to Sbx
+ Any aAnyValue = sbxToUnoValueImpl( pVar );
+ try
+ {
+ // set the value
+ mxInvocation->setValue( pProp->GetName(), aAnyValue );
+ }
+ catch( const Exception& )
+ {
+ implHandleAnyException( ::cppu::getCaughtException() );
+ }
+ }
+ }
+ }
+ else if( pMeth )
+ {
+ bool bInvocation = pMeth->isInvocationBased();
+ if( pHint->GetId() == SfxHintId::BasicDataWanted )
+ {
+ // number of Parameter -1 because of Param0 == this
+ sal_uInt32 nParamCount = pParams ? (pParams->Count() - 1) : 0;
+ Sequence<Any> args;
+ bool bOutParams = false;
+
+ if( !bInvocation && mxUnoAccess.is() )
+ {
+ // get info
+ const Sequence<ParamInfo>& rInfoSeq = pMeth->getParamInfos();
+ const ParamInfo* pParamInfos = rInfoSeq.getConstArray();
+ sal_uInt32 nUnoParamCount = rInfoSeq.getLength();
+ sal_uInt32 nAllocParamCount = nParamCount;
+
+ // ignore surplus parameter; alternative: throw an error
+ if( nParamCount > nUnoParamCount )
+ {
+ nParamCount = nUnoParamCount;
+ nAllocParamCount = nParamCount;
+ }
+ else if( nParamCount < nUnoParamCount )
+ {
+ SbiInstance* pInst = GetSbData()->pInst;
+ if( pInst && pInst->IsCompatibility() )
+ {
+ // Check types
+ bool bError = false;
+ for( sal_uInt32 i = nParamCount ; i < nUnoParamCount ; i++ )
+ {
+ const ParamInfo& rInfo = pParamInfos[i];
+ const Reference< XIdlClass >& rxClass = rInfo.aType;
+ if( rxClass->getTypeClass() != TypeClass_ANY )
+ {
+ bError = true;
+ StarBASIC::Error( ERRCODE_BASIC_NOT_OPTIONAL );
+ }
+ }
+ if( !bError )
+ nAllocParamCount = nUnoParamCount;
+ }
+ }
+
+ if( nAllocParamCount > 0 )
+ {
+ args.realloc( nAllocParamCount );
+ Any* pAnyArgs = args.getArray();
+ for( sal_uInt32 i = 0 ; i < nParamCount ; i++ )
+ {
+ const ParamInfo& rInfo = pParamInfos[i];
+ const Reference< XIdlClass >& rxClass = rInfo.aType;
+
+ css::uno::Type aType( rxClass->getTypeClass(), rxClass->getName() );
+
+ // ATTENTION: Don't forget for Sbx-Parameter the offset!
+ pAnyArgs[i] = sbxToUnoValue(pParams->Get(i + 1), aType);
+
+ // If it is not certain check whether the out-parameter are available.
+ if( !bOutParams )
+ {
+ ParamMode aParamMode = rInfo.aMode;
+ if( aParamMode != ParamMode_IN )
+ bOutParams = true;
+ }
+ }
+ }
+ }
+ else if( bInvocation && pParams && mxInvocation.is() )
+ {
+ processAutomationParams( pParams, args, nParamCount );
+ }
+
+ // call the method
+ GetSbData()->bBlockCompilerError = true; // #106433 Block compiler errors for API calls
+ try
+ {
+ if( !bInvocation && mxUnoAccess.is() )
+ {
+ Any aRetAny = pMeth->m_xUnoMethod->invoke( getUnoAny(), args );
+
+ // take over the value from Uno to Sbx
+ unoToSbxValue( pVar, aRetAny );
+
+ // Did we to copy back the Out-Parameter?
+ if( bOutParams )
+ {
+ const Any* pAnyArgs = args.getConstArray();
+
+ // get info
+ const Sequence<ParamInfo>& rInfoSeq = pMeth->getParamInfos();
+ const ParamInfo* pParamInfos = rInfoSeq.getConstArray();
+
+ sal_uInt32 j;
+ for( j = 0 ; j < nParamCount ; j++ )
+ {
+ const ParamInfo& rInfo = pParamInfos[j];
+ ParamMode aParamMode = rInfo.aMode;
+ if( aParamMode != ParamMode_IN )
+ unoToSbxValue(pParams->Get(j + 1), pAnyArgs[j]);
+ }
+ }
+ }
+ else if( bInvocation && mxInvocation.is() )
+ {
+ Any aRetAny = invokeAutomationMethod( pMeth->GetName(), args, pParams, nParamCount, mxInvocation, INVOKETYPE::Func );
+ unoToSbxValue( pVar, aRetAny );
+ }
+
+ // remove parameter here, because this was not done anymore in unoToSbxValue()
+ // for arrays
+ if( pParams )
+ pVar->SetParameters( nullptr );
+ }
+ catch( const Exception& )
+ {
+ implHandleAnyException( ::cppu::getCaughtException() );
+ }
+ GetSbData()->bBlockCompilerError = false; // #106433 Unblock compiler errors
+ }
+ }
+ else
+ SbxObject::Notify( rBC, rHint );
+}
+
+
+SbUnoObject::SbUnoObject( const OUString& aName_, const Any& aUnoObj_ )
+ : SbxObject( aName_ )
+ , bNeedIntrospection( true )
+ , bNativeCOMObject( false )
+{
+ // beat out again the default properties of Sbx
+ Remove( "Name", SbxClassType::DontCare );
+ Remove( "Parent", SbxClassType::DontCare );
+
+ // check the type of the objects
+ TypeClass eType = aUnoObj_.getValueType().getTypeClass();
+ Reference< XInterface > x;
+ if( eType == TypeClass_INTERFACE )
+ {
+ // get the interface from the Any
+ aUnoObj_ >>= x;
+ if( !x.is() )
+ return;
+ }
+
+ // Did the object have an invocation itself?
+ mxInvocation.set( x, UNO_QUERY );
+
+ if( mxInvocation.is() )
+ {
+
+ // get the ExactName
+ mxExactNameInvocation.set( mxInvocation, UNO_QUERY );
+
+ // The remainder refers only to the introspection
+ Reference< XTypeProvider > xTypeProvider( x, UNO_QUERY );
+ if( !xTypeProvider.is() )
+ {
+ bNeedIntrospection = false;
+ return;
+ }
+
+ // Ignore introspection based members for COM objects to avoid
+ // hiding of equally named COM symbols, e.g. XInvocation::getValue
+ Reference< oleautomation::XAutomationObject > xAutomationObject( aUnoObj_, UNO_QUERY );
+ if( xAutomationObject.is() )
+ bNativeCOMObject = true;
+ }
+
+ maTmpUnoObj = aUnoObj_;
+
+
+ //*** Define the name ***
+ bool bFatalError = true;
+
+ // Is it an interface or a struct?
+ bool bSetClassName = false;
+ OUString aClassName_;
+ if( eType == TypeClass_STRUCT || eType == TypeClass_EXCEPTION )
+ {
+ // Struct is Ok
+ bFatalError = false;
+
+ // insert the real name of the class
+ if( aName_.isEmpty() )
+ {
+ aClassName_ = aUnoObj_.getValueType().getTypeName();
+ bSetClassName = true;
+ }
+ StructRefInfo aThisStruct( maTmpUnoObj, maTmpUnoObj.getValueType(), 0 );
+ maStructInfo = std::make_shared<SbUnoStructRefObject>( GetName(), aThisStruct );
+ }
+ else if( eType == TypeClass_INTERFACE )
+ {
+ // Interface works always through the type in the Any
+ bFatalError = false;
+ }
+ if( bSetClassName )
+ SetClassName( aClassName_ );
+
+ // Neither interface nor Struct -> FatalError
+ if( bFatalError )
+ {
+ StarBASIC::FatalError( ERRCODE_BASIC_EXCEPTION );
+ return;
+ }
+
+ // pass the introspection primal on demand
+}
+
+SbUnoObject::~SbUnoObject()
+{
+}
+
+
+// pass the introspection on Demand
+void SbUnoObject::doIntrospection()
+{
+ if( !bNeedIntrospection )
+ return;
+
+ Reference<XComponentContext> xContext = comphelper::getProcessComponentContext();
+
+ if (!xContext.is())
+ return;
+
+
+ // get the introspection service
+ Reference<XIntrospection> xIntrospection;
+
+ try
+ {
+ xIntrospection = theIntrospection::get(xContext);
+ }
+ catch ( const css::uno::DeploymentException& )
+ {
+ }
+
+ if (!xIntrospection.is())
+ return;
+
+ bNeedIntrospection = false;
+
+ // pass the introspection
+ try
+ {
+ mxUnoAccess = xIntrospection->inspect( maTmpUnoObj );
+ }
+ catch( const RuntimeException& e )
+ {
+ StarBASIC::Error( ERRCODE_BASIC_EXCEPTION, implGetExceptionMsg( e ) );
+ }
+
+ if( !mxUnoAccess.is() )
+ {
+ // #51475 mark to indicate an invalid object (no mxMaterialHolder)
+ return;
+ }
+
+ // get MaterialHolder from access
+ mxMaterialHolder.set( mxUnoAccess, UNO_QUERY );
+
+ // get ExactName from access
+ mxExactName.set( mxUnoAccess, UNO_QUERY );
+}
+
+
+// Start of a list of all SbUnoMethod-Instances
+static SbUnoMethod* pFirst = nullptr;
+
+void clearUnoMethodsForBasic( StarBASIC const * pBasic )
+{
+ SbUnoMethod* pMeth = pFirst;
+ while( pMeth )
+ {
+ SbxObject* pObject = pMeth->GetParent();
+ if ( pObject )
+ {
+ StarBASIC* pModBasic = dynamic_cast< StarBASIC* >( pObject->GetParent() );
+ if ( pModBasic == pBasic )
+ {
+ // for now the solution is to remove the method from the list and to clear it,
+ // but in case the element should be correctly transferred to another StarBASIC,
+ // we should either set module parent to NULL without clearing it, or even
+ // set the new StarBASIC as the parent of the module
+ // pObject->SetParent( NULL );
+
+ if( pMeth == pFirst )
+ pFirst = pMeth->pNext;
+ else if( pMeth->pPrev )
+ pMeth->pPrev->pNext = pMeth->pNext;
+ if( pMeth->pNext )
+ pMeth->pNext->pPrev = pMeth->pPrev;
+
+ pMeth->pPrev = nullptr;
+ pMeth->pNext = nullptr;
+
+ pMeth->SbxValue::Clear();
+ pObject->SbxValue::Clear();
+
+ // start from the beginning after object clearing, the cycle will end since the method is removed each time
+ pMeth = pFirst;
+ }
+ else
+ pMeth = pMeth->pNext;
+ }
+ else
+ pMeth = pMeth->pNext;
+ }
+}
+
+void clearUnoMethods()
+{
+ SbUnoMethod* pMeth = pFirst;
+ while( pMeth )
+ {
+ pMeth->SbxValue::Clear();
+ pMeth = pMeth->pNext;
+ }
+}
+
+
+SbUnoMethod::SbUnoMethod
+(
+ const OUString& aName_,
+ SbxDataType eSbxType,
+ Reference< XIdlMethod > const & xUnoMethod_,
+ bool bInvocation
+)
+ : SbxMethod( aName_, eSbxType )
+ , mbInvocation( bInvocation )
+{
+ m_xUnoMethod = xUnoMethod_;
+ pParamInfoSeq = nullptr;
+
+ // enregister the method in a list
+ pNext = pFirst;
+ pPrev = nullptr;
+ pFirst = this;
+ if( pNext )
+ pNext->pPrev = this;
+}
+
+SbUnoMethod::~SbUnoMethod()
+{
+ pParamInfoSeq.reset();
+
+ if( this == pFirst )
+ pFirst = pNext;
+ else if( pPrev )
+ pPrev->pNext = pNext;
+ if( pNext )
+ pNext->pPrev = pPrev;
+}
+
+SbxInfo* SbUnoMethod::GetInfo()
+{
+ if( !pInfo.is() && m_xUnoMethod.is() )
+ {
+ SbiInstance* pInst = GetSbData()->pInst;
+ if( pInst && pInst->IsCompatibility() )
+ {
+ pInfo = new SbxInfo();
+
+ const Sequence<ParamInfo>& rInfoSeq = getParamInfos();
+ const ParamInfo* pParamInfos = rInfoSeq.getConstArray();
+ sal_uInt32 nParamCount = rInfoSeq.getLength();
+
+ for( sal_uInt32 i = 0 ; i < nParamCount ; i++ )
+ {
+ const ParamInfo& rInfo = pParamInfos[i];
+ OUString aParamName = rInfo.aName;
+
+ pInfo->AddParam( aParamName, SbxVARIANT, SbxFlagBits::Read );
+ }
+ }
+ }
+ return pInfo.get();
+}
+
+const Sequence<ParamInfo>& SbUnoMethod::getParamInfos()
+{
+ if (!pParamInfoSeq)
+ {
+ Sequence<ParamInfo> aTmp;
+ if (m_xUnoMethod.is())
+ aTmp = m_xUnoMethod->getParameterInfos();
+ pParamInfoSeq.reset( new Sequence<ParamInfo>(aTmp) );
+ }
+ return *pParamInfoSeq;
+}
+
+SbUnoProperty::SbUnoProperty
+(
+ const OUString& aName_,
+ SbxDataType eSbxType,
+ SbxDataType eRealSbxType,
+ Property aUnoProp_,
+ sal_Int32 nId_,
+ bool bInvocation,
+ bool bUnoStruct
+)
+ : SbxProperty( aName_, eSbxType )
+ , aUnoProp(std::move( aUnoProp_ ))
+ , nId( nId_ )
+ , mbInvocation( bInvocation )
+ , mRealType( eRealSbxType )
+ , mbUnoStruct( bUnoStruct )
+{
+ // as needed establish a dummy array so that SbiRuntime::CheckArray() works
+ static SbxArrayRef xDummyArray = new SbxArray( SbxVARIANT );
+ if( eSbxType & SbxARRAY )
+ PutObject( xDummyArray.get() );
+}
+
+SbUnoProperty::~SbUnoProperty()
+{}
+
+
+SbxVariable* SbUnoObject::Find( const OUString& rName, SbxClassType t )
+{
+ static Reference< XIdlMethod > xDummyMethod;
+ static Property aDummyProp;
+
+ SbxVariable* pRes = SbxObject::Find( rName, t );
+
+ if( bNeedIntrospection )
+ doIntrospection();
+
+ // New 1999-03-04: Create properties on demand. Therefore search now via
+ // IntrospectionAccess if a property or a method of the required name exist
+ if( !pRes )
+ {
+ OUString aUName( rName );
+ if( mxUnoAccess.is() && !bNativeCOMObject )
+ {
+ if( mxExactName.is() )
+ {
+ OUString aUExactName = mxExactName->getExactName( aUName );
+ if( !aUExactName.isEmpty() )
+ {
+ aUName = aUExactName;
+ }
+ }
+ if( mxUnoAccess->hasProperty( aUName, PropertyConcept::ALL - PropertyConcept::DANGEROUS ) )
+ {
+ const Property& rProp = mxUnoAccess->
+ getProperty( aUName, PropertyConcept::ALL - PropertyConcept::DANGEROUS );
+
+ // If the property could be void the type had to be set to Variant
+ SbxDataType eSbxType;
+ if( rProp.Attributes & PropertyAttribute::MAYBEVOID )
+ eSbxType = SbxVARIANT;
+ else
+ eSbxType = unoToSbxType( rProp.Type.getTypeClass() );
+
+ SbxDataType eRealSbxType = ( ( rProp.Attributes & PropertyAttribute::MAYBEVOID ) ? unoToSbxType( rProp.Type.getTypeClass() ) : eSbxType );
+ // create the property and superimpose it
+ auto pProp = tools::make_ref<SbUnoProperty>( rProp.Name, eSbxType, eRealSbxType, rProp, 0, false, ( rProp.Type.getTypeClass() == css::uno::TypeClass_STRUCT ) );
+ QuickInsert( pProp.get() );
+ pRes = pProp.get();
+ }
+ else if( mxUnoAccess->hasMethod( aUName,
+ MethodConcept::ALL - MethodConcept::DANGEROUS ) )
+ {
+ // address the method
+ const Reference< XIdlMethod >& rxMethod = mxUnoAccess->
+ getMethod( aUName, MethodConcept::ALL - MethodConcept::DANGEROUS );
+
+ // create SbUnoMethod and superimpose it
+ auto xMethRef = tools::make_ref<SbUnoMethod>( rxMethod->getName(),
+ unoToSbxType( rxMethod->getReturnType() ), rxMethod, false );
+ QuickInsert( xMethRef.get() );
+ pRes = xMethRef.get();
+ }
+
+ // If nothing was found check via XNameAccess
+ if( !pRes )
+ {
+ try
+ {
+ Reference< XNameAccess > xNameAccess( mxUnoAccess->queryAdapter( cppu::UnoType<XPropertySet>::get()), UNO_QUERY );
+
+ if( xNameAccess.is() && xNameAccess->hasByName( rName ) )
+ {
+ Any aAny = xNameAccess->getByName( rName );
+
+ // ATTENTION: Because of XNameAccess, the variable generated here
+ // may not be included as a fixed property in the object and therefore
+ // won't be stored anywhere.
+ // If this leads to problems, it has to be created
+ // synthetically or a class SbUnoNameAccessProperty,
+ // which checks the existence on access and which
+ // is disposed if the name is not found anymore.
+ pRes = new SbxVariable( SbxVARIANT );
+ unoToSbxValue( pRes, aAny );
+ }
+ }
+ catch( const NoSuchElementException& e )
+ {
+ StarBASIC::Error( ERRCODE_BASIC_EXCEPTION, implGetExceptionMsg( e ) );
+ }
+ catch( const Exception& )
+ {
+ // Establish so that the exception error will not be overwritten
+ if( !pRes )
+ pRes = new SbxVariable( SbxVARIANT );
+
+ implHandleAnyException( ::cppu::getCaughtException() );
+ }
+ }
+ }
+ if( !pRes && mxInvocation.is() )
+ {
+ if( mxExactNameInvocation.is() )
+ {
+ OUString aUExactName = mxExactNameInvocation->getExactName( aUName );
+ if( !aUExactName.isEmpty() )
+ {
+ aUName = aUExactName;
+ }
+ }
+
+ try
+ {
+ if( mxInvocation->hasProperty( aUName ) )
+ {
+ // create a property and superimpose it
+ auto xVarRef = tools::make_ref<SbUnoProperty>( aUName, SbxVARIANT, SbxVARIANT, aDummyProp, 0, true, false );
+ QuickInsert( xVarRef.get() );
+ pRes = xVarRef.get();
+ }
+ else if( mxInvocation->hasMethod( aUName ) )
+ {
+ // create SbUnoMethode and superimpose it
+ auto xMethRef = tools::make_ref<SbUnoMethod>( aUName, SbxVARIANT, xDummyMethod, true );
+ QuickInsert( xMethRef.get() );
+ pRes = xMethRef.get();
+ }
+ else
+ {
+ Reference< XDirectInvocation > xDirectInvoke( mxInvocation, UNO_QUERY );
+ if ( xDirectInvoke.is() && xDirectInvoke->hasMember( aUName ) )
+ {
+ auto xMethRef = tools::make_ref<SbUnoMethod>( aUName, SbxVARIANT, xDummyMethod, true );
+ QuickInsert( xMethRef.get() );
+ pRes = xMethRef.get();
+ }
+
+ }
+ }
+ catch( const RuntimeException& e )
+ {
+ // Establish so that the exception error will not be overwritten
+ if( !pRes )
+ pRes = new SbxVariable( SbxVARIANT );
+
+ StarBASIC::Error( ERRCODE_BASIC_EXCEPTION, implGetExceptionMsg( e ) );
+ }
+ }
+ }
+
+ // At the very end checking if the Dbg_-Properties are meant
+
+ if( !pRes )
+ {
+ if( rName.equalsIgnoreAsciiCase(ID_DBG_SUPPORTEDINTERFACES) ||
+ rName.equalsIgnoreAsciiCase(ID_DBG_PROPERTIES) ||
+ rName.equalsIgnoreAsciiCase(ID_DBG_METHODS) )
+ {
+ // Create
+ implCreateDbgProperties();
+
+ // Now they have to be found regular
+ pRes = SbxObject::Find( rName, SbxClassType::DontCare );
+ }
+ }
+ return pRes;
+}
+
+
+// help method to create the dbg_-Properties
+void SbUnoObject::implCreateDbgProperties()
+{
+ Property aProp;
+
+ // Id == -1: display the implemented interfaces corresponding the ClassProvider
+ auto xVarRef = tools::make_ref<SbUnoProperty>( OUString(ID_DBG_SUPPORTEDINTERFACES), SbxSTRING, SbxSTRING, aProp, -1, false, false );
+ QuickInsert( xVarRef.get() );
+
+ // Id == -2: output the properties
+ xVarRef = tools::make_ref<SbUnoProperty>( OUString(ID_DBG_PROPERTIES), SbxSTRING, SbxSTRING, aProp, -2, false, false );
+ QuickInsert( xVarRef.get() );
+
+ // Id == -3: output the Methods
+ xVarRef = tools::make_ref<SbUnoProperty>( OUString(ID_DBG_METHODS), SbxSTRING, SbxSTRING, aProp, -3, false, false );
+ QuickInsert( xVarRef.get() );
+}
+
+void SbUnoObject::implCreateAll()
+{
+ // throw away all existing methods and properties
+ pMethods = tools::make_ref<SbxArray>();
+ pProps = tools::make_ref<SbxArray>();
+
+ if( bNeedIntrospection ) doIntrospection();
+
+ // get introspection
+ Reference< XIntrospectionAccess > xAccess = mxUnoAccess;
+ if( !xAccess.is() || bNativeCOMObject )
+ {
+ if( mxInvocation.is() )
+ xAccess = mxInvocation->getIntrospection();
+ else if( bNativeCOMObject )
+ return;
+ }
+ if( !xAccess.is() )
+ return;
+
+ // Establish properties
+ Sequence<Property> props = xAccess->getProperties( PropertyConcept::ALL - PropertyConcept::DANGEROUS );
+ sal_uInt32 nPropCount = props.getLength();
+ const Property* pProps_ = props.getConstArray();
+
+ sal_uInt32 i;
+ for( i = 0 ; i < nPropCount ; i++ )
+ {
+ const Property& rProp = pProps_[ i ];
+
+ // If the property could be void the type had to be set to Variant
+ SbxDataType eSbxType;
+ if( rProp.Attributes & PropertyAttribute::MAYBEVOID )
+ eSbxType = SbxVARIANT;
+ else
+ eSbxType = unoToSbxType( rProp.Type.getTypeClass() );
+
+ SbxDataType eRealSbxType = ( ( rProp.Attributes & PropertyAttribute::MAYBEVOID ) ? unoToSbxType( rProp.Type.getTypeClass() ) : eSbxType );
+ // Create property and superimpose it
+ auto xVarRef = tools::make_ref<SbUnoProperty>( rProp.Name, eSbxType, eRealSbxType, rProp, i, false, ( rProp.Type.getTypeClass() == css::uno::TypeClass_STRUCT ) );
+ QuickInsert( xVarRef.get() );
+ }
+
+ // Create Dbg_-Properties
+ implCreateDbgProperties();
+
+ // Create methods
+ Sequence< Reference< XIdlMethod > > aMethodSeq = xAccess->getMethods
+ ( MethodConcept::ALL - MethodConcept::DANGEROUS );
+ sal_uInt32 nMethCount = aMethodSeq.getLength();
+ const Reference< XIdlMethod >* pMethods_ = aMethodSeq.getConstArray();
+ for( i = 0 ; i < nMethCount ; i++ )
+ {
+ // address method
+ const Reference< XIdlMethod >& rxMethod = pMethods_[i];
+
+ // Create SbUnoMethod and superimpose it
+ auto xMethRef = tools::make_ref<SbUnoMethod>
+ ( rxMethod->getName(), unoToSbxType( rxMethod->getReturnType() ), rxMethod, false );
+ QuickInsert( xMethRef.get() );
+ }
+}
+
+
+// output the value
+Any SbUnoObject::getUnoAny()
+{
+ Any aRetAny;
+ if( bNeedIntrospection ) doIntrospection();
+ if ( maStructInfo )
+ aRetAny = maTmpUnoObj;
+ else if( mxMaterialHolder.is() )
+ aRetAny = mxMaterialHolder->getMaterial();
+ else if( mxInvocation.is() )
+ aRetAny <<= mxInvocation;
+ return aRetAny;
+}
+
+// help method to create a Uno-Struct per CoreReflection
+static SbUnoObjectRef Impl_CreateUnoStruct( const OUString& aClassName )
+{
+ // get CoreReflection
+ Reference< XIdlReflection > xCoreReflection = getCoreReflection_Impl();
+ if( !xCoreReflection.is() )
+ return nullptr;
+
+ // search for the class
+ Reference< XIdlClass > xClass;
+ const Reference< XHierarchicalNameAccess >& xHarryName =
+ getCoreReflection_HierarchicalNameAccess_Impl();
+ if( xHarryName.is() && xHarryName->hasByHierarchicalName( aClassName ) )
+ xClass = xCoreReflection->forName( aClassName );
+ if( !xClass.is() )
+ return nullptr;
+
+ // Is it really a struct?
+ TypeClass eType = xClass->getTypeClass();
+ if ( ( eType != TypeClass_STRUCT ) && ( eType != TypeClass_EXCEPTION ) )
+ return nullptr;
+
+ // create an instance
+ Any aNewAny;
+ xClass->createObject( aNewAny );
+ // make a SbUnoObject out of it
+ SbUnoObjectRef pUnoObj = new SbUnoObject( aClassName, aNewAny );
+ return pUnoObj;
+}
+
+
+// Factory-Class to create Uno-Structs per DIM AS NEW
+SbxBaseRef SbUnoFactory::Create( sal_uInt16, sal_uInt32 )
+{
+ // Via SbxId nothing works in Uno
+ return nullptr;
+}
+
+SbxObjectRef SbUnoFactory::CreateObject( const OUString& rClassName )
+{
+ return Impl_CreateUnoStruct( rClassName ).get();
+}
+
+
+// Provisional interface for the UNO-Connection
+// Deliver a SbxObject, that wrap a Uno-Interface
+SbxObjectRef GetSbUnoObject( const OUString& aName, const Any& aUnoObj_ )
+{
+ return new SbUnoObject( aName, aUnoObj_ );
+}
+
+// Force creation of all properties for debugging
+void createAllObjectProperties( SbxObject* pObj )
+{
+ if( !pObj )
+ return;
+
+ SbUnoObject* pUnoObj = dynamic_cast<SbUnoObject*>( pObj );
+ SbUnoStructRefObject* pUnoStructObj = dynamic_cast<SbUnoStructRefObject*>( pObj );
+ if( pUnoObj )
+ {
+ pUnoObj->createAllProperties();
+ }
+ else if ( pUnoStructObj )
+ {
+ pUnoStructObj->createAllProperties();
+ }
+}
+
+
+void RTL_Impl_CreateUnoStruct( SbxArray& rPar )
+{
+ // We need 1 parameter minimum
+ if (rPar.Count() < 2)
+ {
+ StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
+ return;
+ }
+
+ // get the name of the class of the struct
+ OUString aClassName = rPar.Get(1)->GetOUString();
+
+ // try to create Struct with the same name
+ SbUnoObjectRef xUnoObj = Impl_CreateUnoStruct( aClassName );
+ if( !xUnoObj.is() )
+ {
+ return;
+ }
+ // return the object
+ SbxVariableRef refVar = rPar.Get(0);
+ refVar->PutObject( xUnoObj.get() );
+}
+
+void RTL_Impl_CreateUnoService( SbxArray& rPar )
+{
+ // We need 1 Parameter minimum
+ if (rPar.Count() < 2)
+ {
+ StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
+ return;
+ }
+
+ // get the name of the class of the struct
+ OUString aServiceName = rPar.Get(1)->GetOUString();
+
+ // search for the service and instantiate it
+ Reference< XMultiServiceFactory > xFactory( comphelper::getProcessServiceFactory() );
+ Reference< XInterface > xInterface;
+ try
+ {
+ xInterface = xFactory->createInstance( aServiceName );
+ }
+ catch( const Exception& )
+ {
+ implHandleAnyException( ::cppu::getCaughtException() );
+ }
+
+ SbxVariableRef refVar = rPar.Get(0);
+ if( xInterface.is() )
+ {
+ // Create a SbUnoObject out of it and return it
+ SbUnoObjectRef xUnoObj = new SbUnoObject( aServiceName, Any(xInterface) );
+ if( xUnoObj->getUnoAny().hasValue() )
+ {
+ // return the object
+ refVar->PutObject( xUnoObj.get() );
+ }
+ else
+ {
+ refVar->PutObject( nullptr );
+ }
+ }
+ else
+ {
+ refVar->PutObject( nullptr );
+ }
+}
+
+void RTL_Impl_CreateUnoServiceWithArguments( SbxArray& rPar )
+{
+ // We need 2 parameter minimum
+ if (rPar.Count() < 3)
+ {
+ StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
+ return;
+ }
+
+ // get the name of the class of the struct
+ OUString aServiceName = rPar.Get(1)->GetOUString();
+ Any aArgAsAny = sbxToUnoValue(rPar.Get(2),
+ cppu::UnoType<Sequence<Any>>::get() );
+ Sequence< Any > aArgs;
+ aArgAsAny >>= aArgs;
+
+ // search for the service and instantiate it
+ Reference< XMultiServiceFactory > xFactory( comphelper::getProcessServiceFactory() );
+ Reference< XInterface > xInterface;
+ try
+ {
+ xInterface = xFactory->createInstanceWithArguments( aServiceName, aArgs );
+ }
+ catch( const Exception& )
+ {
+ implHandleAnyException( ::cppu::getCaughtException() );
+ }
+
+ SbxVariableRef refVar = rPar.Get(0);
+ if( xInterface.is() )
+ {
+ // Create a SbUnoObject out of it and return it
+ SbUnoObjectRef xUnoObj = new SbUnoObject( aServiceName, Any(xInterface) );
+ if( xUnoObj->getUnoAny().hasValue() )
+ {
+ // return the object
+ refVar->PutObject( xUnoObj.get() );
+ }
+ else
+ {
+ refVar->PutObject( nullptr );
+ }
+ }
+ else
+ {
+ refVar->PutObject( nullptr );
+ }
+}
+
+void RTL_Impl_GetProcessServiceManager( SbxArray& rPar )
+{
+ SbxVariableRef refVar = rPar.Get(0);
+
+ // get the global service manager
+ Reference< XMultiServiceFactory > xFactory( comphelper::getProcessServiceFactory() );
+
+ // Create a SbUnoObject out of it and return it
+ SbUnoObjectRef xUnoObj = new SbUnoObject( "ProcessServiceManager", Any(xFactory) );
+ refVar->PutObject( xUnoObj.get() );
+}
+
+void RTL_Impl_HasInterfaces( SbxArray& rPar )
+{
+ // We need 2 parameter minimum
+ sal_uInt32 nParCount = rPar.Count();
+ if( nParCount < 3 )
+ {
+ StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
+ return;
+ }
+
+ // variable for the return value
+ SbxVariableRef refVar = rPar.Get(0);
+ refVar->PutBool( false );
+
+ // get the Uno-Object
+ SbxBaseRef pObj = rPar.Get(1)->GetObject();
+ auto obj = dynamic_cast<SbUnoObject*>( pObj.get() );
+ if( obj == nullptr )
+ {
+ return;
+ }
+ Any aAny = obj->getUnoAny();
+ auto x = o3tl::tryAccess<Reference<XInterface>>(aAny);
+ if( !x )
+ {
+ return;
+ }
+
+ // get CoreReflection
+ Reference< XIdlReflection > xCoreReflection = getCoreReflection_Impl();
+ if( !xCoreReflection.is() )
+ {
+ return;
+ }
+ for( sal_uInt32 i = 2 ; i < nParCount ; i++ )
+ {
+ // get the name of the interface of the struct
+ OUString aIfaceName = rPar.Get(i)->GetOUString();
+
+ // search for the class
+ Reference< XIdlClass > xClass = xCoreReflection->forName( aIfaceName );
+ if( !xClass.is() )
+ {
+ return;
+ }
+ // check if the interface will be supported
+ OUString aClassName = xClass->getName();
+ Type aClassType( xClass->getTypeClass(), aClassName );
+ if( !(*x)->queryInterface( aClassType ).hasValue() )
+ {
+ return;
+ }
+ }
+
+ // Everything works; then return TRUE
+ refVar->PutBool( true );
+}
+
+void RTL_Impl_IsUnoStruct( SbxArray& rPar )
+{
+ // We need 1 parameter minimum
+ if (rPar.Count() < 2)
+ {
+ StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
+ return;
+ }
+
+ // variable for the return value
+ SbxVariableRef refVar = rPar.Get(0);
+ refVar->PutBool( false );
+
+ // get the Uno-Object
+ SbxVariableRef xParam = rPar.Get(1);
+ if( !xParam->IsObject() )
+ {
+ return;
+ }
+ SbxBaseRef pObj = xParam->GetObject();
+ auto obj = dynamic_cast<SbUnoObject*>( pObj.get() );
+ if( obj == nullptr )
+ {
+ return;
+ }
+ Any aAny = obj->getUnoAny();
+ TypeClass eType = aAny.getValueType().getTypeClass();
+ if( eType == TypeClass_STRUCT )
+ {
+ refVar->PutBool( true );
+ }
+}
+
+
+void RTL_Impl_EqualUnoObjects( SbxArray& rPar )
+{
+ if (rPar.Count() < 3)
+ {
+ StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
+ return;
+ }
+
+ // variable for the return value
+ SbxVariableRef refVar = rPar.Get(0);
+ refVar->PutBool( false );
+
+ // get the Uno-Objects
+ SbxVariableRef xParam1 = rPar.Get(1);
+ if( !xParam1->IsObject() )
+ {
+ return;
+ }
+ SbxBaseRef pObj1 = xParam1->GetObject();
+ auto obj1 = dynamic_cast<SbUnoObject*>( pObj1.get() );
+ if( obj1 == nullptr )
+ {
+ return;
+ }
+ Any aAny1 = obj1->getUnoAny();
+ TypeClass eType1 = aAny1.getValueType().getTypeClass();
+ if( eType1 != TypeClass_INTERFACE )
+ {
+ return;
+ }
+ Reference< XInterface > x1;
+ aAny1 >>= x1;
+
+ SbxVariableRef xParam2 = rPar.Get(2);
+ if( !xParam2->IsObject() )
+ {
+ return;
+ }
+ SbxBaseRef pObj2 = xParam2->GetObject();
+ auto obj2 = dynamic_cast<SbUnoObject*>( pObj2.get() );
+ if( obj2 == nullptr )
+ {
+ return;
+ }
+ Any aAny2 = obj2->getUnoAny();
+ TypeClass eType2 = aAny2.getValueType().getTypeClass();
+ if( eType2 != TypeClass_INTERFACE )
+ {
+ return;
+ }
+ Reference< XInterface > x2;
+ aAny2 >>= x2;
+
+ if( x1 == x2 )
+ {
+ refVar->PutBool( true );
+ }
+}
+
+
+// helper wrapper function to interact with TypeProvider and
+// XTypeDescriptionEnumerationAccess.
+// if it fails for whatever reason
+// returned Reference<> be null e.g. .is() will be false
+
+static Reference< XTypeDescriptionEnumeration > getTypeDescriptorEnumeration( const OUString& sSearchRoot,
+ const Sequence< TypeClass >& types,
+ TypeDescriptionSearchDepth depth )
+{
+ Reference< XTypeDescriptionEnumeration > xEnum;
+ Reference< XTypeDescriptionEnumerationAccess> xTypeEnumAccess( getTypeProvider_Impl(), UNO_QUERY );
+ if ( xTypeEnumAccess.is() )
+ {
+ try
+ {
+ xEnum = xTypeEnumAccess->createTypeDescriptionEnumeration(
+ sSearchRoot, types, depth );
+ }
+ catch(const NoSuchTypeNameException& /*nstne*/ ) {}
+ catch(const InvalidTypeNameException& /*nstne*/ ) {}
+ }
+ return xEnum;
+}
+
+VBAConstantHelper&
+VBAConstantHelper::instance()
+{
+ static VBAConstantHelper aHelper;
+ return aHelper;
+}
+
+void VBAConstantHelper::init()
+{
+ if ( isInited )
+ return;
+
+ Reference< XTypeDescriptionEnumeration > xEnum = getTypeDescriptorEnumeration( "ooo.vba", {TypeClass_CONSTANTS}, TypeDescriptionSearchDepth_INFINITE );
+
+ if ( !xEnum.is())
+ {
+ return; //NULL;
+ }
+ while ( xEnum->hasMoreElements() )
+ {
+ Reference< XConstantsTypeDescription > xConstants( xEnum->nextElement(), UNO_QUERY );
+ if ( xConstants.is() )
+ {
+ // store constant group name
+ OUString sFullName = xConstants->getName();
+ sal_Int32 indexLastDot = sFullName.lastIndexOf('.');
+ OUString sLeafName( sFullName );
+ if ( indexLastDot > -1 )
+ {
+ sLeafName = sFullName.copy( indexLastDot + 1);
+ }
+ aConstCache.push_back( sLeafName ); // assume constant group names are unique
+ const Sequence< Reference< XConstantTypeDescription > > aConsts = xConstants->getConstants();
+ for (const auto& ctd : aConsts)
+ {
+ // store constant member name
+ sFullName = ctd->getName();
+ indexLastDot = sFullName.lastIndexOf('.');
+ sLeafName = sFullName;
+ if ( indexLastDot > -1 )
+ {
+ sLeafName = sFullName.copy( indexLastDot + 1);
+ }
+ aConstHash[ sLeafName.toAsciiLowerCase() ] = ctd->getConstantValue();
+ }
+ }
+ }
+ isInited = true;
+}
+
+bool
+VBAConstantHelper::isVBAConstantType( std::u16string_view rName )
+{
+ init();
+ bool bConstant = false;
+
+ for (auto const& elem : aConstCache)
+ {
+ if( o3tl::equalsIgnoreAsciiCase(rName, elem) )
+ {
+ bConstant = true;
+ break;
+ }
+ }
+ return bConstant;
+}
+
+SbxVariable*
+VBAConstantHelper::getVBAConstant( const OUString& rName )
+{
+ SbxVariable* pConst = nullptr;
+ init();
+
+ auto it = aConstHash.find( rName.toAsciiLowerCase() );
+
+ if ( it != aConstHash.end() )
+ {
+ pConst = new SbxVariable( SbxVARIANT );
+ pConst->SetName( rName );
+ unoToSbxValue( pConst, it->second );
+ }
+
+ return pConst;
+}
+
+// Function to search for a global identifier in the
+// UnoScope and to wrap it for Sbx
+SbUnoClass* findUnoClass( const OUString& rName )
+{
+ // #105550 Check if module exists
+ SbUnoClass* pUnoClass = nullptr;
+
+ const Reference< XHierarchicalNameAccess >& xTypeAccess = getTypeProvider_Impl();
+ if( xTypeAccess->hasByHierarchicalName( rName ) )
+ {
+ Any aRet = xTypeAccess->getByHierarchicalName( rName );
+ Reference< XTypeDescription > xTypeDesc;
+ aRet >>= xTypeDesc;
+
+ if( xTypeDesc.is() )
+ {
+ TypeClass eTypeClass = xTypeDesc->getTypeClass();
+ if( eTypeClass == TypeClass_MODULE || eTypeClass == TypeClass_CONSTANTS )
+ {
+ pUnoClass = new SbUnoClass( rName );
+ }
+ }
+ }
+ return pUnoClass;
+}
+
+SbxVariable* SbUnoClass::Find( const OUString& rName, SbxClassType )
+{
+ SbxVariable* pRes = SbxObject::Find( rName, SbxClassType::Variable );
+
+ // If nothing were located the submodule isn't known yet
+ if( !pRes )
+ {
+ // If it is already a class, ask for the field
+ if( m_xClass.is() )
+ {
+ // Is it a field(?)
+ Reference< XIdlField > xField = m_xClass->getField( rName );
+ if( xField.is() )
+ {
+ try
+ {
+ Any aAny = xField->get( {} ); //TODO: does this make sense?
+
+ // Convert to Sbx
+ pRes = new SbxVariable( SbxVARIANT );
+ pRes->SetName( rName );
+ unoToSbxValue( pRes, aAny );
+ }
+ catch( const Exception& )
+ {
+ implHandleAnyException( ::cppu::getCaughtException() );
+ }
+ }
+ }
+ else
+ {
+ // expand fully qualified name
+ OUString aNewName = GetName()
+ + "."
+ + rName;
+
+ // get CoreReflection
+ Reference< XIdlReflection > xCoreReflection = getCoreReflection_Impl();
+ if( xCoreReflection.is() )
+ {
+ // Is it a constant?
+ Reference< XHierarchicalNameAccess > xHarryName( xCoreReflection, UNO_QUERY );
+ if( xHarryName.is() )
+ {
+ try
+ {
+ Any aValue = xHarryName->getByHierarchicalName( aNewName );
+ TypeClass eType = aValue.getValueType().getTypeClass();
+
+ // Interface located? Then it is a class
+ if( eType == TypeClass_INTERFACE )
+ {
+ Reference< XIdlClass > xClass( aValue, UNO_QUERY );
+ if( xClass.is() )
+ {
+ pRes = new SbxVariable( SbxVARIANT );
+ SbxObjectRef xWrapper = static_cast<SbxObject*>(new SbUnoClass( aNewName, xClass ));
+ pRes->PutObject( xWrapper.get() );
+ }
+ }
+ else
+ {
+ pRes = new SbxVariable( SbxVARIANT );
+ unoToSbxValue( pRes, aValue );
+ }
+ }
+ catch( const NoSuchElementException& )
+ {
+ }
+ }
+
+ // Otherwise take it again as class
+ if( !pRes )
+ {
+ SbUnoClass* pNewClass = findUnoClass( aNewName );
+ if( pNewClass )
+ {
+ pRes = new SbxVariable( SbxVARIANT );
+ SbxObjectRef xWrapper = static_cast<SbxObject*>(pNewClass);
+ pRes->PutObject( xWrapper.get() );
+ }
+ }
+
+ // A UNO service?
+ if( !pRes )
+ {
+ SbUnoService* pUnoService = findUnoService( aNewName );
+ if( pUnoService )
+ {
+ pRes = new SbxVariable( SbxVARIANT );
+ SbxObjectRef xWrapper = static_cast<SbxObject*>(pUnoService);
+ pRes->PutObject( xWrapper.get() );
+ }
+ }
+
+ // A UNO singleton?
+ if( !pRes )
+ {
+ SbUnoSingleton* pUnoSingleton = findUnoSingleton( aNewName );
+ if( pUnoSingleton )
+ {
+ pRes = new SbxVariable( SbxVARIANT );
+ SbxObjectRef xWrapper = static_cast<SbxObject*>(pUnoSingleton);
+ pRes->PutObject( xWrapper.get() );
+ }
+ }
+ }
+ }
+
+ if( pRes )
+ {
+ pRes->SetName( rName );
+
+ // Insert variable, so that it could be found later
+ QuickInsert( pRes );
+
+ // Take us out as listener at once,
+ // the values are all constant
+ if( pRes->IsBroadcaster() )
+ EndListening( pRes->GetBroadcaster(), true );
+ }
+ }
+ return pRes;
+}
+
+
+SbUnoService* findUnoService( const OUString& rName )
+{
+ SbUnoService* pSbUnoService = nullptr;
+
+ const Reference< XHierarchicalNameAccess >& xTypeAccess = getTypeProvider_Impl();
+ if( xTypeAccess->hasByHierarchicalName( rName ) )
+ {
+ Any aRet = xTypeAccess->getByHierarchicalName( rName );
+ Reference< XTypeDescription > xTypeDesc;
+ aRet >>= xTypeDesc;
+
+ if( xTypeDesc.is() )
+ {
+ TypeClass eTypeClass = xTypeDesc->getTypeClass();
+ if( eTypeClass == TypeClass_SERVICE )
+ {
+ Reference< XServiceTypeDescription2 > xServiceTypeDesc( xTypeDesc, UNO_QUERY );
+ if( xServiceTypeDesc.is() )
+ pSbUnoService = new SbUnoService( rName, xServiceTypeDesc );
+ }
+ }
+ }
+ return pSbUnoService;
+}
+
+SbxVariable* SbUnoService::Find( const OUString& rName, SbxClassType )
+{
+ SbxVariable* pRes = SbxObject::Find( rName, SbxClassType::Method );
+
+ if( !pRes )
+ {
+ // If it is already a class ask for a field
+ if( m_bNeedsInit && m_xServiceTypeDesc.is() )
+ {
+ m_bNeedsInit = false;
+
+ Sequence< Reference< XServiceConstructorDescription > > aSCDSeq = m_xServiceTypeDesc->getConstructors();
+ const Reference< XServiceConstructorDescription >* pCtorSeq = aSCDSeq.getConstArray();
+ int nCtorCount = aSCDSeq.getLength();
+ for( int i = 0 ; i < nCtorCount ; ++i )
+ {
+ Reference< XServiceConstructorDescription > xCtor = pCtorSeq[i];
+
+ OUString aName( xCtor->getName() );
+ if( aName.isEmpty() )
+ {
+ if( xCtor->isDefaultConstructor() )
+ {
+ aName = "create";
+ }
+ }
+
+ if( !aName.isEmpty() )
+ {
+ // Create and insert SbUnoServiceCtor
+ SbxVariableRef xSbCtorRef = new SbUnoServiceCtor( aName, xCtor );
+ QuickInsert( xSbCtorRef.get() );
+ }
+ }
+ pRes = SbxObject::Find( rName, SbxClassType::Method );
+ }
+ }
+
+ return pRes;
+}
+
+void SbUnoService::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
+{
+ const SbxHint* pHint = dynamic_cast<const SbxHint*>(&rHint);
+ if( !pHint )
+ return;
+
+ SbxVariable* pVar = pHint->GetVar();
+ SbxArray* pParams = pVar->GetParameters();
+ SbUnoServiceCtor* pUnoCtor = dynamic_cast<SbUnoServiceCtor*>( pVar );
+ if( pUnoCtor && pHint->GetId() == SfxHintId::BasicDataWanted )
+ {
+ // Parameter count -1 because of Param0 == this
+ sal_uInt32 nParamCount = pParams ? (pParams->Count() - 1) : 0;
+ Sequence<Any> args;
+
+ Reference< XServiceConstructorDescription > xCtor = pUnoCtor->getServiceCtorDesc();
+ Sequence< Reference< XParameter > > aParameterSeq = xCtor->getParameters();
+ const Reference< XParameter >* pParameterSeq = aParameterSeq.getConstArray();
+ sal_uInt32 nUnoParamCount = aParameterSeq.getLength();
+
+ // Default: Ignore not needed parameters
+ bool bParameterError = false;
+
+ // Is the last parameter a rest parameter?
+ bool bRestParameterMode = false;
+ if( nUnoParamCount > 0 )
+ {
+ Reference< XParameter > xLastParam = pParameterSeq[ nUnoParamCount - 1 ];
+ if( xLastParam.is() )
+ {
+ if( xLastParam->isRestParameter() )
+ bRestParameterMode = true;
+ }
+ }
+
+ // Too many parameters with context as first parameter?
+ sal_uInt32 nSbxParameterOffset = 1;
+ sal_uInt32 nParameterOffsetByContext = 0;
+ Reference < XComponentContext > xFirstParamContext;
+ if( nParamCount > nUnoParamCount )
+ {
+ // Check if first parameter is a context and use it
+ // then in createInstanceWithArgumentsAndContext
+ Any aArg0 = sbxToUnoValue(pParams->Get(nSbxParameterOffset));
+ if( (aArg0 >>= xFirstParamContext) && xFirstParamContext.is() )
+ nParameterOffsetByContext = 1;
+ }
+
+ sal_uInt32 nEffectiveParamCount = nParamCount - nParameterOffsetByContext;
+ sal_uInt32 nAllocParamCount = nEffectiveParamCount;
+ if( nEffectiveParamCount > nUnoParamCount )
+ {
+ if( !bRestParameterMode )
+ {
+ nEffectiveParamCount = nUnoParamCount;
+ nAllocParamCount = nUnoParamCount;
+ }
+ }
+ // Not enough parameters?
+ else if( nUnoParamCount > nEffectiveParamCount )
+ {
+ // RestParameterMode only helps if one (the last) parameter is missing
+ int nDiff = nUnoParamCount - nEffectiveParamCount;
+ if( !bRestParameterMode || nDiff > 1 )
+ {
+ bParameterError = true;
+ StarBASIC::Error( ERRCODE_BASIC_NOT_OPTIONAL );
+ }
+ }
+
+ if( !bParameterError )
+ {
+ bool bOutParams = false;
+ if( nAllocParamCount > 0 )
+ {
+ args.realloc( nAllocParamCount );
+ Any* pAnyArgs = args.getArray();
+ for( sal_uInt32 i = 0 ; i < nEffectiveParamCount ; i++ )
+ {
+ sal_uInt32 iSbx = i + nSbxParameterOffset + nParameterOffsetByContext;
+
+ // bRestParameterMode allows nEffectiveParamCount > nUnoParamCount
+ Reference< XParameter > xParam;
+ if( i < nUnoParamCount )
+ {
+ xParam = pParameterSeq[i];
+ if( !xParam.is() )
+ continue;
+
+ Reference< XTypeDescription > xParamTypeDesc = xParam->getType();
+ if( !xParamTypeDesc.is() )
+ continue;
+ css::uno::Type aType( xParamTypeDesc->getTypeClass(), xParamTypeDesc->getName() );
+
+ // sbx parameter needs offset 1
+ pAnyArgs[i] = sbxToUnoValue(pParams->Get(iSbx), aType);
+
+ // Check for out parameter if not already done
+ if( !bOutParams && xParam->isOut() )
+ bOutParams = true;
+ }
+ else
+ {
+ pAnyArgs[i] = sbxToUnoValue(pParams->Get(iSbx));
+ }
+ }
+ }
+
+ // "Call" ctor using createInstanceWithArgumentsAndContext
+ Reference < XComponentContext > xContext(
+ xFirstParamContext.is()
+ ? xFirstParamContext
+ : comphelper::getProcessComponentContext() );
+ Reference< XMultiComponentFactory > xServiceMgr( xContext->getServiceManager() );
+
+ Any aRetAny;
+ OUString aServiceName = GetName();
+ Reference < XInterface > xRet;
+ try
+ {
+ xRet = xServiceMgr->createInstanceWithArgumentsAndContext( aServiceName, args, xContext );
+ }
+ catch( const Exception& )
+ {
+ implHandleAnyException( ::cppu::getCaughtException() );
+ }
+ aRetAny <<= xRet;
+ unoToSbxValue( pVar, aRetAny );
+
+ // Copy back out parameters?
+ if( bOutParams )
+ {
+ const Any* pAnyArgs = args.getConstArray();
+
+ for( sal_uInt32 j = 0 ; j < nUnoParamCount ; j++ )
+ {
+ Reference< XParameter > xParam = pParameterSeq[j];
+ if( !xParam.is() )
+ continue;
+
+ if( xParam->isOut() )
+ unoToSbxValue(pParams->Get(j + 1), pAnyArgs[j]);
+ }
+ }
+ }
+ }
+ else
+ SbxObject::Notify( rBC, rHint );
+}
+
+
+SbUnoServiceCtor::SbUnoServiceCtor( const OUString& aName_, Reference< XServiceConstructorDescription > const & xServiceCtorDesc )
+ : SbxMethod( aName_, SbxOBJECT )
+ , m_xServiceCtorDesc( xServiceCtorDesc )
+{
+}
+
+SbUnoServiceCtor::~SbUnoServiceCtor()
+{
+}
+
+SbxInfo* SbUnoServiceCtor::GetInfo()
+{
+ return nullptr;
+}
+
+
+SbUnoSingleton* findUnoSingleton( const OUString& rName )
+{
+ SbUnoSingleton* pSbUnoSingleton = nullptr;
+
+ const Reference< XHierarchicalNameAccess >& xTypeAccess = getTypeProvider_Impl();
+ if( xTypeAccess->hasByHierarchicalName( rName ) )
+ {
+ Any aRet = xTypeAccess->getByHierarchicalName( rName );
+ Reference< XTypeDescription > xTypeDesc;
+ aRet >>= xTypeDesc;
+
+ if( xTypeDesc.is() )
+ {
+ TypeClass eTypeClass = xTypeDesc->getTypeClass();
+ if( eTypeClass == TypeClass_SINGLETON )
+ {
+ Reference< XSingletonTypeDescription > xSingletonTypeDesc( xTypeDesc, UNO_QUERY );
+ if( xSingletonTypeDesc.is() )
+ pSbUnoSingleton = new SbUnoSingleton( rName );
+ }
+ }
+ }
+ return pSbUnoSingleton;
+}
+
+SbUnoSingleton::SbUnoSingleton( const OUString& aName_ )
+ : SbxObject( aName_ )
+{
+ SbxVariableRef xGetMethodRef = new SbxMethod( "get", SbxOBJECT );
+ QuickInsert( xGetMethodRef.get() );
+}
+
+void SbUnoSingleton::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
+{
+ const SbxHint* pHint = dynamic_cast<const SbxHint*>(&rHint);
+ if( pHint )
+ {
+ SbxVariable* pVar = pHint->GetVar();
+ SbxArray* pParams = pVar->GetParameters();
+ sal_uInt32 nParamCount = pParams ? (pParams->Count() - 1) : 0;
+ sal_uInt32 nAllowedParamCount = 1;
+
+ Reference < XComponentContext > xContextToUse;
+ if( nParamCount > 0 )
+ {
+ // Check if first parameter is a context and use it then
+ Reference < XComponentContext > xFirstParamContext;
+ Any aArg1 = sbxToUnoValue(pParams->Get(1));
+ if( (aArg1 >>= xFirstParamContext) && xFirstParamContext.is() )
+ xContextToUse = xFirstParamContext;
+ }
+
+ if( !xContextToUse.is() )
+ {
+ xContextToUse = comphelper::getProcessComponentContext();
+ --nAllowedParamCount;
+ }
+
+ if( nParamCount > nAllowedParamCount )
+ {
+ StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
+ return;
+ }
+
+ Any aRetAny;
+ if( xContextToUse.is() )
+ {
+ OUString aSingletonName = "/singletons/"
+ + GetName();
+ Reference < XInterface > xRet;
+ xContextToUse->getValueByName( aSingletonName ) >>= xRet;
+ aRetAny <<= xRet;
+ }
+ unoToSbxValue( pVar, aRetAny );
+ }
+ else
+ {
+ SbxObject::Notify( rBC, rHint );
+ }
+}
+
+namespace {
+
+// Implementation of an EventAttacher-drawn AllListener, which
+// solely transmits several events to a general AllListener
+class BasicAllListener_Impl : public WeakImplHelper< XAllListener >
+{
+ void firing_impl(const AllEventObject& Event, Any* pRet);
+
+public:
+ SbxObjectRef xSbxObj;
+ OUString aPrefixName;
+
+ explicit BasicAllListener_Impl( OUString aPrefixName );
+
+ // Methods of XAllListener
+ virtual void SAL_CALL firing(const AllEventObject& Event) override;
+ virtual Any SAL_CALL approveFiring(const AllEventObject& Event) override;
+
+ // Methods of XEventListener
+ virtual void SAL_CALL disposing(const EventObject& Source) override;
+};
+
+}
+
+BasicAllListener_Impl::BasicAllListener_Impl(OUString aPrefixName_)
+ : aPrefixName(std::move( aPrefixName_ ))
+{
+}
+
+void BasicAllListener_Impl::firing_impl( const AllEventObject& Event, Any* pRet )
+{
+ SolarMutexGuard guard;
+
+ if( !xSbxObj.is() )
+ return;
+
+ OUString aMethodName = aPrefixName + Event.MethodName;
+
+ SbxVariable * pP = xSbxObj.get();
+ while( pP->GetParent() )
+ {
+ pP = pP->GetParent();
+ StarBASIC * pLib = dynamic_cast<StarBASIC*>( pP );
+ if( pLib )
+ {
+ // Create in a Basic Array
+ SbxArrayRef xSbxArray = new SbxArray( SbxVARIANT );
+ const Any * pArgs = Event.Arguments.getConstArray();
+ sal_Int32 nCount = Event.Arguments.getLength();
+ for( sal_Int32 i = 0; i < nCount; i++ )
+ {
+ // Convert elements
+ SbxVariableRef xVar = new SbxVariable( SbxVARIANT );
+ unoToSbxValue( xVar.get(), pArgs[i] );
+ xSbxArray->Put(xVar.get(), i + 1);
+ }
+
+ pLib->Call( aMethodName, xSbxArray.get() );
+
+ // get the return value from the Param-Array, if requested
+ if( pRet )
+ {
+ SbxVariable* pVar = xSbxArray->Get(0);
+ if( pVar )
+ {
+ // #95792 Avoid a second call
+ SbxFlagBits nFlags = pVar->GetFlags();
+ pVar->SetFlag( SbxFlagBits::NoBroadcast );
+ *pRet = sbxToUnoValueImpl( pVar );
+ pVar->SetFlags( nFlags );
+ }
+ }
+ break;
+ }
+ }
+}
+
+
+// Methods of Listener
+void BasicAllListener_Impl::firing( const AllEventObject& Event )
+{
+ firing_impl( Event, nullptr );
+}
+
+Any BasicAllListener_Impl::approveFiring( const AllEventObject& Event )
+{
+ Any aRetAny;
+ firing_impl( Event, &aRetAny );
+ return aRetAny;
+}
+
+
+// Methods of XEventListener
+void BasicAllListener_Impl ::disposing(const EventObject& )
+{
+ SolarMutexGuard guard;
+
+ xSbxObj.clear();
+}
+
+
+// class InvocationToAllListenerMapper
+// helper class to map XInvocation to XAllListener (also in project eventattacher!)
+
+namespace {
+
+class InvocationToAllListenerMapper : public WeakImplHelper< XInvocation >
+{
+public:
+ InvocationToAllListenerMapper( const Reference< XIdlClass >& ListenerType,
+ const Reference< XAllListener >& AllListener, Any Helper );
+
+ // XInvocation
+ virtual Reference< XIntrospectionAccess > SAL_CALL getIntrospection() override;
+ virtual Any SAL_CALL invoke(const OUString& FunctionName, const Sequence< Any >& Params, Sequence< sal_Int16 >& OutParamIndex, Sequence< Any >& OutParam) override;
+ virtual void SAL_CALL setValue(const OUString& PropertyName, const Any& Value) override;
+ virtual Any SAL_CALL getValue(const OUString& PropertyName) override;
+ virtual sal_Bool SAL_CALL hasMethod(const OUString& Name) override;
+ virtual sal_Bool SAL_CALL hasProperty(const OUString& Name) override;
+
+private:
+ Reference< XAllListener > m_xAllListener;
+ Reference< XIdlClass > m_xListenerType;
+ Any m_Helper;
+};
+
+}
+
+// Function to replace AllListenerAdapterService::createAllListerAdapter
+static Reference< XInterface > createAllListenerAdapter
+(
+ const Reference< XInvocationAdapterFactory2 >& xInvocationAdapterFactory,
+ const Reference< XIdlClass >& xListenerType,
+ const Reference< XAllListener >& xListener,
+ const Any& Helper
+)
+{
+ Reference< XInterface > xAdapter;
+ if( xInvocationAdapterFactory.is() && xListenerType.is() && xListener.is() )
+ {
+ Reference< XInvocation > xInvocationToAllListenerMapper =
+ new InvocationToAllListenerMapper(xListenerType, xListener, Helper);
+ Type aListenerType( xListenerType->getTypeClass(), xListenerType->getName() );
+ xAdapter = xInvocationAdapterFactory->createAdapter( xInvocationToAllListenerMapper, {aListenerType} );
+ }
+ return xAdapter;
+}
+
+
+// InvocationToAllListenerMapper
+InvocationToAllListenerMapper::InvocationToAllListenerMapper
+ ( const Reference< XIdlClass >& ListenerType, const Reference< XAllListener >& AllListener, Any Helper )
+ : m_xAllListener( AllListener )
+ , m_xListenerType( ListenerType )
+ , m_Helper(std::move( Helper ))
+{
+}
+
+
+Reference< XIntrospectionAccess > SAL_CALL InvocationToAllListenerMapper::getIntrospection()
+{
+ return Reference< XIntrospectionAccess >();
+}
+
+
+Any SAL_CALL InvocationToAllListenerMapper::invoke(const OUString& FunctionName, const Sequence< Any >& Params,
+ Sequence< sal_Int16 >&, Sequence< Any >&)
+{
+ Any aRet;
+
+ // Check if to firing or approveFiring has to be called
+ Reference< XIdlMethod > xMethod = m_xListenerType->getMethod( FunctionName );
+ bool bApproveFiring = false;
+ if( !xMethod.is() )
+ return aRet;
+ Reference< XIdlClass > xReturnType = xMethod->getReturnType();
+ Sequence< Reference< XIdlClass > > aExceptionSeq = xMethod->getExceptionTypes();
+ if( ( xReturnType.is() && xReturnType->getTypeClass() != TypeClass_VOID ) ||
+ aExceptionSeq.hasElements() )
+ {
+ bApproveFiring = true;
+ }
+ else
+ {
+ Sequence< ParamInfo > aParamSeq = xMethod->getParameterInfos();
+ sal_uInt32 nParamCount = aParamSeq.getLength();
+ if( nParamCount > 1 )
+ {
+ const ParamInfo* pInfo = aParamSeq.getConstArray();
+ for( sal_uInt32 i = 0 ; i < nParamCount ; i++ )
+ {
+ if( pInfo[ i ].aMode != ParamMode_IN )
+ {
+ bApproveFiring = true;
+ break;
+ }
+ }
+ }
+ }
+
+ AllEventObject aAllEvent;
+ aAllEvent.Source = static_cast<OWeakObject*>(this);
+ aAllEvent.Helper = m_Helper;
+ aAllEvent.ListenerType = Type(m_xListenerType->getTypeClass(), m_xListenerType->getName() );
+ aAllEvent.MethodName = FunctionName;
+ aAllEvent.Arguments = Params;
+ if( bApproveFiring )
+ aRet = m_xAllListener->approveFiring( aAllEvent );
+ else
+ m_xAllListener->firing( aAllEvent );
+ return aRet;
+}
+
+
+void SAL_CALL InvocationToAllListenerMapper::setValue(const OUString&, const Any&)
+{}
+
+
+Any SAL_CALL InvocationToAllListenerMapper::getValue(const OUString&)
+{
+ return Any();
+}
+
+
+sal_Bool SAL_CALL InvocationToAllListenerMapper::hasMethod(const OUString& Name)
+{
+ Reference< XIdlMethod > xMethod = m_xListenerType->getMethod( Name );
+ return xMethod.is();
+}
+
+
+sal_Bool SAL_CALL InvocationToAllListenerMapper::hasProperty(const OUString& Name)
+{
+ Reference< XIdlField > xField = m_xListenerType->getField( Name );
+ return xField.is();
+}
+
+
+// create Uno-Service
+// 1. Parameter == Prefix-Name of the macro
+// 2. Parameter == fully qualified name of the listener
+void SbRtl_CreateUnoListener(StarBASIC * pBasic, SbxArray & rPar, bool)
+{
+ // We need 2 parameters
+ if (rPar.Count() != 3)
+ {
+ StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
+ return;
+ }
+
+ // get the name of the class of the struct
+ OUString aPrefixName = rPar.Get(1)->GetOUString();
+ OUString aListenerClassName = rPar.Get(2)->GetOUString();
+
+ // get the CoreReflection
+ Reference< XIdlReflection > xCoreReflection = getCoreReflection_Impl();
+ if( !xCoreReflection.is() )
+ return;
+
+ // get the AllListenerAdapterService
+ Reference< XComponentContext > xContext( comphelper::getProcessComponentContext() );
+
+ // search the class
+ Reference< XIdlClass > xClass = xCoreReflection->forName( aListenerClassName );
+ if( !xClass.is() )
+ return;
+
+ // From 1999-11-30: get the InvocationAdapterFactory
+ Reference< XInvocationAdapterFactory2 > xInvocationAdapterFactory =
+ InvocationAdapterFactory::create( xContext );
+
+ rtl::Reference<BasicAllListener_Impl> xAllLst = new BasicAllListener_Impl( aPrefixName );
+ Any aTmp;
+ Reference< XInterface > xLst = createAllListenerAdapter( xInvocationAdapterFactory, xClass, xAllLst, aTmp );
+ if( !xLst.is() )
+ return;
+
+ OUString aClassName = xClass->getName();
+ Type aClassType( xClass->getTypeClass(), aClassName );
+ aTmp = xLst->queryInterface( aClassType );
+ if( !aTmp.hasValue() )
+ return;
+
+ SbUnoObject* pUnoObj = new SbUnoObject( aListenerClassName, aTmp );
+ xAllLst->xSbxObj = pUnoObj;
+ xAllLst->xSbxObj->SetParent( pBasic );
+
+ // #100326 Register listener object to set Parent NULL in Dtor
+ SbxArrayRef xBasicUnoListeners = pBasic->getUnoListeners();
+ xBasicUnoListeners->Insert(pUnoObj, xBasicUnoListeners->Count());
+
+ // return the object
+ SbxVariableRef refVar = rPar.Get(0);
+ refVar->PutObject( xAllLst->xSbxObj.get() );
+}
+
+
+// Represents the DefaultContext property of the ProcessServiceManager
+// in the Basic runtime system.
+void RTL_Impl_GetDefaultContext( SbxArray& rPar )
+{
+ SbxVariableRef refVar = rPar.Get(0);
+
+ Any aContextAny( comphelper::getProcessComponentContext() );
+
+ SbUnoObjectRef xUnoObj = new SbUnoObject( "DefaultContext", aContextAny );
+ refVar->PutObject( xUnoObj.get() );
+}
+
+
+// Creates a Basic wrapper object for a strongly typed Uno value
+// 1. parameter: Uno type as full qualified type name, e.g. "byte[]"
+void RTL_Impl_CreateUnoValue( SbxArray& rPar )
+{
+ // 2 parameters needed
+ if (rPar.Count() != 3)
+ {
+ StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
+ return;
+ }
+
+ // get the name of the class of the struct
+ OUString aTypeName = rPar.Get(1)->GetOUString();
+ SbxVariable* pVal = rPar.Get(2);
+
+ if( aTypeName == "type" )
+ {
+ SbxDataType eBaseType = pVal->SbxValue::GetType();
+ OUString aValTypeName;
+ if( eBaseType == SbxSTRING )
+ {
+ aValTypeName = pVal->GetOUString();
+ }
+ else if( eBaseType == SbxOBJECT )
+ {
+ // XIdlClass?
+ Reference< XIdlClass > xIdlClass;
+
+ SbxBaseRef pObj = pVal->GetObject();
+ if( auto obj = dynamic_cast<SbUnoObject*>( pObj.get() ) )
+ {
+ Any aUnoAny = obj->getUnoAny();
+ aUnoAny >>= xIdlClass;
+ }
+
+ if( xIdlClass.is() )
+ {
+ aValTypeName = xIdlClass->getName();
+ }
+ }
+ Type aType;
+ bool bSuccess = implGetTypeByName( aValTypeName, aType );
+ if( bSuccess )
+ {
+ Any aTypeAny( aType );
+ SbxVariableRef refVar = rPar.Get(0);
+ SbxObjectRef xUnoAnyObject = new SbUnoAnyObject( aTypeAny );
+ refVar->PutObject( xUnoAnyObject.get() );
+ }
+ return;
+ }
+
+ // Check the type
+ const Reference< XHierarchicalNameAccess >& xTypeAccess = getTypeProvider_Impl();
+ Any aRet;
+ try
+ {
+ aRet = xTypeAccess->getByHierarchicalName( aTypeName );
+ }
+ catch( const NoSuchElementException& e1 )
+ {
+ StarBASIC::Error( ERRCODE_BASIC_EXCEPTION,
+ implGetExceptionMsg( e1, u"com.sun.star.container.NoSuchElementException" ) );
+ return;
+ }
+ Reference< XTypeDescription > xTypeDesc;
+ aRet >>= xTypeDesc;
+ TypeClass eTypeClass = xTypeDesc->getTypeClass();
+ Type aDestType( eTypeClass, aTypeName );
+
+
+ // Preconvert value
+ Any aVal = sbxToUnoValueImpl( pVal );
+ Any aConvertedVal = convertAny( aVal, aDestType );
+
+ SbxVariableRef refVar = rPar.Get(0);
+ SbxObjectRef xUnoAnyObject = new SbUnoAnyObject( aConvertedVal );
+ refVar->PutObject( xUnoAnyObject.get() );
+}
+
+namespace {
+
+class ModuleInvocationProxy : public WeakImplHelper< XInvocation, XComponent >
+{
+ std::mutex m_aMutex;
+ OUString m_aPrefix;
+ SbxObjectRef m_xScopeObj;
+ bool m_bProxyIsClassModuleObject;
+
+ ::comphelper::OInterfaceContainerHelper4<XEventListener> m_aListeners;
+
+public:
+ ModuleInvocationProxy( std::u16string_view aPrefix, SbxObjectRef const & xScopeObj );
+
+ // XInvocation
+ virtual Reference< XIntrospectionAccess > SAL_CALL getIntrospection() override;
+ virtual void SAL_CALL setValue( const OUString& rProperty, const Any& rValue ) override;
+ virtual Any SAL_CALL getValue( const OUString& rProperty ) override;
+ virtual sal_Bool SAL_CALL hasMethod( const OUString& rName ) override;
+ virtual sal_Bool SAL_CALL hasProperty( const OUString& rProp ) override;
+
+ virtual Any SAL_CALL invoke( const OUString& rFunction,
+ const Sequence< Any >& rParams,
+ Sequence< sal_Int16 >& rOutParamIndex,
+ Sequence< Any >& rOutParam ) override;
+
+ // XComponent
+ virtual void SAL_CALL dispose() override;
+ virtual void SAL_CALL addEventListener( const Reference< XEventListener >& xListener ) override;
+ virtual void SAL_CALL removeEventListener( const Reference< XEventListener >& aListener ) override;
+};
+
+}
+
+ModuleInvocationProxy::ModuleInvocationProxy( std::u16string_view aPrefix, SbxObjectRef const & xScopeObj )
+ : m_aPrefix( OUString::Concat(aPrefix) + "_" )
+ , m_xScopeObj( xScopeObj )
+{
+ m_bProxyIsClassModuleObject = xScopeObj.is() && dynamic_cast<const SbClassModuleObject*>( xScopeObj.get() ) != nullptr;
+}
+
+Reference< XIntrospectionAccess > SAL_CALL ModuleInvocationProxy::getIntrospection()
+{
+ return Reference< XIntrospectionAccess >();
+}
+
+void SAL_CALL ModuleInvocationProxy::setValue(const OUString& rProperty, const Any& rValue)
+{
+ if( !m_bProxyIsClassModuleObject )
+ throw UnknownPropertyException();
+
+ SolarMutexGuard guard;
+
+ OUString aPropertyFunctionName = "Property Set "
+ + m_aPrefix
+ + rProperty;
+
+ SbxVariable* p = m_xScopeObj->Find( aPropertyFunctionName, SbxClassType::Method );
+ SbMethod* pMeth = dynamic_cast<SbMethod*>( p );
+ if( pMeth == nullptr )
+ {
+ // TODO: Check vba behavior concerning missing function
+ //StarBASIC::Error( ERRCODE_BASIC_NO_METHOD, aFunctionName );
+ throw UnknownPropertyException(aPropertyFunctionName);
+ }
+
+ // Setup parameter
+ SbxArrayRef xArray = new SbxArray;
+ SbxVariableRef xVar = new SbxVariable( SbxVARIANT );
+ unoToSbxValue( xVar.get(), rValue );
+ xArray->Put(xVar.get(), 1);
+
+ // Call property method
+ SbxVariableRef xValue = new SbxVariable;
+ pMeth->SetParameters( xArray.get() );
+ pMeth->Call( xValue.get() );
+ pMeth->SetParameters( nullptr );
+
+ // TODO: OutParameter?
+
+
+}
+
+Any SAL_CALL ModuleInvocationProxy::getValue(const OUString& rProperty)
+{
+ if( !m_bProxyIsClassModuleObject )
+ {
+ throw UnknownPropertyException();
+ }
+ SolarMutexGuard guard;
+
+ OUString aPropertyFunctionName = "Property Get "
+ + m_aPrefix
+ + rProperty;
+
+ SbxVariable* p = m_xScopeObj->Find( aPropertyFunctionName, SbxClassType::Method );
+ SbMethod* pMeth = dynamic_cast<SbMethod*>( p );
+ if( pMeth == nullptr )
+ {
+ // TODO: Check vba behavior concerning missing function
+ //StarBASIC::Error( ERRCODE_BASIC_NO_METHOD, aFunctionName );
+ throw UnknownPropertyException(aPropertyFunctionName);
+ }
+
+ // Call method
+ SbxVariableRef xValue = new SbxVariable;
+ pMeth->Call( xValue.get() );
+ Any aRet = sbxToUnoValue( xValue.get() );
+ return aRet;
+}
+
+sal_Bool SAL_CALL ModuleInvocationProxy::hasMethod( const OUString& )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ModuleInvocationProxy::hasProperty( const OUString& )
+{
+ return false;
+}
+
+Any SAL_CALL ModuleInvocationProxy::invoke( const OUString& rFunction,
+ const Sequence< Any >& rParams,
+ Sequence< sal_Int16 >&,
+ Sequence< Any >& )
+{
+ SolarMutexGuard guard;
+
+ Any aRet;
+ SbxObjectRef xScopeObj = m_xScopeObj;
+ if( !xScopeObj.is() )
+ {
+ return aRet;
+ }
+ OUString aFunctionName = m_aPrefix
+ + rFunction;
+
+ bool bSetRescheduleBack = false;
+ bool bOldReschedule = true;
+ SbiInstance* pInst = GetSbData()->pInst;
+ if( pInst && pInst->IsCompatibility() )
+ {
+ bOldReschedule = pInst->IsReschedule();
+ if ( bOldReschedule )
+ {
+ pInst->EnableReschedule( false );
+ bSetRescheduleBack = true;
+ }
+ }
+
+ SbxVariable* p = xScopeObj->Find( aFunctionName, SbxClassType::Method );
+ SbMethod* pMeth = dynamic_cast<SbMethod*>( p );
+ if( pMeth == nullptr )
+ {
+ // TODO: Check vba behavior concerning missing function
+ //StarBASIC::Error( ERRCODE_BASIC_NO_METHOD, aFunctionName );
+ return aRet;
+ }
+
+ // Setup parameters
+ SbxArrayRef xArray;
+ sal_Int32 nParamCount = rParams.getLength();
+ if( nParamCount )
+ {
+ xArray = new SbxArray;
+ const Any *pArgs = rParams.getConstArray();
+ for( sal_Int32 i = 0 ; i < nParamCount ; i++ )
+ {
+ SbxVariableRef xVar = new SbxVariable( SbxVARIANT );
+ unoToSbxValue( xVar.get(), pArgs[i] );
+ xArray->Put(xVar.get(), sal::static_int_cast<sal_uInt16>(i + 1));
+ }
+ }
+
+ // Call method
+ SbxVariableRef xValue = new SbxVariable;
+ if( xArray.is() )
+ pMeth->SetParameters( xArray.get() );
+ pMeth->Call( xValue.get() );
+ aRet = sbxToUnoValue( xValue.get() );
+ pMeth->SetParameters( nullptr );
+
+ if( bSetRescheduleBack )
+ pInst->EnableReschedule( bOldReschedule );
+
+ // TODO: OutParameter?
+
+ return aRet;
+}
+
+void SAL_CALL ModuleInvocationProxy::dispose()
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ EventObject aEvent( static_cast<XComponent*>(this) );
+ m_aListeners.disposeAndClear( aGuard, aEvent );
+
+ m_xScopeObj = nullptr;
+}
+
+void SAL_CALL ModuleInvocationProxy::addEventListener( const Reference< XEventListener >& xListener )
+{
+ std::unique_lock aGuard( m_aMutex );
+ m_aListeners.addInterface( aGuard, xListener );
+}
+
+void SAL_CALL ModuleInvocationProxy::removeEventListener( const Reference< XEventListener >& xListener )
+{
+ std::unique_lock aGuard( m_aMutex );
+ m_aListeners.removeInterface( aGuard, xListener );
+}
+
+
+Reference< XInterface > createComListener( const Any& aControlAny, const OUString& aVBAType,
+ std::u16string_view aPrefix,
+ const SbxObjectRef& xScopeObj )
+{
+ Reference< XInterface > xRet;
+
+ Reference< XComponentContext > xContext(
+ comphelper::getProcessComponentContext() );
+ Reference< XMultiComponentFactory > xServiceMgr( xContext->getServiceManager() );
+
+ Reference< XInvocation > xProxy = new ModuleInvocationProxy( aPrefix, xScopeObj );
+
+ Sequence<Any> args{ aControlAny, Any(aVBAType), Any(xProxy) };
+
+ try
+ {
+ xRet = xServiceMgr->createInstanceWithArgumentsAndContext(
+ "com.sun.star.custom.UnoComListener",
+ args, xContext );
+ }
+ catch( const Exception& )
+ {
+ implHandleAnyException( ::cppu::getCaughtException() );
+ }
+
+ return xRet;
+}
+
+typedef std::vector< WeakReference< XComponent > > ComponentRefVector;
+
+namespace {
+
+struct StarBasicDisposeItem
+{
+ StarBASIC* m_pBasic;
+ SbxArrayRef m_pRegisteredVariables;
+ ComponentRefVector m_vComImplementsObjects;
+
+ explicit StarBasicDisposeItem( StarBASIC* pBasic )
+ : m_pBasic( pBasic )
+ , m_pRegisteredVariables(new SbxArray())
+ {
+ }
+};
+
+}
+
+typedef std::vector< StarBasicDisposeItem* > DisposeItemVector;
+
+static DisposeItemVector GaDisposeItemVector;
+
+static DisposeItemVector::iterator lcl_findItemForBasic( StarBASIC const * pBasic )
+{
+ return std::find_if(GaDisposeItemVector.begin(), GaDisposeItemVector.end(),
+ [&pBasic](StarBasicDisposeItem* pItem) { return pItem->m_pBasic == pBasic; });
+}
+
+static StarBasicDisposeItem* lcl_getOrCreateItemForBasic( StarBASIC* pBasic )
+{
+ DisposeItemVector::iterator it = lcl_findItemForBasic( pBasic );
+ StarBasicDisposeItem* pItem = (it != GaDisposeItemVector.end()) ? *it : nullptr;
+ if( pItem == nullptr )
+ {
+ pItem = new StarBasicDisposeItem( pBasic );
+ GaDisposeItemVector.push_back( pItem );
+ }
+ return pItem;
+}
+
+void registerComponentToBeDisposedForBasic
+ ( const Reference< XComponent >& xComponent, StarBASIC* pBasic )
+{
+ StarBasicDisposeItem* pItem = lcl_getOrCreateItemForBasic( pBasic );
+ pItem->m_vComImplementsObjects.emplace_back(xComponent );
+}
+
+void registerComListenerVariableForBasic( SbxVariable* pVar, StarBASIC* pBasic )
+{
+ StarBasicDisposeItem* pItem = lcl_getOrCreateItemForBasic( pBasic );
+ SbxArray* pArray = pItem->m_pRegisteredVariables.get();
+ pArray->Put(pVar, pArray->Count());
+}
+
+void disposeComVariablesForBasic( StarBASIC const * pBasic )
+{
+ DisposeItemVector::iterator it = lcl_findItemForBasic( pBasic );
+ if( it == GaDisposeItemVector.end() )
+ return;
+
+ StarBasicDisposeItem* pItem = *it;
+
+ SbxArray* pArray = pItem->m_pRegisteredVariables.get();
+ sal_uInt32 nCount = pArray->Count();
+ for( sal_uInt32 i = 0 ; i < nCount ; ++i )
+ {
+ SbxVariable* pVar = pArray->Get(i);
+ pVar->ClearComListener();
+ }
+
+ ComponentRefVector& rv = pItem->m_vComImplementsObjects;
+ for (auto const& elem : rv)
+ {
+ Reference< XComponent > xComponent( elem.get(), UNO_QUERY );
+ if (xComponent.is())
+ xComponent->dispose();
+ }
+
+ delete pItem;
+ GaDisposeItemVector.erase( it );
+}
+
+
+// Handle module implements mechanism for OLE types
+bool SbModule::createCOMWrapperForIface( Any& o_rRetAny, SbClassModuleObject* pProxyClassModuleObject )
+{
+ // For now: Take first interface that allows to instantiate COM wrapper
+ // TODO: Check if support for multiple interfaces is needed
+
+ Reference< XComponentContext > xContext(
+ comphelper::getProcessComponentContext() );
+ Reference< XMultiComponentFactory > xServiceMgr( xContext->getServiceManager() );
+ Reference< XSingleServiceFactory > xComImplementsFactory
+ (
+ xServiceMgr->createInstanceWithContext( "com.sun.star.custom.ComImplementsFactory", xContext ),
+ UNO_QUERY
+ );
+ if( !xComImplementsFactory.is() )
+ return false;
+
+ bool bSuccess = false;
+
+ SbxArray* pModIfaces = pClassData->mxIfaces.get();
+ sal_uInt32 nCount = pModIfaces->Count();
+ for( sal_uInt32 i = 0 ; i < nCount ; ++i )
+ {
+ SbxVariable* pVar = pModIfaces->Get(i);
+ const OUString& aIfaceName = pVar->GetName();
+
+ if( !aIfaceName.isEmpty() )
+ {
+ OUString aPureIfaceName = aIfaceName;
+ sal_Int32 indexLastDot = aIfaceName.lastIndexOf('.');
+ if ( indexLastDot > -1 )
+ {
+ aPureIfaceName = aIfaceName.copy( indexLastDot + 1 );
+ }
+ Reference< XInvocation > xProxy = new ModuleInvocationProxy( aPureIfaceName, pProxyClassModuleObject );
+
+ Sequence<Any> args{ Any(aIfaceName), Any(xProxy) };
+
+ Reference< XInterface > xRet;
+ try
+ {
+ xRet = xComImplementsFactory->createInstanceWithArguments( args );
+ bSuccess = true;
+ }
+ catch( const Exception& )
+ {
+ implHandleAnyException( ::cppu::getCaughtException() );
+ }
+
+ if( bSuccess )
+ {
+ Reference< XComponent > xComponent( xProxy, UNO_QUERY );
+ if( xComponent.is() )
+ {
+ StarBASIC* pParentBasic = nullptr;
+ SbxObject* pCurObject = this;
+ do
+ {
+ SbxObject* pObjParent = pCurObject->GetParent();
+ pParentBasic = dynamic_cast<StarBASIC*>( pObjParent );
+ pCurObject = pObjParent;
+ }
+ while( pParentBasic == nullptr && pCurObject != nullptr );
+
+ assert( pParentBasic != nullptr );
+ registerComponentToBeDisposedForBasic( xComponent, pParentBasic );
+ }
+
+ o_rRetAny <<= xRet;
+ break;
+ }
+ }
+ }
+
+ return bSuccess;
+}
+
+
+// Due to an incorrect behavior IE returns an object instead of a string
+// in some scenarios. Calling toString at the object may correct this.
+// Helper function used in sbxvalue.cxx
+bool handleToStringForCOMObjects( SbxObject* pObj, SbxValue* pVal )
+{
+ bool bSuccess = false;
+
+ if( auto pUnoObj = dynamic_cast<SbUnoObject*>( pObj) )
+ {
+ // Only for native COM objects
+ if( pUnoObj->isNativeCOMObject() )
+ {
+ SbxVariableRef pMeth = pObj->Find( "toString", SbxClassType::Method );
+ if ( pMeth.is() )
+ {
+ SbxValues aRes;
+ pMeth->Get( aRes );
+ pVal->Put( aRes );
+ bSuccess = true;
+ }
+ }
+ }
+ return bSuccess;
+}
+
+Any StructRefInfo::getValue()
+{
+ Any aRet;
+ uno_any_destruct(
+ &aRet, reinterpret_cast< uno_ReleaseFunc >(cpp_release) );
+ typelib_TypeDescription * pTD = nullptr;
+ maType.getDescription(&pTD);
+ uno_any_construct(
+ &aRet, getInst(), pTD,
+ reinterpret_cast< uno_AcquireFunc >(cpp_acquire) );
+ typelib_typedescription_release(pTD);
+ return aRet;
+}
+
+void StructRefInfo::setValue( const Any& rValue )
+{
+ bool bSuccess = uno_type_assignData( getInst(),
+ maType.getTypeLibType(),
+ const_cast<void*>(rValue.getValue()),
+ rValue.getValueTypeRef(),
+ reinterpret_cast< uno_QueryInterfaceFunc >(cpp_queryInterface),
+ reinterpret_cast< uno_AcquireFunc >(cpp_acquire),
+ reinterpret_cast< uno_ReleaseFunc >(cpp_release) );
+ OSL_ENSURE(bSuccess,
+ "StructRefInfo::setValue: ooops... the value could not be assigned!");
+}
+
+OUString StructRefInfo::getTypeName() const
+{
+ return maType.getTypeName();
+}
+
+void* StructRefInfo::getInst()
+{
+ return const_cast<char *>(static_cast<char const *>(maAny.getValue()) + mnPos);
+}
+
+TypeClass StructRefInfo::getTypeClass() const
+{
+ return maType.getTypeClass();
+}
+
+SbUnoStructRefObject::SbUnoStructRefObject( const OUString& aName_, StructRefInfo aMemberInfo ) : SbxObject( aName_ ), maMemberInfo(std::move( aMemberInfo )), mbMemberCacheInit( false )
+{
+ SetClassName( maMemberInfo.getTypeName() );
+}
+
+SbUnoStructRefObject::~SbUnoStructRefObject()
+{
+}
+
+void SbUnoStructRefObject::initMemberCache()
+{
+ if ( mbMemberCacheInit )
+ return;
+ typelib_TypeDescription * pTD = nullptr;
+ maMemberInfo.getType().getDescription(&pTD);
+ for ( typelib_CompoundTypeDescription * pCompTypeDescr = reinterpret_cast<typelib_CompoundTypeDescription *>(pTD);
+ pCompTypeDescr;
+ pCompTypeDescr = pCompTypeDescr->pBaseTypeDescription )
+ {
+ typelib_TypeDescriptionReference ** ppTypeRefs = pCompTypeDescr->ppTypeRefs;
+ rtl_uString ** ppNames = pCompTypeDescr->ppMemberNames;
+ sal_Int32 * pMemberOffsets = pCompTypeDescr->pMemberOffsets;
+ for ( sal_Int32 nPos = pCompTypeDescr->nMembers; nPos--; )
+ {
+ OUString aName( ppNames[nPos] );
+ maFields[ aName ] = std::make_unique<StructRefInfo>( maMemberInfo.getRootAnyRef(), ppTypeRefs[nPos], maMemberInfo.getPos() + pMemberOffsets[nPos] );
+ }
+ }
+ typelib_typedescription_release(pTD);
+ mbMemberCacheInit = true;
+}
+
+SbxVariable* SbUnoStructRefObject::Find( const OUString& rName, SbxClassType t )
+{
+ SbxVariable* pRes = SbxObject::Find( rName, t );
+ if ( !pRes )
+ {
+ if ( !mbMemberCacheInit )
+ initMemberCache();
+ StructFieldInfo::iterator it = maFields.find( rName );
+ if ( it != maFields.end() )
+ {
+ SbxDataType eSbxType;
+ eSbxType = unoToSbxType( it->second->getTypeClass() );
+ SbxDataType eRealSbxType = eSbxType;
+ Property aProp;
+ aProp.Name = rName;
+ aProp.Type = css::uno::Type( it->second->getTypeClass(), it->second->getTypeName() );
+ const bool bIsStruct = aProp.Type.getTypeClass() == css::uno::TypeClass_STRUCT;
+ SbUnoProperty* pProp = new SbUnoProperty( rName, eSbxType, eRealSbxType, std::move(aProp), 0, false, bIsStruct );
+ SbxVariableRef xVarRef = pProp;
+ QuickInsert( xVarRef.get() );
+ pRes = xVarRef.get();
+ }
+ }
+
+ if( !pRes )
+ {
+ if( rName.equalsIgnoreAsciiCase(ID_DBG_SUPPORTEDINTERFACES) ||
+ rName.equalsIgnoreAsciiCase(ID_DBG_PROPERTIES) ||
+ rName.equalsIgnoreAsciiCase(ID_DBG_METHODS) )
+ {
+ // Create
+ implCreateDbgProperties();
+
+ // Now they have to be found regular
+ pRes = SbxObject::Find( rName, SbxClassType::DontCare );
+ }
+ }
+
+ return pRes;
+}
+
+// help method to create the dbg_-Properties
+void SbUnoStructRefObject::implCreateDbgProperties()
+{
+ Property aProp;
+
+ // Id == -1: display the implemented interfaces corresponding the ClassProvider
+ SbxVariableRef xVarRef = new SbUnoProperty( ID_DBG_SUPPORTEDINTERFACES, SbxSTRING, SbxSTRING, aProp, -1, false, false );
+ QuickInsert( xVarRef.get() );
+
+ // Id == -2: output the properties
+ xVarRef = new SbUnoProperty( ID_DBG_PROPERTIES, SbxSTRING, SbxSTRING, aProp, -2, false, false );
+ QuickInsert( xVarRef.get() );
+
+ // Id == -3: output the Methods
+ xVarRef = new SbUnoProperty( ID_DBG_METHODS, SbxSTRING, SbxSTRING, aProp, -3, false, false );
+ QuickInsert( xVarRef.get() );
+}
+
+void SbUnoStructRefObject::implCreateAll()
+{
+ // throw away all existing methods and properties
+ pMethods = new SbxArray;
+ pProps = new SbxArray;
+
+ if (!mbMemberCacheInit)
+ initMemberCache();
+
+ for (auto const& field : maFields)
+ {
+ const OUString& rName = field.first;
+ SbxDataType eSbxType;
+ eSbxType = unoToSbxType( field.second->getTypeClass() );
+ SbxDataType eRealSbxType = eSbxType;
+ Property aProp;
+ aProp.Name = rName;
+ aProp.Type = css::uno::Type( field.second->getTypeClass(), field.second->getTypeName() );
+ const bool bIsStruct = aProp.Type.getTypeClass() == css::uno::TypeClass_STRUCT;
+ SbUnoProperty* pProp = new SbUnoProperty( rName, eSbxType, eRealSbxType, std::move(aProp), 0, false, bIsStruct );
+ SbxVariableRef xVarRef = pProp;
+ QuickInsert( xVarRef.get() );
+ }
+
+ // Create Dbg_-Properties
+ implCreateDbgProperties();
+}
+
+ // output the value
+Any SbUnoStructRefObject::getUnoAny()
+{
+ return maMemberInfo.getValue();
+}
+
+OUString SbUnoStructRefObject::Impl_DumpProperties()
+{
+ OUStringBuffer aRet;
+ aRet.append("Properties of object ");
+ aRet.append( getDbgObjectName() );
+
+ sal_uInt32 nPropCount = pProps->Count();
+ sal_uInt32 nPropsPerLine = 1 + nPropCount / 30;
+ for( sal_uInt32 i = 0; i < nPropCount; i++ )
+ {
+ SbxVariable* pVar = pProps->Get(i);
+ if( pVar )
+ {
+ OUStringBuffer aPropStr;
+ if( (i % nPropsPerLine) == 0 )
+ {
+ aPropStr.append( "\n" );
+ }
+ // output the type and name
+ // Is it in Uno a sequence?
+ SbxDataType eType = pVar->GetFullType();
+
+ const OUString& aName( pVar->GetName() );
+ StructFieldInfo::iterator it = maFields.find( aName );
+
+ if ( it != maFields.end() )
+ {
+ const StructRefInfo& rPropInfo = *it->second;
+
+ if( eType == SbxOBJECT )
+ {
+ if( rPropInfo.getTypeClass() == TypeClass_SEQUENCE )
+ {
+ eType = SbxDataType( SbxOBJECT | SbxARRAY );
+ }
+ }
+ }
+ aPropStr.append( Dbg_SbxDataType2String( eType ) );
+
+ aPropStr.append( " " );
+ aPropStr.append( pVar->GetName() );
+
+ if( i == nPropCount - 1 )
+ {
+ aPropStr.append( "\n" );
+ }
+ else
+ {
+ aPropStr.append( "; " );
+ }
+ aRet.append( aPropStr );
+ }
+ }
+ return aRet.makeStringAndClear();
+}
+
+void SbUnoStructRefObject::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
+{
+ if ( !mbMemberCacheInit )
+ initMemberCache();
+ const SbxHint* pHint = dynamic_cast<const SbxHint*>(&rHint);
+ if( !pHint )
+ return;
+
+ SbxVariable* pVar = pHint->GetVar();
+ SbUnoProperty* pProp = dynamic_cast<SbUnoProperty*>( pVar );
+ if( pProp )
+ {
+ StructFieldInfo::iterator it = maFields.find( pProp->GetName() );
+ // handle get/set of members of struct
+ if( pHint->GetId() == SfxHintId::BasicDataWanted )
+ {
+ // Test-Properties
+ sal_Int32 nId = pProp->nId;
+ if( nId < 0 )
+ {
+ // Id == -1: Display implemented interfaces according the ClassProvider
+ if( nId == -1 ) // Property ID_DBG_SUPPORTEDINTERFACES"
+ {
+ OUString aRet = OUString::Concat( ID_DBG_SUPPORTEDINTERFACES )
+ + " not available.\n(TypeClass is not TypeClass_INTERFACE)\n";
+
+ pVar->PutString( aRet );
+ }
+ // Id == -2: output properties
+ else if( nId == -2 ) // Property ID_DBG_PROPERTIES
+ {
+ // by now all properties must be established
+ implCreateAll();
+ OUString aRetStr = Impl_DumpProperties();
+ pVar->PutString( aRetStr );
+ }
+ // Id == -3: output the methods
+ else if( nId == -3 ) // Property ID_DBG_METHODS
+ {
+ // by now all properties must be established
+ implCreateAll();
+ OUString aRet = "Methods of object "
+ + getDbgObjectName()
+ + "\nNo methods found\n";
+ pVar->PutString( aRet );
+ }
+ return;
+ }
+
+ if ( it != maFields.end() )
+ {
+ Any aRetAny = it->second->getValue();
+ unoToSbxValue( pVar, aRetAny );
+ }
+ else
+ StarBASIC::Error( ERRCODE_BASIC_PROPERTY_NOT_FOUND );
+ }
+ else if( pHint->GetId() == SfxHintId::BasicDataChanged )
+ {
+ if ( it != maFields.end() )
+ {
+ // take over the value from Uno to Sbx
+ Any aAnyValue = sbxToUnoValue( pVar, pProp->aUnoProp.Type, &pProp->aUnoProp );
+ it->second->setValue( aAnyValue );
+ }
+ else
+ StarBASIC::Error( ERRCODE_BASIC_PROPERTY_NOT_FOUND );
+ }
+ }
+ else
+ SbxObject::Notify( rBC, rHint );
+}
+
+StructRefInfo SbUnoStructRefObject::getStructMember( const OUString& rMemberName )
+{
+ if (!mbMemberCacheInit)
+ {
+ initMemberCache();
+ }
+ StructFieldInfo::iterator it = maFields.find( rMemberName );
+
+ css::uno::Type aFoundType;
+ sal_Int32 nFoundPos = -1;
+
+ if ( it != maFields.end() )
+ {
+ aFoundType = it->second->getType();
+ nFoundPos = it->second->getPos();
+ }
+ StructRefInfo aRet( maMemberInfo.getRootAnyRef(), aFoundType, nFoundPos );
+ return aRet;
+}
+
+OUString SbUnoStructRefObject::getDbgObjectName() const
+{
+ OUString aName = GetClassName();
+ if( aName.isEmpty() )
+ {
+ aName += "Unknown";
+ }
+ OUStringBuffer aRet;
+ if( aName.getLength() > 20 )
+ {
+ aRet.append( "\n" );
+ }
+ aRet.append( "\"" );
+ aRet.append( aName );
+ aRet.append( "\":" );
+ return aRet.makeStringAndClear();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */