Bug Summary

File:home/maarten/src/libreoffice/core/basic/source/classes/sbunoobj.cxx
Warning:line 4712, column 5
Use of memory after it is freed

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name sbunoobj.cxx -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D BOOST_ERROR_CODE_HEADER_ONLY -D BOOST_SYSTEM_NO_DEPRECATED -D CPPU_ENV=gcc3 -D LINUX -D OSL_DEBUG_LEVEL=1 -D SAL_LOG_INFO -D SAL_LOG_WARN -D UNIX -D UNX -D X86_64 -D _PTHREADS -D _REENTRANT -D BASIC_DLLIMPLEMENTATION -D EXCEPTIONS_ON -D LIBO_INTERNAL_ONLY -I /home/maarten/src/libreoffice/core/external/boost/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/boost -I /home/maarten/src/libreoffice/core/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include/linux -I /home/maarten/src/libreoffice/core/config_host -I /home/maarten/src/libreoffice/core/basic/inc -I /home/maarten/src/libreoffice/core/basic/source/inc -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/officecfg/registry -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/udkapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/offapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/oovbaapi/normal -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10 -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/x86_64-redhat-linux -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/backward -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O0 -Wno-missing-braces -std=c++17 -fdeprecated-macro -fdebug-compilation-dir /home/maarten/src/libreoffice/core -ferror-limit 19 -fvisibility hidden -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -debug-info-kind=constructor -analyzer-output=html -faddrsig -o /home/maarten/tmp/wis/scan-build-libreoffice/output/report/2020-10-07-141433-9725-1 -x c++ /home/maarten/src/libreoffice/core/basic/source/classes/sbunoobj.cxx

/home/maarten/src/libreoffice/core/basic/source/classes/sbunoobj.cxx

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

/home/maarten/src/libreoffice/core/include/tools/ref.hxx

