tdf#130857 qt weld: Implement QtInstanceWidget::get_text_height
[LibreOffice.git] / basic / source / classes / sbxmod.cxx
blob6558050e1325e90b8fbe4cf848f70704277756b9
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <utility>
22 #include <vcl/svapp.hxx>
23 #include <tools/stream.hxx>
24 #include <comphelper/diagnose_ex.hxx>
25 #include <svl/SfxBroadcaster.hxx>
26 #include <basic/codecompletecache.hxx>
27 #include <basic/sbx.hxx>
28 #include <basic/sbuno.hxx>
29 #include <sbjsmeth.hxx>
30 #include <sbjsmod.hxx>
31 #include <sbintern.hxx>
32 #include <sbprop.hxx>
33 #include <image.hxx>
34 #include <opcodes.hxx>
35 #include <runtime.hxx>
36 #include <token.hxx>
37 #include <sbunoobj.hxx>
39 #include <sal/log.hxx>
41 #include <basic/sberrors.hxx>
42 #include <sbobjmod.hxx>
43 #include <basic/vbahelper.hxx>
44 #include <comphelper/sequence.hxx>
45 #include <cppuhelper/implbase.hxx>
46 #include <unotools/eventcfg.hxx>
47 #include <com/sun/star/lang/XServiceInfo.hpp>
48 #include <com/sun/star/script/ModuleType.hpp>
49 #include <com/sun/star/script/vba/XVBACompatibility.hpp>
50 #include <com/sun/star/script/vba/VBAScriptEventId.hpp>
51 #include <com/sun/star/beans/XPropertySet.hpp>
52 #include <com/sun/star/document/XDocumentEventBroadcaster.hpp>
53 #include <com/sun/star/document/XDocumentEventListener.hpp>
55 #ifdef UNX
56 #include <sys/resource.h>
57 #endif
59 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
60 #include <comphelper/processfactory.hxx>
61 #include <comphelper/asyncquithandler.hxx>
62 #include <map>
63 #include <com/sun/star/reflection/ProxyFactory.hpp>
64 #include <com/sun/star/uno/XAggregation.hpp>
65 #include <com/sun/star/script/XInvocation.hpp>
67 #include <com/sun/star/awt/DialogProvider.hpp>
68 #include <com/sun/star/awt/XTopWindow.hpp>
69 #include <com/sun/star/awt/XWindow.hpp>
70 #include <ooo/vba/VbQueryClose.hpp>
71 #include <memory>
72 #include <sbxmod.hxx>
73 #include <parser.hxx>
75 #include <limits>
77 using namespace com::sun::star;
78 using namespace com::sun::star::lang;
79 using namespace com::sun::star::reflection;
80 using namespace com::sun::star::beans;
81 using namespace com::sun::star::script;
82 using namespace com::sun::star::uno;
84 typedef ::cppu::WeakImplHelper< XInvocation > DocObjectWrapper_BASE;
85 typedef std::map< sal_Int16, Any > OutParamMap;
87 namespace {
89 class DocObjectWrapper : public DocObjectWrapper_BASE
91 Reference< XAggregation > m_xAggProxy;
92 Reference< XInvocation > m_xAggInv;
93 Reference< XTypeProvider > m_xAggregateTypeProv;
94 Sequence< Type > m_Types;
95 SbModule* m_pMod;
96 /// @throws css::uno::RuntimeException
97 SbMethodRef getMethod( const OUString& aName );
98 /// @throws css::uno::RuntimeException
99 SbPropertyRef getProperty( const OUString& aName );
101 public:
102 explicit DocObjectWrapper( SbModule* pMod );
104 virtual Sequence< sal_Int8 > SAL_CALL getImplementationId() override
106 return css::uno::Sequence<sal_Int8>();
109 virtual Reference< XIntrospectionAccess > SAL_CALL getIntrospection( ) override;
111 virtual Any SAL_CALL invoke( const OUString& aFunctionName, const Sequence< Any >& aParams, Sequence< ::sal_Int16 >& aOutParamIndex, Sequence< Any >& aOutParam ) override;
112 virtual void SAL_CALL setValue( const OUString& aPropertyName, const Any& aValue ) override;
113 virtual Any SAL_CALL getValue( const OUString& aPropertyName ) override;
114 virtual sal_Bool SAL_CALL hasMethod( const OUString& aName ) override;
115 virtual sal_Bool SAL_CALL hasProperty( const OUString& aName ) override;
116 virtual Any SAL_CALL queryInterface( const Type& aType ) override;
118 virtual Sequence< Type > SAL_CALL getTypes() override;
123 DocObjectWrapper::DocObjectWrapper( SbModule* pVar ) : m_pMod( pVar )
125 SbObjModule* pMod = dynamic_cast<SbObjModule*>( pVar );
126 if ( !pMod )
127 return;
129 if ( pMod->GetModuleType() != ModuleType::DOCUMENT )
130 return;
132 // Use proxy factory service to create aggregatable proxy.
133 SbUnoObject* pUnoObj = dynamic_cast<SbUnoObject*>( pMod->GetObject() );
134 Reference< XInterface > xIf;
135 if ( pUnoObj )
137 Any aObj = pUnoObj->getUnoAny();
138 aObj >>= xIf;
139 if ( xIf.is() )
141 m_xAggregateTypeProv.set( xIf, UNO_QUERY );
142 m_xAggInv.set( xIf, UNO_QUERY );
145 if ( xIf.is() )
149 Reference< XProxyFactory > xProxyFac = ProxyFactory::create( comphelper::getProcessComponentContext() );
150 m_xAggProxy = xProxyFac->createProxy( xIf );
152 catch(const Exception& )
154 TOOLS_WARN_EXCEPTION( "basic", "DocObjectWrapper::DocObjectWrapper" );
158 if ( !m_xAggProxy.is() )
159 return;
161 osl_atomic_increment( &m_refCount );
163 /* i35609 - Fix crash on Solaris. The setDelegator call needs
164 to be in its own block to ensure that all temporary Reference
165 instances that are acquired during the call are released
166 before m_refCount is decremented again */
168 m_xAggProxy->setDelegator( getXWeak() );
171 osl_atomic_decrement( &m_refCount );
174 Sequence< Type > SAL_CALL DocObjectWrapper::getTypes()
176 if ( !m_Types.hasElements() )
178 Sequence< Type > sTypes;
179 if ( m_xAggregateTypeProv.is() )
181 sTypes = m_xAggregateTypeProv->getTypes();
183 m_Types = comphelper::concatSequences(sTypes,
184 Sequence { cppu::UnoType<XInvocation>::get() });
186 return m_Types;
189 Reference< XIntrospectionAccess > SAL_CALL
190 DocObjectWrapper::getIntrospection( )
192 return nullptr;
195 Any SAL_CALL
196 DocObjectWrapper::invoke( const OUString& aFunctionName, const Sequence< Any >& aParams, Sequence< ::sal_Int16 >& aOutParamIndex, Sequence< Any >& aOutParam )
198 if ( m_xAggInv.is() && m_xAggInv->hasMethod( aFunctionName ) )
199 return m_xAggInv->invoke( aFunctionName, aParams, aOutParamIndex, aOutParam );
200 SbMethodRef pMethod = getMethod( aFunctionName );
201 if ( !pMethod.is() )
202 throw RuntimeException(u"DocObjectWrapper::invoke - Could not get the method reference!"_ustr);
203 // check number of parameters
204 sal_Int32 nParamsCount = aParams.getLength();
205 SbxInfo* pInfo = pMethod->GetInfo();
206 if ( pInfo )
208 sal_Int32 nSbxOptional = 0;
209 sal_uInt16 n = 1;
210 for ( const SbxParamInfo* pParamInfo = pInfo->GetParam( n ); pParamInfo; pParamInfo = pInfo->GetParam( ++n ) )
212 if ( pParamInfo->nFlags & SbxFlagBits::Optional )
213 ++nSbxOptional;
214 else
215 nSbxOptional = 0;
217 sal_Int32 nSbxCount = n - 1;
218 if ( nParamsCount < nSbxCount - nSbxOptional )
220 throw RuntimeException( u"wrong number of parameters!"_ustr );
223 // set parameters
224 SbxArrayRef xSbxParams;
225 if ( nParamsCount > 0 )
227 xSbxParams = new SbxArray;
228 const Any* pParams = aParams.getConstArray();
229 for ( sal_Int32 i = 0; i < nParamsCount; ++i )
231 SbxVariableRef xSbxVar = new SbxVariable( SbxVARIANT );
232 unoToSbxValue( xSbxVar.get(), pParams[i] );
233 xSbxParams->Put(xSbxVar.get(), static_cast<sal_uInt32>(i) + 1);
235 // Enable passing by ref
236 if ( xSbxVar->GetType() != SbxVARIANT )
237 xSbxVar->SetFlag( SbxFlagBits::Fixed );
240 if ( xSbxParams.is() )
241 pMethod->SetParameters( xSbxParams.get() );
243 // call method
244 SbxVariableRef xReturn = new SbxVariable;
246 pMethod->Call( xReturn.get() );
247 Any aReturn;
248 // get output parameters
249 if ( xSbxParams.is() )
251 SbxInfo* pInfo_ = pMethod->GetInfo();
252 if ( pInfo_ )
254 OutParamMap aOutParamMap;
255 for (sal_uInt32 n = 1, nCount = xSbxParams->Count(); n < nCount; ++n)
257 assert(n <= std::numeric_limits<sal_uInt16>::max());
258 const SbxParamInfo* pParamInfo = pInfo_->GetParam( sal::static_int_cast<sal_uInt16>(n) );
259 if ( pParamInfo && ( pParamInfo->eType & SbxBYREF ) != 0 )
261 SbxVariable* pVar = xSbxParams->Get(n);
262 if ( pVar )
264 SbxVariableRef xVar = pVar;
265 aOutParamMap.emplace( n - 1, sbxToUnoValue( xVar.get() ) );
269 sal_Int32 nOutParamCount = aOutParamMap.size();
270 aOutParamIndex.realloc( nOutParamCount );
271 aOutParam.realloc( nOutParamCount );
272 sal_Int16* pOutParamIndex = aOutParamIndex.getArray();
273 Any* pOutParam = aOutParam.getArray();
274 for (auto const& outParam : aOutParamMap)
276 *pOutParamIndex = outParam.first;
277 *pOutParam = outParam.second;
278 ++pOutParamIndex;
279 ++pOutParam;
284 // get return value
285 aReturn = sbxToUnoValue( xReturn.get() );
287 pMethod->SetParameters( nullptr );
289 return aReturn;
292 void SAL_CALL
293 DocObjectWrapper::setValue( const OUString& aPropertyName, const Any& aValue )
295 if ( m_xAggInv.is() && m_xAggInv->hasProperty( aPropertyName ) )
296 return m_xAggInv->setValue( aPropertyName, aValue );
298 SbPropertyRef pProperty = getProperty( aPropertyName );
299 if ( !pProperty.is() )
300 throw UnknownPropertyException(aPropertyName);
301 unoToSbxValue( pProperty.get(), aValue );
304 Any SAL_CALL
305 DocObjectWrapper::getValue( const OUString& aPropertyName )
307 if ( m_xAggInv.is() && m_xAggInv->hasProperty( aPropertyName ) )
308 return m_xAggInv->getValue( aPropertyName );
310 SbPropertyRef pProperty = getProperty( aPropertyName );
311 if ( !pProperty.is() )
312 throw UnknownPropertyException(aPropertyName);
314 SbxVariable* pProp = pProperty.get();
315 if ( pProp->GetType() == SbxEMPTY )
316 pProperty->Broadcast( SfxHintId::BasicDataWanted );
318 Any aRet = sbxToUnoValue( pProp );
319 return aRet;
322 sal_Bool SAL_CALL
323 DocObjectWrapper::hasMethod( const OUString& aName )
325 if ( m_xAggInv.is() && m_xAggInv->hasMethod( aName ) )
326 return true;
327 return getMethod( aName ).is();
330 sal_Bool SAL_CALL
331 DocObjectWrapper::hasProperty( const OUString& aName )
333 bool bRes = false;
334 if ( m_xAggInv.is() && m_xAggInv->hasProperty( aName ) )
335 bRes = true;
336 else bRes = getProperty( aName ).is();
337 return bRes;
340 Any SAL_CALL DocObjectWrapper::queryInterface( const Type& aType )
342 Any aRet = DocObjectWrapper_BASE::queryInterface( aType );
343 if ( aRet.hasValue() )
344 return aRet;
345 else if ( m_xAggProxy.is() )
346 aRet = m_xAggProxy->queryAggregation( aType );
347 return aRet;
350 SbMethodRef DocObjectWrapper::getMethod( const OUString& aName )
352 SbMethodRef pMethod;
353 if ( m_pMod )
355 SbxFlagBits nSaveFlgs = m_pMod->GetFlags();
356 // Limit search to this module
357 m_pMod->ResetFlag( SbxFlagBits::GlobalSearch );
358 pMethod = dynamic_cast<SbMethod*>(m_pMod->SbModule::Find(aName, SbxClassType::Method));
359 m_pMod->SetFlags( nSaveFlgs );
362 return pMethod;
365 SbPropertyRef DocObjectWrapper::getProperty( const OUString& aName )
367 SbPropertyRef pProperty;
368 if ( m_pMod )
370 SbxFlagBits nSaveFlgs = m_pMod->GetFlags();
371 // Limit search to this module.
372 m_pMod->ResetFlag( SbxFlagBits::GlobalSearch );
373 pProperty = dynamic_cast<SbProperty*>(m_pMod->SbModule::Find(aName, SbxClassType::Property));
374 m_pMod->SetFlag( nSaveFlgs );
377 return pProperty;
381 uno::Reference< frame::XModel > getDocumentModel( StarBASIC* pb )
383 uno::Reference< frame::XModel > xModel;
384 if( pb && pb->IsDocBasic() )
386 uno::Any aDoc;
387 if( pb->GetUNOConstant( u"ThisComponent"_ustr, aDoc ) )
388 xModel.set( aDoc, uno::UNO_QUERY );
390 return xModel;
393 static uno::Reference< vba::XVBACompatibility > getVBACompatibility( const uno::Reference< frame::XModel >& rxModel )
395 uno::Reference< vba::XVBACompatibility > xVBACompat;
398 uno::Reference< beans::XPropertySet > xModelProps( rxModel, uno::UNO_QUERY_THROW );
399 xVBACompat.set( xModelProps->getPropertyValue( u"BasicLibraries"_ustr ), uno::UNO_QUERY );
401 catch(const uno::Exception& )
404 return xVBACompat;
407 static bool getDefaultVBAMode( StarBASIC* pb )
409 uno::Reference< frame::XModel > xModel( getDocumentModel( pb ) );
410 if (!xModel.is())
411 return false;
412 uno::Reference< vba::XVBACompatibility > xVBACompat = getVBACompatibility( xModel );
413 return xVBACompat.is() && xVBACompat->getVBACompatibilityMode();
416 // A Basic module has set EXTSEARCH, so that the elements, that the module contains,
417 // could be found from other module.
419 SbModule::SbModule( const OUString& rName, bool bVBASupport )
420 : SbxObject( u"StarBASICModule"_ustr )
421 , mbVBASupport(bVBASupport), mbCompat(bVBASupport), bIsProxyModule(false)
423 SetName( rName );
424 SetFlag( SbxFlagBits::ExtSearch | SbxFlagBits::GlobalSearch );
425 SetModuleType( script::ModuleType::NORMAL );
427 // #i92642: Set name property to initial name
428 SbxVariable* pNameProp = pProps->Find( u"Name"_ustr, SbxClassType::Property );
429 if( pNameProp != nullptr )
431 pNameProp->PutString( GetName() );
435 SbModule::~SbModule()
437 SAL_INFO("basic","Module named " << GetName() << " is destructing");
438 pImage.reset();
439 pBreaks.reset();
440 pClassData.reset();
441 mxWrapper = nullptr;
444 uno::Reference< script::XInvocation > const &
445 SbModule::GetUnoModule()
447 if ( !mxWrapper.is() )
448 mxWrapper = new DocObjectWrapper( this );
450 SAL_INFO("basic","Module named " << GetName() << " returning wrapper mxWrapper (0x" << mxWrapper.get() <<")" );
451 return mxWrapper;
454 bool SbModule::IsCompiled() const
456 return pImage != nullptr;
459 const SbxObject* SbModule::FindType( const OUString& aTypeName ) const
461 return pImage ? pImage->FindType( aTypeName ) : nullptr;
465 // From the code generator: deletion of images and the opposite of validation for entries
467 void SbModule::StartDefinitions()
469 pImage.reset();
470 if( pClassData )
471 pClassData->clear();
473 // methods and properties persist, but they are invalid;
474 // at least are the information under certain conditions clogged
475 sal_uInt32 i;
476 for (i = 0; i < pMethods->Count(); i++)
478 SbMethod* p = dynamic_cast<SbMethod*>(pMethods->Get(i));
479 if( p )
480 p->bInvalid = true;
482 for (i = 0; i < pProps->Count();)
484 SbProperty* p = dynamic_cast<SbProperty*>(pProps->Get(i));
485 if( p )
486 pProps->Remove( i );
487 else
488 i++;
492 // request/create method
494 SbMethod* SbModule::GetMethod( const OUString& rName, SbxDataType t )
496 SbxVariable* p = pMethods->Find( rName, SbxClassType::Method );
497 SbMethod* pMeth = dynamic_cast<SbMethod*>( p );
498 if( p && !pMeth )
500 pMethods->Remove( p );
502 if( !pMeth )
504 pMeth = new SbMethod( rName, t, this );
505 pMeth->SetParent( this );
506 pMeth->SetFlags( SbxFlagBits::Read );
507 pMethods->Put(pMeth, pMethods->Count());
508 StartListening(pMeth->GetBroadcaster(), DuplicateHandling::Prevent);
510 // The method is per default valid, because it could be
511 // created from the compiler (code generator) as well.
512 pMeth->bInvalid = false;
513 pMeth->ResetFlag( SbxFlagBits::Fixed );
514 pMeth->SetFlag( SbxFlagBits::Write );
515 pMeth->SetType( t );
516 pMeth->ResetFlag( SbxFlagBits::Write );
517 if( t != SbxVARIANT )
519 pMeth->SetFlag( SbxFlagBits::Fixed );
521 return pMeth;
524 SbMethod* SbModule::FindMethod( const OUString& rName, SbxClassType t )
526 return dynamic_cast<SbMethod*> (pMethods->Find( rName, t ));
530 // request/create property
532 SbProperty* SbModule::GetProperty( const OUString& rName, SbxDataType t )
534 SbxVariable* p = pProps->Find( rName, SbxClassType::Property );
535 SbProperty* pProp = dynamic_cast<SbProperty*>( p );
536 if( p && !pProp )
538 pProps->Remove( p );
540 if( !pProp )
542 pProp = new SbProperty( rName, t, this );
543 pProp->SetFlag( SbxFlagBits::ReadWrite );
544 pProp->SetParent( this );
545 pProps->Put(pProp, pProps->Count());
546 StartListening(pProp->GetBroadcaster(), DuplicateHandling::Prevent);
548 return pProp;
551 void SbModule::GetProcedureProperty( const OUString& rName, SbxDataType t )
553 SbxVariable* p = pProps->Find( rName, SbxClassType::Property );
554 SbProcedureProperty* pProp = dynamic_cast<SbProcedureProperty*>( p );
555 if( p && !pProp )
557 pProps->Remove( p );
559 if( !pProp )
561 tools::SvRef<SbProcedureProperty> pNewProp = new SbProcedureProperty( rName, t );
562 pNewProp->SetFlag( SbxFlagBits::ReadWrite );
563 pNewProp->SetParent( this );
564 pProps->Put(pNewProp.get(), pProps->Count());
565 StartListening(pNewProp->GetBroadcaster(), DuplicateHandling::Prevent);
569 void SbModule::GetIfaceMapperMethod( const OUString& rName, SbMethod* pImplMeth )
571 SbxVariable* p = pMethods->Find( rName, SbxClassType::Method );
572 SbIfaceMapperMethod* pMapperMethod = dynamic_cast<SbIfaceMapperMethod*>( p );
573 if( p && !pMapperMethod )
575 pMethods->Remove( p );
577 if( !pMapperMethod )
579 pMapperMethod = new SbIfaceMapperMethod( rName, pImplMeth );
580 pMapperMethod->SetParent( this );
581 pMapperMethod->SetFlags( SbxFlagBits::Read );
582 pMethods->Put(pMapperMethod, pMethods->Count());
584 pMapperMethod->bInvalid = false;
587 SbIfaceMapperMethod::~SbIfaceMapperMethod()
592 // From the code generator: remove invalid entries
594 void SbModule::EndDefinitions( bool bNewState )
596 for (sal_uInt32 i = 0; i < pMethods->Count();)
598 SbMethod* p = dynamic_cast<SbMethod*>(pMethods->Get(i));
599 if( p )
601 if( p->bInvalid )
603 pMethods->Remove( p );
605 else
607 p->bInvalid = bNewState;
608 i++;
611 else
612 i++;
614 SetModified( true );
617 void SbModule::Clear()
619 pImage.reset();
620 if( pClassData )
621 pClassData->clear();
622 SbxObject::Clear();
626 SbxVariable* SbModule::Find( const OUString& rName, SbxClassType t )
628 // make sure a search in an uninstantiated class module will fail
629 SbxVariable* pRes = SbxObject::Find( rName, t );
630 if ( bIsProxyModule && !GetSbData()->bRunInit )
632 return nullptr;
634 if( !pRes && pImage )
636 SbiInstance* pInst = GetSbData()->pInst;
637 if( pInst && pInst->IsCompatibility() )
639 // Put enum types as objects into module,
640 // allows MyEnum.First notation
641 SbxArrayRef xArray = pImage->GetEnums();
642 if( xArray.is() )
644 SbxVariable* pEnumVar = xArray->Find( rName, SbxClassType::DontCare );
645 SbxObject* pEnumObject = dynamic_cast<SbxObject*>( pEnumVar );
646 if( pEnumObject )
648 bool bPrivate = pEnumObject->IsSet( SbxFlagBits::Private );
649 OUString aEnumName = pEnumObject->GetName();
651 pRes = new SbxVariable( SbxOBJECT );
652 pRes->SetName( aEnumName );
653 pRes->SetParent( this );
654 pRes->SetFlag( SbxFlagBits::Read );
655 if( bPrivate )
657 pRes->SetFlag( SbxFlagBits::Private );
659 pRes->PutObject( pEnumObject );
664 return pRes;
667 // Parent and BASIC are one!
669 void SbModule::SetParent( SbxObject* p )
671 pParent = p;
674 void SbModule::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
676 const SbxHint* pHint = dynamic_cast<const SbxHint*>(&rHint);
677 if( !pHint )
678 return;
680 SbxVariable* pVar = pHint->GetVar();
681 SbProperty* pProp = dynamic_cast<SbProperty*>( pVar );
682 SbMethod* pMeth = dynamic_cast<SbMethod*>( pVar );
683 SbProcedureProperty* pProcProperty = dynamic_cast<SbProcedureProperty*>( pVar );
684 if( pProcProperty )
687 if( pHint->GetId() == SfxHintId::BasicDataWanted )
689 OUString aProcName = "Property Get "
690 + pProcProperty->GetName();
692 SbxVariable* pMethVar = Find( aProcName, SbxClassType::Method );
693 if( pMethVar )
695 SbxValues aVals;
696 aVals.eType = SbxVARIANT;
698 SbxArray* pArg = pVar->GetParameters();
699 sal_uInt32 nVarParCount = (pArg != nullptr) ? pArg->Count() : 0;
700 if( nVarParCount > 1 )
702 auto xMethParameters = tools::make_ref<SbxArray>();
703 xMethParameters->Put(pMethVar, 0); // Method as parameter 0
704 for( sal_uInt32 i = 1 ; i < nVarParCount ; ++i )
706 SbxVariable* pPar = pArg->Get(i);
707 xMethParameters->Put(pPar, i);
710 pMethVar->SetParameters( xMethParameters.get() );
711 pMethVar->Get( aVals );
712 pMethVar->SetParameters( nullptr );
714 else
716 pMethVar->Get( aVals );
719 pVar->Put( aVals );
722 else if( pHint->GetId() == SfxHintId::BasicDataChanged )
724 SbxVariable* pMethVar = nullptr;
726 bool bSet = pProcProperty->isSet();
727 if( bSet )
729 pProcProperty->setSet( false );
731 OUString aProcName = "Property Set "
732 + pProcProperty->GetName();
733 pMethVar = Find( aProcName, SbxClassType::Method );
735 if( !pMethVar ) // Let
737 OUString aProcName = "Property Let "
738 + pProcProperty->GetName();
739 pMethVar = Find( aProcName, SbxClassType::Method );
742 if( pMethVar )
744 // Setup parameters
745 SbxArrayRef xArray = new SbxArray;
746 xArray->Put(pMethVar, 0); // Method as parameter 0
747 xArray->Put(pVar, 1);
748 pMethVar->SetParameters( xArray.get() );
750 SbxValues aVals;
751 pMethVar->Get( aVals );
752 pMethVar->SetParameters( nullptr );
756 if( pProp )
758 if( pProp->GetModule() != this )
759 SetError( ERRCODE_BASIC_BAD_ACTION );
761 else if( pMeth )
763 if( pHint->GetId() == SfxHintId::BasicDataWanted )
765 if( pMeth->bInvalid && !Compile() )
767 // auto compile has not worked!
768 StarBASIC::Error( ERRCODE_BASIC_BAD_PROP_VALUE );
770 else
772 // Call of a subprogram
773 SbModule* pOld = GetSbData()->pMod;
774 GetSbData()->pMod = this;
775 Run( static_cast<SbMethod*>(pVar) );
776 GetSbData()->pMod = pOld;
780 else
782 // #i92642: Special handling for name property to avoid
783 // side effects when using name as variable implicitly
784 bool bForwardToSbxObject = true;
786 const SfxHintId nId = pHint->GetId();
787 if( (nId == SfxHintId::BasicDataWanted || nId == SfxHintId::BasicDataChanged) &&
788 pVar->GetName().equalsIgnoreAsciiCase( "name" ) )
790 bForwardToSbxObject = false;
792 if( bForwardToSbxObject )
794 SbxObject::Notify( rBC, rHint );
799 // The setting of the source makes the image invalid
800 // and scans the method definitions newly in
802 void SbModule::SetSource32( const OUString& r )
804 // Default basic mode to library container mode, but... allow Option VBASupport 0/1 override
805 SetVBASupport( getDefaultVBAMode( static_cast< StarBASIC*>( GetParent() ) ) );
806 aOUSource = r;
807 StartDefinitions();
808 SbiTokenizer aTok( r );
809 aTok.SetCompatible( IsVBASupport() );
811 while( !aTok.IsEof() )
813 SbiToken eEndTok = NIL;
815 // Searching for SUB or FUNCTION
816 SbiToken eLastTok = NIL;
817 while( !aTok.IsEof() )
819 // #32385: not by declare
820 SbiToken eCurTok = aTok.Next();
821 if( eLastTok != DECLARE )
823 if( eCurTok == SUB )
825 eEndTok = ENDSUB; break;
827 if( eCurTok == FUNCTION )
829 eEndTok = ENDFUNC; break;
831 if( eCurTok == PROPERTY )
833 eEndTok = ENDPROPERTY; break;
835 if( eCurTok == OPTION )
837 eCurTok = aTok.Next();
838 if( eCurTok == COMPATIBLE )
840 mbCompat = true;
841 aTok.SetCompatible( true );
843 else if ( ( eCurTok == VBASUPPORT ) && ( aTok.Next() == NUMBER ) )
845 bool bIsVBA = ( aTok.GetDbl()== 1 );
846 SetVBASupport( bIsVBA );
847 aTok.SetCompatible( bIsVBA );
851 eLastTok = eCurTok;
853 // Definition of the method
854 SbMethod* pMeth = nullptr;
855 if( eEndTok != NIL )
857 sal_uInt16 nLine1 = aTok.GetLine();
858 if( aTok.Next() == SYMBOL )
860 const OUString& rName_( aTok.GetSym() );
861 SbxDataType t = aTok.GetType();
862 if( t == SbxVARIANT && eEndTok == ENDSUB )
864 t = SbxVOID;
866 pMeth = GetMethod( rName_, t );
867 pMeth->nLine1 = pMeth->nLine2 = nLine1;
868 // The method is for a start VALID
869 pMeth->bInvalid = false;
871 else
873 eEndTok = NIL;
876 // Skip up to END SUB/END FUNCTION
877 if( eEndTok != NIL )
879 while( !aTok.IsEof() )
881 if( aTok.Next() == eEndTok )
883 pMeth->nLine2 = aTok.GetLine();
884 break;
887 if( aTok.IsEof() )
889 pMeth->nLine2 = aTok.GetLine();
893 EndDefinitions( true );
896 // Broadcast of a hint to all Basics
898 static void SendHint_( SbxObject* pObj, SfxHintId nId, SbMethod* p )
900 // Self a BASIC?
901 if( dynamic_cast<const StarBASIC *>(pObj) != nullptr && pObj->IsBroadcaster() )
902 pObj->GetBroadcaster().Broadcast( SbxHint( nId, p ) );
903 // Then ask for the subobjects
904 SbxArray* pObjs = pObj->GetObjects();
905 for (sal_uInt32 i = 0; i < pObjs->Count(); i++)
907 SbxVariable* pVar = pObjs->Get(i);
908 if( dynamic_cast<const SbxObject *>(pVar) != nullptr )
909 SendHint_( dynamic_cast<SbxObject*>( pVar), nId, p );
913 static void SendHint( SbxObject* pObj, SfxHintId nId, SbMethod* p )
915 while( pObj->GetParent() )
916 pObj = pObj->GetParent();
917 SendHint_( pObj, nId, p );
920 // #57841 Clear Uno-Objects, which were held in RTL functions,
921 // at the end of the program, so that nothing is held
922 static void ClearUnoObjectsInRTL_Impl_Rek( StarBASIC* pBasic )
924 // delete the return value of CreateUnoService
925 SbxVariable* pVar = pBasic->GetRtl()->Find( u"CreateUnoService"_ustr, SbxClassType::Method );
926 if( pVar )
928 pVar->SbxValue::Clear();
930 // delete the return value of CreateUnoDialog
931 pVar = pBasic->GetRtl()->Find( u"CreateUnoDialog"_ustr, SbxClassType::Method );
932 if( pVar )
934 pVar->SbxValue::Clear();
936 // delete the return value of CDec
937 pVar = pBasic->GetRtl()->Find( u"CDec"_ustr, SbxClassType::Method );
938 if( pVar )
940 pVar->SbxValue::Clear();
942 // delete return value of CreateObject
943 pVar = pBasic->GetRtl()->Find( u"CreateObject"_ustr, SbxClassType::Method );
944 if( pVar )
946 pVar->SbxValue::Clear();
948 // Go over all Sub-Basics
949 SbxArray* pObjs = pBasic->GetObjects();
950 sal_uInt32 nCount = pObjs->Count();
951 for( sal_uInt32 i = 0 ; i < nCount ; i++ )
953 SbxVariable* pObjVar = pObjs->Get(i);
954 StarBASIC* pSubBasic = dynamic_cast<StarBASIC*>( pObjVar );
955 if( pSubBasic )
957 ClearUnoObjectsInRTL_Impl_Rek( pSubBasic );
962 static void ClearUnoObjectsInRTL_Impl( StarBASIC* pBasic )
964 // #67781 Delete return values of the Uno-methods
965 clearUnoMethods();
967 ClearUnoObjectsInRTL_Impl_Rek( pBasic );
969 // Search for the topmost Basic
970 SbxObject* p = pBasic;
971 while( p->GetParent() )
972 p = p->GetParent();
973 if( static_cast<StarBASIC*>(p) != pBasic )
974 ClearUnoObjectsInRTL_Impl_Rek( static_cast<StarBASIC*>(p) );
978 void SbModule::SetVBASupport( bool bSupport )
980 if( mbVBASupport == bSupport )
981 return;
983 mbVBASupport = bSupport;
984 // initialize VBA document API
985 if( mbVBASupport ) try
987 mbCompat = true;
988 StarBASIC* pBasic = static_cast< StarBASIC* >( GetParent() );
989 uno::Reference< lang::XMultiServiceFactory > xFactory( getDocumentModel( pBasic ), uno::UNO_QUERY_THROW );
990 xFactory->createInstance( u"ooo.vba.VBAGlobals"_ustr );
992 catch( Exception& )
997 namespace
999 class RunInitGuard
1001 protected:
1002 std::unique_ptr<SbiRuntime> m_xRt;
1003 SbiGlobals* m_pSbData;
1004 SbModule* m_pOldMod;
1005 public:
1006 RunInitGuard(SbModule* pModule, SbMethod* pMethod, sal_uInt32 nArg, SbiGlobals* pSbData)
1007 : m_xRt(new SbiRuntime(pModule, pMethod, nArg))
1008 , m_pSbData(pSbData)
1009 , m_pOldMod(pSbData->pMod)
1011 m_xRt->pNext = pSbData->pInst->pRun;
1012 m_pSbData->pMod = pModule;
1013 m_pSbData->pInst->pRun = m_xRt.get();
1015 void run()
1017 while (m_xRt->Step()) {}
1019 virtual ~RunInitGuard()
1021 m_pSbData->pInst->pRun = m_xRt->pNext;
1022 m_pSbData->pMod = m_pOldMod;
1023 m_xRt.reset();
1027 class RunGuard : public RunInitGuard
1029 private:
1030 bool m_bDelInst;
1031 public:
1032 RunGuard(SbModule* pModule, SbMethod* pMethod, sal_uInt32 nArg, SbiGlobals* pSbData, bool bDelInst)
1033 : RunInitGuard(pModule, pMethod, nArg, pSbData)
1034 , m_bDelInst(bDelInst)
1036 if (m_xRt->pNext)
1037 m_xRt->pNext->block();
1039 virtual ~RunGuard() override
1041 if (m_xRt->pNext)
1042 m_xRt->pNext->unblock();
1044 // #63710 It can happen by an another thread handling at events,
1045 // that the show call returns to a dialog (by closing the
1046 // dialog per UI), before a by an event triggered further call returned,
1047 // which stands in Basic more top in the stack and that had been run on
1048 // a Basic-Breakpoint. Then would the instance below destroyed. And if the Basic,
1049 // that stand still in the call, further runs, there is a GPF.
1050 // Thus here had to be wait until the other call comes back.
1051 if (m_bDelInst)
1053 // Compare here with 1 instead of 0, because before nCallLvl--
1054 while (m_pSbData->pInst->nCallLvl != 1 && !Application::IsQuit())
1055 Application::Yield();
1058 m_pSbData->pInst->nCallLvl--; // Call-Level down again
1060 // Exist an higher-ranking runtime instance?
1061 // Then take over BasicDebugFlags::Break, if set
1062 SbiRuntime* pRtNext = m_xRt->pNext;
1063 if (pRtNext && (m_xRt->GetDebugFlags() & BasicDebugFlags::Break))
1064 pRtNext->SetDebugFlags(BasicDebugFlags::Break);
1069 // Run a Basic-subprogram
1070 void SbModule::Run( SbMethod* pMeth )
1072 SAL_INFO("basic","About to run " << pMeth->GetName() << ", vba compatmode is " << mbVBASupport );
1074 static sal_uInt16 nMaxCallLevel = 0;
1076 SbiGlobals* pSbData = GetSbData();
1078 bool bDelInst = pSbData->pInst == nullptr;
1079 bool bQuit = false;
1080 StarBASICRef xBasic;
1081 uno::Reference< frame::XModel > xModel;
1082 uno::Reference< script::vba::XVBACompatibility > xVBACompat;
1083 if( bDelInst )
1085 // #32779: Hold Basic during the execution
1086 xBasic = static_cast<StarBASIC*>( GetParent() );
1088 pSbData->pInst = new SbiInstance( static_cast<StarBASIC*>(GetParent()) );
1090 /* If a VBA script in a document is started, get the VBA compatibility
1091 interface from the document Basic library container, and notify all
1092 VBA script listeners about the started script. */
1093 if( mbVBASupport )
1095 StarBASIC* pBasic = static_cast< StarBASIC* >( GetParent() );
1096 if( pBasic && pBasic->IsDocBasic() ) try
1098 xModel.set( getDocumentModel( pBasic ), uno::UNO_SET_THROW );
1099 xVBACompat.set( getVBACompatibility( xModel ), uno::UNO_SET_THROW );
1100 xVBACompat->broadcastVBAScriptEvent( script::vba::VBAScriptEventId::SCRIPT_STARTED, GetName() );
1102 catch(const uno::Exception& )
1107 // Launcher problem
1108 // i80726 The Find below will generate an error in Testtool so we reset it unless there was one before already
1109 bool bWasError = SbxBase::GetError() != ERRCODE_NONE;
1110 SbxVariable* pMSOMacroRuntimeLibVar = Find( u"Launcher"_ustr, SbxClassType::Object );
1111 if ( !bWasError && (SbxBase::GetError() == ERRCODE_BASIC_PROC_UNDEFINED) )
1112 SbxBase::ResetError();
1113 if( pMSOMacroRuntimeLibVar )
1115 StarBASIC* pMSOMacroRuntimeLib = dynamic_cast<StarBASIC*>( pMSOMacroRuntimeLibVar );
1116 if( pMSOMacroRuntimeLib )
1118 SbxFlagBits nGblFlag = pMSOMacroRuntimeLib->GetFlags() & SbxFlagBits::GlobalSearch;
1119 pMSOMacroRuntimeLib->ResetFlag( SbxFlagBits::GlobalSearch );
1120 SbxVariable* pAppSymbol = pMSOMacroRuntimeLib->Find( u"Application"_ustr, SbxClassType::Method );
1121 pMSOMacroRuntimeLib->SetFlag( nGblFlag );
1122 if( pAppSymbol )
1124 pMSOMacroRuntimeLib->SetFlag( SbxFlagBits::ExtSearch ); // Could have been disabled before
1125 pSbData->pMSOMacroRuntimLib = pMSOMacroRuntimeLib;
1130 if( nMaxCallLevel == 0 )
1132 #ifdef UNX
1133 struct rlimit rl;
1134 getrlimit ( RLIMIT_STACK, &rl );
1135 #endif
1136 #if defined LINUX
1137 // Empiric value, 900 = needed bytes/Basic call level
1138 // for Linux including 10% safety margin
1139 nMaxCallLevel = rl.rlim_cur / 900;
1140 #elif defined __sun
1141 // Empiric value, 1650 = needed bytes/Basic call level
1142 // for Solaris including 10% safety margin
1143 nMaxCallLevel = rl.rlim_cur / 1650;
1144 #elif defined _WIN32
1145 nMaxCallLevel = 5800;
1146 #else
1147 nMaxCallLevel = MAXRECURSION;
1148 #endif
1152 // Recursion to deep?
1153 if( ++pSbData->pInst->nCallLvl <= nMaxCallLevel )
1155 // Define a globale variable in all Mods
1156 GlobalRunInit( /* bBasicStart = */ bDelInst );
1158 // Appeared a compiler error? Then we don't launch
1159 if( !pSbData->bGlobalInitErr )
1161 if( bDelInst )
1163 SendHint( GetParent(), SfxHintId::BasicStart, pMeth );
1165 // 1996-10-16: #31460 New concept for StepInto/Over/Out
1166 // For an explanation see runtime.cxx at SbiInstance::CalcBreakCallLevel()
1167 // Identify the BreakCallLevel
1168 pSbData->pInst->CalcBreakCallLevel( pMeth->GetDebugFlags() );
1172 RunGuard xRuntimeGuard(this, pMeth, pMeth->nStart, pSbData, bDelInst);
1174 if (mbVBASupport)
1175 pSbData->pInst->EnableCompatibility(true);
1177 xRuntimeGuard.run();
1180 if( bDelInst )
1182 // #57841 Clear Uno-Objects, which were held in RTL functions,
1183 // at the end of the program, so that nothing is held.
1184 ClearUnoObjectsInRTL_Impl( xBasic.get() );
1186 clearNativeObjectWrapperVector();
1188 SAL_WARN_IF(pSbData->pInst->nCallLvl != 0,"basic","BASIC-Call-Level > 0");
1189 delete pSbData->pInst;
1190 pSbData->pInst = nullptr;
1191 bDelInst = false;
1193 // #i30690
1194 SolarMutexGuard aSolarGuard;
1195 SendHint( GetParent(), SfxHintId::BasicStop, pMeth );
1197 GlobalRunDeInit();
1199 if( xVBACompat.is() )
1201 // notify all VBA script listeners about the stopped script
1204 xVBACompat->broadcastVBAScriptEvent( script::vba::VBAScriptEventId::SCRIPT_STOPPED, GetName() );
1206 catch(const uno::Exception& )
1209 // VBA always ensures screenupdating is enabled after completing
1210 ::basic::vba::lockControllersOfAllDocuments( xModel, false );
1211 ::basic::vba::enableContainerWindowsOfAllDocuments( xModel, true );
1215 else
1216 pSbData->pInst->nCallLvl--; // Call-Level down again
1218 else
1220 pSbData->pInst->nCallLvl--; // Call-Level down again
1221 StarBASIC::FatalError( ERRCODE_BASIC_STACK_OVERFLOW );
1224 StarBASIC* pBasic = dynamic_cast<StarBASIC*>( GetParent() );
1225 if( bDelInst )
1227 // #57841 Clear Uno-Objects, which were held in RTL functions,
1228 // the end of the program, so that nothing is held.
1229 ClearUnoObjectsInRTL_Impl( xBasic.get() );
1231 delete pSbData->pInst;
1232 pSbData->pInst = nullptr;
1234 if ( pBasic && pBasic->IsDocBasic() && pBasic->IsQuitApplication() && !pSbData->pInst )
1235 bQuit = true;
1236 if ( bQuit )
1238 Application::PostUserEvent( LINK( &AsyncQuitHandler::instance(), AsyncQuitHandler, OnAsyncQuit ) );
1242 // Execute of the init method of a module after the loading
1243 // or the compilation
1244 void SbModule::RunInit()
1246 if( !(pImage
1247 && !pImage->bInit
1248 && pImage->IsFlag( SbiImageFlags::INITCODE )) )
1249 return;
1251 SbiGlobals* pSbData = GetSbData();
1253 // Set flag, so that RunInit get active (Testtool)
1254 pSbData->bRunInit = true;
1256 // The init code starts always here
1257 RunInitGuard(this, nullptr, 0, pSbData).run();
1259 pImage->bInit = true;
1260 pImage->bFirstInit = false;
1262 // RunInit is not active anymore
1263 pSbData->bRunInit = false;
1266 // Delete with private/dim declared variables
1268 void SbModule::AddVarName( const OUString& aName )
1270 // see if the name is added already
1271 for ( const auto& rModuleVariableName: mModuleVariableNames )
1273 if ( aName == rModuleVariableName )
1274 return;
1276 mModuleVariableNames.push_back( aName );
1279 void SbModule::RemoveVars()
1281 for ( const auto& rModuleVariableName: mModuleVariableNames )
1283 // We don't want a Find being called in a derived class ( e.g.
1284 // SbUserform because it could trigger say an initialise event
1285 // 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 )
1286 SbxVariableRef p = SbModule::Find( rModuleVariableName, SbxClassType::Property );
1287 if( p.is() )
1288 Remove( p.get() );
1292 void SbModule::ClearPrivateVars()
1294 for (sal_uInt32 i = 0; i < pProps->Count(); i++)
1296 SbProperty* p = dynamic_cast<SbProperty*>(pProps->Get(i));
1297 if( p )
1299 // Delete not the arrays, only their content
1300 if( p->GetType() & SbxARRAY )
1302 SbxArray* pArray = dynamic_cast<SbxArray*>( p->GetObject() );
1303 if( pArray )
1305 for (sal_uInt32 j = 0; j < pArray->Count(); j++)
1307 SbxVariable* pj = pArray->Get(j);
1308 pj->SbxValue::Clear();
1312 else
1314 p->SbxValue::Clear();
1320 void SbModule::implClearIfVarDependsOnDeletedBasic(SbxVariable& rVar, StarBASIC* pDeletedBasic)
1322 if (rVar.SbxValue::GetType() != SbxOBJECT || dynamic_cast<const SbProcedureProperty*>(&rVar) != nullptr)
1323 return;
1325 SbxObject* pObj = dynamic_cast<SbxObject*>(rVar.GetObject());
1326 if( pObj == nullptr )
1327 return;
1329 SbxObject* p = pObj;
1331 SbModule* pMod = dynamic_cast<SbModule*>( p );
1332 if( pMod != nullptr )
1333 pMod->ClearVarsDependingOnDeletedBasic( pDeletedBasic );
1335 while( (p = p->GetParent()) != nullptr )
1337 StarBASIC* pBasic = dynamic_cast<StarBASIC*>( p );
1338 if( pBasic != nullptr && pBasic == pDeletedBasic )
1340 rVar.SbxValue::Clear();
1341 break;
1346 void SbModule::ClearVarsDependingOnDeletedBasic( StarBASIC* pDeletedBasic )
1348 for (sal_uInt32 i = 0; i < pProps->Count(); i++)
1350 SbProperty* p = dynamic_cast<SbProperty*>(pProps->Get(i));
1351 if( p )
1353 if( p->GetType() & SbxARRAY )
1355 SbxArray* pArray = dynamic_cast<SbxArray*>( p->GetObject() );
1356 if( pArray )
1358 for (sal_uInt32 j = 0; j < pArray->Count(); j++)
1360 SbxVariable* pVar = pArray->Get(j);
1361 implClearIfVarDependsOnDeletedBasic(*pVar, pDeletedBasic);
1365 else
1367 implClearIfVarDependsOnDeletedBasic(*p, pDeletedBasic);
1373 void StarBASIC::ClearAllModuleVars()
1375 // Initialise the own module
1376 for (const auto& rModule: pModules)
1378 // Initialise only, if the startcode was already executed
1379 if( rModule->pImage && rModule->pImage->bInit && !rModule->isProxyModule() && dynamic_cast<const SbObjModule*>( rModule.get()) == nullptr )
1380 rModule->ClearPrivateVars();
1385 // Execution of the init-code of all module
1386 void SbModule::GlobalRunInit( bool bBasicStart )
1388 // If no Basic-Start, only initialise, if the module is not initialised
1389 if( !bBasicStart )
1390 if( !pImage || pImage->bInit )
1391 return;
1393 // Initialise GlobalInitErr-Flag for Compiler-Error
1394 // With the help of this flags could be located in SbModule::Run() after the call of
1395 // GlobalRunInit, if at the initialising of the module
1396 // an error occurred. Then it will not be launched.
1397 GetSbData()->bGlobalInitErr = false;
1399 // Parent of the module is a Basic
1400 StarBASIC *pBasic = dynamic_cast<StarBASIC*>( GetParent() );
1401 if( !pBasic )
1402 return;
1404 pBasic->InitAllModules();
1406 SbxObject* pParent_ = pBasic->GetParent();
1407 if( !pParent_ )
1408 return;
1410 StarBASIC * pParentBasic = dynamic_cast<StarBASIC*>( pParent_ );
1411 if( !pParentBasic )
1412 return;
1414 pParentBasic->InitAllModules( pBasic );
1416 // #109018 Parent can also have a parent (library in doc)
1417 SbxObject* pParentParent = pParentBasic->GetParent();
1418 if( pParentParent )
1420 StarBASIC * pParentParentBasic = dynamic_cast<StarBASIC*>( pParentParent );
1421 if( pParentParentBasic )
1422 pParentParentBasic->InitAllModules( pParentBasic );
1426 void SbModule::GlobalRunDeInit()
1428 StarBASIC *pBasic = dynamic_cast<StarBASIC*>( GetParent() );
1429 if( pBasic )
1431 pBasic->DeInitAllModules();
1433 SbxObject* pParent_ = pBasic->GetParent();
1434 if( pParent_ )
1435 pBasic = dynamic_cast<StarBASIC*>( pParent_ );
1436 if( pBasic )
1437 pBasic->DeInitAllModules();
1441 // Search for the next STMNT-Command in the code. This was used from the STMNT-
1442 // Opcode to set the endcolumn.
1444 const sal_uInt8* SbModule::FindNextStmnt( const sal_uInt8* p, sal_uInt16& nLine, sal_uInt16& nCol ) const
1446 return FindNextStmnt( p, nLine, nCol, false );
1449 const sal_uInt8* SbModule::FindNextStmnt( const sal_uInt8* p, sal_uInt16& nLine, sal_uInt16& nCol,
1450 bool bFollowJumps, const SbiImage* pImg ) const
1452 sal_uInt32 nPC = static_cast<sal_uInt32>( p - pImage->GetCode() );
1453 while( nPC < pImage->GetCodeSize() )
1455 SbiOpcode eOp = static_cast<SbiOpcode>( *p++ );
1456 nPC++;
1457 if( bFollowJumps && eOp == SbiOpcode::JUMP_ && pImg )
1459 SAL_WARN_IF( !pImg, "basic", "FindNextStmnt: pImg==NULL with FollowJumps option" );
1460 sal_uInt32 nOp1 = *p++; nOp1 |= *p++ << 8;
1461 nOp1 |= *p++ << 16; nOp1 |= *p++ << 24;
1462 p = pImg->GetCode() + nOp1;
1464 else if( eOp >= SbiOpcode::SbOP1_START && eOp <= SbiOpcode::SbOP1_END )
1466 p += 4;
1467 nPC += 4;
1469 else if( eOp == SbiOpcode::STMNT_ )
1471 sal_uInt32 nl, nc;
1472 nl = *p++; nl |= *p++ << 8;
1473 nl |= *p++ << 16 ; nl |= *p++ << 24;
1474 nc = *p++; nc |= *p++ << 8;
1475 nc |= *p++ << 16 ; nc |= *p++ << 24;
1476 nLine = static_cast<sal_uInt16>(nl); nCol = static_cast<sal_uInt16>(nc);
1477 return p;
1479 else if( eOp >= SbiOpcode::SbOP2_START && eOp <= SbiOpcode::SbOP2_END )
1481 p += 8;
1482 nPC += 8;
1484 else if( eOp < SbiOpcode::SbOP0_START || eOp > SbiOpcode::SbOP0_END )
1486 StarBASIC::FatalError( ERRCODE_BASIC_INTERNAL_ERROR );
1487 break;
1490 return nullptr;
1493 // Test, if a line contains STMNT-Opcodes
1495 bool SbModule::IsBreakable( sal_uInt16 nLine ) const
1497 if( !pImage )
1498 return false;
1499 const sal_uInt8* p = pImage->GetCode();
1500 sal_uInt16 nl, nc;
1501 while( ( p = FindNextStmnt( p, nl, nc ) ) != nullptr )
1502 if( nl == nLine )
1503 return true;
1504 return false;
1507 bool SbModule::IsBP( sal_uInt16 nLine ) const
1509 if( pBreaks )
1511 for( size_t i = 0; i < pBreaks->size(); i++ )
1513 sal_uInt16 b = pBreaks->operator[]( i );
1514 if( b == nLine )
1515 return true;
1516 if( b < nLine )
1517 break;
1520 return false;
1523 bool SbModule::SetBP( sal_uInt16 nLine )
1525 if( !IsBreakable( nLine ) )
1526 return false;
1527 if( !pBreaks )
1528 pBreaks.reset(new SbiBreakpoints);
1529 auto it = std::find_if(pBreaks->begin(), pBreaks->end(),
1530 [&nLine](const sal_uInt16 b) { return b <= nLine; });
1531 if (it != pBreaks->end() && *it == nLine)
1532 return true;
1533 pBreaks->insert( it, nLine );
1535 // #38568: Set during runtime as well here BasicDebugFlags::Break
1536 if( GetSbData()->pInst && GetSbData()->pInst->pRun )
1537 GetSbData()->pInst->pRun->SetDebugFlags( BasicDebugFlags::Break );
1539 return IsBreakable( nLine );
1542 bool SbModule::ClearBP( sal_uInt16 nLine )
1544 bool bRes = false;
1545 if( pBreaks )
1547 auto it = std::find_if(pBreaks->begin(), pBreaks->end(),
1548 [&nLine](const sal_uInt16 b) { return b <= nLine; });
1549 bRes = (it != pBreaks->end()) && (*it == nLine);
1550 if (bRes)
1551 pBreaks->erase(it);
1552 if (pBreaks->empty())
1553 pBreaks.reset();
1555 return bRes;
1558 void SbModule::ClearAllBP()
1560 pBreaks.reset();
1563 void
1564 SbModule::fixUpMethodStart( bool bCvtToLegacy, SbiImage* pImg ) const
1566 if ( !pImg )
1567 pImg = pImage.get();
1568 for (sal_uInt32 i = 0; i < pMethods->Count(); i++)
1570 SbMethod* pMeth = dynamic_cast<SbMethod*>(pMethods->Get(i));
1571 if( pMeth )
1573 //fixup method start positions
1574 if ( bCvtToLegacy )
1575 pMeth->nStart = pImg->CalcLegacyOffset( pMeth->nStart );
1576 else
1577 pMeth->nStart = pImg->CalcNewOffset( static_cast<sal_uInt16>(pMeth->nStart) );
1583 bool SbModule::LoadData( SvStream& rStrm, sal_uInt16 nVer )
1585 Clear();
1586 if( !SbxObject::LoadData( rStrm, 1 ) )
1587 return false;
1588 // As a precaution...
1589 SetFlag( SbxFlagBits::ExtSearch | SbxFlagBits::GlobalSearch );
1590 sal_uInt8 bImage;
1591 rStrm.ReadUChar( bImage );
1592 if( !bImage )
1593 return true;
1595 std::unique_ptr<SbiImage> p(new SbiImage);
1596 sal_uInt32 nImgVer = 0;
1598 if( !p->Load( rStrm, nImgVer ) )
1600 return false;
1602 // If the image is in old format, we fix up the method start offsets
1603 if ( nImgVer < B_IMG_VERSION_12 )
1605 fixUpMethodStart( false, p.get() );
1606 p->ReleaseLegacyBuffer();
1608 aComment = p->aComment;
1609 SetName( p->aName );
1610 if( p->GetCodeSize() )
1612 aOUSource = p->aOUSource;
1613 // Old version: image away
1614 if( nVer == 1 )
1616 SetSource32( p->aOUSource );
1618 else
1619 pImage = std::move(p);
1621 else
1623 SetSource32( p->aOUSource );
1625 return true;
1628 std::pair<bool, sal_uInt32> SbModule::StoreData( SvStream& rStrm ) const
1630 bool bFixup = ( pImage && !pImage->ExceedsLegacyLimits() );
1631 if ( bFixup )
1632 fixUpMethodStart( true );
1633 const auto [bSuccess, nVersion] = SbxObject::StoreData(rStrm);
1634 if (!bSuccess)
1635 return { false, 0 };
1637 if( pImage )
1639 pImage->aOUSource = aOUSource;
1640 pImage->aComment = aComment;
1641 pImage->aName = GetName();
1642 rStrm.WriteUChar( 1 );
1643 // # PCode is saved only for legacy formats only
1644 // It should be noted that it probably isn't necessary
1645 // It would be better not to store the image ( more flexible with
1646 // formats )
1647 bool bRes = pImage->Save( rStrm, nVersion );
1648 if ( bFixup )
1649 fixUpMethodStart( false ); // restore method starts
1650 return { bRes, nVersion };
1653 else
1655 SbiImage aImg;
1656 aImg.aOUSource = aOUSource;
1657 aImg.aComment = aComment;
1658 aImg.aName = GetName();
1659 rStrm.WriteUChar( 1 );
1660 return { aImg.Save(rStrm, nVersion), nVersion };
1664 bool SbModule::ExceedsImgVersion12ModuleSize()
1666 if ( !IsCompiled() )
1667 Compile();
1668 return pImage && pImage->ExceedsImgVersion12Limits();
1671 namespace {
1673 class ErrorHdlResetter
1675 Link<StarBASIC*,bool> mErrHandler;
1676 bool mbError;
1677 public:
1678 ErrorHdlResetter()
1679 : mErrHandler(StarBASIC::GetGlobalErrorHdl()) // save error handler
1680 , mbError( false )
1682 // set new error handler
1683 StarBASIC::SetGlobalErrorHdl( LINK( this, ErrorHdlResetter, BasicErrorHdl ) );
1685 ~ErrorHdlResetter()
1687 // restore error handler
1688 StarBASIC::SetGlobalErrorHdl(mErrHandler);
1690 DECL_LINK( BasicErrorHdl, StarBASIC *, bool );
1691 bool HasError() const { return mbError; }
1696 IMPL_LINK( ErrorHdlResetter, BasicErrorHdl, StarBASIC *, /*pBasic*/, bool)
1698 mbError = true;
1699 return false;
1702 void SbModule::GetCodeCompleteDataFromParse(CodeCompleteDataCache& aCache)
1704 ErrorHdlResetter aErrHdl;
1705 SbxBase::ResetError();
1707 SbiParser aParser(static_cast<StarBASIC*>(GetParent()), this );
1708 aParser.SetCodeCompleting(true);
1710 while( aParser.Parse() ) {}
1711 SbiSymPool* pPool = aParser.pPool;
1712 aCache.Clear();
1713 for( sal_uInt16 i = 0; i < pPool->GetSize(); ++i )
1715 SbiSymDef* pSymDef = pPool->Get(i);
1716 //std::cerr << "i: " << i << ", type: " << pSymDef->GetType() << "; name:" << pSymDef->GetName() << std::endl;
1717 if( (pSymDef->GetType() != SbxEMPTY) && (pSymDef->GetType() != SbxNULL) )
1718 aCache.InsertGlobalVar( pSymDef->GetName(), aParser.aGblStrings.Find(pSymDef->GetTypeId()) );
1720 SbiSymPool& rChildPool = pSymDef->GetPool();
1721 for(sal_uInt16 j = 0; j < rChildPool.GetSize(); ++j )
1723 SbiSymDef* pChildSymDef = rChildPool.Get(j);
1724 //std::cerr << "j: " << j << ", type: " << pChildSymDef->GetType() << "; name:" << pChildSymDef->GetName() << std::endl;
1725 if( (pChildSymDef->GetType() != SbxEMPTY) && (pChildSymDef->GetType() != SbxNULL) )
1726 aCache.InsertLocalVar( pSymDef->GetName(), pChildSymDef->GetName(), aParser.aGblStrings.Find(pChildSymDef->GetTypeId()) );
1732 OUString SbModule::GetKeywordCase( std::u16string_view sKeyword )
1734 return SbiParser::GetKeywordCase( sKeyword );
1737 bool SbModule::HasExeCode()
1739 // And empty Image always has the Global Chain set up
1740 static const unsigned char pEmptyImage[] = { 0x45, 0x0 , 0x0, 0x0, 0x0 };
1741 // let's be stricter for the moment than VBA
1743 if (!IsCompiled())
1745 ErrorHdlResetter aGblErrHdl;
1746 Compile();
1747 if (aGblErrHdl.HasError()) //assume unsafe on compile error
1748 return true;
1751 bool bRes = false;
1752 if (pImage && (pImage->GetCodeSize() != 5 || (memcmp(pImage->GetCode(), pEmptyImage, pImage->GetCodeSize()) != 0 )))
1753 bRes = true;
1755 return bRes;
1758 // Store only image, no source
1759 void SbModule::StoreBinaryData( SvStream& rStrm )
1761 if (!Compile())
1762 return;
1764 const auto [bSuccess, nVersion] = SbxObject::StoreData(rStrm);
1765 if (!bSuccess)
1766 return;
1768 pImage->aOUSource.clear();
1769 pImage->aComment = aComment;
1770 pImage->aName = GetName();
1772 rStrm.WriteUChar(1);
1773 pImage->Save(rStrm, nVersion);
1775 pImage->aOUSource = aOUSource;
1778 // Called for >= OO 1.0 passwd protected libraries only
1780 void SbModule::LoadBinaryData( SvStream& rStrm )
1782 OUString aKeepSource = aOUSource;
1783 LoadData( rStrm, 2 );
1784 LoadCompleted();
1785 aOUSource = aKeepSource;
1788 bool SbModule::LoadCompleted()
1790 SbxArray* p = GetMethods().get();
1791 sal_uInt32 i;
1792 for (i = 0; i < p->Count(); i++)
1794 SbMethod* q = dynamic_cast<SbMethod*>(p->Get(i));
1795 if( q )
1796 q->pMod = this;
1798 p = GetProperties();
1799 for (i = 0; i < p->Count(); i++)
1801 SbProperty* q = dynamic_cast<SbProperty*>(p->Get(i));
1802 if( q )
1803 q->pMod = this;
1805 return true;
1808 void SbModule::handleProcedureProperties( SfxBroadcaster& rBC, const SfxHint& rHint )
1810 bool bDone = false;
1812 const SbxHint* pHint = dynamic_cast<const SbxHint*>(&rHint);
1813 if( pHint )
1815 SbxVariable* pVar = pHint->GetVar();
1816 SbProcedureProperty* pProcProperty = dynamic_cast<SbProcedureProperty*>( pVar );
1817 if( pProcProperty )
1819 bDone = true;
1821 if( pHint->GetId() == SfxHintId::BasicDataWanted )
1823 OUString aProcName = "Property Get "
1824 + pProcProperty->GetName();
1826 SbxVariable* pMeth = Find( aProcName, SbxClassType::Method );
1827 if( pMeth )
1829 SbxValues aVals;
1830 aVals.eType = SbxVARIANT;
1832 SbxArray* pArg = pVar->GetParameters();
1833 sal_uInt32 nVarParCount = (pArg != nullptr) ? pArg->Count() : 0;
1834 if( nVarParCount > 1 )
1836 SbxArrayRef xMethParameters = new SbxArray;
1837 xMethParameters->Put(pMeth, 0); // Method as parameter 0
1838 for( sal_uInt32 i = 1 ; i < nVarParCount ; ++i )
1840 SbxVariable* pPar = pArg->Get(i);
1841 xMethParameters->Put(pPar, i);
1844 pMeth->SetParameters( xMethParameters.get() );
1845 pMeth->Get( aVals );
1846 pMeth->SetParameters( nullptr );
1848 else
1850 pMeth->Get( aVals );
1853 pVar->Put( aVals );
1856 else if( pHint->GetId() == SfxHintId::BasicDataChanged )
1858 SbxVariable* pMeth = nullptr;
1860 bool bSet = pProcProperty->isSet();
1861 if( bSet )
1863 pProcProperty->setSet( false );
1865 OUString aProcName = "Property Set "
1866 + pProcProperty->GetName();
1867 pMeth = Find( aProcName, SbxClassType::Method );
1869 if( !pMeth ) // Let
1871 OUString aProcName = "Property Let "
1872 + pProcProperty->GetName();
1873 pMeth = Find( aProcName, SbxClassType::Method );
1876 if( pMeth )
1878 // Setup parameters
1879 SbxArrayRef xArray = new SbxArray;
1880 xArray->Put(pMeth, 0); // Method as parameter 0
1881 xArray->Put(pVar, 1);
1882 pMeth->SetParameters( xArray.get() );
1884 SbxValues aVals;
1885 pMeth->Get( aVals );
1886 pMeth->SetParameters( nullptr );
1892 if( !bDone )
1893 SbModule::Notify( rBC, rHint );
1897 // Implementation SbJScriptModule (Basic module for JavaScript source code)
1898 SbJScriptModule::SbJScriptModule()
1899 :SbModule( u""_ustr )
1903 bool SbJScriptModule::LoadData( SvStream& rStrm, sal_uInt16 )
1905 Clear();
1906 if( !SbxObject::LoadData( rStrm, 1 ) )
1907 return false;
1909 // Get the source string
1910 aOUSource = rStrm.ReadUniOrByteString( osl_getThreadTextEncoding() );
1911 return true;
1914 std::pair<bool, sal_uInt32> SbJScriptModule::StoreData( SvStream& rStrm ) const
1916 const auto [bSuccess, nVersion] = SbxObject::StoreData(rStrm);
1917 if( !bSuccess )
1918 return { false, 0 };
1920 // Write the source string
1921 OUString aTmp = aOUSource;
1922 rStrm.WriteUniOrByteString( aTmp, osl_getThreadTextEncoding() );
1923 return { true, nVersion };
1927 SbMethod::SbMethod( const OUString& r, SbxDataType t, SbModule* p )
1928 : SbxMethod( r, t ), pMod( p )
1930 bInvalid = true;
1931 nStart = 0;
1932 nDebugFlags = BasicDebugFlags::NONE;
1933 nLine1 = 0;
1934 nLine2 = 0;
1935 refStatics = new SbxArray;
1936 mCaller = nullptr;
1937 // HACK due to 'Reference could not be saved'
1938 SetFlag( SbxFlagBits::NoModify );
1941 SbMethod::SbMethod( const SbMethod& r )
1942 : SvRefBase( r ), SbxMethod( r )
1944 pMod = r.pMod;
1945 bInvalid = r.bInvalid;
1946 nStart = r.nStart;
1947 nDebugFlags = r.nDebugFlags;
1948 nLine1 = r.nLine1;
1949 nLine2 = r.nLine2;
1950 refStatics = r.refStatics;
1951 mCaller = r.mCaller;
1952 SetFlag( SbxFlagBits::NoModify );
1955 SbMethod::~SbMethod()
1959 void SbMethod::ClearStatics()
1961 refStatics = new SbxArray;
1964 SbxArray* SbMethod::GetStatics()
1966 return refStatics.get();
1969 bool SbMethod::LoadData( SvStream& rStrm, sal_uInt16 nVer )
1971 if( !SbxMethod::LoadData( rStrm, 1 ) )
1972 return false;
1974 sal_uInt16 nFlag;
1975 rStrm.ReadUInt16( nFlag );
1977 sal_Int16 nTempStart = static_cast<sal_Int16>(nStart);
1979 if( nVer == 2 )
1981 rStrm.ReadUInt16( nLine1 ).ReadUInt16( nLine2 ).ReadInt16( nTempStart ).ReadCharAsBool( bInvalid );
1982 //tdf#94617
1983 if (nFlag & 0x8000)
1985 sal_uInt16 nMult = nFlag & 0x7FFF;
1986 sal_Int16 const nMax = std::numeric_limits<sal_Int16>::max();
1987 nStart = nMult * nMax + nTempStart;
1989 else
1991 nStart = nTempStart;
1994 else
1996 nStart = nTempStart;
1999 // HACK due to 'Reference could not be saved'
2000 SetFlag( SbxFlagBits::NoModify );
2002 return true;
2005 std::pair<bool, sal_uInt32> SbMethod::StoreData( SvStream& rStrm ) const
2007 auto [bSuccess, nVersion] = SbxMethod::StoreData(rStrm);
2008 if( !bSuccess )
2009 return { false, 0 };
2011 //tdf#94617
2012 const sal_uInt32 nMax = std::numeric_limits<sal_Int16>::max();
2013 // tdf#142391 - store method using binary format 0x13 only when actually needed, i.e.,
2014 // when method starts at an offset that would overflow 16 bits
2015 const sal_Int16 nStartTemp = nStart % nMax;
2016 sal_uInt16 nDebugFlagsTemp = static_cast<sal_uInt16>(nDebugFlags);
2017 if (nStart >= nMax)
2019 assert(nStart <= nMax * 0x7FFF); // Larger addresses can't be stored in version 13
2020 nDebugFlagsTemp = (nStart / nMax) | 0x8000;
2021 nVersion = B_IMG_VERSION_13;
2024 rStrm.WriteUInt16( nDebugFlagsTemp )
2025 .WriteInt16( nLine1 )
2026 .WriteInt16( nLine2 )
2027 .WriteInt16( nStartTemp )
2028 .WriteBool( bInvalid );
2030 return { true, nVersion };
2033 void SbMethod::GetLineRange( sal_uInt16& l1, sal_uInt16& l2 )
2035 l1 = nLine1; l2 = nLine2;
2038 // Could later be deleted
2040 SbxInfo* SbMethod::GetInfo()
2042 return pInfo.get();
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 )
2050 if ( pCaller )
2052 SAL_INFO("basic", "SbMethod::Call Have been passed a caller 0x" << pCaller );
2053 mCaller = pCaller;
2055 // Increment the RefCount of the module
2056 tools::SvRef<SbModule> pMod_ = static_cast<SbModule*>(GetParent());
2058 tools::SvRef<StarBASIC> xHolder = static_cast<StarBASIC*>(pMod_->GetParent());
2060 // Establish the values to get the return value
2061 SbxValues aVals;
2062 aVals.eType = SbxVARIANT;
2064 // #104083: Compile BEFORE get
2065 if( bInvalid && !pMod_->Compile() )
2066 StarBASIC::Error( ERRCODE_BASIC_BAD_PROP_VALUE );
2068 // tdf#143582 - clear return value of the method before calling it
2069 Clear();
2071 Get( aVals );
2072 if ( pRet )
2073 pRet->Put( aVals );
2075 // Was there an error
2076 ErrCode nErr = SbxBase::GetError();
2077 SbxBase::ResetError();
2079 mCaller = nullptr;
2080 return nErr;
2084 // #100883 Own Broadcast for SbMethod
2085 void SbMethod::Broadcast( SfxHintId nHintId )
2087 if( !mpBroadcaster || IsSet( SbxFlagBits::NoBroadcast ) )
2088 return;
2090 // Because the method could be called from outside, test here once again
2091 // the authorisation
2092 if( nHintId == SfxHintId::BasicDataWanted )
2093 if( !CanRead() )
2094 return;
2095 if( nHintId == SfxHintId::BasicDataChanged )
2096 if( !CanWrite() )
2097 return;
2099 if( pMod && !pMod->IsCompiled() )
2100 pMod->Compile();
2102 // Block broadcasts while creating new method
2103 std::unique_ptr<SfxBroadcaster> pSaveBroadcaster = std::move(mpBroadcaster);
2104 SbMethodRef xThisCopy = new SbMethod( *this );
2105 if( mpPar.is() )
2107 // Enregister this as element 0, but don't reset the parent!
2108 if( GetType() != SbxVOID ) {
2109 mpPar->PutDirect( xThisCopy.get(), 0 );
2111 SetParameters( nullptr );
2114 mpBroadcaster = std::move(pSaveBroadcaster);
2115 mpBroadcaster->Broadcast( SbxHint( nHintId, xThisCopy.get() ) );
2117 SbxFlagBits nSaveFlags = GetFlags();
2118 SetFlag( SbxFlagBits::ReadWrite );
2119 pSaveBroadcaster = std::move(mpBroadcaster);
2120 Put( xThisCopy->GetValues_Impl() );
2121 mpBroadcaster = std::move(pSaveBroadcaster);
2122 SetFlags( nSaveFlags );
2126 // Implementation of SbJScriptMethod (method class as a wrapper for JavaScript-functions)
2128 SbJScriptMethod::SbJScriptMethod( SbxDataType t )
2129 : SbMethod( u""_ustr, t, nullptr )
2133 SbJScriptMethod::~SbJScriptMethod()
2137 SbObjModule::SbObjModule( const OUString& rName, const css::script::ModuleInfo& mInfo, bool bIsVbaCompatible )
2138 : SbModule( rName, bIsVbaCompatible )
2140 SetModuleType( mInfo.ModuleType );
2141 if ( mInfo.ModuleType == script::ModuleType::FORM )
2143 SetClassName( u"Form"_ustr );
2145 else if ( mInfo.ModuleObject.is() )
2147 SetUnoObject( uno::Any( mInfo.ModuleObject ) );
2151 SbObjModule::~SbObjModule()
2155 void
2156 SbObjModule::SetUnoObject( const uno::Any& aObj )
2158 SbUnoObject* pUnoObj = pDocObject.get();
2159 if ( pUnoObj && pUnoObj->getUnoAny() == aObj ) // object is equal, nothing to do
2160 return;
2161 pDocObject = new SbUnoObject( GetName(), aObj );
2163 css::uno::Reference< css::lang::XServiceInfo > xServiceInfo( aObj, css::uno::UNO_QUERY_THROW );
2164 if( xServiceInfo->supportsService( u"ooo.vba.excel.Worksheet"_ustr ) )
2166 SetClassName( u"Worksheet"_ustr );
2168 else if( xServiceInfo->supportsService( u"ooo.vba.excel.Workbook"_ustr ) )
2170 SetClassName( u"Workbook"_ustr );
2174 SbxVariable*
2175 SbObjModule::GetObject()
2177 return pDocObject.get();
2179 SbxVariable*
2180 SbObjModule::Find( const OUString& rName, SbxClassType t )
2182 SbxVariable* pVar = nullptr;
2183 if ( pDocObject )
2184 pVar = pDocObject->Find( rName, t );
2185 if ( !pVar )
2186 pVar = SbModule::Find( rName, t );
2187 return pVar;
2190 void SbObjModule::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
2192 SbModule::handleProcedureProperties( rBC, rHint );
2196 typedef ::cppu::WeakImplHelper<
2197 awt::XTopWindowListener,
2198 awt::XWindowListener,
2199 document::XDocumentEventListener > FormObjEventListener_BASE;
2201 class FormObjEventListenerImpl:
2202 public FormObjEventListener_BASE
2204 SbUserFormModule* mpUserForm;
2205 uno::Reference< lang::XComponent > mxComponent;
2206 uno::Reference< frame::XModel > mxModel;
2207 bool mbDisposed;
2208 bool mbOpened;
2209 bool mbActivated;
2210 bool mbShowing;
2212 public:
2213 FormObjEventListenerImpl(const FormObjEventListenerImpl&) = delete;
2214 const FormObjEventListenerImpl& operator=(const FormObjEventListenerImpl&) = delete;
2215 FormObjEventListenerImpl( SbUserFormModule* pUserForm, uno::Reference< lang::XComponent > xComponent, uno::Reference< frame::XModel > xModel ) :
2216 mpUserForm( pUserForm ), mxComponent(std::move( xComponent)), mxModel(std::move( xModel )),
2217 mbDisposed( false ), mbOpened( false ), mbActivated( false ), mbShowing( false )
2219 if ( mxComponent.is() )
2223 uno::Reference< awt::XTopWindow >( mxComponent, uno::UNO_QUERY_THROW )->addTopWindowListener( this );
2225 catch(const uno::Exception& ) {}
2228 uno::Reference< awt::XWindow >( mxComponent, uno::UNO_QUERY_THROW )->addWindowListener( this );
2230 catch(const uno::Exception& ) {}
2233 if ( mxModel.is() )
2237 uno::Reference< document::XDocumentEventBroadcaster >( mxModel, uno::UNO_QUERY_THROW )->addDocumentEventListener( this );
2239 catch(const uno::Exception& ) {}
2243 virtual ~FormObjEventListenerImpl() override
2245 removeListener();
2248 bool isShowing() const { return mbShowing; }
2250 void removeListener()
2252 if ( mxComponent.is() && !mbDisposed )
2256 uno::Reference< awt::XTopWindow >( mxComponent, uno::UNO_QUERY_THROW )->removeTopWindowListener( this );
2258 catch(const uno::Exception& ) {}
2261 uno::Reference< awt::XWindow >( mxComponent, uno::UNO_QUERY_THROW )->removeWindowListener( this );
2263 catch(const uno::Exception& ) {}
2265 mxComponent.clear();
2267 if ( mxModel.is() && !mbDisposed )
2271 uno::Reference< document::XDocumentEventBroadcaster >( mxModel, uno::UNO_QUERY_THROW )->removeDocumentEventListener( this );
2273 catch(const uno::Exception& ) {}
2275 mxModel.clear();
2278 virtual void SAL_CALL windowOpened( const lang::EventObject& /*e*/ ) override
2280 if ( mpUserForm )
2282 mbOpened = true;
2283 mbShowing = true;
2284 if ( mbActivated )
2286 mbOpened = mbActivated = false;
2287 mpUserForm->triggerActivateEvent();
2293 virtual void SAL_CALL windowClosing( const lang::EventObject& /*e*/ ) override
2295 #ifdef IN_THE_FUTURE
2296 uno::Reference< awt::XDialog > xDialog( e.Source, uno::UNO_QUERY );
2297 if ( xDialog.is() )
2299 uno::Reference< awt::XControl > xControl( xDialog, uno::UNO_QUERY );
2300 if ( xControl->getPeer().is() )
2302 uno::Reference< document::XVbaMethodParameter > xVbaMethodParameter( xControl->getPeer(), uno::UNO_QUERY );
2303 if ( xVbaMethodParameter.is() )
2305 sal_Int8 nCancel = 0;
2306 sal_Int8 nCloseMode = ::ooo::vba::VbQueryClose::vbFormControlMenu;
2308 Sequence< Any > aParams;
2309 aParams.realloc(2);
2310 aParams[0] <<= nCancel;
2311 aParams[1] <<= nCloseMode;
2313 mpUserForm->triggerMethod( "Userform_QueryClose", aParams);
2314 return;
2320 mpUserForm->triggerMethod( "Userform_QueryClose" );
2321 #endif
2325 virtual void SAL_CALL windowClosed( const lang::EventObject& /*e*/ ) override
2327 mbOpened = false;
2328 mbShowing = false;
2331 virtual void SAL_CALL windowMinimized( const lang::EventObject& /*e*/ ) override
2335 virtual void SAL_CALL windowNormalized( const lang::EventObject& /*e*/ ) override
2339 virtual void SAL_CALL windowActivated( const lang::EventObject& /*e*/ ) override
2341 if ( mpUserForm )
2343 mbActivated = true;
2344 if ( mbOpened )
2346 mbOpened = mbActivated = false;
2347 mpUserForm->triggerActivateEvent();
2352 virtual void SAL_CALL windowDeactivated( const lang::EventObject& /*e*/ ) override
2354 if ( mpUserForm )
2355 mpUserForm->triggerDeactivateEvent();
2358 virtual void SAL_CALL windowResized( const awt::WindowEvent& /*e*/ ) override
2360 if ( mpUserForm )
2362 mpUserForm->triggerResizeEvent();
2363 mpUserForm->triggerLayoutEvent();
2367 virtual void SAL_CALL windowMoved( const awt::WindowEvent& /*e*/ ) override
2369 if ( mpUserForm )
2370 mpUserForm->triggerLayoutEvent();
2373 virtual void SAL_CALL windowShown( const lang::EventObject& /*e*/ ) override
2377 virtual void SAL_CALL windowHidden( const lang::EventObject& /*e*/ ) override
2381 virtual void SAL_CALL documentEventOccured( const document::DocumentEvent& rEvent ) override
2383 // early disposing on document event "OnUnload", to be sure Basic still exists when calling VBA "UserForm_Terminate"
2384 if( rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::CLOSEDOC ) )
2386 SolarMutexGuard g;
2387 removeListener();
2388 mbDisposed = true;
2389 if ( mpUserForm )
2390 mpUserForm->ResetApiObj(); // will trigger "UserForm_Terminate"
2394 virtual void SAL_CALL disposing( const lang::EventObject& /*Source*/ ) override
2396 removeListener();
2397 mbDisposed = true;
2398 if ( mpUserForm )
2399 mpUserForm->ResetApiObj( false ); // pass false (too late to trigger VBA events here)
2403 SbUserFormModule::SbUserFormModule( const OUString& rName, const css::script::ModuleInfo& mInfo, bool bIsCompat )
2404 : SbObjModule( rName, mInfo, bIsCompat )
2405 , m_mInfo( mInfo )
2406 , mbInit( false )
2408 m_xModel.set( mInfo.ModuleObject, uno::UNO_QUERY_THROW );
2411 SbUserFormModule::~SbUserFormModule()
2415 void SbUserFormModule::ResetApiObj( bool bTriggerTerminateEvent )
2417 SAL_INFO("basic", " SbUserFormModule::ResetApiObj( " << (bTriggerTerminateEvent ? "true )" : "false )") );
2418 if ( bTriggerTerminateEvent && m_xDialog.is() ) // probably someone close the dialog window
2420 triggerTerminateEvent();
2422 pDocObject = nullptr;
2423 m_xDialog = nullptr;
2426 void SbUserFormModule::triggerMethod( const OUString& aMethodToRun )
2428 Sequence< Any > aArguments;
2429 triggerMethod( aMethodToRun, aArguments );
2432 void SbUserFormModule::triggerMethod( const OUString& aMethodToRun, Sequence< Any >& aArguments )
2434 SAL_INFO("basic", "trigger " << aMethodToRun);
2435 // Search method
2436 SbxVariable* pMeth = SbObjModule::Find( aMethodToRun, SbxClassType::Method );
2437 if( !pMeth )
2438 return;
2440 if ( aArguments.hasElements() ) // Setup parameters
2442 auto xArray = tools::make_ref<SbxArray>();
2443 xArray->Put(pMeth, 0); // Method as parameter 0
2445 for ( sal_Int32 i = 0; i < aArguments.getLength(); ++i )
2447 auto xSbxVar = tools::make_ref<SbxVariable>( SbxVARIANT );
2448 unoToSbxValue( xSbxVar.get(), aArguments[i] );
2449 xArray->Put(xSbxVar.get(), static_cast<sal_uInt32>(i) + 1);
2451 // Enable passing by ref
2452 if ( xSbxVar->GetType() != SbxVARIANT )
2453 xSbxVar->SetFlag( SbxFlagBits::Fixed );
2455 pMeth->SetParameters( xArray.get() );
2457 SbxValues aVals;
2458 pMeth->Get( aVals );
2460 auto pArguments = aArguments.getArray();
2461 for ( sal_Int32 i = 0; i < aArguments.getLength(); ++i )
2463 pArguments[i] = sbxToUnoValue(xArray->Get(static_cast<sal_uInt32>(i) + 1));
2465 pMeth->SetParameters( nullptr );
2467 else
2469 SbxValues aVals;
2470 pMeth->Get( aVals );
2474 void SbUserFormModule::triggerActivateEvent()
2476 triggerMethod( u"UserForm_Activate"_ustr );
2479 void SbUserFormModule::triggerDeactivateEvent()
2481 triggerMethod( u"Userform_Deactivate"_ustr );
2484 void SbUserFormModule::triggerInitializeEvent()
2486 if ( mbInit )
2487 return;
2488 triggerMethod(u"Userform_Initialize"_ustr);
2489 mbInit = true;
2492 void SbUserFormModule::triggerTerminateEvent()
2494 triggerMethod(u"Userform_Terminate"_ustr);
2495 mbInit=false;
2498 void SbUserFormModule::triggerLayoutEvent()
2500 triggerMethod(u"Userform_Layout"_ustr);
2503 void SbUserFormModule::triggerResizeEvent()
2505 triggerMethod(u"Userform_Resize"_ustr);
2508 SbUserFormModuleInstance* SbUserFormModule::CreateInstance()
2510 SbUserFormModuleInstance* pInstance = new SbUserFormModuleInstance( this, GetName(), m_mInfo, IsVBASupport() );
2511 return pInstance;
2514 SbUserFormModuleInstance::SbUserFormModuleInstance( SbUserFormModule* pParentModule,
2515 const OUString& rName, const css::script::ModuleInfo& mInfo, bool bIsVBACompat )
2516 : SbUserFormModule( rName, mInfo, bIsVBACompat )
2517 , m_pParentModule( pParentModule )
2521 bool SbUserFormModuleInstance::IsClass( const OUString& rName ) const
2523 bool bParentNameMatches = m_pParentModule->GetName().equalsIgnoreAsciiCase( rName );
2524 bool bRet = bParentNameMatches || SbxObject::IsClass( rName );
2525 return bRet;
2528 SbxVariable* SbUserFormModuleInstance::Find( const OUString& rName, SbxClassType t )
2530 SbxVariable* pVar = m_pParentModule->Find( rName, t );
2531 return pVar;
2535 void SbUserFormModule::Load()
2537 // forces a load
2538 if ( !pDocObject.is() )
2539 InitObject();
2543 void SbUserFormModule::Unload()
2545 sal_Int8 nCancel = 0;
2547 Sequence< Any > aParams = { Any(nCancel), Any(sal_Int8(::ooo::vba::VbQueryClose::vbFormCode)) };
2549 triggerMethod( u"Userform_QueryClose"_ustr, aParams);
2551 aParams[0] >>= nCancel;
2552 // basic boolean ( and what the user might use ) can be ambiguous ( e.g. basic true = -1 )
2553 // test against 0 ( false ) and assume anything else is true
2554 // ( Note: ) this used to work ( something changes somewhere )
2555 if (nCancel != 0)
2557 return;
2560 if ( m_xDialog.is() )
2562 triggerTerminateEvent();
2564 // Search method
2565 SbxVariable* pMeth = SbObjModule::Find( u"UnloadObject"_ustr, SbxClassType::Method );
2566 if( !pMeth )
2567 return;
2569 SAL_INFO("basic", "Attempting to run the UnloadObjectMethod");
2570 m_xDialog.clear(); //release ref to the uno object
2571 SbxValues aVals;
2572 bool bWaitForDispose = true; // assume dialog is showing
2573 if (m_DialogListener)
2575 bWaitForDispose = m_DialogListener->isShowing();
2576 SAL_INFO("basic", "Showing " << bWaitForDispose );
2578 pMeth->Get( aVals);
2579 if ( !bWaitForDispose )
2581 // we've either already got a dispose or we are never going to get one
2582 ResetApiObj();
2583 } // else wait for dispose
2584 SAL_INFO("basic", "UnloadObject completed (we hope)");
2588 void SbUserFormModule::InitObject()
2592 SbUnoObject* pGlobs = static_cast<SbUnoObject*>(GetParent()->Find( u"VBAGlobals"_ustr, SbxClassType::DontCare ));
2593 if ( m_xModel.is() && pGlobs )
2595 // broadcast INITIALIZE_USERFORM script event before the dialog is created
2596 Reference< script::vba::XVBACompatibility > xVBACompat( getVBACompatibility( m_xModel ), uno::UNO_SET_THROW );
2597 xVBACompat->broadcastVBAScriptEvent( script::vba::VBAScriptEventId::INITIALIZE_USERFORM, GetName() );
2598 uno::Reference< lang::XMultiServiceFactory > xVBAFactory( pGlobs->getUnoAny(), uno::UNO_QUERY_THROW );
2599 const uno::Reference< uno::XComponentContext >& xContext = comphelper::getProcessComponentContext();
2600 OUString sDialogUrl( u"vnd.sun.star.script:"_ustr );
2601 OUString sProjectName( u"Standard"_ustr );
2605 Reference< beans::XPropertySet > xProps( m_xModel, UNO_QUERY_THROW );
2606 uno::Reference< script::vba::XVBACompatibility > xVBAMode( xProps->getPropertyValue( u"BasicLibraries"_ustr ), uno::UNO_QUERY_THROW );
2607 sProjectName = xVBAMode->getProjectName();
2609 catch(const Exception& ) {}
2611 sDialogUrl += sProjectName + "." + GetName() + "?location=document";
2613 uno::Reference< awt::XDialogProvider > xProvider = awt::DialogProvider::createWithModel( xContext, m_xModel );
2614 m_xDialog = xProvider->createDialog( sDialogUrl );
2616 // create vba api object
2617 uno::Sequence< uno::Any > aArgs
2619 uno::Any(),
2620 Any(m_xDialog),
2621 Any(m_xModel),
2622 Any(GetParent()->GetName())
2624 pDocObject = new SbUnoObject( GetName(), uno::Any( xVBAFactory->createInstanceWithArguments( u"ooo.vba.msforms.UserForm"_ustr, aArgs ) ) );
2626 uno::Reference< lang::XComponent > xComponent( m_xDialog, uno::UNO_QUERY_THROW );
2628 // the dialog must be disposed at the end!
2629 StarBASIC* pParentBasic = nullptr;
2630 SbxObject* pCurObject = this;
2633 SbxObject* pObjParent = pCurObject->GetParent();
2634 pParentBasic = dynamic_cast<StarBASIC*>( pObjParent );
2635 pCurObject = pObjParent;
2637 while( pParentBasic == nullptr && pCurObject != nullptr );
2639 SAL_WARN_IF( pParentBasic == nullptr, "basic", "pParentBasic == NULL" );
2640 registerComponentToBeDisposedForBasic( xComponent, pParentBasic );
2642 // if old listener object exists, remove it from dialog and document model
2643 if( m_DialogListener.is() )
2644 m_DialogListener->removeListener();
2645 m_DialogListener.set( new FormObjEventListenerImpl( this, xComponent, m_xModel ) );
2647 triggerInitializeEvent();
2650 catch(const uno::Exception& )
2656 SbxVariable*
2657 SbUserFormModule::Find( const OUString& rName, SbxClassType t )
2659 if ( !pDocObject.is() && !GetSbData()->bRunInit && GetSbData()->pInst )
2660 InitObject();
2661 return SbObjModule::Find( rName, t );
2664 SbProperty::SbProperty( const OUString& r, SbxDataType t, SbModule* p )
2665 : SbxProperty( r, t ), pMod( p )
2669 SbProperty::~SbProperty()
2673 SbProcedureProperty::~SbProcedureProperty()
2676 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */