nss: upgrade to release 3.73
[LibreOffice.git] / basic / source / classes / sbxmod.cxx
blob5e9647e955a741ba633d081fd32434ed99851a4d
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 <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>
38 #include <sal/log.hxx>
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>
54 #ifdef UNX
55 #include <sys/resource.h>
56 #endif
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>
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>
74 #include <limits>
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;
83 typedef ::cppu::WeakImplHelper< XInvocation > DocObjectWrapper_BASE;
84 typedef std::map< sal_Int16, Any > OutParamMap;
86 namespace {
88 class DocObjectWrapper : public DocObjectWrapper_BASE
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 );
100 public:
101 explicit DocObjectWrapper( SbModule* pMod );
103 virtual Sequence< sal_Int8 > SAL_CALL getImplementationId() override
105 return css::uno::Sequence<sal_Int8>();
108 virtual Reference< XIntrospectionAccess > SAL_CALL getIntrospection( ) override;
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;
117 virtual Sequence< Type > SAL_CALL getTypes() override;
122 DocObjectWrapper::DocObjectWrapper( SbModule* pVar ) : m_pMod( pVar )
124 SbObjModule* pMod = dynamic_cast<SbObjModule*>( pVar );
125 if ( !pMod )
126 return;
128 if ( pMod->GetModuleType() != ModuleType::DOCUMENT )
129 return;
131 // Use proxy factory service to create aggregatable proxy.
132 SbUnoObject* pUnoObj = dynamic_cast<SbUnoObject*>( pMod->GetObject() );
133 Reference< XInterface > xIf;
134 if ( pUnoObj )
136 Any aObj = pUnoObj->getUnoAny();
137 aObj >>= xIf;
138 if ( xIf.is() )
140 m_xAggregateTypeProv.set( xIf, UNO_QUERY );
141 m_xAggInv.set( xIf, UNO_QUERY );
144 if ( xIf.is() )
148 Reference< XProxyFactory > xProxyFac = ProxyFactory::create( comphelper::getProcessComponentContext() );
149 m_xAggProxy = xProxyFac->createProxy( xIf );
151 catch(const Exception& )
153 TOOLS_WARN_EXCEPTION( "basic", "DocObjectWrapper::DocObjectWrapper" );
157 if ( !m_xAggProxy.is() )
158 return;
160 osl_atomic_increment( &m_refCount );
162 /* i35609 - Fix crash on Solaris. The setDelegator call needs
163 to be in its own block to ensure that all temporary Reference
164 instances that are acquired during the call are released
165 before m_refCount is decremented again */
167 m_xAggProxy->setDelegator( static_cast< cppu::OWeakObject * >( this ) );
170 osl_atomic_decrement( &m_refCount );
173 Sequence< Type > SAL_CALL DocObjectWrapper::getTypes()
175 if ( !m_Types.hasElements() )
177 Sequence< Type > sTypes;
178 if ( m_xAggregateTypeProv.is() )
180 sTypes = m_xAggregateTypeProv->getTypes();
182 m_Types = comphelper::concatSequences(sTypes,
183 Sequence { cppu::UnoType<XInvocation>::get() });
185 return m_Types;
188 Reference< XIntrospectionAccess > SAL_CALL
189 DocObjectWrapper::getIntrospection( )
191 return nullptr;
194 Any SAL_CALL
195 DocObjectWrapper::invoke( const OUString& aFunctionName, const Sequence< Any >& aParams, Sequence< ::sal_Int16 >& aOutParamIndex, Sequence< Any >& aOutParam )
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 )
207 sal_Int32 nSbxOptional = 0;
208 sal_uInt16 n = 1;
209 for ( const SbxParamInfo* pParamInfo = pInfo->GetParam( n ); pParamInfo; pParamInfo = pInfo->GetParam( ++n ) )
211 if ( pParamInfo->nFlags & SbxFlagBits::Optional )
212 ++nSbxOptional;
213 else
214 nSbxOptional = 0;
216 sal_Int32 nSbxCount = n - 1;
217 if ( nParamsCount < nSbxCount - nSbxOptional )
219 throw RuntimeException( "wrong number of parameters!" );
222 // set parameters
223 SbxArrayRef xSbxParams;
224 if ( nParamsCount > 0 )
226 xSbxParams = new SbxArray;
227 const Any* pParams = aParams.getConstArray();
228 for ( sal_Int32 i = 0; i < nParamsCount; ++i )
230 SbxVariableRef xSbxVar = new SbxVariable( SbxVARIANT );
231 unoToSbxValue( xSbxVar.get(), pParams[i] );
232 xSbxParams->Put32( xSbxVar.get(), static_cast< sal_uInt32 >( i ) + 1 );
234 // Enable passing by ref
235 if ( xSbxVar->GetType() != SbxVARIANT )
236 xSbxVar->SetFlag( SbxFlagBits::Fixed );
239 if ( xSbxParams.is() )
240 pMethod->SetParameters( xSbxParams.get() );
242 // call method
243 SbxVariableRef xReturn = new SbxVariable;
245 pMethod->Call( xReturn.get() );
246 Any aReturn;
247 // get output parameters
248 if ( xSbxParams.is() )
250 SbxInfo* pInfo_ = pMethod->GetInfo();
251 if ( pInfo_ )
253 OutParamMap aOutParamMap;
254 for ( sal_uInt32 n = 1, nCount = xSbxParams->Count32(); n < nCount; ++n )
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 )
260 SbxVariable* pVar = xSbxParams->Get32( n );
261 if ( pVar )
263 SbxVariableRef xVar = pVar;
264 aOutParamMap.emplace( n - 1, sbxToUnoValue( xVar.get() ) );
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)
275 *pOutParamIndex = outParam.first;
276 *pOutParam = outParam.second;
277 ++pOutParamIndex;
278 ++pOutParam;
283 // get return value
284 aReturn = sbxToUnoValue( xReturn.get() );
286 pMethod->SetParameters( nullptr );
288 return aReturn;
291 void SAL_CALL
292 DocObjectWrapper::setValue( const OUString& aPropertyName, const Any& aValue )
294 if ( m_xAggInv.is() && m_xAggInv->hasProperty( aPropertyName ) )
295 return m_xAggInv->setValue( aPropertyName, aValue );
297 SbPropertyRef pProperty = getProperty( aPropertyName );
298 if ( !pProperty.is() )
299 throw UnknownPropertyException(aPropertyName);
300 unoToSbxValue( pProperty.get(), aValue );
303 Any SAL_CALL
304 DocObjectWrapper::getValue( const OUString& aPropertyName )
306 if ( m_xAggInv.is() && m_xAggInv->hasProperty( aPropertyName ) )
307 return m_xAggInv->getValue( aPropertyName );
309 SbPropertyRef pProperty = getProperty( aPropertyName );
310 if ( !pProperty.is() )
311 throw UnknownPropertyException(aPropertyName);
313 SbxVariable* pProp = pProperty.get();
314 if ( pProp->GetType() == SbxEMPTY )
315 pProperty->Broadcast( SfxHintId::BasicDataWanted );
317 Any aRet = sbxToUnoValue( pProp );
318 return aRet;
321 sal_Bool SAL_CALL
322 DocObjectWrapper::hasMethod( const OUString& aName )
324 if ( m_xAggInv.is() && m_xAggInv->hasMethod( aName ) )
325 return true;
326 return getMethod( aName ).is();
329 sal_Bool SAL_CALL
330 DocObjectWrapper::hasProperty( const OUString& aName )
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;
339 Any SAL_CALL DocObjectWrapper::queryInterface( const Type& aType )
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;
349 SbMethodRef DocObjectWrapper::getMethod( const OUString& aName )
351 SbMethodRef pMethod;
352 if ( m_pMod )
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 );
361 return pMethod;
364 SbPropertyRef DocObjectWrapper::getProperty( const OUString& aName )
366 SbPropertyRef pProperty;
367 if ( m_pMod )
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 );
376 return pProperty;
380 uno::Reference< frame::XModel > getDocumentModel( StarBASIC* pb )
382 uno::Reference< frame::XModel > xModel;
383 if( pb && pb->IsDocBasic() )
385 uno::Any aDoc;
386 if( pb->GetUNOConstant( "ThisComponent", aDoc ) )
387 xModel.set( aDoc, uno::UNO_QUERY );
389 return xModel;
392 static uno::Reference< vba::XVBACompatibility > getVBACompatibility( const uno::Reference< frame::XModel >& rxModel )
394 uno::Reference< vba::XVBACompatibility > xVBACompat;
397 uno::Reference< beans::XPropertySet > xModelProps( rxModel, uno::UNO_QUERY_THROW );
398 xVBACompat.set( xModelProps->getPropertyValue( "BasicLibraries" ), uno::UNO_QUERY );
400 catch(const uno::Exception& )
403 return xVBACompat;
406 static bool getDefaultVBAMode( StarBASIC* pb )
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();
415 // A Basic module has set EXTSEARCH, so that the elements, that the module contains,
416 // could be found from other module.
418 SbModule::SbModule( const OUString& rName, bool bVBACompat )
419 : SbxObject( "StarBASICModule" ),
420 pImage(nullptr), pBreaks(nullptr), mbVBACompat( bVBACompat ), bIsProxyModule( false )
422 SetName( rName );
423 SetFlag( SbxFlagBits::ExtSearch | SbxFlagBits::GlobalSearch );
424 SetModuleType( script::ModuleType::NORMAL );
426 // #i92642: Set name property to initial name
427 SbxVariable* pNameProp = pProps->Find( "Name", SbxClassType::Property );
428 if( pNameProp != nullptr )
430 pNameProp->PutString( GetName() );
434 SbModule::~SbModule()
436 SAL_INFO("basic","Module named " << GetName() << " is destructing");
437 delete pImage;
438 delete pBreaks;
439 pClassData.reset();
440 mxWrapper = nullptr;
443 uno::Reference< script::XInvocation > const &
444 SbModule::GetUnoModule()
446 if ( !mxWrapper.is() )
447 mxWrapper = new DocObjectWrapper( this );
449 SAL_INFO("basic","Module named " << GetName() << " returning wrapper mxWrapper (0x" << mxWrapper.get() <<")" );
450 return mxWrapper;
453 bool SbModule::IsCompiled() const
455 return pImage != nullptr;
458 const SbxObject* SbModule::FindType( const OUString& aTypeName ) const
460 return pImage ? pImage->FindType( aTypeName ) : nullptr;
464 // From the code generator: deletion of images and the opposite of validation for entries
466 void SbModule::StartDefinitions()
468 delete pImage; pImage = nullptr;
469 if( pClassData )
470 pClassData->clear();
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++ )
477 SbMethod* p = dynamic_cast<SbMethod*>( pMethods->Get32( i ) );
478 if( p )
479 p->bInvalid = true;
481 for( i = 0; i < pProps->Count32(); )
483 SbProperty* p = dynamic_cast<SbProperty*>( pProps->Get32( i ) );
484 if( p )
485 pProps->Remove( i );
486 else
487 i++;
491 // request/create method
493 SbMethod* SbModule::GetMethod( const OUString& rName, SbxDataType t )
495 SbxVariable* p = pMethods->Find( rName, SbxClassType::Method );
496 SbMethod* pMeth = dynamic_cast<SbMethod*>( p );
497 if( p && !pMeth )
499 pMethods->Remove( p );
501 if( !pMeth )
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);
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 )
518 pMeth->SetFlag( SbxFlagBits::Fixed );
520 return pMeth;
523 SbMethod* SbModule::FindMethod( const OUString& rName, SbxClassType t )
525 return dynamic_cast<SbMethod*> (pMethods->Find( rName, t ));
529 // request/create property
531 SbProperty* SbModule::GetProperty( const OUString& rName, SbxDataType t )
533 SbxVariable* p = pProps->Find( rName, SbxClassType::Property );
534 SbProperty* pProp = dynamic_cast<SbProperty*>( p );
535 if( p && !pProp )
537 pProps->Remove( p );
539 if( !pProp )
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);
547 return pProp;
550 void SbModule::GetProcedureProperty( const OUString& rName, SbxDataType t )
552 SbxVariable* p = pProps->Find( rName, SbxClassType::Property );
553 SbProcedureProperty* pProp = dynamic_cast<SbProcedureProperty*>( p );
554 if( p && !pProp )
556 pProps->Remove( p );
558 if( !pProp )
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);
568 void SbModule::GetIfaceMapperMethod( const OUString& rName, SbMethod* pImplMeth )
570 SbxVariable* p = pMethods->Find( rName, SbxClassType::Method );
571 SbIfaceMapperMethod* pMapperMethod = dynamic_cast<SbIfaceMapperMethod*>( p );
572 if( p && !pMapperMethod )
574 pMethods->Remove( p );
576 if( !pMapperMethod )
578 pMapperMethod = new SbIfaceMapperMethod( rName, pImplMeth );
579 pMapperMethod->SetParent( this );
580 pMapperMethod->SetFlags( SbxFlagBits::Read );
581 pMethods->Put32( pMapperMethod, pMethods->Count32() );
583 pMapperMethod->bInvalid = false;
586 SbIfaceMapperMethod::~SbIfaceMapperMethod()
591 // From the code generator: remove invalid entries
593 void SbModule::EndDefinitions( bool bNewState )
595 for( sal_uInt32 i = 0; i < pMethods->Count32(); )
597 SbMethod* p = dynamic_cast<SbMethod*>( pMethods->Get32( i ) );
598 if( p )
600 if( p->bInvalid )
602 pMethods->Remove( p );
604 else
606 p->bInvalid = bNewState;
607 i++;
610 else
611 i++;
613 SetModified( true );
616 void SbModule::Clear()
618 delete pImage; pImage = nullptr;
619 if( pClassData )
620 pClassData->clear();
621 SbxObject::Clear();
625 SbxVariable* SbModule::Find( const OUString& rName, SbxClassType t )
627 // make sure a search in an uninstantiated class module will fail
628 SbxVariable* pRes = SbxObject::Find( rName, t );
629 if ( bIsProxyModule && !GetSbData()->bRunInit )
631 return nullptr;
633 if( !pRes && pImage )
635 SbiInstance* pInst = GetSbData()->pInst;
636 if( pInst && pInst->IsCompatibility() )
638 // Put enum types as objects into module,
639 // allows MyEnum.First notation
640 SbxArrayRef xArray = pImage->GetEnums();
641 if( xArray.is() )
643 SbxVariable* pEnumVar = xArray->Find( rName, SbxClassType::DontCare );
644 SbxObject* pEnumObject = dynamic_cast<SbxObject*>( pEnumVar );
645 if( pEnumObject )
647 bool bPrivate = pEnumObject->IsSet( SbxFlagBits::Private );
648 OUString aEnumName = pEnumObject->GetName();
650 pRes = new SbxVariable( SbxOBJECT );
651 pRes->SetName( aEnumName );
652 pRes->SetParent( this );
653 pRes->SetFlag( SbxFlagBits::Read );
654 if( bPrivate )
656 pRes->SetFlag( SbxFlagBits::Private );
658 pRes->PutObject( pEnumObject );
663 return pRes;
666 // Parent and BASIC are one!
668 void SbModule::SetParent( SbxObject* p )
670 pParent = p;
673 void SbModule::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
675 const SbxHint* pHint = dynamic_cast<const SbxHint*>(&rHint);
676 if( !pHint )
677 return;
679 SbxVariable* pVar = pHint->GetVar();
680 SbProperty* pProp = dynamic_cast<SbProperty*>( pVar );
681 SbMethod* pMeth = dynamic_cast<SbMethod*>( pVar );
682 SbProcedureProperty* pProcProperty = dynamic_cast<SbProcedureProperty*>( pVar );
683 if( pProcProperty )
686 if( pHint->GetId() == SfxHintId::BasicDataWanted )
688 OUString aProcName = "Property Get "
689 + pProcProperty->GetName();
691 SbxVariable* pMethVar = Find( aProcName, SbxClassType::Method );
692 if( pMethVar )
694 SbxValues aVals;
695 aVals.eType = SbxVARIANT;
697 SbxArray* pArg = pVar->GetParameters();
698 sal_uInt32 nVarParCount = (pArg != nullptr) ? pArg->Count32() : 0;
699 if( nVarParCount > 1 )
701 auto xMethParameters = tools::make_ref<SbxArray>();
702 xMethParameters->Put32( pMethVar, 0 ); // Method as parameter 0
703 for( sal_uInt32 i = 1 ; i < nVarParCount ; ++i )
705 SbxVariable* pPar = pArg->Get32( i );
706 xMethParameters->Put32( pPar, i );
709 pMethVar->SetParameters( xMethParameters.get() );
710 pMethVar->Get( aVals );
711 pMethVar->SetParameters( nullptr );
713 else
715 pMethVar->Get( aVals );
718 pVar->Put( aVals );
721 else if( pHint->GetId() == SfxHintId::BasicDataChanged )
723 SbxVariable* pMethVar = nullptr;
725 bool bSet = pProcProperty->isSet();
726 if( bSet )
728 pProcProperty->setSet( false );
730 OUString aProcName = "Property Set "
731 + pProcProperty->GetName();
732 pMethVar = Find( aProcName, SbxClassType::Method );
734 if( !pMethVar ) // Let
736 OUString aProcName = "Property Let "
737 + pProcProperty->GetName();
738 pMethVar = Find( aProcName, SbxClassType::Method );
741 if( pMethVar )
743 // Setup parameters
744 SbxArrayRef xArray = new SbxArray;
745 xArray->Put32( pMethVar, 0 ); // Method as parameter 0
746 xArray->Put32( pVar, 1 );
747 pMethVar->SetParameters( xArray.get() );
749 SbxValues aVals;
750 pMethVar->Get( aVals );
751 pMethVar->SetParameters( nullptr );
755 if( pProp )
757 if( pProp->GetModule() != this )
758 SetError( ERRCODE_BASIC_BAD_ACTION );
760 else if( pMeth )
762 if( pHint->GetId() == SfxHintId::BasicDataWanted )
764 if( pMeth->bInvalid && !Compile() )
766 // auto compile has not worked!
767 StarBASIC::Error( ERRCODE_BASIC_BAD_PROP_VALUE );
769 else
771 // Call of a subprogram
772 SbModule* pOld = GetSbData()->pMod;
773 GetSbData()->pMod = this;
774 Run( static_cast<SbMethod*>(pVar) );
775 GetSbData()->pMod = pOld;
779 else
781 // #i92642: Special handling for name property to avoid
782 // side effects when using name as variable implicitly
783 bool bForwardToSbxObject = true;
785 const SfxHintId nId = pHint->GetId();
786 if( (nId == SfxHintId::BasicDataWanted || nId == SfxHintId::BasicDataChanged) &&
787 pVar->GetName().equalsIgnoreAsciiCase( "name" ) )
789 bForwardToSbxObject = false;
791 if( bForwardToSbxObject )
793 SbxObject::Notify( rBC, rHint );
798 // The setting of the source makes the image invalid
799 // and scans the method definitions newly in
801 void SbModule::SetSource32( const OUString& r )
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() );
810 while( !aTok.IsEof() )
812 SbiToken eEndTok = NIL;
814 // Searching for SUB or FUNCTION
815 SbiToken eLastTok = NIL;
816 while( !aTok.IsEof() )
818 // #32385: not by declare
819 SbiToken eCurTok = aTok.Next();
820 if( eLastTok != DECLARE )
822 if( eCurTok == SUB )
824 eEndTok = ENDSUB; break;
826 if( eCurTok == FUNCTION )
828 eEndTok = ENDFUNC; break;
830 if( eCurTok == PROPERTY )
832 eEndTok = ENDPROPERTY; break;
834 if( eCurTok == OPTION )
836 eCurTok = aTok.Next();
837 if( eCurTok == COMPATIBLE )
839 aTok.SetCompatible( true );
841 else if ( ( eCurTok == VBASUPPORT ) && ( aTok.Next() == NUMBER ) )
843 bool bIsVBA = ( aTok.GetDbl()== 1 );
844 SetVBACompat( bIsVBA );
845 aTok.SetCompatible( bIsVBA );
849 eLastTok = eCurTok;
851 // Definition of the method
852 SbMethod* pMeth = nullptr;
853 if( eEndTok != NIL )
855 sal_uInt16 nLine1 = aTok.GetLine();
856 if( aTok.Next() == SYMBOL )
858 OUString aName_( aTok.GetSym() );
859 SbxDataType t = aTok.GetType();
860 if( t == SbxVARIANT && eEndTok == ENDSUB )
862 t = SbxVOID;
864 pMeth = GetMethod( aName_, t );
865 pMeth->nLine1 = pMeth->nLine2 = nLine1;
866 // The method is for a start VALID
867 pMeth->bInvalid = false;
869 else
871 eEndTok = NIL;
874 // Skip up to END SUB/END FUNCTION
875 if( eEndTok != NIL )
877 while( !aTok.IsEof() )
879 if( aTok.Next() == eEndTok )
881 pMeth->nLine2 = aTok.GetLine();
882 break;
885 if( aTok.IsEof() )
887 pMeth->nLine2 = aTok.GetLine();
891 EndDefinitions( true );
894 // Broadcast of a hint to all Basics
896 static void SendHint_( SbxObject* pObj, SfxHintId nId, SbMethod* p )
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++ )
905 SbxVariable* pVar = pObjs->Get32( i );
906 if( dynamic_cast<const SbxObject *>(pVar) != nullptr )
907 SendHint_( dynamic_cast<SbxObject*>( pVar), nId, p );
911 static void SendHint( SbxObject* pObj, SfxHintId nId, SbMethod* p )
913 while( pObj->GetParent() )
914 pObj = pObj->GetParent();
915 SendHint_( pObj, nId, p );
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 )
922 // delete the return value of CreateUnoService
923 SbxVariable* pVar = pBasic->GetRtl()->Find( "CreateUnoService", SbxClassType::Method );
924 if( pVar )
926 pVar->SbxValue::Clear();
928 // delete the return value of CreateUnoDialog
929 pVar = pBasic->GetRtl()->Find( "CreateUnoDialog", SbxClassType::Method );
930 if( pVar )
932 pVar->SbxValue::Clear();
934 // delete the return value of CDec
935 pVar = pBasic->GetRtl()->Find( "CDec", SbxClassType::Method );
936 if( pVar )
938 pVar->SbxValue::Clear();
940 // delete return value of CreateObject
941 pVar = pBasic->GetRtl()->Find( "CreateObject", SbxClassType::Method );
942 if( pVar )
944 pVar->SbxValue::Clear();
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++ )
951 SbxVariable* pObjVar = pObjs->Get32( i );
952 StarBASIC* pSubBasic = dynamic_cast<StarBASIC*>( pObjVar );
953 if( pSubBasic )
955 ClearUnoObjectsInRTL_Impl_Rek( pSubBasic );
960 static void ClearUnoObjectsInRTL_Impl( StarBASIC* pBasic )
962 // #67781 Delete return values of the Uno-methods
963 clearUnoMethods();
965 ClearUnoObjectsInRTL_Impl_Rek( pBasic );
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) );
976 void SbModule::SetVBACompat( bool bCompat )
978 if( mbVBACompat == bCompat )
979 return;
981 mbVBACompat = bCompat;
982 // initialize VBA document API
983 if( mbVBACompat ) try
985 StarBASIC* pBasic = static_cast< StarBASIC* >( GetParent() );
986 uno::Reference< lang::XMultiServiceFactory > xFactory( getDocumentModel( pBasic ), uno::UNO_QUERY_THROW );
987 xFactory->createInstance( "ooo.vba.VBAGlobals" );
989 catch( Exception& )
994 namespace
996 class RunInitGuard
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)
1008 m_xRt->pNext = pSbData->pInst->pRun;
1009 m_pSbData->pMod = pModule;
1010 m_pSbData->pInst->pRun = m_xRt.get();
1012 void run()
1014 while (m_xRt->Step()) {}
1016 virtual ~RunInitGuard()
1018 m_pSbData->pInst->pRun = m_xRt->pNext;
1019 m_pSbData->pMod = m_pOldMod;
1020 m_xRt.reset();
1024 class RunGuard : public RunInitGuard
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)
1033 if (m_xRt->pNext)
1034 m_xRt->pNext->block();
1036 virtual ~RunGuard() override
1038 if (m_xRt->pNext)
1039 m_xRt->pNext->unblock();
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)
1050 // Compare here with 1 instead of 0, because before nCallLvl--
1051 while (m_pSbData->pInst->nCallLvl != 1)
1052 Application::Yield();
1055 m_pSbData->pInst->nCallLvl--; // Call-Level down again
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);
1066 // Run a Basic-subprogram
1067 void SbModule::Run( SbMethod* pMeth )
1069 SAL_INFO("basic","About to run " << pMeth->GetName() << ", vba compatmode is " << mbVBACompat );
1071 static sal_uInt16 nMaxCallLevel = 0;
1073 SbiGlobals* pSbData = GetSbData();
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 )
1082 // #32779: Hold Basic during the execution
1083 xBasic = static_cast<StarBASIC*>( GetParent() );
1085 pSbData->pInst = new SbiInstance( static_cast<StarBASIC*>(GetParent()) );
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 )
1092 StarBASIC* pBasic = static_cast< StarBASIC* >( GetParent() );
1093 if( pBasic && pBasic->IsDocBasic() ) try
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() );
1099 catch(const uno::Exception& )
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 )
1112 StarBASIC* pMSOMacroRuntimeLib = dynamic_cast<StarBASIC*>( pMSOMacroRuntimeLibVar );
1113 if( pMSOMacroRuntimeLib )
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 )
1121 pMSOMacroRuntimeLib->SetFlag( SbxFlagBits::ExtSearch ); // Could have been disabled before
1122 pSbData->pMSOMacroRuntimLib = pMSOMacroRuntimeLib;
1127 if( nMaxCallLevel == 0 )
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
1149 // Recursion to deep?
1150 if( ++pSbData->pInst->nCallLvl <= nMaxCallLevel )
1152 // Define a globale variable in all Mods
1153 GlobalRunInit( /* bBasicStart = */ bDelInst );
1155 // Appeared a compiler error? Then we don't launch
1156 if( !pSbData->bGlobalInitErr )
1158 if( bDelInst )
1160 SendHint( GetParent(), SfxHintId::BasicStart, pMeth );
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() );
1168 auto xRuntimeGuard(std::make_unique<RunGuard>(this, pMeth, pMeth->nStart, pSbData, bDelInst));
1170 if ( mbVBACompat )
1172 pSbData->pInst->EnableCompatibility( true );
1175 xRuntimeGuard->run();
1177 xRuntimeGuard.reset();
1179 if( bDelInst )
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() );
1185 clearNativeObjectWrapperVector();
1187 SAL_WARN_IF(pSbData->pInst->nCallLvl != 0,"basic","BASIC-Call-Level > 0");
1188 delete pSbData->pInst;
1189 pSbData->pInst = nullptr;
1190 bDelInst = false;
1192 // #i30690
1193 SolarMutexGuard aSolarGuard;
1194 SendHint( GetParent(), SfxHintId::BasicStop, pMeth );
1196 GlobalRunDeInit();
1198 if( xVBACompat.is() )
1200 // notify all VBA script listeners about the stopped script
1203 xVBACompat->broadcastVBAScriptEvent( script::vba::VBAScriptEventId::SCRIPT_STOPPED, GetName() );
1205 catch(const uno::Exception& )
1208 // VBA always ensures screenupdating is enabled after completing
1209 ::basic::vba::lockControllersOfAllDocuments( xModel, false );
1210 ::basic::vba::enableContainerWindowsOfAllDocuments( xModel, true );
1214 else
1215 pSbData->pInst->nCallLvl--; // Call-Level down again
1217 else
1219 pSbData->pInst->nCallLvl--; // Call-Level down again
1220 StarBASIC::FatalError( ERRCODE_BASIC_STACK_OVERFLOW );
1223 StarBASIC* pBasic = dynamic_cast<StarBASIC*>( GetParent() );
1224 if( bDelInst )
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() );
1230 delete pSbData->pInst;
1231 pSbData->pInst = nullptr;
1233 if ( pBasic && pBasic->IsDocBasic() && pBasic->IsQuitApplication() && !pSbData->pInst )
1234 bQuit = true;
1235 if ( bQuit )
1237 Application::PostUserEvent( LINK( &AsyncQuitHandler::instance(), AsyncQuitHandler, OnAsyncQuit ) );
1241 // Execute of the init method of a module after the loading
1242 // or the compilation
1243 void SbModule::RunInit()
1245 if( !(pImage
1246 && !pImage->bInit
1247 && pImage->IsFlag( SbiImageFlags::INITCODE )) )
1248 return;
1250 SbiGlobals* pSbData = GetSbData();
1252 // Set flag, so that RunInit get active (Testtool)
1253 pSbData->bRunInit = true;
1255 // The init code starts always here
1256 auto xRuntimeGuard(std::make_unique<RunInitGuard>(this, nullptr, 0, pSbData));
1257 xRuntimeGuard->run();
1258 xRuntimeGuard.reset();
1260 pImage->bInit = true;
1261 pImage->bFirstInit = false;
1263 // RunInit is not active anymore
1264 pSbData->bRunInit = false;
1267 // Delete with private/dim declared variables
1269 void SbModule::AddVarName( const OUString& aName )
1271 // see if the name is added already
1272 for ( const auto& rModuleVariableName: mModuleVariableNames )
1274 if ( aName == rModuleVariableName )
1275 return;
1277 mModuleVariableNames.push_back( aName );
1280 void SbModule::RemoveVars()
1282 for ( const auto& rModuleVariableName: mModuleVariableNames )
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() );
1293 void SbModule::ClearPrivateVars()
1295 for( sal_uInt32 i = 0 ; i < pProps->Count32() ; i++ )
1297 SbProperty* p = dynamic_cast<SbProperty*>( pProps->Get32( i ) );
1298 if( p )
1300 // Delete not the arrays, only their content
1301 if( p->GetType() & SbxARRAY )
1303 SbxArray* pArray = dynamic_cast<SbxArray*>( p->GetObject() );
1304 if( pArray )
1306 for( sal_uInt32 j = 0 ; j < pArray->Count32() ; j++ )
1308 SbxVariable* pj = pArray->Get32( j );
1309 pj->SbxValue::Clear();
1313 else
1315 p->SbxValue::Clear();
1321 void SbModule::implClearIfVarDependsOnDeletedBasic( SbxVariable* pVar, StarBASIC* pDeletedBasic )
1323 if( pVar->SbxValue::GetType() != SbxOBJECT || dynamic_cast<const SbProcedureProperty*>( pVar) != nullptr )
1324 return;
1326 SbxObject* pObj = dynamic_cast<SbxObject*>( pVar->GetObject() );
1327 if( pObj == nullptr )
1328 return;
1330 SbxObject* p = pObj;
1332 SbModule* pMod = dynamic_cast<SbModule*>( p );
1333 if( pMod != nullptr )
1334 pMod->ClearVarsDependingOnDeletedBasic( pDeletedBasic );
1336 while( (p = p->GetParent()) != nullptr )
1338 StarBASIC* pBasic = dynamic_cast<StarBASIC*>( p );
1339 if( pBasic != nullptr && pBasic == pDeletedBasic )
1341 pVar->SbxValue::Clear();
1342 break;
1347 void SbModule::ClearVarsDependingOnDeletedBasic( StarBASIC* pDeletedBasic )
1349 for( sal_uInt32 i = 0 ; i < pProps->Count32() ; i++ )
1351 SbProperty* p = dynamic_cast<SbProperty*>( pProps->Get32( i ) );
1352 if( p )
1354 if( p->GetType() & SbxARRAY )
1356 SbxArray* pArray = dynamic_cast<SbxArray*>( p->GetObject() );
1357 if( pArray )
1359 for( sal_uInt32 j = 0 ; j < pArray->Count32() ; j++ )
1361 SbxVariable* pVar = pArray->Get32( j );
1362 implClearIfVarDependsOnDeletedBasic( pVar, pDeletedBasic );
1366 else
1368 implClearIfVarDependsOnDeletedBasic( p, pDeletedBasic );
1374 void StarBASIC::ClearAllModuleVars()
1376 // Initialise the own module
1377 for (const auto& rModule: pModules)
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();
1386 // Execution of the init-code of all module
1387 void SbModule::GlobalRunInit( bool bBasicStart )
1389 // If no Basic-Start, only initialise, if the module is not initialised
1390 if( !bBasicStart )
1391 if( !pImage || pImage->bInit )
1392 return;
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;
1400 // Parent of the module is a Basic
1401 StarBASIC *pBasic = dynamic_cast<StarBASIC*>( GetParent() );
1402 if( !pBasic )
1403 return;
1405 pBasic->InitAllModules();
1407 SbxObject* pParent_ = pBasic->GetParent();
1408 if( !pParent_ )
1409 return;
1411 StarBASIC * pParentBasic = dynamic_cast<StarBASIC*>( pParent_ );
1412 if( !pParentBasic )
1413 return;
1415 pParentBasic->InitAllModules( pBasic );
1417 // #109018 Parent can also have a parent (library in doc)
1418 SbxObject* pParentParent = pParentBasic->GetParent();
1419 if( pParentParent )
1421 StarBASIC * pParentParentBasic = dynamic_cast<StarBASIC*>( pParentParent );
1422 if( pParentParentBasic )
1423 pParentParentBasic->InitAllModules( pParentBasic );
1427 void SbModule::GlobalRunDeInit()
1429 StarBASIC *pBasic = dynamic_cast<StarBASIC*>( GetParent() );
1430 if( pBasic )
1432 pBasic->DeInitAllModules();
1434 SbxObject* pParent_ = pBasic->GetParent();
1435 if( pParent_ )
1436 pBasic = dynamic_cast<StarBASIC*>( pParent_ );
1437 if( pBasic )
1438 pBasic->DeInitAllModules();
1442 // Search for the next STMNT-Command in the code. This was used from the STMNT-
1443 // Opcode to set the endcolumn.
1445 const sal_uInt8* SbModule::FindNextStmnt( const sal_uInt8* p, sal_uInt16& nLine, sal_uInt16& nCol ) const
1447 return FindNextStmnt( p, nLine, nCol, false );
1450 const sal_uInt8* SbModule::FindNextStmnt( const sal_uInt8* p, sal_uInt16& nLine, sal_uInt16& nCol,
1451 bool bFollowJumps, const SbiImage* pImg ) const
1453 sal_uInt32 nPC = static_cast<sal_uInt32>( p - reinterpret_cast<const sal_uInt8*>(pImage->GetCode()) );
1454 while( nPC < pImage->GetCodeSize() )
1456 SbiOpcode eOp = static_cast<SbiOpcode>( *p++ );
1457 nPC++;
1458 if( bFollowJumps && eOp == SbiOpcode::JUMP_ && pImg )
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;
1465 else if( eOp >= SbiOpcode::SbOP1_START && eOp <= SbiOpcode::SbOP1_END )
1467 p += 4;
1468 nPC += 4;
1470 else if( eOp == SbiOpcode::STMNT_ )
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;
1480 else if( eOp >= SbiOpcode::SbOP2_START && eOp <= SbiOpcode::SbOP2_END )
1482 p += 8;
1483 nPC += 8;
1485 else if( eOp < SbiOpcode::SbOP0_START || eOp > SbiOpcode::SbOP0_END )
1487 StarBASIC::FatalError( ERRCODE_BASIC_INTERNAL_ERROR );
1488 break;
1491 return nullptr;
1494 // Test, if a line contains STMNT-Opcodes
1496 bool SbModule::IsBreakable( sal_uInt16 nLine ) const
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;
1508 bool SbModule::IsBP( sal_uInt16 nLine ) const
1510 if( pBreaks )
1512 for( size_t i = 0; i < pBreaks->size(); i++ )
1514 sal_uInt16 b = pBreaks->operator[]( i );
1515 if( b == nLine )
1516 return true;
1517 if( b < nLine )
1518 break;
1521 return false;
1524 bool SbModule::SetBP( sal_uInt16 nLine )
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 );
1536 // #38568: Set during runtime as well here BasicDebugFlags::Break
1537 if( GetSbData()->pInst && GetSbData()->pInst->pRun )
1538 GetSbData()->pInst->pRun->SetDebugFlags( BasicDebugFlags::Break );
1540 return IsBreakable( nLine );
1543 bool SbModule::ClearBP( sal_uInt16 nLine )
1545 bool bRes = false;
1546 if( pBreaks )
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)
1553 pBreaks->erase(it);
1555 if( pBreaks->empty() )
1557 delete pBreaks;
1558 pBreaks = nullptr;
1561 return bRes;
1564 void SbModule::ClearAllBP()
1566 delete pBreaks;
1567 pBreaks = nullptr;
1570 void
1571 SbModule::fixUpMethodStart( bool bCvtToLegacy, SbiImage* pImg ) const
1573 if ( !pImg )
1574 pImg = pImage;
1575 for( sal_uInt32 i = 0; i < pMethods->Count32(); i++ )
1577 SbMethod* pMeth = dynamic_cast<SbMethod*>( pMethods->Get32(i) );
1578 if( pMeth )
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) );
1590 bool SbModule::LoadData( SvStream& rStrm, sal_uInt16 nVer )
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 )
1601 SbiImage* p = new SbiImage;
1602 sal_uInt32 nImgVer = 0;
1604 if( !p->Load( rStrm, nImgVer ) )
1606 delete p;
1607 return false;
1609 // If the image is in old format, we fix up the method start offsets
1610 if ( nImgVer < B_EXT_IMG_VERSION )
1612 fixUpMethodStart( false, p );
1613 p->ReleaseLegacyBuffer();
1615 aComment = p->aComment;
1616 SetName( p->aName );
1617 if( p->GetCodeSize() )
1619 aOUSource = p->aOUSource;
1620 // Old version: image away
1621 if( nVer == 1 )
1623 SetSource32( p->aOUSource );
1624 delete p;
1626 else
1627 pImage = p;
1629 else
1631 SetSource32( p->aOUSource );
1632 delete p;
1635 return true;
1638 bool SbModule::StoreData( SvStream& rStrm ) const
1640 bool bFixup = ( pImage && !pImage->ExceedsLegacyLimits() );
1641 if ( bFixup )
1642 fixUpMethodStart( true );
1643 bool bRet = SbxObject::StoreData( rStrm );
1644 if ( !bRet )
1645 return false;
1647 if( pImage )
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;
1663 else
1665 SbiImage aImg;
1666 aImg.aOUSource = aOUSource;
1667 aImg.aComment = aComment;
1668 aImg.aName = GetName();
1669 rStrm.WriteUChar( 1 );
1670 return aImg.Save( rStrm );
1674 bool SbModule::ExceedsLegacyModuleSize()
1676 if ( !IsCompiled() )
1677 Compile();
1678 return pImage && pImage->ExceedsLegacyLimits();
1681 namespace {
1683 class ErrorHdlResetter
1685 Link<StarBASIC*,bool> mErrHandler;
1686 bool mbError;
1687 public:
1688 ErrorHdlResetter()
1689 : mErrHandler(StarBASIC::GetGlobalErrorHdl()) // save error handler
1690 , mbError( false )
1692 // set new error handler
1693 StarBASIC::SetGlobalErrorHdl( LINK( this, ErrorHdlResetter, BasicErrorHdl ) );
1695 ~ErrorHdlResetter()
1697 // restore error handler
1698 StarBASIC::SetGlobalErrorHdl(mErrHandler);
1700 DECL_LINK( BasicErrorHdl, StarBASIC *, bool );
1701 bool HasError() const { return mbError; }
1706 IMPL_LINK( ErrorHdlResetter, BasicErrorHdl, StarBASIC *, /*pBasic*/, bool)
1708 mbError = true;
1709 return false;
1712 void SbModule::GetCodeCompleteDataFromParse(CodeCompleteDataCache& aCache)
1714 ErrorHdlResetter aErrHdl;
1715 SbxBase::ResetError();
1717 auto pParser = std::make_unique<SbiParser>(static_cast<StarBASIC*>(GetParent()), this );
1718 pParser->SetCodeCompleting(true);
1720 while( pParser->Parse() ) {}
1721 SbiSymPool* pPool = pParser->pPool;
1722 aCache.Clear();
1723 for( sal_uInt16 i = 0; i < pPool->GetSize(); ++i )
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()) );
1730 SbiSymPool& rChildPool = pSymDef->GetPool();
1731 for(sal_uInt16 j = 0; j < rChildPool.GetSize(); ++j )
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()) );
1742 OUString SbModule::GetKeywordCase( const OUString& sKeyword )
1744 return SbiParser::GetKeywordCase( sKeyword );
1747 bool SbModule::HasExeCode()
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
1753 if (!IsCompiled())
1755 ErrorHdlResetter aGblErrHdl;
1756 Compile();
1757 if (aGblErrHdl.HasError()) //assume unsafe on compile error
1758 return true;
1761 bool bRes = false;
1762 if (pImage && (pImage->GetCodeSize() != 5 || (memcmp(pImage->GetCode(), pEmptyImage, pImage->GetCodeSize()) != 0 )))
1763 bRes = true;
1765 return bRes;
1768 // Store only image, no source
1769 void SbModule::StoreBinaryData( SvStream& rStrm )
1771 if (!Compile())
1772 return;
1774 if (!SbxObject::StoreData(rStrm))
1775 return;
1777 pImage->aOUSource.clear();
1778 pImage->aComment = aComment;
1779 pImage->aName = GetName();
1781 rStrm.WriteUChar(1);
1782 pImage->Save(rStrm);
1784 pImage->aOUSource = aOUSource;
1787 // Called for >= OO 1.0 passwd protected libraries only
1789 void SbModule::LoadBinaryData( SvStream& rStrm )
1791 OUString aKeepSource = aOUSource;
1792 LoadData( rStrm, 2 );
1793 LoadCompleted();
1794 aOUSource = aKeepSource;
1797 bool SbModule::LoadCompleted()
1799 SbxArray* p = GetMethods().get();
1800 sal_uInt32 i;
1801 for( i = 0; i < p->Count32(); i++ )
1803 SbMethod* q = dynamic_cast<SbMethod*>( p->Get32( i ) );
1804 if( q )
1805 q->pMod = this;
1807 p = GetProperties();
1808 for( i = 0; i < p->Count32(); i++ )
1810 SbProperty* q = dynamic_cast<SbProperty*>( p->Get32( i ) );
1811 if( q )
1812 q->pMod = this;
1814 return true;
1817 void SbModule::handleProcedureProperties( SfxBroadcaster& rBC, const SfxHint& rHint )
1819 bool bDone = false;
1821 const SbxHint* pHint = dynamic_cast<const SbxHint*>(&rHint);
1822 if( pHint )
1824 SbxVariable* pVar = pHint->GetVar();
1825 SbProcedureProperty* pProcProperty = dynamic_cast<SbProcedureProperty*>( pVar );
1826 if( pProcProperty )
1828 bDone = true;
1830 if( pHint->GetId() == SfxHintId::BasicDataWanted )
1832 OUString aProcName = "Property Get "
1833 + pProcProperty->GetName();
1835 SbxVariable* pMeth = Find( aProcName, SbxClassType::Method );
1836 if( pMeth )
1838 SbxValues aVals;
1839 aVals.eType = SbxVARIANT;
1841 SbxArray* pArg = pVar->GetParameters();
1842 sal_uInt32 nVarParCount = (pArg != nullptr) ? pArg->Count32() : 0;
1843 if( nVarParCount > 1 )
1845 SbxArrayRef xMethParameters = new SbxArray;
1846 xMethParameters->Put32( pMeth, 0 ); // Method as parameter 0
1847 for( sal_uInt32 i = 1 ; i < nVarParCount ; ++i )
1849 SbxVariable* pPar = pArg->Get32( i );
1850 xMethParameters->Put32( pPar, i );
1853 pMeth->SetParameters( xMethParameters.get() );
1854 pMeth->Get( aVals );
1855 pMeth->SetParameters( nullptr );
1857 else
1859 pMeth->Get( aVals );
1862 pVar->Put( aVals );
1865 else if( pHint->GetId() == SfxHintId::BasicDataChanged )
1867 SbxVariable* pMeth = nullptr;
1869 bool bSet = pProcProperty->isSet();
1870 if( bSet )
1872 pProcProperty->setSet( false );
1874 OUString aProcName = "Property Set "
1875 + pProcProperty->GetName();
1876 pMeth = Find( aProcName, SbxClassType::Method );
1878 if( !pMeth ) // Let
1880 OUString aProcName = "Property Let "
1881 + pProcProperty->GetName();
1882 pMeth = Find( aProcName, SbxClassType::Method );
1885 if( pMeth )
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() );
1893 SbxValues aVals;
1894 pMeth->Get( aVals );
1895 pMeth->SetParameters( nullptr );
1901 if( !bDone )
1902 SbModule::Notify( rBC, rHint );
1906 // Implementation SbJScriptModule (Basic module for JavaScript source code)
1907 SbJScriptModule::SbJScriptModule()
1908 :SbModule( "" )
1912 bool SbJScriptModule::LoadData( SvStream& rStrm, sal_uInt16 )
1914 Clear();
1915 if( !SbxObject::LoadData( rStrm, 1 ) )
1916 return false;
1918 // Get the source string
1919 aOUSource = rStrm.ReadUniOrByteString( osl_getThreadTextEncoding() );
1920 return true;
1923 bool SbJScriptModule::StoreData( SvStream& rStrm ) const
1925 if( !SbxObject::StoreData( rStrm ) )
1926 return false;
1928 // Write the source string
1929 OUString aTmp = aOUSource;
1930 rStrm.WriteUniOrByteString( aTmp, osl_getThreadTextEncoding() );
1931 return true;
1935 SbMethod::SbMethod( const OUString& r, SbxDataType t, SbModule* p )
1936 : SbxMethod( r, t ), pMod( p )
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 );
1949 SbMethod::SbMethod( const SbMethod& r )
1950 : SvRefBase( r ), SbxMethod( r )
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 );
1963 SbMethod::~SbMethod()
1967 void SbMethod::ClearStatics()
1969 refStatics = new SbxArray;
1972 SbxArray* SbMethod::GetStatics()
1974 return refStatics.get();
1977 bool SbMethod::LoadData( SvStream& rStrm, sal_uInt16 nVer )
1979 if( !SbxMethod::LoadData( rStrm, 1 ) )
1980 return false;
1982 sal_uInt16 nFlag;
1983 rStrm.ReadUInt16( nFlag );
1985 sal_Int16 nTempStart = static_cast<sal_Int16>(nStart);
1987 if( nVer == 2 )
1989 rStrm.ReadUInt16( nLine1 ).ReadUInt16( nLine2 ).ReadInt16( nTempStart ).ReadCharAsBool( bInvalid );
1990 //tdf#94617
1991 if (nFlag & 0x8000)
1993 sal_uInt16 nMult = nFlag & 0x7FFF;
1994 sal_Int16 const nMax = std::numeric_limits<sal_Int16>::max();
1995 nStart = nMult * nMax + nTempStart;
1997 else
1999 nStart = nTempStart;
2002 else
2004 nStart = nTempStart;
2007 // HACK due to 'Reference could not be saved'
2008 SetFlag( SbxFlagBits::NoModify );
2010 return true;
2013 bool SbMethod::StoreData( SvStream& rStrm ) const
2015 if( !SbxMethod::StoreData( rStrm ) )
2016 return false;
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;
2024 rStrm.WriteUInt16( nDebugFlagsTemp )
2025 .WriteInt16( nLine1 )
2026 .WriteInt16( nLine2 )
2027 .WriteInt16( nStartTemp )
2028 .WriteBool( bInvalid );
2030 return true;
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 Get( aVals );
2069 if ( pRet )
2070 pRet->Put( aVals );
2072 // Was there an error
2073 ErrCode nErr = SbxBase::GetError();
2074 SbxBase::ResetError();
2076 mCaller = nullptr;
2077 return nErr;
2081 // #100883 Own Broadcast for SbMethod
2082 void SbMethod::Broadcast( SfxHintId nHintId )
2084 if( !mpBroadcaster || IsSet( SbxFlagBits::NoBroadcast ) )
2085 return;
2087 // Because the method could be called from outside, test here once again
2088 // the authorisation
2089 if( nHintId == SfxHintId::BasicDataWanted )
2090 if( !CanRead() )
2091 return;
2092 if( nHintId == SfxHintId::BasicDataChanged )
2093 if( !CanWrite() )
2094 return;
2096 if( pMod && !pMod->IsCompiled() )
2097 pMod->Compile();
2099 // Block broadcasts while creating new method
2100 std::unique_ptr<SfxBroadcaster> pSaveBroadcaster = std::move(mpBroadcaster);
2101 SbMethod* pThisCopy = new SbMethod( *this );
2102 SbMethodRef xHolder = pThisCopy;
2103 if( mpPar.is() )
2105 // Enregister this as element 0, but don't reset the parent!
2106 if( GetType() != SbxVOID ) {
2107 mpPar->PutDirect( pThisCopy, 0 );
2109 SetParameters( nullptr );
2112 mpBroadcaster = std::move(pSaveBroadcaster);
2113 mpBroadcaster->Broadcast( SbxHint( nHintId, pThisCopy ) );
2115 SbxFlagBits nSaveFlags = GetFlags();
2116 SetFlag( SbxFlagBits::ReadWrite );
2117 pSaveBroadcaster = std::move(mpBroadcaster);
2118 Put( pThisCopy->GetValues_Impl() );
2119 mpBroadcaster = std::move(pSaveBroadcaster);
2120 SetFlags( nSaveFlags );
2124 // Implementation of SbJScriptMethod (method class as a wrapper for JavaScript-functions)
2126 SbJScriptMethod::SbJScriptMethod( SbxDataType t )
2127 : SbMethod( "", t, nullptr )
2131 SbJScriptMethod::~SbJScriptMethod()
2135 SbObjModule::SbObjModule( const OUString& rName, const css::script::ModuleInfo& mInfo, bool bIsVbaCompatible )
2136 : SbModule( rName, bIsVbaCompatible )
2138 SetModuleType( mInfo.ModuleType );
2139 if ( mInfo.ModuleType == script::ModuleType::FORM )
2141 SetClassName( "Form" );
2143 else if ( mInfo.ModuleObject.is() )
2145 SetUnoObject( uno::Any( mInfo.ModuleObject ) );
2149 SbObjModule::~SbObjModule()
2153 void
2154 SbObjModule::SetUnoObject( const uno::Any& aObj )
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 );
2161 css::uno::Reference< css::lang::XServiceInfo > xServiceInfo( aObj, css::uno::UNO_QUERY_THROW );
2162 if( xServiceInfo->supportsService( "ooo.vba.excel.Worksheet" ) )
2164 SetClassName( "Worksheet" );
2166 else if( xServiceInfo->supportsService( "ooo.vba.excel.Workbook" ) )
2168 SetClassName( "Workbook" );
2172 SbxVariable*
2173 SbObjModule::GetObject()
2175 return pDocObject.get();
2177 SbxVariable*
2178 SbObjModule::Find( const OUString& rName, SbxClassType t )
2180 SbxVariable* pVar = nullptr;
2181 if ( pDocObject )
2182 pVar = pDocObject->Find( rName, t );
2183 if ( !pVar )
2184 pVar = SbModule::Find( rName, t );
2185 return pVar;
2188 void SbObjModule::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
2190 SbModule::handleProcedureProperties( rBC, rHint );
2194 typedef ::cppu::WeakImplHelper<
2195 awt::XTopWindowListener,
2196 awt::XWindowListener,
2197 document::XDocumentEventListener > FormObjEventListener_BASE;
2199 class FormObjEventListenerImpl:
2200 public FormObjEventListener_BASE
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;
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 )
2217 if ( mxComponent.is() )
2221 uno::Reference< awt::XTopWindow >( mxComponent, uno::UNO_QUERY_THROW )->addTopWindowListener( this );
2223 catch(const uno::Exception& ) {}
2226 uno::Reference< awt::XWindow >( mxComponent, uno::UNO_QUERY_THROW )->addWindowListener( this );
2228 catch(const uno::Exception& ) {}
2231 if ( mxModel.is() )
2235 uno::Reference< document::XDocumentEventBroadcaster >( mxModel, uno::UNO_QUERY_THROW )->addDocumentEventListener( this );
2237 catch(const uno::Exception& ) {}
2241 virtual ~FormObjEventListenerImpl() override
2243 removeListener();
2246 bool isShowing() const { return mbShowing; }
2248 void removeListener()
2250 if ( mxComponent.is() && !mbDisposed )
2254 uno::Reference< awt::XTopWindow >( mxComponent, uno::UNO_QUERY_THROW )->removeTopWindowListener( this );
2256 catch(const uno::Exception& ) {}
2259 uno::Reference< awt::XWindow >( mxComponent, uno::UNO_QUERY_THROW )->removeWindowListener( this );
2261 catch(const uno::Exception& ) {}
2263 mxComponent.clear();
2265 if ( mxModel.is() && !mbDisposed )
2269 uno::Reference< document::XDocumentEventBroadcaster >( mxModel, uno::UNO_QUERY_THROW )->removeDocumentEventListener( this );
2271 catch(const uno::Exception& ) {}
2273 mxModel.clear();
2276 virtual void SAL_CALL windowOpened( const lang::EventObject& /*e*/ ) override
2278 if ( mpUserForm )
2280 mbOpened = true;
2281 mbShowing = true;
2282 if ( mbActivated )
2284 mbOpened = mbActivated = false;
2285 mpUserForm->triggerActivateEvent();
2291 virtual void SAL_CALL windowClosing( const lang::EventObject& /*e*/ ) override
2293 #ifdef IN_THE_FUTURE
2294 uno::Reference< awt::XDialog > xDialog( e.Source, uno::UNO_QUERY );
2295 if ( xDialog.is() )
2297 uno::Reference< awt::XControl > xControl( xDialog, uno::UNO_QUERY );
2298 if ( xControl->getPeer().is() )
2300 uno::Reference< document::XVbaMethodParameter > xVbaMethodParameter( xControl->getPeer(), uno::UNO_QUERY );
2301 if ( xVbaMethodParameter.is() )
2303 sal_Int8 nCancel = 0;
2304 sal_Int8 nCloseMode = ::ooo::vba::VbQueryClose::vbFormControlMenu;
2306 Sequence< Any > aParams;
2307 aParams.realloc(2);
2308 aParams[0] <<= nCancel;
2309 aParams[1] <<= nCloseMode;
2311 mpUserForm->triggerMethod( "Userform_QueryClose", aParams);
2312 return;
2318 mpUserForm->triggerMethod( "Userform_QueryClose" );
2319 #endif
2323 virtual void SAL_CALL windowClosed( const lang::EventObject& /*e*/ ) override
2325 mbOpened = false;
2326 mbShowing = false;
2329 virtual void SAL_CALL windowMinimized( const lang::EventObject& /*e*/ ) override
2333 virtual void SAL_CALL windowNormalized( const lang::EventObject& /*e*/ ) override
2337 virtual void SAL_CALL windowActivated( const lang::EventObject& /*e*/ ) override
2339 if ( mpUserForm )
2341 mbActivated = true;
2342 if ( mbOpened )
2344 mbOpened = mbActivated = false;
2345 mpUserForm->triggerActivateEvent();
2350 virtual void SAL_CALL windowDeactivated( const lang::EventObject& /*e*/ ) override
2352 if ( mpUserForm )
2353 mpUserForm->triggerDeactivateEvent();
2356 virtual void SAL_CALL windowResized( const awt::WindowEvent& /*e*/ ) override
2358 if ( mpUserForm )
2360 mpUserForm->triggerResizeEvent();
2361 mpUserForm->triggerLayoutEvent();
2365 virtual void SAL_CALL windowMoved( const awt::WindowEvent& /*e*/ ) override
2367 if ( mpUserForm )
2368 mpUserForm->triggerLayoutEvent();
2371 virtual void SAL_CALL windowShown( const lang::EventObject& /*e*/ ) override
2375 virtual void SAL_CALL windowHidden( const lang::EventObject& /*e*/ ) override
2379 virtual void SAL_CALL documentEventOccured( const document::DocumentEvent& rEvent ) override
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 ) )
2384 removeListener();
2385 mbDisposed = true;
2386 if ( mpUserForm )
2387 mpUserForm->ResetApiObj(); // will trigger "UserForm_Terminate"
2391 virtual void SAL_CALL disposing( const lang::EventObject& /*Source*/ ) override
2393 removeListener();
2394 mbDisposed = true;
2395 if ( mpUserForm )
2396 mpUserForm->ResetApiObj( false ); // pass false (too late to trigger VBA events here)
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 )
2405 m_xModel.set( mInfo.ModuleObject, uno::UNO_QUERY_THROW );
2408 SbUserFormModule::~SbUserFormModule()
2412 void SbUserFormModule::ResetApiObj( bool bTriggerTerminateEvent )
2414 SAL_INFO("basic", " SbUserFormModule::ResetApiObj( " << (bTriggerTerminateEvent ? "true )" : "false )") );
2415 if ( bTriggerTerminateEvent && m_xDialog.is() ) // probably someone close the dialog window
2417 triggerTerminateEvent();
2419 pDocObject = nullptr;
2420 m_xDialog = nullptr;
2423 void SbUserFormModule::triggerMethod( const OUString& aMethodToRun )
2425 Sequence< Any > aArguments;
2426 triggerMethod( aMethodToRun, aArguments );
2429 void SbUserFormModule::triggerMethod( const OUString& aMethodToRun, Sequence< Any >& aArguments )
2431 SAL_INFO("basic", "trigger " << aMethodToRun);
2432 // Search method
2433 SbxVariable* pMeth = SbObjModule::Find( aMethodToRun, SbxClassType::Method );
2434 if( !pMeth )
2435 return;
2437 if ( aArguments.hasElements() ) // Setup parameters
2439 auto xArray = tools::make_ref<SbxArray>();
2440 xArray->Put32( pMeth, 0 ); // Method as parameter 0
2442 for ( sal_Int32 i = 0; i < aArguments.getLength(); ++i )
2444 auto xSbxVar = tools::make_ref<SbxVariable>( SbxVARIANT );
2445 unoToSbxValue( xSbxVar.get(), aArguments[i] );
2446 xArray->Put32( xSbxVar.get(), static_cast< sal_uInt32 >( i ) + 1 );
2448 // Enable passing by ref
2449 if ( xSbxVar->GetType() != SbxVARIANT )
2450 xSbxVar->SetFlag( SbxFlagBits::Fixed );
2452 pMeth->SetParameters( xArray.get() );
2454 SbxValues aVals;
2455 pMeth->Get( aVals );
2457 for ( sal_Int32 i = 0; i < aArguments.getLength(); ++i )
2459 aArguments[i] = sbxToUnoValue( xArray->Get32( static_cast< sal_uInt32 >(i) + 1) );
2461 pMeth->SetParameters( nullptr );
2463 else
2465 SbxValues aVals;
2466 pMeth->Get( aVals );
2470 void SbUserFormModule::triggerActivateEvent()
2472 triggerMethod( "UserForm_Activate" );
2475 void SbUserFormModule::triggerDeactivateEvent()
2477 triggerMethod( "Userform_Deactivate" );
2480 void SbUserFormModule::triggerInitializeEvent()
2482 if ( mbInit )
2483 return;
2484 triggerMethod("Userform_Initialize");
2485 mbInit = true;
2488 void SbUserFormModule::triggerTerminateEvent()
2490 triggerMethod("Userform_Terminate");
2491 mbInit=false;
2494 void SbUserFormModule::triggerLayoutEvent()
2496 triggerMethod("Userform_Layout");
2499 void SbUserFormModule::triggerResizeEvent()
2501 triggerMethod("Userform_Resize");
2504 SbUserFormModuleInstance* SbUserFormModule::CreateInstance()
2506 SbUserFormModuleInstance* pInstance = new SbUserFormModuleInstance( this, GetName(), m_mInfo, IsVBACompat() );
2507 return pInstance;
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 )
2517 bool SbUserFormModuleInstance::IsClass( const OUString& rName ) const
2519 bool bParentNameMatches = m_pParentModule->GetName().equalsIgnoreAsciiCase( rName );
2520 bool bRet = bParentNameMatches || SbxObject::IsClass( rName );
2521 return bRet;
2524 SbxVariable* SbUserFormModuleInstance::Find( const OUString& rName, SbxClassType t )
2526 SbxVariable* pVar = m_pParentModule->Find( rName, t );
2527 return pVar;
2531 void SbUserFormModule::Load()
2533 // forces a load
2534 if ( !pDocObject.is() )
2535 InitObject();
2539 void SbUserFormModule::Unload()
2541 sal_Int8 nCancel = 0;
2543 Sequence< Any > aParams;
2544 aParams.realloc(2);
2545 aParams[0] <<= nCancel;
2546 aParams[1] <<= sal_Int8(::ooo::vba::VbQueryClose::vbFormCode);
2548 triggerMethod( "Userform_QueryClose", aParams);
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)
2556 return;
2559 if ( m_xDialog.is() )
2561 triggerTerminateEvent();
2563 // Search method
2564 SbxVariable* pMeth = SbObjModule::Find( "UnloadObject", SbxClassType::Method );
2565 if( !pMeth )
2566 return;
2568 SAL_INFO("basic", "Attempting to run the UnloadObjectMethod");
2569 m_xDialog.clear(); //release ref to the uno object
2570 SbxValues aVals;
2571 bool bWaitForDispose = true; // assume dialog is showing
2572 if (m_DialogListener)
2574 bWaitForDispose = m_DialogListener->isShowing();
2575 SAL_INFO("basic", "Showing " << bWaitForDispose );
2577 pMeth->Get( aVals);
2578 if ( !bWaitForDispose )
2580 // we've either already got a dispose or we are never going to get one
2581 ResetApiObj();
2582 } // else wait for dispose
2583 SAL_INFO("basic", "UnloadObject completed (we hope)");
2587 void SbUserFormModule::InitObject()
2591 SbUnoObject* pGlobs = static_cast<SbUnoObject*>(GetParent()->Find( "VBAGlobals", SbxClassType::DontCare ));
2592 if ( m_xModel.is() && pGlobs )
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" );
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();
2608 catch(const Exception& ) {}
2610 sDialogUrl += sProjectName + "." + GetName() + "?location=document";
2612 uno::Reference< awt::XDialogProvider > xProvider = awt::DialogProvider::createWithModel( xContext, m_xModel );
2613 m_xDialog = xProvider->createDialog( sDialogUrl );
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 ) ) );
2623 uno::Reference< lang::XComponent > xComponent( m_xDialog, uno::UNO_QUERY_THROW );
2625 // the dialog must be disposed at the end!
2626 StarBASIC* pParentBasic = nullptr;
2627 SbxObject* pCurObject = this;
2630 SbxObject* pObjParent = pCurObject->GetParent();
2631 pParentBasic = dynamic_cast<StarBASIC*>( pObjParent );
2632 pCurObject = pObjParent;
2634 while( pParentBasic == nullptr && pCurObject != nullptr );
2636 SAL_WARN_IF( pParentBasic == nullptr, "basic", "pParentBasic == NULL" );
2637 registerComponentToBeDisposedForBasic( xComponent, pParentBasic );
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 ) );
2644 triggerInitializeEvent();
2647 catch(const uno::Exception& )
2653 SbxVariable*
2654 SbUserFormModule::Find( const OUString& rName, SbxClassType t )
2656 if ( !pDocObject.is() && !GetSbData()->bRunInit && GetSbData()->pInst )
2657 InitObject();
2658 return SbObjModule::Find( rName, t );
2661 SbProperty::SbProperty( const OUString& r, SbxDataType t, SbModule* p )
2662 : SbxProperty( r, t ), pMod( p )
2666 SbProperty::~SbProperty()
2670 SbProcedureProperty::~SbProcedureProperty()
2673 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */