Version 6.4.0.3, tag libreoffice-6.4.0.3
[LibreOffice.git] / basic / source / classes / sbunoobj.cxx
blob26aedddd3a40048fb3b8a40daa59de2233de52e3
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/ustrbuf.hxx>
38 #include <com/sun/star/script/ArrayWrapper.hpp>
39 #include <com/sun/star/script/CannotConvertException.hpp>
40 #include <com/sun/star/script/NativeObjectWrapper.hpp>
42 #include <com/sun/star/uno/XComponentContext.hpp>
43 #include <com/sun/star/uno/DeploymentException.hpp>
44 #include <com/sun/star/lang/XTypeProvider.hpp>
45 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
46 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
47 #include <com/sun/star/lang/XServiceInfo.hpp>
48 #include <com/sun/star/beans/PropertyAttribute.hpp>
49 #include <com/sun/star/beans/PropertyConcept.hpp>
50 #include <com/sun/star/beans/MethodConcept.hpp>
51 #include <com/sun/star/beans/XPropertySet.hpp>
52 #include <com/sun/star/beans/theIntrospection.hpp>
53 #include <com/sun/star/script/BasicErrorException.hpp>
54 #include <com/sun/star/script/InvocationAdapterFactory.hpp>
55 #include <com/sun/star/script/XAllListener.hpp>
56 #include <com/sun/star/script/Converter.hpp>
57 #include <com/sun/star/script/XDefaultProperty.hpp>
58 #include <com/sun/star/script/XDirectInvocation.hpp>
59 #include <com/sun/star/container/XNameAccess.hpp>
60 #include <com/sun/star/container/XHierarchicalNameAccess.hpp>
61 #include <com/sun/star/reflection/XIdlArray.hpp>
62 #include <com/sun/star/reflection/XIdlReflection.hpp>
63 #include <com/sun/star/reflection/XServiceConstructorDescription.hpp>
64 #include <com/sun/star/reflection/XSingletonTypeDescription.hpp>
65 #include <com/sun/star/reflection/theCoreReflection.hpp>
66 #include <com/sun/star/bridge/oleautomation/NamedArgument.hpp>
67 #include <com/sun/star/bridge/oleautomation/Date.hpp>
68 #include <com/sun/star/bridge/oleautomation/Decimal.hpp>
69 #include <com/sun/star/bridge/oleautomation/Currency.hpp>
70 #include <com/sun/star/bridge/oleautomation/XAutomationObject.hpp>
71 #include <com/sun/star/script/XAutomationInvocation.hpp>
73 #include <rtlproto.hxx>
75 #include <basic/sbstar.hxx>
76 #include <basic/sbuno.hxx>
77 #include <basic/sberrors.hxx>
78 #include <sbunoobj.hxx>
79 #include <sbintern.hxx>
80 #include <runtime.hxx>
82 #include <algorithm>
83 #include <math.h>
84 #include <memory>
85 #include <unordered_map>
86 #include <com/sun/star/reflection/XTypeDescriptionEnumerationAccess.hpp>
87 #include <com/sun/star/reflection/XConstantsTypeDescription.hpp>
89 using com::sun::star::uno::Reference;
90 using namespace com::sun::star::uno;
91 using namespace com::sun::star::lang;
92 using namespace com::sun::star::reflection;
93 using namespace com::sun::star::beans;
94 using namespace com::sun::star::script;
95 using namespace com::sun::star::container;
96 using namespace com::sun::star::bridge;
97 using namespace cppu;
100 // Identifiers for creating the strings for dbg_Properties
101 static char const ID_DBG_SUPPORTEDINTERFACES[] = "Dbg_SupportedInterfaces";
102 static char const ID_DBG_PROPERTIES[] = "Dbg_Properties";
103 static char const ID_DBG_METHODS[] = "Dbg_Methods";
105 static char const aSeqLevelStr[] = "[]";
107 // Gets the default property for a uno object. Note: There is some
108 // redirection built in. The property name specifies the name
109 // of the default property.
111 bool SbUnoObject::getDefaultPropName( SbUnoObject const * pUnoObj, OUString& sDfltProp )
113 bool bResult = false;
114 Reference< XDefaultProperty> xDefaultProp( pUnoObj->maTmpUnoObj, UNO_QUERY );
115 if ( xDefaultProp.is() )
117 sDfltProp = xDefaultProp->getDefaultPropertyName();
118 if ( !sDfltProp.isEmpty() )
119 bResult = true;
121 return bResult;
124 SbxVariable* getDefaultProp( SbxVariable* pRef )
126 SbxVariable* pDefaultProp = nullptr;
127 if ( pRef->GetType() == SbxOBJECT )
129 SbxObject* pObj = dynamic_cast<SbxObject*>(pRef);
130 if (!pObj)
132 SbxBase* pObjVarObj = pRef->GetObject();
133 pObj = dynamic_cast<SbxObject*>( pObjVarObj );
135 if (SbUnoObject* pUnoObj = dynamic_cast<SbUnoObject*>(pObj))
137 pDefaultProp = pUnoObj->GetDfltProperty();
140 return pDefaultProp;
143 void SetSbUnoObjectDfltPropName( SbxObject* pObj )
145 SbUnoObject* pUnoObj = dynamic_cast<SbUnoObject*>( pObj );
146 if ( pUnoObj )
148 OUString sDfltPropName;
150 if ( SbUnoObject::getDefaultPropName( pUnoObj, sDfltPropName ) )
152 pUnoObj->SetDfltProperty( sDfltPropName );
157 // save CoreReflection statically
158 static Reference< XIdlReflection > getCoreReflection_Impl()
160 return css::reflection::theCoreReflection::get(
161 comphelper::getProcessComponentContext());
164 // save CoreReflection statically
165 static Reference< XHierarchicalNameAccess > const & getCoreReflection_HierarchicalNameAccess_Impl()
167 static Reference< XHierarchicalNameAccess > xCoreReflection_HierarchicalNameAccess;
169 if( !xCoreReflection_HierarchicalNameAccess.is() )
171 Reference< XIdlReflection > xCoreReflection = getCoreReflection_Impl();
172 if( xCoreReflection.is() )
174 xCoreReflection_HierarchicalNameAccess =
175 Reference< XHierarchicalNameAccess >( xCoreReflection, UNO_QUERY );
178 return xCoreReflection_HierarchicalNameAccess;
181 // Hold TypeProvider statically
182 static Reference< XHierarchicalNameAccess > const & getTypeProvider_Impl()
184 static Reference< XHierarchicalNameAccess > xAccess;
186 // Do we have already CoreReflection; if not obtain it
187 if( !xAccess.is() )
189 Reference< XComponentContext > xContext(
190 comphelper::getProcessComponentContext() );
191 if( xContext.is() )
193 xContext->getValueByName(
194 "/singletons/com.sun.star.reflection.theTypeDescriptionManager" )
195 >>= xAccess;
196 OSL_ENSURE( xAccess.is(), "### TypeDescriptionManager singleton not accessible!?" );
198 if( !xAccess.is() )
200 throw DeploymentException(
201 "/singletons/com.sun.star.reflection.theTypeDescriptionManager singleton not accessible" );
204 return xAccess;
207 // Hold TypeConverter statically
208 static Reference< XTypeConverter > const & getTypeConverter_Impl()
210 static Reference< XTypeConverter > xTypeConverter;
212 // Do we have already CoreReflection; if not obtain it
213 if( !xTypeConverter.is() )
215 Reference< XComponentContext > xContext(
216 comphelper::getProcessComponentContext() );
217 if( xContext.is() )
219 xTypeConverter = Converter::create(xContext);
221 if( !xTypeConverter.is() )
223 throw DeploymentException(
224 "com.sun.star.script.Converter service not accessible" );
227 return xTypeConverter;
231 // #111851 factory function to create an OLE object
232 SbUnoObject* createOLEObject_Impl( const OUString& aType )
234 static Reference< XMultiServiceFactory > xOLEFactory;
235 static bool bNeedsInit = true;
237 if( bNeedsInit )
239 bNeedsInit = false;
241 Reference< XComponentContext > xContext( comphelper::getProcessComponentContext() );
242 if( xContext.is() )
244 Reference<XMultiComponentFactory> xSMgr = xContext->getServiceManager();
245 xOLEFactory.set(
246 xSMgr->createInstanceWithContext( "com.sun.star.bridge.OleObjectFactory", xContext ),
247 UNO_QUERY );
251 SbUnoObject* pUnoObj = nullptr;
252 if( xOLEFactory.is() )
254 // some type names available in VBA can not be directly used in COM
255 OUString aOLEType = aType;
256 if ( aOLEType == "SAXXMLReader30" )
258 aOLEType = "Msxml2.SAXXMLReader.3.0";
260 Reference< XInterface > xOLEObject = xOLEFactory->createInstance( aOLEType );
261 if( xOLEObject.is() )
263 pUnoObj = new SbUnoObject( aType, Any(xOLEObject) );
264 OUString sDfltPropName;
266 if ( SbUnoObject::getDefaultPropName( pUnoObj, sDfltPropName ) )
267 pUnoObj->SetDfltProperty( sDfltPropName );
270 return pUnoObj;
274 namespace
276 void lcl_indent( OUStringBuffer& _inout_rBuffer, sal_Int32 _nLevel )
278 while ( _nLevel-- > 0 )
280 _inout_rBuffer.append( " " );
285 static void implAppendExceptionMsg( OUStringBuffer& _inout_rBuffer, const Exception& _e, const OUString& _rExceptionType, sal_Int32 _nLevel )
287 _inout_rBuffer.append( "\n" );
288 lcl_indent( _inout_rBuffer, _nLevel );
289 _inout_rBuffer.append( "Type: " );
291 if ( _rExceptionType.isEmpty() )
292 _inout_rBuffer.append( "Unknown" );
293 else
294 _inout_rBuffer.append( _rExceptionType );
296 _inout_rBuffer.append( "\n" );
297 lcl_indent( _inout_rBuffer, _nLevel );
298 _inout_rBuffer.append( "Message: " );
299 _inout_rBuffer.append( _e.Message );
303 // construct an error message for the exception
304 static OUString implGetExceptionMsg( const Exception& e, const OUString& aExceptionType_ )
306 OUStringBuffer aMessageBuf;
307 implAppendExceptionMsg( aMessageBuf, e, aExceptionType_, 0 );
308 return aMessageBuf.makeStringAndClear();
311 static OUString implGetExceptionMsg( const Any& _rCaughtException )
313 auto e = o3tl::tryAccess<Exception>(_rCaughtException);
314 OSL_PRECOND( e, "implGetExceptionMsg: illegal argument!" );
315 if ( !e )
317 return OUString();
319 return implGetExceptionMsg( *e, _rCaughtException.getValueTypeName() );
322 static Any convertAny( const Any& rVal, const Type& aDestType )
324 Any aConvertedVal;
325 const Reference< XTypeConverter >& xConverter = getTypeConverter_Impl();
328 aConvertedVal = xConverter->convertTo( rVal, aDestType );
330 catch( const IllegalArgumentException& )
332 StarBASIC::Error( ERRCODE_BASIC_EXCEPTION,
333 implGetExceptionMsg( ::cppu::getCaughtException() ) );
334 return aConvertedVal;
336 catch( const CannotConvertException& e2 )
338 StarBASIC::Error( ERRCODE_BASIC_EXCEPTION,
339 implGetExceptionMsg( e2, "com.sun.star.lang.IllegalArgumentException" ) );
340 return aConvertedVal;
342 return aConvertedVal;
346 // #105565 Special Object to wrap a strongly typed Uno Any
349 // TODO: source out later
350 static Reference<XIdlClass> TypeToIdlClass( const Type& rType )
352 return getCoreReflection_Impl()->forName(rType.getTypeName());
355 // Exception type unknown
356 template< class EXCEPTION >
357 static OUString implGetExceptionMsg( const EXCEPTION& e )
359 return implGetExceptionMsg( e, cppu::UnoType<decltype(e)>::get().getTypeName() );
362 static void implHandleBasicErrorException( BasicErrorException const & e )
364 ErrCode nError = StarBASIC::GetSfxFromVBError( static_cast<sal_uInt16>(e.ErrorCode) );
365 StarBASIC::Error( nError, e.ErrorMessageArgument );
368 static void implHandleWrappedTargetException( const Any& _rWrappedTargetException )
370 Any aExamine( _rWrappedTargetException );
372 // completely strip the first InvocationTargetException, its error message isn't of any
373 // interest to the user, it just says something like "invoking the UNO method went wrong.".
374 InvocationTargetException aInvocationError;
375 if ( aExamine >>= aInvocationError )
376 aExamine = aInvocationError.TargetException;
378 BasicErrorException aBasicError;
380 ErrCode nError( ERRCODE_BASIC_EXCEPTION );
381 OUStringBuffer aMessageBuf;
383 // strip any other WrappedTargetException instances, but this time preserve the error messages.
384 WrappedTargetException aWrapped;
385 sal_Int32 nLevel = 0;
386 while ( aExamine >>= aWrapped )
388 // special handling for BasicErrorException errors
389 if ( aWrapped.TargetException >>= aBasicError )
391 nError = StarBASIC::GetSfxFromVBError( static_cast<sal_uInt16>(aBasicError.ErrorCode) );
392 aMessageBuf.append( aBasicError.ErrorMessageArgument );
393 aExamine.clear();
394 break;
397 // append this round's message
398 implAppendExceptionMsg( aMessageBuf, aWrapped, aExamine.getValueTypeName(), nLevel );
399 if ( aWrapped.TargetException.getValueTypeClass() == TypeClass_EXCEPTION )
400 // there is a next chain element
401 aMessageBuf.append( "\nTargetException:" );
403 // next round
404 aExamine = aWrapped.TargetException;
405 ++nLevel;
408 if ( auto e = o3tl::tryAccess<Exception>(aExamine) )
410 // the last element in the chain is still an exception, but no WrappedTargetException
411 implAppendExceptionMsg( aMessageBuf, *e, aExamine.getValueTypeName(), nLevel );
414 StarBASIC::Error( nError, aMessageBuf.makeStringAndClear() );
417 static void implHandleAnyException( const Any& _rCaughtException )
419 BasicErrorException aBasicError;
420 WrappedTargetException aWrappedError;
422 if ( _rCaughtException >>= aBasicError )
424 implHandleBasicErrorException( aBasicError );
426 else if ( _rCaughtException >>= aWrappedError )
428 implHandleWrappedTargetException( _rCaughtException );
430 else
432 StarBASIC::Error( ERRCODE_BASIC_EXCEPTION, implGetExceptionMsg( _rCaughtException ) );
436 // NativeObjectWrapper handling
437 struct ObjectItem
439 SbxObjectRef m_xNativeObj;
441 explicit ObjectItem( SbxObject* pNativeObj )
442 : m_xNativeObj( pNativeObj )
446 typedef std::vector< ObjectItem > NativeObjectWrapperVector;
447 class GaNativeObjectWrapperVector : public rtl::Static<NativeObjectWrapperVector, GaNativeObjectWrapperVector> {};
449 void clearNativeObjectWrapperVector()
451 GaNativeObjectWrapperVector::get().clear();
454 static sal_uInt32 lcl_registerNativeObjectWrapper( SbxObject* pNativeObj )
456 NativeObjectWrapperVector &rNativeObjectWrapperVector = GaNativeObjectWrapperVector::get();
457 sal_uInt32 nIndex = rNativeObjectWrapperVector.size();
458 rNativeObjectWrapperVector.emplace_back( pNativeObj );
459 return nIndex;
462 static SbxObject* lcl_getNativeObject( sal_uInt32 nIndex )
464 SbxObjectRef xRetObj;
465 NativeObjectWrapperVector &rNativeObjectWrapperVector = GaNativeObjectWrapperVector::get();
466 if( nIndex < rNativeObjectWrapperVector.size() )
468 ObjectItem& rItem = rNativeObjectWrapperVector[ nIndex ];
469 xRetObj = rItem.m_xNativeObj;
471 return xRetObj.get();
474 // convert from Uno to Sbx
475 static SbxDataType unoToSbxType( TypeClass eType )
477 SbxDataType eRetType = SbxVOID;
479 switch( eType )
481 case TypeClass_INTERFACE:
482 case TypeClass_TYPE:
483 case TypeClass_STRUCT:
484 case TypeClass_EXCEPTION: eRetType = SbxOBJECT; break;
486 case TypeClass_ENUM: eRetType = SbxLONG; break;
487 case TypeClass_SEQUENCE:
488 eRetType = SbxDataType( SbxOBJECT | SbxARRAY );
489 break;
492 case TypeClass_ANY: eRetType = SbxVARIANT; break;
493 case TypeClass_BOOLEAN: eRetType = SbxBOOL; break;
494 case TypeClass_CHAR: eRetType = SbxCHAR; break;
495 case TypeClass_STRING: eRetType = SbxSTRING; break;
496 case TypeClass_FLOAT: eRetType = SbxSINGLE; break;
497 case TypeClass_DOUBLE: eRetType = SbxDOUBLE; break;
498 case TypeClass_BYTE: eRetType = SbxINTEGER; break;
499 case TypeClass_SHORT: eRetType = SbxINTEGER; break;
500 case TypeClass_LONG: eRetType = SbxLONG; break;
501 case TypeClass_HYPER: eRetType = SbxSALINT64; break;
502 case TypeClass_UNSIGNED_SHORT: eRetType = SbxUSHORT; break;
503 case TypeClass_UNSIGNED_LONG: eRetType = SbxULONG; break;
504 case TypeClass_UNSIGNED_HYPER: eRetType = SbxSALUINT64;break;
505 default: break;
507 return eRetType;
510 static SbxDataType unoToSbxType( const Reference< XIdlClass >& xIdlClass )
512 SbxDataType eRetType = SbxVOID;
513 if( xIdlClass.is() )
515 TypeClass eType = xIdlClass->getTypeClass();
516 eRetType = unoToSbxType( eType );
518 return eRetType;
521 static void implSequenceToMultiDimArray( SbxDimArray*& pArray, Sequence< sal_Int32 >& indices, Sequence< sal_Int32 >& sizes, const Any& aValue, sal_Int32 dimension, bool bIsZeroIndex, Type const * pType )
523 const Type& aType = aValue.getValueType();
524 TypeClass eTypeClass = aType.getTypeClass();
526 sal_Int32 dimCopy = dimension;
528 if ( eTypeClass == TypeClass_SEQUENCE )
530 Reference< XIdlClass > xIdlTargetClass = TypeToIdlClass( aType );
531 Reference< XIdlArray > xIdlArray = xIdlTargetClass->getArray();
532 typelib_TypeDescription * pTD = nullptr;
533 aType.getDescription( &pTD );
534 Type aElementType( reinterpret_cast<typelib_IndirectTypeDescription *>(pTD)->pType );
535 ::typelib_typedescription_release( pTD );
537 sal_Int32 nLen = xIdlArray->getLen( aValue );
538 for ( sal_Int32 index = 0; index < nLen; ++index )
540 Any aElementAny = xIdlArray->get( aValue, static_cast<sal_uInt32>(index) );
541 // This detects the dimension were currently processing
542 if ( dimCopy == dimension )
544 ++dimCopy;
545 if ( sizes.getLength() < dimCopy )
547 sizes.realloc( sizes.getLength() + 1 );
548 sizes[ sizes.getLength() - 1 ] = nLen;
549 indices.realloc( indices.getLength() + 1 );
553 if ( bIsZeroIndex )
554 indices[ dimCopy - 1 ] = index;
555 else
556 indices[ dimCopy - 1] = index + 1;
558 implSequenceToMultiDimArray( pArray, indices, sizes, aElementAny, dimCopy, bIsZeroIndex, &aElementType );
562 else
564 if ( !indices.hasElements() )
566 // Should never ever get here ( indices.getLength()
567 // should equal number of dimensions in the array )
568 // And that should at least be 1 !
569 // #QUESTION is there a better error?
570 StarBASIC::Error( ERRCODE_BASIC_INVALID_OBJECT );
571 return;
574 SbxDataType eSbxElementType = unoToSbxType( pType ? pType->getTypeClass() : aValue.getValueTypeClass() );
575 if ( !pArray )
577 pArray = new SbxDimArray( eSbxElementType );
578 sal_Int32 nIndexLen = indices.getLength();
580 // Dimension the array
581 for ( sal_Int32 index = 0; index < nIndexLen; ++index )
583 if ( bIsZeroIndex )
584 pArray->unoAddDim32( 0, sizes[ index ] - 1);
585 else
586 pArray->unoAddDim32( 1, sizes[ index ] );
591 if ( pArray )
593 auto xVar = tools::make_ref<SbxVariable>( eSbxElementType );
594 unoToSbxValue( xVar.get(), aValue );
596 sal_Int32* pIndices = indices.getArray();
597 pArray->Put32( xVar.get(), pIndices );
603 void unoToSbxValue( SbxVariable* pVar, const Any& aValue )
605 const Type& aType = aValue.getValueType();
606 TypeClass eTypeClass = aType.getTypeClass();
607 switch( eTypeClass )
609 case TypeClass_TYPE:
611 // Map Type to IdlClass
612 Type aType_;
613 aValue >>= aType_;
614 Reference<XIdlClass> xClass = TypeToIdlClass( aType_ );
615 Any aClassAny;
616 aClassAny <<= xClass;
618 // instantiate SbUnoObject
619 SbUnoObject* pSbUnoObject = new SbUnoObject( OUString(), aClassAny );
620 SbxObjectRef xWrapper = static_cast<SbxObject*>(pSbUnoObject);
622 // If the object is invalid deliver null
623 if( !pSbUnoObject->getUnoAny().hasValue() )
625 pVar->PutObject( nullptr );
627 else
629 pVar->PutObject( xWrapper.get() );
632 break;
633 // Interfaces and Structs must be wrapped in a SbUnoObject
634 case TypeClass_INTERFACE:
635 case TypeClass_STRUCT:
636 case TypeClass_EXCEPTION:
638 if( eTypeClass == TypeClass_STRUCT )
640 ArrayWrapper aWrap;
641 NativeObjectWrapper aNativeObjectWrapper;
642 if ( aValue >>= aWrap )
644 SbxDimArray* pArray = nullptr;
645 Sequence< sal_Int32 > indices;
646 Sequence< sal_Int32 > sizes;
647 implSequenceToMultiDimArray( pArray, indices, sizes, aWrap.Array, /*dimension*/0, aWrap.IsZeroIndex, nullptr );
648 if ( pArray )
650 SbxDimArrayRef xArray = pArray;
651 SbxFlagBits nFlags = pVar->GetFlags();
652 pVar->ResetFlag( SbxFlagBits::Fixed );
653 pVar->PutObject( xArray.get() );
654 pVar->SetFlags( nFlags );
656 else
657 pVar->PutEmpty();
658 break;
660 else if ( aValue >>= aNativeObjectWrapper )
662 sal_uInt32 nIndex = 0;
663 if( aNativeObjectWrapper.ObjectId >>= nIndex )
665 SbxObject* pObj = lcl_getNativeObject( nIndex );
666 pVar->PutObject( pObj );
668 else
669 pVar->PutEmpty();
670 break;
672 else
674 SbiInstance* pInst = GetSbData()->pInst;
675 if( pInst && pInst->IsCompatibility() )
677 oleautomation::Date aDate;
678 if( aValue >>= aDate )
680 pVar->PutDate( aDate.Value );
681 break;
683 else
685 oleautomation::Decimal aDecimal;
686 if( aValue >>= aDecimal )
688 pVar->PutDecimal( aDecimal );
689 break;
691 else
693 oleautomation::Currency aCurrency;
694 if( aValue >>= aCurrency )
696 pVar->PutCurrency( aCurrency.Value );
697 break;
704 // instantiate a SbUnoObject
705 SbUnoObject* pSbUnoObject = new SbUnoObject( OUString(), aValue );
706 //If this is called externally e.g. from the scripting
707 //framework then there is no 'active' runtime the default property will not be set up
708 //only a vba object will have XDefaultProp set anyway so... this
709 //test seems a bit of overkill
710 //if ( SbiRuntime::isVBAEnabled() )
712 OUString sDfltPropName;
714 if ( SbUnoObject::getDefaultPropName( pSbUnoObject, sDfltPropName ) )
716 pSbUnoObject->SetDfltProperty( sDfltPropName );
719 SbxObjectRef xWrapper = static_cast<SbxObject*>(pSbUnoObject);
721 // If the object is invalid deliver null
722 if( !pSbUnoObject->getUnoAny().hasValue() )
724 pVar->PutObject( nullptr );
726 else
728 pVar->PutObject( xWrapper.get() );
731 break;
734 case TypeClass_ENUM:
736 sal_Int32 nEnum = 0;
737 enum2int( nEnum, aValue );
738 pVar->PutLong( nEnum );
740 break;
742 case TypeClass_SEQUENCE:
744 Reference< XIdlClass > xIdlTargetClass = TypeToIdlClass( aType );
745 Reference< XIdlArray > xIdlArray = xIdlTargetClass->getArray();
746 sal_Int32 i, nLen = xIdlArray->getLen( aValue );
748 typelib_TypeDescription * pTD = nullptr;
749 aType.getDescription( &pTD );
750 OSL_ASSERT( pTD && pTD->eTypeClass == typelib_TypeClass_SEQUENCE );
751 Type aElementType( reinterpret_cast<typelib_IndirectTypeDescription *>(pTD)->pType );
752 ::typelib_typedescription_release( pTD );
754 // build an Array in Basic
755 SbxDimArrayRef xArray;
756 SbxDataType eSbxElementType = unoToSbxType( aElementType.getTypeClass() );
757 xArray = new SbxDimArray( eSbxElementType );
758 if( nLen > 0 )
760 xArray->unoAddDim32( 0, nLen - 1 );
762 // register the elements as variables
763 for( i = 0 ; i < nLen ; i++ )
765 // convert elements
766 Any aElementAny = xIdlArray->get( aValue, static_cast<sal_uInt32>(i) );
767 auto xVar = tools::make_ref<SbxVariable>( eSbxElementType );
768 unoToSbxValue( xVar.get(), aElementAny );
770 // put into the Array
771 xArray->Put32( xVar.get(), &i );
774 else
776 xArray->unoAddDim( 0, -1 );
779 // return the Array
780 SbxFlagBits nFlags = pVar->GetFlags();
781 pVar->ResetFlag( SbxFlagBits::Fixed );
782 pVar->PutObject( xArray.get() );
783 pVar->SetFlags( nFlags );
786 break;
789 case TypeClass_BOOLEAN: pVar->PutBool( *o3tl::forceAccess<bool>(aValue) ); break;
790 case TypeClass_CHAR:
792 pVar->PutChar( *o3tl::forceAccess<sal_Unicode>(aValue) );
793 break;
795 case TypeClass_STRING: { OUString val; aValue >>= val; pVar->PutString( val ); } break;
796 case TypeClass_FLOAT: { float val = 0; aValue >>= val; pVar->PutSingle( val ); } break;
797 case TypeClass_DOUBLE: { double val = 0; aValue >>= val; pVar->PutDouble( val ); } break;
798 case TypeClass_BYTE: { sal_Int8 val = 0; aValue >>= val; pVar->PutInteger( val ); } break;
799 case TypeClass_SHORT: { sal_Int16 val = 0; aValue >>= val; pVar->PutInteger( val ); } break;
800 case TypeClass_LONG: { sal_Int32 val = 0; aValue >>= val; pVar->PutLong( val ); } break;
801 case TypeClass_HYPER: { sal_Int64 val = 0; aValue >>= val; pVar->PutInt64( val ); } break;
802 case TypeClass_UNSIGNED_SHORT: { sal_uInt16 val = 0; aValue >>= val; pVar->PutUShort( val ); } break;
803 case TypeClass_UNSIGNED_LONG: { sal_uInt32 val = 0; aValue >>= val; pVar->PutULong( val ); } break;
804 case TypeClass_UNSIGNED_HYPER: { sal_uInt64 val = 0; aValue >>= val; pVar->PutUInt64( val ); } break;
805 default: pVar->PutEmpty(); break;
809 // Deliver the reflection for Sbx types
810 static Type getUnoTypeForSbxBaseType( SbxDataType eType )
812 Type aRetType = cppu::UnoType<void>::get();
813 switch( eType )
815 case SbxNULL: aRetType = cppu::UnoType<XInterface>::get(); break;
816 case SbxINTEGER: aRetType = cppu::UnoType<sal_Int16>::get(); break;
817 case SbxLONG: aRetType = cppu::UnoType<sal_Int32>::get(); break;
818 case SbxSINGLE: aRetType = cppu::UnoType<float>::get(); break;
819 case SbxDOUBLE: aRetType = cppu::UnoType<double>::get(); break;
820 case SbxCURRENCY: aRetType = cppu::UnoType<oleautomation::Currency>::get(); break;
821 case SbxDECIMAL: aRetType = cppu::UnoType<oleautomation::Decimal>::get(); break;
822 case SbxDATE: {
823 SbiInstance* pInst = GetSbData()->pInst;
824 if( pInst && pInst->IsCompatibility() )
825 aRetType = cppu::UnoType<double>::get();
826 else
827 aRetType = cppu::UnoType<oleautomation::Date>::get();
829 break;
830 case SbxSTRING: aRetType = cppu::UnoType<OUString>::get(); break;
831 case SbxBOOL: aRetType = cppu::UnoType<sal_Bool>::get(); break;
832 case SbxVARIANT: aRetType = cppu::UnoType<Any>::get(); break;
833 case SbxCHAR: aRetType = cppu::UnoType<cppu::UnoCharType>::get(); break;
834 case SbxBYTE: aRetType = cppu::UnoType<sal_Int8>::get(); break;
835 case SbxUSHORT: aRetType = cppu::UnoType<cppu::UnoUnsignedShortType>::get(); break;
836 case SbxULONG: aRetType = ::cppu::UnoType<sal_uInt32>::get(); break;
837 // map machine-dependent ones to long for consistency
838 case SbxINT: aRetType = ::cppu::UnoType<sal_Int32>::get(); break;
839 case SbxUINT: aRetType = ::cppu::UnoType<sal_uInt32>::get(); break;
840 default: break;
842 return aRetType;
845 // Converting of Sbx to Uno without a know target class for TypeClass_ANY
846 static Type getUnoTypeForSbxValue( const SbxValue* pVal )
848 Type aRetType = cppu::UnoType<void>::get();
849 if( !pVal )
850 return aRetType;
852 // convert SbxType to Uno
853 SbxDataType eBaseType = pVal->SbxValue::GetType();
854 if( eBaseType == SbxOBJECT )
856 SbxBaseRef xObj = pVal->GetObject();
857 if( !xObj.is() )
859 aRetType = cppu::UnoType<XInterface>::get();
860 return aRetType;
863 if( auto pArray = dynamic_cast<SbxDimArray*>( xObj.get() ) )
865 short nDims = pArray->GetDims();
866 Type aElementType = getUnoTypeForSbxBaseType( static_cast<SbxDataType>(pArray->GetType() & 0xfff) );
867 TypeClass eElementTypeClass = aElementType.getTypeClass();
869 // Normal case: One dimensional array
870 sal_Int32 nLower, nUpper;
871 if( nDims == 1 && pArray->GetDim32( 1, nLower, nUpper ) )
873 if( eElementTypeClass == TypeClass_VOID || eElementTypeClass == TypeClass_ANY )
875 // If all elements of the arrays are from the same type, take
876 // this one - otherwise the whole will be considered as Any-Sequence
877 bool bNeedsInit = true;
879 for (sal_Int32 aIdx[1] = { nLower }; aIdx[0] <= nUpper; ++aIdx[0])
881 SbxVariableRef xVar = pArray->Get32(aIdx);
882 Type aType = getUnoTypeForSbxValue( xVar.get() );
883 if( bNeedsInit )
885 if( aType.getTypeClass() == TypeClass_VOID )
887 // if only first element is void: different types -> []any
888 // if all elements are void: []void is not allowed -> []any
889 aElementType = cppu::UnoType<Any>::get();
890 break;
892 aElementType = aType;
893 bNeedsInit = false;
895 else if( aElementType != aType )
897 // different types -> AnySequence
898 aElementType = cppu::UnoType<Any>::get();
899 break;
904 OUString aSeqTypeName = aSeqLevelStr + aElementType.getTypeName();
905 aRetType = Type( TypeClass_SEQUENCE, aSeqTypeName );
907 // #i33795 Map also multi dimensional arrays to corresponding sequences
908 else if( nDims > 1 )
910 if( eElementTypeClass == TypeClass_VOID || eElementTypeClass == TypeClass_ANY )
912 // For this check the array's dim structure does not matter
913 sal_uInt32 nFlatArraySize = pArray->Count32();
915 bool bNeedsInit = true;
916 for( sal_uInt32 i = 0 ; i < nFlatArraySize ; i++ )
918 SbxVariableRef xVar = pArray->SbxArray::Get32( i );
919 Type aType = getUnoTypeForSbxValue( xVar.get() );
920 if( bNeedsInit )
922 if( aType.getTypeClass() == TypeClass_VOID )
924 // if only first element is void: different types -> []any
925 // if all elements are void: []void is not allowed -> []any
926 aElementType = cppu::UnoType<Any>::get();
927 break;
929 aElementType = aType;
930 bNeedsInit = false;
932 else if( aElementType != aType )
934 // different types -> AnySequence
935 aElementType = cppu::UnoType<Any>::get();
936 break;
941 OUStringBuffer aSeqTypeName;
942 for( short iDim = 0 ; iDim < nDims ; iDim++ )
944 aSeqTypeName.append(aSeqLevelStr);
946 aSeqTypeName.append(aElementType.getTypeName());
947 aRetType = Type( TypeClass_SEQUENCE, aSeqTypeName.makeStringAndClear() );
950 // No array, but ...
951 else if( auto obj = dynamic_cast<SbUnoObject*>( xObj.get() ) )
953 aRetType = obj->getUnoAny().getValueType();
955 // SbUnoAnyObject?
956 else if( auto any = dynamic_cast<SbUnoAnyObject*>( xObj.get() ) )
958 aRetType = any->getValue().getValueType();
960 // Otherwise it is a No-Uno-Basic-Object -> default==deliver void
962 // No object, convert basic type
963 else
965 aRetType = getUnoTypeForSbxBaseType( eBaseType );
967 return aRetType;
970 // converting of Sbx to Uno without known target class for TypeClass_ANY
971 static Any sbxToUnoValueImpl( const SbxValue* pVar, bool bBlockConversionToSmallestType = false )
973 SbxDataType eBaseType = pVar->SbxValue::GetType();
974 if( eBaseType == SbxOBJECT )
976 SbxBaseRef xObj = pVar->GetObject();
977 if( xObj.is() )
979 if( auto obj = dynamic_cast<SbUnoAnyObject*>( xObj.get() ) )
980 return obj->getValue();
981 if( auto pClassModuleObj = dynamic_cast<SbClassModuleObject*>( xObj.get() ) )
983 Any aRetAny;
984 SbModule* pClassModule = pClassModuleObj->getClassModule();
985 if( pClassModule->createCOMWrapperForIface( aRetAny, pClassModuleObj ) )
986 return aRetAny;
988 if( dynamic_cast<const SbUnoObject*>( xObj.get() ) == nullptr )
990 // Create NativeObjectWrapper to identify object in case of callbacks
991 SbxObject* pObj = dynamic_cast<SbxObject*>( pVar->GetObject() );
992 if( pObj != nullptr )
994 NativeObjectWrapper aNativeObjectWrapper;
995 sal_uInt32 nIndex = lcl_registerNativeObjectWrapper( pObj );
996 aNativeObjectWrapper.ObjectId <<= nIndex;
997 Any aRetAny;
998 aRetAny <<= aNativeObjectWrapper;
999 return aRetAny;
1005 Type aType = getUnoTypeForSbxValue( pVar );
1006 TypeClass eType = aType.getTypeClass();
1008 if( !bBlockConversionToSmallestType )
1010 // #79615 Choose "smallest" representation for int values
1011 // because up cast is allowed, downcast not
1012 switch( eType )
1014 case TypeClass_FLOAT:
1015 case TypeClass_DOUBLE:
1017 double d = pVar->GetDouble();
1018 if( rtl::math::approxEqual(d, floor( d )) )
1020 if( d >= -128 && d <= 127 )
1021 aType = ::cppu::UnoType<sal_Int8>::get();
1022 else if( d >= SbxMININT && d <= SbxMAXINT )
1023 aType = ::cppu::UnoType<sal_Int16>::get();
1024 else if( d >= -SbxMAXLNG && d <= SbxMAXLNG )
1025 aType = ::cppu::UnoType<sal_Int32>::get();
1027 break;
1029 case TypeClass_SHORT:
1031 sal_Int16 n = pVar->GetInteger();
1032 if( n >= -128 && n <= 127 )
1033 aType = ::cppu::UnoType<sal_Int8>::get();
1034 break;
1036 case TypeClass_LONG:
1038 sal_Int32 n = pVar->GetLong();
1039 if( n >= -128 && n <= 127 )
1040 aType = ::cppu::UnoType<sal_Int8>::get();
1041 else if( n >= SbxMININT && n <= SbxMAXINT )
1042 aType = ::cppu::UnoType<sal_Int16>::get();
1043 break;
1045 case TypeClass_UNSIGNED_SHORT:
1047 sal_uInt16 n = pVar->GetUShort();
1048 if( n <= 255 )
1049 aType = cppu::UnoType<sal_uInt8>::get();
1050 break;
1052 case TypeClass_UNSIGNED_LONG:
1054 sal_uInt32 n = pVar->GetLong();
1055 if( n <= 255 )
1056 aType = cppu::UnoType<sal_uInt8>::get();
1057 else if( n <= SbxMAXUINT )
1058 aType = cppu::UnoType<cppu::UnoUnsignedShortType>::get();
1059 break;
1061 // TODO: need to add hyper types ?
1062 default: break;
1066 return sbxToUnoValue( pVar, aType );
1070 // Helper function for StepREDIMP
1071 static Any implRekMultiDimArrayToSequence( SbxDimArray* pArray,
1072 const Type& aElemType, short nMaxDimIndex, short nActualDim,
1073 sal_Int32* pActualIndices, sal_Int32* pLowerBounds, sal_Int32* pUpperBounds )
1075 sal_Int32 nSeqLevel = nMaxDimIndex - nActualDim + 1;
1076 OUStringBuffer aSeqTypeName;
1077 sal_Int32 i;
1078 for( i = 0 ; i < nSeqLevel ; i++ )
1080 aSeqTypeName.append(aSeqLevelStr);
1082 aSeqTypeName.append(aElemType.getTypeName());
1083 Type aSeqType( TypeClass_SEQUENCE, aSeqTypeName.makeStringAndClear() );
1085 // Create Sequence instance
1086 Any aRetVal;
1087 Reference< XIdlClass > xIdlTargetClass = TypeToIdlClass( aSeqType );
1088 xIdlTargetClass->createObject( aRetVal );
1090 // Alloc sequence according to array bounds
1091 sal_Int32 nUpper = pUpperBounds[nActualDim];
1092 sal_Int32 nLower = pLowerBounds[nActualDim];
1093 sal_Int32 nSeqSize = nUpper - nLower + 1;
1094 Reference< XIdlArray > xArray = xIdlTargetClass->getArray();
1095 xArray->realloc( aRetVal, nSeqSize );
1097 sal_Int32& ri = pActualIndices[nActualDim];
1099 for( ri = nLower,i = 0 ; ri <= nUpper ; ri++,i++ )
1101 Any aElementVal;
1103 if( nActualDim < nMaxDimIndex )
1105 aElementVal = implRekMultiDimArrayToSequence( pArray, aElemType,
1106 nMaxDimIndex, nActualDim + 1, pActualIndices, pLowerBounds, pUpperBounds );
1108 else
1110 SbxVariable* pSource = pArray->Get32( pActualIndices );
1111 aElementVal = sbxToUnoValue( pSource, aElemType );
1116 // transfer to the sequence
1117 xArray->set( aRetVal, i, aElementVal );
1119 catch( const IllegalArgumentException& )
1121 StarBASIC::Error( ERRCODE_BASIC_EXCEPTION,
1122 implGetExceptionMsg( ::cppu::getCaughtException() ) );
1124 catch (const IndexOutOfBoundsException&)
1126 StarBASIC::Error( ERRCODE_BASIC_OUT_OF_RANGE );
1129 return aRetVal;
1132 // Map old interface
1133 Any sbxToUnoValue( const SbxValue* pVar )
1135 return sbxToUnoValueImpl( pVar );
1138 // function to find a global identifier in
1139 // the UnoScope and to wrap it for Sbx
1140 static bool implGetTypeByName( const OUString& rName, Type& rRetType )
1142 bool bSuccess = false;
1144 const Reference< XHierarchicalNameAccess >& xTypeAccess = getTypeProvider_Impl();
1145 if( xTypeAccess->hasByHierarchicalName( rName ) )
1147 Any aRet = xTypeAccess->getByHierarchicalName( rName );
1148 Reference< XTypeDescription > xTypeDesc;
1149 aRet >>= xTypeDesc;
1151 if( xTypeDesc.is() )
1153 rRetType = Type( xTypeDesc->getTypeClass(), xTypeDesc->getName() );
1154 bSuccess = true;
1157 return bSuccess;
1161 // converting of Sbx to Uno with known target class
1162 Any sbxToUnoValue( const SbxValue* pVar, const Type& rType, Property const * pUnoProperty )
1164 Any aRetVal;
1166 // #94560 No conversion of empty/void for MAYBE_VOID properties
1167 if( pUnoProperty && pUnoProperty->Attributes & PropertyAttribute::MAYBEVOID )
1169 if( pVar->IsEmpty() )
1170 return aRetVal;
1173 SbxDataType eBaseType = pVar->SbxValue::GetType();
1174 if( eBaseType == SbxOBJECT )
1176 SbxBaseRef xObj = pVar->GetObject();
1177 if ( auto obj = dynamic_cast<SbUnoAnyObject*>( xObj.get() ) )
1179 return obj->getValue();
1183 TypeClass eType = rType.getTypeClass();
1184 switch( eType )
1186 case TypeClass_INTERFACE:
1187 case TypeClass_STRUCT:
1188 case TypeClass_EXCEPTION:
1190 Reference< XIdlClass > xIdlTargetClass = TypeToIdlClass( rType );
1192 // null reference?
1193 if( pVar->IsNull() && eType == TypeClass_INTERFACE )
1195 Reference< XInterface > xRef;
1196 OUString aClassName = xIdlTargetClass->getName();
1197 Type aClassType( xIdlTargetClass->getTypeClass(), aClassName );
1198 aRetVal.setValue( &xRef, aClassType );
1200 else
1202 // #112368 Special conversion for Decimal, Currency and Date
1203 if( eType == TypeClass_STRUCT )
1205 SbiInstance* pInst = GetSbData()->pInst;
1206 if( pInst && pInst->IsCompatibility() )
1208 if( rType == cppu::UnoType<oleautomation::Decimal>::get())
1210 oleautomation::Decimal aDecimal;
1211 pVar->fillAutomationDecimal( aDecimal );
1212 aRetVal <<= aDecimal;
1213 break;
1215 else if( rType == cppu::UnoType<oleautomation::Currency>::get())
1217 // assumes per previous code that ole Currency is Int64
1218 aRetVal <<= pVar->GetInt64();
1219 break;
1221 else if( rType == cppu::UnoType<oleautomation::Date>::get())
1223 oleautomation::Date aDate;
1224 aDate.Value = pVar->GetDate();
1225 aRetVal <<= aDate;
1226 break;
1231 SbxBaseRef pObj = pVar->GetObject();
1232 if( auto obj = dynamic_cast<SbUnoObject*>( pObj.get() ) )
1234 aRetVal = obj->getUnoAny();
1236 else if( auto structRef = dynamic_cast<SbUnoStructRefObject*>( pObj.get() ) )
1238 aRetVal = structRef->getUnoAny();
1240 else
1242 // null object -> null XInterface
1243 Reference<XInterface> xInt;
1244 aRetVal <<= xInt;
1248 break;
1250 case TypeClass_TYPE:
1252 if( eBaseType == SbxOBJECT )
1254 // XIdlClass?
1255 Reference< XIdlClass > xIdlClass;
1257 SbxBaseRef pObj = pVar->GetObject();
1258 if( auto obj = dynamic_cast<SbUnoObject*>( pObj.get() ) )
1260 Any aUnoAny = obj->getUnoAny();
1261 aUnoAny >>= xIdlClass;
1264 if( xIdlClass.is() )
1266 OUString aClassName = xIdlClass->getName();
1267 Type aType( xIdlClass->getTypeClass(), aClassName );
1268 aRetVal <<= aType;
1271 else if( eBaseType == SbxSTRING )
1273 OUString aTypeName = pVar->GetOUString();
1274 Type aType;
1275 bool bSuccess = implGetTypeByName( aTypeName, aType );
1276 if( bSuccess )
1278 aRetVal <<= aType;
1282 break;
1285 case TypeClass_ENUM:
1287 aRetVal = int2enum( pVar->GetLong(), rType );
1289 break;
1291 case TypeClass_SEQUENCE:
1293 SbxBaseRef xObj = pVar->GetObject();
1294 if( auto pArray = dynamic_cast<SbxDimArray*>( xObj.get() ) )
1296 short nDims = pArray->GetDims();
1298 // Normal case: One dimensional array
1299 sal_Int32 nLower, nUpper;
1300 if( nDims == 1 && pArray->GetDim32( 1, nLower, nUpper ) )
1302 sal_Int32 nSeqSize = nUpper - nLower + 1;
1304 // create the instance of the required sequence
1305 Reference< XIdlClass > xIdlTargetClass = TypeToIdlClass( rType );
1306 xIdlTargetClass->createObject( aRetVal );
1307 Reference< XIdlArray > xArray = xIdlTargetClass->getArray();
1308 xArray->realloc( aRetVal, nSeqSize );
1310 // Element-Type
1311 OUString aClassName = xIdlTargetClass->getName();
1312 typelib_TypeDescription * pSeqTD = nullptr;
1313 typelib_typedescription_getByName( &pSeqTD, aClassName.pData );
1314 OSL_ASSERT( pSeqTD );
1315 Type aElemType( reinterpret_cast<typelib_IndirectTypeDescription *>(pSeqTD)->pType );
1317 // convert all array member and register them
1318 sal_Int32 aIdx[1];
1319 aIdx[0] = nLower;
1320 for (sal_Int32 i = 0 ; i < nSeqSize; ++i, ++aIdx[0])
1322 SbxVariableRef xVar = pArray->Get32(aIdx);
1324 // Convert the value of Sbx to Uno
1325 Any aAnyValue = sbxToUnoValue( xVar.get(), aElemType );
1329 // insert in the sequence
1330 xArray->set( aRetVal, i, aAnyValue );
1332 catch( const IllegalArgumentException& )
1334 StarBASIC::Error( ERRCODE_BASIC_EXCEPTION,
1335 implGetExceptionMsg( ::cppu::getCaughtException() ) );
1337 catch (const IndexOutOfBoundsException&)
1339 StarBASIC::Error( ERRCODE_BASIC_OUT_OF_RANGE );
1343 // #i33795 Map also multi dimensional arrays to corresponding sequences
1344 else if( nDims > 1 )
1346 // Element-Type
1347 typelib_TypeDescription * pSeqTD = nullptr;
1348 Type aCurType( rType );
1349 sal_Int32 nSeqLevel = 0;
1350 Type aElemType;
1353 OUString aTypeName = aCurType.getTypeName();
1354 typelib_typedescription_getByName( &pSeqTD, aTypeName.pData );
1355 OSL_ASSERT( pSeqTD );
1356 if( pSeqTD->eTypeClass == typelib_TypeClass_SEQUENCE )
1358 aCurType = Type( reinterpret_cast<typelib_IndirectTypeDescription *>(pSeqTD)->pType );
1359 nSeqLevel++;
1361 else
1363 aElemType = aCurType;
1364 break;
1367 while( true );
1369 if( nSeqLevel == nDims )
1371 std::unique_ptr<sal_Int32[]> pLowerBounds(new sal_Int32[nDims]);
1372 std::unique_ptr<sal_Int32[]> pUpperBounds(new sal_Int32[nDims]);
1373 std::unique_ptr<sal_Int32[]> pActualIndices(new sal_Int32[nDims]);
1374 for( short i = 1 ; i <= nDims ; i++ )
1376 sal_Int32 lBound, uBound;
1377 pArray->GetDim32( i, lBound, uBound );
1379 short j = i - 1;
1380 pActualIndices[j] = pLowerBounds[j] = lBound;
1381 pUpperBounds[j] = uBound;
1384 aRetVal = implRekMultiDimArrayToSequence( pArray, aElemType,
1385 nDims - 1, 0, pActualIndices.get(), pLowerBounds.get(), pUpperBounds.get() );
1390 break;
1393 // for Any use the class independent converting routine
1394 case TypeClass_ANY:
1396 aRetVal = sbxToUnoValueImpl( pVar );
1398 break;
1400 case TypeClass_BOOLEAN:
1402 aRetVal <<= pVar->GetBool();
1403 break;
1405 case TypeClass_CHAR:
1407 aRetVal <<= pVar->GetChar();
1408 break;
1410 case TypeClass_STRING: aRetVal <<= pVar->GetOUString(); break;
1411 case TypeClass_FLOAT: aRetVal <<= pVar->GetSingle(); break;
1412 case TypeClass_DOUBLE: aRetVal <<= pVar->GetDouble(); break;
1414 case TypeClass_BYTE:
1416 sal_Int16 nVal = pVar->GetInteger();
1417 bool bOverflow = false;
1418 if( nVal < -128 )
1420 bOverflow = true;
1421 nVal = -128;
1423 else if( nVal > 255 ) // 128..255 map to -128..-1
1425 bOverflow = true;
1426 nVal = 127;
1428 if( bOverflow )
1429 StarBASIC::Error( ERRCODE_BASIC_MATH_OVERFLOW );
1431 sal_Int8 nByteVal = static_cast<sal_Int8>(nVal);
1432 aRetVal <<= nByteVal;
1433 break;
1435 case TypeClass_SHORT: aRetVal <<= pVar->GetInteger(); break;
1436 case TypeClass_LONG: aRetVal <<= pVar->GetLong(); break;
1437 case TypeClass_HYPER: aRetVal <<= pVar->GetInt64(); break;
1438 case TypeClass_UNSIGNED_SHORT: aRetVal <<= pVar->GetUShort(); break;
1439 case TypeClass_UNSIGNED_LONG: aRetVal <<= pVar->GetULong(); break;
1440 case TypeClass_UNSIGNED_HYPER: aRetVal <<= pVar->GetUInt64(); break;
1441 default: break;
1444 return aRetVal;
1447 static void processAutomationParams( SbxArray* pParams, Sequence< Any >& args, sal_uInt32 nParamCount )
1449 AutomationNamedArgsSbxArray* pArgNamesArray = dynamic_cast<AutomationNamedArgsSbxArray*>( pParams );
1451 args.realloc( nParamCount );
1452 Any* pAnyArgs = args.getArray();
1453 bool bBlockConversionToSmallestType = GetSbData()->pInst->IsCompatibility();
1454 sal_uInt32 i = 0;
1455 if( pArgNamesArray )
1457 Sequence< OUString >& rNameSeq = pArgNamesArray->getNames();
1458 OUString* pNames = rNameSeq.getArray();
1459 Any aValAny;
1460 for( i = 0 ; i < nParamCount ; i++ )
1462 sal_uInt16 iSbx = static_cast<sal_uInt16>(i+1);
1464 aValAny = sbxToUnoValueImpl( pParams->Get( iSbx ),
1465 bBlockConversionToSmallestType );
1467 OUString aParamName = pNames[iSbx];
1468 if( !aParamName.isEmpty() )
1470 oleautomation::NamedArgument aNamedArgument;
1471 aNamedArgument.Name = aParamName;
1472 aNamedArgument.Value = aValAny;
1473 pAnyArgs[i] <<= aNamedArgument;
1475 else
1477 pAnyArgs[i] = aValAny;
1481 else
1483 for( i = 0 ; i < nParamCount ; i++ )
1485 pAnyArgs[i] = sbxToUnoValueImpl( pParams->Get( static_cast<sal_uInt16>(i+1) ),
1486 bBlockConversionToSmallestType );
1491 enum class INVOKETYPE
1493 GetProp = 0,
1494 Func
1496 static Any invokeAutomationMethod( const OUString& Name, Sequence< Any > const & args, SbxArray* pParams, sal_uInt32 nParamCount, Reference< XInvocation > const & rxInvocation, INVOKETYPE invokeType )
1498 Sequence< sal_Int16 > OutParamIndex;
1499 Sequence< Any > OutParam;
1501 Any aRetAny;
1502 switch( invokeType )
1504 case INVOKETYPE::Func:
1505 aRetAny = rxInvocation->invoke( Name, args, OutParamIndex, OutParam );
1506 break;
1507 case INVOKETYPE::GetProp:
1509 Reference< XAutomationInvocation > xAutoInv( rxInvocation, UNO_QUERY );
1510 aRetAny = xAutoInv->invokeGetProperty( Name, args, OutParamIndex, OutParam );
1511 break;
1513 default:
1514 assert(false); break;
1517 const sal_Int16* pIndices = OutParamIndex.getConstArray();
1518 sal_uInt32 nLen = OutParamIndex.getLength();
1519 if( nLen )
1521 const Any* pNewValues = OutParam.getConstArray();
1522 for( sal_uInt32 j = 0 ; j < nLen ; j++ )
1524 sal_Int16 iTarget = pIndices[ j ];
1525 if( iTarget >= static_cast<sal_Int16>(nParamCount) )
1526 break;
1527 unoToSbxValue( pParams->Get( static_cast<sal_uInt16>(j+1) ), pNewValues[ j ] );
1530 return aRetAny;
1533 // Debugging help method to readout the imlemented interfaces of an object
1534 static OUString Impl_GetInterfaceInfo( const Reference< XInterface >& x, const Reference< XIdlClass >& xClass, sal_uInt16 nRekLevel )
1536 Type aIfaceType = cppu::UnoType<XInterface>::get();
1537 static Reference< XIdlClass > xIfaceClass = TypeToIdlClass( aIfaceType );
1539 OUStringBuffer aRetStr;
1540 for( sal_uInt16 i = 0 ; i < nRekLevel ; i++ )
1541 aRetStr.append( " " );
1542 aRetStr.append( xClass->getName() );
1543 OUString aClassName = xClass->getName();
1544 Type aClassType( xClass->getTypeClass(), aClassName );
1546 // checking if the interface is really supported
1547 if( !x->queryInterface( aClassType ).hasValue() )
1549 aRetStr.append( " (ERROR: Not really supported!)\n" );
1551 // Are there super interfaces?
1552 else
1554 aRetStr.append( "\n" );
1556 // get the super interfaces
1557 Sequence< Reference< XIdlClass > > aSuperClassSeq = xClass->getSuperclasses();
1558 const Reference< XIdlClass >* pClasses = aSuperClassSeq.getConstArray();
1559 sal_uInt32 nSuperIfaceCount = aSuperClassSeq.getLength();
1560 for( sal_uInt32 j = 0 ; j < nSuperIfaceCount ; j++ )
1562 const Reference< XIdlClass >& rxIfaceClass = pClasses[j];
1563 if( !rxIfaceClass->equals( xIfaceClass ) )
1564 aRetStr.append( Impl_GetInterfaceInfo( x, rxIfaceClass, nRekLevel + 1 ) );
1567 return aRetStr.makeStringAndClear();
1570 static OUString getDbgObjectNameImpl(SbUnoObject& rUnoObj)
1572 OUString aName = rUnoObj.GetClassName();
1573 if( aName.isEmpty() )
1575 Any aToInspectObj = rUnoObj.getUnoAny();
1576 Reference< XInterface > xObj(aToInspectObj, css::uno::UNO_QUERY);
1577 if( xObj.is() )
1579 Reference< XServiceInfo > xServiceInfo( xObj, UNO_QUERY );
1580 if( xServiceInfo.is() )
1581 aName = xServiceInfo->getImplementationName();
1584 return aName;
1587 static OUString getDbgObjectName(SbUnoObject& rUnoObj)
1589 OUString aName = getDbgObjectNameImpl(rUnoObj);
1590 if( aName.isEmpty() )
1591 aName += "Unknown";
1593 OUStringBuffer aRet;
1594 if( aName.getLength() > 20 )
1596 aRet.append( "\n" );
1598 aRet.append( "\"" );
1599 aRet.append( aName );
1600 aRet.append( "\":" );
1601 return aRet.makeStringAndClear();
1604 OUString getBasicObjectTypeName( SbxObject* pObj )
1606 if (pObj)
1608 if (SbUnoObject* pUnoObj = dynamic_cast<SbUnoObject*>(pObj))
1610 return getDbgObjectNameImpl(*pUnoObj);
1612 else if (SbUnoStructRefObject* pUnoStructObj = dynamic_cast<SbUnoStructRefObject*>(pObj))
1614 return pUnoStructObj->GetClassName();
1617 return OUString();
1620 namespace {
1622 bool matchesBasicTypeName(
1623 css::uno::Reference<css::reflection::XIdlClass> const & unoType, OUString const & basicTypeName)
1625 if (unoType->getName().endsWithIgnoreAsciiCase(basicTypeName)) {
1626 return true;
1628 auto const sups = unoType->getSuperclasses();
1629 return std::any_of(
1630 sups.begin(), sups.end(),
1631 [&basicTypeName](auto const & t) { return matchesBasicTypeName(t, basicTypeName); });
1636 bool checkUnoObjectType(SbUnoObject& rUnoObj, const OUString& rClass)
1638 Any aToInspectObj = rUnoObj.getUnoAny();
1640 // Return true for XInvocation based objects as interface type names don't count then
1641 Reference< XInvocation > xInvocation( aToInspectObj, UNO_QUERY );
1642 if( xInvocation.is() )
1644 return true;
1646 bool bResult = false;
1647 Reference< XTypeProvider > xTypeProvider( aToInspectObj, UNO_QUERY );
1648 if( xTypeProvider.is() )
1650 /* Although interfaces in the ooo.vba namespace obey the IDL rules and
1651 have a leading 'X', in Basic we want to be able to do something
1652 like 'Dim wb As Workbooks' or 'Dim lb As MSForms.Label'. Here we
1653 add a leading 'X' to the class name and a leading dot to the entire
1654 type name. This results e.g. in '.XWorkbooks' or '.MSForms.XLabel'
1655 which matches the interface names 'ooo.vba.excel.XWorkbooks' or
1656 'ooo.vba.msforms.XLabel'.
1658 OUString aClassName;
1659 if ( SbiRuntime::isVBAEnabled() )
1661 aClassName = ".";
1662 sal_Int32 nClassNameDot = rClass.lastIndexOf( '.' );
1663 if( nClassNameDot >= 0 )
1665 aClassName += rClass.copy( 0, nClassNameDot + 1 ) + "X" + rClass.copy( nClassNameDot + 1 );
1667 else
1669 aClassName += "X" + rClass;
1672 else // assume extended type declaration support for basic ( can't get here
1673 // otherwise.
1674 aClassName = rClass;
1676 Sequence< Type > aTypeSeq = xTypeProvider->getTypes();
1677 const Type* pTypeArray = aTypeSeq.getConstArray();
1678 sal_uInt32 nIfaceCount = aTypeSeq.getLength();
1679 for( sal_uInt32 j = 0 ; j < nIfaceCount ; j++ )
1681 const Type& rType = pTypeArray[j];
1683 Reference<XIdlClass> xClass = TypeToIdlClass( rType );
1684 if( !xClass.is() )
1686 OSL_FAIL("failed to get XIdlClass for type");
1687 break;
1689 OUString aInterfaceName = xClass->getName();
1690 if ( aInterfaceName == "com.sun.star.bridge.oleautomation.XAutomationObject" )
1692 // there is a hack in the extensions/source/ole/oleobj.cxx to return the typename of the automation object, lets check if it
1693 // matches
1694 Reference< XInvocation > xInv( aToInspectObj, UNO_QUERY );
1695 if ( xInv.is() )
1697 OUString sTypeName;
1698 xInv->getValue( "$GetTypeName" ) >>= sTypeName;
1699 if ( sTypeName.isEmpty() || sTypeName == "IDispatch" )
1701 // can't check type, leave it pass
1702 bResult = true;
1704 else
1706 bResult = sTypeName == rClass;
1709 break; // finished checking automation object
1712 if ( matchesBasicTypeName(xClass, aClassName) )
1714 bResult = true;
1715 break;
1719 return bResult;
1722 // Debugging help method to readout the imlemented interfaces of an object
1723 static OUString Impl_GetSupportedInterfaces(SbUnoObject& rUnoObj)
1725 Any aToInspectObj = rUnoObj.getUnoAny();
1727 // allow only TypeClass interface
1728 OUStringBuffer aRet;
1729 auto x = o3tl::tryAccess<Reference<XInterface>>(aToInspectObj);
1730 if( !x )
1732 aRet.append( ID_DBG_SUPPORTEDINTERFACES );
1733 aRet.append( " not available.\n(TypeClass is not TypeClass_INTERFACE)\n" );
1735 else
1737 Reference< XTypeProvider > xTypeProvider( *x, UNO_QUERY );
1739 aRet.append( "Supported interfaces by object " );
1740 aRet.append(getDbgObjectName(rUnoObj));
1741 aRet.append( "\n" );
1742 if( xTypeProvider.is() )
1744 // get the interfaces of the implementation
1745 Sequence< Type > aTypeSeq = xTypeProvider->getTypes();
1746 const Type* pTypeArray = aTypeSeq.getConstArray();
1747 sal_uInt32 nIfaceCount = aTypeSeq.getLength();
1748 for( sal_uInt32 j = 0 ; j < nIfaceCount ; j++ )
1750 const Type& rType = pTypeArray[j];
1752 Reference<XIdlClass> xClass = TypeToIdlClass( rType );
1753 if( xClass.is() )
1755 aRet.append( Impl_GetInterfaceInfo( *x, xClass, 1 ) );
1757 else
1759 typelib_TypeDescription * pTD = nullptr;
1760 rType.getDescription( &pTD );
1762 aRet.append( "*** ERROR: No IdlClass for type \"" );
1763 aRet.append( pTD->pTypeName );
1764 aRet.append( "\"\n*** Please check type library\n" );
1769 return aRet.makeStringAndClear();
1773 // Debugging help method SbxDataType -> String
1774 static OUString Dbg_SbxDataType2String( SbxDataType eType )
1776 OUStringBuffer aRet;
1777 switch( +eType )
1779 case SbxEMPTY: aRet.append("SbxEMPTY"); break;
1780 case SbxNULL: aRet.append("SbxNULL"); break;
1781 case SbxINTEGER: aRet.append("SbxINTEGER"); break;
1782 case SbxLONG: aRet.append("SbxLONG"); break;
1783 case SbxSINGLE: aRet.append("SbxSINGLE"); break;
1784 case SbxDOUBLE: aRet.append("SbxDOUBLE"); break;
1785 case SbxCURRENCY: aRet.append("SbxCURRENCY"); break;
1786 case SbxDECIMAL: aRet.append("SbxDECIMAL"); break;
1787 case SbxDATE: aRet.append("SbxDATE"); break;
1788 case SbxSTRING: aRet.append("SbxSTRING"); break;
1789 case SbxOBJECT: aRet.append("SbxOBJECT"); break;
1790 case SbxERROR: aRet.append("SbxERROR"); break;
1791 case SbxBOOL: aRet.append("SbxBOOL"); break;
1792 case SbxVARIANT: aRet.append("SbxVARIANT"); break;
1793 case SbxDATAOBJECT: aRet.append("SbxDATAOBJECT"); break;
1794 case SbxCHAR: aRet.append("SbxCHAR"); break;
1795 case SbxBYTE: aRet.append("SbxBYTE"); break;
1796 case SbxUSHORT: aRet.append("SbxUSHORT"); break;
1797 case SbxULONG: aRet.append("SbxULONG"); break;
1798 case SbxSALINT64: aRet.append("SbxINT64"); break;
1799 case SbxSALUINT64: aRet.append("SbxUINT64"); break;
1800 case SbxINT: aRet.append("SbxINT"); break;
1801 case SbxUINT: aRet.append("SbxUINT"); break;
1802 case SbxVOID: aRet.append("SbxVOID"); break;
1803 case SbxHRESULT: aRet.append("SbxHRESULT"); break;
1804 case SbxPOINTER: aRet.append("SbxPOINTER"); break;
1805 case SbxDIMARRAY: aRet.append("SbxDIMARRAY"); break;
1806 case SbxCARRAY: aRet.append("SbxCARRAY"); break;
1807 case SbxUSERDEF: aRet.append("SbxUSERDEF"); break;
1808 case SbxLPSTR: aRet.append("SbxLPSTR"); break;
1809 case SbxLPWSTR: aRet.append("SbxLPWSTR"); break;
1810 case SbxCoreSTRING: aRet.append("SbxCoreSTRING"); break;
1811 case SbxOBJECT | SbxARRAY: aRet.append("SbxARRAY"); break;
1812 default: aRet.append("Unknown Sbx-Type!");break;
1814 return aRet.makeStringAndClear();
1817 // Debugging help method to display the properties of a SbUnoObjects
1818 static OUString Impl_DumpProperties(SbUnoObject& rUnoObj)
1820 OUStringBuffer aRet;
1821 aRet.append("Properties of object ");
1822 aRet.append(getDbgObjectName(rUnoObj));
1824 // analyse the Uno-Infos to recognise the arrays
1825 Reference< XIntrospectionAccess > xAccess = rUnoObj.getIntrospectionAccess();
1826 if( !xAccess.is() )
1828 Reference< XInvocation > xInvok = rUnoObj.getInvocation();
1829 if( xInvok.is() )
1830 xAccess = xInvok->getIntrospection();
1832 if( !xAccess.is() )
1834 aRet.append( "\nUnknown, no introspection available\n" );
1835 return aRet.makeStringAndClear();
1838 Sequence<Property> props = xAccess->getProperties( PropertyConcept::ALL - PropertyConcept::DANGEROUS );
1839 sal_uInt32 nUnoPropCount = props.getLength();
1840 const Property* pUnoProps = props.getConstArray();
1842 SbxArray* pProps = rUnoObj.GetProperties();
1843 sal_uInt16 nPropCount = pProps->Count();
1844 sal_uInt16 nPropsPerLine = 1 + nPropCount / 30;
1845 for( sal_uInt16 i = 0; i < nPropCount; i++ )
1847 SbxVariable* pVar = pProps->Get( i );
1848 if( pVar )
1850 OUStringBuffer aPropStr;
1851 if( (i % nPropsPerLine) == 0 )
1852 aPropStr.append( "\n" );
1854 // output the type and name
1855 // Is it in Uno a sequence?
1856 SbxDataType eType = pVar->GetFullType();
1858 bool bMaybeVoid = false;
1859 if( i < nUnoPropCount )
1861 const Property& rProp = pUnoProps[ i ];
1863 // For MAYBEVOID freshly convert the type from Uno,
1864 // so not just SbxEMPTY is returned.
1865 if( rProp.Attributes & PropertyAttribute::MAYBEVOID )
1867 eType = unoToSbxType( rProp.Type.getTypeClass() );
1868 bMaybeVoid = true;
1870 if( eType == SbxOBJECT )
1872 Type aType = rProp.Type;
1873 if( aType.getTypeClass() == TypeClass_SEQUENCE )
1874 eType = SbxDataType( SbxOBJECT | SbxARRAY );
1877 aPropStr.append( Dbg_SbxDataType2String( eType ) );
1878 if( bMaybeVoid )
1879 aPropStr.append( "/void" );
1880 aPropStr.append( " " );
1881 aPropStr.append( pVar->GetName() );
1883 if( i == nPropCount - 1 )
1884 aPropStr.append( "\n" );
1885 else
1886 aPropStr.append( "; " );
1888 aRet.append( aPropStr.makeStringAndClear() );
1891 return aRet.makeStringAndClear();
1894 // Debugging help method to display the methods of an SbUnoObjects
1895 static OUString Impl_DumpMethods(SbUnoObject& rUnoObj)
1897 OUStringBuffer aRet;
1898 aRet.append("Methods of object ");
1899 aRet.append(getDbgObjectName(rUnoObj));
1901 // XIntrospectionAccess, so that the types of the parameter could be outputted
1902 Reference< XIntrospectionAccess > xAccess = rUnoObj.getIntrospectionAccess();
1903 if( !xAccess.is() )
1905 Reference< XInvocation > xInvok = rUnoObj.getInvocation();
1906 if( xInvok.is() )
1907 xAccess = xInvok->getIntrospection();
1909 if( !xAccess.is() )
1911 aRet.append( "\nUnknown, no introspection available\n" );
1912 return aRet.makeStringAndClear();
1914 Sequence< Reference< XIdlMethod > > methods = xAccess->getMethods
1915 ( MethodConcept::ALL - MethodConcept::DANGEROUS );
1916 const Reference< XIdlMethod >* pUnoMethods = methods.getConstArray();
1918 SbxArray* pMethods = rUnoObj.GetMethods();
1919 sal_uInt16 nMethodCount = pMethods->Count();
1920 if( !nMethodCount )
1922 aRet.append( "\nNo methods found\n" );
1923 return aRet.makeStringAndClear();
1925 sal_uInt16 nPropsPerLine = 1 + nMethodCount / 30;
1926 for( sal_uInt16 i = 0; i < nMethodCount; i++ )
1928 SbxVariable* pVar = pMethods->Get( i );
1929 if( pVar )
1931 if( (i % nPropsPerLine) == 0 )
1932 aRet.append( "\n" );
1934 // address the method
1935 const Reference< XIdlMethod >& rxMethod = pUnoMethods[i];
1937 // Is it in Uno a sequence?
1938 SbxDataType eType = pVar->GetFullType();
1939 if( eType == SbxOBJECT )
1941 Reference< XIdlClass > xClass = rxMethod->getReturnType();
1942 if( xClass.is() && xClass->getTypeClass() == TypeClass_SEQUENCE )
1943 eType = SbxDataType( SbxOBJECT | SbxARRAY );
1945 // output the name and the type
1946 aRet.append( Dbg_SbxDataType2String( eType ) );
1947 aRet.append( " " );
1948 aRet.append ( pVar->GetName() );
1949 aRet.append( " ( " );
1951 // the get-method mustn't have a parameter
1952 Sequence< Reference< XIdlClass > > aParamsSeq = rxMethod->getParameterTypes();
1953 sal_uInt32 nParamCount = aParamsSeq.getLength();
1954 const Reference< XIdlClass >* pParams = aParamsSeq.getConstArray();
1956 if( nParamCount > 0 )
1958 for( sal_uInt32 j = 0; j < nParamCount; j++ )
1960 aRet.append ( Dbg_SbxDataType2String( unoToSbxType( pParams[ j ] ) ) );
1961 if( j < nParamCount - 1 )
1962 aRet.append( ", " );
1965 else
1966 aRet.append( "void" );
1968 aRet.append( " ) " );
1970 if( i == nMethodCount - 1 )
1971 aRet.append( "\n" );
1972 else
1973 aRet.append( "; " );
1976 return aRet.makeStringAndClear();
1980 // Implementation SbUnoObject
1981 void SbUnoObject::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
1983 if( bNeedIntrospection )
1984 doIntrospection();
1986 const SbxHint* pHint = dynamic_cast<const SbxHint*>(&rHint);
1987 if( pHint )
1989 SbxVariable* pVar = pHint->GetVar();
1990 SbxArray* pParams = pVar->GetParameters();
1991 SbUnoProperty* pProp = dynamic_cast<SbUnoProperty*>( pVar );
1992 SbUnoMethod* pMeth = dynamic_cast<SbUnoMethod*>( pVar );
1993 if( pProp )
1995 bool bInvocation = pProp->isInvocationBased();
1996 if( pHint->GetId() == SfxHintId::BasicDataWanted )
1998 // Test-Properties
1999 sal_Int32 nId = pProp->nId;
2000 if( nId < 0 )
2002 // Id == -1: Display implemented interfaces according the ClassProvider
2003 if( nId == -1 ) // Property ID_DBG_SUPPORTEDINTERFACES"
2005 OUString aRetStr = Impl_GetSupportedInterfaces(*this);
2006 pVar->PutString( aRetStr );
2008 // Id == -2: output properties
2009 else if( nId == -2 ) // Property ID_DBG_PROPERTIES
2011 // now all properties must be created
2012 implCreateAll();
2013 OUString aRetStr = Impl_DumpProperties(*this);
2014 pVar->PutString( aRetStr );
2016 // Id == -3: output the methods
2017 else if( nId == -3 ) // Property ID_DBG_METHODS
2019 // now all properties must be created
2020 implCreateAll();
2021 OUString aRetStr = Impl_DumpMethods(*this);
2022 pVar->PutString( aRetStr );
2024 return;
2027 if( !bInvocation && mxUnoAccess.is() )
2031 if ( maStructInfo.get() )
2033 StructRefInfo aMember = maStructInfo->getStructMember( pProp->GetName() );
2034 if ( aMember.isEmpty() )
2036 StarBASIC::Error( ERRCODE_BASIC_PROPERTY_NOT_FOUND );
2038 else
2040 if ( pProp->isUnoStruct() )
2042 SbUnoStructRefObject* pSbUnoObject = new SbUnoStructRefObject( pProp->GetName(), aMember );
2043 SbxObjectRef xWrapper = static_cast<SbxObject*>(pSbUnoObject);
2044 pVar->PutObject( xWrapper.get() );
2046 else
2048 Any aRetAny = aMember.getValue();
2049 // take over the value from Uno to Sbx
2050 unoToSbxValue( pVar, aRetAny );
2052 return;
2055 // get the value
2056 Reference< XPropertySet > xPropSet( mxUnoAccess->queryAdapter( cppu::UnoType<XPropertySet>::get()), UNO_QUERY );
2057 Any aRetAny = xPropSet->getPropertyValue( pProp->GetName() );
2058 // The use of getPropertyValue (instead of using the index) is
2059 // suboptimal, but the refactoring to XInvocation is already pending
2060 // Otherwise it is possible to use FastPropertySet
2062 // take over the value from Uno to Sbx
2063 unoToSbxValue( pVar, aRetAny );
2065 catch( const Exception& )
2067 implHandleAnyException( ::cppu::getCaughtException() );
2070 else if( bInvocation && mxInvocation.is() )
2074 sal_uInt32 nParamCount = pParams ? (static_cast<sal_uInt32>(pParams->Count()) - 1) : 0;
2075 bool bCanBeConsideredAMethod = mxInvocation->hasMethod( pProp->GetName() );
2076 Any aRetAny;
2077 if ( bCanBeConsideredAMethod && nParamCount )
2079 // Automation properties have methods, so... we need to invoke this through
2080 // XInvocation
2081 Sequence<Any> args;
2082 processAutomationParams( pParams, args, nParamCount );
2083 aRetAny = invokeAutomationMethod( pProp->GetName(), args, pParams, nParamCount, mxInvocation, INVOKETYPE::GetProp );
2085 else
2086 aRetAny = mxInvocation->getValue( pProp->GetName() );
2087 // take over the value from Uno to Sbx
2088 unoToSbxValue( pVar, aRetAny );
2089 if( pParams && bCanBeConsideredAMethod )
2090 pVar->SetParameters( nullptr );
2093 catch( const Exception& )
2095 implHandleAnyException( ::cppu::getCaughtException() );
2099 else if( pHint->GetId() == SfxHintId::BasicDataChanged )
2101 if( !bInvocation && mxUnoAccess.is() )
2103 if( pProp->aUnoProp.Attributes & PropertyAttribute::READONLY )
2105 StarBASIC::Error( ERRCODE_BASIC_PROP_READONLY );
2106 return;
2108 if ( maStructInfo.get() )
2110 StructRefInfo aMember = maStructInfo->getStructMember( pProp->GetName() );
2111 if ( aMember.isEmpty() )
2113 StarBASIC::Error( ERRCODE_BASIC_PROPERTY_NOT_FOUND );
2115 else
2117 Any aAnyValue = sbxToUnoValue( pVar, pProp->aUnoProp.Type, &pProp->aUnoProp );
2118 aMember.setValue( aAnyValue );
2120 return;
2122 // take over the value from Uno to Sbx
2123 Any aAnyValue = sbxToUnoValue( pVar, pProp->aUnoProp.Type, &pProp->aUnoProp );
2126 // set the value
2127 Reference< XPropertySet > xPropSet( mxUnoAccess->queryAdapter( cppu::UnoType<XPropertySet>::get()), UNO_QUERY );
2128 xPropSet->setPropertyValue( pProp->GetName(), aAnyValue );
2129 // The use of getPropertyValue (instead of using the index) is
2130 // suboptimal, but the refactoring to XInvocation is already pending
2131 // Otherwise it is possible to use FastPropertySet
2133 catch( const Exception& )
2135 implHandleAnyException( ::cppu::getCaughtException() );
2138 else if( bInvocation && mxInvocation.is() )
2140 // take over the value from Uno to Sbx
2141 Any aAnyValue = sbxToUnoValueImpl( pVar );
2144 // set the value
2145 mxInvocation->setValue( pProp->GetName(), aAnyValue );
2147 catch( const Exception& )
2149 implHandleAnyException( ::cppu::getCaughtException() );
2154 else if( pMeth )
2156 bool bInvocation = pMeth->isInvocationBased();
2157 if( pHint->GetId() == SfxHintId::BasicDataWanted )
2159 // number of Parameter -1 because of Param0 == this
2160 sal_uInt32 nParamCount = pParams ? (static_cast<sal_uInt32>(pParams->Count()) - 1) : 0;
2161 Sequence<Any> args;
2162 bool bOutParams = false;
2164 if( !bInvocation && mxUnoAccess.is() )
2166 // get info
2167 const Sequence<ParamInfo>& rInfoSeq = pMeth->getParamInfos();
2168 const ParamInfo* pParamInfos = rInfoSeq.getConstArray();
2169 sal_uInt32 nUnoParamCount = rInfoSeq.getLength();
2170 sal_uInt32 nAllocParamCount = nParamCount;
2172 // ignore surplus parameter; alternative: throw an error
2173 if( nParamCount > nUnoParamCount )
2175 nParamCount = nUnoParamCount;
2176 nAllocParamCount = nParamCount;
2178 else if( nParamCount < nUnoParamCount )
2180 SbiInstance* pInst = GetSbData()->pInst;
2181 if( pInst && pInst->IsCompatibility() )
2183 // Check types
2184 bool bError = false;
2185 for( sal_uInt32 i = nParamCount ; i < nUnoParamCount ; i++ )
2187 const ParamInfo& rInfo = pParamInfos[i];
2188 const Reference< XIdlClass >& rxClass = rInfo.aType;
2189 if( rxClass->getTypeClass() != TypeClass_ANY )
2191 bError = true;
2192 StarBASIC::Error( ERRCODE_BASIC_NOT_OPTIONAL );
2195 if( !bError )
2196 nAllocParamCount = nUnoParamCount;
2200 if( nAllocParamCount > 0 )
2202 args.realloc( nAllocParamCount );
2203 Any* pAnyArgs = args.getArray();
2204 for( sal_uInt32 i = 0 ; i < nParamCount ; i++ )
2206 const ParamInfo& rInfo = pParamInfos[i];
2207 const Reference< XIdlClass >& rxClass = rInfo.aType;
2209 css::uno::Type aType( rxClass->getTypeClass(), rxClass->getName() );
2211 // ATTENTION: Don't forget for Sbx-Parameter the offset!
2212 pAnyArgs[i] = sbxToUnoValue( pParams->Get( static_cast<sal_uInt16>(i+1) ), aType );
2214 // If it is not certain check whether the out-parameter are available.
2215 if( !bOutParams )
2217 ParamMode aParamMode = rInfo.aMode;
2218 if( aParamMode != ParamMode_IN )
2219 bOutParams = true;
2224 else if( bInvocation && pParams && mxInvocation.is() )
2226 processAutomationParams( pParams, args, nParamCount );
2229 // call the method
2230 GetSbData()->bBlockCompilerError = true; // #106433 Block compiler errors for API calls
2233 if( !bInvocation && mxUnoAccess.is() )
2235 Any aRetAny = pMeth->m_xUnoMethod->invoke( getUnoAny(), args );
2237 // take over the value from Uno to Sbx
2238 unoToSbxValue( pVar, aRetAny );
2240 // Did we to copy back the Out-Parameter?
2241 if( bOutParams )
2243 const Any* pAnyArgs = args.getConstArray();
2245 // get info
2246 const Sequence<ParamInfo>& rInfoSeq = pMeth->getParamInfos();
2247 const ParamInfo* pParamInfos = rInfoSeq.getConstArray();
2249 sal_uInt32 j;
2250 for( j = 0 ; j < nParamCount ; j++ )
2252 const ParamInfo& rInfo = pParamInfos[j];
2253 ParamMode aParamMode = rInfo.aMode;
2254 if( aParamMode != ParamMode_IN )
2255 unoToSbxValue( pParams->Get( static_cast<sal_uInt16>(j+1) ), pAnyArgs[ j ] );
2259 else if( bInvocation && mxInvocation.is() )
2261 Any aRetAny = invokeAutomationMethod( pMeth->GetName(), args, pParams, nParamCount, mxInvocation, INVOKETYPE::Func );
2262 unoToSbxValue( pVar, aRetAny );
2265 // remove parameter here, because this was not done anymore in unoToSbxValue()
2266 // for arrays
2267 if( pParams )
2268 pVar->SetParameters( nullptr );
2270 catch( const Exception& )
2272 implHandleAnyException( ::cppu::getCaughtException() );
2274 GetSbData()->bBlockCompilerError = false; // #106433 Unblock compiler errors
2277 else
2278 SbxObject::Notify( rBC, rHint );
2283 SbUnoObject::SbUnoObject( const OUString& aName_, const Any& aUnoObj_ )
2284 : SbxObject( aName_ )
2285 , bNeedIntrospection( true )
2286 , bNativeCOMObject( false )
2288 // beat out again the default properties of Sbx
2289 Remove( "Name", SbxClassType::DontCare );
2290 Remove( "Parent", SbxClassType::DontCare );
2292 // check the type of the objects
2293 TypeClass eType = aUnoObj_.getValueType().getTypeClass();
2294 Reference< XInterface > x;
2295 if( eType == TypeClass_INTERFACE )
2297 // get the interface from the Any
2298 aUnoObj_ >>= x;
2299 if( !x.is() )
2300 return;
2303 Reference< XTypeProvider > xTypeProvider;
2304 // Did the object have an invocation itself?
2305 mxInvocation.set( x, UNO_QUERY );
2307 xTypeProvider.set( x, UNO_QUERY );
2309 if( mxInvocation.is() )
2312 // get the ExactName
2313 mxExactNameInvocation.set( mxInvocation, UNO_QUERY );
2315 // The remainder refers only to the introspection
2316 if( !xTypeProvider.is() )
2318 bNeedIntrospection = false;
2319 return;
2322 // Ignore introspection based members for COM objects to avoid
2323 // hiding of equally named COM symbols, e.g. XInvocation::getValue
2324 Reference< oleautomation::XAutomationObject > xAutomationObject( aUnoObj_, UNO_QUERY );
2325 if( xAutomationObject.is() )
2326 bNativeCOMObject = true;
2329 maTmpUnoObj = aUnoObj_;
2332 //*** Define the name ***
2333 bool bFatalError = true;
2335 // Is it an interface or a struct?
2336 bool bSetClassName = false;
2337 OUString aClassName_;
2338 if( eType == TypeClass_STRUCT || eType == TypeClass_EXCEPTION )
2340 // Struct is Ok
2341 bFatalError = false;
2343 // insert the real name of the class
2344 if( aName_.isEmpty() )
2346 aClassName_ = aUnoObj_.getValueType().getTypeName();
2347 bSetClassName = true;
2349 StructRefInfo aThisStruct( maTmpUnoObj, maTmpUnoObj.getValueType(), 0 );
2350 maStructInfo.reset( new SbUnoStructRefObject( GetName(), aThisStruct ) );
2352 else if( eType == TypeClass_INTERFACE )
2354 // Interface works always through the type in the Any
2355 bFatalError = false;
2357 if( bSetClassName )
2358 SetClassName( aClassName_ );
2360 // Neither interface nor Struct -> FatalError
2361 if( bFatalError )
2363 StarBASIC::FatalError( ERRCODE_BASIC_EXCEPTION );
2364 return;
2367 // pass the introspection primal on demand
2370 SbUnoObject::~SbUnoObject()
2375 // pass the introspection on Demand
2376 void SbUnoObject::doIntrospection()
2378 if( !bNeedIntrospection )
2379 return;
2381 Reference<XComponentContext> xContext = comphelper::getProcessComponentContext();
2383 if (!xContext.is())
2384 return;
2387 // get the introspection service
2388 Reference<XIntrospection> xIntrospection;
2392 xIntrospection = theIntrospection::get(xContext);
2394 catch ( const css::uno::DeploymentException& )
2398 if (!xIntrospection.is())
2399 return;
2401 bNeedIntrospection = false;
2403 // pass the introspection
2406 mxUnoAccess = xIntrospection->inspect( maTmpUnoObj );
2408 catch( const RuntimeException& e )
2410 StarBASIC::Error( ERRCODE_BASIC_EXCEPTION, implGetExceptionMsg( e ) );
2413 if( !mxUnoAccess.is() )
2415 // #51475 mark to indicate an invalid object (no mxMaterialHolder)
2416 return;
2419 // get MaterialHolder from access
2420 mxMaterialHolder.set( mxUnoAccess, UNO_QUERY );
2422 // get ExactName from access
2423 mxExactName.set( mxUnoAccess, UNO_QUERY );
2427 // Start of a list of all SbUnoMethod-Instances
2428 static SbUnoMethod* pFirst = nullptr;
2430 void clearUnoMethodsForBasic( StarBASIC const * pBasic )
2432 SbUnoMethod* pMeth = pFirst;
2433 while( pMeth )
2435 SbxObject* pObject = pMeth->GetParent();
2436 if ( pObject )
2438 StarBASIC* pModBasic = dynamic_cast< StarBASIC* >( pObject->GetParent() );
2439 if ( pModBasic == pBasic )
2441 // for now the solution is to remove the method from the list and to clear it,
2442 // but in case the element should be correctly transferred to another StarBASIC,
2443 // we should either set module parent to NULL without clearing it, or even
2444 // set the new StarBASIC as the parent of the module
2445 // pObject->SetParent( NULL );
2447 if( pMeth == pFirst )
2448 pFirst = pMeth->pNext;
2449 else if( pMeth->pPrev )
2450 pMeth->pPrev->pNext = pMeth->pNext;
2451 if( pMeth->pNext )
2452 pMeth->pNext->pPrev = pMeth->pPrev;
2454 pMeth->pPrev = nullptr;
2455 pMeth->pNext = nullptr;
2457 pMeth->SbxValue::Clear();
2458 pObject->SbxValue::Clear();
2460 // start from the beginning after object clearing, the cycle will end since the method is removed each time
2461 pMeth = pFirst;
2463 else
2464 pMeth = pMeth->pNext;
2466 else
2467 pMeth = pMeth->pNext;
2471 void clearUnoMethods()
2473 SbUnoMethod* pMeth = pFirst;
2474 while( pMeth )
2476 pMeth->SbxValue::Clear();
2477 pMeth = pMeth->pNext;
2482 SbUnoMethod::SbUnoMethod
2484 const OUString& aName_,
2485 SbxDataType eSbxType,
2486 Reference< XIdlMethod > const & xUnoMethod_,
2487 bool bInvocation
2489 : SbxMethod( aName_, eSbxType )
2490 , mbInvocation( bInvocation )
2492 m_xUnoMethod = xUnoMethod_;
2493 pParamInfoSeq = nullptr;
2495 // enregister the method in a list
2496 pNext = pFirst;
2497 pPrev = nullptr;
2498 pFirst = this;
2499 if( pNext )
2500 pNext->pPrev = this;
2503 SbUnoMethod::~SbUnoMethod()
2505 pParamInfoSeq.reset();
2507 if( this == pFirst )
2508 pFirst = pNext;
2509 else if( pPrev )
2510 pPrev->pNext = pNext;
2511 if( pNext )
2512 pNext->pPrev = pPrev;
2515 SbxInfo* SbUnoMethod::GetInfo()
2517 if( !pInfo.is() && m_xUnoMethod.is() )
2519 SbiInstance* pInst = GetSbData()->pInst;
2520 if( pInst && pInst->IsCompatibility() )
2522 pInfo = new SbxInfo();
2524 const Sequence<ParamInfo>& rInfoSeq = getParamInfos();
2525 const ParamInfo* pParamInfos = rInfoSeq.getConstArray();
2526 sal_uInt32 nParamCount = rInfoSeq.getLength();
2528 for( sal_uInt32 i = 0 ; i < nParamCount ; i++ )
2530 const ParamInfo& rInfo = pParamInfos[i];
2531 OUString aParamName = rInfo.aName;
2533 pInfo->AddParam( aParamName, SbxVARIANT, SbxFlagBits::Read );
2537 return pInfo.get();
2540 const Sequence<ParamInfo>& SbUnoMethod::getParamInfos()
2542 if (!pParamInfoSeq)
2544 Sequence<ParamInfo> aTmp;
2545 if (m_xUnoMethod.is())
2546 aTmp = m_xUnoMethod->getParameterInfos();
2547 pParamInfoSeq.reset( new Sequence<ParamInfo>(aTmp) );
2549 return *pParamInfoSeq;
2552 SbUnoProperty::SbUnoProperty
2554 const OUString& aName_,
2555 SbxDataType eSbxType,
2556 SbxDataType eRealSbxType,
2557 const Property& aUnoProp_,
2558 sal_Int32 nId_,
2559 bool bInvocation,
2560 bool bUnoStruct
2562 : SbxProperty( aName_, eSbxType )
2563 , aUnoProp( aUnoProp_ )
2564 , nId( nId_ )
2565 , mbInvocation( bInvocation )
2566 , mRealType( eRealSbxType )
2567 , mbUnoStruct( bUnoStruct )
2569 // as needed establish a dummy array so that SbiRuntime::CheckArray() works
2570 static SbxArrayRef xDummyArray = new SbxArray( SbxVARIANT );
2571 if( eSbxType & SbxARRAY )
2572 PutObject( xDummyArray.get() );
2575 SbUnoProperty::~SbUnoProperty()
2579 SbxVariable* SbUnoObject::Find( const OUString& rName, SbxClassType t )
2581 static Reference< XIdlMethod > xDummyMethod;
2582 static Property aDummyProp;
2584 SbxVariable* pRes = SbxObject::Find( rName, t );
2586 if( bNeedIntrospection )
2587 doIntrospection();
2589 // New 1999-03-04: Create properties on demand. Therefore search now via
2590 // IntrospectionAccess if a property or a method of the required name exist
2591 if( !pRes )
2593 OUString aUName( rName );
2594 if( mxUnoAccess.is() && !bNativeCOMObject )
2596 if( mxExactName.is() )
2598 OUString aUExactName = mxExactName->getExactName( aUName );
2599 if( !aUExactName.isEmpty() )
2601 aUName = aUExactName;
2604 if( mxUnoAccess->hasProperty( aUName, PropertyConcept::ALL - PropertyConcept::DANGEROUS ) )
2606 const Property& rProp = mxUnoAccess->
2607 getProperty( aUName, PropertyConcept::ALL - PropertyConcept::DANGEROUS );
2609 // If the property could be void the type had to be set to Variant
2610 SbxDataType eSbxType;
2611 if( rProp.Attributes & PropertyAttribute::MAYBEVOID )
2612 eSbxType = SbxVARIANT;
2613 else
2614 eSbxType = unoToSbxType( rProp.Type.getTypeClass() );
2616 SbxDataType eRealSbxType = ( ( rProp.Attributes & PropertyAttribute::MAYBEVOID ) ? unoToSbxType( rProp.Type.getTypeClass() ) : eSbxType );
2617 // create the property and superimpose it
2618 auto pProp = tools::make_ref<SbUnoProperty>( rProp.Name, eSbxType, eRealSbxType, rProp, 0, false, ( rProp.Type.getTypeClass() == css::uno::TypeClass_STRUCT ) );
2619 QuickInsert( pProp.get() );
2620 pRes = pProp.get();
2622 else if( mxUnoAccess->hasMethod( aUName,
2623 MethodConcept::ALL - MethodConcept::DANGEROUS ) )
2625 // address the method
2626 const Reference< XIdlMethod >& rxMethod = mxUnoAccess->
2627 getMethod( aUName, MethodConcept::ALL - MethodConcept::DANGEROUS );
2629 // create SbUnoMethod and superimpose it
2630 auto xMethRef = tools::make_ref<SbUnoMethod>( rxMethod->getName(),
2631 unoToSbxType( rxMethod->getReturnType() ), rxMethod, false );
2632 QuickInsert( xMethRef.get() );
2633 pRes = xMethRef.get();
2636 // If nothing was found check via XNameAccess
2637 if( !pRes )
2641 Reference< XNameAccess > xNameAccess( mxUnoAccess->queryAdapter( cppu::UnoType<XPropertySet>::get()), UNO_QUERY );
2643 if( xNameAccess.is() && xNameAccess->hasByName( rName ) )
2645 Any aAny = xNameAccess->getByName( rName );
2647 // ATTENTION: Because of XNameAccess, the variable generated here
2648 // may not be included as a fixed property in the object and therefore
2649 // won't be stored anywhere.
2650 // If this leads to problems, it has to be created
2651 // synthetically or a class SbUnoNameAccessProperty,
2652 // which checks the existence on access and which
2653 // is disposed if the name is not found anymore.
2654 pRes = new SbxVariable( SbxVARIANT );
2655 unoToSbxValue( pRes, aAny );
2658 catch( const NoSuchElementException& e )
2660 StarBASIC::Error( ERRCODE_BASIC_EXCEPTION, implGetExceptionMsg( e ) );
2662 catch( const Exception& )
2664 // Establish so that the exception error will not be overwritten
2665 if( !pRes )
2666 pRes = new SbxVariable( SbxVARIANT );
2668 implHandleAnyException( ::cppu::getCaughtException() );
2672 if( !pRes && mxInvocation.is() )
2674 if( mxExactNameInvocation.is() )
2676 OUString aUExactName = mxExactNameInvocation->getExactName( aUName );
2677 if( !aUExactName.isEmpty() )
2679 aUName = aUExactName;
2685 if( mxInvocation->hasProperty( aUName ) )
2687 // create a property and superimpose it
2688 auto xVarRef = tools::make_ref<SbUnoProperty>( aUName, SbxVARIANT, SbxVARIANT, aDummyProp, 0, true, false );
2689 QuickInsert( xVarRef.get() );
2690 pRes = xVarRef.get();
2692 else if( mxInvocation->hasMethod( aUName ) )
2694 // create SbUnoMethode and superimpose it
2695 auto xMethRef = tools::make_ref<SbUnoMethod>( aUName, SbxVARIANT, xDummyMethod, true );
2696 QuickInsert( xMethRef.get() );
2697 pRes = xMethRef.get();
2699 else
2701 Reference< XDirectInvocation > xDirectInvoke( mxInvocation, UNO_QUERY );
2702 if ( xDirectInvoke.is() && xDirectInvoke->hasMember( aUName ) )
2704 auto xMethRef = tools::make_ref<SbUnoMethod>( aUName, SbxVARIANT, xDummyMethod, true );
2705 QuickInsert( xMethRef.get() );
2706 pRes = xMethRef.get();
2711 catch( const RuntimeException& e )
2713 // Establish so that the exception error will not be overwritten
2714 if( !pRes )
2715 pRes = new SbxVariable( SbxVARIANT );
2717 StarBASIC::Error( ERRCODE_BASIC_EXCEPTION, implGetExceptionMsg( e ) );
2722 // At the very end checking if the Dbg_-Properties are meant
2724 if( !pRes )
2726 if( rName.equalsIgnoreAsciiCase(ID_DBG_SUPPORTEDINTERFACES) ||
2727 rName.equalsIgnoreAsciiCase(ID_DBG_PROPERTIES) ||
2728 rName.equalsIgnoreAsciiCase(ID_DBG_METHODS) )
2730 // Create
2731 implCreateDbgProperties();
2733 // Now they have to be found regular
2734 pRes = SbxObject::Find( rName, SbxClassType::DontCare );
2737 return pRes;
2741 // help method to create the dbg_-Properties
2742 void SbUnoObject::implCreateDbgProperties()
2744 Property aProp;
2746 // Id == -1: display the implemented interfaces corresponding the ClassProvider
2747 auto xVarRef = tools::make_ref<SbUnoProperty>( OUString(ID_DBG_SUPPORTEDINTERFACES), SbxSTRING, SbxSTRING, aProp, -1, false, false );
2748 QuickInsert( xVarRef.get() );
2750 // Id == -2: output the properties
2751 xVarRef = tools::make_ref<SbUnoProperty>( OUString(ID_DBG_PROPERTIES), SbxSTRING, SbxSTRING, aProp, -2, false, false );
2752 QuickInsert( xVarRef.get() );
2754 // Id == -3: output the Methods
2755 xVarRef = tools::make_ref<SbUnoProperty>( OUString(ID_DBG_METHODS), SbxSTRING, SbxSTRING, aProp, -3, false, false );
2756 QuickInsert( xVarRef.get() );
2759 void SbUnoObject::implCreateAll()
2761 // throw away all existing methods and properties
2762 pMethods = tools::make_ref<SbxArray>();
2763 pProps = tools::make_ref<SbxArray>();
2765 if( bNeedIntrospection ) doIntrospection();
2767 // get introspection
2768 Reference< XIntrospectionAccess > xAccess = mxUnoAccess;
2769 if( !xAccess.is() || bNativeCOMObject )
2771 if( mxInvocation.is() )
2772 xAccess = mxInvocation->getIntrospection();
2773 else if( bNativeCOMObject )
2774 return;
2776 if( !xAccess.is() )
2777 return;
2779 // Establish properties
2780 Sequence<Property> props = xAccess->getProperties( PropertyConcept::ALL - PropertyConcept::DANGEROUS );
2781 sal_uInt32 nPropCount = props.getLength();
2782 const Property* pProps_ = props.getConstArray();
2784 sal_uInt32 i;
2785 for( i = 0 ; i < nPropCount ; i++ )
2787 const Property& rProp = pProps_[ i ];
2789 // If the property could be void the type had to be set to Variant
2790 SbxDataType eSbxType;
2791 if( rProp.Attributes & PropertyAttribute::MAYBEVOID )
2792 eSbxType = SbxVARIANT;
2793 else
2794 eSbxType = unoToSbxType( rProp.Type.getTypeClass() );
2796 SbxDataType eRealSbxType = ( ( rProp.Attributes & PropertyAttribute::MAYBEVOID ) ? unoToSbxType( rProp.Type.getTypeClass() ) : eSbxType );
2797 // Create property and superimpose it
2798 auto xVarRef = tools::make_ref<SbUnoProperty>( rProp.Name, eSbxType, eRealSbxType, rProp, i, false, ( rProp.Type.getTypeClass() == css::uno::TypeClass_STRUCT ) );
2799 QuickInsert( xVarRef.get() );
2802 // Create Dbg_-Properties
2803 implCreateDbgProperties();
2805 // Create methods
2806 Sequence< Reference< XIdlMethod > > aMethodSeq = xAccess->getMethods
2807 ( MethodConcept::ALL - MethodConcept::DANGEROUS );
2808 sal_uInt32 nMethCount = aMethodSeq.getLength();
2809 const Reference< XIdlMethod >* pMethods_ = aMethodSeq.getConstArray();
2810 for( i = 0 ; i < nMethCount ; i++ )
2812 // address method
2813 const Reference< XIdlMethod >& rxMethod = pMethods_[i];
2815 // Create SbUnoMethod and superimpose it
2816 auto xMethRef = tools::make_ref<SbUnoMethod>
2817 ( rxMethod->getName(), unoToSbxType( rxMethod->getReturnType() ), rxMethod, false );
2818 QuickInsert( xMethRef.get() );
2823 // output the value
2824 Any SbUnoObject::getUnoAny()
2826 Any aRetAny;
2827 if( bNeedIntrospection ) doIntrospection();
2828 if ( maStructInfo.get() )
2829 aRetAny = maTmpUnoObj;
2830 else if( mxMaterialHolder.is() )
2831 aRetAny = mxMaterialHolder->getMaterial();
2832 else if( mxInvocation.is() )
2833 aRetAny <<= mxInvocation;
2834 return aRetAny;
2837 // help method to create a Uno-Struct per CoreReflection
2838 static SbUnoObject* Impl_CreateUnoStruct( const OUString& aClassName )
2840 // get CoreReflection
2841 Reference< XIdlReflection > xCoreReflection = getCoreReflection_Impl();
2842 if( !xCoreReflection.is() )
2843 return nullptr;
2845 // search for the class
2846 Reference< XIdlClass > xClass;
2847 const Reference< XHierarchicalNameAccess >& xHarryName =
2848 getCoreReflection_HierarchicalNameAccess_Impl();
2849 if( xHarryName.is() && xHarryName->hasByHierarchicalName( aClassName ) )
2850 xClass = xCoreReflection->forName( aClassName );
2851 if( !xClass.is() )
2852 return nullptr;
2854 // Is it really a struct?
2855 TypeClass eType = xClass->getTypeClass();
2856 if ( ( eType != TypeClass_STRUCT ) && ( eType != TypeClass_EXCEPTION ) )
2857 return nullptr;
2859 // create an instance
2860 Any aNewAny;
2861 xClass->createObject( aNewAny );
2862 // make a SbUnoObject out of it
2863 SbUnoObject* pUnoObj = new SbUnoObject( aClassName, aNewAny );
2864 return pUnoObj;
2868 // Factory-Class to create Uno-Structs per DIM AS NEW
2869 SbxBase* SbUnoFactory::Create( sal_uInt16, sal_uInt32 )
2871 // Via SbxId nothing works in Uno
2872 return nullptr;
2875 SbxObject* SbUnoFactory::CreateObject( const OUString& rClassName )
2877 return Impl_CreateUnoStruct( rClassName );
2881 // Provisional interface for the UNO-Connection
2882 // Deliver a SbxObject, that wrap a Uno-Interface
2883 SbxObjectRef GetSbUnoObject( const OUString& aName, const Any& aUnoObj_ )
2885 return new SbUnoObject( aName, aUnoObj_ );
2888 // Force creation of all properties for debugging
2889 void createAllObjectProperties( SbxObject* pObj )
2891 if( !pObj )
2892 return;
2894 SbUnoObject* pUnoObj = dynamic_cast<SbUnoObject*>( pObj );
2895 SbUnoStructRefObject* pUnoStructObj = dynamic_cast<SbUnoStructRefObject*>( pObj );
2896 if( pUnoObj )
2898 pUnoObj->createAllProperties();
2900 else if ( pUnoStructObj )
2902 pUnoStructObj->createAllProperties();
2907 void RTL_Impl_CreateUnoStruct( SbxArray& rPar )
2909 // We need 1 parameter minimum
2910 if ( rPar.Count() < 2 )
2912 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
2913 return;
2916 // get the name of the class of the struct
2917 OUString aClassName = rPar.Get(1)->GetOUString();
2919 // try to create Struct with the same name
2920 SbUnoObjectRef xUnoObj = Impl_CreateUnoStruct( aClassName );
2921 if( !xUnoObj.is() )
2923 return;
2925 // return the object
2926 SbxVariableRef refVar = rPar.Get(0);
2927 refVar->PutObject( xUnoObj.get() );
2930 void RTL_Impl_CreateUnoService( SbxArray& rPar )
2932 // We need 1 Parameter minimum
2933 if ( rPar.Count() < 2 )
2935 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
2936 return;
2939 // get the name of the class of the struct
2940 OUString aServiceName = rPar.Get(1)->GetOUString();
2942 // search for the service and instantiate it
2943 Reference< XMultiServiceFactory > xFactory( comphelper::getProcessServiceFactory() );
2944 Reference< XInterface > xInterface;
2947 xInterface = xFactory->createInstance( aServiceName );
2949 catch( const Exception& )
2951 implHandleAnyException( ::cppu::getCaughtException() );
2954 SbxVariableRef refVar = rPar.Get(0);
2955 if( xInterface.is() )
2957 // Create a SbUnoObject out of it and return it
2958 SbUnoObjectRef xUnoObj = new SbUnoObject( aServiceName, Any(xInterface) );
2959 if( xUnoObj->getUnoAny().hasValue() )
2961 // return the object
2962 refVar->PutObject( xUnoObj.get() );
2964 else
2966 refVar->PutObject( nullptr );
2969 else
2971 refVar->PutObject( nullptr );
2975 void RTL_Impl_CreateUnoServiceWithArguments( SbxArray& rPar )
2977 // We need 2 parameter minimum
2978 if ( rPar.Count() < 3 )
2980 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
2981 return;
2984 // get the name of the class of the struct
2985 OUString aServiceName = rPar.Get(1)->GetOUString();
2986 Any aArgAsAny = sbxToUnoValue( rPar.Get(2),
2987 cppu::UnoType<Sequence<Any>>::get() );
2988 Sequence< Any > aArgs;
2989 aArgAsAny >>= aArgs;
2991 // search for the service and instantiate it
2992 Reference< XMultiServiceFactory > xFactory( comphelper::getProcessServiceFactory() );
2993 Reference< XInterface > xInterface;
2996 xInterface = xFactory->createInstanceWithArguments( aServiceName, aArgs );
2998 catch( const Exception& )
3000 implHandleAnyException( ::cppu::getCaughtException() );
3003 SbxVariableRef refVar = rPar.Get(0);
3004 if( xInterface.is() )
3006 // Create a SbUnoObject out of it and return it
3007 SbUnoObjectRef xUnoObj = new SbUnoObject( aServiceName, Any(xInterface) );
3008 if( xUnoObj->getUnoAny().hasValue() )
3010 // return the object
3011 refVar->PutObject( xUnoObj.get() );
3013 else
3015 refVar->PutObject( nullptr );
3018 else
3020 refVar->PutObject( nullptr );
3024 void RTL_Impl_GetProcessServiceManager( SbxArray& rPar )
3026 SbxVariableRef refVar = rPar.Get(0);
3028 // get the global service manager
3029 Reference< XMultiServiceFactory > xFactory( comphelper::getProcessServiceFactory() );
3031 // Create a SbUnoObject out of it and return it
3032 SbUnoObjectRef xUnoObj = new SbUnoObject( "ProcessServiceManager", Any(xFactory) );
3033 refVar->PutObject( xUnoObj.get() );
3036 void RTL_Impl_HasInterfaces( SbxArray& rPar )
3038 // We need 2 parameter minimum
3039 sal_uInt16 nParCount = rPar.Count();
3040 if( nParCount < 3 )
3042 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
3043 return;
3046 // variable for the return value
3047 SbxVariableRef refVar = rPar.Get(0);
3048 refVar->PutBool( false );
3050 // get the Uno-Object
3051 SbxBaseRef pObj = rPar.Get( 1 )->GetObject();
3052 auto obj = dynamic_cast<SbUnoObject*>( pObj.get() );
3053 if( obj == nullptr )
3055 return;
3057 Any aAny = obj->getUnoAny();
3058 auto x = o3tl::tryAccess<Reference<XInterface>>(aAny);
3059 if( !x )
3061 return;
3064 // get CoreReflection
3065 Reference< XIdlReflection > xCoreReflection = getCoreReflection_Impl();
3066 if( !xCoreReflection.is() )
3068 return;
3070 for( sal_uInt16 i = 2 ; i < nParCount ; i++ )
3072 // get the name of the interface of the struct
3073 OUString aIfaceName = rPar.Get( i )->GetOUString();
3075 // search for the class
3076 Reference< XIdlClass > xClass = xCoreReflection->forName( aIfaceName );
3077 if( !xClass.is() )
3079 return;
3081 // check if the interface will be supported
3082 OUString aClassName = xClass->getName();
3083 Type aClassType( xClass->getTypeClass(), aClassName );
3084 if( !(*x)->queryInterface( aClassType ).hasValue() )
3086 return;
3090 // Everything works; then return TRUE
3091 refVar->PutBool( true );
3094 void RTL_Impl_IsUnoStruct( SbxArray& rPar )
3096 // We need 1 parameter minimum
3097 if ( rPar.Count() < 2 )
3099 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
3100 return;
3103 // variable for the return value
3104 SbxVariableRef refVar = rPar.Get(0);
3105 refVar->PutBool( false );
3107 // get the Uno-Object
3108 SbxVariableRef xParam = rPar.Get( 1 );
3109 if( !xParam->IsObject() )
3111 return;
3113 SbxBaseRef pObj = rPar.Get( 1 )->GetObject();
3114 auto obj = dynamic_cast<SbUnoObject*>( pObj.get() );
3115 if( obj == nullptr )
3117 return;
3119 Any aAny = obj->getUnoAny();
3120 TypeClass eType = aAny.getValueType().getTypeClass();
3121 if( eType == TypeClass_STRUCT )
3123 refVar->PutBool( true );
3128 void RTL_Impl_EqualUnoObjects( SbxArray& rPar )
3130 if ( rPar.Count() < 3 )
3132 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
3133 return;
3136 // variable for the return value
3137 SbxVariableRef refVar = rPar.Get(0);
3138 refVar->PutBool( false );
3140 // get the Uno-Objects
3141 SbxVariableRef xParam1 = rPar.Get( 1 );
3142 if( !xParam1->IsObject() )
3144 return;
3146 SbxBaseRef pObj1 = xParam1->GetObject();
3147 auto obj1 = dynamic_cast<SbUnoObject*>( pObj1.get() );
3148 if( obj1 == nullptr )
3150 return;
3152 Any aAny1 = obj1->getUnoAny();
3153 TypeClass eType1 = aAny1.getValueType().getTypeClass();
3154 if( eType1 != TypeClass_INTERFACE )
3156 return;
3158 Reference< XInterface > x1;
3159 aAny1 >>= x1;
3161 SbxVariableRef xParam2 = rPar.Get( 2 );
3162 if( !xParam2->IsObject() )
3164 return;
3166 SbxBaseRef pObj2 = xParam2->GetObject();
3167 auto obj2 = dynamic_cast<SbUnoObject*>( pObj2.get() );
3168 if( obj2 == nullptr )
3170 return;
3172 Any aAny2 = obj2->getUnoAny();
3173 TypeClass eType2 = aAny2.getValueType().getTypeClass();
3174 if( eType2 != TypeClass_INTERFACE )
3176 return;
3178 Reference< XInterface > x2;
3179 aAny2 >>= x2;
3181 if( x1 == x2 )
3183 refVar->PutBool( true );
3188 // helper wrapper function to interact with TypeProvider and
3189 // XTypeDescriptionEnumerationAccess.
3190 // if it fails for whatever reason
3191 // returned Reference<> be null e.g. .is() will be false
3193 static Reference< XTypeDescriptionEnumeration > getTypeDescriptorEnumeration( const OUString& sSearchRoot,
3194 const Sequence< TypeClass >& types,
3195 TypeDescriptionSearchDepth depth )
3197 Reference< XTypeDescriptionEnumeration > xEnum;
3198 Reference< XTypeDescriptionEnumerationAccess> xTypeEnumAccess( getTypeProvider_Impl(), UNO_QUERY );
3199 if ( xTypeEnumAccess.is() )
3203 xEnum = xTypeEnumAccess->createTypeDescriptionEnumeration(
3204 sSearchRoot, types, depth );
3206 catch(const NoSuchTypeNameException& /*nstne*/ ) {}
3207 catch(const InvalidTypeNameException& /*nstne*/ ) {}
3209 return xEnum;
3212 VBAConstantHelper&
3213 VBAConstantHelper::instance()
3215 static VBAConstantHelper aHelper;
3216 return aHelper;
3219 void VBAConstantHelper::init()
3221 if ( !isInited )
3223 Sequence< TypeClass > types(1);
3224 types[ 0 ] = TypeClass_CONSTANTS;
3225 Reference< XTypeDescriptionEnumeration > xEnum = getTypeDescriptorEnumeration( "ooo.vba", types, TypeDescriptionSearchDepth_INFINITE );
3227 if ( !xEnum.is())
3229 return; //NULL;
3231 while ( xEnum->hasMoreElements() )
3233 Reference< XConstantsTypeDescription > xConstants( xEnum->nextElement(), UNO_QUERY );
3234 if ( xConstants.is() )
3236 // store constant group name
3237 OUString sFullName = xConstants->getName();
3238 sal_Int32 indexLastDot = sFullName.lastIndexOf('.');
3239 OUString sLeafName( sFullName );
3240 if ( indexLastDot > -1 )
3242 sLeafName = sFullName.copy( indexLastDot + 1);
3244 aConstCache.push_back( sLeafName ); // assume constant group names are unique
3245 Sequence< Reference< XConstantTypeDescription > > aConsts = xConstants->getConstants();
3246 for (sal_Int32 i = 0; i != aConsts.getLength(); ++i)
3248 // store constant member name
3249 sFullName = aConsts[i]->getName();
3250 indexLastDot = sFullName.lastIndexOf('.');
3251 sLeafName = sFullName;
3252 if ( indexLastDot > -1 )
3254 sLeafName = sFullName.copy( indexLastDot + 1);
3256 aConstHash[ sLeafName.toAsciiLowerCase() ] = aConsts[i]->getConstantValue();
3260 isInited = true;
3264 bool
3265 VBAConstantHelper::isVBAConstantType( const OUString& rName )
3267 init();
3268 bool bConstant = false;
3270 for (auto const& elem : aConstCache)
3272 if( rName.equalsIgnoreAsciiCase(elem) )
3274 bConstant = true;
3275 break;
3278 return bConstant;
3281 SbxVariable*
3282 VBAConstantHelper::getVBAConstant( const OUString& rName )
3284 SbxVariable* pConst = nullptr;
3285 init();
3287 auto it = aConstHash.find( rName.toAsciiLowerCase() );
3289 if ( it != aConstHash.end() )
3291 pConst = new SbxVariable( SbxVARIANT );
3292 pConst->SetName( rName );
3293 unoToSbxValue( pConst, it->second );
3296 return pConst;
3299 // Function to search for a global identifier in the
3300 // UnoScope and to wrap it for Sbx
3301 SbUnoClass* findUnoClass( const OUString& rName )
3303 // #105550 Check if module exists
3304 SbUnoClass* pUnoClass = nullptr;
3306 const Reference< XHierarchicalNameAccess >& xTypeAccess = getTypeProvider_Impl();
3307 if( xTypeAccess->hasByHierarchicalName( rName ) )
3309 Any aRet = xTypeAccess->getByHierarchicalName( rName );
3310 Reference< XTypeDescription > xTypeDesc;
3311 aRet >>= xTypeDesc;
3313 if( xTypeDesc.is() )
3315 TypeClass eTypeClass = xTypeDesc->getTypeClass();
3316 if( eTypeClass == TypeClass_MODULE || eTypeClass == TypeClass_CONSTANTS )
3318 pUnoClass = new SbUnoClass( rName );
3322 return pUnoClass;
3325 SbxVariable* SbUnoClass::Find( const OUString& rName, SbxClassType )
3327 SbxVariable* pRes = SbxObject::Find( rName, SbxClassType::Variable );
3329 // If nothing were located the submodule isn't known yet
3330 if( !pRes )
3332 // If it is already a class, ask for the field
3333 if( m_xClass.is() )
3335 // Is it a field(?)
3336 Reference< XIdlField > xField = m_xClass->getField( rName );
3337 if( xField.is() )
3341 Any aAny = xField->get( {} ); //TODO: does this make sense?
3343 // Convert to Sbx
3344 pRes = new SbxVariable( SbxVARIANT );
3345 pRes->SetName( rName );
3346 unoToSbxValue( pRes, aAny );
3348 catch( const Exception& )
3350 implHandleAnyException( ::cppu::getCaughtException() );
3354 else
3356 // expand fully qualified name
3357 OUString aNewName = GetName()
3358 + "."
3359 + rName;
3361 // get CoreReflection
3362 Reference< XIdlReflection > xCoreReflection = getCoreReflection_Impl();
3363 if( xCoreReflection.is() )
3365 // Is it a constant?
3366 Reference< XHierarchicalNameAccess > xHarryName( xCoreReflection, UNO_QUERY );
3367 if( xHarryName.is() )
3371 Any aValue = xHarryName->getByHierarchicalName( aNewName );
3372 TypeClass eType = aValue.getValueType().getTypeClass();
3374 // Interface located? Then it is a class
3375 if( eType == TypeClass_INTERFACE )
3377 Reference< XIdlClass > xClass( aValue, UNO_QUERY );
3378 if( xClass.is() )
3380 pRes = new SbxVariable( SbxVARIANT );
3381 SbxObjectRef xWrapper = static_cast<SbxObject*>(new SbUnoClass( aNewName, xClass ));
3382 pRes->PutObject( xWrapper.get() );
3385 else
3387 pRes = new SbxVariable( SbxVARIANT );
3388 unoToSbxValue( pRes, aValue );
3391 catch( const NoSuchElementException& )
3396 // Otherwise take it again as class
3397 if( !pRes )
3399 SbUnoClass* pNewClass = findUnoClass( aNewName );
3400 if( pNewClass )
3402 pRes = new SbxVariable( SbxVARIANT );
3403 SbxObjectRef xWrapper = static_cast<SbxObject*>(pNewClass);
3404 pRes->PutObject( xWrapper.get() );
3408 // A UNO service?
3409 if( !pRes )
3411 SbUnoService* pUnoService = findUnoService( aNewName );
3412 if( pUnoService )
3414 pRes = new SbxVariable( SbxVARIANT );
3415 SbxObjectRef xWrapper = static_cast<SbxObject*>(pUnoService);
3416 pRes->PutObject( xWrapper.get() );
3420 // A UNO singleton?
3421 if( !pRes )
3423 SbUnoSingleton* pUnoSingleton = findUnoSingleton( aNewName );
3424 if( pUnoSingleton )
3426 pRes = new SbxVariable( SbxVARIANT );
3427 SbxObjectRef xWrapper = static_cast<SbxObject*>(pUnoSingleton);
3428 pRes->PutObject( xWrapper.get() );
3434 if( pRes )
3436 pRes->SetName( rName );
3438 // Insert variable, so that it could be found later
3439 QuickInsert( pRes );
3441 // Take us out as listener at once,
3442 // the values are all constant
3443 if( pRes->IsBroadcaster() )
3444 EndListening( pRes->GetBroadcaster(), true );
3447 return pRes;
3451 SbUnoService* findUnoService( const OUString& rName )
3453 SbUnoService* pSbUnoService = nullptr;
3455 const Reference< XHierarchicalNameAccess >& xTypeAccess = getTypeProvider_Impl();
3456 if( xTypeAccess->hasByHierarchicalName( rName ) )
3458 Any aRet = xTypeAccess->getByHierarchicalName( rName );
3459 Reference< XTypeDescription > xTypeDesc;
3460 aRet >>= xTypeDesc;
3462 if( xTypeDesc.is() )
3464 TypeClass eTypeClass = xTypeDesc->getTypeClass();
3465 if( eTypeClass == TypeClass_SERVICE )
3467 Reference< XServiceTypeDescription2 > xServiceTypeDesc( xTypeDesc, UNO_QUERY );
3468 if( xServiceTypeDesc.is() )
3469 pSbUnoService = new SbUnoService( rName, xServiceTypeDesc );
3473 return pSbUnoService;
3476 SbxVariable* SbUnoService::Find( const OUString& rName, SbxClassType )
3478 SbxVariable* pRes = SbxObject::Find( rName, SbxClassType::Method );
3480 if( !pRes )
3482 // If it is already a class ask for a field
3483 if( m_bNeedsInit && m_xServiceTypeDesc.is() )
3485 m_bNeedsInit = false;
3487 Sequence< Reference< XServiceConstructorDescription > > aSCDSeq = m_xServiceTypeDesc->getConstructors();
3488 const Reference< XServiceConstructorDescription >* pCtorSeq = aSCDSeq.getConstArray();
3489 int nCtorCount = aSCDSeq.getLength();
3490 for( int i = 0 ; i < nCtorCount ; ++i )
3492 Reference< XServiceConstructorDescription > xCtor = pCtorSeq[i];
3494 OUString aName( xCtor->getName() );
3495 if( aName.isEmpty() )
3497 if( xCtor->isDefaultConstructor() )
3499 aName = "create";
3503 if( !aName.isEmpty() )
3505 // Create and insert SbUnoServiceCtor
3506 SbxVariableRef xSbCtorRef = new SbUnoServiceCtor( aName, xCtor );
3507 QuickInsert( xSbCtorRef.get() );
3510 pRes = SbxObject::Find( rName, SbxClassType::Method );
3514 return pRes;
3517 void SbUnoService::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
3519 const SbxHint* pHint = dynamic_cast<const SbxHint*>(&rHint);
3520 if( pHint )
3522 SbxVariable* pVar = pHint->GetVar();
3523 SbxArray* pParams = pVar->GetParameters();
3524 SbUnoServiceCtor* pUnoCtor = dynamic_cast<SbUnoServiceCtor*>( pVar );
3525 if( pUnoCtor && pHint->GetId() == SfxHintId::BasicDataWanted )
3527 // Parameter count -1 because of Param0 == this
3528 sal_uInt32 nParamCount = pParams ? (static_cast<sal_uInt32>(pParams->Count()) - 1) : 0;
3529 Sequence<Any> args;
3531 Reference< XServiceConstructorDescription > xCtor = pUnoCtor->getServiceCtorDesc();
3532 Sequence< Reference< XParameter > > aParameterSeq = xCtor->getParameters();
3533 const Reference< XParameter >* pParameterSeq = aParameterSeq.getConstArray();
3534 sal_uInt32 nUnoParamCount = aParameterSeq.getLength();
3536 // Default: Ignore not needed parameters
3537 bool bParameterError = false;
3539 // Is the last parameter a rest parameter?
3540 bool bRestParameterMode = false;
3541 if( nUnoParamCount > 0 )
3543 Reference< XParameter > xLastParam = pParameterSeq[ nUnoParamCount - 1 ];
3544 if( xLastParam.is() )
3546 if( xLastParam->isRestParameter() )
3547 bRestParameterMode = true;
3551 // Too many parameters with context as first parameter?
3552 sal_uInt16 nSbxParameterOffset = 1;
3553 sal_uInt16 nParameterOffsetByContext = 0;
3554 Reference < XComponentContext > xFirstParamContext;
3555 if( nParamCount > nUnoParamCount )
3557 // Check if first parameter is a context and use it
3558 // then in createInstanceWithArgumentsAndContext
3559 Any aArg0 = sbxToUnoValue( pParams->Get( nSbxParameterOffset ) );
3560 if( (aArg0 >>= xFirstParamContext) && xFirstParamContext.is() )
3561 nParameterOffsetByContext = 1;
3564 sal_uInt32 nEffectiveParamCount = nParamCount - nParameterOffsetByContext;
3565 sal_uInt32 nAllocParamCount = nEffectiveParamCount;
3566 if( nEffectiveParamCount > nUnoParamCount )
3568 if( !bRestParameterMode )
3570 nEffectiveParamCount = nUnoParamCount;
3571 nAllocParamCount = nUnoParamCount;
3574 // Not enough parameters?
3575 else if( nUnoParamCount > nEffectiveParamCount )
3577 // RestParameterMode only helps if one (the last) parameter is missing
3578 int nDiff = nUnoParamCount - nEffectiveParamCount;
3579 if( !bRestParameterMode || nDiff > 1 )
3581 bParameterError = true;
3582 StarBASIC::Error( ERRCODE_BASIC_NOT_OPTIONAL );
3586 if( !bParameterError )
3588 bool bOutParams = false;
3589 if( nAllocParamCount > 0 )
3591 args.realloc( nAllocParamCount );
3592 Any* pAnyArgs = args.getArray();
3593 for( sal_uInt32 i = 0 ; i < nEffectiveParamCount ; i++ )
3595 sal_uInt16 iSbx = static_cast<sal_uInt16>(i + nSbxParameterOffset + nParameterOffsetByContext);
3597 // bRestParameterMode allows nEffectiveParamCount > nUnoParamCount
3598 Reference< XParameter > xParam;
3599 if( i < nUnoParamCount )
3601 xParam = pParameterSeq[i];
3602 if( !xParam.is() )
3603 continue;
3605 Reference< XTypeDescription > xParamTypeDesc = xParam->getType();
3606 if( !xParamTypeDesc.is() )
3607 continue;
3608 css::uno::Type aType( xParamTypeDesc->getTypeClass(), xParamTypeDesc->getName() );
3610 // sbx parameter needs offset 1
3611 pAnyArgs[i] = sbxToUnoValue( pParams->Get( iSbx ), aType );
3613 // Check for out parameter if not already done
3614 if( !bOutParams && xParam->isOut() )
3615 bOutParams = true;
3617 else
3619 pAnyArgs[i] = sbxToUnoValue( pParams->Get( iSbx ) );
3624 // "Call" ctor using createInstanceWithArgumentsAndContext
3625 Reference < XComponentContext > xContext(
3626 xFirstParamContext.is()
3627 ? xFirstParamContext
3628 : comphelper::getProcessComponentContext() );
3629 Reference< XMultiComponentFactory > xServiceMgr( xContext->getServiceManager() );
3631 Any aRetAny;
3632 OUString aServiceName = GetName();
3633 Reference < XInterface > xRet;
3636 xRet = xServiceMgr->createInstanceWithArgumentsAndContext( aServiceName, args, xContext );
3638 catch( const Exception& )
3640 implHandleAnyException( ::cppu::getCaughtException() );
3642 aRetAny <<= xRet;
3643 unoToSbxValue( pVar, aRetAny );
3645 // Copy back out parameters?
3646 if( bOutParams )
3648 const Any* pAnyArgs = args.getConstArray();
3650 for( sal_uInt32 j = 0 ; j < nUnoParamCount ; j++ )
3652 Reference< XParameter > xParam = pParameterSeq[j];
3653 if( !xParam.is() )
3654 continue;
3656 if( xParam->isOut() )
3657 unoToSbxValue( pParams->Get( static_cast<sal_uInt16>(j+1) ), pAnyArgs[ j ] );
3662 else
3663 SbxObject::Notify( rBC, rHint );
3668 SbUnoServiceCtor::SbUnoServiceCtor( const OUString& aName_, Reference< XServiceConstructorDescription > const & xServiceCtorDesc )
3669 : SbxMethod( aName_, SbxOBJECT )
3670 , m_xServiceCtorDesc( xServiceCtorDesc )
3674 SbUnoServiceCtor::~SbUnoServiceCtor()
3678 SbxInfo* SbUnoServiceCtor::GetInfo()
3680 SbxInfo* pRet = nullptr;
3682 return pRet;
3686 SbUnoSingleton* findUnoSingleton( const OUString& rName )
3688 SbUnoSingleton* pSbUnoSingleton = nullptr;
3690 const Reference< XHierarchicalNameAccess >& xTypeAccess = getTypeProvider_Impl();
3691 if( xTypeAccess->hasByHierarchicalName( rName ) )
3693 Any aRet = xTypeAccess->getByHierarchicalName( rName );
3694 Reference< XTypeDescription > xTypeDesc;
3695 aRet >>= xTypeDesc;
3697 if( xTypeDesc.is() )
3699 TypeClass eTypeClass = xTypeDesc->getTypeClass();
3700 if( eTypeClass == TypeClass_SINGLETON )
3702 Reference< XSingletonTypeDescription > xSingletonTypeDesc( xTypeDesc, UNO_QUERY );
3703 if( xSingletonTypeDesc.is() )
3704 pSbUnoSingleton = new SbUnoSingleton( rName );
3708 return pSbUnoSingleton;
3711 SbUnoSingleton::SbUnoSingleton( const OUString& aName_ )
3712 : SbxObject( aName_ )
3714 SbxVariableRef xGetMethodRef = new SbxMethod( "get", SbxOBJECT );
3715 QuickInsert( xGetMethodRef.get() );
3718 void SbUnoSingleton::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
3720 const SbxHint* pHint = dynamic_cast<const SbxHint*>(&rHint);
3721 if( pHint )
3723 SbxVariable* pVar = pHint->GetVar();
3724 SbxArray* pParams = pVar->GetParameters();
3725 sal_uInt32 nParamCount = pParams ? (static_cast<sal_uInt32>(pParams->Count()) - 1) : 0;
3726 sal_uInt32 nAllowedParamCount = 1;
3728 Reference < XComponentContext > xContextToUse;
3729 if( nParamCount > 0 )
3731 // Check if first parameter is a context and use it then
3732 Reference < XComponentContext > xFirstParamContext;
3733 Any aArg1 = sbxToUnoValue( pParams->Get( 1 ) );
3734 if( (aArg1 >>= xFirstParamContext) && xFirstParamContext.is() )
3735 xContextToUse = xFirstParamContext;
3738 if( !xContextToUse.is() )
3740 xContextToUse = comphelper::getProcessComponentContext();
3741 --nAllowedParamCount;
3744 if( nParamCount > nAllowedParamCount )
3746 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
3747 return;
3750 Any aRetAny;
3751 if( xContextToUse.is() )
3753 OUString aSingletonName = "/singletons/"
3754 + GetName();
3755 Reference < XInterface > xRet;
3756 xContextToUse->getValueByName( aSingletonName ) >>= xRet;
3757 aRetAny <<= xRet;
3759 unoToSbxValue( pVar, aRetAny );
3761 else
3763 SbxObject::Notify( rBC, rHint );
3768 // Implementation of an EventAttacher-drawn AllListener, which
3769 // solely transmits several events to a general AllListener
3770 class BasicAllListener_Impl : public WeakImplHelper< XAllListener >
3772 void firing_impl(const AllEventObject& Event, Any* pRet);
3774 public:
3775 SbxObjectRef xSbxObj;
3776 OUString aPrefixName;
3778 explicit BasicAllListener_Impl( const OUString& aPrefixName );
3780 // Methods of XAllListener
3781 virtual void SAL_CALL firing(const AllEventObject& Event) override;
3782 virtual Any SAL_CALL approveFiring(const AllEventObject& Event) override;
3784 // Methods of XEventListener
3785 virtual void SAL_CALL disposing(const EventObject& Source) override;
3789 BasicAllListener_Impl::BasicAllListener_Impl(const OUString& aPrefixName_)
3790 : aPrefixName( aPrefixName_ )
3794 void BasicAllListener_Impl::firing_impl( const AllEventObject& Event, Any* pRet )
3796 SolarMutexGuard guard;
3798 if( xSbxObj.is() )
3800 OUString aMethodName = aPrefixName + Event.MethodName;
3802 SbxVariable * pP = xSbxObj.get();
3803 while( pP->GetParent() )
3805 pP = pP->GetParent();
3806 StarBASIC * pLib = dynamic_cast<StarBASIC*>( pP );
3807 if( pLib )
3809 // Create in a Basic Array
3810 SbxArrayRef xSbxArray = new SbxArray( SbxVARIANT );
3811 const Any * pArgs = Event.Arguments.getConstArray();
3812 sal_Int32 nCount = Event.Arguments.getLength();
3813 for( sal_Int32 i = 0; i < nCount; i++ )
3815 // Convert elements
3816 SbxVariableRef xVar = new SbxVariable( SbxVARIANT );
3817 unoToSbxValue( xVar.get(), pArgs[i] );
3818 xSbxArray->Put( xVar.get(), sal::static_int_cast< sal_uInt16 >(i+1) );
3821 pLib->Call( aMethodName, xSbxArray.get() );
3823 // get the return value from the Param-Array, if requested
3824 if( pRet )
3826 SbxVariable* pVar = xSbxArray->Get( 0 );
3827 if( pVar )
3829 // #95792 Avoid a second call
3830 SbxFlagBits nFlags = pVar->GetFlags();
3831 pVar->SetFlag( SbxFlagBits::NoBroadcast );
3832 *pRet = sbxToUnoValueImpl( pVar );
3833 pVar->SetFlags( nFlags );
3836 break;
3843 // Methods of Listener
3844 void BasicAllListener_Impl::firing( const AllEventObject& Event )
3846 firing_impl( Event, nullptr );
3849 Any BasicAllListener_Impl::approveFiring( const AllEventObject& Event )
3851 Any aRetAny;
3852 firing_impl( Event, &aRetAny );
3853 return aRetAny;
3857 // Methods of XEventListener
3858 void BasicAllListener_Impl ::disposing(const EventObject& )
3860 SolarMutexGuard guard;
3862 xSbxObj.clear();
3866 // class InvocationToAllListenerMapper
3867 // helper class to map XInvocation to XAllListener (also in project eventattacher!)
3869 class InvocationToAllListenerMapper : public WeakImplHelper< XInvocation >
3871 public:
3872 InvocationToAllListenerMapper( const Reference< XIdlClass >& ListenerType,
3873 const Reference< XAllListener >& AllListener, const Any& Helper );
3875 // XInvocation
3876 virtual Reference< XIntrospectionAccess > SAL_CALL getIntrospection() override;
3877 virtual Any SAL_CALL invoke(const OUString& FunctionName, const Sequence< Any >& Params, Sequence< sal_Int16 >& OutParamIndex, Sequence< Any >& OutParam) override;
3878 virtual void SAL_CALL setValue(const OUString& PropertyName, const Any& Value) override;
3879 virtual Any SAL_CALL getValue(const OUString& PropertyName) override;
3880 virtual sal_Bool SAL_CALL hasMethod(const OUString& Name) override;
3881 virtual sal_Bool SAL_CALL hasProperty(const OUString& Name) override;
3883 private:
3884 Reference< XAllListener > m_xAllListener;
3885 Reference< XIdlClass > m_xListenerType;
3886 Any m_Helper;
3890 // Function to replace AllListenerAdapterService::createAllListerAdapter
3891 static Reference< XInterface > createAllListenerAdapter
3893 const Reference< XInvocationAdapterFactory2 >& xInvocationAdapterFactory,
3894 const Reference< XIdlClass >& xListenerType,
3895 const Reference< XAllListener >& xListener,
3896 const Any& Helper
3899 Reference< XInterface > xAdapter;
3900 if( xInvocationAdapterFactory.is() && xListenerType.is() && xListener.is() )
3902 Reference< XInvocation > xInvocationToAllListenerMapper =
3903 new InvocationToAllListenerMapper(xListenerType, xListener, Helper);
3904 Type aListenerType( xListenerType->getTypeClass(), xListenerType->getName() );
3905 Sequence<Type> arg2(1);
3906 arg2[0] = aListenerType;
3907 xAdapter = xInvocationAdapterFactory->createAdapter( xInvocationToAllListenerMapper, arg2 );
3909 return xAdapter;
3913 // InvocationToAllListenerMapper
3914 InvocationToAllListenerMapper::InvocationToAllListenerMapper
3915 ( const Reference< XIdlClass >& ListenerType, const Reference< XAllListener >& AllListener, const Any& Helper )
3916 : m_xAllListener( AllListener )
3917 , m_xListenerType( ListenerType )
3918 , m_Helper( Helper )
3923 Reference< XIntrospectionAccess > SAL_CALL InvocationToAllListenerMapper::getIntrospection()
3925 return Reference< XIntrospectionAccess >();
3929 Any SAL_CALL InvocationToAllListenerMapper::invoke(const OUString& FunctionName, const Sequence< Any >& Params,
3930 Sequence< sal_Int16 >&, Sequence< Any >&)
3932 Any aRet;
3934 // Check if to firing or approveFiring has to be called
3935 Reference< XIdlMethod > xMethod = m_xListenerType->getMethod( FunctionName );
3936 bool bApproveFiring = false;
3937 if( !xMethod.is() )
3938 return aRet;
3939 Reference< XIdlClass > xReturnType = xMethod->getReturnType();
3940 Sequence< Reference< XIdlClass > > aExceptionSeq = xMethod->getExceptionTypes();
3941 if( ( xReturnType.is() && xReturnType->getTypeClass() != TypeClass_VOID ) ||
3942 aExceptionSeq.hasElements() )
3944 bApproveFiring = true;
3946 else
3948 Sequence< ParamInfo > aParamSeq = xMethod->getParameterInfos();
3949 sal_uInt32 nParamCount = aParamSeq.getLength();
3950 if( nParamCount > 1 )
3952 const ParamInfo* pInfo = aParamSeq.getConstArray();
3953 for( sal_uInt32 i = 0 ; i < nParamCount ; i++ )
3955 if( pInfo[ i ].aMode != ParamMode_IN )
3957 bApproveFiring = true;
3958 break;
3964 AllEventObject aAllEvent;
3965 aAllEvent.Source = static_cast<OWeakObject*>(this);
3966 aAllEvent.Helper = m_Helper;
3967 aAllEvent.ListenerType = Type(m_xListenerType->getTypeClass(), m_xListenerType->getName() );
3968 aAllEvent.MethodName = FunctionName;
3969 aAllEvent.Arguments = Params;
3970 if( bApproveFiring )
3971 aRet = m_xAllListener->approveFiring( aAllEvent );
3972 else
3973 m_xAllListener->firing( aAllEvent );
3974 return aRet;
3978 void SAL_CALL InvocationToAllListenerMapper::setValue(const OUString&, const Any&)
3982 Any SAL_CALL InvocationToAllListenerMapper::getValue(const OUString&)
3984 return Any();
3988 sal_Bool SAL_CALL InvocationToAllListenerMapper::hasMethod(const OUString& Name)
3990 Reference< XIdlMethod > xMethod = m_xListenerType->getMethod( Name );
3991 return xMethod.is();
3995 sal_Bool SAL_CALL InvocationToAllListenerMapper::hasProperty(const OUString& Name)
3997 Reference< XIdlField > xField = m_xListenerType->getField( Name );
3998 return xField.is();
4002 // create Uno-Service
4003 // 1. Parameter == Prefix-Name of the macro
4004 // 2. Parameter == fully qualified name of the listener
4005 void SbRtl_CreateUnoListener(StarBASIC * pBasic, SbxArray & rPar, bool)
4007 // We need 2 parameters
4008 if ( rPar.Count() != 3 )
4010 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
4011 return;
4014 // get the name of the class of the struct
4015 OUString aPrefixName = rPar.Get(1)->GetOUString();
4016 OUString aListenerClassName = rPar.Get(2)->GetOUString();
4018 // get the CoreReflection
4019 Reference< XIdlReflection > xCoreReflection = getCoreReflection_Impl();
4020 if( !xCoreReflection.is() )
4021 return;
4023 // get the AllListenerAdapterService
4024 Reference< XComponentContext > xContext( comphelper::getProcessComponentContext() );
4026 // search the class
4027 Reference< XIdlClass > xClass = xCoreReflection->forName( aListenerClassName );
4028 if( !xClass.is() )
4029 return;
4031 // From 1999-11-30: get the InvocationAdapterFactory
4032 Reference< XInvocationAdapterFactory2 > xInvocationAdapterFactory =
4033 InvocationAdapterFactory::create( xContext );
4035 BasicAllListener_Impl * p;
4036 Reference< XAllListener > xAllLst = p = new BasicAllListener_Impl( aPrefixName );
4037 Any aTmp;
4038 Reference< XInterface > xLst = createAllListenerAdapter( xInvocationAdapterFactory, xClass, xAllLst, aTmp );
4039 if( !xLst.is() )
4040 return;
4042 OUString aClassName = xClass->getName();
4043 Type aClassType( xClass->getTypeClass(), aClassName );
4044 aTmp = xLst->queryInterface( aClassType );
4045 if( !aTmp.hasValue() )
4046 return;
4048 SbUnoObject* pUnoObj = new SbUnoObject( aListenerClassName, aTmp );
4049 p->xSbxObj = pUnoObj;
4050 p->xSbxObj->SetParent( pBasic );
4052 // #100326 Register listener object to set Parent NULL in Dtor
4053 SbxArrayRef xBasicUnoListeners = pBasic->getUnoListeners();
4054 xBasicUnoListeners->Insert( pUnoObj, xBasicUnoListeners->Count() );
4056 // return the object
4057 SbxVariableRef refVar = rPar.Get(0);
4058 refVar->PutObject( p->xSbxObj.get() );
4062 // Represents the DefaultContext property of the ProcessServiceManager
4063 // in the Basic runtime system.
4064 void RTL_Impl_GetDefaultContext( SbxArray& rPar )
4066 SbxVariableRef refVar = rPar.Get(0);
4068 Any aContextAny( comphelper::getProcessComponentContext() );
4070 SbUnoObjectRef xUnoObj = new SbUnoObject( "DefaultContext", aContextAny );
4071 refVar->PutObject( xUnoObj.get() );
4075 // Creates a Basic wrapper object for a strongly typed Uno value
4076 // 1. parameter: Uno type as full qualified type name, e.g. "byte[]"
4077 void RTL_Impl_CreateUnoValue( SbxArray& rPar )
4079 // 2 parameters needed
4080 if ( rPar.Count() != 3 )
4082 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
4083 return;
4086 // get the name of the class of the struct
4087 OUString aTypeName = rPar.Get(1)->GetOUString();
4088 SbxVariable* pVal = rPar.Get(2);
4090 if( aTypeName == "type" )
4092 SbxDataType eBaseType = pVal->SbxValue::GetType();
4093 OUString aValTypeName;
4094 if( eBaseType == SbxSTRING )
4096 aValTypeName = pVal->GetOUString();
4098 else if( eBaseType == SbxOBJECT )
4100 // XIdlClass?
4101 Reference< XIdlClass > xIdlClass;
4103 SbxBaseRef pObj = pVal->GetObject();
4104 if( auto obj = dynamic_cast<SbUnoObject*>( pObj.get() ) )
4106 Any aUnoAny = obj->getUnoAny();
4107 aUnoAny >>= xIdlClass;
4110 if( xIdlClass.is() )
4112 aValTypeName = xIdlClass->getName();
4115 Type aType;
4116 bool bSuccess = implGetTypeByName( aValTypeName, aType );
4117 if( bSuccess )
4119 Any aTypeAny( aType );
4120 SbxVariableRef refVar = rPar.Get(0);
4121 SbxObjectRef xUnoAnyObject = new SbUnoAnyObject( aTypeAny );
4122 refVar->PutObject( xUnoAnyObject.get() );
4124 return;
4127 // Check the type
4128 const Reference< XHierarchicalNameAccess >& xTypeAccess = getTypeProvider_Impl();
4129 Any aRet;
4132 aRet = xTypeAccess->getByHierarchicalName( aTypeName );
4134 catch( const NoSuchElementException& e1 )
4136 StarBASIC::Error( ERRCODE_BASIC_EXCEPTION,
4137 implGetExceptionMsg( e1, "com.sun.star.container.NoSuchElementException" ) );
4138 return;
4140 Reference< XTypeDescription > xTypeDesc;
4141 aRet >>= xTypeDesc;
4142 TypeClass eTypeClass = xTypeDesc->getTypeClass();
4143 Type aDestType( eTypeClass, aTypeName );
4146 // Preconvert value
4147 Any aVal = sbxToUnoValueImpl( pVal );
4148 Any aConvertedVal = convertAny( aVal, aDestType );
4150 SbxVariableRef refVar = rPar.Get(0);
4151 SbxObjectRef xUnoAnyObject = new SbUnoAnyObject( aConvertedVal );
4152 refVar->PutObject( xUnoAnyObject.get() );
4156 class ModuleInvocationProxy : public WeakImplHelper< XInvocation, XComponent >
4158 ::osl::Mutex m_aMutex;
4159 OUString m_aPrefix;
4160 SbxObjectRef m_xScopeObj;
4161 bool m_bProxyIsClassModuleObject;
4163 ::comphelper::OInterfaceContainerHelper2 m_aListeners;
4165 public:
4166 ModuleInvocationProxy( OUString const & aPrefix, SbxObjectRef const & xScopeObj );
4168 // XInvocation
4169 virtual Reference< XIntrospectionAccess > SAL_CALL getIntrospection() override;
4170 virtual void SAL_CALL setValue( const OUString& rProperty, const Any& rValue ) override;
4171 virtual Any SAL_CALL getValue( const OUString& rProperty ) override;
4172 virtual sal_Bool SAL_CALL hasMethod( const OUString& rName ) override;
4173 virtual sal_Bool SAL_CALL hasProperty( const OUString& rProp ) override;
4175 virtual Any SAL_CALL invoke( const OUString& rFunction,
4176 const Sequence< Any >& rParams,
4177 Sequence< sal_Int16 >& rOutParamIndex,
4178 Sequence< Any >& rOutParam ) override;
4180 // XComponent
4181 virtual void SAL_CALL dispose() override;
4182 virtual void SAL_CALL addEventListener( const Reference< XEventListener >& xListener ) override;
4183 virtual void SAL_CALL removeEventListener( const Reference< XEventListener >& aListener ) override;
4186 ModuleInvocationProxy::ModuleInvocationProxy( OUString const & aPrefix, SbxObjectRef const & xScopeObj )
4187 : m_aMutex()
4188 , m_aPrefix( aPrefix + "_" )
4189 , m_xScopeObj( xScopeObj )
4190 , m_aListeners( m_aMutex )
4192 m_bProxyIsClassModuleObject = xScopeObj.is() && dynamic_cast<const SbClassModuleObject*>( xScopeObj.get() ) != nullptr;
4195 Reference< XIntrospectionAccess > SAL_CALL ModuleInvocationProxy::getIntrospection()
4197 return Reference< XIntrospectionAccess >();
4200 void SAL_CALL ModuleInvocationProxy::setValue(const OUString& rProperty, const Any& rValue)
4202 if( !m_bProxyIsClassModuleObject )
4203 throw UnknownPropertyException();
4205 SolarMutexGuard guard;
4207 OUString aPropertyFunctionName = "Property Set "
4208 + m_aPrefix
4209 + rProperty;
4211 SbxVariable* p = m_xScopeObj->Find( aPropertyFunctionName, SbxClassType::Method );
4212 SbMethod* pMeth = dynamic_cast<SbMethod*>( p );
4213 if( pMeth == nullptr )
4215 // TODO: Check vba behavior concerning missing function
4216 //StarBASIC::Error( ERRCODE_BASIC_NO_METHOD, aFunctionName );
4217 throw UnknownPropertyException(aPropertyFunctionName);
4220 // Setup parameter
4221 SbxArrayRef xArray = new SbxArray;
4222 SbxVariableRef xVar = new SbxVariable( SbxVARIANT );
4223 unoToSbxValue( xVar.get(), rValue );
4224 xArray->Put( xVar.get(), 1 );
4226 // Call property method
4227 SbxVariableRef xValue = new SbxVariable;
4228 pMeth->SetParameters( xArray.get() );
4229 pMeth->Call( xValue.get() );
4230 pMeth->SetParameters( nullptr );
4232 // TODO: OutParameter?
4237 Any SAL_CALL ModuleInvocationProxy::getValue(const OUString& rProperty)
4239 if( !m_bProxyIsClassModuleObject )
4241 throw UnknownPropertyException();
4243 SolarMutexGuard guard;
4245 OUString aPropertyFunctionName = "Property Get "
4246 + m_aPrefix
4247 + rProperty;
4249 SbxVariable* p = m_xScopeObj->Find( aPropertyFunctionName, SbxClassType::Method );
4250 SbMethod* pMeth = dynamic_cast<SbMethod*>( p );
4251 if( pMeth == nullptr )
4253 // TODO: Check vba behavior concerning missing function
4254 //StarBASIC::Error( ERRCODE_BASIC_NO_METHOD, aFunctionName );
4255 throw UnknownPropertyException(aPropertyFunctionName);
4258 // Call method
4259 SbxVariableRef xValue = new SbxVariable;
4260 pMeth->Call( xValue.get() );
4261 Any aRet = sbxToUnoValue( xValue.get() );
4262 return aRet;
4265 sal_Bool SAL_CALL ModuleInvocationProxy::hasMethod( const OUString& )
4267 return false;
4270 sal_Bool SAL_CALL ModuleInvocationProxy::hasProperty( const OUString& )
4272 return false;
4275 Any SAL_CALL ModuleInvocationProxy::invoke( const OUString& rFunction,
4276 const Sequence< Any >& rParams,
4277 Sequence< sal_Int16 >&,
4278 Sequence< Any >& )
4280 SolarMutexGuard guard;
4282 Any aRet;
4283 SbxObjectRef xScopeObj = m_xScopeObj;
4284 if( !xScopeObj.is() )
4286 return aRet;
4288 OUString aFunctionName = m_aPrefix
4289 + rFunction;
4291 bool bSetRescheduleBack = false;
4292 bool bOldReschedule = true;
4293 SbiInstance* pInst = GetSbData()->pInst;
4294 if( pInst && pInst->IsCompatibility() )
4296 bOldReschedule = pInst->IsReschedule();
4297 if ( bOldReschedule )
4299 pInst->EnableReschedule( false );
4300 bSetRescheduleBack = true;
4304 SbxVariable* p = xScopeObj->Find( aFunctionName, SbxClassType::Method );
4305 SbMethod* pMeth = dynamic_cast<SbMethod*>( p );
4306 if( pMeth == nullptr )
4308 // TODO: Check vba behavior concerning missing function
4309 //StarBASIC::Error( ERRCODE_BASIC_NO_METHOD, aFunctionName );
4310 return aRet;
4313 // Setup parameters
4314 SbxArrayRef xArray;
4315 sal_Int32 nParamCount = rParams.getLength();
4316 if( nParamCount )
4318 xArray = new SbxArray;
4319 const Any *pArgs = rParams.getConstArray();
4320 for( sal_Int32 i = 0 ; i < nParamCount ; i++ )
4322 SbxVariableRef xVar = new SbxVariable( SbxVARIANT );
4323 unoToSbxValue( xVar.get(), pArgs[i] );
4324 xArray->Put( xVar.get(), sal::static_int_cast< sal_uInt16 >(i+1) );
4328 // Call method
4329 SbxVariableRef xValue = new SbxVariable;
4330 if( xArray.is() )
4331 pMeth->SetParameters( xArray.get() );
4332 pMeth->Call( xValue.get() );
4333 aRet = sbxToUnoValue( xValue.get() );
4334 pMeth->SetParameters( nullptr );
4336 if( bSetRescheduleBack )
4337 pInst->EnableReschedule( bOldReschedule );
4339 // TODO: OutParameter?
4341 return aRet;
4344 void SAL_CALL ModuleInvocationProxy::dispose()
4346 ::osl::MutexGuard aGuard( m_aMutex );
4348 EventObject aEvent( static_cast<XComponent*>(this) );
4349 m_aListeners.disposeAndClear( aEvent );
4351 m_xScopeObj = nullptr;
4354 void SAL_CALL ModuleInvocationProxy::addEventListener( const Reference< XEventListener >& xListener )
4356 m_aListeners.addInterface( xListener );
4359 void SAL_CALL ModuleInvocationProxy::removeEventListener( const Reference< XEventListener >& xListener )
4361 m_aListeners.removeInterface( xListener );
4365 Reference< XInterface > createComListener( const Any& aControlAny, const OUString& aVBAType,
4366 const OUString& aPrefix, const SbxObjectRef& xScopeObj )
4368 Reference< XInterface > xRet;
4370 Reference< XComponentContext > xContext(
4371 comphelper::getProcessComponentContext() );
4372 Reference< XMultiComponentFactory > xServiceMgr( xContext->getServiceManager() );
4374 Reference< XInvocation > xProxy = new ModuleInvocationProxy( aPrefix, xScopeObj );
4376 Sequence<Any> args( 3 );
4377 args[0] = aControlAny;
4378 args[1] <<= aVBAType;
4379 args[2] <<= xProxy;
4383 xRet = xServiceMgr->createInstanceWithArgumentsAndContext(
4384 "com.sun.star.custom.UnoComListener",
4385 args, xContext );
4387 catch( const Exception& )
4389 implHandleAnyException( ::cppu::getCaughtException() );
4392 return xRet;
4395 typedef std::vector< WeakReference< XComponent > > ComponentRefVector;
4397 struct StarBasicDisposeItem
4399 StarBASIC* m_pBasic;
4400 SbxArrayRef m_pRegisteredVariables;
4401 ComponentRefVector m_vComImplementsObjects;
4403 explicit StarBasicDisposeItem( StarBASIC* pBasic )
4404 : m_pBasic( pBasic )
4405 , m_pRegisteredVariables(new SbxArray())
4410 typedef std::vector< StarBasicDisposeItem* > DisposeItemVector;
4412 static DisposeItemVector GaDisposeItemVector;
4414 static DisposeItemVector::iterator lcl_findItemForBasic( StarBASIC const * pBasic )
4416 return std::find_if(GaDisposeItemVector.begin(), GaDisposeItemVector.end(),
4417 [&pBasic](StarBasicDisposeItem* pItem) { return pItem->m_pBasic == pBasic; });
4420 static StarBasicDisposeItem* lcl_getOrCreateItemForBasic( StarBASIC* pBasic )
4422 DisposeItemVector::iterator it = lcl_findItemForBasic( pBasic );
4423 StarBasicDisposeItem* pItem = (it != GaDisposeItemVector.end()) ? *it : nullptr;
4424 if( pItem == nullptr )
4426 pItem = new StarBasicDisposeItem( pBasic );
4427 GaDisposeItemVector.push_back( pItem );
4429 return pItem;
4432 void registerComponentToBeDisposedForBasic
4433 ( const Reference< XComponent >& xComponent, StarBASIC* pBasic )
4435 StarBasicDisposeItem* pItem = lcl_getOrCreateItemForBasic( pBasic );
4436 pItem->m_vComImplementsObjects.emplace_back(xComponent );
4439 void registerComListenerVariableForBasic( SbxVariable* pVar, StarBASIC* pBasic )
4441 StarBasicDisposeItem* pItem = lcl_getOrCreateItemForBasic( pBasic );
4442 SbxArray* pArray = pItem->m_pRegisteredVariables.get();
4443 pArray->Put( pVar, pArray->Count() );
4446 void disposeComVariablesForBasic( StarBASIC const * pBasic )
4448 DisposeItemVector::iterator it = lcl_findItemForBasic( pBasic );
4449 if( it != GaDisposeItemVector.end() )
4451 StarBasicDisposeItem* pItem = *it;
4453 SbxArray* pArray = pItem->m_pRegisteredVariables.get();
4454 sal_uInt16 nCount = pArray->Count();
4455 for( sal_uInt16 i = 0 ; i < nCount ; ++i )
4457 SbxVariable* pVar = pArray->Get( i );
4458 pVar->ClearComListener();
4461 ComponentRefVector& rv = pItem->m_vComImplementsObjects;
4462 for (auto const& elem : rv)
4464 Reference< XComponent > xComponent( elem.get(), UNO_QUERY );
4465 if (xComponent.is())
4466 xComponent->dispose();
4469 delete pItem;
4470 GaDisposeItemVector.erase( it );
4475 // Handle module implements mechanism for OLE types
4476 bool SbModule::createCOMWrapperForIface( Any& o_rRetAny, SbClassModuleObject* pProxyClassModuleObject )
4478 // For now: Take first interface that allows to instantiate COM wrapper
4479 // TODO: Check if support for multiple interfaces is needed
4481 Reference< XComponentContext > xContext(
4482 comphelper::getProcessComponentContext() );
4483 Reference< XMultiComponentFactory > xServiceMgr( xContext->getServiceManager() );
4484 Reference< XSingleServiceFactory > xComImplementsFactory
4486 xServiceMgr->createInstanceWithContext( "com.sun.star.custom.ComImplementsFactory", xContext ),
4487 UNO_QUERY
4489 if( !xComImplementsFactory.is() )
4490 return false;
4492 bool bSuccess = false;
4494 SbxArray* pModIfaces = pClassData->mxIfaces.get();
4495 sal_uInt16 nCount = pModIfaces->Count();
4496 for( sal_uInt16 i = 0 ; i < nCount ; ++i )
4498 SbxVariable* pVar = pModIfaces->Get( i );
4499 const OUString& aIfaceName = pVar->GetName();
4501 if( !aIfaceName.isEmpty() )
4503 OUString aPureIfaceName = aIfaceName;
4504 sal_Int32 indexLastDot = aIfaceName.lastIndexOf('.');
4505 if ( indexLastDot > -1 )
4507 aPureIfaceName = aIfaceName.copy( indexLastDot + 1 );
4509 Reference< XInvocation > xProxy = new ModuleInvocationProxy( aPureIfaceName, pProxyClassModuleObject );
4511 Sequence<Any> args( 2 );
4512 args[0] <<= aIfaceName;
4513 args[1] <<= xProxy;
4515 Reference< XInterface > xRet;
4518 xRet = xComImplementsFactory->createInstanceWithArguments( args );
4519 bSuccess = true;
4521 catch( const Exception& )
4523 implHandleAnyException( ::cppu::getCaughtException() );
4526 if( bSuccess )
4528 Reference< XComponent > xComponent( xProxy, UNO_QUERY );
4529 if( xComponent.is() )
4531 StarBASIC* pParentBasic = nullptr;
4532 SbxObject* pCurObject = this;
4535 SbxObject* pObjParent = pCurObject->GetParent();
4536 pParentBasic = dynamic_cast<StarBASIC*>( pObjParent );
4537 pCurObject = pObjParent;
4539 while( pParentBasic == nullptr && pCurObject != nullptr );
4541 OSL_ASSERT( pParentBasic != nullptr );
4542 registerComponentToBeDisposedForBasic( xComponent, pParentBasic );
4545 o_rRetAny <<= xRet;
4546 break;
4551 return bSuccess;
4555 // Due to an incorrect behavior IE returns an object instead of a string
4556 // in some scenarios. Calling toString at the object may correct this.
4557 // Helper function used in sbxvalue.cxx
4558 bool handleToStringForCOMObjects( SbxObject* pObj, SbxValue* pVal )
4560 bool bSuccess = false;
4562 if( auto pUnoObj = dynamic_cast<SbUnoObject*>( pObj) )
4564 // Only for native COM objects
4565 if( pUnoObj->isNativeCOMObject() )
4567 SbxVariableRef pMeth = pObj->Find( "toString", SbxClassType::Method );
4568 if ( pMeth.is() )
4570 SbxValues aRes;
4571 pMeth->Get( aRes );
4572 pVal->Put( aRes );
4573 bSuccess = true;
4577 return bSuccess;
4580 Any StructRefInfo::getValue()
4582 Any aRet;
4583 uno_any_destruct(
4584 &aRet, reinterpret_cast< uno_ReleaseFunc >(cpp_release) );
4585 typelib_TypeDescription * pTD = nullptr;
4586 maType.getDescription(&pTD);
4587 uno_any_construct(
4588 &aRet, getInst(), pTD,
4589 reinterpret_cast< uno_AcquireFunc >(cpp_acquire) );
4590 typelib_typedescription_release(pTD);
4591 return aRet;
4594 void StructRefInfo::setValue( const Any& rValue )
4596 bool bSuccess = uno_type_assignData( getInst(),
4597 maType.getTypeLibType(),
4598 const_cast<void*>(rValue.getValue()),
4599 rValue.getValueTypeRef(),
4600 reinterpret_cast< uno_QueryInterfaceFunc >(cpp_queryInterface),
4601 reinterpret_cast< uno_AcquireFunc >(cpp_acquire),
4602 reinterpret_cast< uno_ReleaseFunc >(cpp_release) );
4603 OSL_ENSURE(bSuccess,
4604 "StructRefInfo::setValue: ooops... the value could not be assigned!");
4607 OUString StructRefInfo::getTypeName() const
4609 return maType.getTypeName();
4612 void* StructRefInfo::getInst()
4614 return const_cast<char *>(static_cast<char const *>(maAny.getValue()) + mnPos);
4617 TypeClass StructRefInfo::getTypeClass() const
4619 return maType.getTypeClass();
4622 SbUnoStructRefObject::SbUnoStructRefObject( const OUString& aName_, const StructRefInfo& rMemberInfo ) : SbxObject( aName_ ), maMemberInfo( rMemberInfo ), mbMemberCacheInit( false )
4624 SetClassName( maMemberInfo.getTypeName() );
4627 SbUnoStructRefObject::~SbUnoStructRefObject()
4631 void SbUnoStructRefObject::initMemberCache()
4633 if ( mbMemberCacheInit )
4634 return;
4635 typelib_TypeDescription * pTD = nullptr;
4636 maMemberInfo.getType().getDescription(&pTD);
4637 typelib_CompoundTypeDescription * pCompTypeDescr = reinterpret_cast<typelib_CompoundTypeDescription *>(pTD);
4638 for ( pCompTypeDescr = reinterpret_cast<typelib_CompoundTypeDescription *>(pTD); pCompTypeDescr;
4639 pCompTypeDescr = pCompTypeDescr->pBaseTypeDescription )
4641 typelib_TypeDescriptionReference ** ppTypeRefs = pCompTypeDescr->ppTypeRefs;
4642 rtl_uString ** ppNames = pCompTypeDescr->ppMemberNames;
4643 sal_Int32 * pMemberOffsets = pCompTypeDescr->pMemberOffsets;
4644 for ( sal_Int32 nPos = pCompTypeDescr->nMembers; nPos--; )
4646 OUString aName( ppNames[nPos] );
4647 maFields[ aName ] = std::make_unique<StructRefInfo>( maMemberInfo.getRootAnyRef(), ppTypeRefs[nPos], maMemberInfo.getPos() + pMemberOffsets[nPos] );
4650 typelib_typedescription_release(pTD);
4651 mbMemberCacheInit = true;
4654 SbxVariable* SbUnoStructRefObject::Find( const OUString& rName, SbxClassType t )
4656 SbxVariable* pRes = SbxObject::Find( rName, t );
4657 if ( !pRes )
4659 if ( !mbMemberCacheInit )
4660 initMemberCache();
4661 StructFieldInfo::iterator it = maFields.find( rName );
4662 if ( it != maFields.end() )
4664 SbxDataType eSbxType;
4665 eSbxType = unoToSbxType( it->second->getTypeClass() );
4666 SbxDataType eRealSbxType = eSbxType;
4667 Property aProp;
4668 aProp.Name = rName;
4669 aProp.Type = css::uno::Type( it->second->getTypeClass(), it->second->getTypeName() );
4670 SbUnoProperty* pProp = new SbUnoProperty( rName, eSbxType, eRealSbxType, aProp, 0, false, ( aProp.Type.getTypeClass() == css::uno::TypeClass_STRUCT) );
4671 SbxVariableRef xVarRef = pProp;
4672 QuickInsert( xVarRef.get() );
4673 pRes = xVarRef.get();
4677 if( !pRes )
4679 if( rName.equalsIgnoreAsciiCase(ID_DBG_SUPPORTEDINTERFACES) ||
4680 rName.equalsIgnoreAsciiCase(ID_DBG_PROPERTIES) ||
4681 rName.equalsIgnoreAsciiCase(ID_DBG_METHODS) )
4683 // Create
4684 implCreateDbgProperties();
4686 // Now they have to be found regular
4687 pRes = SbxObject::Find( rName, SbxClassType::DontCare );
4691 return pRes;
4694 // help method to create the dbg_-Properties
4695 void SbUnoStructRefObject::implCreateDbgProperties()
4697 Property aProp;
4699 // Id == -1: display the implemented interfaces corresponding the ClassProvider
4700 SbxVariableRef xVarRef = new SbUnoProperty( ID_DBG_SUPPORTEDINTERFACES, SbxSTRING, SbxSTRING, aProp, -1, false, false );
4701 QuickInsert( xVarRef.get() );
4703 // Id == -2: output the properties
4704 xVarRef = new SbUnoProperty( ID_DBG_PROPERTIES, SbxSTRING, SbxSTRING, aProp, -2, false, false );
4705 QuickInsert( xVarRef.get() );
4707 // Id == -3: output the Methods
4708 xVarRef = new SbUnoProperty( ID_DBG_METHODS, SbxSTRING, SbxSTRING, aProp, -3, false, false );
4709 QuickInsert( xVarRef.get() );
4712 void SbUnoStructRefObject::implCreateAll()
4714 // throw away all existing methods and properties
4715 pMethods = new SbxArray;
4716 pProps = new SbxArray;
4718 if (!mbMemberCacheInit)
4719 initMemberCache();
4721 for (auto const& field : maFields)
4723 const OUString& rName = field.first;
4724 SbxDataType eSbxType;
4725 eSbxType = unoToSbxType( field.second->getTypeClass() );
4726 SbxDataType eRealSbxType = eSbxType;
4727 Property aProp;
4728 aProp.Name = rName;
4729 aProp.Type = css::uno::Type( field.second->getTypeClass(), field.second->getTypeName() );
4730 SbUnoProperty* pProp = new SbUnoProperty( rName, eSbxType, eRealSbxType, aProp, 0, false, ( aProp.Type.getTypeClass() == css::uno::TypeClass_STRUCT) );
4731 SbxVariableRef xVarRef = pProp;
4732 QuickInsert( xVarRef.get() );
4735 // Create Dbg_-Properties
4736 implCreateDbgProperties();
4739 // output the value
4740 Any SbUnoStructRefObject::getUnoAny()
4742 return maMemberInfo.getValue();
4745 OUString SbUnoStructRefObject::Impl_DumpProperties()
4747 OUStringBuffer aRet;
4748 aRet.append("Properties of object ");
4749 aRet.append( getDbgObjectName() );
4751 sal_uInt16 nPropCount = pProps->Count();
4752 sal_uInt16 nPropsPerLine = 1 + nPropCount / 30;
4753 for( sal_uInt16 i = 0; i < nPropCount; i++ )
4755 SbxVariable* pVar = pProps->Get( i );
4756 if( pVar )
4758 OUStringBuffer aPropStr;
4759 if( (i % nPropsPerLine) == 0 )
4761 aPropStr.append( "\n" );
4763 // output the type and name
4764 // Is it in Uno a sequence?
4765 SbxDataType eType = pVar->GetFullType();
4767 const OUString& aName( pVar->GetName() );
4768 StructFieldInfo::iterator it = maFields.find( aName );
4770 if ( it != maFields.end() )
4772 const StructRefInfo& rPropInfo = *it->second;
4774 if( eType == SbxOBJECT )
4776 if( rPropInfo.getTypeClass() == TypeClass_SEQUENCE )
4778 eType = SbxDataType( SbxOBJECT | SbxARRAY );
4782 aPropStr.append( Dbg_SbxDataType2String( eType ) );
4784 aPropStr.append( " " );
4785 aPropStr.append( pVar->GetName() );
4787 if( i == nPropCount - 1 )
4789 aPropStr.append( "\n" );
4791 else
4793 aPropStr.append( "; " );
4795 aRet.append( aPropStr.makeStringAndClear() );
4798 return aRet.makeStringAndClear();
4801 void SbUnoStructRefObject::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
4803 if ( !mbMemberCacheInit )
4804 initMemberCache();
4805 const SbxHint* pHint = dynamic_cast<const SbxHint*>(&rHint);
4806 if( pHint )
4808 SbxVariable* pVar = pHint->GetVar();
4809 SbUnoProperty* pProp = dynamic_cast<SbUnoProperty*>( pVar );
4810 if( pProp )
4812 StructFieldInfo::iterator it = maFields.find( pProp->GetName() );
4813 // handle get/set of members of struct
4814 if( pHint->GetId() == SfxHintId::BasicDataWanted )
4816 // Test-Properties
4817 sal_Int32 nId = pProp->nId;
4818 if( nId < 0 )
4820 // Id == -1: Display implemented interfaces according the ClassProvider
4821 if( nId == -1 ) // Property ID_DBG_SUPPORTEDINTERFACES"
4823 OUString aRet = OUStringLiteral( ID_DBG_SUPPORTEDINTERFACES )
4824 + " not available.\n(TypeClass is not TypeClass_INTERFACE)\n";
4826 pVar->PutString( aRet );
4828 // Id == -2: output properties
4829 else if( nId == -2 ) // Property ID_DBG_PROPERTIES
4831 // by now all properties must be established
4832 implCreateAll();
4833 OUString aRetStr = Impl_DumpProperties();
4834 pVar->PutString( aRetStr );
4836 // Id == -3: output the methods
4837 else if( nId == -3 ) // Property ID_DBG_METHODS
4839 // by now all properties must be established
4840 implCreateAll();
4841 OUString aRet = "Methods of object "
4842 + getDbgObjectName()
4843 + "\nNo methods found\n";
4844 pVar->PutString( aRet );
4846 return;
4849 if ( it != maFields.end() )
4851 Any aRetAny = it->second->getValue();
4852 unoToSbxValue( pVar, aRetAny );
4854 else
4855 StarBASIC::Error( ERRCODE_BASIC_PROPERTY_NOT_FOUND );
4857 else if( pHint->GetId() == SfxHintId::BasicDataChanged )
4859 if ( it != maFields.end() )
4861 // take over the value from Uno to Sbx
4862 Any aAnyValue = sbxToUnoValue( pVar, pProp->aUnoProp.Type, &pProp->aUnoProp );
4863 it->second->setValue( aAnyValue );
4865 else
4866 StarBASIC::Error( ERRCODE_BASIC_PROPERTY_NOT_FOUND );
4869 else
4870 SbxObject::Notify( rBC, rHint );
4874 StructRefInfo SbUnoStructRefObject::getStructMember( const OUString& rMemberName )
4876 if (!mbMemberCacheInit)
4878 initMemberCache();
4880 StructFieldInfo::iterator it = maFields.find( rMemberName );
4882 css::uno::Type aFoundType;
4883 sal_Int32 nFoundPos = -1;
4885 if ( it != maFields.end() )
4887 aFoundType = it->second->getType();
4888 nFoundPos = it->second->getPos();
4890 StructRefInfo aRet( maMemberInfo.getRootAnyRef(), aFoundType, nFoundPos );
4891 return aRet;
4894 OUString SbUnoStructRefObject::getDbgObjectName() const
4896 OUString aName = GetClassName();
4897 if( aName.isEmpty() )
4899 aName += "Unknown";
4901 OUStringBuffer aRet;
4902 if( aName.getLength() > 20 )
4904 aRet.append( "\n" );
4906 aRet.append( "\"" );
4907 aRet.append( aName );
4908 aRet.append( "\":" );
4909 return aRet.makeStringAndClear();
4912 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */