1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <rtl/ustrbuf.hxx>
22 #include <tools/stream.hxx>
23 #include <tools/debug.hxx>
24 #include <vcl/errinf.hxx>
25 #include <comphelper/solarmutex.hxx>
26 #include <basic/sbx.hxx>
27 #include <vcl/svapp.hxx>
28 #include <comphelper/processfactory.hxx>
30 #include <sbunoobj.hxx>
31 #include <sbjsmeth.hxx>
32 #include <sbjsmod.hxx>
33 #include <sbintern.hxx>
34 #include <runtime.hxx>
35 #include <basic/sberrors.hxx>
36 #include <basic/sbuno.hxx>
38 #include <sbobjmod.hxx>
41 #include <cppuhelper/implbase.hxx>
42 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
43 #include <com/sun/star/util/XCloseBroadcaster.hpp>
44 #include <com/sun/star/util/XCloseListener.hpp>
45 #include <sal/log.hxx>
46 #include <errobject.hxx>
48 #include <unordered_map>
51 #include <unotools/transliterationwrapper.hxx>
53 #include <com/sun/star/script/ModuleType.hpp>
54 #include <com/sun/star/script/ModuleInfo.hpp>
56 #include <strings.hrc>
58 using namespace ::com::sun::star::script
;
60 constexpr OUStringLiteral SB_RTLNAME
= u
"@SBRTL";
62 using namespace ::com::sun::star
;
63 using namespace ::com::sun::star::uno
;
64 using com::sun::star::uno::Reference
;
65 using com::sun::star::uno::Any
;
66 using com::sun::star::uno::UNO_QUERY
;
67 using com::sun::star::lang::XMultiServiceFactory
;
70 class DocBasicItem
: public ::cppu::WeakImplHelper
< util::XCloseListener
>
73 explicit DocBasicItem( StarBASIC
& rDocBasic
);
74 virtual ~DocBasicItem() override
;
76 const SbxObjectRef
& getClassModules() const { return mxClassModules
; }
77 bool isDocClosed() const { return mbDocClosed
; }
79 void clearDependingVarsOnDelete( StarBASIC
& rDeletedBasic
);
81 void startListening();
84 void setDisposed( bool bDisposed
)
86 mbDisposed
= bDisposed
;
89 virtual void SAL_CALL
queryClosing( const lang::EventObject
& rSource
, sal_Bool bGetsOwnership
) override
;
90 virtual void SAL_CALL
notifyClosing( const lang::EventObject
& rSource
) override
;
91 virtual void SAL_CALL
disposing( const lang::EventObject
& rSource
) override
;
94 StarBASIC
& mrDocBasic
;
95 SbxObjectRef mxClassModules
;
101 DocBasicItem::DocBasicItem( StarBASIC
& rDocBasic
) :
102 mrDocBasic( rDocBasic
),
103 mxClassModules( new SbxObject( OUString() ) ),
104 mbDocClosed( false ),
109 DocBasicItem::~DocBasicItem()
111 // tdf#90969 HACK: don't use SolarMutexGuard - there is a horrible global
112 // map GaDocBasicItems holding instances, and these get deleted from exit
113 // handlers, when the SolarMutex is already dead
114 comphelper::SolarMutex
*pSolarMutex
= comphelper::SolarMutex::get();
116 pSolarMutex
->acquire();
121 mxClassModules
.clear(); // release with SolarMutex locked
128 pSolarMutex
= comphelper::SolarMutex::get();
130 pSolarMutex
->release();
133 void DocBasicItem::clearDependingVarsOnDelete( StarBASIC
& rDeletedBasic
)
135 mrDocBasic
.implClearDependingVarsOnDelete( &rDeletedBasic
);
138 void DocBasicItem::startListening()
141 mrDocBasic
.GetUNOConstant( "ThisComponent", aThisComp
);
142 Reference
< util::XCloseBroadcaster
> xCloseBC( aThisComp
, UNO_QUERY
);
143 mbDisposed
= !xCloseBC
.is();
146 try { xCloseBC
->addCloseListener( this ); } catch(const uno::Exception
& ) {}
150 void DocBasicItem::stopListening()
152 if( mbDisposed
) return;
155 if (!mrDocBasic
.GetUNOConstant("ThisComponent", aThisComp
))
158 Reference
< util::XCloseBroadcaster
> xCloseBC( aThisComp
, UNO_QUERY
);
161 try { xCloseBC
->removeCloseListener( this ); } catch(const uno::Exception
& ) {}
165 void SAL_CALL
DocBasicItem::queryClosing( const lang::EventObject
& /*rSource*/, sal_Bool
/*bGetsOwnership*/ )
169 void SAL_CALL
DocBasicItem::notifyClosing( const lang::EventObject
& /*rEvent*/ )
175 void SAL_CALL
DocBasicItem::disposing( const lang::EventObject
& /*rEvent*/ )
183 typedef ::rtl::Reference
< DocBasicItem
> DocBasicItemRef
;
185 std::unordered_map
< const StarBASIC
*, DocBasicItemRef
> gaDocBasicItems
;
187 const DocBasicItem
* lclFindDocBasicItem( const StarBASIC
* pDocBasic
)
189 auto it
= gaDocBasicItems
.find( pDocBasic
);
190 auto end
= gaDocBasicItems
.end();
191 return (it
!= end
) ? it
->second
.get() : nullptr;
194 void lclInsertDocBasicItem( StarBASIC
& rDocBasic
)
196 DocBasicItemRef
& rxDocBasicItem
= gaDocBasicItems
[ &rDocBasic
];
197 rxDocBasicItem
.set( new DocBasicItem( rDocBasic
) );
198 rxDocBasicItem
->startListening();
201 void lclRemoveDocBasicItem( StarBASIC
& rDocBasic
)
203 auto it
= gaDocBasicItems
.find( &rDocBasic
);
204 if( it
!= gaDocBasicItems
.end() )
206 it
->second
->stopListening();
207 gaDocBasicItems
.erase( it
);
209 for( auto& rEntry
: gaDocBasicItems
)
211 rEntry
.second
->clearDependingVarsOnDelete( rDocBasic
);
215 StarBASIC
* lclGetDocBasicForModule( SbModule
* pModule
)
217 StarBASIC
* pRetBasic
= nullptr;
218 SbxObject
* pCurParent
= pModule
;
219 while( pCurParent
->GetParent() != nullptr )
221 pCurParent
= pCurParent
->GetParent();
222 StarBASIC
* pDocBasic
= dynamic_cast<StarBASIC
*>( pCurParent
);
223 if( pDocBasic
!= nullptr && pDocBasic
->IsDocBasic() )
225 pRetBasic
= pDocBasic
;
235 SbxObject
* StarBASIC::getVBAGlobals( )
237 if ( !pVBAGlobals
.is() )
240 if ( GetUNOConstant("ThisComponent", aThisDoc
) )
242 Reference
< XMultiServiceFactory
> xDocFac( aThisDoc
, UNO_QUERY
);
247 xDocFac
->createInstance("ooo.vba.VBAGlobals");
249 catch(const Exception
& )
255 pVBAGlobals
= static_cast<SbUnoObject
*>(Find( "VBAGlobals" , SbxClassType::DontCare
));
257 return pVBAGlobals
.get();
261 SbxVariable
* StarBASIC::VBAFind( const OUString
& rName
, SbxClassType t
)
263 if( rName
== "ThisComponent" )
267 // rename to init globals
268 if ( getVBAGlobals( ) )
270 return pVBAGlobals
->Find( rName
, t
);
277 // Create array for conversion SFX <-> VB error code
278 struct SFX_VB_ErrorItem
286 const SFX_VB_ErrorItem SFX_VB_ErrorTab
[] =
288 { 1, ERRCODE_BASIC_EXCEPTION
}, // #87844 Map exception to error code 1
289 { 2, ERRCODE_BASIC_SYNTAX
},
290 { 3, ERRCODE_BASIC_NO_GOSUB
},
291 { 4, ERRCODE_BASIC_REDO_FROM_START
},
292 { 5, ERRCODE_BASIC_BAD_ARGUMENT
},
293 { 6, ERRCODE_BASIC_MATH_OVERFLOW
},
294 { 7, ERRCODE_BASIC_NO_MEMORY
},
295 { 8, ERRCODE_BASIC_ALREADY_DIM
},
296 { 9, ERRCODE_BASIC_OUT_OF_RANGE
},
297 { 10, ERRCODE_BASIC_DUPLICATE_DEF
},
298 { 11, ERRCODE_BASIC_ZERODIV
},
299 { 12, ERRCODE_BASIC_VAR_UNDEFINED
},
300 { 13, ERRCODE_BASIC_CONVERSION
},
301 { 14, ERRCODE_BASIC_BAD_PARAMETER
},
302 { 18, ERRCODE_BASIC_USER_ABORT
},
303 { 20, ERRCODE_BASIC_BAD_RESUME
},
304 { 28, ERRCODE_BASIC_STACK_OVERFLOW
},
305 { 35, ERRCODE_BASIC_PROC_UNDEFINED
},
306 { 48, ERRCODE_BASIC_BAD_DLL_LOAD
},
307 { 49, ERRCODE_BASIC_BAD_DLL_CALL
},
308 { 51, ERRCODE_BASIC_INTERNAL_ERROR
},
309 { 52, ERRCODE_BASIC_BAD_CHANNEL
},
310 { 53, ERRCODE_BASIC_FILE_NOT_FOUND
},
311 { 54, ERRCODE_BASIC_BAD_FILE_MODE
},
312 { 55, ERRCODE_BASIC_FILE_ALREADY_OPEN
},
313 { 57, ERRCODE_BASIC_IO_ERROR
},
314 { 58, ERRCODE_BASIC_FILE_EXISTS
},
315 { 59, ERRCODE_BASIC_BAD_RECORD_LENGTH
},
316 { 61, ERRCODE_BASIC_DISK_FULL
},
317 { 62, ERRCODE_BASIC_READ_PAST_EOF
},
318 { 63, ERRCODE_BASIC_BAD_RECORD_NUMBER
},
319 { 67, ERRCODE_BASIC_TOO_MANY_FILES
},
320 { 68, ERRCODE_BASIC_NO_DEVICE
},
321 { 70, ERRCODE_BASIC_ACCESS_DENIED
},
322 { 71, ERRCODE_BASIC_NOT_READY
},
323 { 73, ERRCODE_BASIC_NOT_IMPLEMENTED
},
324 { 74, ERRCODE_BASIC_DIFFERENT_DRIVE
},
325 { 75, ERRCODE_BASIC_ACCESS_ERROR
},
326 { 76, ERRCODE_BASIC_PATH_NOT_FOUND
},
327 { 91, ERRCODE_BASIC_NO_OBJECT
},
328 { 93, ERRCODE_BASIC_BAD_PATTERN
},
329 { 94, ERRCODE_BASIC_IS_NULL
},
330 { 250, ERRCODE_BASIC_DDE_ERROR
},
331 { 280, ERRCODE_BASIC_DDE_WAITINGACK
},
332 { 281, ERRCODE_BASIC_DDE_OUTOFCHANNELS
},
333 { 282, ERRCODE_BASIC_DDE_NO_RESPONSE
},
334 { 283, ERRCODE_BASIC_DDE_MULT_RESPONSES
},
335 { 284, ERRCODE_BASIC_DDE_CHANNEL_LOCKED
},
336 { 285, ERRCODE_BASIC_DDE_NOTPROCESSED
},
337 { 286, ERRCODE_BASIC_DDE_TIMEOUT
},
338 { 287, ERRCODE_BASIC_DDE_USER_INTERRUPT
},
339 { 288, ERRCODE_BASIC_DDE_BUSY
},
340 { 289, ERRCODE_BASIC_DDE_NO_DATA
},
341 { 290, ERRCODE_BASIC_DDE_WRONG_DATA_FORMAT
},
342 { 291, ERRCODE_BASIC_DDE_PARTNER_QUIT
},
343 { 292, ERRCODE_BASIC_DDE_CONV_CLOSED
},
344 { 293, ERRCODE_BASIC_DDE_NO_CHANNEL
},
345 { 294, ERRCODE_BASIC_DDE_INVALID_LINK
},
346 { 295, ERRCODE_BASIC_DDE_QUEUE_OVERFLOW
},
347 { 296, ERRCODE_BASIC_DDE_LINK_ALREADY_EST
},
348 { 297, ERRCODE_BASIC_DDE_LINK_INV_TOPIC
},
349 { 298, ERRCODE_BASIC_DDE_DLL_NOT_FOUND
},
350 { 323, ERRCODE_BASIC_CANNOT_LOAD
},
351 { 341, ERRCODE_BASIC_BAD_INDEX
},
352 { 366, ERRCODE_BASIC_NO_ACTIVE_OBJECT
},
353 { 380, ERRCODE_BASIC_BAD_PROP_VALUE
},
354 { 382, ERRCODE_BASIC_PROP_READONLY
},
355 { 394, ERRCODE_BASIC_PROP_WRITEONLY
},
356 { 420, ERRCODE_BASIC_INVALID_OBJECT
},
357 { 423, ERRCODE_BASIC_NO_METHOD
},
358 { 424, ERRCODE_BASIC_NEEDS_OBJECT
},
359 { 425, ERRCODE_BASIC_INVALID_USAGE_OBJECT
},
360 { 430, ERRCODE_BASIC_NO_OLE
},
361 { 438, ERRCODE_BASIC_BAD_METHOD
},
362 { 440, ERRCODE_BASIC_OLE_ERROR
},
363 { 445, ERRCODE_BASIC_BAD_ACTION
},
364 { 446, ERRCODE_BASIC_NO_NAMED_ARGS
},
365 { 447, ERRCODE_BASIC_BAD_LOCALE
},
366 { 448, ERRCODE_BASIC_NAMED_NOT_FOUND
},
367 { 449, ERRCODE_BASIC_NOT_OPTIONAL
},
368 { 450, ERRCODE_BASIC_WRONG_ARGS
},
369 { 451, ERRCODE_BASIC_NOT_A_COLL
},
370 { 452, ERRCODE_BASIC_BAD_ORDINAL
},
371 { 453, ERRCODE_BASIC_DLLPROC_NOT_FOUND
},
372 { 460, ERRCODE_BASIC_BAD_CLIPBD_FORMAT
},
373 { 951, ERRCODE_BASIC_UNEXPECTED
},
374 { 952, ERRCODE_BASIC_EXPECTED
},
375 { 953, ERRCODE_BASIC_SYMBOL_EXPECTED
},
376 { 954, ERRCODE_BASIC_VAR_EXPECTED
},
377 { 955, ERRCODE_BASIC_LABEL_EXPECTED
},
378 { 956, ERRCODE_BASIC_LVALUE_EXPECTED
},
379 { 957, ERRCODE_BASIC_VAR_DEFINED
},
380 { 958, ERRCODE_BASIC_PROC_DEFINED
},
381 { 959, ERRCODE_BASIC_LABEL_DEFINED
},
382 { 960, ERRCODE_BASIC_UNDEF_VAR
},
383 { 961, ERRCODE_BASIC_UNDEF_ARRAY
},
384 { 962, ERRCODE_BASIC_UNDEF_PROC
},
385 { 963, ERRCODE_BASIC_UNDEF_LABEL
},
386 { 964, ERRCODE_BASIC_UNDEF_TYPE
},
387 { 965, ERRCODE_BASIC_BAD_EXIT
},
388 { 966, ERRCODE_BASIC_BAD_BLOCK
},
389 { 967, ERRCODE_BASIC_BAD_BRACKETS
},
390 { 968, ERRCODE_BASIC_BAD_DECLARATION
},
391 { 969, ERRCODE_BASIC_BAD_PARAMETERS
},
392 { 970, ERRCODE_BASIC_BAD_CHAR_IN_NUMBER
},
393 { 971, ERRCODE_BASIC_MUST_HAVE_DIMS
},
394 { 972, ERRCODE_BASIC_NO_IF
},
395 { 973, ERRCODE_BASIC_NOT_IN_SUBR
},
396 { 974, ERRCODE_BASIC_NOT_IN_MAIN
},
397 { 975, ERRCODE_BASIC_WRONG_DIMS
},
398 { 976, ERRCODE_BASIC_BAD_OPTION
},
399 { 977, ERRCODE_BASIC_CONSTANT_REDECLARED
},
400 { 978, ERRCODE_BASIC_PROG_TOO_LARGE
},
401 { 979, ERRCODE_BASIC_NO_STRINGS_ARRAYS
},
402 { 1000, ERRCODE_BASIC_PROPERTY_NOT_FOUND
},
403 { 1001, ERRCODE_BASIC_METHOD_NOT_FOUND
},
404 { 1002, ERRCODE_BASIC_ARG_MISSING
},
405 { 1003, ERRCODE_BASIC_BAD_NUMBER_OF_ARGS
},
406 { 1004, ERRCODE_BASIC_METHOD_FAILED
},
407 { 1005, ERRCODE_BASIC_SETPROP_FAILED
},
408 { 1006, ERRCODE_BASIC_GETPROP_FAILED
},
409 { 1007, ERRCODE_BASIC_COMPAT
},
410 { 0xFFFF, ErrCode(0xFFFFFFFFUL
) } // End mark
413 // The StarBASIC factory is a hack. When a SbModule is created, its pointer
414 // is saved and given to the following SbProperties/SbMethods. This restores
415 // the Module-relationship. But it works only when a module is loaded.
416 // Can cause troubles with separately loaded properties!
418 SbxBaseRef
SbiFactory::Create( sal_uInt16 nSbxId
, sal_uInt32 nCreator
)
420 if( nCreator
== SBXCR_SBX
)
425 return new StarBASIC( nullptr );
427 return new SbModule( "" );
428 case SBXID_BASICPROP
:
429 return new SbProperty( "", SbxVARIANT
, nullptr );
430 case SBXID_BASICMETHOD
:
431 return new SbMethod( "", SbxVARIANT
, nullptr );
432 case SBXID_JSCRIPTMOD
:
433 return new SbJScriptModule
;
434 case SBXID_JSCRIPTMETH
:
435 return new SbJScriptMethod( SbxVARIANT
);
441 SbxObjectRef
SbiFactory::CreateObject( const OUString
& rClass
)
443 if( rClass
.equalsIgnoreAsciiCase( "StarBASIC" ) )
445 return new StarBASIC( nullptr );
447 else if( rClass
.equalsIgnoreAsciiCase( "StarBASICModule" ) )
449 return new SbModule( OUString() );
451 else if( rClass
.equalsIgnoreAsciiCase( "Collection" ) )
453 return new BasicCollection( "Collection" );
455 else if( rClass
.equalsIgnoreAsciiCase( "FileSystemObject" ) )
459 Reference
< XMultiServiceFactory
> xFactory( comphelper::getProcessServiceFactory(), UNO_SET_THROW
);
460 OUString
aServiceName("ooo.vba.FileSystemObject");
461 Reference
< XInterface
> xInterface( xFactory
->createInstance( aServiceName
), UNO_SET_THROW
);
462 return new SbUnoObject( aServiceName
, uno::Any( xInterface
) );
464 catch(const Exception
& )
472 SbxBaseRef
SbOLEFactory::Create( sal_uInt16
, sal_uInt32
)
478 SbxObjectRef
SbOLEFactory::CreateObject( const OUString
& rClassName
)
480 SbxObjectRef pRet
= createOLEObject_Impl( rClassName
);
485 // SbFormFactory, show user forms by: dim as new <user form name>
487 SbxBaseRef
SbFormFactory::Create( sal_uInt16
, sal_uInt32
)
493 SbxObjectRef
SbFormFactory::CreateObject( const OUString
& rClassName
)
495 if( SbModule
* pMod
= GetSbData()->pMod
)
497 if( SbxVariable
* pVar
= pMod
->Find( rClassName
, SbxClassType::Object
) )
499 if( SbUserFormModule
* pFormModule
= dynamic_cast<SbUserFormModule
*>( pVar
->GetObject() ) )
501 bool bInitState
= pFormModule
->getInitState();
504 // Not the first instantiate, reset
505 pFormModule
->ResetApiObj( false/*bTriggerTerminateEvent*/ );
506 pFormModule
->setInitState( false );
512 return pFormModule
->CreateInstance();
522 SbxObjectRef
cloneTypeObjectImpl( const SbxObject
& rTypeObj
)
524 SbxObjectRef pRet
= new SbxObject( rTypeObj
);
525 pRet
->PutObject( pRet
.get() );
527 // Copy the properties, not only the reference to them
528 SbxArray
* pProps
= pRet
->GetProperties();
529 sal_uInt32 nCount
= pProps
->Count();
530 for( sal_uInt32 i
= 0 ; i
< nCount
; i
++ )
532 SbxVariable
* pVar
= pProps
->Get(i
);
533 SbxProperty
* pProp
= dynamic_cast<SbxProperty
*>( pVar
);
536 SbxProperty
* pNewProp
= new SbxProperty( *pProp
);
537 SbxDataType eVarType
= pVar
->GetType();
538 if( eVarType
& SbxARRAY
)
540 SbxBase
* pParObj
= pVar
->GetObject();
541 SbxDimArray
* pSource
= dynamic_cast<SbxDimArray
*>( pParObj
);
542 SbxDimArray
* pDest
= new SbxDimArray( pVar
->GetType() );
544 pDest
->setHasFixedSize( pSource
&& pSource
->hasFixedSize() );
545 if (pSource
&& pSource
->GetDims() && pSource
->hasFixedSize())
549 for (sal_Int32 j
= 1; j
<= pSource
->GetDims(); ++j
)
551 pSource
->GetDim(j
, lb
, ub
);
552 pDest
->AddDim(lb
, ub
);
557 pDest
->unoAddDim(0, -1); // variant array
559 SbxFlagBits nSavFlags
= pVar
->GetFlags();
560 pNewProp
->ResetFlag( SbxFlagBits::Fixed
);
561 // need to reset the FIXED flag
562 // when calling PutObject ( because the type will not match Object )
563 pNewProp
->PutObject( pDest
);
564 pNewProp
->SetFlags( nSavFlags
);
566 if( eVarType
== SbxOBJECT
)
568 SbxBase
* pObjBase
= pVar
->GetObject();
569 SbxObject
* pSrcObj
= dynamic_cast<SbxObject
*>( pObjBase
);
570 SbxObjectRef pDestObj
;
571 if( pSrcObj
!= nullptr )
572 pDestObj
= cloneTypeObjectImpl( *pSrcObj
);
573 pNewProp
->PutObject( pDestObj
.get() );
575 pProps
->PutDirect( pNewProp
, i
);
581 SbxBaseRef
SbTypeFactory::Create( sal_uInt16
, sal_uInt32
)
587 SbxObjectRef
SbTypeFactory::CreateObject( const OUString
& rClassName
)
590 SbModule
* pMod
= GetSbData()->pMod
;
593 const SbxObject
* pObj
= pMod
->FindType( rClassName
);
596 pRet
= cloneTypeObjectImpl( *pObj
);
602 SbxObjectRef
createUserTypeImpl( const OUString
& rClassName
)
604 SbxObjectRef pRetObj
= GetSbData()->pTypeFac
->CreateObject( rClassName
);
609 SbClassModuleObject::SbClassModuleObject( SbModule
* pClassModule
)
610 : SbModule( pClassModule
->GetName() )
611 , mpClassModule( pClassModule
)
612 , mbInitializeEventDone( false )
614 aOUSource
= pClassModule
->aOUSource
;
615 aComment
= pClassModule
->aComment
;
616 // see comment in destructor about these two
617 pImage
.reset(pClassModule
->pImage
.get());
618 pBreaks
= pClassModule
->pBreaks
;
620 SetClassName( pClassModule
->GetName() );
622 // Allow search only internally
623 ResetFlag( SbxFlagBits::GlobalSearch
);
625 // Copy the methods from original class module
626 SbxArray
* pClassMethods
= pClassModule
->GetMethods().get();
627 sal_uInt32 nMethodCount
= pClassMethods
->Count();
629 for( i
= 0 ; i
< nMethodCount
; i
++ )
631 SbxVariable
* pVar
= pClassMethods
->Get(i
);
633 // Exclude SbIfaceMapperMethod to copy them in a second step
634 SbIfaceMapperMethod
* pIfaceMethod
= dynamic_cast<SbIfaceMapperMethod
*>( pVar
);
637 SbMethod
* pMethod
= dynamic_cast<SbMethod
*>( pVar
);
640 SbxFlagBits nFlags_
= pMethod
->GetFlags();
641 pMethod
->SetFlag( SbxFlagBits::NoBroadcast
);
642 SbMethod
* pNewMethod
= new SbMethod( *pMethod
);
643 pNewMethod
->ResetFlag( SbxFlagBits::NoBroadcast
);
644 pMethod
->SetFlags( nFlags_
);
645 pNewMethod
->pMod
= this;
646 pNewMethod
->SetParent( this );
647 pMethods
->PutDirect( pNewMethod
, i
);
648 StartListening(pNewMethod
->GetBroadcaster(), DuplicateHandling::Prevent
);
653 // Copy SbIfaceMapperMethod in a second step to ensure that
654 // the corresponding base methods have already been copied
655 for( i
= 0 ; i
< nMethodCount
; i
++ )
657 SbxVariable
* pVar
= pClassMethods
->Get(i
);
659 SbIfaceMapperMethod
* pIfaceMethod
= dynamic_cast<SbIfaceMapperMethod
*>( pVar
);
662 SbMethod
* pImplMethod
= pIfaceMethod
->getImplMethod();
665 OSL_FAIL( "No ImplMethod" );
669 // Search for own copy of ImplMethod
670 SbxVariable
* p
= pMethods
->Find( pImplMethod
->GetName(), SbxClassType::Method
);
671 SbMethod
* pImplMethodCopy
= dynamic_cast<SbMethod
*>( p
);
672 if( !pImplMethodCopy
)
674 OSL_FAIL( "Found no ImplMethod copy" );
677 SbIfaceMapperMethod
* pNewIfaceMethod
=
678 new SbIfaceMapperMethod( pIfaceMethod
->GetName(), pImplMethodCopy
);
679 pMethods
->PutDirect( pNewIfaceMethod
, i
);
683 // Copy the properties from original class module
684 SbxArray
* pClassProps
= pClassModule
->GetProperties();
685 sal_uInt32 nPropertyCount
= pClassProps
->Count();
686 for( i
= 0 ; i
< nPropertyCount
; i
++ )
688 SbxVariable
* pVar
= pClassProps
->Get(i
);
689 SbProcedureProperty
* pProcedureProp
= dynamic_cast<SbProcedureProperty
*>( pVar
);
692 SbxFlagBits nFlags_
= pProcedureProp
->GetFlags();
693 pProcedureProp
->SetFlag( SbxFlagBits::NoBroadcast
);
694 SbProcedureProperty
* pNewProp
= new SbProcedureProperty
695 ( pProcedureProp
->GetName(), pProcedureProp
->GetType() );
696 pNewProp
->SetFlags( nFlags_
); // Copy flags
697 pNewProp
->ResetFlag( SbxFlagBits::NoBroadcast
); // except the Broadcast if it was set
698 pProcedureProp
->SetFlags( nFlags_
);
699 pProps
->PutDirect( pNewProp
, i
);
700 StartListening(pNewProp
->GetBroadcaster(), DuplicateHandling::Prevent
);
704 SbxProperty
* pProp
= dynamic_cast<SbxProperty
*>( pVar
);
707 SbxFlagBits nFlags_
= pProp
->GetFlags();
708 pProp
->SetFlag( SbxFlagBits::NoBroadcast
);
709 SbxProperty
* pNewProp
= new SbxProperty( *pProp
);
711 // Special handling for modules instances and collections, they need
712 // to be instantiated, otherwise all refer to the same base object
713 SbxDataType eVarType
= pProp
->GetType();
714 if( eVarType
== SbxOBJECT
)
716 SbxBase
* pObjBase
= pProp
->GetObject();
717 SbxObject
* pObj
= dynamic_cast<SbxObject
*>( pObjBase
);
718 if( pObj
!= nullptr )
720 const OUString
& aObjClass
= pObj
->GetClassName();
722 SbClassModuleObject
* pClassModuleObj
= dynamic_cast<SbClassModuleObject
*>( pObjBase
);
723 if( pClassModuleObj
!= nullptr )
725 SbModule
* pLclClassModule
= pClassModuleObj
->getClassModule();
726 SbClassModuleObject
* pNewObj
= new SbClassModuleObject( pLclClassModule
);
727 pNewObj
->SetName( pProp
->GetName() );
728 pNewObj
->SetParent( pLclClassModule
->pParent
);
729 pNewProp
->PutObject( pNewObj
);
731 else if( aObjClass
.equalsIgnoreAsciiCase( "Collection" ) )
733 BasicCollection
* pNewCollection
= new BasicCollection( "Collection" );
734 pNewCollection
->SetName( pProp
->GetName() );
735 pNewCollection
->SetParent( pClassModule
->pParent
);
736 pNewProp
->PutObject( pNewCollection
);
741 pNewProp
->ResetFlag( SbxFlagBits::NoBroadcast
);
742 pNewProp
->SetParent( this );
743 pProps
->PutDirect( pNewProp
, i
);
744 pProp
->SetFlags( nFlags_
);
748 SetModuleType( ModuleType::CLASS
);
749 mbVBACompat
= pClassModule
->mbVBACompat
;
752 SbClassModuleObject::~SbClassModuleObject()
754 // do not trigger termination event when document is already closed
755 if( StarBASIC::IsRunning() )
756 if( StarBASIC
* pDocBasic
= lclGetDocBasicForModule( this ) )
757 if( const DocBasicItem
* pDocBasicItem
= lclFindDocBasicItem( pDocBasic
) )
758 if( !pDocBasicItem
->isDocClosed() )
759 triggerTerminateEvent();
761 // prevent the base class destructor from deleting these because
762 // we do not actually own them
767 void SbClassModuleObject::Notify( SfxBroadcaster
& rBC
, const SfxHint
& rHint
)
769 handleProcedureProperties( rBC
, rHint
);
772 SbxVariable
* SbClassModuleObject::Find( const OUString
& rName
, SbxClassType t
)
774 SbxVariable
* pRes
= SbxObject::Find( rName
, t
);
777 triggerInitializeEvent();
779 SbIfaceMapperMethod
* pIfaceMapperMethod
= dynamic_cast<SbIfaceMapperMethod
*>( pRes
);
780 if( pIfaceMapperMethod
)
782 pRes
= pIfaceMapperMethod
->getImplMethod();
783 pRes
->SetFlag( SbxFlagBits::ExtFound
);
789 void SbClassModuleObject::triggerInitializeEvent()
791 if( mbInitializeEventDone
)
796 mbInitializeEventDone
= true;
799 SbxVariable
* pMeth
= SbxObject::Find("Class_Initialize", SbxClassType::Method
);
807 void SbClassModuleObject::triggerTerminateEvent()
809 if( !mbInitializeEventDone
|| GetSbData()->bRunInit
)
814 SbxVariable
* pMeth
= SbxObject::Find("Class_Terminate", SbxClassType::Method
);
823 SbClassData::SbClassData()
825 mxIfaces
= new SbxArray();
828 void SbClassData::clear()
831 maRequiredTypes
.clear();
834 SbClassFactory::SbClassFactory()
836 xClassModules
= new SbxObject( OUString() );
839 SbClassFactory::~SbClassFactory()
842 void SbClassFactory::AddClassModule( SbModule
* pClassModule
)
844 SbxObjectRef xToUseClassModules
= xClassModules
;
846 if( StarBASIC
* pDocBasic
= lclGetDocBasicForModule( pClassModule
) )
847 if( const DocBasicItem
* pDocBasicItem
= lclFindDocBasicItem( pDocBasic
) )
848 xToUseClassModules
= pDocBasicItem
->getClassModules();
850 SbxObject
* pParent
= pClassModule
->GetParent();
851 xToUseClassModules
->Insert( pClassModule
);
852 pClassModule
->SetParent( pParent
);
855 void SbClassFactory::RemoveClassModule( SbModule
* pClassModule
)
857 xClassModules
->Remove( pClassModule
);
860 SbxBaseRef
SbClassFactory::Create( sal_uInt16
, sal_uInt32
)
866 SbxObjectRef
SbClassFactory::CreateObject( const OUString
& rClassName
)
868 SbxObjectRef xToUseClassModules
= xClassModules
;
870 if( SbModule
* pMod
= GetSbData()->pMod
)
872 if( StarBASIC
* pDocBasic
= lclGetDocBasicForModule( pMod
) )
874 if( const DocBasicItem
* pDocBasicItem
= lclFindDocBasicItem( pDocBasic
) )
876 xToUseClassModules
= pDocBasicItem
->getClassModules();
880 SbxVariable
* pVar
= xToUseClassModules
->Find( rClassName
, SbxClassType::Object
);
884 SbModule
* pVarMod
= static_cast<SbModule
*>(pVar
);
885 pRet
= new SbClassModuleObject( pVarMod
);
890 SbModule
* SbClassFactory::FindClass( const OUString
& rClassName
)
892 SbxVariable
* pVar
= xClassModules
->Find( rClassName
, SbxClassType::DontCare
);
893 SbModule
* pMod
= pVar
? static_cast<SbModule
*>(pVar
) : nullptr;
897 StarBASIC::StarBASIC( StarBASIC
* p
, bool bIsDocBasic
)
898 : SbxObject("StarBASIC"), bDocBasic( bIsDocBasic
)
901 bNoRtl
= bBreak
= false;
904 if( !GetSbData()->nInst
++ )
906 GetSbData()->pSbFac
.reset( new SbiFactory
);
907 AddFactory( GetSbData()->pSbFac
.get() );
908 GetSbData()->pTypeFac
.reset(new SbTypeFactory
);
909 AddFactory( GetSbData()->pTypeFac
.get() );
910 GetSbData()->pClassFac
.reset(new SbClassFactory
);
911 AddFactory( GetSbData()->pClassFac
.get() );
912 GetSbData()->pOLEFac
.reset(new SbOLEFactory
);
913 AddFactory( GetSbData()->pOLEFac
.get() );
914 GetSbData()->pFormFac
.reset(new SbFormFactory
);
915 AddFactory( GetSbData()->pFormFac
.get() );
916 GetSbData()->pUnoFac
.reset( new SbUnoFactory
);
917 AddFactory( GetSbData()->pUnoFac
.get() );
919 pRtl
= new SbiStdObject(SB_RTLNAME
, this );
920 // Search via StarBasic is always global
921 SetFlag( SbxFlagBits::GlobalSearch
);
922 pVBAGlobals
= nullptr;
927 lclInsertDocBasicItem( *this );
931 // #51727 Override SetModified so that the modified state
932 // is not given to the parent
933 void StarBASIC::SetModified( bool b
)
935 SbxBase::SetModified( b
);
938 StarBASIC::~StarBASIC()
940 // Needs to be first action as it can trigger events
941 disposeComVariablesForBasic( this );
943 if( !--GetSbData()->nInst
)
945 RemoveFactory( GetSbData()->pSbFac
.get() );
946 GetSbData()->pSbFac
.reset();
947 RemoveFactory( GetSbData()->pUnoFac
.get() );
948 GetSbData()->pUnoFac
.reset();
949 RemoveFactory( GetSbData()->pTypeFac
.get() );
950 GetSbData()->pTypeFac
.reset();
951 RemoveFactory( GetSbData()->pClassFac
.get() );
952 GetSbData()->pClassFac
.reset();
953 RemoveFactory( GetSbData()->pOLEFac
.get() );
954 GetSbData()->pOLEFac
.reset();
955 RemoveFactory( GetSbData()->pFormFac
.get() );
956 GetSbData()->pFormFac
.reset();
958 if( SbiGlobals::pGlobals
)
960 delete SbiGlobals::pGlobals
;
961 SbiGlobals::pGlobals
= nullptr;
966 ErrCode eOld
= SbxBase::GetError();
968 lclRemoveDocBasicItem( *this );
970 SbxBase::ResetError();
971 if( eOld
!= ERRCODE_NONE
)
973 SbxBase::SetError( eOld
);
977 // #100326 Set Parent NULL in registered listeners
978 if( xUnoListeners
.is() )
980 sal_uInt32 uCount
= xUnoListeners
->Count();
981 for( sal_uInt32 i
= 0 ; i
< uCount
; i
++ )
983 SbxVariable
* pListenerObj
= xUnoListeners
->Get(i
);
984 pListenerObj
->SetParent( nullptr );
986 xUnoListeners
= nullptr;
989 clearUnoMethodsForBasic( this );
992 void StarBASIC::implClearDependingVarsOnDelete( StarBASIC
* pDeletedBasic
)
994 if( this != pDeletedBasic
)
996 for( const auto& pModule
: pModules
)
998 pModule
->ClearVarsDependingOnDeletedBasic( pDeletedBasic
);
1002 for (sal_uInt32 nObj
= 0; nObj
< pObjs
->Count(); nObj
++)
1004 SbxVariable
* pVar
= pObjs
->Get(nObj
);
1005 StarBASIC
* pBasic
= dynamic_cast<StarBASIC
*>( pVar
);
1006 if( pBasic
&& pBasic
!= pDeletedBasic
)
1008 pBasic
->implClearDependingVarsOnDelete( pDeletedBasic
);
1014 SbModule
* StarBASIC::MakeModule( const OUString
& rName
, const OUString
& rSrc
)
1017 aInfo
.ModuleType
= ModuleType::NORMAL
;
1018 return MakeModule( rName
, aInfo
, rSrc
);
1020 SbModule
* StarBASIC::MakeModule( const OUString
& rName
, const ModuleInfo
& mInfo
, const OUString
& rSrc
)
1025 "create module " << rName
<< " type mInfo " << mInfo
.ModuleType
);
1026 SbModule
* p
= nullptr;
1027 switch ( mInfo
.ModuleType
)
1029 case ModuleType::DOCUMENT
:
1030 // In theory we should be able to create Object modules
1031 // in ordinary basic ( in vba mode thought these are create
1032 // by the application/basic and not by the user )
1033 p
= new SbObjModule( rName
, mInfo
, isVBAEnabled() );
1035 case ModuleType::CLASS
:
1036 p
= new SbModule( rName
, isVBAEnabled() );
1037 p
->SetModuleType( ModuleType::CLASS
);
1039 case ModuleType::FORM
:
1040 p
= new SbUserFormModule( rName
, mInfo
, isVBAEnabled() );
1043 p
= new SbModule( rName
, isVBAEnabled() );
1046 p
->SetSource32( rSrc
);
1047 p
->SetParent( this );
1048 pModules
.emplace_back(p
);
1049 SetModified( true );
1053 void StarBASIC::Insert( SbxVariable
* pVar
)
1055 if( auto pModule
= dynamic_cast<SbModule
*>(pVar
) )
1057 pModules
.emplace_back(pModule
);
1058 pVar
->SetParent( this );
1059 StartListening(pVar
->GetBroadcaster(), DuplicateHandling::Prevent
);
1063 bool bWasModified
= IsModified();
1064 SbxObject::Insert( pVar
);
1065 if( !bWasModified
&& pVar
->IsSet( SbxFlagBits::DontStore
) )
1067 SetModified( false );
1072 void StarBASIC::Remove( SbxVariable
* pVar
)
1074 SbModule
* pModule
= dynamic_cast<SbModule
*>(pVar
);
1077 // #87540 Can be last reference!
1078 SbModuleRef xVar
= pModule
;
1079 pModules
.erase(std::remove(pModules
.begin(), pModules
.end(), xVar
));
1080 pVar
->SetParent( nullptr );
1081 EndListening( pVar
->GetBroadcaster() );
1085 SbxObject::Remove( pVar
);
1089 void StarBASIC::Clear()
1094 SbModule
* StarBASIC::FindModule( std::u16string_view rName
)
1096 for (const auto& pModule
: pModules
)
1098 if( pModule
->GetName().equalsIgnoreAsciiCase( rName
) )
1100 return pModule
.get();
1107 struct ClassModuleRunInitItem
1109 SbModule
* m_pModule
;
1111 bool m_bRunInitDone
;
1113 ClassModuleRunInitItem()
1114 : m_pModule( nullptr )
1115 , m_bProcessing( false )
1116 , m_bRunInitDone( false )
1118 explicit ClassModuleRunInitItem( SbModule
* pModule
)
1119 : m_pModule( pModule
)
1120 , m_bProcessing( false )
1121 , m_bRunInitDone( false )
1125 // Derive from unordered_map type instead of typedef
1126 // to allow forward declaration in sbmod.hxx
1127 class ModuleInitDependencyMap
: public
1128 std::unordered_map
< OUString
, ClassModuleRunInitItem
>
1131 void SbModule::implProcessModuleRunInit( ModuleInitDependencyMap
& rMap
, ClassModuleRunInitItem
& rItem
)
1133 rItem
.m_bProcessing
= true;
1135 SbModule
* pModule
= rItem
.m_pModule
;
1136 if( pModule
->pClassData
!= nullptr )
1138 std::vector
< OUString
>& rReqTypes
= pModule
->pClassData
->maRequiredTypes
;
1139 for( const auto& rStr
: rReqTypes
)
1141 // Is required type a class module?
1142 ModuleInitDependencyMap::iterator itFind
= rMap
.find( rStr
);
1143 if( itFind
!= rMap
.end() )
1145 ClassModuleRunInitItem
& rParentItem
= itFind
->second
;
1146 if( rParentItem
.m_bProcessing
)
1148 // TODO: raise error?
1149 OSL_FAIL( "Cyclic module dependency detected" );
1153 if( !rParentItem
.m_bRunInitDone
)
1155 implProcessModuleRunInit( rMap
, rParentItem
);
1162 rItem
.m_bRunInitDone
= true;
1163 rItem
.m_bProcessing
= false;
1166 // Run Init-Code of all modules (including inserted libraries)
1167 void StarBASIC::InitAllModules( StarBASIC
const * pBasicNotToInit
)
1169 SolarMutexGuard guard
;
1172 for (const auto& pModule
: pModules
)
1176 // compile modules first then RunInit ( otherwise there is
1177 // can be order dependency, e.g. classmodule A has a member
1178 // of type classmodule B and classmodule B hasn't been compiled yet )
1180 // Consider required types to init in right order. Class modules
1181 // that are required by other modules have to be initialized first.
1182 ModuleInitDependencyMap aMIDMap
;
1183 for (const auto& pModule
: pModules
)
1185 OUString aModuleName
= pModule
->GetName();
1186 if( pModule
->isProxyModule() )
1188 aMIDMap
[aModuleName
] = ClassModuleRunInitItem( pModule
.get() );
1192 for (auto & elem
: aMIDMap
)
1194 ClassModuleRunInitItem
& rItem
= elem
.second
;
1195 SbModule::implProcessModuleRunInit( aMIDMap
, rItem
);
1198 // Call RunInit on standard modules
1199 for (const auto& pModule
: pModules
)
1201 if( !pModule
->isProxyModule() )
1207 // Check all objects if they are BASIC,
1208 // if yes initialize
1209 for (sal_uInt32 nObj
= 0; nObj
< pObjs
->Count(); nObj
++)
1211 SbxVariable
* pVar
= pObjs
->Get(nObj
);
1212 StarBASIC
* pBasic
= dynamic_cast<StarBASIC
*>( pVar
);
1213 if( pBasic
&& pBasic
!= pBasicNotToInit
)
1215 pBasic
->InitAllModules();
1220 // #88329 Put modules back to not initialised state to
1221 // force reinitialisation at next start
1222 void StarBASIC::DeInitAllModules()
1224 // Deinit own modules
1225 for (const auto& pModule
: pModules
)
1227 if( pModule
->pImage
&& !pModule
->isProxyModule() && dynamic_cast<SbObjModule
*>( pModule
.get()) == nullptr )
1229 pModule
->pImage
->bInit
= false;
1233 for (sal_uInt32 nObj
= 0; nObj
< pObjs
->Count(); nObj
++)
1235 SbxVariable
* pVar
= pObjs
->Get(nObj
);
1236 StarBASIC
* pBasic
= dynamic_cast<StarBASIC
*>( pVar
);
1239 pBasic
->DeInitAllModules();
1244 // This implementation at first searches within the runtime library,
1245 // then it looks for an element within one module. This module can be
1246 // a public var or an entrypoint. If it is not found and we look for a
1247 // method and a module with the given name is found the search continues
1248 // for entrypoint "Main".
1249 // If this fails again a conventional search over objects is performed.
1250 SbxVariable
* StarBASIC::Find( const OUString
& rName
, SbxClassType t
)
1252 SbxVariable
* pRes
= nullptr;
1253 SbModule
* pNamed
= nullptr;
1254 // "Extended" search in Runtime Lib
1255 // but only if SbiRuntime has not set the flag
1258 if( t
== SbxClassType::DontCare
|| t
== SbxClassType::Object
)
1260 if( rName
.equalsIgnoreAsciiCase( SB_RTLNAME
) )
1267 pRes
= static_cast<SbiStdObject
*>(pRtl
.get())->Find( rName
, t
);
1271 pRes
->SetFlag( SbxFlagBits::ExtFound
);
1277 for (const auto& pModule
: pModules
)
1279 if( pModule
->IsVisible() )
1281 // Remember module for Main() call
1282 // or is the name equal?!?
1283 if( pModule
->GetName().equalsIgnoreAsciiCase( rName
) )
1285 if( t
== SbxClassType::Object
|| t
== SbxClassType::DontCare
)
1287 pRes
= pModule
.get(); break;
1289 pNamed
= pModule
.get();
1291 // Only variables qualified by the Module Name e.g. Sheet1.foo
1292 // should work for Document && Class type Modules
1293 sal_Int32 nType
= pModule
->GetModuleType();
1294 if ( nType
== ModuleType::DOCUMENT
|| nType
== ModuleType::FORM
)
1298 // otherwise check if the element is available
1299 // unset GBLSEARCH-Flag (due to recursion)
1300 SbxFlagBits nGblFlag
= pModule
->GetFlags() & SbxFlagBits::GlobalSearch
;
1301 pModule
->ResetFlag( SbxFlagBits::GlobalSearch
);
1302 pRes
= pModule
->Find( rName
, t
);
1303 pModule
->SetFlag( nGblFlag
);
1311 OUString
aMainStr("Main");
1312 if( !pRes
&& pNamed
&& ( t
== SbxClassType::Method
|| t
== SbxClassType::DontCare
) &&
1313 !pNamed
->GetName().equalsIgnoreAsciiCase( aMainStr
) )
1315 pRes
= pNamed
->Find( aMainStr
, SbxClassType::Method
);
1319 pRes
= SbxObject::Find( rName
, t
);
1324 bool StarBASIC::Call( const OUString
& rName
, SbxArray
* pParam
)
1326 bool bRes
= SbxObject::Call( rName
, pParam
);
1329 ErrCode eErr
= SbxBase::GetError();
1330 SbxBase::ResetError();
1331 if( eErr
!= ERRCODE_NONE
)
1333 RTError( eErr
, OUString(), 0, 0, 0 );
1339 // Find method via name (e.g. query via BASIC IDE)
1340 SbxBase
* StarBASIC::FindSBXInCurrentScope( const OUString
& rName
)
1342 if( !GetSbData()->pInst
)
1346 if( !GetSbData()->pInst
->pRun
)
1350 return GetSbData()->pInst
->pRun
->FindElementExtern( rName
);
1353 void StarBASIC::QuitAndExitApplication()
1359 void StarBASIC::Stop()
1361 SbiInstance
* p
= GetSbData()->pInst
;
1366 bool StarBASIC::IsRunning()
1368 return GetSbData()->pInst
!= nullptr;
1371 SbMethod
* StarBASIC::GetActiveMethod( sal_uInt16 nLevel
)
1373 if( GetSbData()->pInst
)
1375 return GetSbData()->pInst
->GetCaller( nLevel
);
1383 SbModule
* StarBASIC::GetActiveModule()
1385 if( GetSbData()->pInst
&& !GetSbData()->bCompilerError
)
1387 return GetSbData()->pInst
->GetActiveModule();
1391 return GetSbData()->pCompMod
;
1395 BasicDebugFlags
StarBASIC::BreakPoint( sal_Int32 l
, sal_Int32 c1
, sal_Int32 c2
)
1397 SetErrorData( ERRCODE_NONE
, l
, c1
, c2
);
1399 if( GetSbData()->aBreakHdl
.IsSet() )
1401 return GetSbData()->aBreakHdl
.Call( this );
1409 BasicDebugFlags
StarBASIC::StepPoint( sal_Int32 l
, sal_Int32 c1
, sal_Int32 c2
)
1411 SetErrorData( ERRCODE_NONE
, l
, c1
, c2
);
1413 if( GetSbData()->aBreakHdl
.IsSet() )
1415 return GetSbData()->aBreakHdl
.Call( this );
1423 BasicDebugFlags
StarBASIC::BreakHdl()
1425 return aBreakHdl
.IsSet() ? aBreakHdl
.Call( this ) : BasicDebugFlags::Continue
;
1428 // Calls for error handler and break handler
1429 sal_uInt16
StarBASIC::GetLine() { return GetSbData()->nLine
; }
1430 sal_uInt16
StarBASIC::GetCol1() { return GetSbData()->nCol1
; }
1431 sal_uInt16
StarBASIC::GetCol2() { return GetSbData()->nCol2
; }
1433 // Specific to error handler
1434 ErrCode
const & StarBASIC::GetErrorCode() { return GetSbData()->nCode
; }
1435 const OUString
& StarBASIC::GetErrorText() { return GetSbData()->aErrMsg
; }
1438 // The mapping between the old and the new error codes take place by searching
1439 // through the table SFX_VB_ErrorTab[]. This is indeed not with good performance,
1440 // but it consumes much less memory than corresponding switch blocks.
1441 // Because the conversion of error codes has not to be fast. There is no
1442 // binary search by VB Error -> Error SFX.
1444 // Map back new error codes to old, Sbx-compatible
1445 sal_uInt16
StarBASIC::GetVBErrorCode( ErrCode nError
)
1447 sal_uInt16 nRet
= 0;
1449 if( SbiRuntime::isVBAEnabled() )
1451 if ( nError
== ERRCODE_BASIC_ARRAY_FIX
)
1453 else if ( nError
== ERRCODE_BASIC_STRING_OVERFLOW
)
1455 else if ( nError
== ERRCODE_BASIC_EXPR_TOO_COMPLEX
)
1457 else if ( nError
== ERRCODE_BASIC_OPER_NOT_PERFORM
)
1459 else if ( nError
== ERRCODE_BASIC_TOO_MANY_DLL
)
1461 else if ( nError
== ERRCODE_BASIC_LOOP_NOT_INIT
)
1468 const SFX_VB_ErrorItem
* pErrItem
;
1469 sal_uInt16 nIndex
= 0;
1472 pErrItem
= SFX_VB_ErrorTab
+ nIndex
;
1473 if( pErrItem
->nErrorSFX
== nError
)
1475 nRet
= pErrItem
->nErrorVB
;
1480 while( pErrItem
->nErrorVB
!= 0xFFFF ); // up to end mark
1484 ErrCode
StarBASIC::GetSfxFromVBError( sal_uInt16 nError
)
1486 ErrCode nRet
= ERRCODE_NONE
;
1488 if( SbiRuntime::isVBAEnabled() )
1498 return ERRCODE_NONE
;
1500 return ERRCODE_BASIC_ARRAY_FIX
;
1502 return ERRCODE_BASIC_STRING_OVERFLOW
;
1504 return ERRCODE_BASIC_EXPR_TOO_COMPLEX
;
1506 return ERRCODE_BASIC_OPER_NOT_PERFORM
;
1508 return ERRCODE_BASIC_TOO_MANY_DLL
;
1510 return ERRCODE_BASIC_LOOP_NOT_INIT
;
1512 nRet
= ERRCODE_NONE
;
1515 const SFX_VB_ErrorItem
* pErrItem
;
1516 sal_uInt16 nIndex
= 0;
1519 pErrItem
= SFX_VB_ErrorTab
+ nIndex
;
1520 if( pErrItem
->nErrorVB
== nError
)
1522 nRet
= pErrItem
->nErrorSFX
;
1525 else if( pErrItem
->nErrorVB
> nError
)
1527 break; // couldn't found anymore
1531 while( pErrItem
->nErrorVB
!= 0xFFFF ); // up to end mark
1535 // set Error- / Break-data
1536 void StarBASIC::SetErrorData( ErrCode nCode
, sal_uInt16 nLine
,
1537 sal_uInt16 nCol1
, sal_uInt16 nCol2
)
1539 SbiGlobals
& aGlobals
= *GetSbData();
1540 aGlobals
.nCode
= nCode
;
1541 aGlobals
.nLine
= nLine
;
1542 aGlobals
.nCol1
= nCol1
;
1543 aGlobals
.nCol2
= nCol2
;
1546 void StarBASIC::MakeErrorText( ErrCode nId
, std::u16string_view aMsg
)
1548 SolarMutexGuard aSolarGuard
;
1549 sal_uInt16 nOldID
= GetVBErrorCode( nId
);
1551 TranslateId pErrorMsg
;
1552 for (std::pair
<TranslateId
, ErrCode
> const *pItem
= RID_BASIC_START
; pItem
->second
; ++pItem
)
1554 if (nId
== pItem
->second
)
1556 pErrorMsg
= pItem
->first
;
1563 // merge message with additional text
1564 OUString sError
= BasResId(pErrorMsg
);
1565 OUStringBuffer
aMsg1(sError
);
1566 // replace argument placeholder with %s
1567 OUString
aSrgStr( "$(ARG1)" );
1568 sal_Int32 nResult
= sError
.indexOf(aSrgStr
);
1572 aMsg1
.remove(nResult
, aSrgStr
.getLength());
1573 aMsg1
.insert(nResult
, aMsg
);
1575 else if (!aMsg
.empty())
1577 // tdf#123144 - create a meaningful error message
1578 aMsg1
= BasResId(STR_ADDITIONAL_INFO
)
1579 .replaceFirst("$ERR", aMsg1
)
1580 .replaceFirst("$MSG", aMsg
);
1582 GetSbData()->aErrMsg
= aMsg1
.makeStringAndClear();
1584 // tdf#123144 - don't use an artificial error message if there is a custom one
1585 else if (!aMsg
.empty())
1587 GetSbData()->aErrMsg
= aMsg
;
1589 else if( nOldID
!= 0 )
1591 OUString aStdMsg
= "Error " + OUString::number(nOldID
) +
1592 ": No error text available!";
1593 GetSbData()->aErrMsg
= aStdMsg
;
1597 GetSbData()->aErrMsg
.clear();
1601 bool StarBASIC::CError( ErrCode code
, const OUString
& rMsg
,
1602 sal_Int32 l
, sal_Int32 c1
, sal_Int32 c2
)
1604 SolarMutexGuard aSolarGuard
;
1606 // compiler error during runtime -> stop program
1609 // #109018 Check if running Basic is affected
1610 StarBASIC
* pStartedBasic
= GetSbData()->pInst
->GetBasic();
1611 if( pStartedBasic
!= this )
1618 // set flag, so that GlobalRunInit notice the error
1619 GetSbData()->bGlobalInitErr
= true;
1621 // tinker the error message
1622 MakeErrorText( code
, rMsg
);
1624 // Implementation of the code for the string transport to SFX-Error
1625 if( !rMsg
.isEmpty() )
1627 code
= *new StringErrorInfo( code
, rMsg
);
1629 SetErrorData( code
, l
, c1
, c2
);
1630 GetSbData()->bCompilerError
= true;
1632 if( GetSbData()->aErrHdl
.IsSet() )
1634 bRet
= GetSbData()->aErrHdl
.Call( this );
1640 GetSbData()->bCompilerError
= false; // only true for error handler
1644 bool StarBASIC::RTError( ErrCode code
, const OUString
& rMsg
, sal_Int32 l
, sal_Int32 c1
, sal_Int32 c2
)
1646 SolarMutexGuard aSolarGuard
;
1649 if( c
.GetClass() == ErrCodeClass::Compiler
)
1653 MakeErrorText( c
, rMsg
);
1655 // Implementation of the code for the string transport to SFX-Error
1656 if( !rMsg
.isEmpty() )
1658 // very confusing, even though MakeErrorText sets up the error text
1659 // seems that this is not used ( if rMsg already has content )
1660 // In the case of VBA MakeErrorText also formats the error to be a little more
1661 // like vba ( adds an error number etc )
1662 if ( SbiRuntime::isVBAEnabled() && ( code
== ERRCODE_BASIC_COMPAT
) )
1664 OUString aTmp
= "\'" + OUString::number(SbxErrObject::getUnoErrObject()->getNumber()) +
1665 "\'\n" + (!GetSbData()->aErrMsg
.isEmpty() ? GetSbData()->aErrMsg
: rMsg
);
1666 code
= *new StringErrorInfo( code
, aTmp
);
1670 code
= *new StringErrorInfo( code
, rMsg
);
1674 SetErrorData( code
, l
, c1
, c2
);
1675 if( GetSbData()->aErrHdl
.IsSet() )
1677 return GetSbData()->aErrHdl
.Call( this );
1685 void StarBASIC::Error( ErrCode n
)
1687 Error( n
, OUString() );
1690 void StarBASIC::Error( ErrCode n
, const OUString
& rMsg
)
1692 if( GetSbData()->pInst
)
1694 GetSbData()->pInst
->Error( n
, rMsg
);
1698 void StarBASIC::FatalError( ErrCode n
)
1700 if( GetSbData()->pInst
)
1702 GetSbData()->pInst
->FatalError( n
);
1706 void StarBASIC::FatalError( ErrCode _errCode
, const OUString
& _details
)
1708 if( GetSbData()->pInst
)
1710 GetSbData()->pInst
->FatalError( _errCode
, _details
);
1714 ErrCode
StarBASIC::GetErrBasic()
1716 if( GetSbData()->pInst
)
1718 return GetSbData()->pInst
->GetErr();
1722 return ERRCODE_NONE
;
1726 // make the additional message for the RTL function error accessible
1727 OUString
StarBASIC::GetErrorMsg()
1729 if( GetSbData()->pInst
)
1731 return GetSbData()->pInst
->GetErrorMsg();
1739 sal_Int32
StarBASIC::GetErl()
1741 if( GetSbData()->pInst
)
1743 return GetSbData()->pInst
->GetErl();
1751 bool StarBASIC::ErrorHdl()
1753 return aErrorHdl
.Call( this );
1756 Link
<StarBASIC
*,bool> const & StarBASIC::GetGlobalErrorHdl()
1758 return GetSbData()->aErrHdl
;
1761 void StarBASIC::SetGlobalErrorHdl( const Link
<StarBASIC
*,bool>& rLink
)
1763 GetSbData()->aErrHdl
= rLink
;
1766 void StarBASIC::SetGlobalBreakHdl( const Link
<StarBASIC
*,BasicDebugFlags
>& rLink
)
1768 GetSbData()->aBreakHdl
= rLink
;
1771 SbxArrayRef
const & StarBASIC::getUnoListeners()
1773 if( !xUnoListeners
.is() )
1775 xUnoListeners
= new SbxArray();
1777 return xUnoListeners
;
1781 bool StarBASIC::LoadData( SvStream
& r
, sal_uInt16 nVer
)
1783 if( !SbxObject::LoadData( r
, nVer
) )
1787 // #95459 Delete dialogs, otherwise endless recursion
1788 // in SbxVariable::GetType() if dialogs are accessed
1789 sal_uInt32 nObjCount
= pObjs
->Count();
1790 std::unique_ptr
<SbxVariable
*[]> ppDeleteTab(new SbxVariable
*[ nObjCount
]);
1793 for( nObj
= 0 ; nObj
< nObjCount
; nObj
++ )
1795 SbxVariable
* pVar
= pObjs
->Get(nObj
);
1796 StarBASIC
* pBasic
= dynamic_cast<StarBASIC
*>( pVar
);
1797 ppDeleteTab
[nObj
] = pBasic
? nullptr : pVar
;
1799 for( nObj
= 0 ; nObj
< nObjCount
; nObj
++ )
1801 SbxVariable
* pVar
= ppDeleteTab
[nObj
];
1804 pObjs
->Remove( pVar
);
1807 ppDeleteTab
.reset();
1811 r
.ReadUInt16( nMod
);
1812 const size_t nMinSbxSize(14);
1813 const size_t nMaxPossibleEntries
= r
.remainingSize() / nMinSbxSize
;
1814 if (nMod
> nMaxPossibleEntries
)
1816 nMod
= nMaxPossibleEntries
;
1817 SAL_WARN("basic", "Parsing error: " << nMaxPossibleEntries
<<
1818 " max possible entries, but " << nMod
<< " claimed, truncating");
1820 for (sal_uInt16 i
= 0; i
< nMod
; ++i
)
1822 SbxBaseRef pBase
= SbxBase::Load( r
);
1823 SbModule
* pMod
= dynamic_cast<SbModule
*>(pBase
.get());
1828 else if( dynamic_cast<const SbJScriptModule
*>( pMod
) != nullptr )
1830 // assign Ref, so that pMod will be deleted
1831 SbModuleRef xDeleteRef
= pMod
;
1835 pMod
->SetParent( this );
1836 pModules
.emplace_back(pMod
);
1839 // HACK for SFX-Bullshit!
1840 SbxVariable
* p
= Find( "FALSE", SbxClassType::Property
);
1845 p
= Find( "TRUE", SbxClassType::Property
);
1850 // End of the hacks!
1851 // Search via StarBASIC is at all times global
1852 DBG_ASSERT( IsSet( SbxFlagBits::GlobalSearch
), "Basic loaded without GBLSEARCH" );
1853 SetFlag( SbxFlagBits::GlobalSearch
);
1857 bool StarBASIC::StoreData( SvStream
& r
) const
1859 if( !SbxObject::StoreData( r
) )
1863 assert(pModules
.size() < SAL_MAX_UINT16
);
1864 r
.WriteUInt16( static_cast<sal_uInt16
>(pModules
.size()));
1865 for( const auto& rpModule
: pModules
)
1867 if( !rpModule
->Store( r
) )
1875 bool StarBASIC::GetUNOConstant( const OUString
& rName
, css::uno::Any
& aOut
)
1878 SbUnoObject
* pGlobs
= dynamic_cast<SbUnoObject
*>( Find( rName
, SbxClassType::DontCare
) );
1881 aOut
= pGlobs
->getUnoAny();
1887 Reference
< frame::XModel
> StarBASIC::GetModelFromBasic( SbxObject
* pBasic
)
1889 OSL_PRECOND( pBasic
!= nullptr, "getModelFromBasic: illegal call!" );
1894 // look for the ThisComponent variable, first in the parent (which
1895 // might be the document's Basic), then in the parent's parent (which might be
1896 // the application Basic)
1897 static const OUStringLiteral
sThisComponent( u
"ThisComponent");
1898 SbxVariable
* pThisComponent
= nullptr;
1900 SbxObject
* pLookup
= pBasic
->GetParent();
1901 while ( pLookup
&& !pThisComponent
)
1903 pThisComponent
= pLookup
->Find( sThisComponent
, SbxClassType::Object
);
1904 pLookup
= pLookup
->GetParent();
1906 if ( !pThisComponent
)
1908 SAL_WARN("basic", "Failed to get ThisComponent");
1909 // the application Basic, at the latest, should have this variable
1913 Any
aThisComponentAny( sbxToUnoValue( pThisComponent
) );
1914 Reference
< frame::XModel
> xModel( aThisComponentAny
, UNO_QUERY
);
1917 // it's no XModel. Okay, ThisComponent nowadays is allowed to be a controller.
1918 Reference
< frame::XController
> xController( aThisComponentAny
, UNO_QUERY
);
1919 if ( xController
.is() )
1921 xModel
= xController
->getModel();
1932 void StarBASIC::DetachAllDocBasicItems()
1934 for (auto const& item
: gaDocBasicItems
)
1936 DocBasicItemRef xItem
= item
.second
;
1937 xItem
->setDisposed(true);
1941 // #118116 Implementation Collection object
1944 constexpr OUStringLiteral pCountStr
= u
"Count";
1945 constexpr OUStringLiteral pAddStr
= u
"Add";
1946 constexpr OUStringLiteral pItemStr
= u
"Item";
1947 constexpr OUStringLiteral pRemoveStr
= u
"Remove";
1948 constexpr sal_uInt16 nCountHash
= SbxVariable::MakeHashCode(pCountStr
);
1949 constexpr sal_uInt16 nAddHash
= SbxVariable::MakeHashCode(pAddStr
);
1950 constexpr sal_uInt16 nItemHash
= SbxVariable::MakeHashCode(pItemStr
);
1951 constexpr sal_uInt16 nRemoveHash
= SbxVariable::MakeHashCode(pRemoveStr
);
1953 SbxInfoRef
BasicCollection::xAddInfo
;
1954 SbxInfoRef
BasicCollection::xItemInfo
;
1956 BasicCollection::BasicCollection( const OUString
& rClass
)
1957 : SbxObject( rClass
)
1962 BasicCollection::~BasicCollection()
1965 void BasicCollection::Clear()
1971 void BasicCollection::Initialize()
1973 xItemArray
= new SbxArray();
1974 SetType( SbxOBJECT
);
1975 SetFlag( SbxFlagBits::Fixed
);
1976 ResetFlag( SbxFlagBits::Write
);
1978 p
= Make( pCountStr
, SbxClassType::Property
, SbxINTEGER
);
1979 p
->ResetFlag( SbxFlagBits::Write
);
1980 p
->SetFlag( SbxFlagBits::DontStore
);
1981 p
= Make( pAddStr
, SbxClassType::Method
, SbxEMPTY
);
1982 p
->SetFlag( SbxFlagBits::DontStore
);
1983 p
= Make( pItemStr
, SbxClassType::Method
, SbxVARIANT
);
1984 p
->SetFlag( SbxFlagBits::DontStore
);
1985 p
= Make( pRemoveStr
, SbxClassType::Method
, SbxEMPTY
);
1986 p
->SetFlag( SbxFlagBits::DontStore
);
1987 if ( !xAddInfo
.is() )
1989 xAddInfo
= new SbxInfo
;
1990 xAddInfo
->AddParam( "Item", SbxVARIANT
);
1991 xAddInfo
->AddParam( "Key", SbxVARIANT
, SbxFlagBits::Read
| SbxFlagBits::Optional
);
1992 xAddInfo
->AddParam( "Before", SbxVARIANT
, SbxFlagBits::Read
| SbxFlagBits::Optional
);
1993 xAddInfo
->AddParam( "After", SbxVARIANT
, SbxFlagBits::Read
| SbxFlagBits::Optional
);
1995 if ( !xItemInfo
.is() )
1997 xItemInfo
= new SbxInfo
;
1998 xItemInfo
->AddParam( "Index", SbxVARIANT
, SbxFlagBits::Read
| SbxFlagBits::Optional
);
2002 void BasicCollection::Notify( SfxBroadcaster
& rCst
, const SfxHint
& rHint
)
2004 const SbxHint
* p
= dynamic_cast<const SbxHint
*>(&rHint
);
2007 const SfxHintId nId
= p
->GetId();
2008 bool bRead
= nId
== SfxHintId::BasicDataWanted
;
2009 bool bWrite
= nId
== SfxHintId::BasicDataChanged
;
2010 bool bRequestInfo
= nId
== SfxHintId::BasicInfoWanted
;
2011 SbxVariable
* pVar
= p
->GetVar();
2012 SbxArray
* pArg
= pVar
->GetParameters();
2013 OUString
aVarName( pVar
->GetName() );
2014 if( bRead
|| bWrite
)
2016 if( pVar
->GetHashCode() == nCountHash
2017 && aVarName
.equalsIgnoreAsciiCase( pCountStr
) )
2019 pVar
->PutLong(xItemArray
->Count());
2021 else if( pVar
->GetHashCode() == nAddHash
2022 && aVarName
.equalsIgnoreAsciiCase( pAddStr
) )
2026 else if( pVar
->GetHashCode() == nItemHash
2027 && aVarName
.equalsIgnoreAsciiCase( pItemStr
) )
2031 else if( pVar
->GetHashCode() == nRemoveHash
2032 && aVarName
.equalsIgnoreAsciiCase( pRemoveStr
) )
2038 SbxObject::Notify( rCst
, rHint
);
2042 else if ( bRequestInfo
)
2044 if( pVar
->GetHashCode() == nAddHash
2045 && aVarName
.equalsIgnoreAsciiCase( pAddStr
) )
2047 pVar
->SetInfo( xAddInfo
.get() );
2049 else if( pVar
->GetHashCode() == nItemHash
2050 && aVarName
.equalsIgnoreAsciiCase( pItemStr
) )
2052 pVar
->SetInfo( xItemInfo
.get() );
2056 SbxObject::Notify( rCst
, rHint
);
2059 sal_Int32
BasicCollection::implGetIndex( SbxVariable
const * pIndexVar
)
2061 sal_Int32 nIndex
= -1;
2062 if( pIndexVar
->GetType() == SbxSTRING
)
2064 nIndex
= implGetIndexForName( pIndexVar
->GetOUString() );
2068 nIndex
= pIndexVar
->GetLong() - 1;
2073 sal_Int32
BasicCollection::implGetIndexForName(std::u16string_view rName
)
2075 sal_Int32 nIndex
= -1;
2076 sal_Int32 nCount
= xItemArray
->Count();
2077 sal_Int32 nNameHash
= MakeHashCode( rName
);
2079 // tdf#144245 - case-insensitive operation for non-ASCII characters
2080 utl::TransliterationWrapper
& rTransliteration
= SbGlobal::GetTransliteration();
2082 for( sal_Int32 i
= 0 ; i
< nCount
; i
++ )
2084 SbxVariable
* pVar
= xItemArray
->Get(i
);
2085 if (pVar
->GetHashCode() == nNameHash
2086 && rTransliteration
.isEqual(pVar
->GetName(), OUString(rName
)))
2095 void BasicCollection::CollAdd( SbxArray
* pPar_
)
2097 sal_uInt32 nCount
= pPar_
->Count();
2098 if( nCount
< 2 || nCount
> 5 )
2100 SetError( ERRCODE_BASIC_WRONG_ARGS
);
2104 SbxVariable
* pItem
= pPar_
->Get(1);
2107 sal_uInt32 nNextIndex
;
2110 nNextIndex
= xItemArray
->Count();
2114 SbxVariable
* pBefore
= pPar_
->Get(3);
2117 if( !( pBefore
->IsErr() || ( pBefore
->GetType() == SbxEMPTY
) ) )
2119 SetError( ERRCODE_BASIC_BAD_ARGUMENT
);
2122 SbxVariable
* pAfter
= pPar_
->Get(4);
2123 sal_Int32 nAfterIndex
= implGetIndex( pAfter
);
2124 if( nAfterIndex
== -1 )
2126 SetError( ERRCODE_BASIC_BAD_ARGUMENT
);
2129 nNextIndex
= sal::static_int_cast
<sal_uInt32
>(nAfterIndex
+ 1);
2131 else // if( nCount == 4 )
2133 sal_Int32 nBeforeIndex
= implGetIndex( pBefore
);
2134 if( nBeforeIndex
== -1 )
2136 SetError( ERRCODE_BASIC_BAD_ARGUMENT
);
2139 nNextIndex
= sal::static_int_cast
<sal_uInt32
>(nBeforeIndex
);
2143 auto pNewItem
= tools::make_ref
<SbxVariable
>( *pItem
);
2146 SbxVariable
* pKey
= pPar_
->Get(2);
2147 if( !( pKey
->IsErr() || ( pKey
->GetType() == SbxEMPTY
) ) )
2149 if( pKey
->GetType() != SbxSTRING
)
2151 SetError( ERRCODE_BASIC_BAD_ARGUMENT
);
2154 OUString aKey
= pKey
->GetOUString();
2155 if( implGetIndexForName( aKey
) != -1 )
2157 SetError( ERRCODE_BASIC_BAD_ARGUMENT
);
2160 pNewItem
->SetName( aKey
);
2163 pNewItem
->SetFlag( SbxFlagBits::ReadWrite
);
2164 xItemArray
->Insert(pNewItem
.get(), nNextIndex
);
2168 SetError( ERRCODE_BASIC_BAD_ARGUMENT
);
2173 void BasicCollection::CollItem( SbxArray
* pPar_
)
2175 if (pPar_
->Count() != 2)
2177 SetError( ERRCODE_BASIC_WRONG_ARGS
);
2180 SbxVariable
* pRes
= nullptr;
2181 SbxVariable
* p
= pPar_
->Get(1);
2182 sal_Int32 nIndex
= implGetIndex( p
);
2183 if (nIndex
>= 0 && nIndex
< static_cast<sal_Int32
>(xItemArray
->Count()))
2185 pRes
= xItemArray
->Get(nIndex
);
2189 SetError( ERRCODE_BASIC_BAD_ARGUMENT
);
2193 *(pPar_
->Get(0)) = *pRes
;
2197 void BasicCollection::CollRemove( SbxArray
* pPar_
)
2199 if (pPar_
== nullptr || pPar_
->Count() != 2)
2201 SetError( ERRCODE_BASIC_WRONG_ARGS
);
2205 SbxVariable
* p
= pPar_
->Get(1);
2206 sal_Int32 nIndex
= implGetIndex( p
);
2207 if (nIndex
>= 0 && nIndex
< static_cast<sal_Int32
>(xItemArray
->Count()))
2209 xItemArray
->Remove( nIndex
);
2211 // Correct for stack if necessary
2212 SbiInstance
* pInst
= GetSbData()->pInst
;
2213 SbiRuntime
* pRT
= pInst
? pInst
->pRun
: nullptr;
2216 SbiForStack
* pStack
= pRT
->FindForStackItemForCollection( this );
2217 if( pStack
!= nullptr )
2219 if( pStack
->nCurCollectionIndex
>= nIndex
)
2221 --pStack
->nCurCollectionIndex
;
2228 SetError( ERRCODE_BASIC_BAD_ARGUMENT
);
2232 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */