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 <tools/stream.hxx>
22 #include <tools/debug.hxx>
23 #include <vcl/errinf.hxx>
24 #include <comphelper/solarmutex.hxx>
25 #include <basic/sbx.hxx>
26 #include <vcl/svapp.hxx>
27 #include <comphelper/processfactory.hxx>
29 #include <sbunoobj.hxx>
30 #include <sbjsmeth.hxx>
31 #include <sbjsmod.hxx>
32 #include <sbintern.hxx>
33 #include <runtime.hxx>
34 #include <basic/sberrors.hxx>
35 #include <basic/sbuno.hxx>
37 #include <sbobjmod.hxx>
40 #include <cppuhelper/implbase.hxx>
41 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
42 #include <com/sun/star/util/XCloseBroadcaster.hpp>
43 #include <com/sun/star/util/XCloseListener.hpp>
44 #include <sal/log.hxx>
45 #include <errobject.hxx>
47 #include <unordered_map>
49 #include <com/sun/star/script/ModuleType.hpp>
50 #include <com/sun/star/script/ModuleInfo.hpp>
52 using namespace ::com::sun::star::script
;
55 #define RTLNAME "@SBRTL"
57 using namespace ::com::sun::star
;
58 using namespace ::com::sun::star::uno
;
59 using com::sun::star::uno::Reference
;
60 using com::sun::star::uno::Any
;
61 using com::sun::star::uno::UNO_QUERY
;
62 using com::sun::star::lang::XMultiServiceFactory
;
65 class DocBasicItem
: public ::cppu::WeakImplHelper
< util::XCloseListener
>
68 explicit DocBasicItem( StarBASIC
& rDocBasic
);
69 virtual ~DocBasicItem() override
;
71 const SbxObjectRef
& getClassModules() const { return mxClassModules
; }
72 bool isDocClosed() const { return mbDocClosed
; }
74 void clearDependingVarsOnDelete( StarBASIC
& rDeletedBasic
);
76 void startListening();
79 void setDisposed( bool bDisposed
)
81 mbDisposed
= bDisposed
;
84 virtual void SAL_CALL
queryClosing( const lang::EventObject
& rSource
, sal_Bool bGetsOwnership
) override
;
85 virtual void SAL_CALL
notifyClosing( const lang::EventObject
& rSource
) override
;
86 virtual void SAL_CALL
disposing( const lang::EventObject
& rSource
) override
;
89 StarBASIC
& mrDocBasic
;
90 SbxObjectRef mxClassModules
;
96 DocBasicItem::DocBasicItem( StarBASIC
& rDocBasic
) :
97 mrDocBasic( rDocBasic
),
98 mxClassModules( new SbxObject( OUString() ) ),
104 DocBasicItem::~DocBasicItem()
106 // tdf#90969 HACK: don't use SolarMutexGuard - there is a horrible global
107 // map GaDocBasicItems holding instances, and these get deleted from exit
108 // handlers, when the SolarMutex is already dead
109 comphelper::SolarMutex
*pSolarMutex
= comphelper::SolarMutex::get();
111 pSolarMutex
->acquire();
116 mxClassModules
.clear(); // release with SolarMutex locked
123 pSolarMutex
= comphelper::SolarMutex::get();
125 pSolarMutex
->release();
128 void DocBasicItem::clearDependingVarsOnDelete( StarBASIC
& rDeletedBasic
)
130 mrDocBasic
.implClearDependingVarsOnDelete( &rDeletedBasic
);
133 void DocBasicItem::startListening()
136 mrDocBasic
.GetUNOConstant( "ThisComponent", aThisComp
);
137 Reference
< util::XCloseBroadcaster
> xCloseBC( aThisComp
, UNO_QUERY
);
138 mbDisposed
= !xCloseBC
.is();
141 try { xCloseBC
->addCloseListener( this ); } catch(const uno::Exception
& ) {}
145 void DocBasicItem::stopListening()
147 if( mbDisposed
) return;
150 if (!mrDocBasic
.GetUNOConstant("ThisComponent", aThisComp
))
153 Reference
< util::XCloseBroadcaster
> xCloseBC( aThisComp
, UNO_QUERY
);
156 try { xCloseBC
->removeCloseListener( this ); } catch(const uno::Exception
& ) {}
160 void SAL_CALL
DocBasicItem::queryClosing( const lang::EventObject
& /*rSource*/, sal_Bool
/*bGetsOwnership*/ )
164 void SAL_CALL
DocBasicItem::notifyClosing( const lang::EventObject
& /*rEvent*/ )
170 void SAL_CALL
DocBasicItem::disposing( const lang::EventObject
& /*rEvent*/ )
178 typedef ::rtl::Reference
< DocBasicItem
> DocBasicItemRef
;
180 class GaDocBasicItems
: public rtl::Static
<std::unordered_map
< const StarBASIC
*, DocBasicItemRef
>,GaDocBasicItems
> {};
182 const DocBasicItem
* lclFindDocBasicItem( const StarBASIC
* pDocBasic
)
184 auto it
= GaDocBasicItems::get().find( pDocBasic
);
185 auto end
= GaDocBasicItems::get().end();
186 return (it
!= end
) ? it
->second
.get() : nullptr;
189 void lclInsertDocBasicItem( StarBASIC
& rDocBasic
)
191 DocBasicItemRef
& rxDocBasicItem
= GaDocBasicItems::get()[ &rDocBasic
];
192 rxDocBasicItem
.set( new DocBasicItem( rDocBasic
) );
193 rxDocBasicItem
->startListening();
196 void lclRemoveDocBasicItem( StarBASIC
& rDocBasic
)
198 auto it
= GaDocBasicItems::get().find( &rDocBasic
);
199 if( it
!= GaDocBasicItems::get().end() )
201 it
->second
->stopListening();
202 GaDocBasicItems::get().erase( it
);
204 for( auto& rEntry
: GaDocBasicItems::get() )
206 rEntry
.second
->clearDependingVarsOnDelete( rDocBasic
);
210 StarBASIC
* lclGetDocBasicForModule( SbModule
* pModule
)
212 StarBASIC
* pRetBasic
= nullptr;
213 SbxObject
* pCurParent
= pModule
;
214 while( pCurParent
->GetParent() != nullptr )
216 pCurParent
= pCurParent
->GetParent();
217 StarBASIC
* pDocBasic
= dynamic_cast<StarBASIC
*>( pCurParent
);
218 if( pDocBasic
!= nullptr && pDocBasic
->IsDocBasic() )
220 pRetBasic
= pDocBasic
;
230 SbxObject
* StarBASIC::getVBAGlobals( )
232 if ( !pVBAGlobals
.is() )
235 if ( GetUNOConstant("ThisComponent", aThisDoc
) )
237 Reference
< XMultiServiceFactory
> xDocFac( aThisDoc
, UNO_QUERY
);
242 xDocFac
->createInstance("ooo.vba.VBAGlobals");
244 catch(const Exception
& )
250 const OUString
aVBAHook("VBAGlobals");
251 pVBAGlobals
= static_cast<SbUnoObject
*>(Find( aVBAHook
, SbxClassType::DontCare
));
253 return pVBAGlobals
.get();
257 SbxVariable
* StarBASIC::VBAFind( const OUString
& rName
, SbxClassType t
)
259 if( rName
== "ThisComponent" )
263 // rename to init globals
264 if ( getVBAGlobals( ) )
266 return pVBAGlobals
->Find( rName
, t
);
271 // Create array for conversion SFX <-> VB error code
272 struct SFX_VB_ErrorItem
278 const SFX_VB_ErrorItem SFX_VB_ErrorTab
[] =
280 { 1, ERRCODE_BASIC_EXCEPTION
}, // #87844 Map exception to error code 1
281 { 2, ERRCODE_BASIC_SYNTAX
},
282 { 3, ERRCODE_BASIC_NO_GOSUB
},
283 { 4, ERRCODE_BASIC_REDO_FROM_START
},
284 { 5, ERRCODE_BASIC_BAD_ARGUMENT
},
285 { 6, ERRCODE_BASIC_MATH_OVERFLOW
},
286 { 7, ERRCODE_BASIC_NO_MEMORY
},
287 { 8, ERRCODE_BASIC_ALREADY_DIM
},
288 { 9, ERRCODE_BASIC_OUT_OF_RANGE
},
289 { 10, ERRCODE_BASIC_DUPLICATE_DEF
},
290 { 11, ERRCODE_BASIC_ZERODIV
},
291 { 12, ERRCODE_BASIC_VAR_UNDEFINED
},
292 { 13, ERRCODE_BASIC_CONVERSION
},
293 { 14, ERRCODE_BASIC_BAD_PARAMETER
},
294 { 18, ERRCODE_BASIC_USER_ABORT
},
295 { 20, ERRCODE_BASIC_BAD_RESUME
},
296 { 28, ERRCODE_BASIC_STACK_OVERFLOW
},
297 { 35, ERRCODE_BASIC_PROC_UNDEFINED
},
298 { 48, ERRCODE_BASIC_BAD_DLL_LOAD
},
299 { 49, ERRCODE_BASIC_BAD_DLL_CALL
},
300 { 51, ERRCODE_BASIC_INTERNAL_ERROR
},
301 { 52, ERRCODE_BASIC_BAD_CHANNEL
},
302 { 53, ERRCODE_BASIC_FILE_NOT_FOUND
},
303 { 54, ERRCODE_BASIC_BAD_FILE_MODE
},
304 { 55, ERRCODE_BASIC_FILE_ALREADY_OPEN
},
305 { 57, ERRCODE_BASIC_IO_ERROR
},
306 { 58, ERRCODE_BASIC_FILE_EXISTS
},
307 { 59, ERRCODE_BASIC_BAD_RECORD_LENGTH
},
308 { 61, ERRCODE_BASIC_DISK_FULL
},
309 { 62, ERRCODE_BASIC_READ_PAST_EOF
},
310 { 63, ERRCODE_BASIC_BAD_RECORD_NUMBER
},
311 { 67, ERRCODE_BASIC_TOO_MANY_FILES
},
312 { 68, ERRCODE_BASIC_NO_DEVICE
},
313 { 70, ERRCODE_BASIC_ACCESS_DENIED
},
314 { 71, ERRCODE_BASIC_NOT_READY
},
315 { 73, ERRCODE_BASIC_NOT_IMPLEMENTED
},
316 { 74, ERRCODE_BASIC_DIFFERENT_DRIVE
},
317 { 75, ERRCODE_BASIC_ACCESS_ERROR
},
318 { 76, ERRCODE_BASIC_PATH_NOT_FOUND
},
319 { 91, ERRCODE_BASIC_NO_OBJECT
},
320 { 93, ERRCODE_BASIC_BAD_PATTERN
},
321 { 94, ERRCODE_BASIC_IS_NULL
},
322 { 250, ERRCODE_BASIC_DDE_ERROR
},
323 { 280, ERRCODE_BASIC_DDE_WAITINGACK
},
324 { 281, ERRCODE_BASIC_DDE_OUTOFCHANNELS
},
325 { 282, ERRCODE_BASIC_DDE_NO_RESPONSE
},
326 { 283, ERRCODE_BASIC_DDE_MULT_RESPONSES
},
327 { 284, ERRCODE_BASIC_DDE_CHANNEL_LOCKED
},
328 { 285, ERRCODE_BASIC_DDE_NOTPROCESSED
},
329 { 286, ERRCODE_BASIC_DDE_TIMEOUT
},
330 { 287, ERRCODE_BASIC_DDE_USER_INTERRUPT
},
331 { 288, ERRCODE_BASIC_DDE_BUSY
},
332 { 289, ERRCODE_BASIC_DDE_NO_DATA
},
333 { 290, ERRCODE_BASIC_DDE_WRONG_DATA_FORMAT
},
334 { 291, ERRCODE_BASIC_DDE_PARTNER_QUIT
},
335 { 292, ERRCODE_BASIC_DDE_CONV_CLOSED
},
336 { 293, ERRCODE_BASIC_DDE_NO_CHANNEL
},
337 { 294, ERRCODE_BASIC_DDE_INVALID_LINK
},
338 { 295, ERRCODE_BASIC_DDE_QUEUE_OVERFLOW
},
339 { 296, ERRCODE_BASIC_DDE_LINK_ALREADY_EST
},
340 { 297, ERRCODE_BASIC_DDE_LINK_INV_TOPIC
},
341 { 298, ERRCODE_BASIC_DDE_DLL_NOT_FOUND
},
342 { 323, ERRCODE_BASIC_CANNOT_LOAD
},
343 { 341, ERRCODE_BASIC_BAD_INDEX
},
344 { 366, ERRCODE_BASIC_NO_ACTIVE_OBJECT
},
345 { 380, ERRCODE_BASIC_BAD_PROP_VALUE
},
346 { 382, ERRCODE_BASIC_PROP_READONLY
},
347 { 394, ERRCODE_BASIC_PROP_WRITEONLY
},
348 { 420, ERRCODE_BASIC_INVALID_OBJECT
},
349 { 423, ERRCODE_BASIC_NO_METHOD
},
350 { 424, ERRCODE_BASIC_NEEDS_OBJECT
},
351 { 425, ERRCODE_BASIC_INVALID_USAGE_OBJECT
},
352 { 430, ERRCODE_BASIC_NO_OLE
},
353 { 438, ERRCODE_BASIC_BAD_METHOD
},
354 { 440, ERRCODE_BASIC_OLE_ERROR
},
355 { 445, ERRCODE_BASIC_BAD_ACTION
},
356 { 446, ERRCODE_BASIC_NO_NAMED_ARGS
},
357 { 447, ERRCODE_BASIC_BAD_LOCALE
},
358 { 448, ERRCODE_BASIC_NAMED_NOT_FOUND
},
359 { 449, ERRCODE_BASIC_NOT_OPTIONAL
},
360 { 450, ERRCODE_BASIC_WRONG_ARGS
},
361 { 451, ERRCODE_BASIC_NOT_A_COLL
},
362 { 452, ERRCODE_BASIC_BAD_ORDINAL
},
363 { 453, ERRCODE_BASIC_DLLPROC_NOT_FOUND
},
364 { 460, ERRCODE_BASIC_BAD_CLIPBD_FORMAT
},
365 { 951, ERRCODE_BASIC_UNEXPECTED
},
366 { 952, ERRCODE_BASIC_EXPECTED
},
367 { 953, ERRCODE_BASIC_SYMBOL_EXPECTED
},
368 { 954, ERRCODE_BASIC_VAR_EXPECTED
},
369 { 955, ERRCODE_BASIC_LABEL_EXPECTED
},
370 { 956, ERRCODE_BASIC_LVALUE_EXPECTED
},
371 { 957, ERRCODE_BASIC_VAR_DEFINED
},
372 { 958, ERRCODE_BASIC_PROC_DEFINED
},
373 { 959, ERRCODE_BASIC_LABEL_DEFINED
},
374 { 960, ERRCODE_BASIC_UNDEF_VAR
},
375 { 961, ERRCODE_BASIC_UNDEF_ARRAY
},
376 { 962, ERRCODE_BASIC_UNDEF_PROC
},
377 { 963, ERRCODE_BASIC_UNDEF_LABEL
},
378 { 964, ERRCODE_BASIC_UNDEF_TYPE
},
379 { 965, ERRCODE_BASIC_BAD_EXIT
},
380 { 966, ERRCODE_BASIC_BAD_BLOCK
},
381 { 967, ERRCODE_BASIC_BAD_BRACKETS
},
382 { 968, ERRCODE_BASIC_BAD_DECLARATION
},
383 { 969, ERRCODE_BASIC_BAD_PARAMETERS
},
384 { 970, ERRCODE_BASIC_BAD_CHAR_IN_NUMBER
},
385 { 971, ERRCODE_BASIC_MUST_HAVE_DIMS
},
386 { 972, ERRCODE_BASIC_NO_IF
},
387 { 973, ERRCODE_BASIC_NOT_IN_SUBR
},
388 { 974, ERRCODE_BASIC_NOT_IN_MAIN
},
389 { 975, ERRCODE_BASIC_WRONG_DIMS
},
390 { 976, ERRCODE_BASIC_BAD_OPTION
},
391 { 977, ERRCODE_BASIC_CONSTANT_REDECLARED
},
392 { 978, ERRCODE_BASIC_PROG_TOO_LARGE
},
393 { 979, ERRCODE_BASIC_NO_STRINGS_ARRAYS
},
394 { 1000, ERRCODE_BASIC_PROPERTY_NOT_FOUND
},
395 { 1001, ERRCODE_BASIC_METHOD_NOT_FOUND
},
396 { 1002, ERRCODE_BASIC_ARG_MISSING
},
397 { 1003, ERRCODE_BASIC_BAD_NUMBER_OF_ARGS
},
398 { 1004, ERRCODE_BASIC_METHOD_FAILED
},
399 { 1005, ERRCODE_BASIC_SETPROP_FAILED
},
400 { 1006, ERRCODE_BASIC_GETPROP_FAILED
},
401 { 1007, ERRCODE_BASIC_COMPAT
},
402 { 0xFFFF, ErrCode(0xFFFFFFFFUL
) } // End mark
405 // The StarBASIC factory is a hack. When a SbModule is created, its pointer
406 // is saved and given to the following SbProperties/SbMethods. This restores
407 // the Module-relationship. But it works only when a module is loaded.
408 // Can cause troubles with separately loaded properties!
410 SbxBase
* SbiFactory::Create( sal_uInt16 nSbxId
, sal_uInt32 nCreator
)
412 if( nCreator
== SBXCR_SBX
)
417 return new StarBASIC( nullptr );
419 return new SbModule( "" );
420 case SBXID_BASICPROP
:
421 return new SbProperty( "", SbxVARIANT
, nullptr );
422 case SBXID_BASICMETHOD
:
423 return new SbMethod( "", SbxVARIANT
, nullptr );
424 case SBXID_JSCRIPTMOD
:
425 return new SbJScriptModule
;
426 case SBXID_JSCRIPTMETH
:
427 return new SbJScriptMethod( SbxVARIANT
);
433 SbxObject
* SbiFactory::CreateObject( const OUString
& rClass
)
435 if( rClass
.equalsIgnoreAsciiCase( "StarBASIC" ) )
437 return new StarBASIC( nullptr );
439 else if( rClass
.equalsIgnoreAsciiCase( "StarBASICModule" ) )
441 return new SbModule( OUString() );
443 else if( rClass
.equalsIgnoreAsciiCase( "Collection" ) )
445 return new BasicCollection( "Collection" );
447 else if( rClass
.equalsIgnoreAsciiCase( "FileSystemObject" ) )
451 Reference
< XMultiServiceFactory
> xFactory( comphelper::getProcessServiceFactory(), UNO_SET_THROW
);
452 OUString
aServiceName("ooo.vba.FileSystemObject");
453 Reference
< XInterface
> xInterface( xFactory
->createInstance( aServiceName
), UNO_SET_THROW
);
454 return new SbUnoObject( aServiceName
, uno::Any( xInterface
) );
456 catch(const Exception
& )
464 // Factory class to create OLE objects
465 class SbOLEFactory
: public SbxFactory
468 virtual SbxBase
* Create( sal_uInt16 nSbxId
, sal_uInt32
) override
;
469 virtual SbxObject
* CreateObject( const OUString
& ) override
;
472 SbxBase
* SbOLEFactory::Create( sal_uInt16
, sal_uInt32
)
478 SbxObject
* SbOLEFactory::CreateObject( const OUString
& rClassName
)
480 SbxObject
* pRet
= createOLEObject_Impl( rClassName
);
485 // SbFormFactory, show user forms by: dim as new <user form name>
487 class SbFormFactory
: public SbxFactory
490 virtual SbxBase
* Create( sal_uInt16 nSbxId
, sal_uInt32
) override
;
491 virtual SbxObject
* CreateObject( const OUString
& ) override
;
494 SbxBase
* SbFormFactory::Create( sal_uInt16
, sal_uInt32
)
500 SbxObject
* SbFormFactory::CreateObject( const OUString
& rClassName
)
502 if( SbModule
* pMod
= GetSbData()->pMod
)
504 if( SbxVariable
* pVar
= pMod
->Find( rClassName
, SbxClassType::Object
) )
506 if( SbUserFormModule
* pFormModule
= dynamic_cast<SbUserFormModule
*>( pVar
->GetObject() ) )
508 bool bInitState
= pFormModule
->getInitState();
511 // Not the first instantiate, reset
512 pFormModule
->ResetApiObj( false/*bTriggerTerminateEvent*/ );
513 pFormModule
->setInitState( false );
519 return pFormModule
->CreateInstance();
529 SbxObject
* cloneTypeObjectImpl( const SbxObject
& rTypeObj
)
531 SbxObject
* pRet
= new SbxObject( rTypeObj
);
532 pRet
->PutObject( pRet
);
534 // Copy the properties, not only the reference to them
535 SbxArray
* pProps
= pRet
->GetProperties();
536 sal_uInt32 nCount
= pProps
->Count32();
537 for( sal_uInt32 i
= 0 ; i
< nCount
; i
++ )
539 SbxVariable
* pVar
= pProps
->Get32( i
);
540 SbxProperty
* pProp
= dynamic_cast<SbxProperty
*>( pVar
);
543 SbxProperty
* pNewProp
= new SbxProperty( *pProp
);
544 SbxDataType eVarType
= pVar
->GetType();
545 if( eVarType
& SbxARRAY
)
547 SbxBase
* pParObj
= pVar
->GetObject();
548 SbxDimArray
* pSource
= dynamic_cast<SbxDimArray
*>( pParObj
);
549 SbxDimArray
* pDest
= new SbxDimArray( pVar
->GetType() );
551 pDest
->setHasFixedSize( pSource
&& pSource
->hasFixedSize() );
552 if ( pSource
&& pSource
->GetDims() && pSource
->hasFixedSize() )
556 for ( sal_Int32 j
= 1 ; j
<= pSource
->GetDims(); ++j
)
558 pSource
->GetDim32( j
, lb
, ub
);
559 pDest
->AddDim32( lb
, ub
);
564 pDest
->unoAddDim( 0, -1 ); // variant array
566 SbxFlagBits nSavFlags
= pVar
->GetFlags();
567 pNewProp
->ResetFlag( SbxFlagBits::Fixed
);
568 // need to reset the FIXED flag
569 // when calling PutObject ( because the type will not match Object )
570 pNewProp
->PutObject( pDest
);
571 pNewProp
->SetFlags( nSavFlags
);
573 if( eVarType
== SbxOBJECT
)
575 SbxBase
* pObjBase
= pVar
->GetObject();
576 SbxObject
* pSrcObj
= dynamic_cast<SbxObject
*>( pObjBase
);
577 SbxObject
* pDestObj
= nullptr;
578 if( pSrcObj
!= nullptr )
579 pDestObj
= cloneTypeObjectImpl( *pSrcObj
);
580 pNewProp
->PutObject( pDestObj
);
582 pProps
->PutDirect( pNewProp
, i
);
588 // Factory class to create user defined objects (type command)
589 class SbTypeFactory
: public SbxFactory
592 virtual SbxBase
* Create( sal_uInt16 nSbxId
, sal_uInt32
) override
;
593 virtual SbxObject
* CreateObject( const OUString
& ) override
;
596 SbxBase
* SbTypeFactory::Create( sal_uInt16
, sal_uInt32
)
602 SbxObject
* SbTypeFactory::CreateObject( const OUString
& rClassName
)
604 SbxObject
* pRet
= nullptr;
605 SbModule
* pMod
= GetSbData()->pMod
;
608 const SbxObject
* pObj
= pMod
->FindType( rClassName
);
611 pRet
= cloneTypeObjectImpl( *pObj
);
617 SbxObject
* createUserTypeImpl( const OUString
& rClassName
)
619 SbxObject
* pRetObj
= GetSbData()->pTypeFac
->CreateObject( rClassName
);
624 SbClassModuleObject::SbClassModuleObject( SbModule
* pClassModule
)
625 : SbModule( pClassModule
->GetName() )
626 , mpClassModule( pClassModule
)
627 , mbInitializeEventDone( false )
629 aOUSource
= pClassModule
->aOUSource
;
630 aComment
= pClassModule
->aComment
;
631 // see comment in destructor about these two
632 pImage
= pClassModule
->pImage
;
633 pBreaks
= pClassModule
->pBreaks
;
635 SetClassName( pClassModule
->GetName() );
637 // Allow search only internally
638 ResetFlag( SbxFlagBits::GlobalSearch
);
640 // Copy the methods from original class module
641 SbxArray
* pClassMethods
= pClassModule
->GetMethods().get();
642 sal_uInt32 nMethodCount
= pClassMethods
->Count32();
644 for( i
= 0 ; i
< nMethodCount
; i
++ )
646 SbxVariable
* pVar
= pClassMethods
->Get32( i
);
648 // Exclude SbIfaceMapperMethod to copy them in a second step
649 SbIfaceMapperMethod
* pIfaceMethod
= dynamic_cast<SbIfaceMapperMethod
*>( pVar
);
652 SbMethod
* pMethod
= dynamic_cast<SbMethod
*>( pVar
);
655 SbxFlagBits nFlags_
= pMethod
->GetFlags();
656 pMethod
->SetFlag( SbxFlagBits::NoBroadcast
);
657 SbMethod
* pNewMethod
= new SbMethod( *pMethod
);
658 pNewMethod
->ResetFlag( SbxFlagBits::NoBroadcast
);
659 pMethod
->SetFlags( nFlags_
);
660 pNewMethod
->pMod
= this;
661 pNewMethod
->SetParent( this );
662 pMethods
->PutDirect( pNewMethod
, i
);
663 StartListening(pNewMethod
->GetBroadcaster(), DuplicateHandling::Prevent
);
668 // Copy SbIfaceMapperMethod in a second step to ensure that
669 // the corresponding base methods have already been copied
670 for( i
= 0 ; i
< nMethodCount
; i
++ )
672 SbxVariable
* pVar
= pClassMethods
->Get32( i
);
674 SbIfaceMapperMethod
* pIfaceMethod
= dynamic_cast<SbIfaceMapperMethod
*>( pVar
);
677 SbMethod
* pImplMethod
= pIfaceMethod
->getImplMethod();
680 OSL_FAIL( "No ImplMethod" );
684 // Search for own copy of ImplMethod
685 SbxVariable
* p
= pMethods
->Find( pImplMethod
->GetName(), SbxClassType::Method
);
686 SbMethod
* pImplMethodCopy
= dynamic_cast<SbMethod
*>( p
);
687 if( !pImplMethodCopy
)
689 OSL_FAIL( "Found no ImplMethod copy" );
692 SbIfaceMapperMethod
* pNewIfaceMethod
=
693 new SbIfaceMapperMethod( pIfaceMethod
->GetName(), pImplMethodCopy
);
694 pMethods
->PutDirect( pNewIfaceMethod
, i
);
698 // Copy the properties from original class module
699 SbxArray
* pClassProps
= pClassModule
->GetProperties();
700 sal_uInt32 nPropertyCount
= pClassProps
->Count32();
701 for( i
= 0 ; i
< nPropertyCount
; i
++ )
703 SbxVariable
* pVar
= pClassProps
->Get32( i
);
704 SbProcedureProperty
* pProcedureProp
= dynamic_cast<SbProcedureProperty
*>( pVar
);
707 SbxFlagBits nFlags_
= pProcedureProp
->GetFlags();
708 pProcedureProp
->SetFlag( SbxFlagBits::NoBroadcast
);
709 SbProcedureProperty
* pNewProp
= new SbProcedureProperty
710 ( pProcedureProp
->GetName(), pProcedureProp
->GetType() );
711 pNewProp
->SetFlags( nFlags_
); // Copy flags
712 pNewProp
->ResetFlag( SbxFlagBits::NoBroadcast
); // except the Broadcast if it was set
713 pProcedureProp
->SetFlags( nFlags_
);
714 pProps
->PutDirect( pNewProp
, i
);
715 StartListening(pNewProp
->GetBroadcaster(), DuplicateHandling::Prevent
);
719 SbxProperty
* pProp
= dynamic_cast<SbxProperty
*>( pVar
);
722 SbxFlagBits nFlags_
= pProp
->GetFlags();
723 pProp
->SetFlag( SbxFlagBits::NoBroadcast
);
724 SbxProperty
* pNewProp
= new SbxProperty( *pProp
);
726 // Special handling for modules instances and collections, they need
727 // to be instantiated, otherwise all refer to the same base object
728 SbxDataType eVarType
= pProp
->GetType();
729 if( eVarType
== SbxOBJECT
)
731 SbxBase
* pObjBase
= pProp
->GetObject();
732 SbxObject
* pObj
= dynamic_cast<SbxObject
*>( pObjBase
);
733 if( pObj
!= nullptr )
735 const OUString
& aObjClass
= pObj
->GetClassName();
737 SbClassModuleObject
* pClassModuleObj
= dynamic_cast<SbClassModuleObject
*>( pObjBase
);
738 if( pClassModuleObj
!= nullptr )
740 SbModule
* pLclClassModule
= pClassModuleObj
->getClassModule();
741 SbClassModuleObject
* pNewObj
= new SbClassModuleObject( pLclClassModule
);
742 pNewObj
->SetName( pProp
->GetName() );
743 pNewObj
->SetParent( pLclClassModule
->pParent
);
744 pNewProp
->PutObject( pNewObj
);
746 else if( aObjClass
.equalsIgnoreAsciiCase( "Collection" ) )
748 BasicCollection
* pNewCollection
= new BasicCollection( "Collection" );
749 pNewCollection
->SetName( pProp
->GetName() );
750 pNewCollection
->SetParent( pClassModule
->pParent
);
751 pNewProp
->PutObject( pNewCollection
);
756 pNewProp
->ResetFlag( SbxFlagBits::NoBroadcast
);
757 pNewProp
->SetParent( this );
758 pProps
->PutDirect( pNewProp
, i
);
759 pProp
->SetFlags( nFlags_
);
763 SetModuleType( ModuleType::CLASS
);
764 mbVBACompat
= pClassModule
->mbVBACompat
;
767 SbClassModuleObject::~SbClassModuleObject()
769 // do not trigger termination event when document is already closed
770 if( StarBASIC::IsRunning() )
771 if( StarBASIC
* pDocBasic
= lclGetDocBasicForModule( this ) )
772 if( const DocBasicItem
* pDocBasicItem
= lclFindDocBasicItem( pDocBasic
) )
773 if( !pDocBasicItem
->isDocClosed() )
774 triggerTerminateEvent();
776 // prevent the base class destructor from deleting these because
777 // we do not actually own them
782 void SbClassModuleObject::Notify( SfxBroadcaster
& rBC
, const SfxHint
& rHint
)
784 handleProcedureProperties( rBC
, rHint
);
787 SbxVariable
* SbClassModuleObject::Find( const OUString
& rName
, SbxClassType t
)
789 SbxVariable
* pRes
= SbxObject::Find( rName
, t
);
792 triggerInitializeEvent();
794 SbIfaceMapperMethod
* pIfaceMapperMethod
= dynamic_cast<SbIfaceMapperMethod
*>( pRes
);
795 if( pIfaceMapperMethod
)
797 pRes
= pIfaceMapperMethod
->getImplMethod();
798 pRes
->SetFlag( SbxFlagBits::ExtFound
);
804 void SbClassModuleObject::triggerInitializeEvent()
806 if( mbInitializeEventDone
)
811 mbInitializeEventDone
= true;
814 SbxVariable
* pMeth
= SbxObject::Find("Class_Initialize", SbxClassType::Method
);
822 void SbClassModuleObject::triggerTerminateEvent()
824 if( !mbInitializeEventDone
|| GetSbData()->bRunInit
)
829 SbxVariable
* pMeth
= SbxObject::Find("Class_Terminate", SbxClassType::Method
);
838 SbClassData::SbClassData()
840 mxIfaces
= new SbxArray();
843 void SbClassData::clear()
846 maRequiredTypes
.clear();
849 SbClassFactory::SbClassFactory()
851 xClassModules
= new SbxObject( OUString() );
854 SbClassFactory::~SbClassFactory()
857 void SbClassFactory::AddClassModule( SbModule
* pClassModule
)
859 SbxObjectRef xToUseClassModules
= xClassModules
;
861 if( StarBASIC
* pDocBasic
= lclGetDocBasicForModule( pClassModule
) )
862 if( const DocBasicItem
* pDocBasicItem
= lclFindDocBasicItem( pDocBasic
) )
863 xToUseClassModules
= pDocBasicItem
->getClassModules();
865 SbxObject
* pParent
= pClassModule
->GetParent();
866 xToUseClassModules
->Insert( pClassModule
);
867 pClassModule
->SetParent( pParent
);
870 void SbClassFactory::RemoveClassModule( SbModule
* pClassModule
)
872 xClassModules
->Remove( pClassModule
);
875 SbxBase
* SbClassFactory::Create( sal_uInt16
, sal_uInt32
)
881 SbxObject
* SbClassFactory::CreateObject( const OUString
& rClassName
)
883 SbxObjectRef xToUseClassModules
= xClassModules
;
885 if( SbModule
* pMod
= GetSbData()->pMod
)
887 if( StarBASIC
* pDocBasic
= lclGetDocBasicForModule( pMod
) )
889 if( const DocBasicItem
* pDocBasicItem
= lclFindDocBasicItem( pDocBasic
) )
891 xToUseClassModules
= pDocBasicItem
->getClassModules();
895 SbxVariable
* pVar
= xToUseClassModules
->Find( rClassName
, SbxClassType::Object
);
896 SbxObject
* pRet
= nullptr;
899 SbModule
* pVarMod
= static_cast<SbModule
*>(pVar
);
900 pRet
= new SbClassModuleObject( pVarMod
);
905 SbModule
* SbClassFactory::FindClass( const OUString
& rClassName
)
907 SbxVariable
* pVar
= xClassModules
->Find( rClassName
, SbxClassType::DontCare
);
908 SbModule
* pMod
= pVar
? static_cast<SbModule
*>(pVar
) : nullptr;
912 StarBASIC::StarBASIC( StarBASIC
* p
, bool bIsDocBasic
)
913 : SbxObject("StarBASIC"), bDocBasic( bIsDocBasic
)
916 bNoRtl
= bBreak
= false;
919 if( !GetSbData()->nInst
++ )
921 GetSbData()->pSbFac
.reset( new SbiFactory
);
922 AddFactory( GetSbData()->pSbFac
.get() );
923 GetSbData()->pTypeFac
= new SbTypeFactory
;
924 AddFactory( GetSbData()->pTypeFac
);
925 GetSbData()->pClassFac
= new SbClassFactory
;
926 AddFactory( GetSbData()->pClassFac
);
927 GetSbData()->pOLEFac
= new SbOLEFactory
;
928 AddFactory( GetSbData()->pOLEFac
);
929 GetSbData()->pFormFac
= new SbFormFactory
;
930 AddFactory( GetSbData()->pFormFac
);
931 GetSbData()->pUnoFac
.reset( new SbUnoFactory
);
932 AddFactory( GetSbData()->pUnoFac
.get() );
934 pRtl
= new SbiStdObject(RTLNAME
, this );
935 // Search via StarBasic is always global
936 SetFlag( SbxFlagBits::GlobalSearch
);
937 pVBAGlobals
= nullptr;
942 lclInsertDocBasicItem( *this );
946 // #51727 Override SetModified so that the modified state
947 // is not given to the parent
948 void StarBASIC::SetModified( bool b
)
950 SbxBase::SetModified( b
);
953 StarBASIC::~StarBASIC()
955 // Needs to be first action as it can trigger events
956 disposeComVariablesForBasic( this );
958 if( !--GetSbData()->nInst
)
960 RemoveFactory( GetSbData()->pSbFac
.get() );
961 GetSbData()->pSbFac
.reset();
962 RemoveFactory( GetSbData()->pUnoFac
.get() );
963 GetSbData()->pUnoFac
.reset();
964 RemoveFactory( GetSbData()->pTypeFac
);
965 delete GetSbData()->pTypeFac
; GetSbData()->pTypeFac
= nullptr;
966 RemoveFactory( GetSbData()->pClassFac
);
967 delete GetSbData()->pClassFac
; GetSbData()->pClassFac
= nullptr;
968 RemoveFactory( GetSbData()->pOLEFac
);
969 delete GetSbData()->pOLEFac
; GetSbData()->pOLEFac
= nullptr;
970 RemoveFactory( GetSbData()->pFormFac
);
971 delete GetSbData()->pFormFac
; GetSbData()->pFormFac
= nullptr;
973 if( SbiGlobals::pGlobals
)
975 delete SbiGlobals::pGlobals
;
976 SbiGlobals::pGlobals
= nullptr;
981 ErrCode eOld
= SbxBase::GetError();
983 lclRemoveDocBasicItem( *this );
985 SbxBase::ResetError();
986 if( eOld
!= ERRCODE_NONE
)
988 SbxBase::SetError( eOld
);
992 // #100326 Set Parent NULL in registered listeners
993 if( xUnoListeners
.is() )
995 sal_uInt16 uCount
= xUnoListeners
->Count();
996 for( sal_uInt16 i
= 0 ; i
< uCount
; i
++ )
998 SbxVariable
* pListenerObj
= xUnoListeners
->Get( i
);
999 pListenerObj
->SetParent( nullptr );
1001 xUnoListeners
= nullptr;
1004 clearUnoMethodsForBasic( this );
1007 void StarBASIC::implClearDependingVarsOnDelete( StarBASIC
* pDeletedBasic
)
1009 if( this != pDeletedBasic
)
1011 for( const auto& pModule
: pModules
)
1013 pModule
->ClearVarsDependingOnDeletedBasic( pDeletedBasic
);
1017 for( sal_uInt16 nObj
= 0; nObj
< pObjs
->Count(); nObj
++ )
1019 SbxVariable
* pVar
= pObjs
->Get( nObj
);
1020 StarBASIC
* pBasic
= dynamic_cast<StarBASIC
*>( pVar
);
1021 if( pBasic
&& pBasic
!= pDeletedBasic
)
1023 pBasic
->implClearDependingVarsOnDelete( pDeletedBasic
);
1029 SbModule
* StarBASIC::MakeModule( const OUString
& rName
, const OUString
& rSrc
)
1032 aInfo
.ModuleType
= ModuleType::NORMAL
;
1033 return MakeModule( rName
, aInfo
, rSrc
);
1035 SbModule
* StarBASIC::MakeModule( const OUString
& rName
, const ModuleInfo
& mInfo
, const OUString
& rSrc
)
1040 "create module " << rName
<< " type mInfo " << mInfo
.ModuleType
);
1041 SbModule
* p
= nullptr;
1042 switch ( mInfo
.ModuleType
)
1044 case ModuleType::DOCUMENT
:
1045 // In theory we should be able to create Object modules
1046 // in ordinary basic ( in vba mode thought these are create
1047 // by the application/basic and not by the user )
1048 p
= new SbObjModule( rName
, mInfo
, isVBAEnabled() );
1050 case ModuleType::CLASS
:
1051 p
= new SbModule( rName
, isVBAEnabled() );
1052 p
->SetModuleType( ModuleType::CLASS
);
1054 case ModuleType::FORM
:
1055 p
= new SbUserFormModule( rName
, mInfo
, isVBAEnabled() );
1058 p
= new SbModule( rName
, isVBAEnabled() );
1061 p
->SetSource32( rSrc
);
1062 p
->SetParent( this );
1063 pModules
.emplace_back(p
);
1064 SetModified( true );
1068 void StarBASIC::Insert( SbxVariable
* pVar
)
1070 if( dynamic_cast<const SbModule
*>(pVar
) != nullptr)
1072 pModules
.emplace_back(static_cast<SbModule
*>(pVar
));
1073 pVar
->SetParent( this );
1074 StartListening(pVar
->GetBroadcaster(), DuplicateHandling::Prevent
);
1078 bool bWasModified
= IsModified();
1079 SbxObject::Insert( pVar
);
1080 if( !bWasModified
&& pVar
->IsSet( SbxFlagBits::DontStore
) )
1082 SetModified( false );
1087 void StarBASIC::Remove( SbxVariable
* pVar
)
1089 SbModule
* pModule
= dynamic_cast<SbModule
*>(pVar
);
1092 // #87540 Can be last reference!
1093 SbModuleRef xVar
= pModule
;
1094 pModules
.erase(std::remove(pModules
.begin(), pModules
.end(), xVar
));
1095 pVar
->SetParent( nullptr );
1096 EndListening( pVar
->GetBroadcaster() );
1100 SbxObject::Remove( pVar
);
1104 void StarBASIC::Clear()
1109 SbModule
* StarBASIC::FindModule( const OUString
& rName
)
1111 for (const auto& pModule
: pModules
)
1113 if( pModule
->GetName().equalsIgnoreAsciiCase( rName
) )
1115 return pModule
.get();
1122 struct ClassModuleRunInitItem
1124 SbModule
* m_pModule
;
1126 bool m_bRunInitDone
;
1128 ClassModuleRunInitItem()
1129 : m_pModule( nullptr )
1130 , m_bProcessing( false )
1131 , m_bRunInitDone( false )
1133 explicit ClassModuleRunInitItem( SbModule
* pModule
)
1134 : m_pModule( pModule
)
1135 , m_bProcessing( false )
1136 , m_bRunInitDone( false )
1140 // Derive from unordered_map type instead of typedef
1141 // to allow forward declaration in sbmod.hxx
1142 class ModuleInitDependencyMap
: public
1143 std::unordered_map
< OUString
, ClassModuleRunInitItem
>
1146 void SbModule::implProcessModuleRunInit( ModuleInitDependencyMap
& rMap
, ClassModuleRunInitItem
& rItem
)
1148 rItem
.m_bProcessing
= true;
1150 SbModule
* pModule
= rItem
.m_pModule
;
1151 if( pModule
->pClassData
!= nullptr )
1153 std::vector
< OUString
>& rReqTypes
= pModule
->pClassData
->maRequiredTypes
;
1154 for( const auto& rStr
: rReqTypes
)
1156 // Is required type a class module?
1157 ModuleInitDependencyMap::iterator itFind
= rMap
.find( rStr
);
1158 if( itFind
!= rMap
.end() )
1160 ClassModuleRunInitItem
& rParentItem
= itFind
->second
;
1161 if( rParentItem
.m_bProcessing
)
1163 // TODO: raise error?
1164 OSL_FAIL( "Cyclic module dependency detected" );
1168 if( !rParentItem
.m_bRunInitDone
)
1170 implProcessModuleRunInit( rMap
, rParentItem
);
1177 rItem
.m_bRunInitDone
= true;
1178 rItem
.m_bProcessing
= false;
1181 // Run Init-Code of all modules (including inserted libraries)
1182 void StarBASIC::InitAllModules( StarBASIC
const * pBasicNotToInit
)
1184 SolarMutexGuard guard
;
1187 for (const auto& pModule
: pModules
)
1191 // compile modules first then RunInit ( otherwise there is
1192 // can be order dependency, e.g. classmodule A has a member
1193 // of type classmodule B and classmodule B hasn't been compiled yet )
1195 // Consider required types to init in right order. Class modules
1196 // that are required by other modules have to be initialized first.
1197 ModuleInitDependencyMap aMIDMap
;
1198 for (const auto& pModule
: pModules
)
1200 OUString aModuleName
= pModule
->GetName();
1201 if( pModule
->isProxyModule() )
1203 aMIDMap
[aModuleName
] = ClassModuleRunInitItem( pModule
.get() );
1207 for (auto & elem
: aMIDMap
)
1209 ClassModuleRunInitItem
& rItem
= elem
.second
;
1210 SbModule::implProcessModuleRunInit( aMIDMap
, rItem
);
1213 // Call RunInit on standard modules
1214 for (const auto& pModule
: pModules
)
1216 if( !pModule
->isProxyModule() )
1222 // Check all objects if they are BASIC,
1223 // if yes initialize
1224 for ( sal_uInt16 nObj
= 0; nObj
< pObjs
->Count(); nObj
++ )
1226 SbxVariable
* pVar
= pObjs
->Get( nObj
);
1227 StarBASIC
* pBasic
= dynamic_cast<StarBASIC
*>( pVar
);
1228 if( pBasic
&& pBasic
!= pBasicNotToInit
)
1230 pBasic
->InitAllModules();
1235 // #88329 Put modules back to not initialised state to
1236 // force reinitialisation at next start
1237 void StarBASIC::DeInitAllModules()
1239 // Deinit own modules
1240 for (const auto& pModule
: pModules
)
1242 if( pModule
->pImage
&& !pModule
->isProxyModule() && dynamic_cast<SbObjModule
*>( pModule
.get()) == nullptr )
1244 pModule
->pImage
->bInit
= false;
1248 for ( sal_uInt16 nObj
= 0; nObj
< pObjs
->Count(); nObj
++ )
1250 SbxVariable
* pVar
= pObjs
->Get( nObj
);
1251 StarBASIC
* pBasic
= dynamic_cast<StarBASIC
*>( pVar
);
1254 pBasic
->DeInitAllModules();
1259 // This implementation at first searches within the runtime library,
1260 // then it looks for an element within one module. This module can be
1261 // a public var or an entrypoint. If it is not found and we look for a
1262 // method and a module with the given name is found the search continues
1263 // for entrypoint "Main".
1264 // If this fails again a conventional search over objects is performend.
1265 SbxVariable
* StarBASIC::Find( const OUString
& rName
, SbxClassType t
)
1267 SbxVariable
* pRes
= nullptr;
1268 SbModule
* pNamed
= nullptr;
1269 // "Extended" search in Runtime Lib
1270 // but only if SbiRuntime has not set the flag
1273 if( t
== SbxClassType::DontCare
|| t
== SbxClassType::Object
)
1275 if( rName
.equalsIgnoreAsciiCase( RTLNAME
) )
1282 pRes
= static_cast<SbiStdObject
*>(pRtl
.get())->Find( rName
, t
);
1286 pRes
->SetFlag( SbxFlagBits::ExtFound
);
1292 for (const auto& pModule
: pModules
)
1294 if( pModule
->IsVisible() )
1296 // Remember module for Main() call
1297 // or is the name equal?!?
1298 if( pModule
->GetName().equalsIgnoreAsciiCase( rName
) )
1300 if( t
== SbxClassType::Object
|| t
== SbxClassType::DontCare
)
1302 pRes
= pModule
.get(); break;
1304 pNamed
= pModule
.get();
1306 // Only variables qualified by the Module Name e.g. Sheet1.foo
1307 // should work for Document && Class type Modules
1308 sal_Int32 nType
= pModule
->GetModuleType();
1309 if ( nType
== ModuleType::DOCUMENT
|| nType
== ModuleType::FORM
)
1313 // otherwise check if the element is available
1314 // unset GBLSEARCH-Flag (due to recursion)
1315 SbxFlagBits nGblFlag
= pModule
->GetFlags() & SbxFlagBits::GlobalSearch
;
1316 pModule
->ResetFlag( SbxFlagBits::GlobalSearch
);
1317 pRes
= pModule
->Find( rName
, t
);
1318 pModule
->SetFlag( nGblFlag
);
1326 OUString
aMainStr("Main");
1327 if( !pRes
&& pNamed
&& ( t
== SbxClassType::Method
|| t
== SbxClassType::DontCare
) &&
1328 !pNamed
->GetName().equalsIgnoreAsciiCase( aMainStr
) )
1330 pRes
= pNamed
->Find( aMainStr
, SbxClassType::Method
);
1334 pRes
= SbxObject::Find( rName
, t
);
1339 bool StarBASIC::Call( const OUString
& rName
, SbxArray
* pParam
)
1341 bool bRes
= SbxObject::Call( rName
, pParam
);
1344 ErrCode eErr
= SbxBase::GetError();
1345 SbxBase::ResetError();
1346 if( eErr
!= ERRCODE_NONE
)
1348 RTError( eErr
, OUString(), 0, 0, 0 );
1354 // Find method via name (e.g. query via BASIC IDE)
1355 SbxBase
* StarBASIC::FindSBXInCurrentScope( const OUString
& rName
)
1357 if( !GetSbData()->pInst
)
1361 if( !GetSbData()->pInst
->pRun
)
1365 return GetSbData()->pInst
->pRun
->FindElementExtern( rName
);
1368 void StarBASIC::QuitAndExitApplication()
1374 void StarBASIC::Stop()
1376 SbiInstance
* p
= GetSbData()->pInst
;
1381 bool StarBASIC::IsRunning()
1383 return GetSbData()->pInst
!= nullptr;
1386 SbMethod
* StarBASIC::GetActiveMethod( sal_uInt16 nLevel
)
1388 if( GetSbData()->pInst
)
1390 return GetSbData()->pInst
->GetCaller( nLevel
);
1398 SbModule
* StarBASIC::GetActiveModule()
1400 if( GetSbData()->pInst
&& !GetSbData()->bCompilerError
)
1402 return GetSbData()->pInst
->GetActiveModule();
1406 return GetSbData()->pCompMod
;
1410 BasicDebugFlags
StarBASIC::BreakPoint( sal_Int32 l
, sal_Int32 c1
, sal_Int32 c2
)
1412 SetErrorData( ERRCODE_NONE
, l
, c1
, c2
);
1414 if( GetSbData()->aBreakHdl
.IsSet() )
1416 return GetSbData()->aBreakHdl
.Call( this );
1424 BasicDebugFlags
StarBASIC::StepPoint( sal_Int32 l
, sal_Int32 c1
, sal_Int32 c2
)
1426 SetErrorData( ERRCODE_NONE
, l
, c1
, c2
);
1428 if( GetSbData()->aBreakHdl
.IsSet() )
1430 return GetSbData()->aBreakHdl
.Call( this );
1438 BasicDebugFlags
StarBASIC::BreakHdl()
1440 return aBreakHdl
.IsSet() ? aBreakHdl
.Call( this ) : BasicDebugFlags::Continue
;
1443 // Calls for error handler and break handler
1444 sal_uInt16
StarBASIC::GetLine() { return GetSbData()->nLine
; }
1445 sal_uInt16
StarBASIC::GetCol1() { return GetSbData()->nCol1
; }
1446 sal_uInt16
StarBASIC::GetCol2() { return GetSbData()->nCol2
; }
1448 // Specific to error handler
1449 ErrCode
const & StarBASIC::GetErrorCode() { return GetSbData()->nCode
; }
1450 const OUString
& StarBASIC::GetErrorText() { return GetSbData()->aErrMsg
; }
1453 // The mapping between the old and the new error codes take place by searching
1454 // through the table SFX_VB_ErrorTab[]. This is indeed not with good performance,
1455 // but it consumes much less memory than corresponding switch blocks.
1456 // Because the conversion of error codes has not to be fast. There is no
1457 // binary search by VB Error -> Error SFX.
1459 // Map back new error codes to old, Sbx-compatible
1460 sal_uInt16
StarBASIC::GetVBErrorCode( ErrCode nError
)
1462 sal_uInt16 nRet
= 0;
1464 if( SbiRuntime::isVBAEnabled() )
1466 if ( nError
== ERRCODE_BASIC_ARRAY_FIX
)
1468 else if ( nError
== ERRCODE_BASIC_STRING_OVERFLOW
)
1470 else if ( nError
== ERRCODE_BASIC_EXPR_TOO_COMPLEX
)
1472 else if ( nError
== ERRCODE_BASIC_OPER_NOT_PERFORM
)
1474 else if ( nError
== ERRCODE_BASIC_TOO_MANY_DLL
)
1476 else if ( nError
== ERRCODE_BASIC_LOOP_NOT_INIT
)
1483 const SFX_VB_ErrorItem
* pErrItem
;
1484 sal_uInt16 nIndex
= 0;
1487 pErrItem
= SFX_VB_ErrorTab
+ nIndex
;
1488 if( pErrItem
->nErrorSFX
== nError
)
1490 nRet
= pErrItem
->nErrorVB
;
1495 while( pErrItem
->nErrorVB
!= 0xFFFF ); // up to end mark
1499 ErrCode
StarBASIC::GetSfxFromVBError( sal_uInt16 nError
)
1501 ErrCode nRet
= ERRCODE_NONE
;
1503 if( SbiRuntime::isVBAEnabled() )
1513 return ERRCODE_NONE
;
1515 return ERRCODE_BASIC_ARRAY_FIX
;
1517 return ERRCODE_BASIC_STRING_OVERFLOW
;
1519 return ERRCODE_BASIC_EXPR_TOO_COMPLEX
;
1521 return ERRCODE_BASIC_OPER_NOT_PERFORM
;
1523 return ERRCODE_BASIC_TOO_MANY_DLL
;
1525 return ERRCODE_BASIC_LOOP_NOT_INIT
;
1527 nRet
= ERRCODE_NONE
;
1530 const SFX_VB_ErrorItem
* pErrItem
;
1531 sal_uInt16 nIndex
= 0;
1534 pErrItem
= SFX_VB_ErrorTab
+ nIndex
;
1535 if( pErrItem
->nErrorVB
== nError
)
1537 nRet
= pErrItem
->nErrorSFX
;
1540 else if( pErrItem
->nErrorVB
> nError
)
1542 break; // couldn't found anymore
1546 while( pErrItem
->nErrorVB
!= 0xFFFF ); // up to end mark
1550 // set Error- / Break-data
1551 void StarBASIC::SetErrorData( ErrCode nCode
, sal_uInt16 nLine
,
1552 sal_uInt16 nCol1
, sal_uInt16 nCol2
)
1554 SbiGlobals
& aGlobals
= *GetSbData();
1555 aGlobals
.nCode
= nCode
;
1556 aGlobals
.nLine
= nLine
;
1557 aGlobals
.nCol1
= nCol1
;
1558 aGlobals
.nCol2
= nCol2
;
1561 void StarBASIC::MakeErrorText( ErrCode nId
, const OUString
& aMsg
)
1563 SolarMutexGuard aSolarGuard
;
1564 sal_uInt16 nOldID
= GetVBErrorCode( nId
);
1566 const char* pErrorMsg
= nullptr;
1567 for (std::pair
<const char *, ErrCode
> const *pItem
= RID_BASIC_START
; pItem
->second
; ++pItem
)
1569 if (nId
== pItem
->second
)
1571 pErrorMsg
= pItem
->first
;
1578 // merge message with additional text
1579 OUString sError
= BasResId(pErrorMsg
);
1580 OUStringBuffer
aMsg1(sError
);
1581 // replace argument placeholder with %s
1582 OUString
aSrgStr( "$(ARG1)" );
1583 sal_Int32 nResult
= sError
.indexOf(aSrgStr
);
1587 aMsg1
.remove(nResult
, aSrgStr
.getLength());
1588 aMsg1
.insert(nResult
, aMsg
);
1590 GetSbData()->aErrMsg
= aMsg1
.makeStringAndClear();
1592 else if( nOldID
!= 0 )
1594 OUString aStdMsg
= "Error " + OUString::number(nOldID
) +
1595 ": No error text available!";
1596 GetSbData()->aErrMsg
= aStdMsg
;
1600 GetSbData()->aErrMsg
.clear();
1604 bool StarBASIC::CError( ErrCode code
, const OUString
& rMsg
,
1605 sal_Int32 l
, sal_Int32 c1
, sal_Int32 c2
)
1607 SolarMutexGuard aSolarGuard
;
1609 // compiler error during runtime -> stop program
1612 // #109018 Check if running Basic is affected
1613 StarBASIC
* pStartedBasic
= GetSbData()->pInst
->GetBasic();
1614 if( pStartedBasic
!= this )
1621 // set flag, so that GlobalRunInit notice the error
1622 GetSbData()->bGlobalInitErr
= true;
1624 // tinker the error message
1625 MakeErrorText( code
, rMsg
);
1627 // Implementation of the code for the string transport to SFX-Error
1628 if( !rMsg
.isEmpty() )
1630 code
= *new StringErrorInfo( code
, rMsg
);
1632 SetErrorData( code
, l
, c1
, c2
);
1633 GetSbData()->bCompilerError
= true;
1635 if( GetSbData()->aErrHdl
.IsSet() )
1637 bRet
= GetSbData()->aErrHdl
.Call( this );
1643 GetSbData()->bCompilerError
= false; // only true for error handler
1647 bool StarBASIC::RTError( ErrCode code
, const OUString
& rMsg
, sal_Int32 l
, sal_Int32 c1
, sal_Int32 c2
)
1649 SolarMutexGuard aSolarGuard
;
1652 if( c
.GetClass() == ErrCodeClass::Compiler
)
1656 MakeErrorText( c
, rMsg
);
1658 // Implementation of the code for the string transport to SFX-Error
1659 if( !rMsg
.isEmpty() )
1661 // very confusing, even though MakeErrorText sets up the error text
1662 // seems that this is not used ( if rMsg already has content )
1663 // In the case of VBA MakeErrorText also formats the error to be a little more
1664 // like vba ( adds an error number etc )
1665 if ( SbiRuntime::isVBAEnabled() && ( code
== ERRCODE_BASIC_COMPAT
) )
1667 OUString aTmp
= "\'" + OUString::number(SbxErrObject::getUnoErrObject()->getNumber()) +
1668 "\'\n" + (!GetSbData()->aErrMsg
.isEmpty() ? GetSbData()->aErrMsg
: rMsg
);
1669 code
= *new StringErrorInfo( code
, aTmp
);
1673 code
= *new StringErrorInfo( code
, rMsg
);
1677 SetErrorData( code
, l
, c1
, c2
);
1678 if( GetSbData()->aErrHdl
.IsSet() )
1680 return GetSbData()->aErrHdl
.Call( this );
1688 void StarBASIC::Error( ErrCode n
)
1690 Error( n
, OUString() );
1693 void StarBASIC::Error( ErrCode n
, const OUString
& rMsg
)
1695 if( GetSbData()->pInst
)
1697 GetSbData()->pInst
->Error( n
, rMsg
);
1701 void StarBASIC::FatalError( ErrCode n
)
1703 if( GetSbData()->pInst
)
1705 GetSbData()->pInst
->FatalError( n
);
1709 void StarBASIC::FatalError( ErrCode _errCode
, const OUString
& _details
)
1711 if( GetSbData()->pInst
)
1713 GetSbData()->pInst
->FatalError( _errCode
, _details
);
1717 ErrCode
StarBASIC::GetErrBasic()
1719 if( GetSbData()->pInst
)
1721 return GetSbData()->pInst
->GetErr();
1725 return ERRCODE_NONE
;
1729 // make the additional message for the RTL function error accessible
1730 OUString
StarBASIC::GetErrorMsg()
1732 if( GetSbData()->pInst
)
1734 return GetSbData()->pInst
->GetErrorMsg();
1742 sal_Int32
StarBASIC::GetErl()
1744 if( GetSbData()->pInst
)
1746 return GetSbData()->pInst
->GetErl();
1754 bool StarBASIC::ErrorHdl()
1756 return aErrorHdl
.Call( this );
1759 Link
<StarBASIC
*,bool> const & StarBASIC::GetGlobalErrorHdl()
1761 return GetSbData()->aErrHdl
;
1764 void StarBASIC::SetGlobalErrorHdl( const Link
<StarBASIC
*,bool>& rLink
)
1766 GetSbData()->aErrHdl
= rLink
;
1769 void StarBASIC::SetGlobalBreakHdl( const Link
<StarBASIC
*,BasicDebugFlags
>& rLink
)
1771 GetSbData()->aBreakHdl
= rLink
;
1774 SbxArrayRef
const & StarBASIC::getUnoListeners()
1776 if( !xUnoListeners
.is() )
1778 xUnoListeners
= new SbxArray();
1780 return xUnoListeners
;
1784 bool StarBASIC::LoadData( SvStream
& r
, sal_uInt16 nVer
)
1786 if( !SbxObject::LoadData( r
, nVer
) )
1790 // #95459 Delete dialogs, otherwise endless recursion
1791 // in SbxVarable::GetType() if dialogs are accessed
1792 sal_uInt16 nObjCount
= pObjs
->Count();
1793 std::unique_ptr
<SbxVariable
*[]> ppDeleteTab(new SbxVariable
*[ nObjCount
]);
1796 for( nObj
= 0 ; nObj
< nObjCount
; nObj
++ )
1798 SbxVariable
* pVar
= pObjs
->Get( nObj
);
1799 StarBASIC
* pBasic
= dynamic_cast<StarBASIC
*>( pVar
);
1800 ppDeleteTab
[nObj
] = pBasic
? nullptr : pVar
;
1802 for( nObj
= 0 ; nObj
< nObjCount
; nObj
++ )
1804 SbxVariable
* pVar
= ppDeleteTab
[nObj
];
1807 pObjs
->Remove( pVar
);
1810 ppDeleteTab
.reset();
1814 r
.ReadUInt16( nMod
);
1815 const size_t nMinSbxSize(14);
1816 const size_t nMaxPossibleEntries
= r
.remainingSize() / nMinSbxSize
;
1817 if (nMod
> nMaxPossibleEntries
)
1819 nMod
= nMaxPossibleEntries
;
1820 SAL_WARN("basic", "Parsing error: " << nMaxPossibleEntries
<<
1821 " max possible entries, but " << nMod
<< " claimed, truncating");
1823 for (sal_uInt16 i
= 0; i
< nMod
; ++i
)
1825 SbxBase
* pBase
= SbxBase::Load( r
);
1826 SbModule
* pMod
= dynamic_cast<SbModule
*>(pBase
);
1831 else if( dynamic_cast<const SbJScriptModule
*>( pMod
) != nullptr )
1833 // assign Ref, so that pMod will be deleted
1834 SbModuleRef xRef
= pMod
;
1838 pMod
->SetParent( this );
1839 pModules
.emplace_back(pMod
);
1842 // HACK for SFX-Bullshit!
1843 SbxVariable
* p
= Find( "FALSE", SbxClassType::Property
);
1848 p
= Find( "TRUE", SbxClassType::Property
);
1853 // End of the hacks!
1854 // Search via StarBASIC is at all times global
1855 DBG_ASSERT( IsSet( SbxFlagBits::GlobalSearch
), "Basic loaded without GBLSEARCH" );
1856 SetFlag( SbxFlagBits::GlobalSearch
);
1860 bool StarBASIC::StoreData( SvStream
& r
) const
1862 if( !SbxObject::StoreData( r
) )
1866 assert(pModules
.size() < SAL_MAX_UINT16
);
1867 r
.WriteUInt16( static_cast<sal_uInt16
>(pModules
.size()));
1868 for( const auto& rpModule
: pModules
)
1870 if( !rpModule
->Store( r
) )
1878 bool StarBASIC::GetUNOConstant( const OUString
& rName
, css::uno::Any
& aOut
)
1881 SbUnoObject
* pGlobs
= dynamic_cast<SbUnoObject
*>( Find( rName
, SbxClassType::DontCare
) );
1884 aOut
= pGlobs
->getUnoAny();
1890 Reference
< frame::XModel
> StarBASIC::GetModelFromBasic( SbxObject
* pBasic
)
1892 OSL_PRECOND( pBasic
!= nullptr, "getModelFromBasic: illegal call!" );
1897 // look for the ThisComponent variable, first in the parent (which
1898 // might be the document's Basic), then in the parent's parent (which might be
1899 // the application Basic)
1900 const OUString
sThisComponent( "ThisComponent");
1901 SbxVariable
* pThisComponent
= nullptr;
1903 SbxObject
* pLookup
= pBasic
->GetParent();
1904 while ( pLookup
&& !pThisComponent
)
1906 pThisComponent
= pLookup
->Find( sThisComponent
, SbxClassType::Object
);
1907 pLookup
= pLookup
->GetParent();
1909 if ( !pThisComponent
)
1911 SAL_WARN("basic", "Failed to get ThisComponent");
1912 // the application Basic, at the latest, should have this variable
1916 Any
aThisComponentAny( sbxToUnoValue( pThisComponent
) );
1917 Reference
< frame::XModel
> xModel( aThisComponentAny
, UNO_QUERY
);
1920 // it's no XModel. Okay, ThisComponent nowadays is allowed to be a controller.
1921 Reference
< frame::XController
> xController( aThisComponentAny
, UNO_QUERY
);
1922 if ( xController
.is() )
1924 xModel
= xController
->getModel();
1935 void StarBASIC::DetachAllDocBasicItems()
1937 std::unordered_map
< const StarBASIC
*, DocBasicItemRef
>& rItems
= GaDocBasicItems::get();
1938 for (auto const& item
: rItems
)
1940 DocBasicItemRef xItem
= item
.second
;
1941 xItem
->setDisposed(true);
1945 // #118116 Implementation Collection object
1948 static const char pCountStr
[] = "Count";
1949 static const char pAddStr
[] = "Add";
1950 static const char pItemStr
[] = "Item";
1951 static const char pRemoveStr
[] = "Remove";
1952 static sal_uInt16 nCountHash
= 0, nAddHash
, nItemHash
, nRemoveHash
;
1954 SbxInfoRef
BasicCollection::xAddInfo
;
1955 SbxInfoRef
BasicCollection::xItemInfo
;
1957 BasicCollection::BasicCollection( const OUString
& rClass
)
1958 : SbxObject( rClass
)
1962 nCountHash
= MakeHashCode( pCountStr
);
1963 nAddHash
= MakeHashCode( pAddStr
);
1964 nItemHash
= MakeHashCode( pItemStr
);
1965 nRemoveHash
= MakeHashCode( pRemoveStr
);
1971 BasicCollection::~BasicCollection()
1974 void BasicCollection::Clear()
1980 void BasicCollection::Initialize()
1982 xItemArray
= new SbxArray();
1983 SetType( SbxOBJECT
);
1984 SetFlag( SbxFlagBits::Fixed
);
1985 ResetFlag( SbxFlagBits::Write
);
1987 p
= Make( pCountStr
, SbxClassType::Property
, SbxINTEGER
);
1988 p
->ResetFlag( SbxFlagBits::Write
);
1989 p
->SetFlag( SbxFlagBits::DontStore
);
1990 p
= Make( pAddStr
, SbxClassType::Method
, SbxEMPTY
);
1991 p
->SetFlag( SbxFlagBits::DontStore
);
1992 p
= Make( pItemStr
, SbxClassType::Method
, SbxVARIANT
);
1993 p
->SetFlag( SbxFlagBits::DontStore
);
1994 p
= Make( pRemoveStr
, SbxClassType::Method
, SbxEMPTY
);
1995 p
->SetFlag( SbxFlagBits::DontStore
);
1996 if ( !xAddInfo
.is() )
1998 xAddInfo
= new SbxInfo
;
1999 xAddInfo
->AddParam( "Item", SbxVARIANT
);
2000 xAddInfo
->AddParam( "Key", SbxVARIANT
, SbxFlagBits::Read
| SbxFlagBits::Optional
);
2001 xAddInfo
->AddParam( "Before", SbxVARIANT
, SbxFlagBits::Read
| SbxFlagBits::Optional
);
2002 xAddInfo
->AddParam( "After", SbxVARIANT
, SbxFlagBits::Read
| SbxFlagBits::Optional
);
2004 if ( !xItemInfo
.is() )
2006 xItemInfo
= new SbxInfo
;
2007 xItemInfo
->AddParam( "Index", SbxVARIANT
, SbxFlagBits::Read
| SbxFlagBits::Optional
);
2011 void BasicCollection::Notify( SfxBroadcaster
& rCst
, const SfxHint
& rHint
)
2013 const SbxHint
* p
= dynamic_cast<const SbxHint
*>(&rHint
);
2016 const SfxHintId nId
= p
->GetId();
2017 bool bRead
= nId
== SfxHintId::BasicDataWanted
;
2018 bool bWrite
= nId
== SfxHintId::BasicDataChanged
;
2019 bool bRequestInfo
= nId
== SfxHintId::BasicInfoWanted
;
2020 SbxVariable
* pVar
= p
->GetVar();
2021 SbxArray
* pArg
= pVar
->GetParameters();
2022 OUString
aVarName( pVar
->GetName() );
2023 if( bRead
|| bWrite
)
2025 if( pVar
->GetHashCode() == nCountHash
2026 && aVarName
.equalsIgnoreAsciiCase( pCountStr
) )
2028 pVar
->PutLong( xItemArray
->Count32() );
2030 else if( pVar
->GetHashCode() == nAddHash
2031 && aVarName
.equalsIgnoreAsciiCase( pAddStr
) )
2035 else if( pVar
->GetHashCode() == nItemHash
2036 && aVarName
.equalsIgnoreAsciiCase( pItemStr
) )
2040 else if( pVar
->GetHashCode() == nRemoveHash
2041 && aVarName
.equalsIgnoreAsciiCase( pRemoveStr
) )
2047 SbxObject::Notify( rCst
, rHint
);
2051 else if ( bRequestInfo
)
2053 if( pVar
->GetHashCode() == nAddHash
2054 && aVarName
.equalsIgnoreAsciiCase( pAddStr
) )
2056 pVar
->SetInfo( xAddInfo
.get() );
2058 else if( pVar
->GetHashCode() == nItemHash
2059 && aVarName
.equalsIgnoreAsciiCase( pItemStr
) )
2061 pVar
->SetInfo( xItemInfo
.get() );
2065 SbxObject::Notify( rCst
, rHint
);
2068 sal_Int32
BasicCollection::implGetIndex( SbxVariable
const * pIndexVar
)
2070 sal_Int32 nIndex
= -1;
2071 if( pIndexVar
->GetType() == SbxSTRING
)
2073 nIndex
= implGetIndexForName( pIndexVar
->GetOUString() );
2077 nIndex
= pIndexVar
->GetLong() - 1;
2082 sal_Int32
BasicCollection::implGetIndexForName( const OUString
& rName
)
2084 sal_Int32 nIndex
= -1;
2085 sal_Int32 nCount
= xItemArray
->Count32();
2086 sal_Int32 nNameHash
= MakeHashCode( rName
);
2087 for( sal_Int32 i
= 0 ; i
< nCount
; i
++ )
2089 SbxVariable
* pVar
= xItemArray
->Get32( i
);
2090 if( pVar
->GetHashCode() == nNameHash
&&
2091 pVar
->GetName().equalsIgnoreAsciiCase( rName
) )
2100 void BasicCollection::CollAdd( SbxArray
* pPar_
)
2102 sal_uInt16 nCount
= pPar_
->Count();
2103 if( nCount
< 2 || nCount
> 5 )
2105 SetError( ERRCODE_BASIC_WRONG_ARGS
);
2109 SbxVariable
* pItem
= pPar_
->Get(1);
2115 nNextIndex
= xItemArray
->Count();
2119 SbxVariable
* pBefore
= pPar_
->Get(3);
2122 if( !( pBefore
->IsErr() || ( pBefore
->GetType() == SbxEMPTY
) ) )
2124 SetError( ERRCODE_BASIC_BAD_ARGUMENT
);
2127 SbxVariable
* pAfter
= pPar_
->Get(4);
2128 sal_Int32 nAfterIndex
= implGetIndex( pAfter
);
2129 if( nAfterIndex
== -1 )
2131 SetError( ERRCODE_BASIC_BAD_ARGUMENT
);
2134 nNextIndex
= nAfterIndex
+ 1;
2136 else // if( nCount == 4 )
2138 sal_Int32 nBeforeIndex
= implGetIndex( pBefore
);
2139 if( nBeforeIndex
== -1 )
2141 SetError( ERRCODE_BASIC_BAD_ARGUMENT
);
2144 nNextIndex
= nBeforeIndex
;
2148 auto pNewItem
= tools::make_ref
<SbxVariable
>( *pItem
);
2151 SbxVariable
* pKey
= pPar_
->Get(2);
2152 if( !( pKey
->IsErr() || ( pKey
->GetType() == SbxEMPTY
) ) )
2154 if( pKey
->GetType() != SbxSTRING
)
2156 SetError( ERRCODE_BASIC_BAD_ARGUMENT
);
2159 OUString aKey
= pKey
->GetOUString();
2160 if( implGetIndexForName( aKey
) != -1 )
2162 SetError( ERRCODE_BASIC_BAD_ARGUMENT
);
2165 pNewItem
->SetName( aKey
);
2168 pNewItem
->SetFlag( SbxFlagBits::ReadWrite
);
2169 xItemArray
->Insert32( pNewItem
.get(), nNextIndex
);
2173 SetError( ERRCODE_BASIC_BAD_ARGUMENT
);
2178 void BasicCollection::CollItem( SbxArray
* pPar_
)
2180 if( pPar_
->Count() != 2 )
2182 SetError( ERRCODE_BASIC_WRONG_ARGS
);
2185 SbxVariable
* pRes
= nullptr;
2186 SbxVariable
* p
= pPar_
->Get( 1 );
2187 sal_Int32 nIndex
= implGetIndex( p
);
2188 if( nIndex
>= 0 && nIndex
< static_cast<sal_Int32
>(xItemArray
->Count32()) )
2190 pRes
= xItemArray
->Get32( nIndex
);
2194 SetError( ERRCODE_BASIC_BAD_ARGUMENT
);
2198 *(pPar_
->Get(0)) = *pRes
;
2202 void BasicCollection::CollRemove( SbxArray
* pPar_
)
2204 if( pPar_
== nullptr || pPar_
->Count() != 2 )
2206 SetError( ERRCODE_BASIC_WRONG_ARGS
);
2210 SbxVariable
* p
= pPar_
->Get( 1 );
2211 sal_Int32 nIndex
= implGetIndex( p
);
2212 if( nIndex
>= 0 && nIndex
< static_cast<sal_Int32
>(xItemArray
->Count32()) )
2214 xItemArray
->Remove( nIndex
);
2216 // Correct for stack if necessary
2217 SbiInstance
* pInst
= GetSbData()->pInst
;
2218 SbiRuntime
* pRT
= pInst
? pInst
->pRun
: nullptr;
2221 SbiForStack
* pStack
= pRT
->FindForStackItemForCollection( this );
2222 if( pStack
!= nullptr )
2224 if( pStack
->nCurCollectionIndex
>= nIndex
)
2226 --pStack
->nCurCollectionIndex
;
2233 SetError( ERRCODE_BASIC_BAD_ARGUMENT
);
2237 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */