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