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