1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19#ifndef INCLUDED_TOOLS_REF_HXX
20#define INCLUDED_TOOLS_REF_HXX
21
22#include <sal/config.h>
23#include <cassert>
24#include <tools/toolsdllapi.h>
25#include <utility>
26
27/**
28 This implements similar functionality to boost::intrusive_ptr
29*/
30
31namespace tools {
32
33/** T must be a class that extends SvRefBase */
34template<typename T> class SAL_DLLPUBLIC_RTTI__attribute__ ((type_visibility("default"))) SvRef final {
35public:
36 SvRef(): pObj(nullptr) {}
37
38 SvRef(SvRef&& rObj) noexcept
39 {
40 pObj = rObj.pObj;
41 rObj.pObj = nullptr;
42 }
43
44 SvRef(SvRef const & rObj): pObj(rObj.pObj)
45 {
46 if (pObj != nullptr) pObj->AddNextRef();
47 }
48
49 SvRef(T * pObjP): pObj(pObjP)
50 {
51 if (pObj != nullptr) pObj->AddFirstRef();
52 }
53
54 ~SvRef()
55 {
56 if (pObj != nullptr) pObj->ReleaseRef();
9
Taking true branch
10
Calling 'SvRefBase::ReleaseRef'
17
Returning; memory was released
57 }
58
59 void clear()
60 {
61 if (pObj != nullptr) {
62 T * pRefObj = pObj;
63 pObj = nullptr;
64 pRefObj->ReleaseRef();
65 }
66 }
67
68 SvRef & operator =(SvRef const & rObj)
69 {
70 if (rObj.pObj != nullptr) {
71 rObj.pObj->AddNextRef();
72 }
73 T * pRefObj = pObj;
74 pObj = rObj.pObj;
75 if (pRefObj != nullptr) {
76 pRefObj->ReleaseRef();
77 }
78 return *this;
79 }
80
81 SvRef & operator =(SvRef && rObj)
82 {
83 if (pObj != nullptr) {
84 pObj->ReleaseRef();
85 }
86 pObj = rObj.pObj;
87 rObj.pObj = nullptr;
88 return *this;
89 }
90
91 bool is() const { return pObj != nullptr; }
92
93 explicit operator bool() const { return is(); }
94
95 T * get() const { return pObj; }
96
97 T * operator ->() const { assert(pObj != nullptr)(static_cast <bool> (pObj != nullptr) ? void (0) : __assert_fail
("pObj != nullptr", "/home/maarten/src/libreoffice/core/include/tools/ref.hxx"
, 97, __extension__ __PRETTY_FUNCTION__))
; return pObj; }
98
99 T & operator *() const { assert(pObj != nullptr)(static_cast <bool> (pObj != nullptr) ? void (0) : __assert_fail
("pObj != nullptr", "/home/maarten/src/libreoffice/core/include/tools/ref.hxx"
, 99, __extension__ __PRETTY_FUNCTION__))
; return *pObj; }
100
101 bool operator ==(const SvRef<T> &rhs) const { return pObj == rhs.pObj; }
102 bool operator !=(const SvRef<T> &rhs) const { return !(*this == rhs); }
103
104private:
105 T * pObj;
106};
107
108/**
109 * This implements similar functionality to std::make_shared.
110 */
111template<typename T, typename... Args>
112SvRef<T> make_ref(Args&& ... args)
113{
114 return SvRef<T>(new T(std::forward<Args>(args)...));
115}
116
117}
118
119/** Classes that want to be referenced-counted via SvRef<T>, should extend this base class */
120class TOOLS_DLLPUBLIC__attribute__ ((visibility("default"))) SvRefBase
121{
122 // work around a clang 3.5 optimization bug: if the bNoDelete is *first*
123 // it mis-compiles "if (--nRefCount == 0)" and never deletes any object
124 unsigned int nRefCount : 31;
125 // the only reason this is not bool is because MSVC cannot handle mixed type bitfields
126 unsigned int bNoDelete : 1;
127
128protected:
129 virtual ~SvRefBase() COVERITY_NOEXCEPT_FALSE;
130
131public:
132 SvRefBase() : nRefCount(0), bNoDelete(1) {}
133 SvRefBase(const SvRefBase &) : nRefCount(0), bNoDelete(1) {}
134
135 SvRefBase & operator=(const SvRefBase &) { return *this; }
136
137 void RestoreNoDelete()
138 { bNoDelete = 1; }
139
140 void AddNextRef()
141 {
142 assert( nRefCount < (1 << 30) && "Do not add refs to dead objects" )(static_cast <bool> (nRefCount < (1 << 30) &&
"Do not add refs to dead objects") ? void (0) : __assert_fail
("nRefCount < (1 << 30) && \"Do not add refs to dead objects\""
, "/home/maarten/src/libreoffice/core/include/tools/ref.hxx",
142, __extension__ __PRETTY_FUNCTION__))
;
143 ++nRefCount;
144 }
145
146 void AddFirstRef()
147 {
148 assert( nRefCount < (1 << 30) && "Do not add refs to dead objects" )(static_cast <bool> (nRefCount < (1 << 30) &&
"Do not add refs to dead objects") ? void (0) : __assert_fail
("nRefCount < (1 << 30) && \"Do not add refs to dead objects\""
, "/home/maarten/src/libreoffice/core/include/tools/ref.hxx",
148, __extension__ __PRETTY_FUNCTION__))
;
149 if( bNoDelete )
150 bNoDelete = 0;
151 ++nRefCount;
152 }
153
154 void ReleaseRef()
155 {
156 assert( nRefCount >= 1)(static_cast <bool> (nRefCount >= 1) ? void (0) : __assert_fail
("nRefCount >= 1", "/home/maarten/src/libreoffice/core/include/tools/ref.hxx"
, 156, __extension__ __PRETTY_FUNCTION__))
;
11
Assuming field 'nRefCount' is >= 1
12
'?' condition is true
157 if( --nRefCount == 0 && !bNoDelete)
13
Assuming the condition is true
14
Assuming field 'bNoDelete' is 0
15
Taking true branch
158 {
159 // I'm not sure about the original purpose of this line, but right now
160 // it serves the purpose that anything that attempts to do an AddRef()
161 // after an object is deleted will trip an assert.
162 nRefCount = 1 << 30;
163 delete this;
16
Memory is released
164 }
165 }
166
167 unsigned int GetRefCount() const
168 { return nRefCount; }
169};
170
171template<typename T>
172class SvCompatWeakBase;
173
174/** SvCompatWeakHdl acts as an intermediary between SvCompatWeakRef<T> and T.
175*/
176template<typename T>
177class SvCompatWeakHdl final : public SvRefBase
178{
179 friend class SvCompatWeakBase<T>;
180 T* _pObj;
181
182 SvCompatWeakHdl( T* pObj ) : _pObj( pObj ) {}
183
184public:
185 void ResetWeakBase( ) { _pObj = nullptr; }
186 T* GetObj() { return _pObj; }
187};
188
189/** We only have one place that extends this, in include/sfx2/frame.hxx, class SfxFrame.
190 Its function is to notify the SvCompatWeakHdl when an SfxFrame object is deleted.
191*/
192template<typename T>
193class SvCompatWeakBase
194{
195 tools::SvRef< SvCompatWeakHdl<T> > _xHdl;
196
197public:
198 /** Does not use initializer due to compiler warnings,
199 because the lifetime of the _xHdl object can exceed the lifetime of this class.
200 */
201 SvCompatWeakBase( T* pObj ) { _xHdl = new SvCompatWeakHdl<T>( pObj ); }
202
203 ~SvCompatWeakBase() { _xHdl->ResetWeakBase(); }
204
205 SvCompatWeakHdl<T>* GetHdl() { return _xHdl.get(); }
206};
207
208/** We only have one weak reference in LO, in include/sfx2/frame.hxx, class SfxFrameWeak.
209*/
210template<typename T>
211class SAL_WARN_UNUSED__attribute__((warn_unused)) SvCompatWeakRef
212{
213 tools::SvRef< SvCompatWeakHdl<T> > _xHdl;
214public:
215 SvCompatWeakRef( ) {}
216 SvCompatWeakRef( T* pObj )
217 { if( pObj ) _xHdl = pObj->GetHdl(); }
218#if defined(__COVERITY__)
219 ~SvCompatWeakRef() COVERITY_NOEXCEPT_FALSE {}
220#endif
221 SvCompatWeakRef& operator = ( T * pObj )
222 { _xHdl = pObj ? pObj->GetHdl() : nullptr; return *this; }
223 bool is() const
224 { return _xHdl.is() && _xHdl->GetObj(); }
225 explicit operator bool() const { return is(); }
226 T* operator -> () const
227 { return _xHdl.is() ? _xHdl->GetObj() : nullptr; }
228 operator T* () const
229 { return _xHdl.is() ? _xHdl->GetObj() : nullptr; }
230};
231
232#endif
233
234/* vim:set shiftwidth=4 softtabstop=4 expandtab: */