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