nss: upgrade to release 3.73
[LibreOffice.git] / basic / source / classes / sbunoobj.cxx
blob3816d351302c346e9d6fc77cf974e54b5626069f
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
22 #include <o3tl/any.hxx>
23 #include <osl/mutex.hxx>
24 #include <vcl/svapp.hxx>
25 #include <vcl/errcode.hxx>
26 #include <svl/hint.hxx>
28 #include <cppuhelper/implbase.hxx>
29 #include <cppuhelper/exc_hlp.hxx>
30 #include <comphelper/interfacecontainer2.hxx>
31 #include <comphelper/extract.hxx>
32 #include <comphelper/processfactory.hxx>
33 #include <cppuhelper/weakref.hxx>
35 #include <rtl/instance.hxx>
36 #include <rtl/math.hxx>
37 #include <rtl/ustrbuf.hxx>
39 #include <com/sun/star/script/ArrayWrapper.hpp>
40 #include <com/sun/star/script/CannotConvertException.hpp>
41 #include <com/sun/star/script/NativeObjectWrapper.hpp>
43 #include <com/sun/star/uno/XComponentContext.hpp>
44 #include <com/sun/star/uno/DeploymentException.hpp>
45 #include <com/sun/star/lang/XTypeProvider.hpp>
46 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
47 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
48 #include <com/sun/star/lang/XServiceInfo.hpp>
49 #include <com/sun/star/beans/PropertyAttribute.hpp>
50 #include <com/sun/star/beans/PropertyConcept.hpp>
51 #include <com/sun/star/beans/MethodConcept.hpp>
52 #include <com/sun/star/beans/XPropertySet.hpp>
53 #include <com/sun/star/beans/theIntrospection.hpp>
54 #include <com/sun/star/script/BasicErrorException.hpp>
55 #include <com/sun/star/script/InvocationAdapterFactory.hpp>
56 #include <com/sun/star/script/XAllListener.hpp>
57 #include <com/sun/star/script/Converter.hpp>
58 #include <com/sun/star/script/XDefaultProperty.hpp>
59 #include <com/sun/star/script/XDirectInvocation.hpp>
60 #include <com/sun/star/container/XNameAccess.hpp>
61 #include <com/sun/star/container/XHierarchicalNameAccess.hpp>
62 #include <com/sun/star/reflection/XIdlArray.hpp>
63 #include <com/sun/star/reflection/XIdlReflection.hpp>
64 #include <com/sun/star/reflection/XServiceConstructorDescription.hpp>
65 #include <com/sun/star/reflection/XSingletonTypeDescription.hpp>
66 #include <com/sun/star/reflection/theCoreReflection.hpp>
67 #include <com/sun/star/bridge/oleautomation/NamedArgument.hpp>
68 #include <com/sun/star/bridge/oleautomation/Date.hpp>
69 #include <com/sun/star/bridge/oleautomation/Decimal.hpp>
70 #include <com/sun/star/bridge/oleautomation/Currency.hpp>
71 #include <com/sun/star/bridge/oleautomation/XAutomationObject.hpp>
72 #include <com/sun/star/script/XAutomationInvocation.hpp>
74 #include <rtlproto.hxx>
76 #include <basic/sbstar.hxx>
77 #include <basic/sbuno.hxx>
78 #include <basic/sberrors.hxx>
79 #include <sbunoobj.hxx>
80 #include <sbintern.hxx>
81 #include <runtime.hxx>
83 #include <algorithm>
84 #include <math.h>
85 #include <memory>
86 #include <unordered_map>
87 #include <com/sun/star/reflection/XTypeDescriptionEnumerationAccess.hpp>
88 #include <com/sun/star/reflection/XConstantsTypeDescription.hpp>
90 using com::sun::star::uno::Reference;
91 using namespace com::sun::star::uno;
92 using namespace com::sun::star::lang;
93 using namespace com::sun::star::reflection;
94 using namespace com::sun::star::beans;
95 using namespace com::sun::star::script;
96 using namespace com::sun::star::container;
97 using namespace com::sun::star::bridge;
98 using namespace cppu;
101 // Identifiers for creating the strings for dbg_Properties
102 char16_t constexpr ID_DBG_SUPPORTEDINTERFACES[] = u"Dbg_SupportedInterfaces";
103 char const ID_DBG_PROPERTIES[] = "Dbg_Properties";
104 char const ID_DBG_METHODS[] = "Dbg_Methods";
106 char const aSeqLevelStr[] = "[]";
108 // Gets the default property for a uno object. Note: There is some
109 // redirection built in. The property name specifies the name
110 // of the default property.
112 bool SbUnoObject::getDefaultPropName( SbUnoObject const * pUnoObj, OUString& sDfltProp )
114 bool bResult = false;
115 Reference< XDefaultProperty> xDefaultProp( pUnoObj->maTmpUnoObj, UNO_QUERY );
116 if ( xDefaultProp.is() )
118 sDfltProp = xDefaultProp->getDefaultPropertyName();
119 if ( !sDfltProp.isEmpty() )
120 bResult = true;
122 return bResult;
125 SbxVariable* getDefaultProp( SbxVariable* pRef )
127 SbxVariable* pDefaultProp = nullptr;
128 if ( pRef->GetType() == SbxOBJECT )
130 SbxObject* pObj = dynamic_cast<SbxObject*>(pRef);
131 if (!pObj)
133 SbxBase* pObjVarObj = pRef->GetObject();
134 pObj = dynamic_cast<SbxObject*>( pObjVarObj );
136 if (SbUnoObject* pUnoObj = dynamic_cast<SbUnoObject*>(pObj))
138 pDefaultProp = pUnoObj->GetDfltProperty();
141 return pDefaultProp;
144 void SetSbUnoObjectDfltPropName( SbxObject* pObj )
146 SbUnoObject* pUnoObj = dynamic_cast<SbUnoObject*>( pObj );
147 if ( pUnoObj )
149 OUString sDfltPropName;
151 if ( SbUnoObject::getDefaultPropName( pUnoObj, sDfltPropName ) )
153 pUnoObj->SetDfltProperty( sDfltPropName );
158 // save CoreReflection statically
159 static Reference< XIdlReflection > getCoreReflection_Impl()
161 return css::reflection::theCoreReflection::get(
162 comphelper::getProcessComponentContext());
165 // save CoreReflection statically
166 static Reference< XHierarchicalNameAccess > const & getCoreReflection_HierarchicalNameAccess_Impl()
168 static Reference< XHierarchicalNameAccess > xCoreReflection_HierarchicalNameAccess;
170 if( !xCoreReflection_HierarchicalNameAccess.is() )
172 Reference< XIdlReflection > xCoreReflection = getCoreReflection_Impl();
173 if( xCoreReflection.is() )
175 xCoreReflection_HierarchicalNameAccess =
176 Reference< XHierarchicalNameAccess >( xCoreReflection, UNO_QUERY );
179 return xCoreReflection_HierarchicalNameAccess;
182 // Hold TypeProvider statically
183 static Reference< XHierarchicalNameAccess > const & getTypeProvider_Impl()
185 static Reference< XHierarchicalNameAccess > xAccess;
187 // Do we have already CoreReflection; if not obtain it
188 if( !xAccess.is() )
190 Reference< XComponentContext > xContext(
191 comphelper::getProcessComponentContext() );
192 if( xContext.is() )
194 xContext->getValueByName(
195 "/singletons/com.sun.star.reflection.theTypeDescriptionManager" )
196 >>= xAccess;
197 OSL_ENSURE( xAccess.is(), "### TypeDescriptionManager singleton not accessible!?" );
199 if( !xAccess.is() )
201 throw DeploymentException(
202 "/singletons/com.sun.star.reflection.theTypeDescriptionManager singleton not accessible" );
205 return xAccess;
208 // Hold TypeConverter statically
209 static Reference< XTypeConverter > const & getTypeConverter_Impl()
211 static Reference< XTypeConverter > xTypeConverter;
213 // Do we have already CoreReflection; if not obtain it
214 if( !xTypeConverter.is() )
216 Reference< XComponentContext > xContext(
217 comphelper::getProcessComponentContext() );
218 if( xContext.is() )
220 xTypeConverter = Converter::create(xContext);
222 if( !xTypeConverter.is() )
224 throw DeploymentException(
225 "com.sun.star.script.Converter service not accessible" );
228 return xTypeConverter;
232 // #111851 factory function to create an OLE object
233 SbUnoObject* createOLEObject_Impl( const OUString& aType )
235 static Reference< XMultiServiceFactory > xOLEFactory;
236 static bool bNeedsInit = true;
238 if( bNeedsInit )
240 bNeedsInit = false;
242 Reference< XComponentContext > xContext( comphelper::getProcessComponentContext() );
243 if( xContext.is() )
245 Reference<XMultiComponentFactory> xSMgr = xContext->getServiceManager();
246 xOLEFactory.set(
247 xSMgr->createInstanceWithContext( "com.sun.star.bridge.OleObjectFactory", xContext ),
248 UNO_QUERY );
252 SbUnoObject* pUnoObj = nullptr;
253 if( xOLEFactory.is() )
255 // some type names available in VBA can not be directly used in COM
256 OUString aOLEType = aType;
257 if ( aOLEType == "SAXXMLReader30" )
259 aOLEType = "Msxml2.SAXXMLReader.3.0";
261 Reference< XInterface > xOLEObject = xOLEFactory->createInstance( aOLEType );
262 if( xOLEObject.is() )
264 pUnoObj = new SbUnoObject( aType, Any(xOLEObject) );
265 OUString sDfltPropName;
267 if ( SbUnoObject::getDefaultPropName( pUnoObj, sDfltPropName ) )
268 pUnoObj->SetDfltProperty( sDfltPropName );
271 return pUnoObj;
275 namespace
277 void lcl_indent( OUStringBuffer& _inout_rBuffer, sal_Int32 _nLevel )
279 while ( _nLevel-- > 0 )
281 _inout_rBuffer.append( " " );
286 static void implAppendExceptionMsg( OUStringBuffer& _inout_rBuffer, const Exception& _e, const OUString& _rExceptionType, sal_Int32 _nLevel )
288 _inout_rBuffer.append( "\n" );
289 lcl_indent( _inout_rBuffer, _nLevel );
290 _inout_rBuffer.append( "Type: " );
292 if ( _rExceptionType.isEmpty() )
293 _inout_rBuffer.append( "Unknown" );
294 else
295 _inout_rBuffer.append( _rExceptionType );
297 _inout_rBuffer.append( "\n" );
298 lcl_indent( _inout_rBuffer, _nLevel );
299 _inout_rBuffer.append( "Message: " );
300 _inout_rBuffer.append( _e.Message );
304 // construct an error message for the exception
305 static OUString implGetExceptionMsg( const Exception& e, const OUString& aExceptionType_ )
307 OUStringBuffer aMessageBuf;
308 implAppendExceptionMsg( aMessageBuf, e, aExceptionType_, 0 );
309 return aMessageBuf.makeStringAndClear();
312 static OUString implGetExceptionMsg( const Any& _rCaughtException )
314 auto e = o3tl::tryAccess<Exception>(_rCaughtException);
315 OSL_PRECOND( e, "implGetExceptionMsg: illegal argument!" );
316 if ( !e )
318 return OUString();
320 return implGetExceptionMsg( *e, _rCaughtException.getValueTypeName() );
323 static Any convertAny( const Any& rVal, const Type& aDestType )
325 Any aConvertedVal;
326 const Reference< XTypeConverter >& xConverter = getTypeConverter_Impl();
329 aConvertedVal = xConverter->convertTo( rVal, aDestType );
331 catch( const IllegalArgumentException& )
333 StarBASIC::Error( ERRCODE_BASIC_EXCEPTION,
334 implGetExceptionMsg( ::cppu::getCaughtException() ) );
335 return aConvertedVal;
337 catch( const CannotConvertException& e2 )
339 StarBASIC::Error( ERRCODE_BASIC_EXCEPTION,
340 implGetExceptionMsg( e2, "com.sun.star.lang.IllegalArgumentException" ) );
341 return aConvertedVal;
343 return aConvertedVal;
347 // #105565 Special Object to wrap a strongly typed Uno Any
350 // TODO: source out later
351 static Reference<XIdlClass> TypeToIdlClass( const Type& rType )
353 return getCoreReflection_Impl()->forName(rType.getTypeName());
356 // Exception type unknown
357 template< class EXCEPTION >
358 static OUString implGetExceptionMsg( const EXCEPTION& e )
360 return implGetExceptionMsg( e, cppu::UnoType<decltype(e)>::get().getTypeName() );
363 static void implHandleBasicErrorException( BasicErrorException const & e )
365 ErrCode nError = StarBASIC::GetSfxFromVBError( static_cast<sal_uInt16>(e.ErrorCode) );
366 StarBASIC::Error( nError, e.ErrorMessageArgument );
369 static void implHandleWrappedTargetException( const Any& _rWrappedTargetException )
371 Any aExamine( _rWrappedTargetException );
373 // completely strip the first InvocationTargetException, its error message isn't of any
374 // interest to the user, it just says something like "invoking the UNO method went wrong.".
375 InvocationTargetException aInvocationError;
376 if ( aExamine >>= aInvocationError )
377 aExamine = aInvocationError.TargetException;
379 BasicErrorException aBasicError;
381 ErrCode nError( ERRCODE_BASIC_EXCEPTION );
382 OUStringBuffer aMessageBuf;
384 // strip any other WrappedTargetException instances, but this time preserve the error messages.
385 WrappedTargetException aWrapped;
386 sal_Int32 nLevel = 0;
387 while ( aExamine >>= aWrapped )
389 // special handling for BasicErrorException errors
390 if ( aWrapped.TargetException >>= aBasicError )
392 nError = StarBASIC::GetSfxFromVBError( static_cast<sal_uInt16>(aBasicError.ErrorCode) );
393 aMessageBuf.append( aBasicError.ErrorMessageArgument );
394 aExamine.clear();
395 break;
398 // append this round's message
399 implAppendExceptionMsg( aMessageBuf, aWrapped, aExamine.getValueTypeName(), nLevel );
400 if ( aWrapped.TargetException.getValueTypeClass() == TypeClass_EXCEPTION )
401 // there is a next chain element
402 aMessageBuf.append( "\nTargetException:" );
404 // next round
405 aExamine = aWrapped.TargetException;
406 ++nLevel;
409 if ( auto e = o3tl::tryAccess<Exception>(aExamine) )
411 // the last element in the chain is still an exception, but no WrappedTargetException
412 implAppendExceptionMsg( aMessageBuf, *e, aExamine.getValueTypeName(), nLevel );
415 StarBASIC::Error( nError, aMessageBuf.makeStringAndClear() );
418 static void implHandleAnyException( const Any& _rCaughtException )
420 BasicErrorException aBasicError;
421 WrappedTargetException aWrappedError;
423 if ( _rCaughtException >>= aBasicError )
425 implHandleBasicErrorException( aBasicError );
427 else if ( _rCaughtException >>= aWrappedError )
429 implHandleWrappedTargetException( _rCaughtException );
431 else
433 StarBASIC::Error( ERRCODE_BASIC_EXCEPTION, implGetExceptionMsg( _rCaughtException ) );
437 namespace {
439 // NativeObjectWrapper handling
440 struct ObjectItem
442 SbxObjectRef m_xNativeObj;
444 explicit ObjectItem( SbxObject* pNativeObj )
445 : m_xNativeObj( pNativeObj )
451 typedef std::vector< ObjectItem > NativeObjectWrapperVector;
453 namespace {
455 class GaNativeObjectWrapperVector : public rtl::Static<NativeObjectWrapperVector, GaNativeObjectWrapperVector> {};
459 void clearNativeObjectWrapperVector()
461 GaNativeObjectWrapperVector::get().clear();
464 static sal_uInt32 lcl_registerNativeObjectWrapper( SbxObject* pNativeObj )
466 NativeObjectWrapperVector &rNativeObjectWrapperVector = GaNativeObjectWrapperVector::get();
467 sal_uInt32 nIndex = rNativeObjectWrapperVector.size();
468 rNativeObjectWrapperVector.emplace_back( pNativeObj );
469 return nIndex;
472 static SbxObject* lcl_getNativeObject( sal_uInt32 nIndex )
474 SbxObjectRef xRetObj;
475 NativeObjectWrapperVector &rNativeObjectWrapperVector = GaNativeObjectWrapperVector::get();
476 if( nIndex < rNativeObjectWrapperVector.size() )
478 ObjectItem& rItem = rNativeObjectWrapperVector[ nIndex ];
479 xRetObj = rItem.m_xNativeObj;
481 return xRetObj.get();
484 // convert from Uno to Sbx
485 static SbxDataType unoToSbxType( TypeClass eType )
487 SbxDataType eRetType = SbxVOID;
489 switch( eType )
491 case TypeClass_INTERFACE:
492 case TypeClass_TYPE:
493 case TypeClass_STRUCT:
494 case TypeClass_EXCEPTION: eRetType = SbxOBJECT; break;
496 case TypeClass_ENUM: eRetType = SbxLONG; break;
497 case TypeClass_SEQUENCE:
498 eRetType = SbxDataType( SbxOBJECT | SbxARRAY );
499 break;
502 case TypeClass_ANY: eRetType = SbxVARIANT; break;
503 case TypeClass_BOOLEAN: eRetType = SbxBOOL; break;
504 case TypeClass_CHAR: eRetType = SbxCHAR; break;
505 case TypeClass_STRING: eRetType = SbxSTRING; break;
506 case TypeClass_FLOAT: eRetType = SbxSINGLE; break;
507 case TypeClass_DOUBLE: eRetType = SbxDOUBLE; break;
508 case TypeClass_BYTE: eRetType = SbxINTEGER; break;
509 case TypeClass_SHORT: eRetType = SbxINTEGER; break;
510 case TypeClass_LONG: eRetType = SbxLONG; break;
511 case TypeClass_HYPER: eRetType = SbxSALINT64; break;
512 case TypeClass_UNSIGNED_SHORT: eRetType = SbxUSHORT; break;
513 case TypeClass_UNSIGNED_LONG: eRetType = SbxULONG; break;
514 case TypeClass_UNSIGNED_HYPER: eRetType = SbxSALUINT64;break;
515 default: break;
517 return eRetType;
520 static SbxDataType unoToSbxType( const Reference< XIdlClass >& xIdlClass )
522 SbxDataType eRetType = SbxVOID;
523 if( xIdlClass.is() )
525 TypeClass eType = xIdlClass->getTypeClass();
526 eRetType = unoToSbxType( eType );
528 return eRetType;
531 static void implSequenceToMultiDimArray( SbxDimArray*& pArray, Sequence< sal_Int32 >& indices, Sequence< sal_Int32 >& sizes, const Any& aValue, sal_Int32 dimension, bool bIsZeroIndex, Type const * pType )
533 const Type& aType = aValue.getValueType();
534 TypeClass eTypeClass = aType.getTypeClass();
536 sal_Int32 dimCopy = dimension;
538 if ( eTypeClass == TypeClass_SEQUENCE )
540 Reference< XIdlClass > xIdlTargetClass = TypeToIdlClass( aType );
541 Reference< XIdlArray > xIdlArray = xIdlTargetClass->getArray();
542 typelib_TypeDescription * pTD = nullptr;
543 aType.getDescription( &pTD );
544 Type aElementType( reinterpret_cast<typelib_IndirectTypeDescription *>(pTD)->pType );
545 ::typelib_typedescription_release( pTD );
547 sal_Int32 nLen = xIdlArray->getLen( aValue );
548 for ( sal_Int32 index = 0; index < nLen; ++index )
550 Any aElementAny = xIdlArray->get( aValue, static_cast<sal_uInt32>(index) );
551 // This detects the dimension were currently processing
552 if ( dimCopy == dimension )
554 ++dimCopy;
555 if ( sizes.getLength() < dimCopy )
557 sizes.realloc( sizes.getLength() + 1 );
558 sizes[ sizes.getLength() - 1 ] = nLen;
559 indices.realloc( indices.getLength() + 1 );
563 if ( bIsZeroIndex )
564 indices[ dimCopy - 1 ] = index;
565 else
566 indices[ dimCopy - 1] = index + 1;
568 implSequenceToMultiDimArray( pArray, indices, sizes, aElementAny, dimCopy, bIsZeroIndex, &aElementType );
572 else
574 if ( !indices.hasElements() )
576 // Should never ever get here ( indices.getLength()
577 // should equal number of dimensions in the array )
578 // And that should at least be 1 !
579 // #QUESTION is there a better error?
580 StarBASIC::Error( ERRCODE_BASIC_INVALID_OBJECT );
581 return;
584 SbxDataType eSbxElementType = unoToSbxType( pType ? pType->getTypeClass() : aValue.getValueTypeClass() );
585 if ( !pArray )
587 pArray = new SbxDimArray( eSbxElementType );
588 sal_Int32 nIndexLen = indices.getLength();
590 // Dimension the array
591 for ( sal_Int32 index = 0; index < nIndexLen; ++index )
593 if ( bIsZeroIndex )
594 pArray->unoAddDim32( 0, sizes[ index ] - 1);
595 else
596 pArray->unoAddDim32( 1, sizes[ index ] );
601 if ( pArray )
603 auto xVar = tools::make_ref<SbxVariable>( eSbxElementType );
604 unoToSbxValue( xVar.get(), aValue );
606 sal_Int32* pIndices = indices.getArray();
607 pArray->Put32( xVar.get(), pIndices );
613 void unoToSbxValue( SbxVariable* pVar, const Any& aValue )
615 const Type& aType = aValue.getValueType();
616 TypeClass eTypeClass = aType.getTypeClass();
617 switch( eTypeClass )
619 case TypeClass_TYPE:
621 // Map Type to IdlClass
622 Type aType_;
623 aValue >>= aType_;
624 Reference<XIdlClass> xClass = TypeToIdlClass( aType_ );
625 Any aClassAny;
626 aClassAny <<= xClass;
628 // instantiate SbUnoObject
629 SbUnoObject* pSbUnoObject = new SbUnoObject( OUString(), aClassAny );
630 SbxObjectRef xWrapper = static_cast<SbxObject*>(pSbUnoObject);
632 // If the object is invalid deliver null
633 if( !pSbUnoObject->getUnoAny().hasValue() )
635 pVar->PutObject( nullptr );
637 else
639 pVar->PutObject( xWrapper.get() );
642 break;
643 // Interfaces and Structs must be wrapped in a SbUnoObject
644 case TypeClass_INTERFACE:
645 case TypeClass_STRUCT:
646 case TypeClass_EXCEPTION:
648 if( eTypeClass == TypeClass_STRUCT )
650 ArrayWrapper aWrap;
651 NativeObjectWrapper aNativeObjectWrapper;
652 if ( aValue >>= aWrap )
654 SbxDimArray* pArray = nullptr;
655 Sequence< sal_Int32 > indices;
656 Sequence< sal_Int32 > sizes;
657 implSequenceToMultiDimArray( pArray, indices, sizes, aWrap.Array, /*dimension*/0, aWrap.IsZeroIndex, nullptr );
658 if ( pArray )
660 SbxDimArrayRef xArray = pArray;
661 SbxFlagBits nFlags = pVar->GetFlags();
662 pVar->ResetFlag( SbxFlagBits::Fixed );
663 pVar->PutObject( xArray.get() );
664 pVar->SetFlags( nFlags );
666 else
667 pVar->PutEmpty();
668 break;
670 else if ( aValue >>= aNativeObjectWrapper )
672 sal_uInt32 nIndex = 0;
673 if( aNativeObjectWrapper.ObjectId >>= nIndex )
675 SbxObject* pObj = lcl_getNativeObject( nIndex );
676 pVar->PutObject( pObj );
678 else
679 pVar->PutEmpty();
680 break;
682 else
684 SbiInstance* pInst = GetSbData()->pInst;
685 if( pInst && pInst->IsCompatibility() )
687 oleautomation::Date aDate;
688 if( aValue >>= aDate )
690 pVar->PutDate( aDate.Value );
691 break;
693 else
695 oleautomation::Decimal aDecimal;
696 if( aValue >>= aDecimal )
698 pVar->PutDecimal( aDecimal );
699 break;
701 else
703 oleautomation::Currency aCurrency;
704 if( aValue >>= aCurrency )
706 pVar->PutCurrency( aCurrency.Value );
707 break;
714 // instantiate a SbUnoObject
715 SbUnoObject* pSbUnoObject = new SbUnoObject( OUString(), aValue );
716 //If this is called externally e.g. from the scripting
717 //framework then there is no 'active' runtime the default property will not be set up
718 //only a vba object will have XDefaultProp set anyway so... this
719 //test seems a bit of overkill
720 //if ( SbiRuntime::isVBAEnabled() )
722 OUString sDfltPropName;
724 if ( SbUnoObject::getDefaultPropName( pSbUnoObject, sDfltPropName ) )
726 pSbUnoObject->SetDfltProperty( sDfltPropName );
729 SbxObjectRef xWrapper = static_cast<SbxObject*>(pSbUnoObject);
731 // If the object is invalid deliver null
732 if( !pSbUnoObject->getUnoAny().hasValue() )
734 pVar->PutObject( nullptr );
736 else
738 pVar->PutObject( xWrapper.get() );
741 break;
744 case TypeClass_ENUM:
746 sal_Int32 nEnum = 0;
747 enum2int( nEnum, aValue );
748 pVar->PutLong( nEnum );
750 break;
752 case TypeClass_SEQUENCE:
754 Reference< XIdlClass > xIdlTargetClass = TypeToIdlClass( aType );
755 Reference< XIdlArray > xIdlArray = xIdlTargetClass->getArray();
756 sal_Int32 i, nLen = xIdlArray->getLen( aValue );
758 typelib_TypeDescription * pTD = nullptr;
759 aType.getDescription( &pTD );
760 assert( pTD && pTD->eTypeClass == typelib_TypeClass_SEQUENCE );
761 Type aElementType( reinterpret_cast<typelib_IndirectTypeDescription *>(pTD)->pType );
762 ::typelib_typedescription_release( pTD );
764 // build an Array in Basic
765 SbxDimArrayRef xArray;
766 SbxDataType eSbxElementType = unoToSbxType( aElementType.getTypeClass() );
767 xArray = new SbxDimArray( eSbxElementType );
768 if( nLen > 0 )
770 xArray->unoAddDim32( 0, nLen - 1 );
772 // register the elements as variables
773 for( i = 0 ; i < nLen ; i++ )
775 // convert elements
776 Any aElementAny = xIdlArray->get( aValue, static_cast<sal_uInt32>(i) );
777 auto xVar = tools::make_ref<SbxVariable>( eSbxElementType );
778 unoToSbxValue( xVar.get(), aElementAny );
780 // put into the Array
781 xArray->Put32( xVar.get(), &i );
784 else
786 xArray->unoAddDim32( 0, -1 );
789 // return the Array
790 SbxFlagBits nFlags = pVar->GetFlags();
791 pVar->ResetFlag( SbxFlagBits::Fixed );
792 pVar->PutObject( xArray.get() );
793 pVar->SetFlags( nFlags );
796 break;
799 case TypeClass_BOOLEAN: pVar->PutBool( *o3tl::forceAccess<bool>(aValue) ); break;
800 case TypeClass_CHAR:
802 pVar->PutChar( *o3tl::forceAccess<sal_Unicode>(aValue) );
803 break;
805 case TypeClass_STRING: { OUString val; aValue >>= val; pVar->PutString( val ); } break;
806 case TypeClass_FLOAT: { float val = 0; aValue >>= val; pVar->PutSingle( val ); } break;
807 case TypeClass_DOUBLE: { double val = 0; aValue >>= val; pVar->PutDouble( val ); } break;
808 case TypeClass_BYTE: { sal_Int8 val = 0; aValue >>= val; pVar->PutInteger( val ); } break;
809 case TypeClass_SHORT: { sal_Int16 val = 0; aValue >>= val; pVar->PutInteger( val ); } break;
810 case TypeClass_LONG: { sal_Int32 val = 0; aValue >>= val; pVar->PutLong( val ); } break;
811 case TypeClass_HYPER: { sal_Int64 val = 0; aValue >>= val; pVar->PutInt64( val ); } break;
812 case TypeClass_UNSIGNED_SHORT: { sal_uInt16 val = 0; aValue >>= val; pVar->PutUShort( val ); } break;
813 case TypeClass_UNSIGNED_LONG: { sal_uInt32 val = 0; aValue >>= val; pVar->PutULong( val ); } break;
814 case TypeClass_UNSIGNED_HYPER: { sal_uInt64 val = 0; aValue >>= val; pVar->PutUInt64( val ); } break;
815 default: pVar->PutEmpty(); break;
819 // Deliver the reflection for Sbx types
820 static Type getUnoTypeForSbxBaseType( SbxDataType eType )
822 Type aRetType = cppu::UnoType<void>::get();
823 switch( eType )
825 case SbxNULL: aRetType = cppu::UnoType<XInterface>::get(); break;
826 case SbxINTEGER: aRetType = cppu::UnoType<sal_Int16>::get(); break;
827 case SbxLONG: aRetType = cppu::UnoType<sal_Int32>::get(); break;
828 case SbxSINGLE: aRetType = cppu::UnoType<float>::get(); break;
829 case SbxDOUBLE: aRetType = cppu::UnoType<double>::get(); break;
830 case SbxCURRENCY: aRetType = cppu::UnoType<oleautomation::Currency>::get(); break;
831 case SbxDECIMAL: aRetType = cppu::UnoType<oleautomation::Decimal>::get(); break;
832 case SbxDATE: {
833 SbiInstance* pInst = GetSbData()->pInst;
834 if( pInst && pInst->IsCompatibility() )
835 aRetType = cppu::UnoType<double>::get();
836 else
837 aRetType = cppu::UnoType<oleautomation::Date>::get();
839 break;
840 case SbxSTRING: aRetType = cppu::UnoType<OUString>::get(); break;
841 case SbxBOOL: aRetType = cppu::UnoType<sal_Bool>::get(); break;
842 case SbxVARIANT: aRetType = cppu::UnoType<Any>::get(); break;
843 case SbxCHAR: aRetType = cppu::UnoType<cppu::UnoCharType>::get(); break;
844 case SbxBYTE: aRetType = cppu::UnoType<sal_Int8>::get(); break;
845 case SbxUSHORT: aRetType = cppu::UnoType<cppu::UnoUnsignedShortType>::get(); break;
846 case SbxULONG: aRetType = ::cppu::UnoType<sal_uInt32>::get(); break;
847 // map machine-dependent ones to long for consistency
848 case SbxINT: aRetType = ::cppu::UnoType<sal_Int32>::get(); break;
849 case SbxUINT: aRetType = ::cppu::UnoType<sal_uInt32>::get(); break;
850 default: break;
852 return aRetType;
855 // Converting of Sbx to Uno without a know target class for TypeClass_ANY
856 static Type getUnoTypeForSbxValue( const SbxValue* pVal )
858 Type aRetType = cppu::UnoType<void>::get();
859 if( !pVal )
860 return aRetType;
862 // convert SbxType to Uno
863 SbxDataType eBaseType = pVal->SbxValue::GetType();
864 if( eBaseType == SbxOBJECT )
866 SbxBaseRef xObj = pVal->GetObject();
867 if( !xObj.is() )
869 aRetType = cppu::UnoType<XInterface>::get();
870 return aRetType;
873 if( auto pArray = dynamic_cast<SbxDimArray*>( xObj.get() ) )
875 sal_Int32 nDims = pArray->GetDims32();
876 Type aElementType = getUnoTypeForSbxBaseType( static_cast<SbxDataType>(pArray->GetType() & 0xfff) );
877 TypeClass eElementTypeClass = aElementType.getTypeClass();
879 // Normal case: One dimensional array
880 sal_Int32 nLower, nUpper;
881 if( nDims == 1 && pArray->GetDim32( 1, nLower, nUpper ) )
883 if( eElementTypeClass == TypeClass_VOID || eElementTypeClass == TypeClass_ANY )
885 // If all elements of the arrays are from the same type, take
886 // this one - otherwise the whole will be considered as Any-Sequence
887 bool bNeedsInit = true;
889 for (sal_Int32 aIdx[1] = { nLower }; aIdx[0] <= nUpper; ++aIdx[0])
891 SbxVariableRef xVar = pArray->Get32(aIdx);
892 Type aType = getUnoTypeForSbxValue( xVar.get() );
893 if( bNeedsInit )
895 if( aType.getTypeClass() == TypeClass_VOID )
897 // if only first element is void: different types -> []any
898 // if all elements are void: []void is not allowed -> []any
899 aElementType = cppu::UnoType<Any>::get();
900 break;
902 aElementType = aType;
903 bNeedsInit = false;
905 else if( aElementType != aType )
907 // different types -> AnySequence
908 aElementType = cppu::UnoType<Any>::get();
909 break;
914 OUString aSeqTypeName = aSeqLevelStr + aElementType.getTypeName();
915 aRetType = Type( TypeClass_SEQUENCE, aSeqTypeName );
917 // #i33795 Map also multi dimensional arrays to corresponding sequences
918 else if( nDims > 1 )
920 if( eElementTypeClass == TypeClass_VOID || eElementTypeClass == TypeClass_ANY )
922 // For this check the array's dim structure does not matter
923 sal_uInt32 nFlatArraySize = pArray->Count32();
925 bool bNeedsInit = true;
926 for( sal_uInt32 i = 0 ; i < nFlatArraySize ; i++ )
928 SbxVariableRef xVar = pArray->SbxArray::Get32( i );
929 Type aType = getUnoTypeForSbxValue( xVar.get() );
930 if( bNeedsInit )
932 if( aType.getTypeClass() == TypeClass_VOID )
934 // if only first element is void: different types -> []any
935 // if all elements are void: []void is not allowed -> []any
936 aElementType = cppu::UnoType<Any>::get();
937 break;
939 aElementType = aType;
940 bNeedsInit = false;
942 else if( aElementType != aType )
944 // different types -> AnySequence
945 aElementType = cppu::UnoType<Any>::get();
946 break;
951 OUStringBuffer aSeqTypeName;
952 for(sal_Int32 iDim = 0 ; iDim < nDims ; iDim++ )
954 aSeqTypeName.append(aSeqLevelStr);
956 aSeqTypeName.append(aElementType.getTypeName());
957 aRetType = Type( TypeClass_SEQUENCE, aSeqTypeName.makeStringAndClear() );
960 // No array, but ...
961 else if( auto obj = dynamic_cast<SbUnoObject*>( xObj.get() ) )
963 aRetType = obj->getUnoAny().getValueType();
965 // SbUnoAnyObject?
966 else if( auto any = dynamic_cast<SbUnoAnyObject*>( xObj.get() ) )
968 aRetType = any->getValue().getValueType();
970 // Otherwise it is a No-Uno-Basic-Object -> default==deliver void
972 // No object, convert basic type
973 else
975 aRetType = getUnoTypeForSbxBaseType( eBaseType );
977 return aRetType;
980 // converting of Sbx to Uno without known target class for TypeClass_ANY
981 static Any sbxToUnoValueImpl( const SbxValue* pVar, bool bBlockConversionToSmallestType = false )
983 SbxDataType eBaseType = pVar->SbxValue::GetType();
984 if( eBaseType == SbxOBJECT )
986 SbxBaseRef xObj = pVar->GetObject();
987 if( xObj.is() )
989 if( auto obj = dynamic_cast<SbUnoAnyObject*>( xObj.get() ) )
990 return obj->getValue();
991 if( auto pClassModuleObj = dynamic_cast<SbClassModuleObject*>( xObj.get() ) )
993 Any aRetAny;
994 SbModule* pClassModule = pClassModuleObj->getClassModule();
995 if( pClassModule->createCOMWrapperForIface( aRetAny, pClassModuleObj ) )
996 return aRetAny;
998 if( dynamic_cast<const SbUnoObject*>( xObj.get() ) == nullptr )
1000 // Create NativeObjectWrapper to identify object in case of callbacks
1001 SbxObject* pObj = dynamic_cast<SbxObject*>( pVar->GetObject() );
1002 if( pObj != nullptr )
1004 NativeObjectWrapper aNativeObjectWrapper;
1005 sal_uInt32 nIndex = lcl_registerNativeObjectWrapper( pObj );
1006 aNativeObjectWrapper.ObjectId <<= nIndex;
1007 Any aRetAny;
1008 aRetAny <<= aNativeObjectWrapper;
1009 return aRetAny;
1015 Type aType = getUnoTypeForSbxValue( pVar );
1016 TypeClass eType = aType.getTypeClass();
1018 if( !bBlockConversionToSmallestType )
1020 // #79615 Choose "smallest" representation for int values
1021 // because up cast is allowed, downcast not
1022 switch( eType )
1024 case TypeClass_FLOAT:
1025 case TypeClass_DOUBLE:
1027 double d = pVar->GetDouble();
1028 if( rtl::math::approxEqual(d, floor( d )) )
1030 if( d >= -128 && d <= 127 )
1031 aType = ::cppu::UnoType<sal_Int8>::get();
1032 else if( d >= SbxMININT && d <= SbxMAXINT )
1033 aType = ::cppu::UnoType<sal_Int16>::get();
1034 else if( d >= -SbxMAXLNG && d <= SbxMAXLNG )
1035 aType = ::cppu::UnoType<sal_Int32>::get();
1037 break;
1039 case TypeClass_SHORT:
1041 sal_Int16 n = pVar->GetInteger();
1042 if( n >= -128 && n <= 127 )
1043 aType = ::cppu::UnoType<sal_Int8>::get();
1044 break;
1046 case TypeClass_LONG:
1048 sal_Int32 n = pVar->GetLong();
1049 if( n >= -128 && n <= 127 )
1050 aType = ::cppu::UnoType<sal_Int8>::get();
1051 else if( n >= SbxMININT && n <= SbxMAXINT )
1052 aType = ::cppu::UnoType<sal_Int16>::get();
1053 break;
1055 case TypeClass_UNSIGNED_SHORT:
1057 sal_uInt16 n = pVar->GetUShort();
1058 if( n <= 255 )
1059 aType = cppu::UnoType<sal_uInt8>::get();
1060 break;
1062 case TypeClass_UNSIGNED_LONG:
1064 sal_uInt32 n = pVar->GetLong();
1065 if( n <= 255 )
1066 aType = cppu::UnoType<sal_uInt8>::get();
1067 else if( n <= SbxMAXUINT )
1068 aType = cppu::UnoType<cppu::UnoUnsignedShortType>::get();
1069 break;
1071 // TODO: need to add hyper types ?
1072 default: break;
1076 return sbxToUnoValue( pVar, aType );
1080 // Helper function for StepREDIMP
1081 static Any implRekMultiDimArrayToSequence( SbxDimArray* pArray,
1082 const Type& aElemType, sal_Int32 nMaxDimIndex, sal_Int32 nActualDim,
1083 sal_Int32* pActualIndices, sal_Int32* pLowerBounds, sal_Int32* pUpperBounds )
1085 sal_Int32 nSeqLevel = nMaxDimIndex - nActualDim + 1;
1086 OUStringBuffer aSeqTypeName;
1087 sal_Int32 i;
1088 for( i = 0 ; i < nSeqLevel ; i++ )
1090 aSeqTypeName.append(aSeqLevelStr);
1092 aSeqTypeName.append(aElemType.getTypeName());
1093 Type aSeqType( TypeClass_SEQUENCE, aSeqTypeName.makeStringAndClear() );
1095 // Create Sequence instance
1096 Any aRetVal;
1097 Reference< XIdlClass > xIdlTargetClass = TypeToIdlClass( aSeqType );
1098 xIdlTargetClass->createObject( aRetVal );
1100 // Alloc sequence according to array bounds
1101 sal_Int32 nUpper = pUpperBounds[nActualDim];
1102 sal_Int32 nLower = pLowerBounds[nActualDim];
1103 sal_Int32 nSeqSize = nUpper - nLower + 1;
1104 Reference< XIdlArray > xArray = xIdlTargetClass->getArray();
1105 xArray->realloc( aRetVal, nSeqSize );
1107 sal_Int32& ri = pActualIndices[nActualDim];
1109 for( ri = nLower,i = 0 ; ri <= nUpper ; ri++,i++ )
1111 Any aElementVal;
1113 if( nActualDim < nMaxDimIndex )
1115 aElementVal = implRekMultiDimArrayToSequence( pArray, aElemType,
1116 nMaxDimIndex, nActualDim + 1, pActualIndices, pLowerBounds, pUpperBounds );
1118 else
1120 SbxVariable* pSource = pArray->Get32( pActualIndices );
1121 aElementVal = sbxToUnoValue( pSource, aElemType );
1126 // transfer to the sequence
1127 xArray->set( aRetVal, i, aElementVal );
1129 catch( const IllegalArgumentException& )
1131 StarBASIC::Error( ERRCODE_BASIC_EXCEPTION,
1132 implGetExceptionMsg( ::cppu::getCaughtException() ) );
1134 catch (const IndexOutOfBoundsException&)
1136 StarBASIC::Error( ERRCODE_BASIC_OUT_OF_RANGE );
1139 return aRetVal;
1142 // Map old interface
1143 Any sbxToUnoValue( const SbxValue* pVar )
1145 return sbxToUnoValueImpl( pVar );
1148 // function to find a global identifier in
1149 // the UnoScope and to wrap it for Sbx
1150 static bool implGetTypeByName( const OUString& rName, Type& rRetType )
1152 bool bSuccess = false;
1154 const Reference< XHierarchicalNameAccess >& xTypeAccess = getTypeProvider_Impl();
1155 if( xTypeAccess->hasByHierarchicalName( rName ) )
1157 Any aRet = xTypeAccess->getByHierarchicalName( rName );
1158 Reference< XTypeDescription > xTypeDesc;
1159 aRet >>= xTypeDesc;
1161 if( xTypeDesc.is() )
1163 rRetType = Type( xTypeDesc->getTypeClass(), xTypeDesc->getName() );
1164 bSuccess = true;
1167 return bSuccess;
1171 // converting of Sbx to Uno with known target class
1172 Any sbxToUnoValue( const SbxValue* pVar, const Type& rType, Property const * pUnoProperty )
1174 Any aRetVal;
1176 // #94560 No conversion of empty/void for MAYBE_VOID properties
1177 if( pUnoProperty && pUnoProperty->Attributes & PropertyAttribute::MAYBEVOID )
1179 if( pVar->IsEmpty() )
1180 return aRetVal;
1183 SbxDataType eBaseType = pVar->SbxValue::GetType();
1184 if( eBaseType == SbxOBJECT )
1186 SbxBaseRef xObj = pVar->GetObject();
1187 if ( auto obj = dynamic_cast<SbUnoAnyObject*>( xObj.get() ) )
1189 return obj->getValue();
1193 TypeClass eType = rType.getTypeClass();
1194 switch( eType )
1196 case TypeClass_INTERFACE:
1197 case TypeClass_STRUCT:
1198 case TypeClass_EXCEPTION:
1200 Reference< XIdlClass > xIdlTargetClass = TypeToIdlClass( rType );
1202 // null reference?
1203 if( pVar->IsNull() && eType == TypeClass_INTERFACE )
1205 Reference< XInterface > xRef;
1206 OUString aClassName = xIdlTargetClass->getName();
1207 Type aClassType( xIdlTargetClass->getTypeClass(), aClassName );
1208 aRetVal.setValue( &xRef, aClassType );
1210 else
1212 // #112368 Special conversion for Decimal, Currency and Date
1213 if( eType == TypeClass_STRUCT )
1215 SbiInstance* pInst = GetSbData()->pInst;
1216 if( pInst && pInst->IsCompatibility() )
1218 if( rType == cppu::UnoType<oleautomation::Decimal>::get())
1220 oleautomation::Decimal aDecimal;
1221 pVar->fillAutomationDecimal( aDecimal );
1222 aRetVal <<= aDecimal;
1223 break;
1225 else if( rType == cppu::UnoType<oleautomation::Currency>::get())
1227 // assumes per previous code that ole Currency is Int64
1228 aRetVal <<= pVar->GetInt64();
1229 break;
1231 else if( rType == cppu::UnoType<oleautomation::Date>::get())
1233 oleautomation::Date aDate;
1234 aDate.Value = pVar->GetDate();
1235 aRetVal <<= aDate;
1236 break;
1241 SbxBaseRef pObj = pVar->GetObject();
1242 if( auto obj = dynamic_cast<SbUnoObject*>( pObj.get() ) )
1244 aRetVal = obj->getUnoAny();
1246 else if( auto structRef = dynamic_cast<SbUnoStructRefObject*>( pObj.get() ) )
1248 aRetVal = structRef->getUnoAny();
1250 else
1252 // null object -> null XInterface
1253 Reference<XInterface> xInt;
1254 aRetVal <<= xInt;
1258 break;
1260 case TypeClass_TYPE:
1262 if( eBaseType == SbxOBJECT )
1264 // XIdlClass?
1265 Reference< XIdlClass > xIdlClass;
1267 SbxBaseRef pObj = pVar->GetObject();
1268 if( auto obj = dynamic_cast<SbUnoObject*>( pObj.get() ) )
1270 Any aUnoAny = obj->getUnoAny();
1271 aUnoAny >>= xIdlClass;
1274 if( xIdlClass.is() )
1276 OUString aClassName = xIdlClass->getName();
1277 Type aType( xIdlClass->getTypeClass(), aClassName );
1278 aRetVal <<= aType;
1281 else if( eBaseType == SbxSTRING )
1283 OUString aTypeName = pVar->GetOUString();
1284 Type aType;
1285 bool bSuccess = implGetTypeByName( aTypeName, aType );
1286 if( bSuccess )
1288 aRetVal <<= aType;
1292 break;
1295 case TypeClass_ENUM:
1297 aRetVal = int2enum( pVar->GetLong(), rType );
1299 break;
1301 case TypeClass_SEQUENCE:
1303 SbxBaseRef xObj = pVar->GetObject();
1304 if( auto pArray = dynamic_cast<SbxDimArray*>( xObj.get() ) )
1306 sal_Int32 nDims = pArray->GetDims32();
1308 // Normal case: One dimensional array
1309 sal_Int32 nLower, nUpper;
1310 if( nDims == 1 && pArray->GetDim32( 1, nLower, nUpper ) )
1312 sal_Int32 nSeqSize = nUpper - nLower + 1;
1314 // create the instance of the required sequence
1315 Reference< XIdlClass > xIdlTargetClass = TypeToIdlClass( rType );
1316 xIdlTargetClass->createObject( aRetVal );
1317 Reference< XIdlArray > xArray = xIdlTargetClass->getArray();
1318 xArray->realloc( aRetVal, nSeqSize );
1320 // Element-Type
1321 OUString aClassName = xIdlTargetClass->getName();
1322 typelib_TypeDescription * pSeqTD = nullptr;
1323 typelib_typedescription_getByName( &pSeqTD, aClassName.pData );
1324 assert( pSeqTD );
1325 Type aElemType( reinterpret_cast<typelib_IndirectTypeDescription *>(pSeqTD)->pType );
1327 // convert all array member and register them
1328 sal_Int32 aIdx[1];
1329 aIdx[0] = nLower;
1330 for (sal_Int32 i = 0 ; i < nSeqSize; ++i, ++aIdx[0])
1332 SbxVariableRef xVar = pArray->Get32(aIdx);
1334 // Convert the value of Sbx to Uno
1335 Any aAnyValue = sbxToUnoValue( xVar.get(), aElemType );
1339 // insert in the sequence
1340 xArray->set( aRetVal, i, aAnyValue );
1342 catch( const IllegalArgumentException& )
1344 StarBASIC::Error( ERRCODE_BASIC_EXCEPTION,
1345 implGetExceptionMsg( ::cppu::getCaughtException() ) );
1347 catch (const IndexOutOfBoundsException&)
1349 StarBASIC::Error( ERRCODE_BASIC_OUT_OF_RANGE );
1353 // #i33795 Map also multi dimensional arrays to corresponding sequences
1354 else if( nDims > 1 )
1356 // Element-Type
1357 typelib_TypeDescription * pSeqTD = nullptr;
1358 Type aCurType( rType );
1359 sal_Int32 nSeqLevel = 0;
1360 Type aElemType;
1363 OUString aTypeName = aCurType.getTypeName();
1364 typelib_typedescription_getByName( &pSeqTD, aTypeName.pData );
1365 assert( pSeqTD );
1366 if( pSeqTD->eTypeClass == typelib_TypeClass_SEQUENCE )
1368 aCurType = Type( reinterpret_cast<typelib_IndirectTypeDescription *>(pSeqTD)->pType );
1369 nSeqLevel++;
1371 else
1373 aElemType = aCurType;
1374 break;
1377 while( true );
1379 if( nSeqLevel == nDims )
1381 std::unique_ptr<sal_Int32[]> pLowerBounds(new sal_Int32[nDims]);
1382 std::unique_ptr<sal_Int32[]> pUpperBounds(new sal_Int32[nDims]);
1383 std::unique_ptr<sal_Int32[]> pActualIndices(new sal_Int32[nDims]);
1384 for(sal_Int32 i = 1 ; i <= nDims ; i++ )
1386 sal_Int32 lBound, uBound;
1387 pArray->GetDim32( i, lBound, uBound );
1389 sal_Int32 j = i - 1;
1390 pActualIndices[j] = pLowerBounds[j] = lBound;
1391 pUpperBounds[j] = uBound;
1394 aRetVal = implRekMultiDimArrayToSequence( pArray, aElemType,
1395 nDims - 1, 0, pActualIndices.get(), pLowerBounds.get(), pUpperBounds.get() );
1400 break;
1403 // for Any use the class independent converting routine
1404 case TypeClass_ANY:
1406 aRetVal = sbxToUnoValueImpl( pVar );
1408 break;
1410 case TypeClass_BOOLEAN:
1412 aRetVal <<= pVar->GetBool();
1413 break;
1415 case TypeClass_CHAR:
1417 aRetVal <<= pVar->GetChar();
1418 break;
1420 case TypeClass_STRING: aRetVal <<= pVar->GetOUString(); break;
1421 case TypeClass_FLOAT: aRetVal <<= pVar->GetSingle(); break;
1422 case TypeClass_DOUBLE: aRetVal <<= pVar->GetDouble(); break;
1424 case TypeClass_BYTE:
1426 sal_Int16 nVal = pVar->GetInteger();
1427 bool bOverflow = false;
1428 if( nVal < -128 )
1430 bOverflow = true;
1431 nVal = -128;
1433 else if( nVal > 255 ) // 128..255 map to -128..-1
1435 bOverflow = true;
1436 nVal = 127;
1438 if( bOverflow )
1439 StarBASIC::Error( ERRCODE_BASIC_MATH_OVERFLOW );
1441 sal_Int8 nByteVal = static_cast<sal_Int8>(nVal);
1442 aRetVal <<= nByteVal;
1443 break;
1445 case TypeClass_SHORT: aRetVal <<= pVar->GetInteger(); break;
1446 case TypeClass_LONG: aRetVal <<= pVar->GetLong(); break;
1447 case TypeClass_HYPER: aRetVal <<= pVar->GetInt64(); break;
1448 case TypeClass_UNSIGNED_SHORT: aRetVal <<= pVar->GetUShort(); break;
1449 case TypeClass_UNSIGNED_LONG: aRetVal <<= pVar->GetULong(); break;
1450 case TypeClass_UNSIGNED_HYPER: aRetVal <<= pVar->GetUInt64(); break;
1451 default: break;
1454 return aRetVal;
1457 static void processAutomationParams( SbxArray* pParams, Sequence< Any >& args, sal_uInt32 nParamCount )
1459 AutomationNamedArgsSbxArray* pArgNamesArray = dynamic_cast<AutomationNamedArgsSbxArray*>( pParams );
1461 args.realloc( nParamCount );
1462 Any* pAnyArgs = args.getArray();
1463 bool bBlockConversionToSmallestType = GetSbData()->pInst->IsCompatibility();
1464 sal_uInt32 i = 0;
1465 if( pArgNamesArray )
1467 Sequence< OUString >& rNameSeq = pArgNamesArray->getNames();
1468 OUString* pNames = rNameSeq.getArray();
1469 Any aValAny;
1470 for( i = 0 ; i < nParamCount ; i++ )
1472 sal_uInt32 iSbx = i + 1;
1474 aValAny = sbxToUnoValueImpl( pParams->Get32( iSbx ),
1475 bBlockConversionToSmallestType );
1477 OUString aParamName = pNames[iSbx];
1478 if( !aParamName.isEmpty() )
1480 oleautomation::NamedArgument aNamedArgument;
1481 aNamedArgument.Name = aParamName;
1482 aNamedArgument.Value = aValAny;
1483 pAnyArgs[i] <<= aNamedArgument;
1485 else
1487 pAnyArgs[i] = aValAny;
1491 else
1493 for( i = 0 ; i < nParamCount ; i++ )
1495 pAnyArgs[i] = sbxToUnoValueImpl(pParams->Get32(i + 1),
1496 bBlockConversionToSmallestType );
1502 namespace {
1504 enum class INVOKETYPE
1506 GetProp = 0,
1507 Func
1512 static Any invokeAutomationMethod( const OUString& Name, Sequence< Any > const & args, SbxArray* pParams, sal_uInt32 nParamCount, Reference< XInvocation > const & rxInvocation, INVOKETYPE invokeType )
1514 Sequence< sal_Int16 > OutParamIndex;
1515 Sequence< Any > OutParam;
1517 Any aRetAny;
1518 switch( invokeType )
1520 case INVOKETYPE::Func:
1521 aRetAny = rxInvocation->invoke( Name, args, OutParamIndex, OutParam );
1522 break;
1523 case INVOKETYPE::GetProp:
1525 Reference< XAutomationInvocation > xAutoInv( rxInvocation, UNO_QUERY );
1526 aRetAny = xAutoInv->invokeGetProperty( Name, args, OutParamIndex, OutParam );
1527 break;
1529 default:
1530 assert(false); break;
1533 const sal_Int16* pIndices = OutParamIndex.getConstArray();
1534 sal_uInt32 nLen = OutParamIndex.getLength();
1535 if( nLen )
1537 const Any* pNewValues = OutParam.getConstArray();
1538 for( sal_uInt32 j = 0 ; j < nLen ; j++ )
1540 sal_Int16 iTarget = pIndices[ j ];
1541 if( iTarget >= static_cast<sal_Int16>(nParamCount) )
1542 break;
1543 unoToSbxValue( pParams->Get32(j + 1), pNewValues[ j ] );
1546 return aRetAny;
1549 // Debugging help method to readout the implemented interfaces of an object
1550 static OUString Impl_GetInterfaceInfo( const Reference< XInterface >& x, const Reference< XIdlClass >& xClass, sal_uInt16 nRekLevel )
1552 Type aIfaceType = cppu::UnoType<XInterface>::get();
1553 static Reference< XIdlClass > xIfaceClass = TypeToIdlClass( aIfaceType );
1555 OUStringBuffer aRetStr;
1556 for( sal_uInt16 i = 0 ; i < nRekLevel ; i++ )
1557 aRetStr.append( " " );
1558 aRetStr.append( xClass->getName() );
1559 OUString aClassName = xClass->getName();
1560 Type aClassType( xClass->getTypeClass(), aClassName );
1562 // checking if the interface is really supported
1563 if( !x->queryInterface( aClassType ).hasValue() )
1565 aRetStr.append( " (ERROR: Not really supported!)\n" );
1567 // Are there super interfaces?
1568 else
1570 aRetStr.append( "\n" );
1572 // get the super interfaces
1573 Sequence< Reference< XIdlClass > > aSuperClassSeq = xClass->getSuperclasses();
1574 const Reference< XIdlClass >* pClasses = aSuperClassSeq.getConstArray();
1575 sal_uInt32 nSuperIfaceCount = aSuperClassSeq.getLength();
1576 for( sal_uInt32 j = 0 ; j < nSuperIfaceCount ; j++ )
1578 const Reference< XIdlClass >& rxIfaceClass = pClasses[j];
1579 if( !rxIfaceClass->equals( xIfaceClass ) )
1580 aRetStr.append( Impl_GetInterfaceInfo( x, rxIfaceClass, nRekLevel + 1 ) );
1583 return aRetStr.makeStringAndClear();
1586 static OUString getDbgObjectNameImpl(SbUnoObject& rUnoObj)
1588 OUString aName = rUnoObj.GetClassName();
1589 if( aName.isEmpty() )
1591 Any aToInspectObj = rUnoObj.getUnoAny();
1592 Reference< XInterface > xObj(aToInspectObj, css::uno::UNO_QUERY);
1593 if( xObj.is() )
1595 Reference< XServiceInfo > xServiceInfo( xObj, UNO_QUERY );
1596 if( xServiceInfo.is() )
1597 aName = xServiceInfo->getImplementationName();
1600 return aName;
1603 static OUString getDbgObjectName(SbUnoObject& rUnoObj)
1605 OUString aName = getDbgObjectNameImpl(rUnoObj);
1606 if( aName.isEmpty() )
1607 aName += "Unknown";
1609 OUStringBuffer aRet;
1610 if( aName.getLength() > 20 )
1612 aRet.append( "\n" );
1614 aRet.append( "\"" );
1615 aRet.append( aName );
1616 aRet.append( "\":" );
1617 return aRet.makeStringAndClear();
1620 OUString getBasicObjectTypeName( SbxObject* pObj )
1622 if (pObj)
1624 if (SbUnoObject* pUnoObj = dynamic_cast<SbUnoObject*>(pObj))
1626 return getDbgObjectNameImpl(*pUnoObj);
1628 else if (SbUnoStructRefObject* pUnoStructObj = dynamic_cast<SbUnoStructRefObject*>(pObj))
1630 return pUnoStructObj->GetClassName();
1633 return OUString();
1636 namespace {
1638 bool matchesBasicTypeName(
1639 css::uno::Reference<css::reflection::XIdlClass> const & unoType, OUString const & basicTypeName)
1641 if (unoType->getName().endsWithIgnoreAsciiCase(basicTypeName)) {
1642 return true;
1644 auto const sups = unoType->getSuperclasses();
1645 return std::any_of(
1646 sups.begin(), sups.end(),
1647 [&basicTypeName](auto const & t) { return matchesBasicTypeName(t, basicTypeName); });
1652 bool checkUnoObjectType(SbUnoObject& rUnoObj, const OUString& rClass)
1654 Any aToInspectObj = rUnoObj.getUnoAny();
1656 // Return true for XInvocation based objects as interface type names don't count then
1657 Reference< XInvocation > xInvocation( aToInspectObj, UNO_QUERY );
1658 if( xInvocation.is() )
1660 return true;
1662 bool bResult = false;
1663 Reference< XTypeProvider > xTypeProvider( aToInspectObj, UNO_QUERY );
1664 if( xTypeProvider.is() )
1666 /* Although interfaces in the ooo.vba namespace obey the IDL rules and
1667 have a leading 'X', in Basic we want to be able to do something
1668 like 'Dim wb As Workbooks' or 'Dim lb As MSForms.Label'. Here we
1669 add a leading 'X' to the class name and a leading dot to the entire
1670 type name. This results e.g. in '.XWorkbooks' or '.MSForms.XLabel'
1671 which matches the interface names 'ooo.vba.excel.XWorkbooks' or
1672 'ooo.vba.msforms.XLabel'.
1674 OUString aClassName;
1675 if ( SbiRuntime::isVBAEnabled() )
1677 aClassName = ".";
1678 sal_Int32 nClassNameDot = rClass.lastIndexOf( '.' );
1679 if( nClassNameDot >= 0 )
1681 aClassName += OUString::Concat(rClass.subView( 0, nClassNameDot + 1 )) + "X" + rClass.subView( nClassNameDot + 1 );
1683 else
1685 aClassName += "X" + rClass;
1688 else // assume extended type declaration support for basic ( can't get here
1689 // otherwise.
1690 aClassName = rClass;
1692 Sequence< Type > aTypeSeq = xTypeProvider->getTypes();
1693 const Type* pTypeArray = aTypeSeq.getConstArray();
1694 sal_uInt32 nIfaceCount = aTypeSeq.getLength();
1695 for( sal_uInt32 j = 0 ; j < nIfaceCount ; j++ )
1697 const Type& rType = pTypeArray[j];
1699 Reference<XIdlClass> xClass = TypeToIdlClass( rType );
1700 if( !xClass.is() )
1702 OSL_FAIL("failed to get XIdlClass for type");
1703 break;
1705 OUString aInterfaceName = xClass->getName();
1706 if ( aInterfaceName == "com.sun.star.bridge.oleautomation.XAutomationObject" )
1708 // there is a hack in the extensions/source/ole/oleobj.cxx to return the typename of the automation object, lets check if it
1709 // matches
1710 Reference< XInvocation > xInv( aToInspectObj, UNO_QUERY );
1711 if ( xInv.is() )
1713 OUString sTypeName;
1714 xInv->getValue( "$GetTypeName" ) >>= sTypeName;
1715 if ( sTypeName.isEmpty() || sTypeName == "IDispatch" )
1717 // can't check type, leave it pass
1718 bResult = true;
1720 else
1722 bResult = sTypeName == rClass;
1725 break; // finished checking automation object
1728 if ( matchesBasicTypeName(xClass, aClassName) )
1730 bResult = true;
1731 break;
1735 return bResult;
1738 // Debugging help method to readout the implemented interfaces of an object
1739 static OUString Impl_GetSupportedInterfaces(SbUnoObject& rUnoObj)
1741 Any aToInspectObj = rUnoObj.getUnoAny();
1743 // allow only TypeClass interface
1744 OUStringBuffer aRet;
1745 auto x = o3tl::tryAccess<Reference<XInterface>>(aToInspectObj);
1746 if( !x )
1748 aRet.append( ID_DBG_SUPPORTEDINTERFACES );
1749 aRet.append( " not available.\n(TypeClass is not TypeClass_INTERFACE)\n" );
1751 else
1753 Reference< XTypeProvider > xTypeProvider( *x, UNO_QUERY );
1755 aRet.append( "Supported interfaces by object " );
1756 aRet.append(getDbgObjectName(rUnoObj));
1757 aRet.append( "\n" );
1758 if( xTypeProvider.is() )
1760 // get the interfaces of the implementation
1761 Sequence< Type > aTypeSeq = xTypeProvider->getTypes();
1762 const Type* pTypeArray = aTypeSeq.getConstArray();
1763 sal_uInt32 nIfaceCount = aTypeSeq.getLength();
1764 for( sal_uInt32 j = 0 ; j < nIfaceCount ; j++ )
1766 const Type& rType = pTypeArray[j];
1768 Reference<XIdlClass> xClass = TypeToIdlClass( rType );
1769 if( xClass.is() )
1771 aRet.append( Impl_GetInterfaceInfo( *x, xClass, 1 ) );
1773 else
1775 typelib_TypeDescription * pTD = nullptr;
1776 rType.getDescription( &pTD );
1778 aRet.append( "*** ERROR: No IdlClass for type \"" );
1779 aRet.append( pTD->pTypeName );
1780 aRet.append( "\"\n*** Please check type library\n" );
1785 return aRet.makeStringAndClear();
1789 // Debugging help method SbxDataType -> String
1790 static OUString Dbg_SbxDataType2String( SbxDataType eType )
1792 OUStringBuffer aRet;
1793 switch( +eType )
1795 case SbxEMPTY: aRet.append("SbxEMPTY"); break;
1796 case SbxNULL: aRet.append("SbxNULL"); break;
1797 case SbxINTEGER: aRet.append("SbxINTEGER"); break;
1798 case SbxLONG: aRet.append("SbxLONG"); break;
1799 case SbxSINGLE: aRet.append("SbxSINGLE"); break;
1800 case SbxDOUBLE: aRet.append("SbxDOUBLE"); break;
1801 case SbxCURRENCY: aRet.append("SbxCURRENCY"); break;
1802 case SbxDECIMAL: aRet.append("SbxDECIMAL"); break;
1803 case SbxDATE: aRet.append("SbxDATE"); break;
1804 case SbxSTRING: aRet.append("SbxSTRING"); break;
1805 case SbxOBJECT: aRet.append("SbxOBJECT"); break;
1806 case SbxERROR: aRet.append("SbxERROR"); break;
1807 case SbxBOOL: aRet.append("SbxBOOL"); break;
1808 case SbxVARIANT: aRet.append("SbxVARIANT"); break;
1809 case SbxDATAOBJECT: aRet.append("SbxDATAOBJECT"); break;
1810 case SbxCHAR: aRet.append("SbxCHAR"); break;
1811 case SbxBYTE: aRet.append("SbxBYTE"); break;
1812 case SbxUSHORT: aRet.append("SbxUSHORT"); break;
1813 case SbxULONG: aRet.append("SbxULONG"); break;
1814 case SbxSALINT64: aRet.append("SbxINT64"); break;
1815 case SbxSALUINT64: aRet.append("SbxUINT64"); break;
1816 case SbxINT: aRet.append("SbxINT"); break;
1817 case SbxUINT: aRet.append("SbxUINT"); break;
1818 case SbxVOID: aRet.append("SbxVOID"); break;
1819 case SbxHRESULT: aRet.append("SbxHRESULT"); break;
1820 case SbxPOINTER: aRet.append("SbxPOINTER"); break;
1821 case SbxDIMARRAY: aRet.append("SbxDIMARRAY"); break;
1822 case SbxCARRAY: aRet.append("SbxCARRAY"); break;
1823 case SbxUSERDEF: aRet.append("SbxUSERDEF"); break;
1824 case SbxLPSTR: aRet.append("SbxLPSTR"); break;
1825 case SbxLPWSTR: aRet.append("SbxLPWSTR"); break;
1826 case SbxCoreSTRING: aRet.append("SbxCoreSTRING"); break;
1827 case SbxOBJECT | SbxARRAY: aRet.append("SbxARRAY"); break;
1828 default: aRet.append("Unknown Sbx-Type!");break;
1830 return aRet.makeStringAndClear();
1833 // Debugging help method to display the properties of a SbUnoObjects
1834 static OUString Impl_DumpProperties(SbUnoObject& rUnoObj)
1836 OUStringBuffer aRet;
1837 aRet.append("Properties of object ");
1838 aRet.append(getDbgObjectName(rUnoObj));
1840 // analyse the Uno-Infos to recognise the arrays
1841 Reference< XIntrospectionAccess > xAccess = rUnoObj.getIntrospectionAccess();
1842 if( !xAccess.is() )
1844 Reference< XInvocation > xInvok = rUnoObj.getInvocation();
1845 if( xInvok.is() )
1846 xAccess = xInvok->getIntrospection();
1848 if( !xAccess.is() )
1850 aRet.append( "\nUnknown, no introspection available\n" );
1851 return aRet.makeStringAndClear();
1854 Sequence<Property> props = xAccess->getProperties( PropertyConcept::ALL - PropertyConcept::DANGEROUS );
1855 sal_uInt32 nUnoPropCount = props.getLength();
1856 const Property* pUnoProps = props.getConstArray();
1858 SbxArray* pProps = rUnoObj.GetProperties();
1859 sal_uInt32 nPropCount = pProps->Count32();
1860 sal_uInt32 nPropsPerLine = 1 + nPropCount / 30;
1861 for( sal_uInt32 i = 0; i < nPropCount; i++ )
1863 SbxVariable* pVar = pProps->Get32( i );
1864 if( pVar )
1866 OUStringBuffer aPropStr;
1867 if( (i % nPropsPerLine) == 0 )
1868 aPropStr.append( "\n" );
1870 // output the type and name
1871 // Is it in Uno a sequence?
1872 SbxDataType eType = pVar->GetFullType();
1874 bool bMaybeVoid = false;
1875 if( i < nUnoPropCount )
1877 const Property& rProp = pUnoProps[ i ];
1879 // For MAYBEVOID freshly convert the type from Uno,
1880 // so not just SbxEMPTY is returned.
1881 if( rProp.Attributes & PropertyAttribute::MAYBEVOID )
1883 eType = unoToSbxType( rProp.Type.getTypeClass() );
1884 bMaybeVoid = true;
1886 if( eType == SbxOBJECT )
1888 Type aType = rProp.Type;
1889 if( aType.getTypeClass() == TypeClass_SEQUENCE )
1890 eType = SbxDataType( SbxOBJECT | SbxARRAY );
1893 aPropStr.append( Dbg_SbxDataType2String( eType ) );
1894 if( bMaybeVoid )
1895 aPropStr.append( "/void" );
1896 aPropStr.append( " " );
1897 aPropStr.append( pVar->GetName() );
1899 if( i == nPropCount - 1 )
1900 aPropStr.append( "\n" );
1901 else
1902 aPropStr.append( "; " );
1904 aRet.append( aPropStr.makeStringAndClear() );
1907 return aRet.makeStringAndClear();
1910 // Debugging help method to display the methods of an SbUnoObjects
1911 static OUString Impl_DumpMethods(SbUnoObject& rUnoObj)
1913 OUStringBuffer aRet;
1914 aRet.append("Methods of object ");
1915 aRet.append(getDbgObjectName(rUnoObj));
1917 // XIntrospectionAccess, so that the types of the parameter could be outputted
1918 Reference< XIntrospectionAccess > xAccess = rUnoObj.getIntrospectionAccess();
1919 if( !xAccess.is() )
1921 Reference< XInvocation > xInvok = rUnoObj.getInvocation();
1922 if( xInvok.is() )
1923 xAccess = xInvok->getIntrospection();
1925 if( !xAccess.is() )
1927 aRet.append( "\nUnknown, no introspection available\n" );
1928 return aRet.makeStringAndClear();
1930 Sequence< Reference< XIdlMethod > > methods = xAccess->getMethods
1931 ( MethodConcept::ALL - MethodConcept::DANGEROUS );
1932 const Reference< XIdlMethod >* pUnoMethods = methods.getConstArray();
1934 SbxArray* pMethods = rUnoObj.GetMethods();
1935 sal_uInt32 nMethodCount = pMethods->Count32();
1936 if( !nMethodCount )
1938 aRet.append( "\nNo methods found\n" );
1939 return aRet.makeStringAndClear();
1941 sal_uInt32 nPropsPerLine = 1 + nMethodCount / 30;
1942 for( sal_uInt32 i = 0; i < nMethodCount; i++ )
1944 SbxVariable* pVar = pMethods->Get32( i );
1945 if( pVar )
1947 if( (i % nPropsPerLine) == 0 )
1948 aRet.append( "\n" );
1950 // address the method
1951 const Reference< XIdlMethod >& rxMethod = pUnoMethods[i];
1953 // Is it in Uno a sequence?
1954 SbxDataType eType = pVar->GetFullType();
1955 if( eType == SbxOBJECT )
1957 Reference< XIdlClass > xClass = rxMethod->getReturnType();
1958 if( xClass.is() && xClass->getTypeClass() == TypeClass_SEQUENCE )
1959 eType = SbxDataType( SbxOBJECT | SbxARRAY );
1961 // output the name and the type
1962 aRet.append( Dbg_SbxDataType2String( eType ) );
1963 aRet.append( " " );
1964 aRet.append ( pVar->GetName() );
1965 aRet.append( " ( " );
1967 // the get-method mustn't have a parameter
1968 Sequence< Reference< XIdlClass > > aParamsSeq = rxMethod->getParameterTypes();
1969 sal_uInt32 nParamCount = aParamsSeq.getLength();
1970 const Reference< XIdlClass >* pParams = aParamsSeq.getConstArray();
1972 if( nParamCount > 0 )
1974 for( sal_uInt32 j = 0; j < nParamCount; j++ )
1976 aRet.append ( Dbg_SbxDataType2String( unoToSbxType( pParams[ j ] ) ) );
1977 if( j < nParamCount - 1 )
1978 aRet.append( ", " );
1981 else
1982 aRet.append( "void" );
1984 aRet.append( " ) " );
1986 if( i == nMethodCount - 1 )
1987 aRet.append( "\n" );
1988 else
1989 aRet.append( "; " );
1992 return aRet.makeStringAndClear();
1996 // Implementation SbUnoObject
1997 void SbUnoObject::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
1999 if( bNeedIntrospection )
2000 doIntrospection();
2002 const SbxHint* pHint = dynamic_cast<const SbxHint*>(&rHint);
2003 if( !pHint )
2004 return;
2006 SbxVariable* pVar = pHint->GetVar();
2007 SbxArray* pParams = pVar->GetParameters();
2008 SbUnoProperty* pProp = dynamic_cast<SbUnoProperty*>( pVar );
2009 SbUnoMethod* pMeth = dynamic_cast<SbUnoMethod*>( pVar );
2010 if( pProp )
2012 bool bInvocation = pProp->isInvocationBased();
2013 if( pHint->GetId() == SfxHintId::BasicDataWanted )
2015 // Test-Properties
2016 sal_Int32 nId = pProp->nId;
2017 if( nId < 0 )
2019 // Id == -1: Display implemented interfaces according the ClassProvider
2020 if( nId == -1 ) // Property ID_DBG_SUPPORTEDINTERFACES"
2022 OUString aRetStr = Impl_GetSupportedInterfaces(*this);
2023 pVar->PutString( aRetStr );
2025 // Id == -2: output properties
2026 else if( nId == -2 ) // Property ID_DBG_PROPERTIES
2028 // now all properties must be created
2029 implCreateAll();
2030 OUString aRetStr = Impl_DumpProperties(*this);
2031 pVar->PutString( aRetStr );
2033 // Id == -3: output the methods
2034 else if( nId == -3 ) // Property ID_DBG_METHODS
2036 // now all properties must be created
2037 implCreateAll();
2038 OUString aRetStr = Impl_DumpMethods(*this);
2039 pVar->PutString( aRetStr );
2041 return;
2044 if( !bInvocation && mxUnoAccess.is() )
2048 if ( maStructInfo )
2050 StructRefInfo aMember = maStructInfo->getStructMember( pProp->GetName() );
2051 if ( aMember.isEmpty() )
2053 StarBASIC::Error( ERRCODE_BASIC_PROPERTY_NOT_FOUND );
2055 else
2057 if ( pProp->isUnoStruct() )
2059 SbUnoStructRefObject* pSbUnoObject = new SbUnoStructRefObject( pProp->GetName(), aMember );
2060 SbxObjectRef xWrapper = static_cast<SbxObject*>(pSbUnoObject);
2061 pVar->PutObject( xWrapper.get() );
2063 else
2065 Any aRetAny = aMember.getValue();
2066 // take over the value from Uno to Sbx
2067 unoToSbxValue( pVar, aRetAny );
2069 return;
2072 // get the value
2073 Reference< XPropertySet > xPropSet( mxUnoAccess->queryAdapter( cppu::UnoType<XPropertySet>::get()), UNO_QUERY );
2074 Any aRetAny = xPropSet->getPropertyValue( pProp->GetName() );
2075 // The use of getPropertyValue (instead of using the index) is
2076 // suboptimal, but the refactoring to XInvocation is already pending
2077 // Otherwise it is possible to use FastPropertySet
2079 // take over the value from Uno to Sbx
2080 unoToSbxValue( pVar, aRetAny );
2082 catch( const Exception& )
2084 implHandleAnyException( ::cppu::getCaughtException() );
2087 else if( bInvocation && mxInvocation.is() )
2091 sal_uInt32 nParamCount = pParams ? (pParams->Count32() - 1) : 0;
2092 bool bCanBeConsideredAMethod = mxInvocation->hasMethod( pProp->GetName() );
2093 Any aRetAny;
2094 if ( bCanBeConsideredAMethod && nParamCount )
2096 // Automation properties have methods, so... we need to invoke this through
2097 // XInvocation
2098 Sequence<Any> args;
2099 processAutomationParams( pParams, args, nParamCount );
2100 aRetAny = invokeAutomationMethod( pProp->GetName(), args, pParams, nParamCount, mxInvocation, INVOKETYPE::GetProp );
2102 else
2103 aRetAny = mxInvocation->getValue( pProp->GetName() );
2104 // take over the value from Uno to Sbx
2105 unoToSbxValue( pVar, aRetAny );
2106 if( pParams && bCanBeConsideredAMethod )
2107 pVar->SetParameters( nullptr );
2110 catch( const Exception& )
2112 implHandleAnyException( ::cppu::getCaughtException() );
2116 else if( pHint->GetId() == SfxHintId::BasicDataChanged )
2118 if( !bInvocation && mxUnoAccess.is() )
2120 if( pProp->aUnoProp.Attributes & PropertyAttribute::READONLY )
2122 StarBASIC::Error( ERRCODE_BASIC_PROP_READONLY );
2123 return;
2125 if ( maStructInfo )
2127 StructRefInfo aMember = maStructInfo->getStructMember( pProp->GetName() );
2128 if ( aMember.isEmpty() )
2130 StarBASIC::Error( ERRCODE_BASIC_PROPERTY_NOT_FOUND );
2132 else
2134 Any aAnyValue = sbxToUnoValue( pVar, pProp->aUnoProp.Type, &pProp->aUnoProp );
2135 aMember.setValue( aAnyValue );
2137 return;
2139 // take over the value from Uno to Sbx
2140 Any aAnyValue = sbxToUnoValue( pVar, pProp->aUnoProp.Type, &pProp->aUnoProp );
2143 // set the value
2144 Reference< XPropertySet > xPropSet( mxUnoAccess->queryAdapter( cppu::UnoType<XPropertySet>::get()), UNO_QUERY );
2145 xPropSet->setPropertyValue( pProp->GetName(), aAnyValue );
2146 // The use of getPropertyValue (instead of using the index) is
2147 // suboptimal, but the refactoring to XInvocation is already pending
2148 // Otherwise it is possible to use FastPropertySet
2150 catch( const Exception& )
2152 implHandleAnyException( ::cppu::getCaughtException() );
2155 else if( bInvocation && mxInvocation.is() )
2157 // take over the value from Uno to Sbx
2158 Any aAnyValue = sbxToUnoValueImpl( pVar );
2161 // set the value
2162 mxInvocation->setValue( pProp->GetName(), aAnyValue );
2164 catch( const Exception& )
2166 implHandleAnyException( ::cppu::getCaughtException() );
2171 else if( pMeth )
2173 bool bInvocation = pMeth->isInvocationBased();
2174 if( pHint->GetId() == SfxHintId::BasicDataWanted )
2176 // number of Parameter -1 because of Param0 == this
2177 sal_uInt32 nParamCount = pParams ? (pParams->Count32() - 1) : 0;
2178 Sequence<Any> args;
2179 bool bOutParams = false;
2181 if( !bInvocation && mxUnoAccess.is() )
2183 // get info
2184 const Sequence<ParamInfo>& rInfoSeq = pMeth->getParamInfos();
2185 const ParamInfo* pParamInfos = rInfoSeq.getConstArray();
2186 sal_uInt32 nUnoParamCount = rInfoSeq.getLength();
2187 sal_uInt32 nAllocParamCount = nParamCount;
2189 // ignore surplus parameter; alternative: throw an error
2190 if( nParamCount > nUnoParamCount )
2192 nParamCount = nUnoParamCount;
2193 nAllocParamCount = nParamCount;
2195 else if( nParamCount < nUnoParamCount )
2197 SbiInstance* pInst = GetSbData()->pInst;
2198 if( pInst && pInst->IsCompatibility() )
2200 // Check types
2201 bool bError = false;
2202 for( sal_uInt32 i = nParamCount ; i < nUnoParamCount ; i++ )
2204 const ParamInfo& rInfo = pParamInfos[i];
2205 const Reference< XIdlClass >& rxClass = rInfo.aType;
2206 if( rxClass->getTypeClass() != TypeClass_ANY )
2208 bError = true;
2209 StarBASIC::Error( ERRCODE_BASIC_NOT_OPTIONAL );
2212 if( !bError )
2213 nAllocParamCount = nUnoParamCount;
2217 if( nAllocParamCount > 0 )
2219 args.realloc( nAllocParamCount );
2220 Any* pAnyArgs = args.getArray();
2221 for( sal_uInt32 i = 0 ; i < nParamCount ; i++ )
2223 const ParamInfo& rInfo = pParamInfos[i];
2224 const Reference< XIdlClass >& rxClass = rInfo.aType;
2226 css::uno::Type aType( rxClass->getTypeClass(), rxClass->getName() );
2228 // ATTENTION: Don't forget for Sbx-Parameter the offset!
2229 pAnyArgs[i] = sbxToUnoValue( pParams->Get32(i + 1), aType );
2231 // If it is not certain check whether the out-parameter are available.
2232 if( !bOutParams )
2234 ParamMode aParamMode = rInfo.aMode;
2235 if( aParamMode != ParamMode_IN )
2236 bOutParams = true;
2241 else if( bInvocation && pParams && mxInvocation.is() )
2243 processAutomationParams( pParams, args, nParamCount );
2246 // call the method
2247 GetSbData()->bBlockCompilerError = true; // #106433 Block compiler errors for API calls
2250 if( !bInvocation && mxUnoAccess.is() )
2252 Any aRetAny = pMeth->m_xUnoMethod->invoke( getUnoAny(), args );
2254 // take over the value from Uno to Sbx
2255 unoToSbxValue( pVar, aRetAny );
2257 // Did we to copy back the Out-Parameter?
2258 if( bOutParams )
2260 const Any* pAnyArgs = args.getConstArray();
2262 // get info
2263 const Sequence<ParamInfo>& rInfoSeq = pMeth->getParamInfos();
2264 const ParamInfo* pParamInfos = rInfoSeq.getConstArray();
2266 sal_uInt32 j;
2267 for( j = 0 ; j < nParamCount ; j++ )
2269 const ParamInfo& rInfo = pParamInfos[j];
2270 ParamMode aParamMode = rInfo.aMode;
2271 if( aParamMode != ParamMode_IN )
2272 unoToSbxValue( pParams->Get32(j + 1), pAnyArgs[ j ] );
2276 else if( bInvocation && mxInvocation.is() )
2278 Any aRetAny = invokeAutomationMethod( pMeth->GetName(), args, pParams, nParamCount, mxInvocation, INVOKETYPE::Func );
2279 unoToSbxValue( pVar, aRetAny );
2282 // remove parameter here, because this was not done anymore in unoToSbxValue()
2283 // for arrays
2284 if( pParams )
2285 pVar->SetParameters( nullptr );
2287 catch( const Exception& )
2289 implHandleAnyException( ::cppu::getCaughtException() );
2291 GetSbData()->bBlockCompilerError = false; // #106433 Unblock compiler errors
2294 else
2295 SbxObject::Notify( rBC, rHint );
2299 SbUnoObject::SbUnoObject( const OUString& aName_, const Any& aUnoObj_ )
2300 : SbxObject( aName_ )
2301 , bNeedIntrospection( true )
2302 , bNativeCOMObject( false )
2304 // beat out again the default properties of Sbx
2305 Remove( "Name", SbxClassType::DontCare );
2306 Remove( "Parent", SbxClassType::DontCare );
2308 // check the type of the objects
2309 TypeClass eType = aUnoObj_.getValueType().getTypeClass();
2310 Reference< XInterface > x;
2311 if( eType == TypeClass_INTERFACE )
2313 // get the interface from the Any
2314 aUnoObj_ >>= x;
2315 if( !x.is() )
2316 return;
2319 Reference< XTypeProvider > xTypeProvider;
2320 // Did the object have an invocation itself?
2321 mxInvocation.set( x, UNO_QUERY );
2323 xTypeProvider.set( x, UNO_QUERY );
2325 if( mxInvocation.is() )
2328 // get the ExactName
2329 mxExactNameInvocation.set( mxInvocation, UNO_QUERY );
2331 // The remainder refers only to the introspection
2332 if( !xTypeProvider.is() )
2334 bNeedIntrospection = false;
2335 return;
2338 // Ignore introspection based members for COM objects to avoid
2339 // hiding of equally named COM symbols, e.g. XInvocation::getValue
2340 Reference< oleautomation::XAutomationObject > xAutomationObject( aUnoObj_, UNO_QUERY );
2341 if( xAutomationObject.is() )
2342 bNativeCOMObject = true;
2345 maTmpUnoObj = aUnoObj_;
2348 //*** Define the name ***
2349 bool bFatalError = true;
2351 // Is it an interface or a struct?
2352 bool bSetClassName = false;
2353 OUString aClassName_;
2354 if( eType == TypeClass_STRUCT || eType == TypeClass_EXCEPTION )
2356 // Struct is Ok
2357 bFatalError = false;
2359 // insert the real name of the class
2360 if( aName_.isEmpty() )
2362 aClassName_ = aUnoObj_.getValueType().getTypeName();
2363 bSetClassName = true;
2365 StructRefInfo aThisStruct( maTmpUnoObj, maTmpUnoObj.getValueType(), 0 );
2366 maStructInfo = std::make_shared<SbUnoStructRefObject>( GetName(), aThisStruct );
2368 else if( eType == TypeClass_INTERFACE )
2370 // Interface works always through the type in the Any
2371 bFatalError = false;
2373 if( bSetClassName )
2374 SetClassName( aClassName_ );
2376 // Neither interface nor Struct -> FatalError
2377 if( bFatalError )
2379 StarBASIC::FatalError( ERRCODE_BASIC_EXCEPTION );
2380 return;
2383 // pass the introspection primal on demand
2386 SbUnoObject::~SbUnoObject()
2391 // pass the introspection on Demand
2392 void SbUnoObject::doIntrospection()
2394 if( !bNeedIntrospection )
2395 return;
2397 Reference<XComponentContext> xContext = comphelper::getProcessComponentContext();
2399 if (!xContext.is())
2400 return;
2403 // get the introspection service
2404 Reference<XIntrospection> xIntrospection;
2408 xIntrospection = theIntrospection::get(xContext);
2410 catch ( const css::uno::DeploymentException& )
2414 if (!xIntrospection.is())
2415 return;
2417 bNeedIntrospection = false;
2419 // pass the introspection
2422 mxUnoAccess = xIntrospection->inspect( maTmpUnoObj );
2424 catch( const RuntimeException& e )
2426 StarBASIC::Error( ERRCODE_BASIC_EXCEPTION, implGetExceptionMsg( e ) );
2429 if( !mxUnoAccess.is() )
2431 // #51475 mark to indicate an invalid object (no mxMaterialHolder)
2432 return;
2435 // get MaterialHolder from access
2436 mxMaterialHolder.set( mxUnoAccess, UNO_QUERY );
2438 // get ExactName from access
2439 mxExactName.set( mxUnoAccess, UNO_QUERY );
2443 // Start of a list of all SbUnoMethod-Instances
2444 static SbUnoMethod* pFirst = nullptr;
2446 void clearUnoMethodsForBasic( StarBASIC const * pBasic )
2448 SbUnoMethod* pMeth = pFirst;
2449 while( pMeth )
2451 SbxObject* pObject = pMeth->GetParent();
2452 if ( pObject )
2454 StarBASIC* pModBasic = dynamic_cast< StarBASIC* >( pObject->GetParent() );
2455 if ( pModBasic == pBasic )
2457 // for now the solution is to remove the method from the list and to clear it,
2458 // but in case the element should be correctly transferred to another StarBASIC,
2459 // we should either set module parent to NULL without clearing it, or even
2460 // set the new StarBASIC as the parent of the module
2461 // pObject->SetParent( NULL );
2463 if( pMeth == pFirst )
2464 pFirst = pMeth->pNext;
2465 else if( pMeth->pPrev )
2466 pMeth->pPrev->pNext = pMeth->pNext;
2467 if( pMeth->pNext )
2468 pMeth->pNext->pPrev = pMeth->pPrev;
2470 pMeth->pPrev = nullptr;
2471 pMeth->pNext = nullptr;
2473 pMeth->SbxValue::Clear();
2474 pObject->SbxValue::Clear();
2476 // start from the beginning after object clearing, the cycle will end since the method is removed each time
2477 pMeth = pFirst;
2479 else
2480 pMeth = pMeth->pNext;
2482 else
2483 pMeth = pMeth->pNext;
2487 void clearUnoMethods()
2489 SbUnoMethod* pMeth = pFirst;
2490 while( pMeth )
2492 pMeth->SbxValue::Clear();
2493 pMeth = pMeth->pNext;
2498 SbUnoMethod::SbUnoMethod
2500 const OUString& aName_,
2501 SbxDataType eSbxType,
2502 Reference< XIdlMethod > const & xUnoMethod_,
2503 bool bInvocation
2505 : SbxMethod( aName_, eSbxType )
2506 , mbInvocation( bInvocation )
2508 m_xUnoMethod = xUnoMethod_;
2509 pParamInfoSeq = nullptr;
2511 // enregister the method in a list
2512 pNext = pFirst;
2513 pPrev = nullptr;
2514 pFirst = this;
2515 if( pNext )
2516 pNext->pPrev = this;
2519 SbUnoMethod::~SbUnoMethod()
2521 pParamInfoSeq.reset();
2523 if( this == pFirst )
2524 pFirst = pNext;
2525 else if( pPrev )
2526 pPrev->pNext = pNext;
2527 if( pNext )
2528 pNext->pPrev = pPrev;
2531 SbxInfo* SbUnoMethod::GetInfo()
2533 if( !pInfo.is() && m_xUnoMethod.is() )
2535 SbiInstance* pInst = GetSbData()->pInst;
2536 if( pInst && pInst->IsCompatibility() )
2538 pInfo = new SbxInfo();
2540 const Sequence<ParamInfo>& rInfoSeq = getParamInfos();
2541 const ParamInfo* pParamInfos = rInfoSeq.getConstArray();
2542 sal_uInt32 nParamCount = rInfoSeq.getLength();
2544 for( sal_uInt32 i = 0 ; i < nParamCount ; i++ )
2546 const ParamInfo& rInfo = pParamInfos[i];
2547 OUString aParamName = rInfo.aName;
2549 pInfo->AddParam( aParamName, SbxVARIANT, SbxFlagBits::Read );
2553 return pInfo.get();
2556 const Sequence<ParamInfo>& SbUnoMethod::getParamInfos()
2558 if (!pParamInfoSeq)
2560 Sequence<ParamInfo> aTmp;
2561 if (m_xUnoMethod.is())
2562 aTmp = m_xUnoMethod->getParameterInfos();
2563 pParamInfoSeq.reset( new Sequence<ParamInfo>(aTmp) );
2565 return *pParamInfoSeq;
2568 SbUnoProperty::SbUnoProperty
2570 const OUString& aName_,
2571 SbxDataType eSbxType,
2572 SbxDataType eRealSbxType,
2573 const Property& aUnoProp_,
2574 sal_Int32 nId_,
2575 bool bInvocation,
2576 bool bUnoStruct
2578 : SbxProperty( aName_, eSbxType )
2579 , aUnoProp( aUnoProp_ )
2580 , nId( nId_ )
2581 , mbInvocation( bInvocation )
2582 , mRealType( eRealSbxType )
2583 , mbUnoStruct( bUnoStruct )
2585 // as needed establish a dummy array so that SbiRuntime::CheckArray() works
2586 static SbxArrayRef xDummyArray = new SbxArray( SbxVARIANT );
2587 if( eSbxType & SbxARRAY )
2588 PutObject( xDummyArray.get() );
2591 SbUnoProperty::~SbUnoProperty()
2595 SbxVariable* SbUnoObject::Find( const OUString& rName, SbxClassType t )
2597 static Reference< XIdlMethod > xDummyMethod;
2598 static Property aDummyProp;
2600 SbxVariable* pRes = SbxObject::Find( rName, t );
2602 if( bNeedIntrospection )
2603 doIntrospection();
2605 // New 1999-03-04: Create properties on demand. Therefore search now via
2606 // IntrospectionAccess if a property or a method of the required name exist
2607 if( !pRes )
2609 OUString aUName( rName );
2610 if( mxUnoAccess.is() && !bNativeCOMObject )
2612 if( mxExactName.is() )
2614 OUString aUExactName = mxExactName->getExactName( aUName );
2615 if( !aUExactName.isEmpty() )
2617 aUName = aUExactName;
2620 if( mxUnoAccess->hasProperty( aUName, PropertyConcept::ALL - PropertyConcept::DANGEROUS ) )
2622 const Property& rProp = mxUnoAccess->
2623 getProperty( aUName, PropertyConcept::ALL - PropertyConcept::DANGEROUS );
2625 // If the property could be void the type had to be set to Variant
2626 SbxDataType eSbxType;
2627 if( rProp.Attributes & PropertyAttribute::MAYBEVOID )
2628 eSbxType = SbxVARIANT;
2629 else
2630 eSbxType = unoToSbxType( rProp.Type.getTypeClass() );
2632 SbxDataType eRealSbxType = ( ( rProp.Attributes & PropertyAttribute::MAYBEVOID ) ? unoToSbxType( rProp.Type.getTypeClass() ) : eSbxType );
2633 // create the property and superimpose it
2634 auto pProp = tools::make_ref<SbUnoProperty>( rProp.Name, eSbxType, eRealSbxType, rProp, 0, false, ( rProp.Type.getTypeClass() == css::uno::TypeClass_STRUCT ) );
2635 QuickInsert( pProp.get() );
2636 pRes = pProp.get();
2638 else if( mxUnoAccess->hasMethod( aUName,
2639 MethodConcept::ALL - MethodConcept::DANGEROUS ) )
2641 // address the method
2642 const Reference< XIdlMethod >& rxMethod = mxUnoAccess->
2643 getMethod( aUName, MethodConcept::ALL - MethodConcept::DANGEROUS );
2645 // create SbUnoMethod and superimpose it
2646 auto xMethRef = tools::make_ref<SbUnoMethod>( rxMethod->getName(),
2647 unoToSbxType( rxMethod->getReturnType() ), rxMethod, false );
2648 QuickInsert( xMethRef.get() );
2649 pRes = xMethRef.get();
2652 // If nothing was found check via XNameAccess
2653 if( !pRes )
2657 Reference< XNameAccess > xNameAccess( mxUnoAccess->queryAdapter( cppu::UnoType<XPropertySet>::get()), UNO_QUERY );
2659 if( xNameAccess.is() && xNameAccess->hasByName( rName ) )
2661 Any aAny = xNameAccess->getByName( rName );
2663 // ATTENTION: Because of XNameAccess, the variable generated here
2664 // may not be included as a fixed property in the object and therefore
2665 // won't be stored anywhere.
2666 // If this leads to problems, it has to be created
2667 // synthetically or a class SbUnoNameAccessProperty,
2668 // which checks the existence on access and which
2669 // is disposed if the name is not found anymore.
2670 pRes = new SbxVariable( SbxVARIANT );
2671 unoToSbxValue( pRes, aAny );
2674 catch( const NoSuchElementException& e )
2676 StarBASIC::Error( ERRCODE_BASIC_EXCEPTION, implGetExceptionMsg( e ) );
2678 catch( const Exception& )
2680 // Establish so that the exception error will not be overwritten
2681 if( !pRes )
2682 pRes = new SbxVariable( SbxVARIANT );
2684 implHandleAnyException( ::cppu::getCaughtException() );
2688 if( !pRes && mxInvocation.is() )
2690 if( mxExactNameInvocation.is() )
2692 OUString aUExactName = mxExactNameInvocation->getExactName( aUName );
2693 if( !aUExactName.isEmpty() )
2695 aUName = aUExactName;
2701 if( mxInvocation->hasProperty( aUName ) )
2703 // create a property and superimpose it
2704 auto xVarRef = tools::make_ref<SbUnoProperty>( aUName, SbxVARIANT, SbxVARIANT, aDummyProp, 0, true, false );
2705 QuickInsert( xVarRef.get() );
2706 pRes = xVarRef.get();
2708 else if( mxInvocation->hasMethod( aUName ) )
2710 // create SbUnoMethode and superimpose it
2711 auto xMethRef = tools::make_ref<SbUnoMethod>( aUName, SbxVARIANT, xDummyMethod, true );
2712 QuickInsert( xMethRef.get() );
2713 pRes = xMethRef.get();
2715 else
2717 Reference< XDirectInvocation > xDirectInvoke( mxInvocation, UNO_QUERY );
2718 if ( xDirectInvoke.is() && xDirectInvoke->hasMember( aUName ) )
2720 auto xMethRef = tools::make_ref<SbUnoMethod>( aUName, SbxVARIANT, xDummyMethod, true );
2721 QuickInsert( xMethRef.get() );
2722 pRes = xMethRef.get();
2727 catch( const RuntimeException& e )
2729 // Establish so that the exception error will not be overwritten
2730 if( !pRes )
2731 pRes = new SbxVariable( SbxVARIANT );
2733 StarBASIC::Error( ERRCODE_BASIC_EXCEPTION, implGetExceptionMsg( e ) );
2738 // At the very end checking if the Dbg_-Properties are meant
2740 if( !pRes )
2742 if( rName.equalsIgnoreAsciiCase(ID_DBG_SUPPORTEDINTERFACES) ||
2743 rName.equalsIgnoreAsciiCase(ID_DBG_PROPERTIES) ||
2744 rName.equalsIgnoreAsciiCase(ID_DBG_METHODS) )
2746 // Create
2747 implCreateDbgProperties();
2749 // Now they have to be found regular
2750 pRes = SbxObject::Find( rName, SbxClassType::DontCare );
2753 return pRes;
2757 // help method to create the dbg_-Properties
2758 void SbUnoObject::implCreateDbgProperties()
2760 Property aProp;
2762 // Id == -1: display the implemented interfaces corresponding the ClassProvider
2763 auto xVarRef = tools::make_ref<SbUnoProperty>( OUString(ID_DBG_SUPPORTEDINTERFACES), SbxSTRING, SbxSTRING, aProp, -1, false, false );
2764 QuickInsert( xVarRef.get() );
2766 // Id == -2: output the properties
2767 xVarRef = tools::make_ref<SbUnoProperty>( OUString(ID_DBG_PROPERTIES), SbxSTRING, SbxSTRING, aProp, -2, false, false );
2768 QuickInsert( xVarRef.get() );
2770 // Id == -3: output the Methods
2771 xVarRef = tools::make_ref<SbUnoProperty>( OUString(ID_DBG_METHODS), SbxSTRING, SbxSTRING, aProp, -3, false, false );
2772 QuickInsert( xVarRef.get() );
2775 void SbUnoObject::implCreateAll()
2777 // throw away all existing methods and properties
2778 pMethods = tools::make_ref<SbxArray>();
2779 pProps = tools::make_ref<SbxArray>();
2781 if( bNeedIntrospection ) doIntrospection();
2783 // get introspection
2784 Reference< XIntrospectionAccess > xAccess = mxUnoAccess;
2785 if( !xAccess.is() || bNativeCOMObject )
2787 if( mxInvocation.is() )
2788 xAccess = mxInvocation->getIntrospection();
2789 else if( bNativeCOMObject )
2790 return;
2792 if( !xAccess.is() )
2793 return;
2795 // Establish properties
2796 Sequence<Property> props = xAccess->getProperties( PropertyConcept::ALL - PropertyConcept::DANGEROUS );
2797 sal_uInt32 nPropCount = props.getLength();
2798 const Property* pProps_ = props.getConstArray();
2800 sal_uInt32 i;
2801 for( i = 0 ; i < nPropCount ; i++ )
2803 const Property& rProp = pProps_[ i ];
2805 // If the property could be void the type had to be set to Variant
2806 SbxDataType eSbxType;
2807 if( rProp.Attributes & PropertyAttribute::MAYBEVOID )
2808 eSbxType = SbxVARIANT;
2809 else
2810 eSbxType = unoToSbxType( rProp.Type.getTypeClass() );
2812 SbxDataType eRealSbxType = ( ( rProp.Attributes & PropertyAttribute::MAYBEVOID ) ? unoToSbxType( rProp.Type.getTypeClass() ) : eSbxType );
2813 // Create property and superimpose it
2814 auto xVarRef = tools::make_ref<SbUnoProperty>( rProp.Name, eSbxType, eRealSbxType, rProp, i, false, ( rProp.Type.getTypeClass() == css::uno::TypeClass_STRUCT ) );
2815 QuickInsert( xVarRef.get() );
2818 // Create Dbg_-Properties
2819 implCreateDbgProperties();
2821 // Create methods
2822 Sequence< Reference< XIdlMethod > > aMethodSeq = xAccess->getMethods
2823 ( MethodConcept::ALL - MethodConcept::DANGEROUS );
2824 sal_uInt32 nMethCount = aMethodSeq.getLength();
2825 const Reference< XIdlMethod >* pMethods_ = aMethodSeq.getConstArray();
2826 for( i = 0 ; i < nMethCount ; i++ )
2828 // address method
2829 const Reference< XIdlMethod >& rxMethod = pMethods_[i];
2831 // Create SbUnoMethod and superimpose it
2832 auto xMethRef = tools::make_ref<SbUnoMethod>
2833 ( rxMethod->getName(), unoToSbxType( rxMethod->getReturnType() ), rxMethod, false );
2834 QuickInsert( xMethRef.get() );
2839 // output the value
2840 Any SbUnoObject::getUnoAny()
2842 Any aRetAny;
2843 if( bNeedIntrospection ) doIntrospection();
2844 if ( maStructInfo )
2845 aRetAny = maTmpUnoObj;
2846 else if( mxMaterialHolder.is() )
2847 aRetAny = mxMaterialHolder->getMaterial();
2848 else if( mxInvocation.is() )
2849 aRetAny <<= mxInvocation;
2850 return aRetAny;
2853 // help method to create a Uno-Struct per CoreReflection
2854 static SbUnoObject* Impl_CreateUnoStruct( const OUString& aClassName )
2856 // get CoreReflection
2857 Reference< XIdlReflection > xCoreReflection = getCoreReflection_Impl();
2858 if( !xCoreReflection.is() )
2859 return nullptr;
2861 // search for the class
2862 Reference< XIdlClass > xClass;
2863 const Reference< XHierarchicalNameAccess >& xHarryName =
2864 getCoreReflection_HierarchicalNameAccess_Impl();
2865 if( xHarryName.is() && xHarryName->hasByHierarchicalName( aClassName ) )
2866 xClass = xCoreReflection->forName( aClassName );
2867 if( !xClass.is() )
2868 return nullptr;
2870 // Is it really a struct?
2871 TypeClass eType = xClass->getTypeClass();
2872 if ( ( eType != TypeClass_STRUCT ) && ( eType != TypeClass_EXCEPTION ) )
2873 return nullptr;
2875 // create an instance
2876 Any aNewAny;
2877 xClass->createObject( aNewAny );
2878 // make a SbUnoObject out of it
2879 SbUnoObject* pUnoObj = new SbUnoObject( aClassName, aNewAny );
2880 return pUnoObj;
2884 // Factory-Class to create Uno-Structs per DIM AS NEW
2885 SbxBase* SbUnoFactory::Create( sal_uInt16, sal_uInt32 )
2887 // Via SbxId nothing works in Uno
2888 return nullptr;
2891 SbxObject* SbUnoFactory::CreateObject( const OUString& rClassName )
2893 return Impl_CreateUnoStruct( rClassName );
2897 // Provisional interface for the UNO-Connection
2898 // Deliver a SbxObject, that wrap a Uno-Interface
2899 SbxObjectRef GetSbUnoObject( const OUString& aName, const Any& aUnoObj_ )
2901 return new SbUnoObject( aName, aUnoObj_ );
2904 // Force creation of all properties for debugging
2905 void createAllObjectProperties( SbxObject* pObj )
2907 if( !pObj )
2908 return;
2910 SbUnoObject* pUnoObj = dynamic_cast<SbUnoObject*>( pObj );
2911 SbUnoStructRefObject* pUnoStructObj = dynamic_cast<SbUnoStructRefObject*>( pObj );
2912 if( pUnoObj )
2914 pUnoObj->createAllProperties();
2916 else if ( pUnoStructObj )
2918 pUnoStructObj->createAllProperties();
2923 void RTL_Impl_CreateUnoStruct( SbxArray& rPar )
2925 // We need 1 parameter minimum
2926 if ( rPar.Count32() < 2 )
2928 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
2929 return;
2932 // get the name of the class of the struct
2933 OUString aClassName = rPar.Get32(1)->GetOUString();
2935 // try to create Struct with the same name
2936 SbUnoObjectRef xUnoObj = Impl_CreateUnoStruct( aClassName );
2937 if( !xUnoObj.is() )
2939 return;
2941 // return the object
2942 SbxVariableRef refVar = rPar.Get32(0);
2943 refVar->PutObject( xUnoObj.get() );
2946 void RTL_Impl_CreateUnoService( SbxArray& rPar )
2948 // We need 1 Parameter minimum
2949 if ( rPar.Count32() < 2 )
2951 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
2952 return;
2955 // get the name of the class of the struct
2956 OUString aServiceName = rPar.Get32(1)->GetOUString();
2958 // search for the service and instantiate it
2959 Reference< XMultiServiceFactory > xFactory( comphelper::getProcessServiceFactory() );
2960 Reference< XInterface > xInterface;
2963 xInterface = xFactory->createInstance( aServiceName );
2965 catch( const Exception& )
2967 implHandleAnyException( ::cppu::getCaughtException() );
2970 SbxVariableRef refVar = rPar.Get32(0);
2971 if( xInterface.is() )
2973 // Create a SbUnoObject out of it and return it
2974 SbUnoObjectRef xUnoObj = new SbUnoObject( aServiceName, Any(xInterface) );
2975 if( xUnoObj->getUnoAny().hasValue() )
2977 // return the object
2978 refVar->PutObject( xUnoObj.get() );
2980 else
2982 refVar->PutObject( nullptr );
2985 else
2987 refVar->PutObject( nullptr );
2991 void RTL_Impl_CreateUnoServiceWithArguments( SbxArray& rPar )
2993 // We need 2 parameter minimum
2994 if ( rPar.Count32() < 3 )
2996 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
2997 return;
3000 // get the name of the class of the struct
3001 OUString aServiceName = rPar.Get32(1)->GetOUString();
3002 Any aArgAsAny = sbxToUnoValue( rPar.Get32(2),
3003 cppu::UnoType<Sequence<Any>>::get() );
3004 Sequence< Any > aArgs;
3005 aArgAsAny >>= aArgs;
3007 // search for the service and instantiate it
3008 Reference< XMultiServiceFactory > xFactory( comphelper::getProcessServiceFactory() );
3009 Reference< XInterface > xInterface;
3012 xInterface = xFactory->createInstanceWithArguments( aServiceName, aArgs );
3014 catch( const Exception& )
3016 implHandleAnyException( ::cppu::getCaughtException() );
3019 SbxVariableRef refVar = rPar.Get32(0);
3020 if( xInterface.is() )
3022 // Create a SbUnoObject out of it and return it
3023 SbUnoObjectRef xUnoObj = new SbUnoObject( aServiceName, Any(xInterface) );
3024 if( xUnoObj->getUnoAny().hasValue() )
3026 // return the object
3027 refVar->PutObject( xUnoObj.get() );
3029 else
3031 refVar->PutObject( nullptr );
3034 else
3036 refVar->PutObject( nullptr );
3040 void RTL_Impl_GetProcessServiceManager( SbxArray& rPar )
3042 SbxVariableRef refVar = rPar.Get32(0);
3044 // get the global service manager
3045 Reference< XMultiServiceFactory > xFactory( comphelper::getProcessServiceFactory() );
3047 // Create a SbUnoObject out of it and return it
3048 SbUnoObjectRef xUnoObj = new SbUnoObject( "ProcessServiceManager", Any(xFactory) );
3049 refVar->PutObject( xUnoObj.get() );
3052 void RTL_Impl_HasInterfaces( SbxArray& rPar )
3054 // We need 2 parameter minimum
3055 sal_uInt32 nParCount = rPar.Count32();
3056 if( nParCount < 3 )
3058 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
3059 return;
3062 // variable for the return value
3063 SbxVariableRef refVar = rPar.Get32(0);
3064 refVar->PutBool( false );
3066 // get the Uno-Object
3067 SbxBaseRef pObj = rPar.Get32( 1 )->GetObject();
3068 auto obj = dynamic_cast<SbUnoObject*>( pObj.get() );
3069 if( obj == nullptr )
3071 return;
3073 Any aAny = obj->getUnoAny();
3074 auto x = o3tl::tryAccess<Reference<XInterface>>(aAny);
3075 if( !x )
3077 return;
3080 // get CoreReflection
3081 Reference< XIdlReflection > xCoreReflection = getCoreReflection_Impl();
3082 if( !xCoreReflection.is() )
3084 return;
3086 for( sal_uInt32 i = 2 ; i < nParCount ; i++ )
3088 // get the name of the interface of the struct
3089 OUString aIfaceName = rPar.Get32( i )->GetOUString();
3091 // search for the class
3092 Reference< XIdlClass > xClass = xCoreReflection->forName( aIfaceName );
3093 if( !xClass.is() )
3095 return;
3097 // check if the interface will be supported
3098 OUString aClassName = xClass->getName();
3099 Type aClassType( xClass->getTypeClass(), aClassName );
3100 if( !(*x)->queryInterface( aClassType ).hasValue() )
3102 return;
3106 // Everything works; then return TRUE
3107 refVar->PutBool( true );
3110 void RTL_Impl_IsUnoStruct( SbxArray& rPar )
3112 // We need 1 parameter minimum
3113 if ( rPar.Count32() < 2 )
3115 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
3116 return;
3119 // variable for the return value
3120 SbxVariableRef refVar = rPar.Get32(0);
3121 refVar->PutBool( false );
3123 // get the Uno-Object
3124 SbxVariableRef xParam = rPar.Get32( 1 );
3125 if( !xParam->IsObject() )
3127 return;
3129 SbxBaseRef pObj = xParam->GetObject();
3130 auto obj = dynamic_cast<SbUnoObject*>( pObj.get() );
3131 if( obj == nullptr )
3133 return;
3135 Any aAny = obj->getUnoAny();
3136 TypeClass eType = aAny.getValueType().getTypeClass();
3137 if( eType == TypeClass_STRUCT )
3139 refVar->PutBool( true );
3144 void RTL_Impl_EqualUnoObjects( SbxArray& rPar )
3146 if ( rPar.Count32() < 3 )
3148 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
3149 return;
3152 // variable for the return value
3153 SbxVariableRef refVar = rPar.Get32(0);
3154 refVar->PutBool( false );
3156 // get the Uno-Objects
3157 SbxVariableRef xParam1 = rPar.Get32( 1 );
3158 if( !xParam1->IsObject() )
3160 return;
3162 SbxBaseRef pObj1 = xParam1->GetObject();
3163 auto obj1 = dynamic_cast<SbUnoObject*>( pObj1.get() );
3164 if( obj1 == nullptr )
3166 return;
3168 Any aAny1 = obj1->getUnoAny();
3169 TypeClass eType1 = aAny1.getValueType().getTypeClass();
3170 if( eType1 != TypeClass_INTERFACE )
3172 return;
3174 Reference< XInterface > x1;
3175 aAny1 >>= x1;
3177 SbxVariableRef xParam2 = rPar.Get32( 2 );
3178 if( !xParam2->IsObject() )
3180 return;
3182 SbxBaseRef pObj2 = xParam2->GetObject();
3183 auto obj2 = dynamic_cast<SbUnoObject*>( pObj2.get() );
3184 if( obj2 == nullptr )
3186 return;
3188 Any aAny2 = obj2->getUnoAny();
3189 TypeClass eType2 = aAny2.getValueType().getTypeClass();
3190 if( eType2 != TypeClass_INTERFACE )
3192 return;
3194 Reference< XInterface > x2;
3195 aAny2 >>= x2;
3197 if( x1 == x2 )
3199 refVar->PutBool( true );
3204 // helper wrapper function to interact with TypeProvider and
3205 // XTypeDescriptionEnumerationAccess.
3206 // if it fails for whatever reason
3207 // returned Reference<> be null e.g. .is() will be false
3209 static Reference< XTypeDescriptionEnumeration > getTypeDescriptorEnumeration( const OUString& sSearchRoot,
3210 const Sequence< TypeClass >& types,
3211 TypeDescriptionSearchDepth depth )
3213 Reference< XTypeDescriptionEnumeration > xEnum;
3214 Reference< XTypeDescriptionEnumerationAccess> xTypeEnumAccess( getTypeProvider_Impl(), UNO_QUERY );
3215 if ( xTypeEnumAccess.is() )
3219 xEnum = xTypeEnumAccess->createTypeDescriptionEnumeration(
3220 sSearchRoot, types, depth );
3222 catch(const NoSuchTypeNameException& /*nstne*/ ) {}
3223 catch(const InvalidTypeNameException& /*nstne*/ ) {}
3225 return xEnum;
3228 VBAConstantHelper&
3229 VBAConstantHelper::instance()
3231 static VBAConstantHelper aHelper;
3232 return aHelper;
3235 void VBAConstantHelper::init()
3237 if ( isInited )
3238 return;
3240 Reference< XTypeDescriptionEnumeration > xEnum = getTypeDescriptorEnumeration( "ooo.vba", {TypeClass_CONSTANTS}, TypeDescriptionSearchDepth_INFINITE );
3242 if ( !xEnum.is())
3244 return; //NULL;
3246 while ( xEnum->hasMoreElements() )
3248 Reference< XConstantsTypeDescription > xConstants( xEnum->nextElement(), UNO_QUERY );
3249 if ( xConstants.is() )
3251 // store constant group name
3252 OUString sFullName = xConstants->getName();
3253 sal_Int32 indexLastDot = sFullName.lastIndexOf('.');
3254 OUString sLeafName( sFullName );
3255 if ( indexLastDot > -1 )
3257 sLeafName = sFullName.copy( indexLastDot + 1);
3259 aConstCache.push_back( sLeafName ); // assume constant group names are unique
3260 const Sequence< Reference< XConstantTypeDescription > > aConsts = xConstants->getConstants();
3261 for (const auto& ctd : aConsts)
3263 // store constant member name
3264 sFullName = ctd->getName();
3265 indexLastDot = sFullName.lastIndexOf('.');
3266 sLeafName = sFullName;
3267 if ( indexLastDot > -1 )
3269 sLeafName = sFullName.copy( indexLastDot + 1);
3271 aConstHash[ sLeafName.toAsciiLowerCase() ] = ctd->getConstantValue();
3275 isInited = true;
3278 bool
3279 VBAConstantHelper::isVBAConstantType( const OUString& rName )
3281 init();
3282 bool bConstant = false;
3284 for (auto const& elem : aConstCache)
3286 if( rName.equalsIgnoreAsciiCase(elem) )
3288 bConstant = true;
3289 break;
3292 return bConstant;
3295 SbxVariable*
3296 VBAConstantHelper::getVBAConstant( const OUString& rName )
3298 SbxVariable* pConst = nullptr;
3299 init();
3301 auto it = aConstHash.find( rName.toAsciiLowerCase() );
3303 if ( it != aConstHash.end() )
3305 pConst = new SbxVariable( SbxVARIANT );
3306 pConst->SetName( rName );
3307 unoToSbxValue( pConst, it->second );
3310 return pConst;
3313 // Function to search for a global identifier in the
3314 // UnoScope and to wrap it for Sbx
3315 SbUnoClass* findUnoClass( const OUString& rName )
3317 // #105550 Check if module exists
3318 SbUnoClass* pUnoClass = nullptr;
3320 const Reference< XHierarchicalNameAccess >& xTypeAccess = getTypeProvider_Impl();
3321 if( xTypeAccess->hasByHierarchicalName( rName ) )
3323 Any aRet = xTypeAccess->getByHierarchicalName( rName );
3324 Reference< XTypeDescription > xTypeDesc;
3325 aRet >>= xTypeDesc;
3327 if( xTypeDesc.is() )
3329 TypeClass eTypeClass = xTypeDesc->getTypeClass();
3330 if( eTypeClass == TypeClass_MODULE || eTypeClass == TypeClass_CONSTANTS )
3332 pUnoClass = new SbUnoClass( rName );
3336 return pUnoClass;
3339 SbxVariable* SbUnoClass::Find( const OUString& rName, SbxClassType )
3341 SbxVariable* pRes = SbxObject::Find( rName, SbxClassType::Variable );
3343 // If nothing were located the submodule isn't known yet
3344 if( !pRes )
3346 // If it is already a class, ask for the field
3347 if( m_xClass.is() )
3349 // Is it a field(?)
3350 Reference< XIdlField > xField = m_xClass->getField( rName );
3351 if( xField.is() )
3355 Any aAny = xField->get( {} ); //TODO: does this make sense?
3357 // Convert to Sbx
3358 pRes = new SbxVariable( SbxVARIANT );
3359 pRes->SetName( rName );
3360 unoToSbxValue( pRes, aAny );
3362 catch( const Exception& )
3364 implHandleAnyException( ::cppu::getCaughtException() );
3368 else
3370 // expand fully qualified name
3371 OUString aNewName = GetName()
3372 + "."
3373 + rName;
3375 // get CoreReflection
3376 Reference< XIdlReflection > xCoreReflection = getCoreReflection_Impl();
3377 if( xCoreReflection.is() )
3379 // Is it a constant?
3380 Reference< XHierarchicalNameAccess > xHarryName( xCoreReflection, UNO_QUERY );
3381 if( xHarryName.is() )
3385 Any aValue = xHarryName->getByHierarchicalName( aNewName );
3386 TypeClass eType = aValue.getValueType().getTypeClass();
3388 // Interface located? Then it is a class
3389 if( eType == TypeClass_INTERFACE )
3391 Reference< XIdlClass > xClass( aValue, UNO_QUERY );
3392 if( xClass.is() )
3394 pRes = new SbxVariable( SbxVARIANT );
3395 SbxObjectRef xWrapper = static_cast<SbxObject*>(new SbUnoClass( aNewName, xClass ));
3396 pRes->PutObject( xWrapper.get() );
3399 else
3401 pRes = new SbxVariable( SbxVARIANT );
3402 unoToSbxValue( pRes, aValue );
3405 catch( const NoSuchElementException& )
3410 // Otherwise take it again as class
3411 if( !pRes )
3413 SbUnoClass* pNewClass = findUnoClass( aNewName );
3414 if( pNewClass )
3416 pRes = new SbxVariable( SbxVARIANT );
3417 SbxObjectRef xWrapper = static_cast<SbxObject*>(pNewClass);
3418 pRes->PutObject( xWrapper.get() );
3422 // A UNO service?
3423 if( !pRes )
3425 SbUnoService* pUnoService = findUnoService( aNewName );
3426 if( pUnoService )
3428 pRes = new SbxVariable( SbxVARIANT );
3429 SbxObjectRef xWrapper = static_cast<SbxObject*>(pUnoService);
3430 pRes->PutObject( xWrapper.get() );
3434 // A UNO singleton?
3435 if( !pRes )
3437 SbUnoSingleton* pUnoSingleton = findUnoSingleton( aNewName );
3438 if( pUnoSingleton )
3440 pRes = new SbxVariable( SbxVARIANT );
3441 SbxObjectRef xWrapper = static_cast<SbxObject*>(pUnoSingleton);
3442 pRes->PutObject( xWrapper.get() );
3448 if( pRes )
3450 pRes->SetName( rName );
3452 // Insert variable, so that it could be found later
3453 QuickInsert( pRes );
3455 // Take us out as listener at once,
3456 // the values are all constant
3457 if( pRes->IsBroadcaster() )
3458 EndListening( pRes->GetBroadcaster(), true );
3461 return pRes;
3465 SbUnoService* findUnoService( const OUString& rName )
3467 SbUnoService* pSbUnoService = nullptr;
3469 const Reference< XHierarchicalNameAccess >& xTypeAccess = getTypeProvider_Impl();
3470 if( xTypeAccess->hasByHierarchicalName( rName ) )
3472 Any aRet = xTypeAccess->getByHierarchicalName( rName );
3473 Reference< XTypeDescription > xTypeDesc;
3474 aRet >>= xTypeDesc;
3476 if( xTypeDesc.is() )
3478 TypeClass eTypeClass = xTypeDesc->getTypeClass();
3479 if( eTypeClass == TypeClass_SERVICE )
3481 Reference< XServiceTypeDescription2 > xServiceTypeDesc( xTypeDesc, UNO_QUERY );
3482 if( xServiceTypeDesc.is() )
3483 pSbUnoService = new SbUnoService( rName, xServiceTypeDesc );
3487 return pSbUnoService;
3490 SbxVariable* SbUnoService::Find( const OUString& rName, SbxClassType )
3492 SbxVariable* pRes = SbxObject::Find( rName, SbxClassType::Method );
3494 if( !pRes )
3496 // If it is already a class ask for a field
3497 if( m_bNeedsInit && m_xServiceTypeDesc.is() )
3499 m_bNeedsInit = false;
3501 Sequence< Reference< XServiceConstructorDescription > > aSCDSeq = m_xServiceTypeDesc->getConstructors();
3502 const Reference< XServiceConstructorDescription >* pCtorSeq = aSCDSeq.getConstArray();
3503 int nCtorCount = aSCDSeq.getLength();
3504 for( int i = 0 ; i < nCtorCount ; ++i )
3506 Reference< XServiceConstructorDescription > xCtor = pCtorSeq[i];
3508 OUString aName( xCtor->getName() );
3509 if( aName.isEmpty() )
3511 if( xCtor->isDefaultConstructor() )
3513 aName = "create";
3517 if( !aName.isEmpty() )
3519 // Create and insert SbUnoServiceCtor
3520 SbxVariableRef xSbCtorRef = new SbUnoServiceCtor( aName, xCtor );
3521 QuickInsert( xSbCtorRef.get() );
3524 pRes = SbxObject::Find( rName, SbxClassType::Method );
3528 return pRes;
3531 void SbUnoService::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
3533 const SbxHint* pHint = dynamic_cast<const SbxHint*>(&rHint);
3534 if( !pHint )
3535 return;
3537 SbxVariable* pVar = pHint->GetVar();
3538 SbxArray* pParams = pVar->GetParameters();
3539 SbUnoServiceCtor* pUnoCtor = dynamic_cast<SbUnoServiceCtor*>( pVar );
3540 if( pUnoCtor && pHint->GetId() == SfxHintId::BasicDataWanted )
3542 // Parameter count -1 because of Param0 == this
3543 sal_uInt32 nParamCount = pParams ? (pParams->Count32() - 1) : 0;
3544 Sequence<Any> args;
3546 Reference< XServiceConstructorDescription > xCtor = pUnoCtor->getServiceCtorDesc();
3547 Sequence< Reference< XParameter > > aParameterSeq = xCtor->getParameters();
3548 const Reference< XParameter >* pParameterSeq = aParameterSeq.getConstArray();
3549 sal_uInt32 nUnoParamCount = aParameterSeq.getLength();
3551 // Default: Ignore not needed parameters
3552 bool bParameterError = false;
3554 // Is the last parameter a rest parameter?
3555 bool bRestParameterMode = false;
3556 if( nUnoParamCount > 0 )
3558 Reference< XParameter > xLastParam = pParameterSeq[ nUnoParamCount - 1 ];
3559 if( xLastParam.is() )
3561 if( xLastParam->isRestParameter() )
3562 bRestParameterMode = true;
3566 // Too many parameters with context as first parameter?
3567 sal_uInt32 nSbxParameterOffset = 1;
3568 sal_uInt32 nParameterOffsetByContext = 0;
3569 Reference < XComponentContext > xFirstParamContext;
3570 if( nParamCount > nUnoParamCount )
3572 // Check if first parameter is a context and use it
3573 // then in createInstanceWithArgumentsAndContext
3574 Any aArg0 = sbxToUnoValue( pParams->Get32( nSbxParameterOffset ) );
3575 if( (aArg0 >>= xFirstParamContext) && xFirstParamContext.is() )
3576 nParameterOffsetByContext = 1;
3579 sal_uInt32 nEffectiveParamCount = nParamCount - nParameterOffsetByContext;
3580 sal_uInt32 nAllocParamCount = nEffectiveParamCount;
3581 if( nEffectiveParamCount > nUnoParamCount )
3583 if( !bRestParameterMode )
3585 nEffectiveParamCount = nUnoParamCount;
3586 nAllocParamCount = nUnoParamCount;
3589 // Not enough parameters?
3590 else if( nUnoParamCount > nEffectiveParamCount )
3592 // RestParameterMode only helps if one (the last) parameter is missing
3593 int nDiff = nUnoParamCount - nEffectiveParamCount;
3594 if( !bRestParameterMode || nDiff > 1 )
3596 bParameterError = true;
3597 StarBASIC::Error( ERRCODE_BASIC_NOT_OPTIONAL );
3601 if( !bParameterError )
3603 bool bOutParams = false;
3604 if( nAllocParamCount > 0 )
3606 args.realloc( nAllocParamCount );
3607 Any* pAnyArgs = args.getArray();
3608 for( sal_uInt32 i = 0 ; i < nEffectiveParamCount ; i++ )
3610 sal_uInt32 iSbx = i + nSbxParameterOffset + nParameterOffsetByContext;
3612 // bRestParameterMode allows nEffectiveParamCount > nUnoParamCount
3613 Reference< XParameter > xParam;
3614 if( i < nUnoParamCount )
3616 xParam = pParameterSeq[i];
3617 if( !xParam.is() )
3618 continue;
3620 Reference< XTypeDescription > xParamTypeDesc = xParam->getType();
3621 if( !xParamTypeDesc.is() )
3622 continue;
3623 css::uno::Type aType( xParamTypeDesc->getTypeClass(), xParamTypeDesc->getName() );
3625 // sbx parameter needs offset 1
3626 pAnyArgs[i] = sbxToUnoValue( pParams->Get32( iSbx ), aType );
3628 // Check for out parameter if not already done
3629 if( !bOutParams && xParam->isOut() )
3630 bOutParams = true;
3632 else
3634 pAnyArgs[i] = sbxToUnoValue( pParams->Get32( iSbx ) );
3639 // "Call" ctor using createInstanceWithArgumentsAndContext
3640 Reference < XComponentContext > xContext(
3641 xFirstParamContext.is()
3642 ? xFirstParamContext
3643 : comphelper::getProcessComponentContext() );
3644 Reference< XMultiComponentFactory > xServiceMgr( xContext->getServiceManager() );
3646 Any aRetAny;
3647 OUString aServiceName = GetName();
3648 Reference < XInterface > xRet;
3651 xRet = xServiceMgr->createInstanceWithArgumentsAndContext( aServiceName, args, xContext );
3653 catch( const Exception& )
3655 implHandleAnyException( ::cppu::getCaughtException() );
3657 aRetAny <<= xRet;
3658 unoToSbxValue( pVar, aRetAny );
3660 // Copy back out parameters?
3661 if( bOutParams )
3663 const Any* pAnyArgs = args.getConstArray();
3665 for( sal_uInt32 j = 0 ; j < nUnoParamCount ; j++ )
3667 Reference< XParameter > xParam = pParameterSeq[j];
3668 if( !xParam.is() )
3669 continue;
3671 if( xParam->isOut() )
3672 unoToSbxValue( pParams->Get32(j + 1), pAnyArgs[ j ] );
3677 else
3678 SbxObject::Notify( rBC, rHint );
3682 SbUnoServiceCtor::SbUnoServiceCtor( const OUString& aName_, Reference< XServiceConstructorDescription > const & xServiceCtorDesc )
3683 : SbxMethod( aName_, SbxOBJECT )
3684 , m_xServiceCtorDesc( xServiceCtorDesc )
3688 SbUnoServiceCtor::~SbUnoServiceCtor()
3692 SbxInfo* SbUnoServiceCtor::GetInfo()
3694 return nullptr;
3698 SbUnoSingleton* findUnoSingleton( const OUString& rName )
3700 SbUnoSingleton* pSbUnoSingleton = nullptr;
3702 const Reference< XHierarchicalNameAccess >& xTypeAccess = getTypeProvider_Impl();
3703 if( xTypeAccess->hasByHierarchicalName( rName ) )
3705 Any aRet = xTypeAccess->getByHierarchicalName( rName );
3706 Reference< XTypeDescription > xTypeDesc;
3707 aRet >>= xTypeDesc;
3709 if( xTypeDesc.is() )
3711 TypeClass eTypeClass = xTypeDesc->getTypeClass();
3712 if( eTypeClass == TypeClass_SINGLETON )
3714 Reference< XSingletonTypeDescription > xSingletonTypeDesc( xTypeDesc, UNO_QUERY );
3715 if( xSingletonTypeDesc.is() )
3716 pSbUnoSingleton = new SbUnoSingleton( rName );
3720 return pSbUnoSingleton;
3723 SbUnoSingleton::SbUnoSingleton( const OUString& aName_ )
3724 : SbxObject( aName_ )
3726 SbxVariableRef xGetMethodRef = new SbxMethod( "get", SbxOBJECT );
3727 QuickInsert( xGetMethodRef.get() );
3730 void SbUnoSingleton::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
3732 const SbxHint* pHint = dynamic_cast<const SbxHint*>(&rHint);
3733 if( pHint )
3735 SbxVariable* pVar = pHint->GetVar();
3736 SbxArray* pParams = pVar->GetParameters();
3737 sal_uInt32 nParamCount = pParams ? (pParams->Count32() - 1) : 0;
3738 sal_uInt32 nAllowedParamCount = 1;
3740 Reference < XComponentContext > xContextToUse;
3741 if( nParamCount > 0 )
3743 // Check if first parameter is a context and use it then
3744 Reference < XComponentContext > xFirstParamContext;
3745 Any aArg1 = sbxToUnoValue( pParams->Get32( 1 ) );
3746 if( (aArg1 >>= xFirstParamContext) && xFirstParamContext.is() )
3747 xContextToUse = xFirstParamContext;
3750 if( !xContextToUse.is() )
3752 xContextToUse = comphelper::getProcessComponentContext();
3753 --nAllowedParamCount;
3756 if( nParamCount > nAllowedParamCount )
3758 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
3759 return;
3762 Any aRetAny;
3763 if( xContextToUse.is() )
3765 OUString aSingletonName = "/singletons/"
3766 + GetName();
3767 Reference < XInterface > xRet;
3768 xContextToUse->getValueByName( aSingletonName ) >>= xRet;
3769 aRetAny <<= xRet;
3771 unoToSbxValue( pVar, aRetAny );
3773 else
3775 SbxObject::Notify( rBC, rHint );
3779 namespace {
3781 // Implementation of an EventAttacher-drawn AllListener, which
3782 // solely transmits several events to a general AllListener
3783 class BasicAllListener_Impl : public WeakImplHelper< XAllListener >
3785 void firing_impl(const AllEventObject& Event, Any* pRet);
3787 public:
3788 SbxObjectRef xSbxObj;
3789 OUString aPrefixName;
3791 explicit BasicAllListener_Impl( const OUString& aPrefixName );
3793 // Methods of XAllListener
3794 virtual void SAL_CALL firing(const AllEventObject& Event) override;
3795 virtual Any SAL_CALL approveFiring(const AllEventObject& Event) override;
3797 // Methods of XEventListener
3798 virtual void SAL_CALL disposing(const EventObject& Source) override;
3803 BasicAllListener_Impl::BasicAllListener_Impl(const OUString& aPrefixName_)
3804 : aPrefixName( aPrefixName_ )
3808 void BasicAllListener_Impl::firing_impl( const AllEventObject& Event, Any* pRet )
3810 SolarMutexGuard guard;
3812 if( !xSbxObj.is() )
3813 return;
3815 OUString aMethodName = aPrefixName + Event.MethodName;
3817 SbxVariable * pP = xSbxObj.get();
3818 while( pP->GetParent() )
3820 pP = pP->GetParent();
3821 StarBASIC * pLib = dynamic_cast<StarBASIC*>( pP );
3822 if( pLib )
3824 // Create in a Basic Array
3825 SbxArrayRef xSbxArray = new SbxArray( SbxVARIANT );
3826 const Any * pArgs = Event.Arguments.getConstArray();
3827 sal_Int32 nCount = Event.Arguments.getLength();
3828 for( sal_Int32 i = 0; i < nCount; i++ )
3830 // Convert elements
3831 SbxVariableRef xVar = new SbxVariable( SbxVARIANT );
3832 unoToSbxValue( xVar.get(), pArgs[i] );
3833 xSbxArray->Put32( xVar.get(), i + 1 );
3836 pLib->Call( aMethodName, xSbxArray.get() );
3838 // get the return value from the Param-Array, if requested
3839 if( pRet )
3841 SbxVariable* pVar = xSbxArray->Get32( 0 );
3842 if( pVar )
3844 // #95792 Avoid a second call
3845 SbxFlagBits nFlags = pVar->GetFlags();
3846 pVar->SetFlag( SbxFlagBits::NoBroadcast );
3847 *pRet = sbxToUnoValueImpl( pVar );
3848 pVar->SetFlags( nFlags );
3851 break;
3857 // Methods of Listener
3858 void BasicAllListener_Impl::firing( const AllEventObject& Event )
3860 firing_impl( Event, nullptr );
3863 Any BasicAllListener_Impl::approveFiring( const AllEventObject& Event )
3865 Any aRetAny;
3866 firing_impl( Event, &aRetAny );
3867 return aRetAny;
3871 // Methods of XEventListener
3872 void BasicAllListener_Impl ::disposing(const EventObject& )
3874 SolarMutexGuard guard;
3876 xSbxObj.clear();
3880 // class InvocationToAllListenerMapper
3881 // helper class to map XInvocation to XAllListener (also in project eventattacher!)
3883 namespace {
3885 class InvocationToAllListenerMapper : public WeakImplHelper< XInvocation >
3887 public:
3888 InvocationToAllListenerMapper( const Reference< XIdlClass >& ListenerType,
3889 const Reference< XAllListener >& AllListener, const Any& Helper );
3891 // XInvocation
3892 virtual Reference< XIntrospectionAccess > SAL_CALL getIntrospection() override;
3893 virtual Any SAL_CALL invoke(const OUString& FunctionName, const Sequence< Any >& Params, Sequence< sal_Int16 >& OutParamIndex, Sequence< Any >& OutParam) override;
3894 virtual void SAL_CALL setValue(const OUString& PropertyName, const Any& Value) override;
3895 virtual Any SAL_CALL getValue(const OUString& PropertyName) override;
3896 virtual sal_Bool SAL_CALL hasMethod(const OUString& Name) override;
3897 virtual sal_Bool SAL_CALL hasProperty(const OUString& Name) override;
3899 private:
3900 Reference< XAllListener > m_xAllListener;
3901 Reference< XIdlClass > m_xListenerType;
3902 Any m_Helper;
3907 // Function to replace AllListenerAdapterService::createAllListerAdapter
3908 static Reference< XInterface > createAllListenerAdapter
3910 const Reference< XInvocationAdapterFactory2 >& xInvocationAdapterFactory,
3911 const Reference< XIdlClass >& xListenerType,
3912 const Reference< XAllListener >& xListener,
3913 const Any& Helper
3916 Reference< XInterface > xAdapter;
3917 if( xInvocationAdapterFactory.is() && xListenerType.is() && xListener.is() )
3919 Reference< XInvocation > xInvocationToAllListenerMapper =
3920 new InvocationToAllListenerMapper(xListenerType, xListener, Helper);
3921 Type aListenerType( xListenerType->getTypeClass(), xListenerType->getName() );
3922 xAdapter = xInvocationAdapterFactory->createAdapter( xInvocationToAllListenerMapper, {aListenerType} );
3924 return xAdapter;
3928 // InvocationToAllListenerMapper
3929 InvocationToAllListenerMapper::InvocationToAllListenerMapper
3930 ( const Reference< XIdlClass >& ListenerType, const Reference< XAllListener >& AllListener, const Any& Helper )
3931 : m_xAllListener( AllListener )
3932 , m_xListenerType( ListenerType )
3933 , m_Helper( Helper )
3938 Reference< XIntrospectionAccess > SAL_CALL InvocationToAllListenerMapper::getIntrospection()
3940 return Reference< XIntrospectionAccess >();
3944 Any SAL_CALL InvocationToAllListenerMapper::invoke(const OUString& FunctionName, const Sequence< Any >& Params,
3945 Sequence< sal_Int16 >&, Sequence< Any >&)
3947 Any aRet;
3949 // Check if to firing or approveFiring has to be called
3950 Reference< XIdlMethod > xMethod = m_xListenerType->getMethod( FunctionName );
3951 bool bApproveFiring = false;
3952 if( !xMethod.is() )
3953 return aRet;
3954 Reference< XIdlClass > xReturnType = xMethod->getReturnType();
3955 Sequence< Reference< XIdlClass > > aExceptionSeq = xMethod->getExceptionTypes();
3956 if( ( xReturnType.is() && xReturnType->getTypeClass() != TypeClass_VOID ) ||
3957 aExceptionSeq.hasElements() )
3959 bApproveFiring = true;
3961 else
3963 Sequence< ParamInfo > aParamSeq = xMethod->getParameterInfos();
3964 sal_uInt32 nParamCount = aParamSeq.getLength();
3965 if( nParamCount > 1 )
3967 const ParamInfo* pInfo = aParamSeq.getConstArray();
3968 for( sal_uInt32 i = 0 ; i < nParamCount ; i++ )
3970 if( pInfo[ i ].aMode != ParamMode_IN )
3972 bApproveFiring = true;
3973 break;
3979 AllEventObject aAllEvent;
3980 aAllEvent.Source = static_cast<OWeakObject*>(this);
3981 aAllEvent.Helper = m_Helper;
3982 aAllEvent.ListenerType = Type(m_xListenerType->getTypeClass(), m_xListenerType->getName() );
3983 aAllEvent.MethodName = FunctionName;
3984 aAllEvent.Arguments = Params;
3985 if( bApproveFiring )
3986 aRet = m_xAllListener->approveFiring( aAllEvent );
3987 else
3988 m_xAllListener->firing( aAllEvent );
3989 return aRet;
3993 void SAL_CALL InvocationToAllListenerMapper::setValue(const OUString&, const Any&)
3997 Any SAL_CALL InvocationToAllListenerMapper::getValue(const OUString&)
3999 return Any();
4003 sal_Bool SAL_CALL InvocationToAllListenerMapper::hasMethod(const OUString& Name)
4005 Reference< XIdlMethod > xMethod = m_xListenerType->getMethod( Name );
4006 return xMethod.is();
4010 sal_Bool SAL_CALL InvocationToAllListenerMapper::hasProperty(const OUString& Name)
4012 Reference< XIdlField > xField = m_xListenerType->getField( Name );
4013 return xField.is();
4017 // create Uno-Service
4018 // 1. Parameter == Prefix-Name of the macro
4019 // 2. Parameter == fully qualified name of the listener
4020 void SbRtl_CreateUnoListener(StarBASIC * pBasic, SbxArray & rPar, bool)
4022 // We need 2 parameters
4023 if ( rPar.Count32() != 3 )
4025 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
4026 return;
4029 // get the name of the class of the struct
4030 OUString aPrefixName = rPar.Get32(1)->GetOUString();
4031 OUString aListenerClassName = rPar.Get32(2)->GetOUString();
4033 // get the CoreReflection
4034 Reference< XIdlReflection > xCoreReflection = getCoreReflection_Impl();
4035 if( !xCoreReflection.is() )
4036 return;
4038 // get the AllListenerAdapterService
4039 Reference< XComponentContext > xContext( comphelper::getProcessComponentContext() );
4041 // search the class
4042 Reference< XIdlClass > xClass = xCoreReflection->forName( aListenerClassName );
4043 if( !xClass.is() )
4044 return;
4046 // From 1999-11-30: get the InvocationAdapterFactory
4047 Reference< XInvocationAdapterFactory2 > xInvocationAdapterFactory =
4048 InvocationAdapterFactory::create( xContext );
4050 BasicAllListener_Impl * p;
4051 Reference< XAllListener > xAllLst = p = new BasicAllListener_Impl( aPrefixName );
4052 Any aTmp;
4053 Reference< XInterface > xLst = createAllListenerAdapter( xInvocationAdapterFactory, xClass, xAllLst, aTmp );
4054 if( !xLst.is() )
4055 return;
4057 OUString aClassName = xClass->getName();
4058 Type aClassType( xClass->getTypeClass(), aClassName );
4059 aTmp = xLst->queryInterface( aClassType );
4060 if( !aTmp.hasValue() )
4061 return;
4063 SbUnoObject* pUnoObj = new SbUnoObject( aListenerClassName, aTmp );
4064 p->xSbxObj = pUnoObj;
4065 p->xSbxObj->SetParent( pBasic );
4067 // #100326 Register listener object to set Parent NULL in Dtor
4068 SbxArrayRef xBasicUnoListeners = pBasic->getUnoListeners();
4069 xBasicUnoListeners->Insert32( pUnoObj, xBasicUnoListeners->Count32() );
4071 // return the object
4072 SbxVariableRef refVar = rPar.Get32(0);
4073 refVar->PutObject( p->xSbxObj.get() );
4077 // Represents the DefaultContext property of the ProcessServiceManager
4078 // in the Basic runtime system.
4079 void RTL_Impl_GetDefaultContext( SbxArray& rPar )
4081 SbxVariableRef refVar = rPar.Get32(0);
4083 Any aContextAny( comphelper::getProcessComponentContext() );
4085 SbUnoObjectRef xUnoObj = new SbUnoObject( "DefaultContext", aContextAny );
4086 refVar->PutObject( xUnoObj.get() );
4090 // Creates a Basic wrapper object for a strongly typed Uno value
4091 // 1. parameter: Uno type as full qualified type name, e.g. "byte[]"
4092 void RTL_Impl_CreateUnoValue( SbxArray& rPar )
4094 // 2 parameters needed
4095 if ( rPar.Count32() != 3 )
4097 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
4098 return;
4101 // get the name of the class of the struct
4102 OUString aTypeName = rPar.Get32(1)->GetOUString();
4103 SbxVariable* pVal = rPar.Get32(2);
4105 if( aTypeName == "type" )
4107 SbxDataType eBaseType = pVal->SbxValue::GetType();
4108 OUString aValTypeName;
4109 if( eBaseType == SbxSTRING )
4111 aValTypeName = pVal->GetOUString();
4113 else if( eBaseType == SbxOBJECT )
4115 // XIdlClass?
4116 Reference< XIdlClass > xIdlClass;
4118 SbxBaseRef pObj = pVal->GetObject();
4119 if( auto obj = dynamic_cast<SbUnoObject*>( pObj.get() ) )
4121 Any aUnoAny = obj->getUnoAny();
4122 aUnoAny >>= xIdlClass;
4125 if( xIdlClass.is() )
4127 aValTypeName = xIdlClass->getName();
4130 Type aType;
4131 bool bSuccess = implGetTypeByName( aValTypeName, aType );
4132 if( bSuccess )
4134 Any aTypeAny( aType );
4135 SbxVariableRef refVar = rPar.Get32(0);
4136 SbxObjectRef xUnoAnyObject = new SbUnoAnyObject( aTypeAny );
4137 refVar->PutObject( xUnoAnyObject.get() );
4139 return;
4142 // Check the type
4143 const Reference< XHierarchicalNameAccess >& xTypeAccess = getTypeProvider_Impl();
4144 Any aRet;
4147 aRet = xTypeAccess->getByHierarchicalName( aTypeName );
4149 catch( const NoSuchElementException& e1 )
4151 StarBASIC::Error( ERRCODE_BASIC_EXCEPTION,
4152 implGetExceptionMsg( e1, "com.sun.star.container.NoSuchElementException" ) );
4153 return;
4155 Reference< XTypeDescription > xTypeDesc;
4156 aRet >>= xTypeDesc;
4157 TypeClass eTypeClass = xTypeDesc->getTypeClass();
4158 Type aDestType( eTypeClass, aTypeName );
4161 // Preconvert value
4162 Any aVal = sbxToUnoValueImpl( pVal );
4163 Any aConvertedVal = convertAny( aVal, aDestType );
4165 SbxVariableRef refVar = rPar.Get32(0);
4166 SbxObjectRef xUnoAnyObject = new SbUnoAnyObject( aConvertedVal );
4167 refVar->PutObject( xUnoAnyObject.get() );
4170 namespace {
4172 class ModuleInvocationProxy : public WeakImplHelper< XInvocation, XComponent >
4174 ::osl::Mutex m_aMutex;
4175 OUString m_aPrefix;
4176 SbxObjectRef m_xScopeObj;
4177 bool m_bProxyIsClassModuleObject;
4179 ::comphelper::OInterfaceContainerHelper2 m_aListeners;
4181 public:
4182 ModuleInvocationProxy( OUString const & aPrefix, SbxObjectRef const & xScopeObj );
4184 // XInvocation
4185 virtual Reference< XIntrospectionAccess > SAL_CALL getIntrospection() override;
4186 virtual void SAL_CALL setValue( const OUString& rProperty, const Any& rValue ) override;
4187 virtual Any SAL_CALL getValue( const OUString& rProperty ) override;
4188 virtual sal_Bool SAL_CALL hasMethod( const OUString& rName ) override;
4189 virtual sal_Bool SAL_CALL hasProperty( const OUString& rProp ) override;
4191 virtual Any SAL_CALL invoke( const OUString& rFunction,
4192 const Sequence< Any >& rParams,
4193 Sequence< sal_Int16 >& rOutParamIndex,
4194 Sequence< Any >& rOutParam ) override;
4196 // XComponent
4197 virtual void SAL_CALL dispose() override;
4198 virtual void SAL_CALL addEventListener( const Reference< XEventListener >& xListener ) override;
4199 virtual void SAL_CALL removeEventListener( const Reference< XEventListener >& aListener ) override;
4204 ModuleInvocationProxy::ModuleInvocationProxy( OUString const & aPrefix, SbxObjectRef const & xScopeObj )
4205 : m_aMutex()
4206 , m_aPrefix( aPrefix + "_" )
4207 , m_xScopeObj( xScopeObj )
4208 , m_aListeners( m_aMutex )
4210 m_bProxyIsClassModuleObject = xScopeObj.is() && dynamic_cast<const SbClassModuleObject*>( xScopeObj.get() ) != nullptr;
4213 Reference< XIntrospectionAccess > SAL_CALL ModuleInvocationProxy::getIntrospection()
4215 return Reference< XIntrospectionAccess >();
4218 void SAL_CALL ModuleInvocationProxy::setValue(const OUString& rProperty, const Any& rValue)
4220 if( !m_bProxyIsClassModuleObject )
4221 throw UnknownPropertyException();
4223 SolarMutexGuard guard;
4225 OUString aPropertyFunctionName = "Property Set "
4226 + m_aPrefix
4227 + rProperty;
4229 SbxVariable* p = m_xScopeObj->Find( aPropertyFunctionName, SbxClassType::Method );
4230 SbMethod* pMeth = dynamic_cast<SbMethod*>( p );
4231 if( pMeth == nullptr )
4233 // TODO: Check vba behavior concerning missing function
4234 //StarBASIC::Error( ERRCODE_BASIC_NO_METHOD, aFunctionName );
4235 throw UnknownPropertyException(aPropertyFunctionName);
4238 // Setup parameter
4239 SbxArrayRef xArray = new SbxArray;
4240 SbxVariableRef xVar = new SbxVariable( SbxVARIANT );
4241 unoToSbxValue( xVar.get(), rValue );
4242 xArray->Put32( xVar.get(), 1 );
4244 // Call property method
4245 SbxVariableRef xValue = new SbxVariable;
4246 pMeth->SetParameters( xArray.get() );
4247 pMeth->Call( xValue.get() );
4248 pMeth->SetParameters( nullptr );
4250 // TODO: OutParameter?
4255 Any SAL_CALL ModuleInvocationProxy::getValue(const OUString& rProperty)
4257 if( !m_bProxyIsClassModuleObject )
4259 throw UnknownPropertyException();
4261 SolarMutexGuard guard;
4263 OUString aPropertyFunctionName = "Property Get "
4264 + m_aPrefix
4265 + rProperty;
4267 SbxVariable* p = m_xScopeObj->Find( aPropertyFunctionName, SbxClassType::Method );
4268 SbMethod* pMeth = dynamic_cast<SbMethod*>( p );
4269 if( pMeth == nullptr )
4271 // TODO: Check vba behavior concerning missing function
4272 //StarBASIC::Error( ERRCODE_BASIC_NO_METHOD, aFunctionName );
4273 throw UnknownPropertyException(aPropertyFunctionName);
4276 // Call method
4277 SbxVariableRef xValue = new SbxVariable;
4278 pMeth->Call( xValue.get() );
4279 Any aRet = sbxToUnoValue( xValue.get() );
4280 return aRet;
4283 sal_Bool SAL_CALL ModuleInvocationProxy::hasMethod( const OUString& )
4285 return false;
4288 sal_Bool SAL_CALL ModuleInvocationProxy::hasProperty( const OUString& )
4290 return false;
4293 Any SAL_CALL ModuleInvocationProxy::invoke( const OUString& rFunction,
4294 const Sequence< Any >& rParams,
4295 Sequence< sal_Int16 >&,
4296 Sequence< Any >& )
4298 SolarMutexGuard guard;
4300 Any aRet;
4301 SbxObjectRef xScopeObj = m_xScopeObj;
4302 if( !xScopeObj.is() )
4304 return aRet;
4306 OUString aFunctionName = m_aPrefix
4307 + rFunction;
4309 bool bSetRescheduleBack = false;
4310 bool bOldReschedule = true;
4311 SbiInstance* pInst = GetSbData()->pInst;
4312 if( pInst && pInst->IsCompatibility() )
4314 bOldReschedule = pInst->IsReschedule();
4315 if ( bOldReschedule )
4317 pInst->EnableReschedule( false );
4318 bSetRescheduleBack = true;
4322 SbxVariable* p = xScopeObj->Find( aFunctionName, SbxClassType::Method );
4323 SbMethod* pMeth = dynamic_cast<SbMethod*>( p );
4324 if( pMeth == nullptr )
4326 // TODO: Check vba behavior concerning missing function
4327 //StarBASIC::Error( ERRCODE_BASIC_NO_METHOD, aFunctionName );
4328 return aRet;
4331 // Setup parameters
4332 SbxArrayRef xArray;
4333 sal_Int32 nParamCount = rParams.getLength();
4334 if( nParamCount )
4336 xArray = new SbxArray;
4337 const Any *pArgs = rParams.getConstArray();
4338 for( sal_Int32 i = 0 ; i < nParamCount ; i++ )
4340 SbxVariableRef xVar = new SbxVariable( SbxVARIANT );
4341 unoToSbxValue( xVar.get(), pArgs[i] );
4342 xArray->Put32( xVar.get(), sal::static_int_cast< sal_uInt16 >(i+1) );
4346 // Call method
4347 SbxVariableRef xValue = new SbxVariable;
4348 if( xArray.is() )
4349 pMeth->SetParameters( xArray.get() );
4350 pMeth->Call( xValue.get() );
4351 aRet = sbxToUnoValue( xValue.get() );
4352 pMeth->SetParameters( nullptr );
4354 if( bSetRescheduleBack )
4355 pInst->EnableReschedule( bOldReschedule );
4357 // TODO: OutParameter?
4359 return aRet;
4362 void SAL_CALL ModuleInvocationProxy::dispose()
4364 ::osl::MutexGuard aGuard( m_aMutex );
4366 EventObject aEvent( static_cast<XComponent*>(this) );
4367 m_aListeners.disposeAndClear( aEvent );
4369 m_xScopeObj = nullptr;
4372 void SAL_CALL ModuleInvocationProxy::addEventListener( const Reference< XEventListener >& xListener )
4374 m_aListeners.addInterface( xListener );
4377 void SAL_CALL ModuleInvocationProxy::removeEventListener( const Reference< XEventListener >& xListener )
4379 m_aListeners.removeInterface( xListener );
4383 Reference< XInterface > createComListener( const Any& aControlAny, const OUString& aVBAType,
4384 const OUString& aPrefix, const SbxObjectRef& xScopeObj )
4386 Reference< XInterface > xRet;
4388 Reference< XComponentContext > xContext(
4389 comphelper::getProcessComponentContext() );
4390 Reference< XMultiComponentFactory > xServiceMgr( xContext->getServiceManager() );
4392 Reference< XInvocation > xProxy = new ModuleInvocationProxy( aPrefix, xScopeObj );
4394 Sequence<Any> args( 3 );
4395 args[0] = aControlAny;
4396 args[1] <<= aVBAType;
4397 args[2] <<= xProxy;
4401 xRet = xServiceMgr->createInstanceWithArgumentsAndContext(
4402 "com.sun.star.custom.UnoComListener",
4403 args, xContext );
4405 catch( const Exception& )
4407 implHandleAnyException( ::cppu::getCaughtException() );
4410 return xRet;
4413 typedef std::vector< WeakReference< XComponent > > ComponentRefVector;
4415 namespace {
4417 struct StarBasicDisposeItem
4419 StarBASIC* m_pBasic;
4420 SbxArrayRef m_pRegisteredVariables;
4421 ComponentRefVector m_vComImplementsObjects;
4423 explicit StarBasicDisposeItem( StarBASIC* pBasic )
4424 : m_pBasic( pBasic )
4425 , m_pRegisteredVariables(new SbxArray())
4432 typedef std::vector< StarBasicDisposeItem* > DisposeItemVector;
4434 static DisposeItemVector GaDisposeItemVector;
4436 static DisposeItemVector::iterator lcl_findItemForBasic( StarBASIC const * pBasic )
4438 return std::find_if(GaDisposeItemVector.begin(), GaDisposeItemVector.end(),
4439 [&pBasic](StarBasicDisposeItem* pItem) { return pItem->m_pBasic == pBasic; });
4442 static StarBasicDisposeItem* lcl_getOrCreateItemForBasic( StarBASIC* pBasic )
4444 DisposeItemVector::iterator it = lcl_findItemForBasic( pBasic );
4445 StarBasicDisposeItem* pItem = (it != GaDisposeItemVector.end()) ? *it : nullptr;
4446 if( pItem == nullptr )
4448 pItem = new StarBasicDisposeItem( pBasic );
4449 GaDisposeItemVector.push_back( pItem );
4451 return pItem;
4454 void registerComponentToBeDisposedForBasic
4455 ( const Reference< XComponent >& xComponent, StarBASIC* pBasic )
4457 StarBasicDisposeItem* pItem = lcl_getOrCreateItemForBasic( pBasic );
4458 pItem->m_vComImplementsObjects.emplace_back(xComponent );
4461 void registerComListenerVariableForBasic( SbxVariable* pVar, StarBASIC* pBasic )
4463 StarBasicDisposeItem* pItem = lcl_getOrCreateItemForBasic( pBasic );
4464 SbxArray* pArray = pItem->m_pRegisteredVariables.get();
4465 pArray->Put32( pVar, pArray->Count32() );
4468 void disposeComVariablesForBasic( StarBASIC const * pBasic )
4470 DisposeItemVector::iterator it = lcl_findItemForBasic( pBasic );
4471 if( it == GaDisposeItemVector.end() )
4472 return;
4474 StarBasicDisposeItem* pItem = *it;
4476 SbxArray* pArray = pItem->m_pRegisteredVariables.get();
4477 sal_uInt32 nCount = pArray->Count32();
4478 for( sal_uInt32 i = 0 ; i < nCount ; ++i )
4480 SbxVariable* pVar = pArray->Get32( i );
4481 pVar->ClearComListener();
4484 ComponentRefVector& rv = pItem->m_vComImplementsObjects;
4485 for (auto const& elem : rv)
4487 Reference< XComponent > xComponent( elem.get(), UNO_QUERY );
4488 if (xComponent.is())
4489 xComponent->dispose();
4492 delete pItem;
4493 GaDisposeItemVector.erase( it );
4497 // Handle module implements mechanism for OLE types
4498 bool SbModule::createCOMWrapperForIface( Any& o_rRetAny, SbClassModuleObject* pProxyClassModuleObject )
4500 // For now: Take first interface that allows to instantiate COM wrapper
4501 // TODO: Check if support for multiple interfaces is needed
4503 Reference< XComponentContext > xContext(
4504 comphelper::getProcessComponentContext() );
4505 Reference< XMultiComponentFactory > xServiceMgr( xContext->getServiceManager() );
4506 Reference< XSingleServiceFactory > xComImplementsFactory
4508 xServiceMgr->createInstanceWithContext( "com.sun.star.custom.ComImplementsFactory", xContext ),
4509 UNO_QUERY
4511 if( !xComImplementsFactory.is() )
4512 return false;
4514 bool bSuccess = false;
4516 SbxArray* pModIfaces = pClassData->mxIfaces.get();
4517 sal_uInt32 nCount = pModIfaces->Count32();
4518 for( sal_uInt32 i = 0 ; i < nCount ; ++i )
4520 SbxVariable* pVar = pModIfaces->Get32( i );
4521 const OUString& aIfaceName = pVar->GetName();
4523 if( !aIfaceName.isEmpty() )
4525 OUString aPureIfaceName = aIfaceName;
4526 sal_Int32 indexLastDot = aIfaceName.lastIndexOf('.');
4527 if ( indexLastDot > -1 )
4529 aPureIfaceName = aIfaceName.copy( indexLastDot + 1 );
4531 Reference< XInvocation > xProxy = new ModuleInvocationProxy( aPureIfaceName, pProxyClassModuleObject );
4533 Sequence<Any> args( 2 );
4534 args[0] <<= aIfaceName;
4535 args[1] <<= xProxy;
4537 Reference< XInterface > xRet;
4540 xRet = xComImplementsFactory->createInstanceWithArguments( args );
4541 bSuccess = true;
4543 catch( const Exception& )
4545 implHandleAnyException( ::cppu::getCaughtException() );
4548 if( bSuccess )
4550 Reference< XComponent > xComponent( xProxy, UNO_QUERY );
4551 if( xComponent.is() )
4553 StarBASIC* pParentBasic = nullptr;
4554 SbxObject* pCurObject = this;
4557 SbxObject* pObjParent = pCurObject->GetParent();
4558 pParentBasic = dynamic_cast<StarBASIC*>( pObjParent );
4559 pCurObject = pObjParent;
4561 while( pParentBasic == nullptr && pCurObject != nullptr );
4563 assert( pParentBasic != nullptr );
4564 registerComponentToBeDisposedForBasic( xComponent, pParentBasic );
4567 o_rRetAny <<= xRet;
4568 break;
4573 return bSuccess;
4577 // Due to an incorrect behavior IE returns an object instead of a string
4578 // in some scenarios. Calling toString at the object may correct this.
4579 // Helper function used in sbxvalue.cxx
4580 bool handleToStringForCOMObjects( SbxObject* pObj, SbxValue* pVal )
4582 bool bSuccess = false;
4584 if( auto pUnoObj = dynamic_cast<SbUnoObject*>( pObj) )
4586 // Only for native COM objects
4587 if( pUnoObj->isNativeCOMObject() )
4589 SbxVariableRef pMeth = pObj->Find( "toString", SbxClassType::Method );
4590 if ( pMeth.is() )
4592 SbxValues aRes;
4593 pMeth->Get( aRes );
4594 pVal->Put( aRes );
4595 bSuccess = true;
4599 return bSuccess;
4602 Any StructRefInfo::getValue()
4604 Any aRet;
4605 uno_any_destruct(
4606 &aRet, reinterpret_cast< uno_ReleaseFunc >(cpp_release) );
4607 typelib_TypeDescription * pTD = nullptr;
4608 maType.getDescription(&pTD);
4609 uno_any_construct(
4610 &aRet, getInst(), pTD,
4611 reinterpret_cast< uno_AcquireFunc >(cpp_acquire) );
4612 typelib_typedescription_release(pTD);
4613 return aRet;
4616 void StructRefInfo::setValue( const Any& rValue )
4618 bool bSuccess = uno_type_assignData( getInst(),
4619 maType.getTypeLibType(),
4620 const_cast<void*>(rValue.getValue()),
4621 rValue.getValueTypeRef(),
4622 reinterpret_cast< uno_QueryInterfaceFunc >(cpp_queryInterface),
4623 reinterpret_cast< uno_AcquireFunc >(cpp_acquire),
4624 reinterpret_cast< uno_ReleaseFunc >(cpp_release) );
4625 OSL_ENSURE(bSuccess,
4626 "StructRefInfo::setValue: ooops... the value could not be assigned!");
4629 OUString StructRefInfo::getTypeName() const
4631 return maType.getTypeName();
4634 void* StructRefInfo::getInst()
4636 return const_cast<char *>(static_cast<char const *>(maAny.getValue()) + mnPos);
4639 TypeClass StructRefInfo::getTypeClass() const
4641 return maType.getTypeClass();
4644 SbUnoStructRefObject::SbUnoStructRefObject( const OUString& aName_, const StructRefInfo& rMemberInfo ) : SbxObject( aName_ ), maMemberInfo( rMemberInfo ), mbMemberCacheInit( false )
4646 SetClassName( maMemberInfo.getTypeName() );
4649 SbUnoStructRefObject::~SbUnoStructRefObject()
4653 void SbUnoStructRefObject::initMemberCache()
4655 if ( mbMemberCacheInit )
4656 return;
4657 typelib_TypeDescription * pTD = nullptr;
4658 maMemberInfo.getType().getDescription(&pTD);
4659 for ( typelib_CompoundTypeDescription * pCompTypeDescr = reinterpret_cast<typelib_CompoundTypeDescription *>(pTD);
4660 pCompTypeDescr;
4661 pCompTypeDescr = pCompTypeDescr->pBaseTypeDescription )
4663 typelib_TypeDescriptionReference ** ppTypeRefs = pCompTypeDescr->ppTypeRefs;
4664 rtl_uString ** ppNames = pCompTypeDescr->ppMemberNames;
4665 sal_Int32 * pMemberOffsets = pCompTypeDescr->pMemberOffsets;
4666 for ( sal_Int32 nPos = pCompTypeDescr->nMembers; nPos--; )
4668 OUString aName( ppNames[nPos] );
4669 maFields[ aName ] = std::make_unique<StructRefInfo>( maMemberInfo.getRootAnyRef(), ppTypeRefs[nPos], maMemberInfo.getPos() + pMemberOffsets[nPos] );
4672 typelib_typedescription_release(pTD);
4673 mbMemberCacheInit = true;
4676 SbxVariable* SbUnoStructRefObject::Find( const OUString& rName, SbxClassType t )
4678 SbxVariable* pRes = SbxObject::Find( rName, t );
4679 if ( !pRes )
4681 if ( !mbMemberCacheInit )
4682 initMemberCache();
4683 StructFieldInfo::iterator it = maFields.find( rName );
4684 if ( it != maFields.end() )
4686 SbxDataType eSbxType;
4687 eSbxType = unoToSbxType( it->second->getTypeClass() );
4688 SbxDataType eRealSbxType = eSbxType;
4689 Property aProp;
4690 aProp.Name = rName;
4691 aProp.Type = css::uno::Type( it->second->getTypeClass(), it->second->getTypeName() );
4692 SbUnoProperty* pProp = new SbUnoProperty( rName, eSbxType, eRealSbxType, aProp, 0, false, ( aProp.Type.getTypeClass() == css::uno::TypeClass_STRUCT) );
4693 SbxVariableRef xVarRef = pProp;
4694 QuickInsert( xVarRef.get() );
4695 pRes = xVarRef.get();
4699 if( !pRes )
4701 if( rName.equalsIgnoreAsciiCase(ID_DBG_SUPPORTEDINTERFACES) ||
4702 rName.equalsIgnoreAsciiCase(ID_DBG_PROPERTIES) ||
4703 rName.equalsIgnoreAsciiCase(ID_DBG_METHODS) )
4705 // Create
4706 implCreateDbgProperties();
4708 // Now they have to be found regular
4709 pRes = SbxObject::Find( rName, SbxClassType::DontCare );
4713 return pRes;
4716 // help method to create the dbg_-Properties
4717 void SbUnoStructRefObject::implCreateDbgProperties()
4719 Property aProp;
4721 // Id == -1: display the implemented interfaces corresponding the ClassProvider
4722 SbxVariableRef xVarRef = new SbUnoProperty( ID_DBG_SUPPORTEDINTERFACES, SbxSTRING, SbxSTRING, aProp, -1, false, false );
4723 QuickInsert( xVarRef.get() );
4725 // Id == -2: output the properties
4726 xVarRef = new SbUnoProperty( ID_DBG_PROPERTIES, SbxSTRING, SbxSTRING, aProp, -2, false, false );
4727 QuickInsert( xVarRef.get() );
4729 // Id == -3: output the Methods
4730 xVarRef = new SbUnoProperty( ID_DBG_METHODS, SbxSTRING, SbxSTRING, aProp, -3, false, false );
4731 QuickInsert( xVarRef.get() );
4734 void SbUnoStructRefObject::implCreateAll()
4736 // throw away all existing methods and properties
4737 pMethods = new SbxArray;
4738 pProps = new SbxArray;
4740 if (!mbMemberCacheInit)
4741 initMemberCache();
4743 for (auto const& field : maFields)
4745 const OUString& rName = field.first;
4746 SbxDataType eSbxType;
4747 eSbxType = unoToSbxType( field.second->getTypeClass() );
4748 SbxDataType eRealSbxType = eSbxType;
4749 Property aProp;
4750 aProp.Name = rName;
4751 aProp.Type = css::uno::Type( field.second->getTypeClass(), field.second->getTypeName() );
4752 SbUnoProperty* pProp = new SbUnoProperty( rName, eSbxType, eRealSbxType, aProp, 0, false, ( aProp.Type.getTypeClass() == css::uno::TypeClass_STRUCT) );
4753 SbxVariableRef xVarRef = pProp;
4754 QuickInsert( xVarRef.get() );
4757 // Create Dbg_-Properties
4758 implCreateDbgProperties();
4761 // output the value
4762 Any SbUnoStructRefObject::getUnoAny()
4764 return maMemberInfo.getValue();
4767 OUString SbUnoStructRefObject::Impl_DumpProperties()
4769 OUStringBuffer aRet;
4770 aRet.append("Properties of object ");
4771 aRet.append( getDbgObjectName() );
4773 sal_uInt32 nPropCount = pProps->Count32();
4774 sal_uInt32 nPropsPerLine = 1 + nPropCount / 30;
4775 for( sal_uInt32 i = 0; i < nPropCount; i++ )
4777 SbxVariable* pVar = pProps->Get32( i );
4778 if( pVar )
4780 OUStringBuffer aPropStr;
4781 if( (i % nPropsPerLine) == 0 )
4783 aPropStr.append( "\n" );
4785 // output the type and name
4786 // Is it in Uno a sequence?
4787 SbxDataType eType = pVar->GetFullType();
4789 const OUString& aName( pVar->GetName() );
4790 StructFieldInfo::iterator it = maFields.find( aName );
4792 if ( it != maFields.end() )
4794 const StructRefInfo& rPropInfo = *it->second;
4796 if( eType == SbxOBJECT )
4798 if( rPropInfo.getTypeClass() == TypeClass_SEQUENCE )
4800 eType = SbxDataType( SbxOBJECT | SbxARRAY );
4804 aPropStr.append( Dbg_SbxDataType2String( eType ) );
4806 aPropStr.append( " " );
4807 aPropStr.append( pVar->GetName() );
4809 if( i == nPropCount - 1 )
4811 aPropStr.append( "\n" );
4813 else
4815 aPropStr.append( "; " );
4817 aRet.append( aPropStr.makeStringAndClear() );
4820 return aRet.makeStringAndClear();
4823 void SbUnoStructRefObject::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
4825 if ( !mbMemberCacheInit )
4826 initMemberCache();
4827 const SbxHint* pHint = dynamic_cast<const SbxHint*>(&rHint);
4828 if( !pHint )
4829 return;
4831 SbxVariable* pVar = pHint->GetVar();
4832 SbUnoProperty* pProp = dynamic_cast<SbUnoProperty*>( pVar );
4833 if( pProp )
4835 StructFieldInfo::iterator it = maFields.find( pProp->GetName() );
4836 // handle get/set of members of struct
4837 if( pHint->GetId() == SfxHintId::BasicDataWanted )
4839 // Test-Properties
4840 sal_Int32 nId = pProp->nId;
4841 if( nId < 0 )
4843 // Id == -1: Display implemented interfaces according the ClassProvider
4844 if( nId == -1 ) // Property ID_DBG_SUPPORTEDINTERFACES"
4846 OUString aRet = OUStringLiteral( ID_DBG_SUPPORTEDINTERFACES )
4847 + " not available.\n(TypeClass is not TypeClass_INTERFACE)\n";
4849 pVar->PutString( aRet );
4851 // Id == -2: output properties
4852 else if( nId == -2 ) // Property ID_DBG_PROPERTIES
4854 // by now all properties must be established
4855 implCreateAll();
4856 OUString aRetStr = Impl_DumpProperties();
4857 pVar->PutString( aRetStr );
4859 // Id == -3: output the methods
4860 else if( nId == -3 ) // Property ID_DBG_METHODS
4862 // by now all properties must be established
4863 implCreateAll();
4864 OUString aRet = "Methods of object "
4865 + getDbgObjectName()
4866 + "\nNo methods found\n";
4867 pVar->PutString( aRet );
4869 return;
4872 if ( it != maFields.end() )
4874 Any aRetAny = it->second->getValue();
4875 unoToSbxValue( pVar, aRetAny );
4877 else
4878 StarBASIC::Error( ERRCODE_BASIC_PROPERTY_NOT_FOUND );
4880 else if( pHint->GetId() == SfxHintId::BasicDataChanged )
4882 if ( it != maFields.end() )
4884 // take over the value from Uno to Sbx
4885 Any aAnyValue = sbxToUnoValue( pVar, pProp->aUnoProp.Type, &pProp->aUnoProp );
4886 it->second->setValue( aAnyValue );
4888 else
4889 StarBASIC::Error( ERRCODE_BASIC_PROPERTY_NOT_FOUND );
4892 else
4893 SbxObject::Notify( rBC, rHint );
4896 StructRefInfo SbUnoStructRefObject::getStructMember( const OUString& rMemberName )
4898 if (!mbMemberCacheInit)
4900 initMemberCache();
4902 StructFieldInfo::iterator it = maFields.find( rMemberName );
4904 css::uno::Type aFoundType;
4905 sal_Int32 nFoundPos = -1;
4907 if ( it != maFields.end() )
4909 aFoundType = it->second->getType();
4910 nFoundPos = it->second->getPos();
4912 StructRefInfo aRet( maMemberInfo.getRootAnyRef(), aFoundType, nFoundPos );
4913 return aRet;
4916 OUString SbUnoStructRefObject::getDbgObjectName() const
4918 OUString aName = GetClassName();
4919 if( aName.isEmpty() )
4921 aName += "Unknown";
4923 OUStringBuffer aRet;
4924 if( aName.getLength() > 20 )
4926 aRet.append( "\n" );
4928 aRet.append( "\"" );
4929 aRet.append( aName );
4930 aRet.append( "\":" );
4931 return aRet.makeStringAndClear();
4934 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */