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 <o3tl/safeint.hxx>
22 #include <osl/diagnose.h>
23 #include <rtl/ustrbuf.hxx>
24 #include <tools/stream.hxx>
25 #include <tools/debug.hxx>
26 #include <vcl/errinf.hxx>
27 #include <comphelper/solarmutex.hxx>
28 #include <basic/sbx.hxx>
29 #include <vcl/svapp.hxx>
30 #include <comphelper/processfactory.hxx>
32 #include <sbunoobj.hxx>
33 #include <sbjsmeth.hxx>
34 #include <sbjsmod.hxx>
35 #include <sbintern.hxx>
36 #include <runtime.hxx>
37 #include <basic/sberrors.hxx>
38 #include <basic/sbuno.hxx>
40 #include <sbobjmod.hxx>
43 #include <cppuhelper/implbase.hxx>
44 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
45 #include <com/sun/star/util/XCloseBroadcaster.hpp>
46 #include <com/sun/star/util/XCloseListener.hpp>
47 #include <sal/log.hxx>
48 #include <errobject.hxx>
50 #include <unordered_map>
52 #include <com/sun/star/script/ModuleType.hpp>
53 #include <com/sun/star/script/ModuleInfo.hpp>
55 #include <strings.hrc>
57 using namespace ::com::sun::star::script
;
59 constexpr OUString SB_RTLNAME
= u
"@SBRTL"_ustr
;
61 using namespace ::com::sun::star
;
62 using namespace ::com::sun::star::uno
;
63 using com::sun::star::uno::Reference
;
64 using com::sun::star::uno::Any
;
65 using com::sun::star::uno::UNO_QUERY
;
66 using com::sun::star::lang::XMultiServiceFactory
;
69 class DocBasicItem
: public ::cppu::WeakImplHelper
< util::XCloseListener
>
72 explicit DocBasicItem( StarBASIC
& rDocBasic
);
73 virtual ~DocBasicItem() override
;
75 const SbxObjectRef
& getClassModules() const { return mxClassModules
; }
76 bool isDocClosed() const { return mbDocClosed
; }
78 void clearDependingVarsOnDelete( StarBASIC
& rDeletedBasic
);
80 void startListening();
83 void setDisposed( bool bDisposed
)
85 mbDisposed
= bDisposed
;
88 virtual void SAL_CALL
queryClosing( const lang::EventObject
& rSource
, sal_Bool bGetsOwnership
) override
;
89 virtual void SAL_CALL
notifyClosing( const lang::EventObject
& rSource
) override
;
90 virtual void SAL_CALL
disposing( const lang::EventObject
& rSource
) override
;
93 StarBASIC
& mrDocBasic
;
94 SbxObjectRef mxClassModules
;
100 DocBasicItem::DocBasicItem( StarBASIC
& rDocBasic
) :
101 mrDocBasic( rDocBasic
),
102 mxClassModules( new SbxObject( OUString() ) ),
103 mbDocClosed( false ),
108 DocBasicItem::~DocBasicItem()
110 // tdf#90969 HACK: don't use SolarMutexGuard - there is a horrible global
111 // map GaDocBasicItems holding instances, and these get deleted from exit
112 // handlers, when the SolarMutex is already dead
113 comphelper::SolarMutex
*pSolarMutex
= comphelper::SolarMutex::get();
115 pSolarMutex
->acquire();
120 mxClassModules
.clear(); // release with SolarMutex locked
127 pSolarMutex
= comphelper::SolarMutex::get();
129 pSolarMutex
->release();
132 void DocBasicItem::clearDependingVarsOnDelete( StarBASIC
& rDeletedBasic
)
134 mrDocBasic
.implClearDependingVarsOnDelete( &rDeletedBasic
);
137 void DocBasicItem::startListening()
140 mrDocBasic
.GetUNOConstant( u
"ThisComponent"_ustr
, aThisComp
);
141 Reference
< util::XCloseBroadcaster
> xCloseBC( aThisComp
, UNO_QUERY
);
142 mbDisposed
= !xCloseBC
.is();
145 try { xCloseBC
->addCloseListener( this ); } catch(const uno::Exception
& ) {}
149 void DocBasicItem::stopListening()
151 if( mbDisposed
) return;
154 if (!mrDocBasic
.GetUNOConstant(u
"ThisComponent"_ustr
, aThisComp
))
157 Reference
< util::XCloseBroadcaster
> xCloseBC( aThisComp
, UNO_QUERY
);
160 try { xCloseBC
->removeCloseListener( this ); } catch(const uno::Exception
& ) {}
164 void SAL_CALL
DocBasicItem::queryClosing( const lang::EventObject
& /*rSource*/, sal_Bool
/*bGetsOwnership*/ )
168 void SAL_CALL
DocBasicItem::notifyClosing( const lang::EventObject
& /*rEvent*/ )
174 void SAL_CALL
DocBasicItem::disposing( const lang::EventObject
& /*rEvent*/ )
182 typedef ::rtl::Reference
< DocBasicItem
> DocBasicItemRef
;
184 std::unordered_map
< const StarBASIC
*, DocBasicItemRef
> gaDocBasicItems
;
186 const DocBasicItem
* lclFindDocBasicItem( const StarBASIC
* pDocBasic
)
188 auto it
= gaDocBasicItems
.find( pDocBasic
);
189 auto end
= gaDocBasicItems
.end();
190 return (it
!= end
) ? it
->second
.get() : nullptr;
193 void lclInsertDocBasicItem( StarBASIC
& rDocBasic
)
195 DocBasicItemRef
& rxDocBasicItem
= gaDocBasicItems
[ &rDocBasic
];
196 rxDocBasicItem
.set( new DocBasicItem( rDocBasic
) );
197 rxDocBasicItem
->startListening();
200 void lclRemoveDocBasicItem( StarBASIC
& rDocBasic
)
202 auto it
= gaDocBasicItems
.find( &rDocBasic
);
203 if( it
!= gaDocBasicItems
.end() )
205 it
->second
->stopListening();
206 gaDocBasicItems
.erase( it
);
208 for( auto& rEntry
: gaDocBasicItems
)
210 rEntry
.second
->clearDependingVarsOnDelete( rDocBasic
);
214 StarBASIC
* lclGetDocBasicForModule( SbModule
* pModule
)
216 StarBASIC
* pRetBasic
= nullptr;
217 SbxObject
* pCurParent
= pModule
;
218 while( pCurParent
->GetParent() != nullptr )
220 pCurParent
= pCurParent
->GetParent();
221 StarBASIC
* pDocBasic
= dynamic_cast<StarBASIC
*>( pCurParent
);
222 if( pDocBasic
!= nullptr && pDocBasic
->IsDocBasic() )
224 pRetBasic
= pDocBasic
;
234 SbxObject
* StarBASIC::getVBAGlobals( )
236 if ( !pVBAGlobals
.is() )
239 if ( GetUNOConstant(u
"ThisComponent"_ustr
, aThisDoc
) )
241 Reference
< XMultiServiceFactory
> xDocFac( aThisDoc
, UNO_QUERY
);
246 xDocFac
->createInstance(u
"ooo.vba.VBAGlobals"_ustr
);
248 catch(const Exception
& )
254 pVBAGlobals
= static_cast<SbUnoObject
*>(Find( u
"VBAGlobals"_ustr
, SbxClassType::DontCare
));
256 return pVBAGlobals
.get();
260 SbxVariable
* StarBASIC::VBAFind( const OUString
& rName
, SbxClassType t
)
262 if( rName
== "ThisComponent" )
266 // rename to init globals
267 if ( getVBAGlobals( ) )
269 return pVBAGlobals
->Find( rName
, t
);
276 // Create array for conversion SFX <-> VB error code
277 struct SFX_VB_ErrorItem
285 const SFX_VB_ErrorItem SFX_VB_ErrorTab
[] =
287 { 1, ERRCODE_BASIC_EXCEPTION
}, // #87844 Map exception to error code 1
288 { 2, ERRCODE_BASIC_SYNTAX
},
289 { 3, ERRCODE_BASIC_NO_GOSUB
},
290 { 4, ERRCODE_BASIC_REDO_FROM_START
},
291 { 5, ERRCODE_BASIC_BAD_ARGUMENT
},
292 { 6, ERRCODE_BASIC_MATH_OVERFLOW
},
293 { 7, ERRCODE_BASIC_NO_MEMORY
},
294 { 8, ERRCODE_BASIC_ALREADY_DIM
},
295 { 9, ERRCODE_BASIC_OUT_OF_RANGE
},
296 { 10, ERRCODE_BASIC_DUPLICATE_DEF
},
297 { 11, ERRCODE_BASIC_ZERODIV
},
298 { 12, ERRCODE_BASIC_VAR_UNDEFINED
},
299 { 13, ERRCODE_BASIC_CONVERSION
},
300 { 14, ERRCODE_BASIC_BAD_PARAMETER
},
301 { 18, ERRCODE_BASIC_USER_ABORT
},
302 { 20, ERRCODE_BASIC_BAD_RESUME
},
303 { 28, ERRCODE_BASIC_STACK_OVERFLOW
},
304 { 35, ERRCODE_BASIC_PROC_UNDEFINED
},
305 { 48, ERRCODE_BASIC_BAD_DLL_LOAD
},
306 { 49, ERRCODE_BASIC_BAD_DLL_CALL
},
307 { 51, ERRCODE_BASIC_INTERNAL_ERROR
},
308 { 52, ERRCODE_BASIC_BAD_CHANNEL
},
309 { 53, ERRCODE_BASIC_FILE_NOT_FOUND
},
310 { 54, ERRCODE_BASIC_BAD_FILE_MODE
},
311 { 55, ERRCODE_BASIC_FILE_ALREADY_OPEN
},
312 { 57, ERRCODE_BASIC_IO_ERROR
},
313 { 58, ERRCODE_BASIC_FILE_EXISTS
},
314 { 59, ERRCODE_BASIC_BAD_RECORD_LENGTH
},
315 { 61, ERRCODE_BASIC_DISK_FULL
},
316 { 62, ERRCODE_BASIC_READ_PAST_EOF
},
317 { 63, ERRCODE_BASIC_BAD_RECORD_NUMBER
},
318 { 67, ERRCODE_BASIC_TOO_MANY_FILES
},
319 { 68, ERRCODE_BASIC_NO_DEVICE
},
320 { 70, ERRCODE_BASIC_ACCESS_DENIED
},
321 { 71, ERRCODE_BASIC_NOT_READY
},
322 { 73, ERRCODE_BASIC_NOT_IMPLEMENTED
},
323 { 74, ERRCODE_BASIC_DIFFERENT_DRIVE
},
324 { 75, ERRCODE_BASIC_ACCESS_ERROR
},
325 { 76, ERRCODE_BASIC_PATH_NOT_FOUND
},
326 { 91, ERRCODE_BASIC_NO_OBJECT
},
327 { 93, ERRCODE_BASIC_BAD_PATTERN
},
328 { 94, ERRCODE_BASIC_IS_NULL
},
329 { 250, ERRCODE_BASIC_DDE_ERROR
},
330 { 280, ERRCODE_BASIC_DDE_WAITINGACK
},
331 { 281, ERRCODE_BASIC_DDE_OUTOFCHANNELS
},
332 { 282, ERRCODE_BASIC_DDE_NO_RESPONSE
},
333 { 283, ERRCODE_BASIC_DDE_MULT_RESPONSES
},
334 { 284, ERRCODE_BASIC_DDE_CHANNEL_LOCKED
},
335 { 285, ERRCODE_BASIC_DDE_NOTPROCESSED
},
336 { 286, ERRCODE_BASIC_DDE_TIMEOUT
},
337 { 287, ERRCODE_BASIC_DDE_USER_INTERRUPT
},
338 { 288, ERRCODE_BASIC_DDE_BUSY
},
339 { 289, ERRCODE_BASIC_DDE_NO_DATA
},
340 { 290, ERRCODE_BASIC_DDE_WRONG_DATA_FORMAT
},
341 { 291, ERRCODE_BASIC_DDE_PARTNER_QUIT
},
342 { 292, ERRCODE_BASIC_DDE_CONV_CLOSED
},
343 { 293, ERRCODE_BASIC_DDE_NO_CHANNEL
},
344 { 294, ERRCODE_BASIC_DDE_INVALID_LINK
},
345 { 295, ERRCODE_BASIC_DDE_QUEUE_OVERFLOW
},
346 { 296, ERRCODE_BASIC_DDE_LINK_ALREADY_EST
},
347 { 297, ERRCODE_BASIC_DDE_LINK_INV_TOPIC
},
348 { 298, ERRCODE_BASIC_DDE_DLL_NOT_FOUND
},
349 { 323, ERRCODE_BASIC_CANNOT_LOAD
},
350 { 341, ERRCODE_BASIC_BAD_INDEX
},
351 { 366, ERRCODE_BASIC_NO_ACTIVE_OBJECT
},
352 { 380, ERRCODE_BASIC_BAD_PROP_VALUE
},
353 { 382, ERRCODE_BASIC_PROP_READONLY
},
354 { 394, ERRCODE_BASIC_PROP_WRITEONLY
},
355 { 420, ERRCODE_BASIC_INVALID_OBJECT
},
356 { 423, ERRCODE_BASIC_NO_METHOD
},
357 { 424, ERRCODE_BASIC_NEEDS_OBJECT
},
358 { 425, ERRCODE_BASIC_INVALID_USAGE_OBJECT
},
359 { 430, ERRCODE_BASIC_NO_OLE
},
360 { 438, ERRCODE_BASIC_BAD_METHOD
},
361 { 440, ERRCODE_BASIC_OLE_ERROR
},
362 { 445, ERRCODE_BASIC_BAD_ACTION
},
363 { 446, ERRCODE_BASIC_NO_NAMED_ARGS
},
364 { 447, ERRCODE_BASIC_BAD_LOCALE
},
365 { 448, ERRCODE_BASIC_NAMED_NOT_FOUND
},
366 { 449, ERRCODE_BASIC_NOT_OPTIONAL
},
367 { 450, ERRCODE_BASIC_WRONG_ARGS
},
368 { 451, ERRCODE_BASIC_NOT_A_COLL
},
369 { 452, ERRCODE_BASIC_BAD_ORDINAL
},
370 { 453, ERRCODE_BASIC_DLLPROC_NOT_FOUND
},
371 { 460, ERRCODE_BASIC_BAD_CLIPBD_FORMAT
},
372 { 951, ERRCODE_BASIC_UNEXPECTED
},
373 { 952, ERRCODE_BASIC_EXPECTED
},
374 { 953, ERRCODE_BASIC_SYMBOL_EXPECTED
},
375 { 954, ERRCODE_BASIC_VAR_EXPECTED
},
376 { 955, ERRCODE_BASIC_LABEL_EXPECTED
},
377 { 956, ERRCODE_BASIC_LVALUE_EXPECTED
},
378 { 957, ERRCODE_BASIC_VAR_DEFINED
},
379 { 958, ERRCODE_BASIC_PROC_DEFINED
},
380 { 959, ERRCODE_BASIC_LABEL_DEFINED
},
381 { 960, ERRCODE_BASIC_UNDEF_VAR
},
382 { 961, ERRCODE_BASIC_UNDEF_ARRAY
},
383 { 962, ERRCODE_BASIC_UNDEF_PROC
},
384 { 963, ERRCODE_BASIC_UNDEF_LABEL
},
385 { 964, ERRCODE_BASIC_UNDEF_TYPE
},
386 { 965, ERRCODE_BASIC_BAD_EXIT
},
387 { 966, ERRCODE_BASIC_BAD_BLOCK
},
388 { 967, ERRCODE_BASIC_BAD_BRACKETS
},
389 { 968, ERRCODE_BASIC_BAD_DECLARATION
},
390 { 969, ERRCODE_BASIC_BAD_PARAMETERS
},
391 { 970, ERRCODE_BASIC_BAD_CHAR_IN_NUMBER
},
392 { 971, ERRCODE_BASIC_MUST_HAVE_DIMS
},
393 { 972, ERRCODE_BASIC_NO_IF
},
394 { 973, ERRCODE_BASIC_NOT_IN_SUBR
},
395 { 974, ERRCODE_BASIC_NOT_IN_MAIN
},
396 { 975, ERRCODE_BASIC_WRONG_DIMS
},
397 { 976, ERRCODE_BASIC_BAD_OPTION
},
398 { 977, ERRCODE_BASIC_CONSTANT_REDECLARED
},
399 { 978, ERRCODE_BASIC_PROG_TOO_LARGE
},
400 { 979, ERRCODE_BASIC_NO_STRINGS_ARRAYS
},
401 { 1000, ERRCODE_BASIC_PROPERTY_NOT_FOUND
},
402 { 1001, ERRCODE_BASIC_METHOD_NOT_FOUND
},
403 { 1002, ERRCODE_BASIC_ARG_MISSING
},
404 { 1003, ERRCODE_BASIC_BAD_NUMBER_OF_ARGS
},
405 { 1004, ERRCODE_BASIC_METHOD_FAILED
},
406 { 1005, ERRCODE_BASIC_SETPROP_FAILED
},
407 { 1006, ERRCODE_BASIC_GETPROP_FAILED
},
408 { 1007, ERRCODE_BASIC_COMPAT
},
409 { 0xFFFF, ErrCode(0xFFFFFFFFUL
) } // End mark
412 // The StarBASIC factory is a hack. When a SbModule is created, its pointer
413 // is saved and given to the following SbProperties/SbMethods. This restores
414 // the Module-relationship. But it works only when a module is loaded.
415 // Can cause troubles with separately loaded properties!
417 SbxBaseRef
SbiFactory::Create( sal_uInt16 nSbxId
, sal_uInt32 nCreator
)
419 if( nCreator
== SBXCR_SBX
)
424 return new StarBASIC( nullptr );
426 return new SbModule( u
""_ustr
);
427 case SBXID_BASICPROP
:
428 return new SbProperty( u
""_ustr
, SbxVARIANT
, nullptr );
429 case SBXID_BASICMETHOD
:
430 return new SbMethod( u
""_ustr
, SbxVARIANT
, nullptr );
431 case SBXID_JSCRIPTMOD
:
432 return new SbJScriptModule
;
433 case SBXID_JSCRIPTMETH
:
434 return new SbJScriptMethod( SbxVARIANT
);
440 SbxObjectRef
SbiFactory::CreateObject( const OUString
& rClass
)
442 if( rClass
.equalsIgnoreAsciiCase( "StarBASIC" ) )
444 return new StarBASIC( nullptr );
446 else if( rClass
.equalsIgnoreAsciiCase( "StarBASICModule" ) )
448 return new SbModule( OUString() );
450 else if( rClass
.equalsIgnoreAsciiCase( "Collection" ) )
452 return new BasicCollection( u
"Collection"_ustr
);
454 else if( rClass
.equalsIgnoreAsciiCase( "FileSystemObject" ) )
458 Reference
< XMultiServiceFactory
> xFactory( comphelper::getProcessServiceFactory(), UNO_SET_THROW
);
459 OUString
aServiceName(u
"ooo.vba.FileSystemObject"_ustr
);
460 Reference
< XInterface
> xInterface( xFactory
->createInstance( aServiceName
), UNO_SET_THROW
);
461 return new SbUnoObject( aServiceName
, uno::Any( xInterface
) );
463 catch(const Exception
& )
471 SbxBaseRef
SbOLEFactory::Create( sal_uInt16
, sal_uInt32
)
477 SbxObjectRef
SbOLEFactory::CreateObject( const OUString
& rClassName
)
479 SbxObjectRef pRet
= createOLEObject_Impl( rClassName
);
484 // SbFormFactory, show user forms by: dim as new <user form name>
486 SbxBaseRef
SbFormFactory::Create( sal_uInt16
, sal_uInt32
)
492 SbxObjectRef
SbFormFactory::CreateObject( const OUString
& rClassName
)
494 if( SbModule
* pMod
= GetSbData()->pMod
)
496 if( SbxVariable
* pVar
= pMod
->Find( rClassName
, SbxClassType::Object
) )
498 if( SbUserFormModule
* pFormModule
= dynamic_cast<SbUserFormModule
*>( pVar
->GetObject() ) )
500 bool bInitState
= pFormModule
->getInitState();
503 // Not the first instantiate, reset
504 pFormModule
->ResetApiObj( false/*bTriggerTerminateEvent*/ );
505 pFormModule
->setInitState( false );
511 return pFormModule
->CreateInstance();
521 SbxObjectRef
cloneTypeObjectImpl( const SbxObject
& rTypeObj
)
523 SbxObjectRef pRet
= new SbxObject( rTypeObj
);
524 pRet
->PutObject( pRet
.get() );
526 // Copy the properties, not only the reference to them
527 SbxArray
* pProps
= pRet
->GetProperties();
528 sal_uInt32 nCount
= pProps
->Count();
529 for( sal_uInt32 i
= 0 ; i
< nCount
; i
++ )
531 SbxVariable
* pVar
= pProps
->Get(i
);
532 SbxProperty
* pProp
= dynamic_cast<SbxProperty
*>( pVar
);
535 SbxProperty
* pNewProp
= new SbxProperty( *pProp
);
536 SbxDataType eVarType
= pVar
->GetType();
537 if( eVarType
& SbxARRAY
)
539 SbxBase
* pParObj
= pVar
->GetObject();
540 SbxDimArray
* pSource
= dynamic_cast<SbxDimArray
*>( pParObj
);
541 SbxDimArray
* pDest
= new SbxDimArray( pVar
->GetType() );
543 pDest
->setHasFixedSize( pSource
&& pSource
->hasFixedSize() );
544 if (pSource
&& pSource
->GetDims() && pSource
->hasFixedSize())
548 for (sal_Int32 j
= 1; j
<= pSource
->GetDims(); ++j
)
550 pSource
->GetDim(j
, lb
, ub
);
551 pDest
->AddDim(lb
, ub
);
556 pDest
->unoAddDim(0, -1); // variant array
558 SbxFlagBits nSavFlags
= pVar
->GetFlags();
559 pNewProp
->ResetFlag( SbxFlagBits::Fixed
);
560 // need to reset the FIXED flag
561 // when calling PutObject ( because the type will not match Object )
562 pNewProp
->PutObject( pDest
);
563 pNewProp
->SetFlags( nSavFlags
);
565 if( eVarType
== SbxOBJECT
)
567 SbxBase
* pObjBase
= pVar
->GetObject();
568 SbxObject
* pSrcObj
= dynamic_cast<SbxObject
*>( pObjBase
);
569 SbxObjectRef pDestObj
;
570 if( pSrcObj
!= nullptr )
571 pDestObj
= cloneTypeObjectImpl( *pSrcObj
);
572 pNewProp
->PutObject( pDestObj
.get() );
574 pProps
->PutDirect( pNewProp
, i
);
580 SbxBaseRef
SbTypeFactory::Create( sal_uInt16
, sal_uInt32
)
586 SbxObjectRef
SbTypeFactory::CreateObject( const OUString
& rClassName
)
589 SbModule
* pMod
= GetSbData()->pMod
;
592 const SbxObject
* pObj
= pMod
->FindType( rClassName
);
595 pRet
= cloneTypeObjectImpl( *pObj
);
601 SbxObjectRef
createUserTypeImpl( const OUString
& rClassName
)
603 SbxObjectRef pRetObj
= GetSbData()->pTypeFac
->CreateObject( rClassName
);
607 SbClassModuleObject::SbClassModuleObject(SbModule
& rClassModule
)
608 : SbModule(rClassModule
.GetName())
609 , mrClassModule(rClassModule
)
610 , mbInitializeEventDone( false )
612 aOUSource
= rClassModule
.aOUSource
;
613 aComment
= rClassModule
.aComment
;
614 pImage
= rClassModule
.pImage
;
615 pBreaks
= rClassModule
.pBreaks
;
617 SetClassName(rClassModule
.GetName());
619 // Allow search only internally
620 ResetFlag( SbxFlagBits::GlobalSearch
);
622 // Copy the methods from original class module
623 SbxArray
* pClassMethods
= rClassModule
.GetMethods().get();
624 sal_uInt32 nMethodCount
= pClassMethods
->Count();
626 for( i
= 0 ; i
< nMethodCount
; i
++ )
628 SbxVariable
* pVar
= pClassMethods
->Get(i
);
630 // Exclude SbIfaceMapperMethod to copy them in a second step
631 SbIfaceMapperMethod
* pIfaceMethod
= dynamic_cast<SbIfaceMapperMethod
*>( pVar
);
634 SbMethod
* pMethod
= dynamic_cast<SbMethod
*>( pVar
);
637 SbxFlagBits nFlags_
= pMethod
->GetFlags();
638 pMethod
->SetFlag( SbxFlagBits::NoBroadcast
);
639 SbMethod
* pNewMethod
= new SbMethod( *pMethod
);
640 pNewMethod
->ResetFlag( SbxFlagBits::NoBroadcast
);
641 pMethod
->SetFlags( nFlags_
);
642 pNewMethod
->pMod
= this;
643 pNewMethod
->SetParent( this );
644 pMethods
->PutDirect( pNewMethod
, i
);
645 StartListening(pNewMethod
->GetBroadcaster(), DuplicateHandling::Prevent
);
650 // Copy SbIfaceMapperMethod in a second step to ensure that
651 // the corresponding base methods have already been copied
652 for( i
= 0 ; i
< nMethodCount
; i
++ )
654 SbxVariable
* pVar
= pClassMethods
->Get(i
);
656 SbIfaceMapperMethod
* pIfaceMethod
= dynamic_cast<SbIfaceMapperMethod
*>( pVar
);
659 SbMethod
* pImplMethod
= pIfaceMethod
->getImplMethod();
662 OSL_FAIL( "No ImplMethod" );
666 // Search for own copy of ImplMethod
667 SbxVariable
* p
= pMethods
->Find( pImplMethod
->GetName(), SbxClassType::Method
);
668 SbMethod
* pImplMethodCopy
= dynamic_cast<SbMethod
*>( p
);
669 if( !pImplMethodCopy
)
671 OSL_FAIL( "Found no ImplMethod copy" );
674 SbIfaceMapperMethod
* pNewIfaceMethod
=
675 new SbIfaceMapperMethod( pIfaceMethod
->GetName(), pImplMethodCopy
);
676 pMethods
->PutDirect( pNewIfaceMethod
, i
);
680 // Copy the properties from original class module
681 SbxArray
* pClassProps
= rClassModule
.GetProperties();
682 sal_uInt32 nPropertyCount
= pClassProps
->Count();
683 for( i
= 0 ; i
< nPropertyCount
; i
++ )
685 SbxVariable
* pVar
= pClassProps
->Get(i
);
686 SbProcedureProperty
* pProcedureProp
= dynamic_cast<SbProcedureProperty
*>( pVar
);
689 SbxFlagBits nFlags_
= pProcedureProp
->GetFlags();
690 pProcedureProp
->SetFlag( SbxFlagBits::NoBroadcast
);
691 SbProcedureProperty
* pNewProp
= new SbProcedureProperty
692 ( pProcedureProp
->GetName(), pProcedureProp
->GetType() );
693 pNewProp
->SetFlags( nFlags_
); // Copy flags
694 pNewProp
->ResetFlag( SbxFlagBits::NoBroadcast
); // except the Broadcast if it was set
695 pProcedureProp
->SetFlags( nFlags_
);
696 pProps
->PutDirect( pNewProp
, i
);
697 StartListening(pNewProp
->GetBroadcaster(), DuplicateHandling::Prevent
);
701 SbxProperty
* pProp
= dynamic_cast<SbxProperty
*>( pVar
);
704 SbxFlagBits nFlags_
= pProp
->GetFlags();
705 pProp
->SetFlag( SbxFlagBits::NoBroadcast
);
706 SbxProperty
* pNewProp
= new SbxProperty( *pProp
);
708 // Special handling for modules instances and collections, they need
709 // to be instantiated, otherwise all refer to the same base object
710 SbxDataType eVarType
= pProp
->GetType();
711 if( eVarType
== SbxOBJECT
)
713 SbxBase
* pObjBase
= pProp
->GetObject();
714 SbxObject
* pObj
= dynamic_cast<SbxObject
*>( pObjBase
);
715 if( pObj
!= nullptr )
717 const OUString
& aObjClass
= pObj
->GetClassName();
719 SbClassModuleObject
* pClassModuleObj
= dynamic_cast<SbClassModuleObject
*>( pObjBase
);
720 if( pClassModuleObj
!= nullptr )
722 SbModule
& rLclClassModule
= pClassModuleObj
->getClassModule();
723 SbClassModuleObject
* pNewObj
= new SbClassModuleObject(rLclClassModule
);
724 pNewObj
->SetName( pProp
->GetName() );
725 pNewObj
->SetParent(rLclClassModule
.pParent
);
726 pNewProp
->PutObject( pNewObj
);
728 else if( aObjClass
.equalsIgnoreAsciiCase( "Collection" ) )
730 BasicCollection
* pNewCollection
= new BasicCollection( u
"Collection"_ustr
);
731 pNewCollection
->SetName( pProp
->GetName() );
732 pNewCollection
->SetParent(rClassModule
.pParent
);
733 pNewProp
->PutObject( pNewCollection
);
738 pNewProp
->ResetFlag( SbxFlagBits::NoBroadcast
);
739 pNewProp
->SetParent( this );
740 pProps
->PutDirect( pNewProp
, i
);
741 pProp
->SetFlags( nFlags_
);
745 SetModuleType( ModuleType::CLASS
);
746 mbVBASupport
= rClassModule
.mbVBASupport
;
749 SbClassModuleObject::~SbClassModuleObject()
751 // do not trigger termination event when document is already closed
752 if( StarBASIC::IsRunning() )
753 if( StarBASIC
* pDocBasic
= lclGetDocBasicForModule( this ) )
754 if( const DocBasicItem
* pDocBasicItem
= lclFindDocBasicItem( pDocBasic
) )
755 if( !pDocBasicItem
->isDocClosed() )
756 triggerTerminateEvent();
759 void SbClassModuleObject::Notify( SfxBroadcaster
& rBC
, const SfxHint
& rHint
)
761 handleProcedureProperties( rBC
, rHint
);
764 SbxVariable
* SbClassModuleObject::Find( const OUString
& rName
, SbxClassType t
)
766 SbxVariable
* pRes
= SbxObject::Find( rName
, t
);
769 triggerInitializeEvent();
771 SbIfaceMapperMethod
* pIfaceMapperMethod
= dynamic_cast<SbIfaceMapperMethod
*>( pRes
);
772 if( pIfaceMapperMethod
)
774 pRes
= pIfaceMapperMethod
->getImplMethod();
775 pRes
->SetFlag( SbxFlagBits::ExtFound
);
781 void SbClassModuleObject::triggerInitializeEvent()
783 if( mbInitializeEventDone
)
788 mbInitializeEventDone
= true;
791 SbxVariable
* pMeth
= SbxObject::Find(u
"Class_Initialize"_ustr
, SbxClassType::Method
);
799 void SbClassModuleObject::triggerTerminateEvent()
801 if( !mbInitializeEventDone
|| GetSbData()->bRunInit
)
806 SbxVariable
* pMeth
= SbxObject::Find(u
"Class_Terminate"_ustr
, SbxClassType::Method
);
815 SbClassData::SbClassData()
817 mxIfaces
= new SbxArray();
820 void SbClassData::clear()
823 maRequiredTypes
.clear();
826 SbClassFactory::SbClassFactory()
828 xClassModules
= new SbxObject( OUString() );
831 SbClassFactory::~SbClassFactory()
834 void SbClassFactory::AddClassModule( SbModule
* pClassModule
)
836 SbxObjectRef xToUseClassModules
= xClassModules
;
838 if( StarBASIC
* pDocBasic
= lclGetDocBasicForModule( pClassModule
) )
839 if( const DocBasicItem
* pDocBasicItem
= lclFindDocBasicItem( pDocBasic
) )
840 xToUseClassModules
= pDocBasicItem
->getClassModules();
842 SbxObject
* pParent
= pClassModule
->GetParent();
843 xToUseClassModules
->Insert( pClassModule
);
844 pClassModule
->SetParent( pParent
);
847 void SbClassFactory::RemoveClassModule( SbModule
* pClassModule
)
849 xClassModules
->Remove( pClassModule
);
852 SbxBaseRef
SbClassFactory::Create( sal_uInt16
, sal_uInt32
)
858 SbxObjectRef
SbClassFactory::CreateObject( const OUString
& rClassName
)
860 SbxObjectRef xToUseClassModules
= xClassModules
;
862 if( SbModule
* pMod
= GetSbData()->pMod
)
864 if( StarBASIC
* pDocBasic
= lclGetDocBasicForModule( pMod
) )
866 if( const DocBasicItem
* pDocBasicItem
= lclFindDocBasicItem( pDocBasic
) )
868 xToUseClassModules
= pDocBasicItem
->getClassModules();
872 SbxVariable
* pVar
= xToUseClassModules
->Find( rClassName
, SbxClassType::Object
);
876 SbModule
* pVarMod
= static_cast<SbModule
*>(pVar
);
877 pRet
= new SbClassModuleObject(*pVarMod
);
882 SbModule
* SbClassFactory::FindClass( const OUString
& rClassName
)
884 SbxVariable
* pVar
= xClassModules
->Find( rClassName
, SbxClassType::DontCare
);
885 SbModule
* pMod
= pVar
? static_cast<SbModule
*>(pVar
) : nullptr;
889 StarBASIC::StarBASIC( StarBASIC
* p
, bool bIsDocBasic
)
890 : SbxObject(u
"StarBASIC"_ustr
), bDocBasic( bIsDocBasic
)
893 bNoRtl
= bBreak
= false;
896 if( !GetSbData()->nInst
++ )
898 GetSbData()->pSbFac
.emplace();
899 AddFactory( &*GetSbData()->pSbFac
);
900 GetSbData()->pTypeFac
.emplace();
901 AddFactory( &*GetSbData()->pTypeFac
);
902 GetSbData()->pClassFac
.reset(new SbClassFactory
);
903 AddFactory( GetSbData()->pClassFac
.get() );
904 GetSbData()->pOLEFac
.emplace();
905 AddFactory( &*GetSbData()->pOLEFac
);
906 GetSbData()->pFormFac
.emplace();
907 AddFactory( &*GetSbData()->pFormFac
);
908 GetSbData()->pUnoFac
.emplace();
909 AddFactory( &*GetSbData()->pUnoFac
);
911 pRtl
= new SbiStdObject(SB_RTLNAME
, this );
912 // Search via StarBasic is always global
913 SetFlag( SbxFlagBits::GlobalSearch
);
914 pVBAGlobals
= nullptr;
919 lclInsertDocBasicItem( *this );
923 // #51727 Override SetModified so that the modified state
924 // is not given to the parent
925 void StarBASIC::SetModified( bool b
)
927 SbxBase::SetModified( b
);
930 StarBASIC::~StarBASIC()
932 // Needs to be first action as it can trigger events
933 disposeComVariablesForBasic( this );
935 if( !--GetSbData()->nInst
)
937 RemoveFactory( &*GetSbData()->pSbFac
);
938 GetSbData()->pSbFac
.reset();
939 RemoveFactory( &*GetSbData()->pUnoFac
);
940 GetSbData()->pUnoFac
.reset();
941 RemoveFactory( &*GetSbData()->pTypeFac
);
942 GetSbData()->pTypeFac
.reset();
943 RemoveFactory( GetSbData()->pClassFac
.get() );
944 GetSbData()->pClassFac
.reset();
945 RemoveFactory( &*GetSbData()->pOLEFac
);
946 GetSbData()->pOLEFac
.reset();
947 RemoveFactory( &*GetSbData()->pFormFac
);
948 GetSbData()->pFormFac
.reset();
950 if( SbiGlobals::pGlobals
)
952 delete SbiGlobals::pGlobals
;
953 SbiGlobals::pGlobals
= nullptr;
958 ErrCode eOld
= SbxBase::GetError();
960 lclRemoveDocBasicItem( *this );
962 SbxBase::ResetError();
963 if( eOld
!= ERRCODE_NONE
)
965 SbxBase::SetError( eOld
);
969 // #100326 Set Parent NULL in registered listeners
970 if( xUnoListeners
.is() )
972 sal_uInt32 uCount
= xUnoListeners
->Count();
973 for( sal_uInt32 i
= 0 ; i
< uCount
; i
++ )
975 SbxVariable
* pListenerObj
= xUnoListeners
->Get(i
);
976 pListenerObj
->SetParent( nullptr );
978 xUnoListeners
= nullptr;
981 clearUnoMethodsForBasic( this );
984 void StarBASIC::implClearDependingVarsOnDelete( StarBASIC
* pDeletedBasic
)
986 if( this != pDeletedBasic
)
988 for( const auto& pModule
: pModules
)
990 pModule
->ClearVarsDependingOnDeletedBasic( pDeletedBasic
);
994 for (sal_uInt32 nObj
= 0; nObj
< pObjs
->Count(); nObj
++)
996 SbxVariable
* pVar
= pObjs
->Get(nObj
);
997 StarBASIC
* pBasic
= dynamic_cast<StarBASIC
*>( pVar
);
998 if( pBasic
&& pBasic
!= pDeletedBasic
)
1000 pBasic
->implClearDependingVarsOnDelete( pDeletedBasic
);
1006 SbModule
* StarBASIC::MakeModule( const OUString
& rName
, const OUString
& rSrc
)
1009 aInfo
.ModuleType
= ModuleType::NORMAL
;
1010 return MakeModule( rName
, aInfo
, rSrc
);
1012 SbModule
* StarBASIC::MakeModule( const OUString
& rName
, const ModuleInfo
& mInfo
, const OUString
& rSrc
)
1017 "create module " << rName
<< " type mInfo " << mInfo
.ModuleType
);
1018 SbModule
* p
= nullptr;
1019 switch ( mInfo
.ModuleType
)
1021 case ModuleType::DOCUMENT
:
1022 // In theory we should be able to create Object modules
1023 // in ordinary basic ( in vba mode thought these are create
1024 // by the application/basic and not by the user )
1025 p
= new SbObjModule( rName
, mInfo
, isVBAEnabled() );
1027 case ModuleType::CLASS
:
1028 p
= new SbModule( rName
, isVBAEnabled() );
1029 p
->SetModuleType( ModuleType::CLASS
);
1031 case ModuleType::FORM
:
1032 p
= new SbUserFormModule( rName
, mInfo
, isVBAEnabled() );
1035 p
= new SbModule( rName
, isVBAEnabled() );
1038 p
->SetSource32( rSrc
);
1039 p
->SetParent( this );
1040 pModules
.emplace_back(p
);
1041 SetModified( true );
1045 void StarBASIC::Insert( SbxVariable
* pVar
)
1047 if( auto pModule
= dynamic_cast<SbModule
*>(pVar
) )
1049 pModules
.emplace_back(pModule
);
1050 pVar
->SetParent( this );
1051 StartListening(pVar
->GetBroadcaster(), DuplicateHandling::Prevent
);
1055 bool bWasModified
= IsModified();
1056 SbxObject::Insert( pVar
);
1057 if( !bWasModified
&& pVar
->IsSet( SbxFlagBits::DontStore
) )
1059 SetModified( false );
1064 void StarBASIC::Remove( SbxVariable
* pVar
)
1066 SbModule
* pModule
= dynamic_cast<SbModule
*>(pVar
);
1069 // #87540 Can be last reference!
1070 SbModuleRef xVar
= pModule
;
1071 std::erase(pModules
, xVar
);
1072 pVar
->SetParent( nullptr );
1073 EndListening( pVar
->GetBroadcaster() );
1077 SbxObject::Remove( pVar
);
1081 void StarBASIC::Clear()
1086 SbModule
* StarBASIC::FindModule( std::u16string_view rName
)
1088 for (const auto& pModule
: pModules
)
1090 if( pModule
->GetName().equalsIgnoreAsciiCase( rName
) )
1092 return pModule
.get();
1099 struct ClassModuleRunInitItem
1101 SbModule
* m_pModule
;
1103 bool m_bRunInitDone
;
1105 ClassModuleRunInitItem()
1106 : m_pModule( nullptr )
1107 , m_bProcessing( false )
1108 , m_bRunInitDone( false )
1110 explicit ClassModuleRunInitItem( SbModule
* pModule
)
1111 : m_pModule( pModule
)
1112 , m_bProcessing( false )
1113 , m_bRunInitDone( false )
1117 // Derive from unordered_map type instead of typedef
1118 // to allow forward declaration in sbmod.hxx
1119 class ModuleInitDependencyMap
: public
1120 std::unordered_map
< OUString
, ClassModuleRunInitItem
>
1123 void SbModule::implProcessModuleRunInit( ModuleInitDependencyMap
& rMap
, ClassModuleRunInitItem
& rItem
)
1125 rItem
.m_bProcessing
= true;
1127 SbModule
* pModule
= rItem
.m_pModule
;
1128 if( pModule
->pClassData
!= nullptr )
1130 std::vector
< OUString
>& rReqTypes
= pModule
->pClassData
->maRequiredTypes
;
1131 for( const auto& rStr
: rReqTypes
)
1133 // Is required type a class module?
1134 ModuleInitDependencyMap::iterator itFind
= rMap
.find( rStr
);
1135 if( itFind
!= rMap
.end() )
1137 ClassModuleRunInitItem
& rParentItem
= itFind
->second
;
1138 if( rParentItem
.m_bProcessing
)
1140 // TODO: raise error?
1141 OSL_FAIL( "Cyclic module dependency detected" );
1145 if( !rParentItem
.m_bRunInitDone
)
1147 implProcessModuleRunInit( rMap
, rParentItem
);
1154 rItem
.m_bRunInitDone
= true;
1155 rItem
.m_bProcessing
= false;
1158 // Run Init-Code of all modules (including inserted libraries)
1159 void StarBASIC::InitAllModules( StarBASIC
const * pBasicNotToInit
)
1161 SolarMutexGuard guard
;
1164 for (const auto& pModule
: pModules
)
1168 // compile modules first then RunInit ( otherwise there is
1169 // can be order dependency, e.g. classmodule A has a member
1170 // of type classmodule B and classmodule B hasn't been compiled yet )
1172 // Consider required types to init in right order. Class modules
1173 // that are required by other modules have to be initialized first.
1174 ModuleInitDependencyMap aMIDMap
;
1175 for (const auto& pModule
: pModules
)
1177 OUString aModuleName
= pModule
->GetName();
1178 if( pModule
->isProxyModule() )
1180 aMIDMap
[aModuleName
] = ClassModuleRunInitItem( pModule
.get() );
1184 for (auto & elem
: aMIDMap
)
1186 ClassModuleRunInitItem
& rItem
= elem
.second
;
1187 SbModule::implProcessModuleRunInit( aMIDMap
, rItem
);
1190 // Call RunInit on standard modules
1191 for (const auto& pModule
: pModules
)
1193 if( !pModule
->isProxyModule() )
1199 // Check all objects if they are BASIC,
1200 // if yes initialize
1201 for (sal_uInt32 nObj
= 0; nObj
< pObjs
->Count(); nObj
++)
1203 SbxVariable
* pVar
= pObjs
->Get(nObj
);
1204 StarBASIC
* pBasic
= dynamic_cast<StarBASIC
*>( pVar
);
1205 if( pBasic
&& pBasic
!= pBasicNotToInit
)
1207 pBasic
->InitAllModules();
1212 // #88329 Put modules back to not initialised state to
1213 // force reinitialisation at next start
1214 void StarBASIC::DeInitAllModules()
1216 // Deinit own modules
1217 for (const auto& pModule
: pModules
)
1219 if( pModule
->pImage
&& !pModule
->isProxyModule() && dynamic_cast<SbObjModule
*>( pModule
.get()) == nullptr )
1221 pModule
->pImage
->bInit
= false;
1225 for (sal_uInt32 nObj
= 0; nObj
< pObjs
->Count(); nObj
++)
1227 SbxVariable
* pVar
= pObjs
->Get(nObj
);
1228 StarBASIC
* pBasic
= dynamic_cast<StarBASIC
*>( pVar
);
1231 pBasic
->DeInitAllModules();
1236 // This implementation at first searches within the runtime library,
1237 // then it looks for an element within one module. This module can be
1238 // a public var or an entrypoint. If it is not found and we look for a
1239 // method and a module with the given name is found the search continues
1240 // for entrypoint "Main".
1241 // If this fails again a conventional search over objects is performed.
1242 SbxVariable
* StarBASIC::Find( const OUString
& rName
, SbxClassType t
)
1244 SbxVariable
* pRes
= nullptr;
1245 SbModule
* pNamed
= nullptr;
1246 // "Extended" search in Runtime Lib
1247 // but only if SbiRuntime has not set the flag
1250 if( t
== SbxClassType::DontCare
|| t
== SbxClassType::Object
)
1252 if( rName
.equalsIgnoreAsciiCase( SB_RTLNAME
) )
1259 pRes
= static_cast<SbiStdObject
*>(pRtl
.get())->Find( rName
, t
);
1263 pRes
->SetFlag( SbxFlagBits::ExtFound
);
1269 for (const auto& pModule
: pModules
)
1271 if( pModule
->IsVisible() )
1273 // Remember module for Main() call
1274 // or is the name equal?!?
1275 if( pModule
->GetName().equalsIgnoreAsciiCase( rName
) )
1277 if( t
== SbxClassType::Object
|| t
== SbxClassType::DontCare
)
1279 pRes
= pModule
.get(); break;
1281 pNamed
= pModule
.get();
1283 // Only variables qualified by the Module Name e.g. Sheet1.foo
1284 // should work for Document && Class type Modules
1285 sal_Int32 nType
= pModule
->GetModuleType();
1286 if ( nType
== ModuleType::DOCUMENT
|| nType
== ModuleType::FORM
)
1290 // otherwise check if the element is available
1291 // unset GBLSEARCH-Flag (due to recursion)
1292 SbxFlagBits nGblFlag
= pModule
->GetFlags() & SbxFlagBits::GlobalSearch
;
1293 pModule
->ResetFlag( SbxFlagBits::GlobalSearch
);
1294 pRes
= pModule
->Find( rName
, t
);
1295 pModule
->SetFlag( nGblFlag
);
1303 static constexpr OUString
aMainStr(u
"Main"_ustr
);
1304 if( !pRes
&& pNamed
&& ( t
== SbxClassType::Method
|| t
== SbxClassType::DontCare
) &&
1305 !pNamed
->GetName().equalsIgnoreAsciiCase( aMainStr
) )
1307 pRes
= pNamed
->Find( aMainStr
, SbxClassType::Method
);
1311 pRes
= SbxObject::Find( rName
, t
);
1316 bool StarBASIC::Call( const OUString
& rName
, SbxArray
* pParam
)
1318 bool bRes
= SbxObject::Call( rName
, pParam
);
1321 ErrCode eErr
= SbxBase::GetError();
1322 if( eErr
!= ERRCODE_NONE
)
1324 RTError(eErr
, SbxBase::GetErrorMsg(), 0, 0, 0);
1326 SbxBase::ResetError();
1331 // Find method via name (e.g. query via BASIC IDE)
1332 SbxBase
* StarBASIC::FindSBXInCurrentScope( const OUString
& rName
)
1334 if( !GetSbData()->pInst
)
1338 if( !GetSbData()->pInst
->pRun
)
1342 return GetSbData()->pInst
->pRun
->FindElementExtern( rName
);
1345 void StarBASIC::QuitAndExitApplication()
1351 void StarBASIC::Stop()
1353 SbiInstance
* p
= GetSbData()->pInst
;
1358 bool StarBASIC::IsRunning()
1360 return GetSbData()->pInst
!= nullptr;
1363 SbMethod
* StarBASIC::GetActiveMethod( sal_uInt16 nLevel
)
1365 if( GetSbData()->pInst
)
1367 return GetSbData()->pInst
->GetCaller( nLevel
);
1375 SbModule
* StarBASIC::GetActiveModule()
1377 if( GetSbData()->pInst
&& !GetSbData()->bCompilerError
)
1379 return GetSbData()->pInst
->GetActiveModule();
1383 return GetSbData()->pCompMod
;
1387 BasicDebugFlags
StarBASIC::BreakPoint( sal_Int32 l
, sal_Int32 c1
, sal_Int32 c2
)
1389 SetErrorData( ERRCODE_NONE
, l
, c1
, c2
);
1391 if( GetSbData()->aBreakHdl
.IsSet() )
1393 return GetSbData()->aBreakHdl
.Call( this );
1401 BasicDebugFlags
StarBASIC::StepPoint( sal_Int32 l
, sal_Int32 c1
, sal_Int32 c2
)
1403 SetErrorData( ERRCODE_NONE
, l
, c1
, c2
);
1405 if( GetSbData()->aBreakHdl
.IsSet() )
1407 return GetSbData()->aBreakHdl
.Call( this );
1415 BasicDebugFlags
StarBASIC::BreakHdl()
1417 return aBreakHdl
.IsSet() ? aBreakHdl
.Call( this ) : BasicDebugFlags::Continue
;
1420 // Calls for error handler and break handler
1421 sal_uInt16
StarBASIC::GetLine() { return GetSbData()->nLine
; }
1422 sal_uInt16
StarBASIC::GetCol1() { return GetSbData()->nCol1
; }
1423 sal_uInt16
StarBASIC::GetCol2() { return GetSbData()->nCol2
; }
1425 // Specific to error handler
1426 ErrCodeMsg
const & StarBASIC::GetErrorCode() { return GetSbData()->nCode
; }
1427 const OUString
& StarBASIC::GetErrorText() { return GetSbData()->aErrMsg
; }
1430 // The mapping between the old and the new error codes take place by searching
1431 // through the table SFX_VB_ErrorTab[]. This is indeed not with good performance,
1432 // but it consumes much less memory than corresponding switch blocks.
1433 // Because the conversion of error codes has not to be fast. There is no
1434 // binary search by VB Error -> Error SFX.
1436 // Map back new error codes to old, Sbx-compatible
1437 sal_uInt16
StarBASIC::GetVBErrorCode( ErrCode nError
)
1439 sal_uInt16 nRet
= 0;
1441 if( SbiRuntime::isVBAEnabled() )
1443 if ( nError
== ERRCODE_BASIC_ARRAY_FIX
)
1445 else if ( nError
== ERRCODE_BASIC_STRING_OVERFLOW
)
1447 else if ( nError
== ERRCODE_BASIC_EXPR_TOO_COMPLEX
)
1449 else if ( nError
== ERRCODE_BASIC_OPER_NOT_PERFORM
)
1451 else if ( nError
== ERRCODE_BASIC_TOO_MANY_DLL
)
1453 else if ( nError
== ERRCODE_BASIC_LOOP_NOT_INIT
)
1460 const SFX_VB_ErrorItem
* pErrItem
;
1461 sal_uInt16 nIndex
= 0;
1464 pErrItem
= SFX_VB_ErrorTab
+ nIndex
;
1465 if( pErrItem
->nErrorSFX
== nError
)
1467 nRet
= pErrItem
->nErrorVB
;
1472 while( pErrItem
->nErrorVB
!= 0xFFFF ); // up to end mark
1476 ErrCode
StarBASIC::GetSfxFromVBError( sal_uInt16 nError
)
1478 ErrCode nRet
= ERRCODE_NONE
;
1480 if( SbiRuntime::isVBAEnabled() )
1490 return ERRCODE_NONE
;
1492 return ERRCODE_BASIC_ARRAY_FIX
;
1494 return ERRCODE_BASIC_STRING_OVERFLOW
;
1496 return ERRCODE_BASIC_EXPR_TOO_COMPLEX
;
1498 return ERRCODE_BASIC_OPER_NOT_PERFORM
;
1500 return ERRCODE_BASIC_TOO_MANY_DLL
;
1502 return ERRCODE_BASIC_LOOP_NOT_INIT
;
1504 nRet
= ERRCODE_NONE
;
1507 const SFX_VB_ErrorItem
* pErrItem
;
1508 sal_uInt16 nIndex
= 0;
1511 pErrItem
= SFX_VB_ErrorTab
+ nIndex
;
1512 if( pErrItem
->nErrorVB
== nError
)
1514 nRet
= pErrItem
->nErrorSFX
;
1517 else if( pErrItem
->nErrorVB
> nError
)
1519 break; // couldn't found anymore
1523 while( pErrItem
->nErrorVB
!= 0xFFFF ); // up to end mark
1527 // set Error- / Break-data
1528 void StarBASIC::SetErrorData( const ErrCodeMsg
& nCode
, sal_uInt16 nLine
,
1529 sal_uInt16 nCol1
, sal_uInt16 nCol2
)
1531 SbiGlobals
& aGlobals
= *GetSbData();
1532 aGlobals
.nCode
= nCode
;
1533 aGlobals
.nLine
= nLine
;
1534 aGlobals
.nCol1
= nCol1
;
1535 aGlobals
.nCol2
= nCol2
;
1538 void StarBASIC::MakeErrorText( ErrCode nId
, std::u16string_view aMsg
)
1540 SolarMutexGuard aSolarGuard
;
1541 sal_uInt16 nOldID
= GetVBErrorCode( nId
);
1543 TranslateId pErrorMsg
;
1544 for (std::pair
<TranslateId
, ErrCode
> const *pItem
= RID_BASIC_START
; pItem
->second
; ++pItem
)
1546 if (nId
== pItem
->second
)
1548 pErrorMsg
= pItem
->first
;
1555 // merge message with additional text
1556 OUString sError
= BasResId(pErrorMsg
);
1557 OUStringBuffer
aMsg1(sError
);
1558 // replace argument placeholder with %s
1559 OUString
aSrgStr( u
"$(ARG1)"_ustr
);
1560 sal_Int32 nResult
= sError
.indexOf(aSrgStr
);
1564 aMsg1
.remove(nResult
, aSrgStr
.getLength());
1565 aMsg1
.insert(nResult
, aMsg
);
1567 else if (!aMsg
.empty())
1569 // tdf#123144 - create a meaningful error message
1570 aMsg1
= BasResId(STR_ADDITIONAL_INFO
)
1571 .replaceFirst("$ERR", aMsg1
)
1572 .replaceFirst("$MSG", aMsg
);
1574 GetSbData()->aErrMsg
= aMsg1
.makeStringAndClear();
1576 // tdf#123144 - don't use an artificial error message if there is a custom one
1577 else if (!aMsg
.empty())
1579 GetSbData()->aErrMsg
= aMsg
;
1581 else if( nOldID
!= 0 )
1583 GetSbData()->aErrMsg
= "Error " + OUString::number(nOldID
) +
1584 ": No error text available!";
1588 GetSbData()->aErrMsg
.clear();
1592 bool StarBASIC::CError( ErrCode code
, const OUString
& rMsg
,
1593 sal_Int32 l
, sal_Int32 c1
, sal_Int32 c2
)
1595 SolarMutexGuard aSolarGuard
;
1597 // compiler error during runtime -> stop program
1600 // #109018 Check if running Basic is affected
1601 StarBASIC
* pStartedBasic
= GetSbData()->pInst
->GetBasic();
1602 if( pStartedBasic
!= this )
1609 // set flag, so that GlobalRunInit notice the error
1610 GetSbData()->bGlobalInitErr
= true;
1612 // tinker the error message
1613 MakeErrorText( code
, rMsg
);
1615 // Implementation of the code for the string transport to SFX-Error
1616 ErrCodeMsg nErr
= code
;
1617 if( !rMsg
.isEmpty() )
1619 nErr
= ErrCodeMsg( code
, rMsg
);
1621 SetErrorData( nErr
, l
, c1
, c2
);
1622 GetSbData()->bCompilerError
= true;
1624 if( GetSbData()->aErrHdl
.IsSet() )
1626 bRet
= GetSbData()->aErrHdl
.Call( this );
1632 GetSbData()->bCompilerError
= false; // only true for error handler
1636 bool StarBASIC::RTError( ErrCode code
, const OUString
& rMsg
, sal_Int32 l
, sal_Int32 c1
, sal_Int32 c2
)
1638 SolarMutexGuard aSolarGuard
;
1641 if( c
.GetClass() == ErrCodeClass::Compiler
)
1645 MakeErrorText( c
, rMsg
);
1647 // Implementation of the code for the string transport to SFX-Error
1648 ErrCodeMsg nErr
= code
;
1649 if( !rMsg
.isEmpty() )
1651 // very confusing, even though MakeErrorText sets up the error text
1652 // seems that this is not used ( if rMsg already has content )
1653 // In the case of VBA MakeErrorText also formats the error to be a little more
1654 // like vba ( adds an error number etc )
1655 if ( SbiRuntime::isVBAEnabled() && ( code
== ERRCODE_BASIC_COMPAT
) )
1657 OUString aTmp
= "\'" + OUString::number(SbxErrObject::getUnoErrObject()->getNumber()) +
1658 "\'\n" + (!GetSbData()->aErrMsg
.isEmpty() ? GetSbData()->aErrMsg
: rMsg
);
1659 nErr
= ErrCodeMsg( code
, aTmp
);
1663 nErr
= ErrCodeMsg( code
, rMsg
);
1667 SetErrorData( nErr
, l
, c1
, c2
);
1668 if( GetSbData()->aErrHdl
.IsSet() )
1670 return GetSbData()->aErrHdl
.Call( this );
1678 void StarBASIC::Error( ErrCode n
, const OUString
& rMsg
)
1680 if( GetSbData()->pInst
)
1682 GetSbData()->pInst
->Error( n
, rMsg
);
1686 void StarBASIC::FatalError( ErrCode n
)
1688 if( GetSbData()->pInst
)
1690 GetSbData()->pInst
->FatalError( n
);
1694 void StarBASIC::FatalError( ErrCode _errCode
, const OUString
& _details
)
1696 if( GetSbData()->pInst
)
1698 GetSbData()->pInst
->FatalError( _errCode
, _details
);
1702 ErrCode
StarBASIC::GetErrBasic()
1704 if( GetSbData()->pInst
)
1706 return GetSbData()->pInst
->GetErr();
1710 return ERRCODE_NONE
;
1714 // make the additional message for the RTL function error accessible
1715 const OUString
& StarBASIC::GetErrorMsg()
1717 if( GetSbData()->pInst
)
1719 return GetSbData()->pInst
->GetErrorMsg();
1723 return EMPTY_OUSTRING
;
1727 sal_Int32
StarBASIC::GetErl()
1729 if( GetSbData()->pInst
)
1731 return GetSbData()->pInst
->GetErl();
1739 bool StarBASIC::ErrorHdl()
1741 return aErrorHdl
.Call( this );
1744 Link
<StarBASIC
*,bool> const & StarBASIC::GetGlobalErrorHdl()
1746 return GetSbData()->aErrHdl
;
1749 void StarBASIC::SetGlobalErrorHdl( const Link
<StarBASIC
*,bool>& rLink
)
1751 GetSbData()->aErrHdl
= rLink
;
1754 void StarBASIC::SetGlobalBreakHdl( const Link
<StarBASIC
*,BasicDebugFlags
>& rLink
)
1756 GetSbData()->aBreakHdl
= rLink
;
1759 SbxArrayRef
const & StarBASIC::getUnoListeners()
1761 if( !xUnoListeners
.is() )
1763 xUnoListeners
= new SbxArray();
1765 return xUnoListeners
;
1769 bool StarBASIC::LoadData( SvStream
& r
, sal_uInt16 nVer
)
1771 if( !SbxObject::LoadData( r
, nVer
) )
1775 // #95459 Delete dialogs, otherwise endless recursion
1776 // in SbxVariable::GetType() if dialogs are accessed
1777 sal_uInt32 nObjCount
= pObjs
->Count();
1778 std::unique_ptr
<SbxVariable
*[]> ppDeleteTab(new SbxVariable
*[ nObjCount
]);
1781 for( nObj
= 0 ; nObj
< nObjCount
; nObj
++ )
1783 SbxVariable
* pVar
= pObjs
->Get(nObj
);
1784 StarBASIC
* pBasic
= dynamic_cast<StarBASIC
*>( pVar
);
1785 ppDeleteTab
[nObj
] = pBasic
? nullptr : pVar
;
1787 for( nObj
= 0 ; nObj
< nObjCount
; nObj
++ )
1789 SbxVariable
* pVar
= ppDeleteTab
[nObj
];
1792 pObjs
->Remove( pVar
);
1795 ppDeleteTab
.reset();
1799 r
.ReadUInt16( nMod
);
1800 const size_t nMinSbxSize(14);
1801 const size_t nMaxPossibleEntries
= r
.remainingSize() / nMinSbxSize
;
1802 if (nMod
> nMaxPossibleEntries
)
1804 nMod
= nMaxPossibleEntries
;
1805 SAL_WARN("basic", "Parsing error: " << nMaxPossibleEntries
<<
1806 " max possible entries, but " << nMod
<< " claimed, truncating");
1808 for (sal_uInt16 i
= 0; i
< nMod
; ++i
)
1810 SbxBaseRef pBase
= SbxBase::Load( r
);
1811 SbModule
* pMod
= dynamic_cast<SbModule
*>(pBase
.get());
1816 else if( dynamic_cast<const SbJScriptModule
*>( pMod
) != nullptr )
1818 // assign Ref, so that pMod will be deleted
1819 SbModuleRef xDeleteRef
= pMod
;
1823 pMod
->SetParent( this );
1824 pModules
.emplace_back(pMod
);
1827 // HACK for SFX-Bullshit!
1828 SbxVariable
* p
= Find( u
"FALSE"_ustr
, SbxClassType::Property
);
1833 p
= Find( u
"TRUE"_ustr
, SbxClassType::Property
);
1838 // End of the hacks!
1839 // Search via StarBASIC is at all times global
1840 DBG_ASSERT( IsSet( SbxFlagBits::GlobalSearch
), "Basic loaded without GBLSEARCH" );
1841 SetFlag( SbxFlagBits::GlobalSearch
);
1845 std::pair
<bool, sal_uInt32
> StarBASIC::StoreData( SvStream
& r
) const
1847 auto [bSuccess
, nVersion
] = SbxObject::StoreData(r
);
1850 return { false, 0 };
1852 assert(pModules
.size() < SAL_MAX_UINT16
);
1853 r
.WriteUInt16( static_cast<sal_uInt16
>(pModules
.size()));
1854 for( const auto& rpModule
: pModules
)
1856 const auto [bSuccessModule
, nVersionModule
] = rpModule
->Store(r
);
1857 if( !bSuccessModule
)
1859 return { false, 0 };
1861 else if (nVersionModule
> nVersion
)
1863 nVersion
= nVersionModule
;
1866 return { true, nVersion
};
1869 bool StarBASIC::GetUNOConstant( const OUString
& rName
, css::uno::Any
& aOut
)
1872 SbUnoObject
* pGlobs
= dynamic_cast<SbUnoObject
*>( Find( rName
, SbxClassType::DontCare
) );
1875 aOut
= pGlobs
->getUnoAny();
1881 Reference
< frame::XModel
> StarBASIC::GetModelFromBasic( SbxObject
* pBasic
)
1883 OSL_PRECOND( pBasic
!= nullptr, "getModelFromBasic: illegal call!" );
1888 // look for the ThisComponent variable, first in the parent (which
1889 // might be the document's Basic), then in the parent's parent (which might be
1890 // the application Basic)
1891 static constexpr OUStringLiteral
sThisComponent( u
"ThisComponent");
1892 SbxVariable
* pThisComponent
= nullptr;
1894 SbxObject
* pLookup
= pBasic
->GetParent();
1895 while ( pLookup
&& !pThisComponent
)
1897 pThisComponent
= pLookup
->Find( sThisComponent
, SbxClassType::Object
);
1898 pLookup
= pLookup
->GetParent();
1900 if ( !pThisComponent
)
1902 SAL_WARN("basic", "Failed to get ThisComponent");
1903 // the application Basic, at the latest, should have this variable
1907 Any
aThisComponentAny( sbxToUnoValue( pThisComponent
) );
1908 Reference
< frame::XModel
> xModel( aThisComponentAny
, UNO_QUERY
);
1911 // it's no XModel. Okay, ThisComponent nowadays is allowed to be a controller.
1912 Reference
< frame::XController
> xController( aThisComponentAny
, UNO_QUERY
);
1913 if ( xController
.is() )
1915 xModel
= xController
->getModel();
1926 void StarBASIC::DetachAllDocBasicItems()
1928 for (auto const& item
: gaDocBasicItems
)
1930 DocBasicItemRef xItem
= item
.second
;
1931 xItem
->setDisposed(true);
1935 // #118116 Implementation Collection object
1939 constexpr OUStringLiteral pCountStr
= u
"Count";
1941 constexpr OUStringLiteral pAddStr
= u
"Add";
1943 constexpr OUStringLiteral pItemStr
= u
"Item";
1945 constexpr OUStringLiteral pRemoveStr
= u
"Remove";
1946 constexpr sal_uInt16 nCountHash
= SbxVariable::MakeHashCode(pCountStr
);
1947 constexpr sal_uInt16 nAddHash
= SbxVariable::MakeHashCode(pAddStr
);
1948 constexpr sal_uInt16 nItemHash
= SbxVariable::MakeHashCode(pItemStr
);
1949 constexpr sal_uInt16 nRemoveHash
= SbxVariable::MakeHashCode(pRemoveStr
);
1951 SbxInfoRef
BasicCollection::xAddInfo
;
1952 SbxInfoRef
BasicCollection::xItemInfo
;
1954 BasicCollection::BasicCollection( const OUString
& rClass
)
1955 : SbxObject( rClass
)
1960 BasicCollection::~BasicCollection()
1963 void BasicCollection::Clear()
1969 void BasicCollection::Initialize()
1971 xItemArray
= new SbxArray();
1972 SetType( SbxOBJECT
);
1973 SetFlag( SbxFlagBits::Fixed
);
1974 ResetFlag( SbxFlagBits::Write
);
1976 p
= Make( pCountStr
, SbxClassType::Property
, SbxINTEGER
);
1977 p
->ResetFlag( SbxFlagBits::Write
);
1978 p
->SetFlag( SbxFlagBits::DontStore
);
1979 p
= Make( pAddStr
, SbxClassType::Method
, SbxEMPTY
);
1980 p
->SetFlag( SbxFlagBits::DontStore
);
1981 p
= Make( pItemStr
, SbxClassType::Method
, SbxVARIANT
);
1982 p
->SetFlag( SbxFlagBits::DontStore
);
1983 p
= Make( pRemoveStr
, SbxClassType::Method
, SbxEMPTY
);
1984 p
->SetFlag( SbxFlagBits::DontStore
);
1985 if ( !xAddInfo
.is() )
1987 xAddInfo
= new SbxInfo
;
1988 xAddInfo
->AddParam( u
"Item"_ustr
, SbxVARIANT
);
1989 xAddInfo
->AddParam( u
"Key"_ustr
, SbxVARIANT
, SbxFlagBits::Read
| SbxFlagBits::Optional
);
1990 xAddInfo
->AddParam( u
"Before"_ustr
, SbxVARIANT
, SbxFlagBits::Read
| SbxFlagBits::Optional
);
1991 xAddInfo
->AddParam( u
"After"_ustr
, SbxVARIANT
, SbxFlagBits::Read
| SbxFlagBits::Optional
);
1993 if ( !xItemInfo
.is() )
1995 xItemInfo
= new SbxInfo
;
1996 xItemInfo
->AddParam( u
"Index"_ustr
, SbxVARIANT
, SbxFlagBits::Read
| SbxFlagBits::Optional
);
2000 void BasicCollection::Notify( SfxBroadcaster
& rCst
, const SfxHint
& rHint
)
2002 const SbxHint
* p
= dynamic_cast<const SbxHint
*>(&rHint
);
2005 const SfxHintId nId
= p
->GetId();
2006 bool bRead
= nId
== SfxHintId::BasicDataWanted
;
2007 bool bWrite
= nId
== SfxHintId::BasicDataChanged
;
2008 bool bRequestInfo
= nId
== SfxHintId::BasicInfoWanted
;
2009 SbxVariable
* pVar
= p
->GetVar();
2010 SbxArray
* pArg
= pVar
->GetParameters();
2011 OUString
aVarName( pVar
->GetName() );
2012 if( bRead
|| bWrite
)
2014 if( pVar
->GetHashCode() == nCountHash
2015 && aVarName
.equalsIgnoreAsciiCase( pCountStr
) )
2017 pVar
->PutLong(xItemArray
->Count());
2019 else if( pVar
->GetHashCode() == nAddHash
2020 && aVarName
.equalsIgnoreAsciiCase( pAddStr
) )
2024 else if( pVar
->GetHashCode() == nItemHash
2025 && aVarName
.equalsIgnoreAsciiCase( pItemStr
) )
2029 else if( pVar
->GetHashCode() == nRemoveHash
2030 && aVarName
.equalsIgnoreAsciiCase( pRemoveStr
) )
2036 SbxObject::Notify( rCst
, rHint
);
2040 else if ( bRequestInfo
)
2042 if( pVar
->GetHashCode() == nAddHash
2043 && aVarName
.equalsIgnoreAsciiCase( pAddStr
) )
2045 pVar
->SetInfo( xAddInfo
.get() );
2047 else if( pVar
->GetHashCode() == nItemHash
2048 && aVarName
.equalsIgnoreAsciiCase( pItemStr
) )
2050 pVar
->SetInfo( xItemInfo
.get() );
2054 SbxObject::Notify( rCst
, rHint
);
2057 sal_Int32
BasicCollection::implGetIndex( SbxVariable
const * pIndexVar
)
2059 sal_Int32 nIndex
= -1;
2060 if( pIndexVar
->GetType() == SbxSTRING
)
2062 nIndex
= implGetIndexForName( pIndexVar
->GetOUString() );
2066 nIndex
= pIndexVar
->GetLong() - 1;
2071 sal_Int32
BasicCollection::implGetIndexForName(const OUString
& rName
)
2073 sal_Int32 nCount
= xItemArray
->Count();
2074 sal_Int32 nNameHash
= MakeHashCode( rName
);
2076 // tdf#144245 - case-insensitive operation for non-ASCII characters
2077 OUString aNameCI
; // Only initialize when matching hash found
2079 for( sal_Int32 i
= 0 ; i
< nCount
; i
++ )
2081 SbxVariable
* pVar
= xItemArray
->Get(i
);
2082 if (pVar
->GetHashCode() == nNameHash
)
2084 if (aNameCI
.isEmpty() && !rName
.isEmpty())
2085 aNameCI
= SbxVariable::NameToCaseInsensitiveName(rName
);
2086 if (aNameCI
== pVar
->GetName(SbxNameType::CaseInsensitive
))
2093 void BasicCollection::CollAdd( SbxArray
* pPar_
)
2095 sal_uInt32 nCount
= pPar_
->Count();
2096 if( nCount
< 2 || nCount
> 5 )
2098 SetError( ERRCODE_BASIC_WRONG_ARGS
);
2102 SbxVariable
* pItem
= pPar_
->Get(1);
2105 sal_uInt32 nNextIndex
;
2108 nNextIndex
= xItemArray
->Count();
2112 SbxVariable
* pBefore
= pPar_
->Get(3);
2115 if( !( pBefore
->IsErr() || ( pBefore
->GetType() == SbxEMPTY
) ) )
2117 SetError( ERRCODE_BASIC_BAD_ARGUMENT
);
2120 SbxVariable
* pAfter
= pPar_
->Get(4);
2121 sal_Int32 nAfterIndex
= implGetIndex( pAfter
);
2122 if( nAfterIndex
== -1 )
2124 SetError( ERRCODE_BASIC_BAD_ARGUMENT
);
2127 nNextIndex
= sal::static_int_cast
<sal_uInt32
>(nAfterIndex
+ 1);
2129 else // if( nCount == 4 )
2131 sal_Int32 nBeforeIndex
= implGetIndex( pBefore
);
2132 if( nBeforeIndex
== -1 )
2134 SetError( ERRCODE_BASIC_BAD_ARGUMENT
);
2137 nNextIndex
= sal::static_int_cast
<sal_uInt32
>(nBeforeIndex
);
2141 auto pNewItem
= tools::make_ref
<SbxVariable
>( *pItem
);
2144 SbxVariable
* pKey
= pPar_
->Get(2);
2145 if( !( pKey
->IsErr() || ( pKey
->GetType() == SbxEMPTY
) ) )
2147 if( pKey
->GetType() != SbxSTRING
)
2149 SetError( ERRCODE_BASIC_BAD_ARGUMENT
);
2152 OUString aKey
= pKey
->GetOUString();
2153 if( implGetIndexForName( aKey
) != -1 )
2155 SetError( ERRCODE_BASIC_BAD_ARGUMENT
);
2158 pNewItem
->SetName( aKey
);
2161 pNewItem
->SetFlag( SbxFlagBits::ReadWrite
);
2162 xItemArray
->Insert(pNewItem
.get(), nNextIndex
);
2166 SetError( ERRCODE_BASIC_BAD_ARGUMENT
);
2171 void BasicCollection::CollItem( SbxArray
* pPar_
)
2173 if (pPar_
->Count() != 2)
2175 SetError( ERRCODE_BASIC_WRONG_ARGS
);
2178 SbxVariable
* pRes
= nullptr;
2179 SbxVariable
* p
= pPar_
->Get(1);
2180 sal_Int32 nIndex
= implGetIndex( p
);
2181 if (nIndex
>= 0 && o3tl::make_unsigned(nIndex
) < xItemArray
->Count())
2183 pRes
= xItemArray
->Get(nIndex
);
2187 SetError( ERRCODE_BASIC_BAD_ARGUMENT
);
2191 *(pPar_
->Get(0)) = *pRes
;
2195 void BasicCollection::CollRemove( SbxArray
* pPar_
)
2197 if (pPar_
== nullptr || pPar_
->Count() != 2)
2199 SetError( ERRCODE_BASIC_WRONG_ARGS
);
2203 SbxVariable
* p
= pPar_
->Get(1);
2204 sal_Int32 nIndex
= implGetIndex( p
);
2205 if (nIndex
>= 0 && o3tl::make_unsigned(nIndex
) < xItemArray
->Count())
2207 xItemArray
->Remove( nIndex
);
2209 // Correct for stack if necessary
2210 SbiInstance
* pInst
= GetSbData()->pInst
;
2211 SbiRuntime
* pRT
= pInst
? pInst
->pRun
: nullptr;
2214 SbiForStack
* pStack
= pRT
->FindForStackItemForCollection( this );
2215 if( pStack
!= nullptr )
2217 if( pStack
->nCurCollectionIndex
>= nIndex
)
2219 --pStack
->nCurCollectionIndex
;
2226 SetError( ERRCODE_BASIC_BAD_ARGUMENT
);
2230 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */