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