xref: /core/basic/source/classes/sbxmod.cxx (revision 889dc7bf)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 
21 #include <vcl/svapp.hxx>
22 #include <tools/stream.hxx>
23 #include <tools/diagnose_ex.h>
24 #include <svl/SfxBroadcaster.hxx>
25 #include <basic/sbx.hxx>
26 #include <basic/sbuno.hxx>
27 #include <sb.hxx>
28 #include <sbjsmeth.hxx>
29 #include <sbjsmod.hxx>
30 #include <sbintern.hxx>
31 #include <image.hxx>
32 #include <opcodes.hxx>
33 #include <runtime.hxx>
34 #include <token.hxx>
35 #include <sbunoobj.hxx>
36 
37 #include <sal/log.hxx>
38 
39 #include <basic/basrdll.hxx>
40 #include <sbobjmod.hxx>
41 #include <basic/vbahelper.hxx>
42 #include <comphelper/sequence.hxx>
43 #include <cppuhelper/implbase.hxx>
44 #include <unotools/eventcfg.hxx>
45 #include <com/sun/star/frame/Desktop.hpp>
46 #include <com/sun/star/lang/XServiceInfo.hpp>
47 #include <com/sun/star/script/ModuleType.hpp>
48 #include <com/sun/star/script/vba/XVBACompatibility.hpp>
49 #include <com/sun/star/script/vba/VBAScriptEventId.hpp>
50 #include <com/sun/star/beans/XPropertySet.hpp>
51 #include <com/sun/star/document/XDocumentEventBroadcaster.hpp>
52 #include <com/sun/star/document/XDocumentEventListener.hpp>
53 
54 #ifdef UNX
55 #include <sys/resource.h>
56 #endif
57 
58 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
59 #include <comphelper/processfactory.hxx>
60 #include <comphelper/asyncquithandler.hxx>
61 #include <map>
62 #include <com/sun/star/reflection/ProxyFactory.hpp>
63 #include <com/sun/star/uno/XAggregation.hpp>
64 #include <com/sun/star/script/XInvocation.hpp>
65 
66 #include <com/sun/star/awt/DialogProvider.hpp>
67 #include <com/sun/star/awt/XTopWindow.hpp>
68 #include <com/sun/star/awt/XWindow.hpp>
69 #include <com/sun/star/awt/XControl.hpp>
70 #include <ooo/vba/VbQueryClose.hpp>
71 #include <list>
72 #include <memory>
73 #include <sbxmod.hxx>
74 #include <parser.hxx>
75 
76 #include <limits>
77 
78 using namespace com::sun::star;
79 using namespace com::sun::star::lang;
80 using namespace com::sun::star::reflection;
81 using namespace com::sun::star::beans;
82 using namespace com::sun::star::script;
83 using namespace com::sun::star::uno;
84 
85 typedef ::cppu::WeakImplHelper< XInvocation > DocObjectWrapper_BASE;
86 typedef std::map< sal_Int16, Any > OutParamMap;
87 
88 class DocObjectWrapper : public DocObjectWrapper_BASE
89 {
90     Reference< XAggregation >  m_xAggProxy;
91     Reference< XInvocation >  m_xAggInv;
92     Reference< XTypeProvider > m_xAggregateTypeProv;
93     Sequence< Type >           m_Types;
94     SbModule*                m_pMod;
95     /// @throws css::uno::RuntimeException
96     SbMethodRef getMethod( const OUString& aName );
97     /// @throws css::uno::RuntimeException
98     SbPropertyRef getProperty( const OUString& aName );
99 
100 public:
101     explicit DocObjectWrapper( SbModule* pMod );
102 
103     virtual Sequence< sal_Int8 > SAL_CALL getImplementationId() override
104     {
105         return css::uno::Sequence<sal_Int8>();
106     }
107 
108     virtual Reference< XIntrospectionAccess > SAL_CALL getIntrospection(  ) override;
109 
110     virtual Any SAL_CALL invoke( const OUString& aFunctionName, const Sequence< Any >& aParams, Sequence< ::sal_Int16 >& aOutParamIndex, Sequence< Any >& aOutParam ) override;
111     virtual void SAL_CALL setValue( const OUString& aPropertyName, const Any& aValue ) override;
112     virtual Any SAL_CALL getValue( const OUString& aPropertyName ) override;
113     virtual sal_Bool SAL_CALL hasMethod( const OUString& aName ) override;
114     virtual sal_Bool SAL_CALL hasProperty( const OUString& aName ) override;
115     virtual  Any SAL_CALL queryInterface( const Type& aType ) override;
116 
117     virtual Sequence< Type > SAL_CALL getTypes() override;
118 };
119 
120 DocObjectWrapper::DocObjectWrapper( SbModule* pVar ) : m_pMod( pVar )
121 {
122     SbObjModule* pMod = dynamic_cast<SbObjModule*>( pVar );
123     if ( pMod )
124     {
125         if ( pMod->GetModuleType() == ModuleType::DOCUMENT )
126         {
127             // Use proxy factory service to create aggregatable proxy.
128             SbUnoObject* pUnoObj = dynamic_cast<SbUnoObject*>( pMod->GetObject()  );
129             Reference< XInterface > xIf;
130             if ( pUnoObj )
131             {
132                    Any aObj = pUnoObj->getUnoAny();
133                    aObj >>= xIf;
134                    if ( xIf.is() )
135                    {
136                        m_xAggregateTypeProv.set( xIf, UNO_QUERY );
137                        m_xAggInv.set( xIf, UNO_QUERY );
138                    }
139             }
140             if ( xIf.is() )
141             {
142                 try
143                 {
144                     Reference< XProxyFactory > xProxyFac = ProxyFactory::create( comphelper::getProcessComponentContext() );
145                     m_xAggProxy = xProxyFac->createProxy( xIf );
146                 }
147                 catch(const Exception& )
148                 {
149                     TOOLS_WARN_EXCEPTION( "basic", "DocObjectWrapper::DocObjectWrapper" );
150                 }
151             }
152 
153             if ( m_xAggProxy.is() )
154             {
155                 osl_atomic_increment( &m_refCount );
156 
157                 /* i35609 - Fix crash on Solaris. The setDelegator call needs
158                     to be in its own block to ensure that all temporary Reference
159                     instances that are acquired during the call are released
160                     before m_refCount is decremented again */
161                 {
162                     m_xAggProxy->setDelegator( static_cast< cppu::OWeakObject * >( this ) );
163                 }
164 
165                 osl_atomic_decrement( &m_refCount );
166             }
167         }
168     }
169 }
170 
171 Sequence< Type > SAL_CALL DocObjectWrapper::getTypes()
172 {
173     if ( !m_Types.hasElements() )
174     {
175         Sequence< Type > sTypes;
176         if ( m_xAggregateTypeProv.is() )
177         {
178             sTypes = m_xAggregateTypeProv->getTypes();
179         }
180         m_Types = comphelper::concatSequences(sTypes,
181             Sequence { cppu::UnoType<XInvocation>::get() });
182     }
183     return m_Types;
184 }
185 
186 Reference< XIntrospectionAccess > SAL_CALL
187 DocObjectWrapper::getIntrospection(  )
188 {
189     return nullptr;
190 }
191 
192 Any SAL_CALL
193 DocObjectWrapper::invoke( const OUString& aFunctionName, const Sequence< Any >& aParams, Sequence< ::sal_Int16 >& aOutParamIndex, Sequence< Any >& aOutParam )
194 {
195     if ( m_xAggInv.is() &&  m_xAggInv->hasMethod( aFunctionName ) )
196             return m_xAggInv->invoke( aFunctionName, aParams, aOutParamIndex, aOutParam );
197     SbMethodRef pMethod = getMethod( aFunctionName );
198     if ( !pMethod.is() )
199         throw RuntimeException();
200     // check number of parameters
201     sal_Int32 nParamsCount = aParams.getLength();
202     SbxInfo* pInfo = pMethod->GetInfo();
203     if ( pInfo )
204     {
205         sal_Int32 nSbxOptional = 0;
206         sal_uInt16 n = 1;
207         for ( const SbxParamInfo* pParamInfo = pInfo->GetParam( n ); pParamInfo; pParamInfo = pInfo->GetParam( ++n ) )
208         {
209             if ( pParamInfo->nFlags & SbxFlagBits::Optional )
210                 ++nSbxOptional;
211             else
212                 nSbxOptional = 0;
213         }
214         sal_Int32 nSbxCount = n - 1;
215         if ( nParamsCount < nSbxCount - nSbxOptional )
216         {
217             throw RuntimeException( "wrong number of parameters!" );
218         }
219     }
220     // set parameters
221     SbxArrayRef xSbxParams;
222     if ( nParamsCount > 0 )
223     {
224         xSbxParams = new SbxArray;
225         const Any* pParams = aParams.getConstArray();
226         for ( sal_Int32 i = 0; i < nParamsCount; ++i )
227         {
228             SbxVariableRef xSbxVar = new SbxVariable( SbxVARIANT );
229             unoToSbxValue( xSbxVar.get(), pParams[i] );
230             xSbxParams->Put( xSbxVar.get(), static_cast< sal_uInt16 >( i ) + 1 );
231 
232             // Enable passing by ref
233             if ( xSbxVar->GetType() != SbxVARIANT )
234                 xSbxVar->SetFlag( SbxFlagBits::Fixed );
235         }
236     }
237     if ( xSbxParams.is() )
238         pMethod->SetParameters( xSbxParams.get() );
239 
240     // call method
241     SbxVariableRef xReturn = new SbxVariable;
242 
243     pMethod->Call( xReturn.get() );
244     Any aReturn;
245     // get output parameters
246     if ( xSbxParams.is() )
247     {
248         SbxInfo* pInfo_ = pMethod->GetInfo();
249         if ( pInfo_ )
250         {
251             OutParamMap aOutParamMap;
252             for ( sal_uInt16 n = 1, nCount = xSbxParams->Count(); n < nCount; ++n )
253             {
254                 const SbxParamInfo* pParamInfo = pInfo_->GetParam( n );
255                 if ( pParamInfo && ( pParamInfo->eType & SbxBYREF ) != 0 )
256                 {
257                     SbxVariable* pVar = xSbxParams->Get( n );
258                     if ( pVar )
259                     {
260                         SbxVariableRef xVar = pVar;
261                         aOutParamMap.emplace( n - 1, sbxToUnoValue( xVar.get() ) );
262                     }
263                 }
264             }
265             sal_Int32 nOutParamCount = aOutParamMap.size();
266             aOutParamIndex.realloc( nOutParamCount );
267             aOutParam.realloc( nOutParamCount );
268             sal_Int16* pOutParamIndex = aOutParamIndex.getArray();
269             Any* pOutParam = aOutParam.getArray();
270             for (auto const& outParam : aOutParamMap)
271             {
272                 *pOutParamIndex = outParam.first;
273                 *pOutParam = outParam.second;
274                 ++pOutParamIndex;
275                 ++pOutParam;
276             }
277         }
278     }
279 
280     // get return value
281     aReturn = sbxToUnoValue( xReturn.get() );
282 
283     pMethod->SetParameters( nullptr );
284 
285     return aReturn;
286 }
287 
288 void SAL_CALL
289 DocObjectWrapper::setValue( const OUString& aPropertyName, const Any& aValue )
290 {
291     if ( m_xAggInv.is() &&  m_xAggInv->hasProperty( aPropertyName ) )
292             return m_xAggInv->setValue( aPropertyName, aValue );
293 
294     SbPropertyRef pProperty = getProperty( aPropertyName );
295     if ( !pProperty.is() )
296        throw UnknownPropertyException();
297     unoToSbxValue( pProperty.get(), aValue );
298 }
299 
300 Any SAL_CALL
301 DocObjectWrapper::getValue( const OUString& aPropertyName )
302 {
303     if ( m_xAggInv.is() &&  m_xAggInv->hasProperty( aPropertyName ) )
304             return m_xAggInv->getValue( aPropertyName );
305 
306     SbPropertyRef pProperty = getProperty( aPropertyName );
307     if ( !pProperty.is() )
308        throw UnknownPropertyException();
309 
310     SbxVariable* pProp = pProperty.get();
311     if ( pProp->GetType() == SbxEMPTY )
312         pProperty->Broadcast( SfxHintId::BasicDataWanted );
313 
314     Any aRet = sbxToUnoValue( pProp );
315     return aRet;
316 }
317 
318 sal_Bool SAL_CALL
319 DocObjectWrapper::hasMethod( const OUString& aName )
320 {
321     if ( m_xAggInv.is() && m_xAggInv->hasMethod( aName ) )
322         return true;
323     return getMethod( aName ).is();
324 }
325 
326 sal_Bool SAL_CALL
327 DocObjectWrapper::hasProperty( const OUString& aName )
328 {
329     bool bRes = false;
330     if ( m_xAggInv.is() && m_xAggInv->hasProperty( aName ) )
331         bRes = true;
332     else bRes = getProperty( aName ).is();
333     return bRes;
334 }
335 
336 Any SAL_CALL DocObjectWrapper::queryInterface( const Type& aType )
337 {
338     Any aRet = DocObjectWrapper_BASE::queryInterface( aType );
339     if ( aRet.hasValue() )
340         return aRet;
341     else if ( m_xAggProxy.is() )
342         aRet = m_xAggProxy->queryAggregation( aType );
343     return aRet;
344 }
345 
346 SbMethodRef DocObjectWrapper::getMethod( const OUString& aName )
347 {
348     SbMethodRef pMethod;
349     if ( m_pMod )
350     {
351         SbxFlagBits nSaveFlgs = m_pMod->GetFlags();
352         // Limit search to this module
353         m_pMod->ResetFlag( SbxFlagBits::GlobalSearch );
354         pMethod = dynamic_cast<SbMethod*>(m_pMod->SbModule::Find(aName,  SbxClassType::Method));
355         m_pMod->SetFlags( nSaveFlgs );
356     }
357 
358     return pMethod;
359 }
360 
361 SbPropertyRef DocObjectWrapper::getProperty( const OUString& aName )
362 {
363     SbPropertyRef pProperty;
364     if ( m_pMod )
365     {
366         SbxFlagBits nSaveFlgs = m_pMod->GetFlags();
367         // Limit search to this module.
368         m_pMod->ResetFlag( SbxFlagBits::GlobalSearch );
369         pProperty = dynamic_cast<SbProperty*>(m_pMod->SbModule::Find(aName,  SbxClassType::Property));
370         m_pMod->SetFlag( nSaveFlgs );
371     }
372 
373     return pProperty;
374 }
375 
376 
377 uno::Reference< frame::XModel > getDocumentModel( StarBASIC* pb )
378 {
379     uno::Reference< frame::XModel > xModel;
380     if( pb && pb->IsDocBasic() )
381     {
382         uno::Any aDoc;
383         if( pb->GetUNOConstant( "ThisComponent", aDoc ) )
384             xModel.set( aDoc, uno::UNO_QUERY );
385     }
386     return xModel;
387 }
388 
389 static uno::Reference< vba::XVBACompatibility > getVBACompatibility( const uno::Reference< frame::XModel >& rxModel )
390 {
391     uno::Reference< vba::XVBACompatibility > xVBACompat;
392     try
393     {
394         uno::Reference< beans::XPropertySet > xModelProps( rxModel, uno::UNO_QUERY_THROW );
395         xVBACompat.set( xModelProps->getPropertyValue( "BasicLibraries" ), uno::UNO_QUERY );
396     }
397     catch(const uno::Exception& )
398     {
399     }
400     return xVBACompat;
401 }
402 
403 static bool getDefaultVBAMode( StarBASIC* pb )
404 {
405     uno::Reference< frame::XModel > xModel( getDocumentModel( pb ) );
406     if (!xModel.is())
407         return false;
408     uno::Reference< vba::XVBACompatibility > xVBACompat = getVBACompatibility( xModel );
409     return xVBACompat.is() && xVBACompat->getVBACompatibilityMode();
410 }
411 
412 // A Basic module has set EXTSEARCH, so that the elements, that the module contains,
413 // could be found from other module.
414 
415 SbModule::SbModule( const OUString& rName, bool bVBACompat )
416          : SbxObject( "StarBASICModule" ),
417            mbVBACompat( bVBACompat ), bIsProxyModule( false )
418 {
419     SetName( rName );
420     SetFlag( SbxFlagBits::ExtSearch | SbxFlagBits::GlobalSearch );
421     SetModuleType( script::ModuleType::NORMAL );
422 
423     // #i92642: Set name property to initial name
424     SbxVariable* pNameProp = pProps->Find( "Name", SbxClassType::Property );
425     if( pNameProp != nullptr )
426     {
427         pNameProp->PutString( GetName() );
428     }
429 }
430 
431 SbModule::~SbModule()
432 {
433     SAL_INFO("basic","Module named " << GetName() << " is destructing");
434     pImage.reset();
435     pBreaks.reset();
436     pClassData.reset();
437     mxWrapper = nullptr;
438 }
439 
440 uno::Reference< script::XInvocation > const &
441 SbModule::GetUnoModule()
442 {
443     if ( !mxWrapper.is() )
444         mxWrapper = new DocObjectWrapper( this );
445 
446     SAL_INFO("basic","Module named " << GetName() << " returning wrapper mxWrapper (0x" << mxWrapper.get() <<")" );
447     return mxWrapper;
448 }
449 
450 bool SbModule::IsCompiled() const
451 {
452     return pImage != nullptr;
453 }
454 
455 const SbxObject* SbModule::FindType( const OUString& aTypeName ) const
456 {
457     return pImage ? pImage->FindType( aTypeName ) : nullptr;
458 }
459 
460 
461 // From the code generator: deletion of images and the opposite of validation for entries
462 
463 void SbModule::StartDefinitions()
464 {
465     pImage.reset();
466     if( pClassData )
467         pClassData->clear();
468 
469     // methods and properties persist, but they are invalid;
470     // at least are the information under certain conditions clogged
471     sal_uInt16 i;
472     for( i = 0; i < pMethods->Count(); i++ )
473     {
474         SbMethod* p = dynamic_cast<SbMethod*>( pMethods->Get( i )  );
475         if( p )
476             p->bInvalid = true;
477     }
478     for( i = 0; i < pProps->Count(); )
479     {
480         SbProperty* p = dynamic_cast<SbProperty*>( pProps->Get( i )  );
481         if( p )
482             pProps->Remove( i );
483         else
484             i++;
485     }
486 }
487 
488 // request/create method
489 
490 SbMethod* SbModule::GetMethod( const OUString& rName, SbxDataType t )
491 {
492     SbxVariable* p = pMethods->Find( rName, SbxClassType::Method );
493     SbMethod* pMeth = dynamic_cast<SbMethod*>( p );
494     if( p && !pMeth )
495     {
496         pMethods->Remove( p );
497     }
498     if( !pMeth )
499     {
500         pMeth = new SbMethod( rName, t, this );
501         pMeth->SetParent( this );
502         pMeth->SetFlags( SbxFlagBits::Read );
503         pMethods->Put( pMeth, pMethods->Count() );
504         StartListening(pMeth->GetBroadcaster(), DuplicateHandling::Prevent);
505     }
506     // The method is per default valid, because it could be
507     // created from the compiler (code generator) as well.
508     pMeth->bInvalid = false;
509     pMeth->ResetFlag( SbxFlagBits::Fixed );
510     pMeth->SetFlag( SbxFlagBits::Write );
511     pMeth->SetType( t );
512     pMeth->ResetFlag( SbxFlagBits::Write );
513     if( t != SbxVARIANT )
514     {
515         pMeth->SetFlag( SbxFlagBits::Fixed );
516     }
517     return pMeth;
518 }
519 
520 SbMethod* SbModule::FindMethod( const OUString& rName, SbxClassType t )
521 {
522     return dynamic_cast<SbMethod*> (pMethods->Find( rName, t ));
523 }
524 
525 
526 // request/create property
527 
528 SbProperty* SbModule::GetProperty( const OUString& rName, SbxDataType t )
529 {
530     SbxVariable* p = pProps->Find( rName, SbxClassType::Property );
531     SbProperty* pProp = dynamic_cast<SbProperty*>( p );
532     if( p && !pProp )
533     {
534         pProps->Remove( p );
535     }
536     if( !pProp )
537     {
538         pProp = new SbProperty( rName, t, this );
539         pProp->SetFlag( SbxFlagBits::ReadWrite );
540         pProp->SetParent( this );
541         pProps->Put( pProp, pProps->Count() );
542         StartListening(pProp->GetBroadcaster(), DuplicateHandling::Prevent);
543     }
544     return pProp;
545 }
546 
547 void SbModule::GetProcedureProperty( const OUString& rName, SbxDataType t )
548 {
549     SbxVariable* p = pProps->Find( rName, SbxClassType::Property );
550     SbProcedureProperty* pProp = dynamic_cast<SbProcedureProperty*>( p );
551     if( p && !pProp )
552     {
553         pProps->Remove( p );
554     }
555     if( !pProp )
556     {
557         pProp = new SbProcedureProperty( rName, t );
558         pProp->SetFlag( SbxFlagBits::ReadWrite );
559         pProp->SetParent( this );
560         pProps->Put( pProp, pProps->Count() );
561         StartListening(pProp->GetBroadcaster(), DuplicateHandling::Prevent);
562     }
563 }
564 
565 void SbModule::GetIfaceMapperMethod( const OUString& rName, SbMethod* pImplMeth )
566 {
567     SbxVariable* p = pMethods->Find( rName, SbxClassType::Method );
568     SbIfaceMapperMethod* pMapperMethod = dynamic_cast<SbIfaceMapperMethod*>( p );
569     if( p && !pMapperMethod )
570     {
571         pMethods->Remove( p );
572     }
573     if( !pMapperMethod )
574     {
575         pMapperMethod = new SbIfaceMapperMethod( rName, pImplMeth );
576         pMapperMethod->SetParent( this );
577         pMapperMethod->SetFlags( SbxFlagBits::Read );
578         pMethods->Put( pMapperMethod, pMethods->Count() );
579     }
580     pMapperMethod->bInvalid = false;
581 }
582 
583 SbIfaceMapperMethod::~SbIfaceMapperMethod()
584 {
585 }
586 
587 
588 // From the code generator: remove invalid entries
589 
590 void SbModule::EndDefinitions( bool bNewState )
591 {
592     for( sal_uInt16 i = 0; i < pMethods->Count(); )
593     {
594         SbMethod* p = dynamic_cast<SbMethod*>( pMethods->Get( i )  );
595         if( p )
596         {
597             if( p->bInvalid )
598             {
599                 pMethods->Remove( p );
600             }
601             else
602             {
603                 p->bInvalid = bNewState;
604                 i++;
605             }
606         }
607         else
608             i++;
609     }
610     SetModified( true );
611 }
612 
613 void SbModule::Clear()
614 {
615     pImage.reset();
616     if( pClassData )
617         pClassData->clear();
618     SbxObject::Clear();
619 }
620 
621 
622 SbxVariable* SbModule::Find( const OUString& rName, SbxClassType t )
623 {
624     // make sure a search in an uninstantiated class module will fail
625     SbxVariable* pRes = SbxObject::Find( rName, t );
626     if ( bIsProxyModule && !GetSbData()->bRunInit )
627     {
628         return nullptr;
629     }
630     if( !pRes && pImage )
631     {
632         SbiInstance* pInst = GetSbData()->pInst;
633         if( pInst && pInst->IsCompatibility() )
634         {
635             // Put enum types as objects into module,
636             // allows MyEnum.First notation
637             SbxArrayRef xArray = pImage->GetEnums();
638             if( xArray.is() )
639             {
640                 SbxVariable* pEnumVar = xArray->Find( rName, SbxClassType::DontCare );
641                 SbxObject* pEnumObject = dynamic_cast<SbxObject*>( pEnumVar  );
642                 if( pEnumObject )
643                 {
644                     bool bPrivate = pEnumObject->IsSet( SbxFlagBits::Private );
645                     OUString aEnumName = pEnumObject->GetName();
646 
647                     pRes = new SbxVariable( SbxOBJECT );
648                     pRes->SetName( aEnumName );
649                     pRes->SetParent( this );
650                     pRes->SetFlag( SbxFlagBits::Read );
651                     if( bPrivate )
652                     {
653                         pRes->SetFlag( SbxFlagBits::Private );
654                     }
655                     pRes->PutObject( pEnumObject );
656                 }
657             }
658         }
659     }
660     return pRes;
661 }
662 
663 
664 const OUString& SbModule::GetSource() const
665 {
666     return aOUSource;
667 }
668 
669 // Parent and BASIC are one!
670 
671 void SbModule::SetParent( SbxObject* p )
672 {
673     pParent = p;
674 }
675 
676 void SbModule::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
677 {
678     const SbxHint* pHint = dynamic_cast<const SbxHint*>(&rHint);
679     if( pHint )
680     {
681         SbxVariable* pVar = pHint->GetVar();
682         SbProperty* pProp = dynamic_cast<SbProperty*>( pVar );
683         SbMethod* pMeth = dynamic_cast<SbMethod*>( pVar );
684         SbProcedureProperty* pProcProperty = dynamic_cast<SbProcedureProperty*>( pVar  );
685         if( pProcProperty )
686         {
687 
688             if( pHint->GetId() == SfxHintId::BasicDataWanted )
689             {
690                 OUString aProcName = "Property Get "
691                                    + pProcProperty->GetName();
692 
693                 SbxVariable* pMethVar = Find( aProcName, SbxClassType::Method );
694                 if( pMethVar )
695                 {
696                     SbxValues aVals;
697                     aVals.eType = SbxVARIANT;
698 
699                     SbxArray* pArg = pVar->GetParameters();
700                     sal_uInt16 nVarParCount = (pArg != nullptr) ? pArg->Count() : 0;
701                     if( nVarParCount > 1 )
702                     {
703                         auto xMethParameters = tools::make_ref<SbxArray>();
704                         xMethParameters->Put( pMethVar, 0 );    // Method as parameter 0
705                         for( sal_uInt16 i = 1 ; i < nVarParCount ; ++i )
706                         {
707                             SbxVariable* pPar = pArg->Get( i );
708                             xMethParameters->Put( pPar, i );
709                         }
710 
711                         pMethVar->SetParameters( xMethParameters.get() );
712                         pMethVar->Get( aVals );
713                         pMethVar->SetParameters( nullptr );
714                     }
715                     else
716                     {
717                         pMethVar->Get( aVals );
718                     }
719 
720                     pVar->Put( aVals );
721                 }
722             }
723             else if( pHint->GetId() == SfxHintId::BasicDataChanged )
724             {
725                 SbxVariable* pMethVar = nullptr;
726 
727                 bool bSet = pProcProperty->isSet();
728                 if( bSet )
729                 {
730                     pProcProperty->setSet( false );
731 
732                     OUString aProcName = "Property Set "
733                                        + pProcProperty->GetName();
734                     pMethVar = Find( aProcName, SbxClassType::Method );
735                 }
736                 if( !pMethVar ) // Let
737                 {
738                     OUString aProcName = "Property Let "
739                                        + pProcProperty->GetName();
740                     pMethVar = Find( aProcName, SbxClassType::Method );
741                 }
742 
743                 if( pMethVar )
744                 {
745                     // Setup parameters
746                     SbxArrayRef xArray = new SbxArray;
747                     xArray->Put( pMethVar, 0 ); // Method as parameter 0
748                     xArray->Put( pVar, 1 );
749                     pMethVar->SetParameters( xArray.get() );
750 
751                     SbxValues aVals;
752                     pMethVar->Get( aVals );
753                     pMethVar->SetParameters( nullptr );
754                 }
755             }
756         }
757         if( pProp )
758         {
759             if( pProp->GetModule() != this )
760                 SetError( ERRCODE_BASIC_BAD_ACTION );
761         }
762         else if( pMeth )
763         {
764             if( pHint->GetId() == SfxHintId::BasicDataWanted )
765             {
766                 if( pMeth->bInvalid && !Compile() )
767                 {
768                     // auto compile has not worked!
769                     StarBASIC::Error( ERRCODE_BASIC_BAD_PROP_VALUE );
770                 }
771                 else
772                 {
773                     // Call of a subprogram
774                     SbModule* pOld = GetSbData()->pMod;
775                     GetSbData()->pMod = this;
776                     Run( static_cast<SbMethod*>(pVar) );
777                     GetSbData()->pMod = pOld;
778                 }
779             }
780         }
781         else
782         {
783             // #i92642: Special handling for name property to avoid
784             // side effects when using name as variable implicitly
785             bool bForwardToSbxObject = true;
786 
787             const SfxHintId nId = pHint->GetId();
788             if( (nId == SfxHintId::BasicDataWanted || nId == SfxHintId::BasicDataChanged) &&
789                 pVar->GetName().equalsIgnoreAsciiCase( "name" ) )
790             {
791                     bForwardToSbxObject = false;
792             }
793             if( bForwardToSbxObject )
794             {
795                 SbxObject::Notify( rBC, rHint );
796             }
797         }
798     }
799 }
800 
801 // The setting of the source makes the image invalid
802 // and scans the method definitions newly in
803 
804 void SbModule::SetSource32( const OUString& r )
805 {
806     // Default basic mode to library container mode, but.. allow Option VBASupport 0/1 override
807     SetVBACompat( getDefaultVBAMode( static_cast< StarBASIC*>( GetParent() ) ) );
808     aOUSource = r;
809     StartDefinitions();
810     SbiTokenizer aTok( r );
811     aTok.SetCompatible( IsVBACompat() );
812 
813     while( !aTok.IsEof() )
814     {
815         SbiToken eEndTok = NIL;
816 
817         // Searching for SUB or FUNCTION
818         SbiToken eLastTok = NIL;
819         while( !aTok.IsEof() )
820         {
821             // #32385: not by declare
822             SbiToken eCurTok = aTok.Next();
823             if( eLastTok != DECLARE )
824             {
825                 if( eCurTok == SUB )
826                 {
827                     eEndTok = ENDSUB; break;
828                 }
829                 if( eCurTok == FUNCTION )
830                 {
831                     eEndTok = ENDFUNC; break;
832                 }
833                 if( eCurTok == PROPERTY )
834                 {
835                     eEndTok = ENDPROPERTY; break;
836                 }
837                 if( eCurTok == OPTION )
838                 {
839                     eCurTok = aTok.Next();
840                     if( eCurTok == COMPATIBLE )
841                     {
842                         aTok.SetCompatible( true );
843                     }
844                     else if ( ( eCurTok == VBASUPPORT ) && ( aTok.Next() == NUMBER ) )
845                     {
846                         bool bIsVBA = ( aTok.GetDbl()== 1 );
847                         SetVBACompat( bIsVBA );
848                         aTok.SetCompatible( bIsVBA );
849                     }
850                 }
851             }
852             eLastTok = eCurTok;
853         }
854         // Definition of the method
855         SbMethod* pMeth = nullptr;
856         if( eEndTok != NIL )
857         {
858             sal_uInt16 nLine1 = aTok.GetLine();
859             if( aTok.Next() == SYMBOL )
860             {
861                 OUString aName_( aTok.GetSym() );
862                 SbxDataType t = aTok.GetType();
863                 if( t == SbxVARIANT && eEndTok == ENDSUB )
864                 {
865                     t = SbxVOID;
866                 }
867                 pMeth = GetMethod( aName_, t );
868                 pMeth->nLine1 = pMeth->nLine2 = nLine1;
869                 // The method is for a start VALID
870                 pMeth->bInvalid = false;
871             }
872             else
873             {
874                 eEndTok = NIL;
875             }
876         }
877         // Skip up to END SUB/END FUNCTION
878         if( eEndTok != NIL )
879         {
880             while( !aTok.IsEof() )
881             {
882                 if( aTok.Next() == eEndTok )
883                 {
884                     pMeth->nLine2 = aTok.GetLine();
885                     break;
886                 }
887             }
888             if( aTok.IsEof() )
889             {
890                 pMeth->nLine2 = aTok.GetLine();
891             }
892         }
893     }
894     EndDefinitions( true );
895 }
896 
897 // Broadcast of a hint to all Basics
898 
899 static void SendHint_( SbxObject* pObj, SfxHintId nId, SbMethod* p )
900 {
901     // Self a BASIC?
902     if( dynamic_cast<const StarBASIC *>(pObj) != nullptr && pObj->IsBroadcaster() )
903         pObj->GetBroadcaster().Broadcast( SbxHint( nId, p ) );
904     // Then ask for the subobjects
905     SbxArray* pObjs = pObj->GetObjects();
906     for( sal_uInt16 i = 0; i < pObjs->Count(); i++ )
907     {
908         SbxVariable* pVar = pObjs->Get( i );
909         if( dynamic_cast<const SbxObject *>(pVar) != nullptr )
910             SendHint_( dynamic_cast<SbxObject*>( pVar), nId, p  );
911     }
912 }
913 
914 static void SendHint( SbxObject* pObj, SfxHintId nId, SbMethod* p )
915 {
916     while( pObj->GetParent() )
917         pObj = pObj->GetParent();
918     SendHint_( pObj, nId, p );
919 }
920 
921 // #57841 Clear Uno-Objects, which were helt in RTL functions,
922 // at the end of the program, so that nothing were helt.
923 static void ClearUnoObjectsInRTL_Impl_Rek( StarBASIC* pBasic )
924 {
925     // delete the return value of CreateUnoService
926     SbxVariable* pVar = pBasic->GetRtl()->Find( "CreateUnoService", SbxClassType::Method );
927     if( pVar )
928     {
929         pVar->SbxValue::Clear();
930     }
931     // delete the return value of CreateUnoDialog
932     pVar = pBasic->GetRtl()->Find( "CreateUnoDialog", SbxClassType::Method );
933     if( pVar )
934     {
935         pVar->SbxValue::Clear();
936     }
937     // delete the return value of CDec
938     pVar = pBasic->GetRtl()->Find( "CDec", SbxClassType::Method );
939     if( pVar )
940     {
941         pVar->SbxValue::Clear();
942     }
943     // delete return value of CreateObject
944     pVar = pBasic->GetRtl()->Find( "CreateObject", SbxClassType::Method );
945     if( pVar )
946     {
947         pVar->SbxValue::Clear();
948     }
949     // Go over all Sub-Basics
950     SbxArray* pObjs = pBasic->GetObjects();
951     sal_uInt16 nCount = pObjs->Count();
952     for( sal_uInt16 i = 0 ; i < nCount ; i++ )
953     {
954         SbxVariable* pObjVar = pObjs->Get( i );
955         StarBASIC* pSubBasic = dynamic_cast<StarBASIC*>( pObjVar  );
956         if( pSubBasic )
957         {
958             ClearUnoObjectsInRTL_Impl_Rek( pSubBasic );
959         }
960     }
961 }
962 
963 static void ClearUnoObjectsInRTL_Impl( StarBASIC* pBasic )
964 {
965     // #67781 Delete return values of the Uno-methods
966     clearUnoMethods();
967 
968     ClearUnoObjectsInRTL_Impl_Rek( pBasic );
969 
970     // Search for the topmost Basic
971     SbxObject* p = pBasic;
972     while( p->GetParent() )
973         p = p->GetParent();
974     if( static_cast<StarBASIC*>(p) != pBasic )
975         ClearUnoObjectsInRTL_Impl_Rek( static_cast<StarBASIC*>(p) );
976 }
977 
978 
979 void SbModule::SetVBACompat( bool bCompat )
980 {
981     if( mbVBACompat != bCompat )
982     {
983         mbVBACompat = bCompat;
984         // initialize VBA document API
985         if( mbVBACompat ) try
986         {
987             StarBASIC* pBasic = static_cast< StarBASIC* >( GetParent() );
988             uno::Reference< lang::XMultiServiceFactory > xFactory( getDocumentModel( pBasic ), uno::UNO_QUERY_THROW );
989             xFactory->createInstance( "ooo.vba.VBAGlobals" );
990         }
991         catch( Exception& )
992         {
993         }
994     }
995 }
996 
997 // Run a Basic-subprogram
998 void SbModule::Run( SbMethod* pMeth )
999 {
1000     SAL_INFO("basic","About to run " << pMeth->GetName() << ", vba compatmode is " << mbVBACompat );
1001 
1002     static sal_uInt16 nMaxCallLevel = 0;
1003 
1004     bool bDelInst = ( GetSbData()->pInst == nullptr );
1005     bool bQuit = false;
1006     StarBASICRef xBasic;
1007     uno::Reference< frame::XModel > xModel;
1008     uno::Reference< script::vba::XVBACompatibility > xVBACompat;
1009     if( bDelInst )
1010     {
1011         // #32779: Hold Basic during the execution
1012         xBasic = static_cast<StarBASIC*>( GetParent() );
1013 
1014         GetSbData()->pInst = new SbiInstance( static_cast<StarBASIC*>(GetParent()) );
1015 
1016         /*  If a VBA script in a document is started, get the VBA compatibility
1017             interface from the document Basic library container, and notify all
1018             VBA script listeners about the started script. */
1019         if( mbVBACompat )
1020         {
1021             StarBASIC* pBasic = static_cast< StarBASIC* >( GetParent() );
1022             if( pBasic && pBasic->IsDocBasic() ) try
1023             {
1024                 xModel.set( getDocumentModel( pBasic ), uno::UNO_SET_THROW );
1025                 xVBACompat.set( getVBACompatibility( xModel ), uno::UNO_SET_THROW );
1026                 xVBACompat->broadcastVBAScriptEvent( script::vba::VBAScriptEventId::SCRIPT_STARTED, GetName() );
1027             }
1028             catch(const uno::Exception& )
1029             {
1030             }
1031         }
1032 
1033         // Launcher problem
1034         // i80726 The Find below will generate an error in Testtool so we reset it unless there was one before already
1035         bool bWasError = SbxBase::GetError() != ERRCODE_NONE;
1036         SbxVariable* pMSOMacroRuntimeLibVar = Find( "Launcher", SbxClassType::Object );
1037         if ( !bWasError && (SbxBase::GetError() == ERRCODE_BASIC_PROC_UNDEFINED) )
1038             SbxBase::ResetError();
1039         if( pMSOMacroRuntimeLibVar )
1040         {
1041             StarBASIC* pMSOMacroRuntimeLib = dynamic_cast<StarBASIC*>( pMSOMacroRuntimeLibVar );
1042             if( pMSOMacroRuntimeLib )
1043             {
1044                 SbxFlagBits nGblFlag = pMSOMacroRuntimeLib->GetFlags() & SbxFlagBits::GlobalSearch;
1045                 pMSOMacroRuntimeLib->ResetFlag( SbxFlagBits::GlobalSearch );
1046                 SbxVariable* pAppSymbol = pMSOMacroRuntimeLib->Find( "Application", SbxClassType::Method );
1047                 pMSOMacroRuntimeLib->SetFlag( nGblFlag );
1048                 if( pAppSymbol )
1049                 {
1050                     pMSOMacroRuntimeLib->SetFlag( SbxFlagBits::ExtSearch );      // Could have been disabled before
1051                     GetSbData()->pMSOMacroRuntimLib = pMSOMacroRuntimeLib;
1052                 }
1053             }
1054         }
1055 
1056         if( nMaxCallLevel == 0 )
1057         {
1058 #ifdef UNX
1059           struct rlimit rl;
1060           getrlimit ( RLIMIT_STACK, &rl );
1061 #endif
1062 #if defined LINUX
1063           // Empiric value, 900 = needed bytes/Basic call level
1064           // for Linux including 10% safety margin
1065           nMaxCallLevel = rl.rlim_cur / 900;
1066 #elif defined __sun
1067           // Empiric value, 1650 = needed bytes/Basic call level
1068           // for Solaris including 10% safety margin
1069           nMaxCallLevel = rl.rlim_cur / 1650;
1070 #elif defined _WIN32
1071           nMaxCallLevel = 5800;
1072 #else
1073           nMaxCallLevel = MAXRECURSION;
1074 #endif
1075         }
1076     }
1077 
1078     // Recursion to deep?
1079     if( ++GetSbData()->pInst->nCallLvl <= nMaxCallLevel )
1080     {
1081         // Define a globale variable in all Mods
1082         GlobalRunInit( /* bBasicStart = */ bDelInst );
1083 
1084         // Appeared a compiler error? Then we don't launch
1085         if( !GetSbData()->bGlobalInitErr )
1086         {
1087             if( bDelInst )
1088             {
1089                 SendHint( GetParent(), SfxHintId::BasicStart, pMeth );
1090 
1091                 // 1996-10-16: #31460 New concept for StepInto/Over/Out
1092                 // For an explanation see runtime.cxx at SbiInstance::CalcBreakCallLevel()
1093                 // Identify the BreakCallLevel
1094                 GetSbData()->pInst->CalcBreakCallLevel( pMeth->GetDebugFlags() );
1095             }
1096 
1097             SbModule* pOldMod = GetSbData()->pMod;
1098             GetSbData()->pMod = this;
1099             std::unique_ptr<SbiRuntime> pRt(new SbiRuntime( this, pMeth, pMeth->nStart ));
1100 
1101             pRt->pNext = GetSbData()->pInst->pRun;
1102             if( pRt->pNext )
1103                 pRt->pNext->block();
1104             GetSbData()->pInst->pRun = pRt.get();
1105             if ( mbVBACompat )
1106             {
1107                 GetSbData()->pInst->EnableCompatibility( true );
1108             }
1109 
1110             while( pRt->Step() ) {}
1111 
1112             if( pRt->pNext )
1113                 pRt->pNext->unblock();
1114 
1115             // #63710 It can happen by an another thread handling at events,
1116             // that the show call returns to a dialog (by closing the
1117             // dialog per UI), before a by an event triggered further call returned,
1118             // which stands in Basic more top in the stack and that had been run on
1119             // a  Basic-Breakpoint. Then would the instance below destroyed. And if the Basic,
1120             // that stand still in the call, further runs, there is a GPF.
1121             // Thus here had to be wait until the other call comes back.
1122             if( bDelInst )
1123             {
1124                 // Compare here with 1 instead of 0, because before nCallLvl--
1125                 while( GetSbData()->pInst->nCallLvl != 1 )
1126                     Application::Yield();
1127             }
1128 
1129             GetSbData()->pInst->pRun = pRt->pNext;
1130             GetSbData()->pInst->nCallLvl--;          // Call-Level down again
1131 
1132             // Exist an higher-ranking runtime instance?
1133             // Then take over BasicDebugFlags::Break, if set
1134             SbiRuntime* pRtNext = pRt->pNext;
1135             if( pRtNext && (pRt->GetDebugFlags() & BasicDebugFlags::Break) )
1136                 pRtNext->SetDebugFlags( BasicDebugFlags::Break );
1137 
1138             pRt.reset();
1139             GetSbData()->pMod = pOldMod;
1140             if( bDelInst )
1141             {
1142                 // #57841 Clear Uno-Objects, which were helt in RTL functions,
1143                 // at the end of the program, so that nothing were helt.
1144                 ClearUnoObjectsInRTL_Impl( xBasic.get() );
1145 
1146                 clearNativeObjectWrapperVector();
1147 
1148                 SAL_WARN_IF(GetSbData()->pInst->nCallLvl != 0,"basic","BASIC-Call-Level > 0");
1149                 delete GetSbData()->pInst;
1150                 GetSbData()->pInst = nullptr;
1151                 bDelInst = false;
1152 
1153                 // #i30690
1154                 SolarMutexGuard aSolarGuard;
1155                 SendHint( GetParent(), SfxHintId::BasicStop, pMeth );
1156 
1157                 GlobalRunDeInit();
1158 
1159                 if( xVBACompat.is() )
1160                 {
1161                     // notify all VBA script listeners about the stopped script
1162                     try
1163                     {
1164                         xVBACompat->broadcastVBAScriptEvent( script::vba::VBAScriptEventId::SCRIPT_STOPPED, GetName() );
1165                     }
1166                     catch(const uno::Exception& )
1167                     {
1168                     }
1169                     // VBA always ensures screenupdating is enabled after completing
1170                     ::basic::vba::lockControllersOfAllDocuments( xModel, false );
1171                     ::basic::vba::enableContainerWindowsOfAllDocuments( xModel, true );
1172                 }
1173             }
1174         }
1175         else
1176                GetSbData()->pInst->nCallLvl--;           // Call-Level down again
1177     }
1178     else
1179     {
1180         GetSbData()->pInst->nCallLvl--;          // Call-Level down again
1181         StarBASIC::FatalError( ERRCODE_BASIC_STACK_OVERFLOW );
1182     }
1183 
1184     StarBASIC* pBasic = dynamic_cast<StarBASIC*>( GetParent() );
1185     if( bDelInst )
1186     {
1187        // #57841 Clear Uno-Objects, which were helt in RTL functions,
1188        // the end of the program, so that nothing were helt.
1189         ClearUnoObjectsInRTL_Impl( xBasic.get() );
1190 
1191         delete GetSbData()->pInst;
1192         GetSbData()->pInst = nullptr;
1193     }
1194     if ( pBasic && pBasic->IsDocBasic() && pBasic->IsQuitApplication() && !GetSbData()->pInst )
1195             bQuit = true;
1196     if ( bQuit )
1197     {
1198         Application::PostUserEvent( LINK( &AsyncQuitHandler::instance(), AsyncQuitHandler, OnAsyncQuit ) );
1199     }
1200 }
1201 
1202 // Execute of the init method of a module after the loading
1203 // or the compilation
1204 
1205 void SbModule::RunInit()
1206 {
1207     if( pImage
1208      && !pImage->bInit
1209      && pImage->IsFlag( SbiImageFlags::INITCODE ) )
1210     {
1211         // Set flag, so that RunInit get active (Testtool)
1212         GetSbData()->bRunInit = true;
1213 
1214         SbModule* pOldMod = GetSbData()->pMod;
1215         GetSbData()->pMod = this;
1216         // The init code starts always here
1217         std::unique_ptr<SbiRuntime> pRt(new SbiRuntime( this, nullptr, 0 ));
1218 
1219         pRt->pNext = GetSbData()->pInst->pRun;
1220         GetSbData()->pInst->pRun = pRt.get();
1221         while( pRt->Step() ) {}
1222 
1223         GetSbData()->pInst->pRun = pRt->pNext;
1224         pRt.reset();
1225         GetSbData()->pMod = pOldMod;
1226         pImage->bInit = true;
1227         pImage->bFirstInit = false;
1228 
1229         // RunInit is not active anymore
1230         GetSbData()->bRunInit = false;
1231     }
1232 }
1233 
1234 // Delete with private/dim declared variables
1235 
1236 void SbModule::AddVarName( const OUString& aName )
1237 {
1238     // see if the name is added already
1239     for ( const auto& rModuleVariableName: mModuleVariableNames )
1240     {
1241         if ( aName == rModuleVariableName )
1242             return;
1243     }
1244     mModuleVariableNames.push_back( aName );
1245 }
1246 
1247 void SbModule::RemoveVars()
1248 {
1249     for ( const auto& rModuleVariableName: mModuleVariableNames )
1250     {
1251     // We don't want a Find being called in a derived class ( e.g.
1252     // SbUserform because it could trigger say an initialise event
1253     // which would cause basic to be re-run in the middle of the init ( and remember RemoveVars is called from compile and we don't want code to run as part of the compile )
1254     SbxVariableRef p = SbModule::Find( rModuleVariableName, SbxClassType::Property );
1255     if( p.is() )
1256         Remove( p.get() );
1257     }
1258 }
1259 
1260 void SbModule::ClearPrivateVars()
1261 {
1262     for( sal_uInt16 i = 0 ; i < pProps->Count() ; i++ )
1263     {
1264         SbProperty* p = dynamic_cast<SbProperty*>( pProps->Get( i )  );
1265         if( p )
1266         {
1267             // Delete not the arrays, only their content
1268             if( p->GetType() & SbxARRAY )
1269             {
1270                 SbxArray* pArray = dynamic_cast<SbxArray*>( p->GetObject() );
1271                 if( pArray )
1272                 {
1273                     for( sal_uInt16 j = 0 ; j < pArray->Count() ; j++ )
1274                     {
1275                         SbxVariable* pj = pArray->Get( j );
1276                         pj->SbxValue::Clear();
1277                     }
1278                 }
1279             }
1280             else
1281             {
1282                 p->SbxValue::Clear();
1283             }
1284         }
1285     }
1286 }
1287 
1288 void SbModule::implClearIfVarDependsOnDeletedBasic( SbxVariable* pVar, StarBASIC* pDeletedBasic )
1289 {
1290     if( pVar->SbxValue::GetType() != SbxOBJECT || dynamic_cast<const SbProcedureProperty*>( pVar) != nullptr )
1291         return;
1292 
1293     SbxObject* pObj = dynamic_cast<SbxObject*>( pVar->GetObject() );
1294     if( pObj != nullptr )
1295     {
1296         SbxObject* p = pObj;
1297 
1298         SbModule* pMod = dynamic_cast<SbModule*>( p  );
1299         if( pMod != nullptr )
1300             pMod->ClearVarsDependingOnDeletedBasic( pDeletedBasic );
1301 
1302         while( (p = p->GetParent()) != nullptr )
1303         {
1304             StarBASIC* pBasic = dynamic_cast<StarBASIC*>( p  );
1305             if( pBasic != nullptr && pBasic == pDeletedBasic )
1306             {
1307                 pVar->SbxValue::Clear();
1308                 break;
1309             }
1310         }
1311     }
1312 }
1313 
1314 void SbModule::ClearVarsDependingOnDeletedBasic( StarBASIC* pDeletedBasic )
1315 {
1316     for( sal_uInt16 i = 0 ; i < pProps->Count() ; i++ )
1317     {
1318         SbProperty* p = dynamic_cast<SbProperty*>( pProps->Get( i )  );
1319         if( p )
1320         {
1321             if( p->GetType() & SbxARRAY )
1322             {
1323                 SbxArray* pArray = dynamic_cast<SbxArray*>( p->GetObject() );
1324                 if( pArray )
1325                 {
1326                     for( sal_uInt16 j = 0 ; j < pArray->Count() ; j++ )
1327                     {
1328                         SbxVariable* pVar = pArray->Get( j );
1329                         implClearIfVarDependsOnDeletedBasic( pVar, pDeletedBasic );
1330                     }
1331                 }
1332             }
1333             else
1334             {
1335                 implClearIfVarDependsOnDeletedBasic( p, pDeletedBasic );
1336             }
1337         }
1338     }
1339 }
1340 
1341 void StarBASIC::ClearAllModuleVars()
1342 {
1343     // Initialise the own module
1344     for (const auto& rModule: pModules)
1345     {
1346         // Initialise only, if the startcode was already executed
1347         if( rModule->pImage && rModule->pImage->bInit && !rModule->isProxyModule() && dynamic_cast<const SbObjModule*>( rModule.get()) == nullptr )
1348             rModule->ClearPrivateVars();
1349     }
1350 
1351 }
1352 
1353 // Execution of the init-code of all module
1354 void SbModule::GlobalRunInit( bool bBasicStart )
1355 {
1356     // If no Basic-Start, only initialise, if the module is not initialised
1357     if( !bBasicStart )
1358         if( !(pImage && !pImage->bInit) )
1359             return;
1360 
1361     // Initialise GlobalInitErr-Flag for Compiler-Error
1362     // With the help of this flags could be located in SbModule::Run() after the call of
1363     // GlobalRunInit, if at the initialising of the module
1364     // an error occurred. Then it will not be launched.
1365     GetSbData()->bGlobalInitErr = false;
1366 
1367     // Parent of the module is a Basic
1368     StarBASIC *pBasic = dynamic_cast<StarBASIC*>( GetParent() );
1369     if( pBasic )
1370     {
1371         pBasic->InitAllModules();
1372 
1373         SbxObject* pParent_ = pBasic->GetParent();
1374         if( pParent_ )
1375         {
1376             StarBASIC * pParentBasic = dynamic_cast<StarBASIC*>( pParent_ );
1377             if( pParentBasic )
1378             {
1379                 pParentBasic->InitAllModules( pBasic );
1380 
1381                 // #109018 Parent can also have a parent (library in doc)
1382                 SbxObject* pParentParent = pParentBasic->GetParent();
1383                 if( pParentParent )
1384                 {
1385                     StarBASIC * pParentParentBasic = dynamic_cast<StarBASIC*>( pParentParent );
1386                     if( pParentParentBasic )
1387                         pParentParentBasic->InitAllModules( pParentBasic );
1388                 }
1389             }
1390         }
1391     }
1392 }
1393 
1394 void SbModule::GlobalRunDeInit()
1395 {
1396     StarBASIC *pBasic = dynamic_cast<StarBASIC*>( GetParent() );
1397     if( pBasic )
1398     {
1399         pBasic->DeInitAllModules();
1400 
1401         SbxObject* pParent_ = pBasic->GetParent();
1402         if( pParent_ )
1403             pBasic = dynamic_cast<StarBASIC*>( pParent_ );
1404         if( pBasic )
1405             pBasic->DeInitAllModules();
1406     }
1407 }
1408 
1409 // Search for the next STMNT-Command in the code. This was used from the STMNT-
1410 // Opcode to set the endcolumn.
1411 
1412 const sal_uInt8* SbModule::FindNextStmnt( const sal_uInt8* p, sal_uInt16& nLine, sal_uInt16& nCol ) const
1413 {
1414     return FindNextStmnt( p, nLine, nCol, false );
1415 }
1416 
1417 const sal_uInt8* SbModule::FindNextStmnt( const sal_uInt8* p, sal_uInt16& nLine, sal_uInt16& nCol,
1418     bool bFollowJumps, const SbiImage* pImg ) const
1419 {
1420     sal_uInt32 nPC = static_cast<sal_uInt32>( p - reinterpret_cast<const sal_uInt8*>(pImage->GetCode()) );
1421     while( nPC < pImage->GetCodeSize() )
1422     {
1423         SbiOpcode eOp = static_cast<SbiOpcode>( *p++ );
1424         nPC++;
1425         if( bFollowJumps && eOp == SbiOpcode::JUMP_ && pImg )
1426         {
1427             SAL_WARN_IF( !pImg, "basic", "FindNextStmnt: pImg==NULL with FollowJumps option" );
1428             sal_uInt32 nOp1 = *p++; nOp1 |= *p++ << 8;
1429             nOp1 |= *p++ << 16; nOp1 |= *p++ << 24;
1430             p = reinterpret_cast<const sal_uInt8*>(pImg->GetCode()) + nOp1;
1431         }
1432         else if( eOp >= SbiOpcode::SbOP1_START && eOp <= SbiOpcode::SbOP1_END )
1433         {
1434             p += 4;
1435             nPC += 4;
1436         }
1437         else if( eOp == SbiOpcode::STMNT_ )
1438         {
1439             sal_uInt32 nl, nc;
1440             nl = *p++; nl |= *p++ << 8;
1441             nl |= *p++ << 16 ; nl |= *p++ << 24;
1442             nc = *p++; nc |= *p++ << 8;
1443             nc |= *p++ << 16 ; nc |= *p++ << 24;
1444             nLine = static_cast<sal_uInt16>(nl); nCol = static_cast<sal_uInt16>(nc);
1445             return p;
1446         }
1447         else if( eOp >= SbiOpcode::SbOP2_START && eOp <= SbiOpcode::SbOP2_END )
1448         {
1449             p += 8;
1450             nPC += 8;
1451         }
1452         else if( !( eOp >= SbiOpcode::SbOP0_START && eOp <= SbiOpcode::SbOP0_END ) )
1453         {
1454             StarBASIC::FatalError( ERRCODE_BASIC_INTERNAL_ERROR );
1455             break;
1456         }
1457     }
1458     return nullptr;
1459 }
1460 
1461 // Test, if a line contains STMNT-Opcodes
1462 
1463 bool SbModule::IsBreakable( sal_uInt16 nLine ) const
1464 {
1465     if( !pImage )
1466         return false;
1467     const sal_uInt8* p = reinterpret_cast<const sal_uInt8*>(pImage->GetCode());
1468     sal_uInt16 nl, nc;
1469     while( ( p = FindNextStmnt( p, nl, nc ) ) != nullptr )
1470         if( nl == nLine )
1471             return true;
1472     return false;
1473 }
1474 
1475 bool SbModule::IsBP( sal_uInt16 nLine ) const
1476 {
1477     if( pBreaks )
1478     {
1479         for( size_t i = 0; i < pBreaks->size(); i++ )
1480         {
1481             sal_uInt16 b = pBreaks->operator[]( i );
1482             if( b == nLine )
1483                 return true;
1484             if( b < nLine )
1485                 break;
1486         }
1487     }
1488     return false;
1489 }
1490 
1491 bool SbModule::SetBP( sal_uInt16 nLine )
1492 {
1493     if( !IsBreakable( nLine ) )
1494         return false;
1495     if( !pBreaks )
1496         pBreaks.reset( new SbiBreakpoints );
1497     auto it = std::find_if(pBreaks->begin(), pBreaks->end(),
1498         [&nLine](const sal_uInt16 b) { return b <= nLine; });
1499     if (it != pBreaks->end() && *it == nLine)
1500         return true;
1501     pBreaks->insert( it, nLine );
1502 
1503     // #38568: Set during runtime as well here BasicDebugFlags::Break
1504     if( GetSbData()->pInst && GetSbData()->pInst->pRun )
1505         GetSbData()->pInst->pRun->SetDebugFlags( BasicDebugFlags::Break );
1506 
1507     return IsBreakable( nLine );
1508 }
1509 
1510 bool SbModule::ClearBP( sal_uInt16 nLine )
1511 {
1512     bool bRes = false;
1513     if( pBreaks )
1514     {
1515         auto it = std::find_if(pBreaks->begin(), pBreaks->end(),
1516             [&nLine](const sal_uInt16 b) { return b <= nLine; });
1517         bRes = (it != pBreaks->end()) && (*it == nLine);
1518         if (bRes)
1519         {
1520             pBreaks->erase(it);
1521         }
1522         if( pBreaks->empty() )
1523         {
1524             pBreaks.reset();
1525         }
1526     }
1527     return bRes;
1528 }
1529 
1530 void SbModule::ClearAllBP()
1531 {
1532     pBreaks.reset();
1533 }
1534 
1535 void
1536 SbModule::fixUpMethodStart( bool bCvtToLegacy, SbiImage* pImg ) const
1537 {
1538         if ( !pImg )
1539             pImg = pImage.get();
1540         for( sal_uInt32 i = 0; i < pMethods->Count(); i++ )
1541         {
1542             SbMethod* pMeth = dynamic_cast<SbMethod*>( pMethods->Get( static_cast<sal_uInt16>(i) )  );
1543             if( pMeth )
1544             {
1545                 //fixup method start positions
1546                 if ( bCvtToLegacy )
1547                     pMeth->nStart = pImg->CalcLegacyOffset( pMeth->nStart );
1548                 else
1549                     pMeth->nStart = pImg->CalcNewOffset( static_cast<sal_uInt16>(pMeth->nStart) );
1550             }
1551         }
1552 
1553 }
1554 
1555 bool SbModule::LoadData( SvStream& rStrm, sal_uInt16 nVer )
1556 {
1557     Clear();
1558     if( !SbxObject::LoadData( rStrm, 1 ) )
1559         return false;
1560     // As a precaution...
1561     SetFlag( SbxFlagBits::ExtSearch | SbxFlagBits::GlobalSearch );
1562     sal_uInt8 bImage;
1563     rStrm.ReadUChar( bImage );
1564     if( bImage )
1565     {
1566         std::unique_ptr<SbiImage> p( new SbiImage );
1567         sal_uInt32 nImgVer = 0;
1568 
1569         if( !p->Load( rStrm, nImgVer ) )
1570         {
1571             return false;
1572         }
1573         // If the image is in old format, we fix up the method start offsets
1574         if ( nImgVer < B_EXT_IMG_VERSION )
1575         {
1576             fixUpMethodStart( false, p.get() );
1577             p->ReleaseLegacyBuffer();
1578         }
1579         aComment = p->aComment;
1580         SetName( p->aName );
1581         if( p->GetCodeSize() )
1582         {
1583             aOUSource = p->aOUSource;
1584             // Old version: image away
1585             if( nVer == 1 )
1586             {
1587                 SetSource32( p->aOUSource );
1588             }
1589             else
1590                 pImage = std::move(p);
1591         }
1592         else
1593         {
1594             SetSource32( p->aOUSource );
1595         }
1596     }
1597     return true;
1598 }
1599 
1600 bool SbModule::StoreData( SvStream& rStrm ) const
1601 {
1602     bool bFixup = ( pImage && !pImage->ExceedsLegacyLimits() );
1603     if ( bFixup )
1604         fixUpMethodStart( true );
1605     bool bRet = SbxObject::StoreData( rStrm );
1606     if ( !bRet )
1607         return false;
1608 
1609     if( pImage )
1610     {
1611         pImage->aOUSource = aOUSource;
1612         pImage->aComment = aComment;
1613         pImage->aName = GetName();
1614         rStrm.WriteUChar( 1 );
1615         // # PCode is saved only for legacy formats only
1616         // It should be noted that it probably isn't necessary
1617         // It would be better not to store the image ( more flexible with
1618         // formats )
1619         bool bRes = pImage->Save( rStrm, B_LEGACYVERSION );
1620         if ( bFixup )
1621             fixUpMethodStart( false ); // restore method starts
1622         return bRes;
1623 
1624     }
1625     else
1626     {
1627         SbiImage aImg;
1628         aImg.aOUSource = aOUSource;
1629         aImg.aComment = aComment;
1630         aImg.aName = GetName();
1631         rStrm.WriteUChar( 1 );
1632         return aImg.Save( rStrm );
1633     }
1634 }
1635 
1636 bool SbModule::ExceedsLegacyModuleSize()
1637 {
1638     if ( !IsCompiled() )
1639         Compile();
1640     return pImage && pImage->ExceedsLegacyLimits();
1641 }
1642 
1643 class ErrorHdlResetter
1644 {
1645     Link<StarBASIC*,bool> mErrHandler;
1646     bool    mbError;
1647 public:
1648     ErrorHdlResetter()
1649         : mErrHandler(StarBASIC::GetGlobalErrorHdl()) // save error handler
1650         , mbError( false )
1651     {
1652         // set new error handler
1653         StarBASIC::SetGlobalErrorHdl( LINK( this, ErrorHdlResetter, BasicErrorHdl ) );
1654     }
1655     ~ErrorHdlResetter()
1656     {
1657         // restore error handler
1658         StarBASIC::SetGlobalErrorHdl(mErrHandler);
1659     }
1660     DECL_LINK( BasicErrorHdl, StarBASIC *, bool );
1661     bool HasError() { return mbError; }
1662 };
1663 
1664 IMPL_LINK( ErrorHdlResetter, BasicErrorHdl, StarBASIC *, /*pBasic*/, bool)
1665 {
1666     mbError = true;
1667     return false;
1668 }
1669 
1670 void SbModule::GetCodeCompleteDataFromParse(CodeCompleteDataCache& aCache)
1671 {
1672     ErrorHdlResetter aErrHdl;
1673     SbxBase::ResetError();
1674 
1675     std::unique_ptr<SbiParser> pParser(new SbiParser( static_cast<StarBASIC*>(GetParent()), this ));
1676     pParser->SetCodeCompleting(true);
1677 
1678     while( pParser->Parse() ) {}
1679     SbiSymPool* pPool = pParser->pPool;
1680     aCache.Clear();
1681     for( sal_uInt16 i = 0; i < pPool->GetSize(); ++i )
1682     {
1683         SbiSymDef* pSymDef = pPool->Get(i);
1684         //std::cerr << "i: " << i << ", type: " << pSymDef->GetType() << "; name:" << pSymDef->GetName() << std::endl;
1685         if( (pSymDef->GetType() != SbxEMPTY) && (pSymDef->GetType() != SbxNULL) )
1686             aCache.InsertGlobalVar( pSymDef->GetName(), pParser->aGblStrings.Find(pSymDef->GetTypeId()) );
1687 
1688         SbiSymPool& rChildPool = pSymDef->GetPool();
1689         for(sal_uInt16 j = 0; j < rChildPool.GetSize(); ++j )
1690         {
1691             SbiSymDef* pChildSymDef = rChildPool.Get(j);
1692             //std::cerr << "j: " << j << ", type: " << pChildSymDef->GetType() << "; name:" << pChildSymDef->GetName() << std::endl;
1693             if( (pChildSymDef->GetType() != SbxEMPTY) && (pChildSymDef->GetType() != SbxNULL) )
1694                 aCache.InsertLocalVar( pSymDef->GetName(), pChildSymDef->GetName(), pParser->aGblStrings.Find(pChildSymDef->GetTypeId()) );
1695         }
1696     }
1697 }
1698 
1699 
1700 OUString SbModule::GetKeywordCase( const OUString& sKeyword )
1701 {
1702     return SbiParser::GetKeywordCase( sKeyword );
1703 }
1704 
1705 bool SbModule::HasExeCode()
1706 {
1707     // And empty Image always has the Global Chain set up
1708     static const unsigned char pEmptyImage[] = { 0x45, 0x0 , 0x0, 0x0, 0x0 };
1709     // lets be stricter for the moment than VBA
1710 
1711     if (!IsCompiled())
1712     {
1713         ErrorHdlResetter aGblErrHdl;
1714         Compile();
1715         if (aGblErrHdl.HasError()) //assume unsafe on compile error
1716             return true;
1717     }
1718 
1719     bool bRes = false;
1720     if (pImage && !(pImage->GetCodeSize() == 5 && (memcmp(pImage->GetCode(), pEmptyImage, pImage->GetCodeSize()) == 0 )))
1721         bRes = true;
1722 
1723     return bRes;
1724 }
1725 
1726 // Store only image, no source
1727 void SbModule::StoreBinaryData( SvStream& rStrm )
1728 {
1729     if (!Compile())
1730         return;
1731 
1732     if (!SbxObject::StoreData(rStrm))
1733         return;
1734 
1735     pImage->aOUSource.clear();
1736     pImage->aComment = aComment;
1737     pImage->aName = GetName();
1738 
1739     rStrm.WriteUChar(1);
1740     pImage->Save(rStrm);
1741 
1742     pImage->aOUSource = aOUSource;
1743 }
1744 
1745 // Called for >= OO 1.0 passwd protected libraries only
1746 
1747 void SbModule::LoadBinaryData( SvStream& rStrm )
1748 {
1749     OUString aKeepSource = aOUSource;
1750     LoadData( rStrm, 2 );
1751     LoadCompleted();
1752     aOUSource = aKeepSource;
1753 }
1754 
1755 bool SbModule::LoadCompleted()
1756 {
1757     SbxArray* p = GetMethods().get();
1758     sal_uInt16 i;
1759     for( i = 0; i < p->Count(); i++ )
1760     {
1761         SbMethod* q = dynamic_cast<SbMethod*>( p->Get( i )  );
1762         if( q )
1763             q->pMod = this;
1764     }
1765     p = GetProperties();
1766     for( i = 0; i < p->Count(); i++ )
1767     {
1768         SbProperty* q = dynamic_cast<SbProperty*>( p->Get( i )  );
1769         if( q )
1770             q->pMod = this;
1771     }
1772     return true;
1773 }
1774 
1775 void SbModule::handleProcedureProperties( SfxBroadcaster& rBC, const SfxHint& rHint )
1776 {
1777     bool bDone = false;
1778 
1779     const SbxHint* pHint = dynamic_cast<const SbxHint*>(&rHint);
1780     if( pHint )
1781     {
1782         SbxVariable* pVar = pHint->GetVar();
1783         SbProcedureProperty* pProcProperty = dynamic_cast<SbProcedureProperty*>( pVar  );
1784         if( pProcProperty )
1785         {
1786             bDone = true;
1787 
1788             if( pHint->GetId() == SfxHintId::BasicDataWanted )
1789             {
1790                 OUString aProcName = "Property Get "
1791                                    + pProcProperty->GetName();
1792 
1793                 SbxVariable* pMeth = Find( aProcName, SbxClassType::Method );
1794                 if( pMeth )
1795                 {
1796                     SbxValues aVals;
1797                     aVals.eType = SbxVARIANT;
1798 
1799                     SbxArray* pArg = pVar->GetParameters();
1800                     sal_uInt16 nVarParCount = (pArg != nullptr) ? pArg->Count() : 0;
1801                     if( nVarParCount > 1 )
1802                     {
1803                         SbxArrayRef xMethParameters = new SbxArray;
1804                         xMethParameters->Put( pMeth, 0 );   // Method as parameter 0
1805                         for( sal_uInt16 i = 1 ; i < nVarParCount ; ++i )
1806                         {
1807                             SbxVariable* pPar = pArg->Get( i );
1808                             xMethParameters->Put( pPar, i );
1809                         }
1810 
1811                         pMeth->SetParameters( xMethParameters.get() );
1812                         pMeth->Get( aVals );
1813                         pMeth->SetParameters( nullptr );
1814                     }
1815                     else
1816                     {
1817                         pMeth->Get( aVals );
1818                     }
1819 
1820                     pVar->Put( aVals );
1821                 }
1822             }
1823             else if( pHint->GetId() == SfxHintId::BasicDataChanged )
1824             {
1825                 SbxVariable* pMeth = nullptr;
1826 
1827                 bool bSet = pProcProperty->isSet();
1828                 if( bSet )
1829                 {
1830                     pProcProperty->setSet( false );
1831 
1832                     OUString aProcName = "Property Set "
1833                                        + pProcProperty->GetName();
1834                     pMeth = Find( aProcName, SbxClassType::Method );
1835                 }
1836                 if( !pMeth )    // Let
1837                 {
1838                     OUString aProcName = "Property Let "
1839                                        + pProcProperty->GetName();
1840                     pMeth = Find( aProcName, SbxClassType::Method );
1841                 }
1842 
1843                 if( pMeth )
1844                 {
1845                     // Setup parameters
1846                     SbxArrayRef xArray = new SbxArray;
1847                     xArray->Put( pMeth, 0 );    // Method as parameter 0
1848                     xArray->Put( pVar, 1 );
1849                     pMeth->SetParameters( xArray.get() );
1850 
1851                     SbxValues aVals;
1852                     pMeth->Get( aVals );
1853                     pMeth->SetParameters( nullptr );
1854                 }
1855             }
1856         }
1857     }
1858 
1859     if( !bDone )
1860         SbModule::Notify( rBC, rHint );
1861 }
1862 
1863 
1864 // Implementation SbJScriptModule (Basic module for JavaScript source code)
1865 SbJScriptModule::SbJScriptModule()
1866     :SbModule( "" )
1867 {
1868 }
1869 
1870 bool SbJScriptModule::LoadData( SvStream& rStrm, sal_uInt16 )
1871 {
1872     Clear();
1873     if( !SbxObject::LoadData( rStrm, 1 ) )
1874         return false;
1875 
1876     // Get the source string
1877     aOUSource = rStrm.ReadUniOrByteString( osl_getThreadTextEncoding() );
1878     return true;
1879 }
1880 
1881 bool SbJScriptModule::StoreData( SvStream& rStrm ) const
1882 {
1883     if( !SbxObject::StoreData( rStrm ) )
1884         return false;
1885 
1886     // Write the source string
1887     OUString aTmp = aOUSource;
1888     rStrm.WriteUniOrByteString( aTmp, osl_getThreadTextEncoding() );
1889     return true;
1890 }
1891 
1892 
1893 SbMethod::SbMethod( const OUString& r, SbxDataType t, SbModule* p )
1894         : SbxMethod( r, t ), pMod( p )
1895 {
1896     bInvalid     = true;
1897     nStart       = 0;
1898     nDebugFlags  = BasicDebugFlags::NONE;
1899     nLine1       = 0;
1900     nLine2       = 0;
1901     refStatics   = new SbxArray;
1902     mCaller      = nullptr;
1903     // HACK due to 'Reference could not be saved'
1904     SetFlag( SbxFlagBits::NoModify );
1905 }
1906 
1907 SbMethod::SbMethod( const SbMethod& r )
1908     : SvRefBase( r ), SbxMethod( r )
1909 {
1910     pMod         = r.pMod;
1911     bInvalid     = r.bInvalid;
1912     nStart       = r.nStart;
1913     nDebugFlags  = r.nDebugFlags;
1914     nLine1       = r.nLine1;
1915     nLine2       = r.nLine2;
1916     refStatics = r.refStatics;
1917     mCaller          = r.mCaller;
1918     SetFlag( SbxFlagBits::NoModify );
1919 }
1920 
1921 SbMethod::~SbMethod()
1922 {
1923 }
1924 
1925 void SbMethod::ClearStatics()
1926 {
1927     refStatics = new SbxArray;
1928 
1929 }
1930 SbxArray* SbMethod::GetStatics()
1931 {
1932     return refStatics.get();
1933 }
1934 
1935 bool SbMethod::LoadData( SvStream& rStrm, sal_uInt16 nVer )
1936 {
1937     if( !SbxMethod::LoadData( rStrm, 1 ) )
1938         return false;
1939 
1940     sal_uInt16 nFlag;
1941     rStrm.ReadUInt16( nFlag );
1942 
1943     sal_Int16 nTempStart = static_cast<sal_Int16>(nStart);
1944 
1945     if( nVer == 2 )
1946     {
1947         rStrm.ReadUInt16( nLine1 ).ReadUInt16( nLine2 ).ReadInt16( nTempStart ).ReadCharAsBool( bInvalid );
1948         //tdf#94617
1949         if (nFlag & 0x8000)
1950         {
1951             sal_uInt16 nMult = nFlag & 0x7FFF;
1952             sal_Int16 const nMax = std::numeric_limits<sal_Int16>::max();
1953             nStart = nMult * nMax + nTempStart;
1954         }
1955         else
1956         {
1957             nStart = nTempStart;
1958         }
1959     }
1960     else
1961     {
1962         nStart = nTempStart;
1963     }
1964 
1965     // HACK due to 'Reference could not be saved'
1966     SetFlag( SbxFlagBits::NoModify );
1967 
1968     return true;
1969 }
1970 
1971 bool SbMethod::StoreData( SvStream& rStrm ) const
1972 {
1973     if( !SbxMethod::StoreData( rStrm ) )
1974         return false;
1975 
1976     //tdf#94617
1977     sal_Int16 nMax = std::numeric_limits<sal_Int16>::max();
1978     sal_Int16 nStartTemp = nStart % nMax;
1979     sal_uInt16 nDebugFlagsTemp = nStart / nMax;
1980     nDebugFlagsTemp |= 0x8000;
1981 
1982     rStrm.WriteUInt16( nDebugFlagsTemp )
1983          .WriteInt16( nLine1 )
1984          .WriteInt16( nLine2 )
1985          .WriteInt16( nStartTemp )
1986          .WriteBool( bInvalid );
1987 
1988     return true;
1989 }
1990 
1991 void SbMethod::GetLineRange( sal_uInt16& l1, sal_uInt16& l2 )
1992 {
1993     l1 = nLine1; l2 = nLine2;
1994 }
1995 
1996 // Could later be deleted
1997 
1998 SbxInfo* SbMethod::GetInfo()
1999 {
2000     return pInfo.get();
2001 }
2002 
2003 // Interface to execute a method of the applications
2004 // With special RefCounting, so that the Basic was not fired of by CloseDocument()
2005 // The return value will be delivered as string.
2006 ErrCode SbMethod::Call( SbxValue* pRet, SbxVariable* pCaller )
2007 {
2008     if ( pCaller )
2009     {
2010         SAL_INFO("basic", "SbMethod::Call Have been passed a caller 0x" << pCaller );
2011         mCaller = pCaller;
2012     }
2013     // Increment the RefCount of the module
2014     tools::SvRef<SbModule> pMod_ = static_cast<SbModule*>(GetParent());
2015 
2016     tools::SvRef<StarBASIC> pBasic = static_cast<StarBASIC*>(pMod_->GetParent());
2017 
2018     // Establish the values to get the return value
2019     SbxValues aVals;
2020     aVals.eType = SbxVARIANT;
2021 
2022     // #104083: Compile BEFORE get
2023     if( bInvalid && !pMod_->Compile() )
2024         StarBASIC::Error( ERRCODE_BASIC_BAD_PROP_VALUE );
2025 
2026     Get( aVals );
2027     if ( pRet )
2028         pRet->Put( aVals );
2029 
2030     // Was there an error
2031     ErrCode nErr = SbxBase::GetError();
2032     SbxBase::ResetError();
2033 
2034     mCaller = nullptr;
2035     return nErr;
2036 }
2037 
2038 
2039 // #100883 Own Broadcast for SbMethod
2040 void SbMethod::Broadcast( SfxHintId nHintId )
2041 {
2042     if( mpBroadcaster && !IsSet( SbxFlagBits::NoBroadcast ) )
2043     {
2044         // Because the method could be called from outside, test here once again
2045         // the authorisation
2046         if( nHintId == SfxHintId::BasicDataWanted )
2047             if( !CanRead() )
2048                 return;
2049         if( nHintId == SfxHintId::BasicDataChanged )
2050             if( !CanWrite() )
2051                 return;
2052 
2053         if( pMod && !pMod->IsCompiled() )
2054             pMod->Compile();
2055 
2056         // Block broadcasts while creating new method
2057         std::unique_ptr<SfxBroadcaster> pSaveBroadcaster = std::move(mpBroadcaster);
2058         SbMethod* pThisCopy = new SbMethod( *this );
2059         SbMethodRef xHolder = pThisCopy;
2060         if( mpPar.is() )
2061         {
2062             // Enregister this as element 0, but don't reset the parent!
2063             if( GetType() != SbxVOID ) {
2064                 mpPar->PutDirect( pThisCopy, 0 );
2065             }
2066             SetParameters( nullptr );
2067         }
2068 
2069         mpBroadcaster = std::move(pSaveBroadcaster);
2070         mpBroadcaster->Broadcast( SbxHint( nHintId, pThisCopy ) );
2071 
2072         SbxFlagBits nSaveFlags = GetFlags();
2073         SetFlag( SbxFlagBits::ReadWrite );
2074         pSaveBroadcaster = std::move(mpBroadcaster);
2075         Put( pThisCopy->GetValues_Impl() );
2076         mpBroadcaster = std::move(pSaveBroadcaster);
2077         SetFlags( nSaveFlags );
2078     }
2079 }
2080 
2081 
2082 // Implementation of SbJScriptMethod (method class as a wrapper for JavaScript-functions)
2083 
2084 SbJScriptMethod::SbJScriptMethod( SbxDataType t )
2085         : SbMethod( "", t, nullptr )
2086 {
2087 }
2088 
2089 SbJScriptMethod::~SbJScriptMethod()
2090 {}
2091 
2092 
2093 SbObjModule::SbObjModule( const OUString& rName, const css::script::ModuleInfo& mInfo, bool bIsVbaCompatible )
2094     : SbModule( rName, bIsVbaCompatible )
2095 {
2096     SetModuleType( mInfo.ModuleType );
2097     if ( mInfo.ModuleType == script::ModuleType::FORM )
2098     {
2099         SetClassName( "Form" );
2100     }
2101     else if ( mInfo.ModuleObject.is() )
2102     {
2103         SetUnoObject( uno::Any( mInfo.ModuleObject ) );
2104     }
2105 }
2106 
2107 SbObjModule::~SbObjModule()
2108 {
2109 }
2110 
2111 void
2112 SbObjModule::SetUnoObject( const uno::Any& aObj )
2113 {
2114     SbUnoObject* pUnoObj = dynamic_cast<SbUnoObject*>( pDocObject.get() );
2115     if ( pUnoObj && pUnoObj->getUnoAny() == aObj ) // object is equal, nothing to do
2116         return;
2117     pDocObject = new SbUnoObject( GetName(), aObj );
2118 
2119     css::uno::Reference< css::lang::XServiceInfo > xServiceInfo( aObj, css::uno::UNO_QUERY_THROW );
2120     if( xServiceInfo->supportsService( "ooo.vba.excel.Worksheet" ) )
2121     {
2122         SetClassName( "Worksheet" );
2123     }
2124     else if( xServiceInfo->supportsService( "ooo.vba.excel.Workbook" ) )
2125     {
2126         SetClassName( "Workbook" );
2127     }
2128 }
2129 
2130 SbxVariable*
2131 SbObjModule::GetObject()
2132 {
2133     return pDocObject.get();
2134 }
2135 SbxVariable*
2136 SbObjModule::Find( const OUString& rName, SbxClassType t )
2137 {
2138     SbxVariable* pVar = nullptr;
2139     if ( pDocObject.get() )
2140         pVar = pDocObject->Find( rName, t );
2141     if ( !pVar )
2142         pVar = SbModule::Find( rName, t );
2143     return pVar;
2144 }
2145 
2146 void SbObjModule::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
2147 {
2148     SbModule::handleProcedureProperties( rBC, rHint );
2149 }
2150 
2151 
2152 typedef ::cppu::WeakImplHelper<
2153     awt::XTopWindowListener,
2154     awt::XWindowListener,
2155     document::XDocumentEventListener > FormObjEventListener_BASE;
2156 
2157 class FormObjEventListenerImpl:
2158     public FormObjEventListener_BASE
2159 {
2160     SbUserFormModule* mpUserForm;
2161     uno::Reference< lang::XComponent > mxComponent;
2162     uno::Reference< frame::XModel > mxModel;
2163     bool mbDisposed;
2164     bool mbOpened;
2165     bool mbActivated;
2166     bool mbShowing;
2167 
2168 public:
2169     FormObjEventListenerImpl(const FormObjEventListenerImpl&) = delete;
2170     const FormObjEventListenerImpl& operator=(const FormObjEventListenerImpl&) = delete;
2171     FormObjEventListenerImpl( SbUserFormModule* pUserForm, const uno::Reference< lang::XComponent >& xComponent, const uno::Reference< frame::XModel >& xModel ) :
2172         mpUserForm( pUserForm ), mxComponent( xComponent), mxModel( xModel ),
2173         mbDisposed( false ), mbOpened( false ), mbActivated( false ), mbShowing( false )
2174     {
2175         if ( mxComponent.is() )
2176         {
2177             try
2178             {
2179                 uno::Reference< awt::XTopWindow >( mxComponent, uno::UNO_QUERY_THROW )->addTopWindowListener( this );
2180             }
2181             catch(const uno::Exception& ) {}
2182             try
2183             {
2184                 uno::Reference< awt::XWindow >( mxComponent, uno::UNO_QUERY_THROW )->addWindowListener( this );
2185             }
2186             catch(const uno::Exception& ) {}
2187         }
2188 
2189         if ( mxModel.is() )
2190         {
2191             try
2192             {
2193                 uno::Reference< document::XDocumentEventBroadcaster >( mxModel, uno::UNO_QUERY_THROW )->addDocumentEventListener( this );
2194             }
2195             catch(const uno::Exception& ) {}
2196         }
2197     }
2198 
2199     virtual ~FormObjEventListenerImpl() override
2200     {
2201         removeListener();
2202     }
2203 
2204     bool isShowing() const { return mbShowing; }
2205 
2206     void removeListener()
2207     {
2208         if ( mxComponent.is() && !mbDisposed )
2209         {
2210             try
2211             {
2212                 uno::Reference< awt::XTopWindow >( mxComponent, uno::UNO_QUERY_THROW )->removeTopWindowListener( this );
2213             }
2214             catch(const uno::Exception& ) {}
2215             try
2216             {
2217                 uno::Reference< awt::XWindow >( mxComponent, uno::UNO_QUERY_THROW )->removeWindowListener( this );
2218             }
2219             catch(const uno::Exception& ) {}
2220         }
2221         mxComponent.clear();
2222 
2223         if ( mxModel.is() && !mbDisposed )
2224         {
2225             try
2226             {
2227                 uno::Reference< document::XDocumentEventBroadcaster >( mxModel, uno::UNO_QUERY_THROW )->removeDocumentEventListener( this );
2228             }
2229             catch(const uno::Exception& ) {}
2230         }
2231         mxModel.clear();
2232     }
2233 
2234     virtual void SAL_CALL windowOpened( const lang::EventObject& /*e*/ ) override
2235     {
2236         if ( mpUserForm )
2237         {
2238             mbOpened = true;
2239             mbShowing = true;
2240             if ( mbActivated )
2241             {
2242                 mbOpened = mbActivated = false;
2243                 mpUserForm->triggerActivateEvent();
2244             }
2245         }
2246     }
2247 
2248 
2249     virtual void SAL_CALL windowClosing( const lang::EventObject& /*e*/ ) override
2250     {
2251 #ifdef IN_THE_FUTURE
2252         uno::Reference< awt::XDialog > xDialog( e.Source, uno::UNO_QUERY );
2253         if ( xDialog.is() )
2254         {
2255             uno::Reference< awt::XControl > xControl( xDialog, uno::UNO_QUERY );
2256             if ( xControl->getPeer().is() )
2257             {
2258                 uno::Reference< document::XVbaMethodParameter > xVbaMethodParameter( xControl->getPeer(), uno::UNO_QUERY );
2259                 if ( xVbaMethodParameter.is() )
2260                 {
2261                     sal_Int8 nCancel = 0;
2262                     sal_Int8 nCloseMode = ::ooo::vba::VbQueryClose::vbFormControlMenu;
2263 
2264                     Sequence< Any > aParams;
2265                     aParams.realloc(2);
2266                     aParams[0] <<= nCancel;
2267                     aParams[1] <<= nCloseMode;
2268 
2269                     mpUserForm->triggerMethod( "Userform_QueryClose", aParams);
2270                     return;
2271 
2272                 }
2273             }
2274         }
2275 
2276         mpUserForm->triggerMethod( "Userform_QueryClose" );
2277 #endif
2278     }
2279 
2280 
2281     virtual void SAL_CALL windowClosed( const lang::EventObject& /*e*/ ) override
2282     {
2283         mbOpened = false;
2284         mbShowing = false;
2285     }
2286 
2287     virtual void SAL_CALL windowMinimized( const lang::EventObject& /*e*/ ) override
2288     {
2289     }
2290 
2291     virtual void SAL_CALL windowNormalized( const lang::EventObject& /*e*/ ) override
2292     {
2293     }
2294 
2295     virtual void SAL_CALL windowActivated( const lang::EventObject& /*e*/ ) override
2296     {
2297         if ( mpUserForm )
2298         {
2299             mbActivated = true;
2300             if ( mbOpened )
2301             {
2302                 mbOpened = mbActivated = false;
2303                 mpUserForm->triggerActivateEvent();
2304             }
2305         }
2306     }
2307 
2308     virtual void SAL_CALL windowDeactivated( const lang::EventObject& /*e*/ ) override
2309     {
2310         if ( mpUserForm )
2311             mpUserForm->triggerDeactivateEvent();
2312     }
2313 
2314     virtual void SAL_CALL windowResized( const awt::WindowEvent& /*e*/ ) override
2315     {
2316         if ( mpUserForm )
2317         {
2318             mpUserForm->triggerResizeEvent();
2319             mpUserForm->triggerLayoutEvent();
2320         }
2321     }
2322 
2323     virtual void SAL_CALL windowMoved( const awt::WindowEvent& /*e*/ ) override
2324     {
2325         if ( mpUserForm )
2326             mpUserForm->triggerLayoutEvent();
2327     }
2328 
2329     virtual void SAL_CALL windowShown( const lang::EventObject& /*e*/ ) override
2330     {
2331     }
2332 
2333     virtual void SAL_CALL windowHidden( const lang::EventObject& /*e*/ ) override
2334     {
2335     }
2336 
2337     virtual void SAL_CALL documentEventOccured( const document::DocumentEvent& rEvent ) override
2338     {
2339         // early disposing on document event "OnUnload", to be sure Basic still exists when calling VBA "UserForm_Terminate"
2340         if( rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::CLOSEDOC ) )
2341         {
2342             removeListener();
2343             mbDisposed = true;
2344             if ( mpUserForm )
2345                 mpUserForm->ResetApiObj();   // will trigger "UserForm_Terminate"
2346         }
2347     }
2348 
2349     virtual void SAL_CALL disposing( const lang::EventObject& /*Source*/ ) override
2350     {
2351         removeListener();
2352         mbDisposed = true;
2353         if ( mpUserForm )
2354             mpUserForm->ResetApiObj( false );   // pass false (too late to trigger VBA events here)
2355     }
2356 };
2357 
2358 SbUserFormModule::SbUserFormModule( const OUString& rName, const css::script::ModuleInfo& mInfo, bool bIsCompat )
2359     : SbObjModule( rName, mInfo, bIsCompat )
2360     , m_mInfo( mInfo )
2361     , mbInit( false )
2362 {
2363     m_xModel.set( mInfo.ModuleObject, uno::UNO_QUERY_THROW );
2364 }
2365 
2366 SbUserFormModule::~SbUserFormModule()
2367 {
2368 }
2369 
2370 void SbUserFormModule::ResetApiObj(  bool bTriggerTerminateEvent )
2371 {
2372     SAL_INFO("basic", " SbUserFormModule::ResetApiObj( " << (bTriggerTerminateEvent ? "true )" : "false )") );
2373     if ( bTriggerTerminateEvent && m_xDialog.is() ) // probably someone close the dialog window
2374     {
2375         triggerTerminateEvent();
2376     }
2377     pDocObject = nullptr;
2378     m_xDialog = nullptr;
2379 }
2380 
2381 void SbUserFormModule::triggerMethod( const OUString& aMethodToRun )
2382 {
2383     Sequence< Any > aArguments;
2384     triggerMethod( aMethodToRun, aArguments );
2385 }
2386 
2387 void SbUserFormModule::triggerMethod( const OUString& aMethodToRun, Sequence< Any >& aArguments )
2388 {
2389     SAL_INFO("basic", "trigger " << aMethodToRun);
2390     // Search method
2391     SbxVariable* pMeth = SbObjModule::Find( aMethodToRun, SbxClassType::Method );
2392     if( pMeth )
2393     {
2394         if ( aArguments.hasElements() )   // Setup parameters
2395         {
2396             auto xArray = tools::make_ref<SbxArray>();
2397             xArray->Put( pMeth, 0 );    // Method as parameter 0
2398 
2399             for ( sal_Int32 i = 0; i < aArguments.getLength(); ++i )
2400             {
2401                 auto xSbxVar = tools::make_ref<SbxVariable>( SbxVARIANT );
2402                 unoToSbxValue( xSbxVar.get(), aArguments[i] );
2403                 xArray->Put( xSbxVar.get(), static_cast< sal_uInt16 >( i ) + 1 );
2404 
2405                 // Enable passing by ref
2406                 if ( xSbxVar->GetType() != SbxVARIANT )
2407                     xSbxVar->SetFlag( SbxFlagBits::Fixed );
2408             }
2409             pMeth->SetParameters( xArray.get() );
2410 
2411             SbxValues aVals;
2412             pMeth->Get( aVals );
2413 
2414             for ( sal_Int32 i = 0; i < aArguments.getLength(); ++i )
2415             {
2416                 aArguments[i] = sbxToUnoValue( xArray->Get( static_cast< sal_uInt16 >(i) + 1) );
2417             }
2418             pMeth->SetParameters( nullptr );
2419         }
2420         else
2421         {
2422             SbxValues aVals;
2423             pMeth->Get( aVals );
2424         }
2425     }
2426 }
2427 
2428 void SbUserFormModule::triggerActivateEvent()
2429 {
2430     triggerMethod( "UserForm_Activate" );
2431 }
2432 
2433 void SbUserFormModule::triggerDeactivateEvent()
2434 {
2435     triggerMethod( "Userform_Deactivate" );
2436 }
2437 
2438 void SbUserFormModule::triggerInitializeEvent()
2439 {
2440     if ( mbInit )
2441         return;
2442     triggerMethod("Userform_Initialize");
2443     mbInit = true;
2444 }
2445 
2446 void SbUserFormModule::triggerTerminateEvent()
2447 {
2448     triggerMethod("Userform_Terminate");
2449     mbInit=false;
2450 }
2451 
2452 void SbUserFormModule::triggerLayoutEvent()
2453 {
2454     triggerMethod("Userform_Layout");
2455 }
2456 
2457 void SbUserFormModule::triggerResizeEvent()
2458 {
2459     triggerMethod("Userform_Resize");
2460 }
2461 
2462 SbUserFormModuleInstance* SbUserFormModule::CreateInstance()
2463 {
2464     SbUserFormModuleInstance* pInstance = new SbUserFormModuleInstance( this, GetName(), m_mInfo, IsVBACompat() );
2465     return pInstance;
2466 }
2467 
2468 SbUserFormModuleInstance::SbUserFormModuleInstance( SbUserFormModule* pParentModule,
2469     const OUString& rName, const css::script::ModuleInfo& mInfo, bool bIsVBACompat )
2470         : SbUserFormModule( rName, mInfo, bIsVBACompat )
2471         , m_pParentModule( pParentModule )
2472 {
2473 }
2474 
2475 bool SbUserFormModuleInstance::IsClass( const OUString& rName ) const
2476 {
2477     bool bParentNameMatches = m_pParentModule->GetName().equalsIgnoreAsciiCase( rName );
2478     bool bRet = bParentNameMatches || SbxObject::IsClass( rName );
2479     return bRet;
2480 }
2481 
2482 SbxVariable* SbUserFormModuleInstance::Find( const OUString& rName, SbxClassType t )
2483 {
2484     SbxVariable* pVar = m_pParentModule->Find( rName, t );
2485     return pVar;
2486 }
2487 
2488 
2489 void SbUserFormModule::Load()
2490 {
2491     // forces a load
2492     if ( !pDocObject.is() )
2493         InitObject();
2494 }
2495 
2496 
2497 void SbUserFormModule::Unload()
2498 {
2499     sal_Int8 nCancel = 0;
2500 
2501     Sequence< Any > aParams;
2502     aParams.realloc(2);
2503     aParams[0] <<= nCancel;
2504     aParams[1] <<= sal_Int8(::ooo::vba::VbQueryClose::vbFormCode);
2505 
2506     triggerMethod( "Userform_QueryClose", aParams);
2507 
2508     aParams[0] >>= nCancel;
2509     // basic boolean ( and what the user might use ) can be ambiguous ( e.g. basic true = -1 )
2510     // test against 0 ( false ) and assume anything else is true
2511     // ( Note: ) this used to work ( something changes somewhere )
2512     if (nCancel != 0)
2513     {
2514         return;
2515     }
2516 
2517     if ( m_xDialog.is() )
2518     {
2519         triggerTerminateEvent();
2520     }
2521     // Search method
2522     SbxVariable* pMeth = SbObjModule::Find( "UnloadObject", SbxClassType::Method );
2523     if( pMeth )
2524     {
2525         SAL_INFO("basic", "Attempting to run the UnloadObjectMethod");
2526         m_xDialog.clear(); //release ref to the uno object
2527         SbxValues aVals;
2528         bool bWaitForDispose = true; // assume dialog is showing
2529         if (m_DialogListener)
2530         {
2531             bWaitForDispose = m_DialogListener->isShowing();
2532             SAL_INFO("basic", "Showing " << bWaitForDispose );
2533         }
2534         pMeth->Get( aVals);
2535         if ( !bWaitForDispose )
2536         {
2537             // we've either already got a dispose or we are never going to get one
2538             ResetApiObj();
2539         } // else wait for dispose
2540         SAL_INFO("basic", "UnloadObject completed (we hope)");
2541     }
2542 }
2543 
2544 
2545 void SbUserFormModule::InitObject()
2546 {
2547     try
2548     {
2549         SbUnoObject* pGlobs = static_cast<SbUnoObject*>(GetParent()->Find( "VBAGlobals", SbxClassType::DontCare ));
2550         if ( m_xModel.is() && pGlobs )
2551         {
2552             // broadcast INITIALIZE_USERFORM script event before the dialog is created
2553             Reference< script::vba::XVBACompatibility > xVBACompat( getVBACompatibility( m_xModel ), uno::UNO_SET_THROW );
2554             xVBACompat->broadcastVBAScriptEvent( script::vba::VBAScriptEventId::INITIALIZE_USERFORM, GetName() );
2555             uno::Reference< lang::XMultiServiceFactory > xVBAFactory( pGlobs->getUnoAny(), uno::UNO_QUERY_THROW );
2556             uno::Reference< uno::XComponentContext > xContext = comphelper::getProcessComponentContext();
2557             OUString sDialogUrl( "vnd.sun.star.script:"  );
2558             OUString sProjectName( "Standard" );
2559 
2560             try
2561             {
2562                 Reference< beans::XPropertySet > xProps( m_xModel, UNO_QUERY_THROW );
2563                 uno::Reference< script::vba::XVBACompatibility > xVBAMode( xProps->getPropertyValue( "BasicLibraries" ), uno::UNO_QUERY_THROW );
2564                 sProjectName = xVBAMode->getProjectName();
2565             }
2566             catch(const Exception& ) {}
2567 
2568             sDialogUrl = sDialogUrl + sProjectName + "." + GetName() + "?location=document";
2569 
2570             uno::Reference< awt::XDialogProvider > xProvider = awt::DialogProvider::createWithModel( xContext, m_xModel  );
2571             m_xDialog = xProvider->createDialog( sDialogUrl );
2572 
2573             // create vba api object
2574             uno::Sequence< uno::Any > aArgs(4);
2575             aArgs[ 0 ] = uno::Any();
2576             aArgs[ 1 ] <<= m_xDialog;
2577             aArgs[ 2 ] <<= m_xModel;
2578             aArgs[ 3 ] <<= GetParent()->GetName();
2579             pDocObject = new SbUnoObject( GetName(), uno::Any( xVBAFactory->createInstanceWithArguments( "ooo.vba.msforms.UserForm", aArgs  ) ) );
2580 
2581             uno::Reference< lang::XComponent > xComponent( m_xDialog, uno::UNO_QUERY_THROW );
2582 
2583             // the dialog must be disposed at the end!
2584             StarBASIC* pParentBasic = nullptr;
2585             SbxObject* pCurObject = this;
2586             do
2587             {
2588                 SbxObject* pObjParent = pCurObject->GetParent();
2589                 pParentBasic = dynamic_cast<StarBASIC*>( pObjParent  );
2590                 pCurObject = pObjParent;
2591             }
2592             while( pParentBasic == nullptr && pCurObject != nullptr );
2593 
2594             SAL_WARN_IF( pParentBasic == nullptr, "basic", "pParentBasic == NULL" );
2595             registerComponentToBeDisposedForBasic( xComponent, pParentBasic );
2596 
2597             // if old listener object exists, remove it from dialog and document model
2598             if( m_DialogListener.is() )
2599                 m_DialogListener->removeListener();
2600             m_DialogListener.set( new FormObjEventListenerImpl( this, xComponent, m_xModel ) );
2601 
2602             triggerInitializeEvent();
2603         }
2604     }
2605     catch(const uno::Exception& )
2606     {
2607     }
2608 
2609 }
2610 
2611 SbxVariable*
2612 SbUserFormModule::Find( const OUString& rName, SbxClassType t )
2613 {
2614     if ( !pDocObject.is() && !GetSbData()->bRunInit && GetSbData()->pInst )
2615         InitObject();
2616     return SbObjModule::Find( rName, t );
2617 }
2618 
2619 SbProperty::SbProperty( const OUString& r, SbxDataType t, SbModule* p )
2620         : SbxProperty( r, t ), pMod( p )
2621 {
2622 }
2623 
2624 SbProperty::~SbProperty()
2625 {}
2626 
2627 
2628 SbProcedureProperty::~SbProcedureProperty()
2629 {}
2630 
2631 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
2632