1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
33 #include <opcodes.hxx>
34 #include <runtime.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>
55 #include <sys/resource.h>
58 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
59 #include <comphelper/processfactory.hxx>
60 #include <comphelper/asyncquithandler.hxx>
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>
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
;
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
;
95 /// @throws css::uno::RuntimeException
96 SbMethodRef
getMethod( const OUString
& aName
);
97 /// @throws css::uno::RuntimeException
98 SbPropertyRef
getProperty( const OUString
& aName
);
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
);
128 if ( pMod
->GetModuleType() != ModuleType::DOCUMENT
)
131 // Use proxy factory service to create aggregatable proxy.
132 SbUnoObject
* pUnoObj
= dynamic_cast<SbUnoObject
*>( pMod
->GetObject() );
133 Reference
< XInterface
> xIf
;
136 Any aObj
= pUnoObj
->getUnoAny();
140 m_xAggregateTypeProv
.set( xIf
, UNO_QUERY
);
141 m_xAggInv
.set( xIf
, UNO_QUERY
);
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() )
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() });
188 Reference
< XIntrospectionAccess
> SAL_CALL
189 DocObjectWrapper::getIntrospection( )
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
);
201 throw RuntimeException();
202 // check number of parameters
203 sal_Int32 nParamsCount
= aParams
.getLength();
204 SbxInfo
* pInfo
= pMethod
->GetInfo();
207 sal_Int32 nSbxOptional
= 0;
209 for ( const SbxParamInfo
* pParamInfo
= pInfo
->GetParam( n
); pParamInfo
; pParamInfo
= pInfo
->GetParam( ++n
) )
211 if ( pParamInfo
->nFlags
& SbxFlagBits::Optional
)
216 sal_Int32 nSbxCount
= n
- 1;
217 if ( nParamsCount
< nSbxCount
- nSbxOptional
)
219 throw RuntimeException( "wrong number of 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() );
243 SbxVariableRef xReturn
= new SbxVariable
;
245 pMethod
->Call( xReturn
.get() );
247 // get output parameters
248 if ( xSbxParams
.is() )
250 SbxInfo
* pInfo_
= pMethod
->GetInfo();
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
);
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
;
284 aReturn
= sbxToUnoValue( xReturn
.get() );
286 pMethod
->SetParameters( nullptr );
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
);
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
);
322 DocObjectWrapper::hasMethod( const OUString
& aName
)
324 if ( m_xAggInv
.is() && m_xAggInv
->hasMethod( aName
) )
326 return getMethod( aName
).is();
330 DocObjectWrapper::hasProperty( const OUString
& aName
)
333 if ( m_xAggInv
.is() && m_xAggInv
->hasProperty( aName
) )
335 else bRes
= getProperty( aName
).is();
339 Any SAL_CALL
DocObjectWrapper::queryInterface( const Type
& aType
)
341 Any aRet
= DocObjectWrapper_BASE::queryInterface( aType
);
342 if ( aRet
.hasValue() )
344 else if ( m_xAggProxy
.is() )
345 aRet
= m_xAggProxy
->queryAggregation( aType
);
349 SbMethodRef
DocObjectWrapper::getMethod( const OUString
& aName
)
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
);
364 SbPropertyRef
DocObjectWrapper::getProperty( const OUString
& aName
)
366 SbPropertyRef pProperty
;
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
);
380 uno::Reference
< frame::XModel
> getDocumentModel( StarBASIC
* pb
)
382 uno::Reference
< frame::XModel
> xModel
;
383 if( pb
&& pb
->IsDocBasic() )
386 if( pb
->GetUNOConstant( "ThisComponent", aDoc
) )
387 xModel
.set( aDoc
, uno::UNO_QUERY
);
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
& )
406 static bool getDefaultVBAMode( StarBASIC
* pb
)
408 uno::Reference
< frame::XModel
> xModel( getDocumentModel( pb
) );
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 )
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");
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() <<")" );
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;
472 // methods and properties persist, but they are invalid;
473 // at least are the information under certain conditions clogged
475 for( i
= 0; i
< pMethods
->Count32(); i
++ )
477 SbMethod
* p
= dynamic_cast<SbMethod
*>( pMethods
->Get32( i
) );
481 for( i
= 0; i
< pProps
->Count32(); )
483 SbProperty
* p
= dynamic_cast<SbProperty
*>( pProps
->Get32( 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
);
499 pMethods
->Remove( p
);
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
);
515 pMeth
->ResetFlag( SbxFlagBits::Write
);
516 if( t
!= SbxVARIANT
)
518 pMeth
->SetFlag( SbxFlagBits::Fixed
);
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
);
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
);
550 void SbModule::GetProcedureProperty( const OUString
& rName
, SbxDataType t
)
552 SbxVariable
* p
= pProps
->Find( rName
, SbxClassType::Property
);
553 SbProcedureProperty
* pProp
= dynamic_cast<SbProcedureProperty
*>( p
);
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
);
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
) );
602 pMethods
->Remove( p
);
606 p
->bInvalid
= bNewState
;
616 void SbModule::Clear()
618 delete pImage
; pImage
= nullptr;
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
)
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();
643 SbxVariable
* pEnumVar
= xArray
->Find( rName
, SbxClassType::DontCare
);
644 SbxObject
* pEnumObject
= dynamic_cast<SbxObject
*>( pEnumVar
);
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
);
656 pRes
->SetFlag( SbxFlagBits::Private
);
658 pRes
->PutObject( pEnumObject
);
666 // Parent and BASIC are one!
668 void SbModule::SetParent( SbxObject
* p
)
673 void SbModule::Notify( SfxBroadcaster
& rBC
, const SfxHint
& rHint
)
675 const SbxHint
* pHint
= dynamic_cast<const SbxHint
*>(&rHint
);
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
);
686 if( pHint
->GetId() == SfxHintId::BasicDataWanted
)
688 OUString aProcName
= "Property Get "
689 + pProcProperty
->GetName();
691 SbxVariable
* pMethVar
= Find( aProcName
, SbxClassType::Method
);
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 );
715 pMethVar
->Get( aVals
);
721 else if( pHint
->GetId() == SfxHintId::BasicDataChanged
)
723 SbxVariable
* pMethVar
= nullptr;
725 bool bSet
= pProcProperty
->isSet();
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
);
744 SbxArrayRef xArray
= new SbxArray
;
745 xArray
->Put32( pMethVar
, 0 ); // Method as parameter 0
746 xArray
->Put32( pVar
, 1 );
747 pMethVar
->SetParameters( xArray
.get() );
750 pMethVar
->Get( aVals
);
751 pMethVar
->SetParameters( nullptr );
757 if( pProp
->GetModule() != this )
758 SetError( ERRCODE_BASIC_BAD_ACTION
);
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
);
771 // Call of a subprogram
772 SbModule
* pOld
= GetSbData()->pMod
;
773 GetSbData()->pMod
= this;
774 Run( static_cast<SbMethod
*>(pVar
) );
775 GetSbData()->pMod
= pOld
;
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() ) ) );
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
)
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
);
851 // Definition of the method
852 SbMethod
* pMeth
= nullptr;
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
)
864 pMeth
= GetMethod( aName_
, t
);
865 pMeth
->nLine1
= pMeth
->nLine2
= nLine1
;
866 // The method is for a start VALID
867 pMeth
->bInvalid
= false;
874 // Skip up to END SUB/END FUNCTION
877 while( !aTok
.IsEof() )
879 if( aTok
.Next() == eEndTok
)
881 pMeth
->nLine2
= aTok
.GetLine();
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
)
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
);
926 pVar
->SbxValue::Clear();
928 // delete the return value of CreateUnoDialog
929 pVar
= pBasic
->GetRtl()->Find( "CreateUnoDialog", SbxClassType::Method
);
932 pVar
->SbxValue::Clear();
934 // delete the return value of CDec
935 pVar
= pBasic
->GetRtl()->Find( "CDec", SbxClassType::Method
);
938 pVar
->SbxValue::Clear();
940 // delete return value of CreateObject
941 pVar
= pBasic
->GetRtl()->Find( "CreateObject", SbxClassType::Method
);
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
);
955 ClearUnoObjectsInRTL_Impl_Rek( pSubBasic
);
960 static void ClearUnoObjectsInRTL_Impl( StarBASIC
* pBasic
)
962 // #67781 Delete return values of the Uno-methods
965 ClearUnoObjectsInRTL_Impl_Rek( pBasic
);
967 // Search for the topmost Basic
968 SbxObject
* p
= pBasic
;
969 while( 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
)
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" );
999 std::unique_ptr
<SbiRuntime
> m_xRt
;
1000 SbiGlobals
* m_pSbData
;
1001 SbModule
* m_pOldMod
;
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();
1014 while (m_xRt
->Step()) {}
1016 virtual ~RunInitGuard()
1018 m_pSbData
->pInst
->pRun
= m_xRt
->pNext
;
1019 m_pSbData
->pMod
= m_pOldMod
;
1024 class RunGuard
: public RunInitGuard
1029 RunGuard(SbModule
* pModule
, SbMethod
* pMethod
, sal_uInt32 nArg
, SbiGlobals
* pSbData
, bool bDelInst
)
1030 : RunInitGuard(pModule
, pMethod
, nArg
, pSbData
)
1031 , m_bDelInst(bDelInst
)
1034 m_xRt
->pNext
->block();
1036 virtual ~RunGuard() override
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.
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;
1077 StarBASICRef xBasic
;
1078 uno::Reference
< frame::XModel
> xModel
;
1079 uno::Reference
< script::vba::XVBACompatibility
> xVBACompat
;
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. */
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
& )
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
);
1121 pMSOMacroRuntimeLib
->SetFlag( SbxFlagBits::ExtSearch
); // Could have been disabled before
1122 pSbData
->pMSOMacroRuntimLib
= pMSOMacroRuntimeLib
;
1127 if( nMaxCallLevel
== 0 )
1131 getrlimit ( RLIMIT_STACK
, &rl
);
1134 // Empiric value, 900 = needed bytes/Basic call level
1135 // for Linux including 10% safety margin
1136 nMaxCallLevel
= rl
.rlim_cur
/ 900;
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;
1144 nMaxCallLevel
= MAXRECURSION
;
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
)
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
));
1172 pSbData
->pInst
->EnableCompatibility( true );
1175 xRuntimeGuard
->run();
1177 xRuntimeGuard
.reset();
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;
1193 SolarMutexGuard aSolarGuard
;
1194 SendHint( GetParent(), SfxHintId::BasicStop
, pMeth
);
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 );
1215 pSbData
->pInst
->nCallLvl
--; // Call-Level down again
1219 pSbData
->pInst
->nCallLvl
--; // Call-Level down again
1220 StarBASIC::FatalError( ERRCODE_BASIC_STACK_OVERFLOW
);
1223 StarBASIC
* pBasic
= dynamic_cast<StarBASIC
*>( GetParent() );
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
)
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()
1247 && pImage
->IsFlag( SbiImageFlags::INITCODE
)) )
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
)
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
);
1293 void SbModule::ClearPrivateVars()
1295 for( sal_uInt32 i
= 0 ; i
< pProps
->Count32() ; i
++ )
1297 SbProperty
* p
= dynamic_cast<SbProperty
*>( pProps
->Get32( i
) );
1300 // Delete not the arrays, only their content
1301 if( p
->GetType() & SbxARRAY
)
1303 SbxArray
* pArray
= dynamic_cast<SbxArray
*>( p
->GetObject() );
1306 for( sal_uInt32 j
= 0 ; j
< pArray
->Count32() ; j
++ )
1308 SbxVariable
* pj
= pArray
->Get32( j
);
1309 pj
->SbxValue::Clear();
1315 p
->SbxValue::Clear();
1321 void SbModule::implClearIfVarDependsOnDeletedBasic( SbxVariable
* pVar
, StarBASIC
* pDeletedBasic
)
1323 if( pVar
->SbxValue::GetType() != SbxOBJECT
|| dynamic_cast<const SbProcedureProperty
*>( pVar
) != nullptr )
1326 SbxObject
* pObj
= dynamic_cast<SbxObject
*>( pVar
->GetObject() );
1327 if( pObj
== nullptr )
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();
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
) );
1354 if( p
->GetType() & SbxARRAY
)
1356 SbxArray
* pArray
= dynamic_cast<SbxArray
*>( p
->GetObject() );
1359 for( sal_uInt32 j
= 0 ; j
< pArray
->Count32() ; j
++ )
1361 SbxVariable
* pVar
= pArray
->Get32( j
);
1362 implClearIfVarDependsOnDeletedBasic( pVar
, pDeletedBasic
);
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
1391 if( !pImage
|| pImage
->bInit
)
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() );
1405 pBasic
->InitAllModules();
1407 SbxObject
* pParent_
= pBasic
->GetParent();
1411 StarBASIC
* pParentBasic
= dynamic_cast<StarBASIC
*>( pParent_
);
1415 pParentBasic
->InitAllModules( pBasic
);
1417 // #109018 Parent can also have a parent (library in doc)
1418 SbxObject
* pParentParent
= pParentBasic
->GetParent();
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() );
1432 pBasic
->DeInitAllModules();
1434 SbxObject
* pParent_
= pBasic
->GetParent();
1436 pBasic
= dynamic_cast<StarBASIC
*>( pParent_
);
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
++ );
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
)
1470 else if( eOp
== SbiOpcode::STMNT_
)
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
);
1480 else if( eOp
>= SbiOpcode::SbOP2_START
&& eOp
<= SbiOpcode::SbOP2_END
)
1485 else if( eOp
< SbiOpcode::SbOP0_START
|| eOp
> SbiOpcode::SbOP0_END
)
1487 StarBASIC::FatalError( ERRCODE_BASIC_INTERNAL_ERROR
);
1494 // Test, if a line contains STMNT-Opcodes
1496 bool SbModule::IsBreakable( sal_uInt16 nLine
) const
1500 const sal_uInt8
* p
= reinterpret_cast<const sal_uInt8
*>(pImage
->GetCode());
1502 while( ( p
= FindNextStmnt( p
, nl
, nc
) ) != nullptr )
1508 bool SbModule::IsBP( sal_uInt16 nLine
) const
1512 for( size_t i
= 0; i
< pBreaks
->size(); i
++ )
1514 sal_uInt16 b
= pBreaks
->operator[]( i
);
1524 bool SbModule::SetBP( sal_uInt16 nLine
)
1526 if( !IsBreakable( nLine
) )
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
)
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
)
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
);
1555 if( pBreaks
->empty() )
1564 void SbModule::ClearAllBP()
1571 SbModule::fixUpMethodStart( bool bCvtToLegacy
, SbiImage
* pImg
) const
1575 for( sal_uInt32 i
= 0; i
< pMethods
->Count32(); i
++ )
1577 SbMethod
* pMeth
= dynamic_cast<SbMethod
*>( pMethods
->Get32(i
) );
1580 //fixup method start positions
1582 pMeth
->nStart
= pImg
->CalcLegacyOffset( pMeth
->nStart
);
1584 pMeth
->nStart
= pImg
->CalcNewOffset( static_cast<sal_uInt16
>(pMeth
->nStart
) );
1590 bool SbModule::LoadData( SvStream
& rStrm
, sal_uInt16 nVer
)
1593 if( !SbxObject::LoadData( rStrm
, 1 ) )
1595 // As a precaution...
1596 SetFlag( SbxFlagBits::ExtSearch
| SbxFlagBits::GlobalSearch
);
1598 rStrm
.ReadUChar( bImage
);
1601 SbiImage
* p
= new SbiImage
;
1602 sal_uInt32 nImgVer
= 0;
1604 if( !p
->Load( rStrm
, nImgVer
) )
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
1623 SetSource32( p
->aOUSource
);
1631 SetSource32( p
->aOUSource
);
1638 bool SbModule::StoreData( SvStream
& rStrm
) const
1640 bool bFixup
= ( pImage
&& !pImage
->ExceedsLegacyLimits() );
1642 fixUpMethodStart( true );
1643 bool bRet
= SbxObject::StoreData( rStrm
);
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
1657 bool bRes
= pImage
->Save( rStrm
, B_LEGACYVERSION
);
1659 fixUpMethodStart( false ); // restore method starts
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() )
1678 return pImage
&& pImage
->ExceedsLegacyLimits();
1683 class ErrorHdlResetter
1685 Link
<StarBASIC
*,bool> mErrHandler
;
1689 : mErrHandler(StarBASIC::GetGlobalErrorHdl()) // save error handler
1692 // set new error handler
1693 StarBASIC::SetGlobalErrorHdl( LINK( this, ErrorHdlResetter
, BasicErrorHdl
) );
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)
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
;
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
1755 ErrorHdlResetter aGblErrHdl
;
1757 if (aGblErrHdl
.HasError()) //assume unsafe on compile error
1762 if (pImage
&& (pImage
->GetCodeSize() != 5 || (memcmp(pImage
->GetCode(), pEmptyImage
, pImage
->GetCodeSize()) != 0 )))
1768 // Store only image, no source
1769 void SbModule::StoreBinaryData( SvStream
& rStrm
)
1774 if (!SbxObject::StoreData(rStrm
))
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 );
1794 aOUSource
= aKeepSource
;
1797 bool SbModule::LoadCompleted()
1799 SbxArray
* p
= GetMethods().get();
1801 for( i
= 0; i
< p
->Count32(); i
++ )
1803 SbMethod
* q
= dynamic_cast<SbMethod
*>( p
->Get32( i
) );
1807 p
= GetProperties();
1808 for( i
= 0; i
< p
->Count32(); i
++ )
1810 SbProperty
* q
= dynamic_cast<SbProperty
*>( p
->Get32( i
) );
1817 void SbModule::handleProcedureProperties( SfxBroadcaster
& rBC
, const SfxHint
& rHint
)
1821 const SbxHint
* pHint
= dynamic_cast<const SbxHint
*>(&rHint
);
1824 SbxVariable
* pVar
= pHint
->GetVar();
1825 SbProcedureProperty
* pProcProperty
= dynamic_cast<SbProcedureProperty
*>( pVar
);
1830 if( pHint
->GetId() == SfxHintId::BasicDataWanted
)
1832 OUString aProcName
= "Property Get "
1833 + pProcProperty
->GetName();
1835 SbxVariable
* pMeth
= Find( aProcName
, SbxClassType::Method
);
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 );
1859 pMeth
->Get( aVals
);
1865 else if( pHint
->GetId() == SfxHintId::BasicDataChanged
)
1867 SbxVariable
* pMeth
= nullptr;
1869 bool bSet
= pProcProperty
->isSet();
1872 pProcProperty
->setSet( false );
1874 OUString aProcName
= "Property Set "
1875 + pProcProperty
->GetName();
1876 pMeth
= Find( aProcName
, SbxClassType::Method
);
1880 OUString aProcName
= "Property Let "
1881 + pProcProperty
->GetName();
1882 pMeth
= Find( aProcName
, SbxClassType::Method
);
1888 SbxArrayRef xArray
= new SbxArray
;
1889 xArray
->Put32( pMeth
, 0 ); // Method as parameter 0
1890 xArray
->Put32( pVar
, 1 );
1891 pMeth
->SetParameters( xArray
.get() );
1894 pMeth
->Get( aVals
);
1895 pMeth
->SetParameters( nullptr );
1902 SbModule::Notify( rBC
, rHint
);
1906 // Implementation SbJScriptModule (Basic module for JavaScript source code)
1907 SbJScriptModule::SbJScriptModule()
1912 bool SbJScriptModule::LoadData( SvStream
& rStrm
, sal_uInt16
)
1915 if( !SbxObject::LoadData( rStrm
, 1 ) )
1918 // Get the source string
1919 aOUSource
= rStrm
.ReadUniOrByteString( osl_getThreadTextEncoding() );
1923 bool SbJScriptModule::StoreData( SvStream
& rStrm
) const
1925 if( !SbxObject::StoreData( rStrm
) )
1928 // Write the source string
1929 OUString aTmp
= aOUSource
;
1930 rStrm
.WriteUniOrByteString( aTmp
, osl_getThreadTextEncoding() );
1935 SbMethod::SbMethod( const OUString
& r
, SbxDataType t
, SbModule
* p
)
1936 : SbxMethod( r
, t
), pMod( p
)
1940 nDebugFlags
= BasicDebugFlags::NONE
;
1943 refStatics
= new SbxArray
;
1945 // HACK due to 'Reference could not be saved'
1946 SetFlag( SbxFlagBits::NoModify
);
1949 SbMethod::SbMethod( const SbMethod
& r
)
1950 : SvRefBase( r
), SbxMethod( r
)
1953 bInvalid
= r
.bInvalid
;
1955 nDebugFlags
= r
.nDebugFlags
;
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 ) )
1983 rStrm
.ReadUInt16( nFlag
);
1985 sal_Int16 nTempStart
= static_cast<sal_Int16
>(nStart
);
1989 rStrm
.ReadUInt16( nLine1
).ReadUInt16( nLine2
).ReadInt16( nTempStart
).ReadCharAsBool( bInvalid
);
1993 sal_uInt16 nMult
= nFlag
& 0x7FFF;
1994 sal_Int16
const nMax
= std::numeric_limits
<sal_Int16
>::max();
1995 nStart
= nMult
* nMax
+ nTempStart
;
1999 nStart
= nTempStart
;
2004 nStart
= nTempStart
;
2007 // HACK due to 'Reference could not be saved'
2008 SetFlag( SbxFlagBits::NoModify
);
2013 bool SbMethod::StoreData( SvStream
& rStrm
) const
2015 if( !SbxMethod::StoreData( rStrm
) )
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
);
2033 void SbMethod::GetLineRange( sal_uInt16
& l1
, sal_uInt16
& l2
)
2035 l1
= nLine1
; l2
= nLine2
;
2038 // Could later be deleted
2040 SbxInfo
* SbMethod::GetInfo()
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
)
2052 SAL_INFO("basic", "SbMethod::Call Have been passed a caller 0x" << 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
2062 aVals
.eType
= SbxVARIANT
;
2064 // #104083: Compile BEFORE get
2065 if( bInvalid
&& !pMod_
->Compile() )
2066 StarBASIC::Error( ERRCODE_BASIC_BAD_PROP_VALUE
);
2072 // Was there an error
2073 ErrCode nErr
= SbxBase::GetError();
2074 SbxBase::ResetError();
2081 // #100883 Own Broadcast for SbMethod
2082 void SbMethod::Broadcast( SfxHintId nHintId
)
2084 if( !mpBroadcaster
|| IsSet( SbxFlagBits::NoBroadcast
) )
2087 // Because the method could be called from outside, test here once again
2088 // the authorisation
2089 if( nHintId
== SfxHintId::BasicDataWanted
)
2092 if( nHintId
== SfxHintId::BasicDataChanged
)
2096 if( pMod
&& !pMod
->IsCompiled() )
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
;
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()
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
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" );
2173 SbObjModule::GetObject()
2175 return pDocObject
.get();
2178 SbObjModule::Find( const OUString
& rName
, SbxClassType t
)
2180 SbxVariable
* pVar
= nullptr;
2182 pVar
= pDocObject
->Find( rName
, t
);
2184 pVar
= SbModule::Find( rName
, t
);
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
;
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
& ) {}
2235 uno::Reference
< document::XDocumentEventBroadcaster
>( mxModel
, uno::UNO_QUERY_THROW
)->addDocumentEventListener( this );
2237 catch(const uno::Exception
& ) {}
2241 virtual ~FormObjEventListenerImpl() override
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
& ) {}
2276 virtual void SAL_CALL
windowOpened( const lang::EventObject
& /*e*/ ) override
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
);
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
;
2308 aParams
[0] <<= nCancel
;
2309 aParams
[1] <<= nCloseMode
;
2311 mpUserForm
->triggerMethod( "Userform_QueryClose", aParams
);
2318 mpUserForm
->triggerMethod( "Userform_QueryClose" );
2323 virtual void SAL_CALL
windowClosed( const lang::EventObject
& /*e*/ ) override
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
2344 mbOpened
= mbActivated
= false;
2345 mpUserForm
->triggerActivateEvent();
2350 virtual void SAL_CALL
windowDeactivated( const lang::EventObject
& /*e*/ ) override
2353 mpUserForm
->triggerDeactivateEvent();
2356 virtual void SAL_CALL
windowResized( const awt::WindowEvent
& /*e*/ ) override
2360 mpUserForm
->triggerResizeEvent();
2361 mpUserForm
->triggerLayoutEvent();
2365 virtual void SAL_CALL
windowMoved( const awt::WindowEvent
& /*e*/ ) override
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
) )
2387 mpUserForm
->ResetApiObj(); // will trigger "UserForm_Terminate"
2391 virtual void SAL_CALL
disposing( const lang::EventObject
& /*Source*/ ) override
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
)
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
);
2433 SbxVariable
* pMeth
= SbObjModule::Find( aMethodToRun
, SbxClassType::Method
);
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() );
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 );
2466 pMeth
->Get( aVals
);
2470 void SbUserFormModule::triggerActivateEvent()
2472 triggerMethod( "UserForm_Activate" );
2475 void SbUserFormModule::triggerDeactivateEvent()
2477 triggerMethod( "Userform_Deactivate" );
2480 void SbUserFormModule::triggerInitializeEvent()
2484 triggerMethod("Userform_Initialize");
2488 void SbUserFormModule::triggerTerminateEvent()
2490 triggerMethod("Userform_Terminate");
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() );
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
);
2524 SbxVariable
* SbUserFormModuleInstance::Find( const OUString
& rName
, SbxClassType t
)
2526 SbxVariable
* pVar
= m_pParentModule
->Find( rName
, t
);
2531 void SbUserFormModule::Load()
2534 if ( !pDocObject
.is() )
2539 void SbUserFormModule::Unload()
2541 sal_Int8 nCancel
= 0;
2543 Sequence
< Any
> aParams
;
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 )
2559 if ( m_xDialog
.is() )
2561 triggerTerminateEvent();
2564 SbxVariable
* pMeth
= SbObjModule::Find( "UnloadObject", SbxClassType::Method
);
2568 SAL_INFO("basic", "Attempting to run the UnloadObjectMethod");
2569 m_xDialog
.clear(); //release ref to the uno object
2571 bool bWaitForDispose
= true; // assume dialog is showing
2572 if (m_DialogListener
)
2574 bWaitForDispose
= m_DialogListener
->isShowing();
2575 SAL_INFO("basic", "Showing " << bWaitForDispose
);
2578 if ( !bWaitForDispose
)
2580 // we've either already got a dispose or we are never going to get one
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
& )
2654 SbUserFormModule::Find( const OUString
& rName
, SbxClassType t
)
2656 if ( !pDocObject
.is() && !GetSbData()->bRunInit
&& GetSbData()->pInst
)
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: */