/************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * *************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_basic.hxx" #include #include #include #include #include #include #include #include "sbdiagnose.hxx" #include "sb.hxx" #include #include "sbjsmod.hxx" #include "sbintern.hxx" #include "image.hxx" #include "opcodes.hxx" #include "runtime.hxx" #include "token.hxx" #include "sbunoobj.hxx" #include "sbtrace.hxx" //#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace com::sun::star; // for the bsearch #ifdef WNT #define CDECL _cdecl #endif #if defined(UNX) || defined(OS2) #define CDECL #endif #ifdef UNX #include #endif #include #include #include #include #include #include #include #include #include #include #include using namespace com::sun::star::lang; using namespace com::sun::star::reflection; using namespace com::sun::star::beans; using namespace com::sun::star::script; #include #include #include #include #include #include #include #include #include #include typedef ::cppu::WeakImplHelper1< XInvocation > DocObjectWrapper_BASE; typedef ::std::map< sal_Int16, Any, ::std::less< sal_Int16 > > OutParamMap; ::com::sun::star::uno::Any sbxToUnoValue( SbxVariable* pVar ); void unoToSbxValue( SbxVariable* pVar, const ::com::sun::star::uno::Any& aValue ); class DocObjectWrapper : public DocObjectWrapper_BASE { Reference< XAggregation > m_xAggProxy; Reference< XInvocation > m_xAggInv; Reference< XTypeProvider > m_xAggregateTypeProv; Sequence< Type > m_Types; SbModule* m_pMod; SbMethodRef getMethod( const rtl::OUString& aName ) throw (RuntimeException); SbPropertyRef getProperty( const rtl::OUString& aName ) throw (RuntimeException); String mName; // for debugging public: DocObjectWrapper( SbModule* pMod ); virtual ~DocObjectWrapper(); virtual void SAL_CALL acquire() throw(); virtual void SAL_CALL release() throw(); virtual Sequence< sal_Int8 > SAL_CALL getImplementationId() throw (RuntimeException) { if( !m_xAggregateTypeProv.is() ) throw RuntimeException(); return m_xAggregateTypeProv->getImplementationId(); } virtual Reference< XIntrospectionAccess > SAL_CALL getIntrospection( ) throw (RuntimeException); virtual Any SAL_CALL invoke( const ::rtl::OUString& aFunctionName, const Sequence< Any >& aParams, Sequence< ::sal_Int16 >& aOutParamIndex, Sequence< Any >& aOutParam ) throw (IllegalArgumentException, CannotConvertException, InvocationTargetException, RuntimeException); virtual void SAL_CALL setValue( const ::rtl::OUString& aPropertyName, const Any& aValue ) throw (UnknownPropertyException, CannotConvertException, InvocationTargetException, RuntimeException); virtual Any SAL_CALL getValue( const ::rtl::OUString& aPropertyName ) throw (UnknownPropertyException, RuntimeException); virtual ::sal_Bool SAL_CALL hasMethod( const ::rtl::OUString& aName ) throw (RuntimeException); virtual ::sal_Bool SAL_CALL hasProperty( const ::rtl::OUString& aName ) throw (RuntimeException); virtual Any SAL_CALL queryInterface( const Type& aType ) throw ( RuntimeException ); virtual Sequence< Type > SAL_CALL getTypes() throw ( RuntimeException ); }; DocObjectWrapper::DocObjectWrapper( SbModule* pVar ) : m_pMod( pVar ), mName( pVar->GetName() ) { SbObjModule* pMod = PTR_CAST(SbObjModule,pVar); if ( pMod ) { if ( pMod->GetModuleType() == ModuleType::DOCUMENT ) { Reference< XMultiServiceFactory > xFactory = comphelper::getProcessServiceFactory(); // Use proxy factory service to create aggregatable proxy. SbUnoObject* pUnoObj = PTR_CAST(SbUnoObject,pMod->GetObject() ); Reference< XInterface > xIf; if ( pUnoObj ) { Any aObj = pUnoObj->getUnoAny(); aObj >>= xIf; if ( xIf.is() ) { m_xAggregateTypeProv.set( xIf, UNO_QUERY ); m_xAggInv.set( xIf, UNO_QUERY ); } } if ( xIf.is() ) { try { Reference< XMultiComponentFactory > xMFac( xFactory, UNO_QUERY_THROW ); Reference< XPropertySet> xPSMPropertySet( xMFac, UNO_QUERY_THROW ); Reference< XComponentContext > xCtx; xPSMPropertySet->getPropertyValue( String( RTL_CONSTASCII_USTRINGPARAM("DefaultContext") ) ) >>= xCtx; Reference< XProxyFactory > xProxyFac( xMFac->createInstanceWithContext( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.reflection.ProxyFactory" ) ), xCtx ), UNO_QUERY_THROW ); m_xAggProxy = xProxyFac->createProxy( xIf ); } catch( Exception& ) { OSL_ENSURE( false, "DocObjectWrapper::DocObjectWrapper: Caught exception!" ); } } if ( m_xAggProxy.is() ) { osl_incrementInterlockedCount( &m_refCount ); /* i35609 - Fix crash on Solaris. The setDelegator call needs to be in its own block to ensure that all temporary Reference instances that are acquired during the call are released before m_refCount is decremented again */ { m_xAggProxy->setDelegator( static_cast< cppu::OWeakObject * >( this ) ); } osl_decrementInterlockedCount( &m_refCount ); } } } } void SAL_CALL DocObjectWrapper::acquire() throw () { osl_incrementInterlockedCount( &m_refCount ); OSL_TRACE("DocObjectWrapper::acquire(%s) 0x%x refcount is now %d", rtl::OUStringToOString( mName, RTL_TEXTENCODING_UTF8 ).getStr(), this, m_refCount ); } void SAL_CALL DocObjectWrapper::release() throw () { if ( osl_decrementInterlockedCount( &m_refCount ) == 0 ) { OSL_TRACE("DocObjectWrapper::release(%s) 0x%x refcount is now %d", rtl::OUStringToOString( mName, RTL_TEXTENCODING_UTF8 ).getStr(), this, m_refCount ); delete this; } else OSL_TRACE("DocObjectWrapper::release(%s) 0x%x refcount is now %d", rtl::OUStringToOString( mName, RTL_TEXTENCODING_UTF8 ).getStr(), this, m_refCount ); } DocObjectWrapper::~DocObjectWrapper() { } Sequence< Type > SAL_CALL DocObjectWrapper::getTypes() throw ( RuntimeException ) { if ( m_Types.getLength() == 0 ) { Sequence< Type > sTypes; if ( m_xAggregateTypeProv.is() ) sTypes = m_xAggregateTypeProv->getTypes(); m_Types.realloc( sTypes.getLength() + 1 ); Type* pPtr = m_Types.getArray(); for ( int i=0; i SAL_CALL DocObjectWrapper::getIntrospection( ) throw (RuntimeException) { return NULL; } Any SAL_CALL DocObjectWrapper::invoke( const ::rtl::OUString& aFunctionName, const Sequence< Any >& aParams, Sequence< ::sal_Int16 >& aOutParamIndex, Sequence< Any >& aOutParam ) throw (IllegalArgumentException, CannotConvertException, InvocationTargetException, RuntimeException) { if ( m_xAggInv.is() && m_xAggInv->hasMethod( aFunctionName ) ) return m_xAggInv->invoke( aFunctionName, aParams, aOutParamIndex, aOutParam ); SbMethodRef pMethod = getMethod( aFunctionName ); if ( !pMethod ) throw RuntimeException(); // check number of parameters sal_Int32 nParamsCount = aParams.getLength(); SbxInfo* pInfo = pMethod->GetInfo(); if ( pInfo ) { sal_Int32 nSbxOptional = 0; sal_uInt16 n = 1; for ( const SbxParamInfo* pParamInfo = pInfo->GetParam( n ); pParamInfo; pParamInfo = pInfo->GetParam( ++n ) ) { if ( ( pParamInfo->nFlags & SBX_OPTIONAL ) != 0 ) ++nSbxOptional; else nSbxOptional = 0; } sal_Int32 nSbxCount = n - 1; if ( nParamsCount < nSbxCount - nSbxOptional ) { throw RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "wrong number of parameters!" ) ), Reference< XInterface >() ); } } // set parameters SbxArrayRef xSbxParams; if ( nParamsCount > 0 ) { xSbxParams = new SbxArray; const Any* pParams = aParams.getConstArray(); for ( sal_Int32 i = 0; i < nParamsCount; ++i ) { SbxVariableRef xSbxVar = new SbxVariable( SbxVARIANT ); unoToSbxValue( static_cast< SbxVariable* >( xSbxVar ), pParams[i] ); xSbxParams->Put( xSbxVar, static_cast< sal_uInt16 >( i ) + 1 ); // Enable passing by ref if ( xSbxVar->GetType() != SbxVARIANT ) xSbxVar->SetFlag( SBX_FIXED ); } } if ( xSbxParams.Is() ) pMethod->SetParameters( xSbxParams ); // call method SbxVariableRef xReturn = new SbxVariable; ErrCode nErr = SbxERR_OK; nErr = pMethod->Call( xReturn ); Any aReturn; // get output parameters if ( xSbxParams.Is() ) { SbxInfo* pInfo_ = pMethod->GetInfo(); if ( pInfo_ ) { OutParamMap aOutParamMap; for ( sal_uInt16 n = 1, nCount = xSbxParams->Count(); n < nCount; ++n ) { const SbxParamInfo* pParamInfo = pInfo_->GetParam( n ); if ( pParamInfo && ( pParamInfo->eType & SbxBYREF ) != 0 ) { SbxVariable* pVar = xSbxParams->Get( n ); if ( pVar ) { SbxVariableRef xVar = pVar; aOutParamMap.insert( OutParamMap::value_type( n - 1, sbxToUnoValue( xVar ) ) ); } } } sal_Int32 nOutParamCount = aOutParamMap.size(); aOutParamIndex.realloc( nOutParamCount ); aOutParam.realloc( nOutParamCount ); sal_Int16* pOutParamIndex = aOutParamIndex.getArray(); Any* pOutParam = aOutParam.getArray(); for ( OutParamMap::iterator aIt = aOutParamMap.begin(); aIt != aOutParamMap.end(); ++aIt, ++pOutParamIndex, ++pOutParam ) { *pOutParamIndex = aIt->first; *pOutParam = aIt->second; } } } // get return value aReturn = sbxToUnoValue( xReturn ); pMethod->SetParameters( NULL ); return aReturn; } void SAL_CALL DocObjectWrapper::setValue( const ::rtl::OUString& aPropertyName, const Any& aValue ) throw (UnknownPropertyException, CannotConvertException, InvocationTargetException, RuntimeException) { if ( m_xAggInv.is() && m_xAggInv->hasProperty( aPropertyName ) ) return m_xAggInv->setValue( aPropertyName, aValue ); SbPropertyRef pProperty = getProperty( aPropertyName ); if ( !pProperty.Is() ) throw UnknownPropertyException(); unoToSbxValue( (SbxVariable*) pProperty, aValue ); } Any SAL_CALL DocObjectWrapper::getValue( const ::rtl::OUString& aPropertyName ) throw (UnknownPropertyException, RuntimeException) { if ( m_xAggInv.is() && m_xAggInv->hasProperty( aPropertyName ) ) return m_xAggInv->getValue( aPropertyName ); SbPropertyRef pProperty = getProperty( aPropertyName ); if ( !pProperty.Is() ) throw UnknownPropertyException(); SbxVariable* pProp = ( SbxVariable* ) pProperty; if ( pProp->GetType() == SbxEMPTY ) pProperty->Broadcast( SBX_HINT_DATAWANTED ); Any aRet = sbxToUnoValue( pProp ); return aRet; } ::sal_Bool SAL_CALL DocObjectWrapper::hasMethod( const ::rtl::OUString& aName ) throw (RuntimeException) { if ( m_xAggInv.is() && m_xAggInv->hasMethod( aName ) ) return sal_True; return getMethod( aName ).Is(); } ::sal_Bool SAL_CALL DocObjectWrapper::hasProperty( const ::rtl::OUString& aName ) throw (RuntimeException) { sal_Bool bRes = sal_False; if ( m_xAggInv.is() && m_xAggInv->hasProperty( aName ) ) bRes = sal_True; else bRes = getProperty( aName ).Is(); return bRes; } Any SAL_CALL DocObjectWrapper::queryInterface( const Type& aType ) throw ( RuntimeException ) { Any aRet = DocObjectWrapper_BASE::queryInterface( aType ); if ( aRet.hasValue() ) return aRet; else if ( m_xAggProxy.is() ) aRet = m_xAggProxy->queryAggregation( aType ); return aRet; } SbMethodRef DocObjectWrapper::getMethod( const rtl::OUString& aName ) throw (RuntimeException) { SbMethodRef pMethod = NULL; if ( m_pMod ) { sal_uInt16 nSaveFlgs = m_pMod->GetFlags(); // Limit search to this module m_pMod->ResetFlag( SBX_GBLSEARCH ); pMethod = (SbMethod*) m_pMod->SbModule::Find( aName, SbxCLASS_METHOD ); m_pMod->SetFlags( nSaveFlgs ); } return pMethod; } SbPropertyRef DocObjectWrapper::getProperty( const rtl::OUString& aName ) throw (RuntimeException) { SbPropertyRef pProperty = NULL; if ( m_pMod ) { sal_uInt16 nSaveFlgs = m_pMod->GetFlags(); // Limit search to this module. m_pMod->ResetFlag( SBX_GBLSEARCH ); pProperty = (SbProperty*)m_pMod->SbModule::Find( aName, SbxCLASS_PROPERTY ); m_pMod->SetFlag( nSaveFlgs ); } return pProperty; } TYPEINIT1(SbModule,SbxObject) TYPEINIT1(SbMethod,SbxMethod) TYPEINIT1(SbProperty,SbxProperty) TYPEINIT1(SbProcedureProperty,SbxProperty) TYPEINIT1(SbJScriptModule,SbModule) TYPEINIT1(SbJScriptMethod,SbMethod) TYPEINIT1(SbObjModule,SbModule) TYPEINIT1(SbUserFormModule,SbObjModule) typedef std::vector HighlightPortions; uno::Reference< frame::XModel > getDocumentModel( StarBASIC* pb ) { uno::Reference< frame::XModel > xModel; if( pb && pb->IsDocBasic() ) { uno::Any aDoc; if( pb->GetUNOConstant( "ThisComponent", aDoc ) ) xModel.set( aDoc, uno::UNO_QUERY ); } return xModel; } uno::Reference< vba::XVBACompatibility > getVBACompatibility( const uno::Reference< frame::XModel >& rxModel ) { uno::Reference< vba::XVBACompatibility > xVBACompat; try { uno::Reference< beans::XPropertySet > xModelProps( rxModel, uno::UNO_QUERY_THROW ); xVBACompat.set( xModelProps->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "BasicLibraries" ) ) ), uno::UNO_QUERY ); } catch( uno::Exception& ) { } return xVBACompat; } bool getDefaultVBAMode( StarBASIC* pb ) { uno::Reference< vba::XVBACompatibility > xVBACompat = getVBACompatibility( getDocumentModel( pb ) ); return xVBACompat.is() && xVBACompat->getVBACompatibilityMode(); } class AsyncQuitHandler { AsyncQuitHandler() {} AsyncQuitHandler( const AsyncQuitHandler&); public: static AsyncQuitHandler& instance() { static AsyncQuitHandler dInst; return dInst; } void QuitApplication() { uno::Reference< lang::XMultiServiceFactory > xFactory = comphelper::getProcessServiceFactory(); if ( xFactory.is() ) { uno::Reference< frame::XDesktop > xDeskTop( xFactory->createInstance( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.frame.Desktop") ) ), uno::UNO_QUERY ); if ( xDeskTop.is() ) xDeskTop->terminate(); } } DECL_LINK( OnAsyncQuit, void* ); }; IMPL_LINK( AsyncQuitHandler, OnAsyncQuit, void*, /*pNull*/ ) { QuitApplication(); return 0L; } ///////////////////////////////////////////////////////////////////////////// // Ein BASIC-Modul hat EXTSEARCH gesetzt, damit die im Modul enthaltenen // Elemente von anderen Modulen aus gefunden werden koennen. SbModule::SbModule( const String& rName, sal_Bool bVBACompat ) : SbxObject( String( RTL_CONSTASCII_USTRINGPARAM("StarBASICModule") ) ), pImage( NULL ), pBreaks( NULL ), pClassData( NULL ), mbVBACompat( bVBACompat ), pDocObject( NULL ), bIsProxyModule( false ) { SetName( rName ); SetFlag( SBX_EXTSEARCH | SBX_GBLSEARCH ); SetModuleType( script::ModuleType::NORMAL ); // #i92642: Set name property to intitial name SbxVariable* pNameProp = pProps->Find( String( RTL_CONSTASCII_USTRINGPARAM("Name") ), SbxCLASS_PROPERTY ); if( pNameProp != NULL ) pNameProp->PutString( GetName() ); } SbModule::~SbModule() { OSL_TRACE("Module named %s is destructing", rtl::OUStringToOString( GetName(), RTL_TEXTENCODING_UTF8 ).getStr() ); if( pImage ) delete pImage; if( pBreaks ) delete pBreaks; if( pClassData ) delete pClassData; mxWrapper = NULL; } uno::Reference< script::XInvocation > SbModule::GetUnoModule() { if ( !mxWrapper.is() ) mxWrapper = new DocObjectWrapper( this ); OSL_TRACE("Module named %s returning wrapper mxWrapper (0x%x)", rtl::OUStringToOString( GetName(), RTL_TEXTENCODING_UTF8 ).getStr(), mxWrapper.get() ); return mxWrapper; } sal_Bool SbModule::IsCompiled() const { return sal_Bool( pImage != 0 ); } const SbxObject* SbModule::FindType( String aTypeName ) const { return pImage ? pImage->FindType( aTypeName ) : NULL; } // Aus dem Codegenerator: Loeschen des Images und Invalidieren der Entries void SbModule::StartDefinitions() { delete pImage; pImage = NULL; if( pClassData ) pClassData->clear(); // Methoden und Properties bleiben erhalten, sind jedoch ungueltig // schliesslich sind ja u.U. die Infos belegt sal_uInt16 i; for( i = 0; i < pMethods->Count(); i++ ) { SbMethod* p = PTR_CAST(SbMethod,pMethods->Get( i ) ); if( p ) p->bInvalid = sal_True; } for( i = 0; i < pProps->Count(); ) { SbProperty* p = PTR_CAST(SbProperty,pProps->Get( i ) ); if( p ) pProps->Remove( i ); else i++; } } // Methode anfordern/anlegen SbMethod* SbModule::GetMethod( const String& rName, SbxDataType t ) { SbxVariable* p = pMethods->Find( rName, SbxCLASS_METHOD ); SbMethod* pMeth = p ? PTR_CAST(SbMethod,p) : NULL; if( p && !pMeth ) pMethods->Remove( p ); if( !pMeth ) { pMeth = new SbMethod( rName, t, this ); pMeth->SetParent( this ); pMeth->SetFlags( SBX_READ ); pMethods->Put( pMeth, pMethods->Count() ); StartListening( pMeth->GetBroadcaster(), sal_True ); } // Per Default ist die Methode GUELTIG, da sie auch vom Compiler // (Codegenerator) erzeugt werden kann pMeth->bInvalid = sal_False; pMeth->ResetFlag( SBX_FIXED ); pMeth->SetFlag( SBX_WRITE ); pMeth->SetType( t ); pMeth->ResetFlag( SBX_WRITE ); if( t != SbxVARIANT ) pMeth->SetFlag( SBX_FIXED ); return pMeth; } // Property anfordern/anlegen SbProperty* SbModule::GetProperty( const String& rName, SbxDataType t ) { SbxVariable* p = pProps->Find( rName, SbxCLASS_PROPERTY ); SbProperty* pProp = p ? PTR_CAST(SbProperty,p) : NULL; if( p && !pProp ) pProps->Remove( p ); if( !pProp ) { pProp = new SbProperty( rName, t, this ); pProp->SetFlag( SBX_READWRITE ); pProp->SetParent( this ); pProps->Put( pProp, pProps->Count() ); StartListening( pProp->GetBroadcaster(), sal_True ); } return pProp; } SbProcedureProperty* SbModule::GetProcedureProperty ( const String& rName, SbxDataType t ) { SbxVariable* p = pProps->Find( rName, SbxCLASS_PROPERTY ); SbProcedureProperty* pProp = p ? PTR_CAST(SbProcedureProperty,p) : NULL; if( p && !pProp ) pProps->Remove( p ); if( !pProp ) { pProp = new SbProcedureProperty( rName, t ); pProp->SetFlag( SBX_READWRITE ); pProp->SetParent( this ); pProps->Put( pProp, pProps->Count() ); StartListening( pProp->GetBroadcaster(), sal_True ); } return pProp; } SbIfaceMapperMethod* SbModule::GetIfaceMapperMethod ( const String& rName, SbMethod* pImplMeth ) { SbxVariable* p = pMethods->Find( rName, SbxCLASS_METHOD ); SbIfaceMapperMethod* pMapperMethod = p ? PTR_CAST(SbIfaceMapperMethod,p) : NULL; if( p && !pMapperMethod ) pMethods->Remove( p ); if( !pMapperMethod ) { pMapperMethod = new SbIfaceMapperMethod( rName, pImplMeth ); pMapperMethod->SetParent( this ); pMapperMethod->SetFlags( SBX_READ ); pMethods->Put( pMapperMethod, pMethods->Count() ); } pMapperMethod->bInvalid = sal_False; return pMapperMethod; } SbIfaceMapperMethod::~SbIfaceMapperMethod() { } TYPEINIT1(SbIfaceMapperMethod,SbMethod) // Aus dem Codegenerator: Ungueltige Eintraege entfernen void SbModule::EndDefinitions( sal_Bool bNewState ) { for( sal_uInt16 i = 0; i < pMethods->Count(); ) { SbMethod* p = PTR_CAST(SbMethod,pMethods->Get( i ) ); if( p ) { if( p->bInvalid ) pMethods->Remove( p ); else { p->bInvalid = bNewState; i++; } } else i++; } SetModified( sal_True ); } void SbModule::Clear() { delete pImage; pImage = NULL; if( pClassData ) pClassData->clear(); SbxObject::Clear(); } SbxVariable* SbModule::Find( const XubString& rName, SbxClassType t ) { // make sure a search in an uninstatiated class module will fail SbxVariable* pRes = SbxObject::Find( rName, t ); if ( bIsProxyModule && !GetSbData()->bRunInit ) return NULL; if( !pRes && pImage ) { SbiInstance* pInst = pINST; if( pInst && pInst->IsCompatibility() ) { // Put enum types as objects into module, // allows MyEnum.First notation SbxArrayRef xArray = pImage->GetEnums(); if( xArray.Is() ) { SbxVariable* pEnumVar = xArray->Find( rName, SbxCLASS_DONTCARE ); SbxObject* pEnumObject = PTR_CAST( SbxObject, pEnumVar ); if( pEnumObject ) { bool bPrivate = pEnumObject->IsSet( SBX_PRIVATE ); String aEnumName = pEnumObject->GetName(); pRes = new SbxVariable( SbxOBJECT ); pRes->SetName( aEnumName ); pRes->SetParent( this ); pRes->SetFlag( SBX_READ ); if( bPrivate ) pRes->SetFlag( SBX_PRIVATE ); pRes->PutObject( pEnumObject ); } } } } return pRes; } const ::rtl::OUString& SbModule::GetSource32() const { return aOUSource; } const String& SbModule::GetSource() const { static String aRetStr; aRetStr = aOUSource; return aRetStr; } // Parent und BASIC sind eins! void SbModule::SetParent( SbxObject* p ) { // #118083: Assertion is not valid any more // DBG_ASSERT( !p || p->IsA( TYPE(StarBASIC) ), "SbModules nur in BASIC eintragen" ); pParent = p; } void SbModule::SFX_NOTIFY( SfxBroadcaster& rBC, const TypeId& rBCType, const SfxHint& rHint, const TypeId& rHintType ) { const SbxHint* pHint = PTR_CAST(SbxHint,&rHint); if( pHint ) { SbxVariable* pVar = pHint->GetVar(); SbProperty* pProp = PTR_CAST(SbProperty,pVar); SbMethod* pMeth = PTR_CAST(SbMethod,pVar); if( pProp ) { if( pProp->GetModule() != this ) SetError( SbxERR_BAD_ACTION ); } else if( pMeth ) { if( pHint->GetId() == SBX_HINT_DATAWANTED ) { if( pMeth->bInvalid && !Compile() ) // Auto-Compile hat nicht geklappt! StarBASIC::Error( SbERR_BAD_PROP_VALUE ); else { // Aufruf eines Unterprogramms SbModule* pOld = pMOD; pMOD = this; Run( (SbMethod*) pVar ); pMOD = pOld; } } } else { // #i92642: Special handling for name property to avoid // side effects when using name as variable implicitely bool bForwardToSbxObject = true; sal_uIntPtr nId = pHint->GetId(); if( (nId == SBX_HINT_DATAWANTED || nId == SBX_HINT_DATACHANGED) && pVar->GetName().EqualsIgnoreCaseAscii( "name" ) ) bForwardToSbxObject = false; if( bForwardToSbxObject ) SbxObject::SFX_NOTIFY( rBC, rBCType, rHint, rHintType ); } } } // Das Setzen der Source macht das Image ungueltig // und scant die Methoden-Definitionen neu ein void SbModule::SetSource( const String& r ) { SetSource32( r ); } void SbModule::SetSource32( const ::rtl::OUString& r ) { // Default basic mode to library container mode, but.. allow Option VBASupport 0/1 override SetVBACompat( getDefaultVBAMode( static_cast< StarBASIC*>( GetParent() ) ) ); aOUSource = r; StartDefinitions(); SbiTokenizer aTok( r ); while( !aTok.IsEof() ) { SbiToken eEndTok = NIL; // Suchen nach SUB oder FUNCTION SbiToken eLastTok = NIL; while( !aTok.IsEof() ) { // #32385: Nicht bei declare SbiToken eCurTok = aTok.Next(); if( eLastTok != DECLARE ) { if( eCurTok == SUB ) { eEndTok = ENDSUB; break; } if( eCurTok == FUNCTION ) { eEndTok = ENDFUNC; break; } if( eCurTok == PROPERTY ) { eEndTok = ENDPROPERTY; break; } if( eCurTok == OPTION ) { eCurTok = aTok.Next(); if( eCurTok == COMPATIBLE ) aTok.SetCompatible( true ); else if ( ( eCurTok == VBASUPPORT ) && ( aTok.Next() == NUMBER ) ) { sal_Bool bIsVBA = ( aTok.GetDbl()== 1 ); SetVBACompat( bIsVBA ); aTok.SetCompatible( bIsVBA ); } } } eLastTok = eCurTok; } // Definition der Methode SbMethod* pMeth = NULL; if( eEndTok != NIL ) { sal_uInt16 nLine1 = aTok.GetLine(); if( aTok.Next() == SYMBOL ) { String aName_( aTok.GetSym() ); SbxDataType t = aTok.GetType(); if( t == SbxVARIANT && eEndTok == ENDSUB ) t = SbxVOID; pMeth = GetMethod( aName_, t ); pMeth->nLine1 = pMeth->nLine2 = nLine1; // Die Methode ist erst mal GUELTIG pMeth->bInvalid = sal_False; } else eEndTok = NIL; } // Skip bis END SUB/END FUNCTION if( eEndTok != NIL ) { while( !aTok.IsEof() ) { if( aTok.Next() == eEndTok ) { pMeth->nLine2 = aTok.GetLine(); break; } } if( aTok.IsEof() ) pMeth->nLine2 = aTok.GetLine(); } } EndDefinitions( sal_True ); } void SbModule::SetComment( const String& r ) { aComment = r; SetModified( sal_True ); } SbMethod* SbModule::GetFunctionForLine( sal_uInt16 nLine ) { for( sal_uInt16 i = 0; i < pMethods->Count(); i++ ) { SbMethod* p = (SbMethod*) pMethods->Get( i ); if( p->GetSbxId() == SBXID_BASICMETHOD ) { if( nLine >= p->nLine1 && nLine <= p->nLine2 ) return p; } } return NULL; } // Ausstrahlen eines Hints an alle Basics static void _SendHint( SbxObject* pObj, sal_uIntPtr nId, SbMethod* p ) { // Selbst ein BASIC? if( pObj->IsA( TYPE(StarBASIC) ) && pObj->IsBroadcaster() ) pObj->GetBroadcaster().Broadcast( SbxHint( nId, p ) ); // Dann die Unterobjekte fragen SbxArray* pObjs = pObj->GetObjects(); for( sal_uInt16 i = 0; i < pObjs->Count(); i++ ) { SbxVariable* pVar = pObjs->Get( i ); if( pVar->IsA( TYPE(SbxObject) ) ) _SendHint( PTR_CAST(SbxObject,pVar), nId, p ); } } static void SendHint( SbxObject* pObj, sal_uIntPtr nId, SbMethod* p ) { while( pObj->GetParent() ) pObj = pObj->GetParent(); _SendHint( pObj, nId, p ); } // #57841 Uno-Objekte, die in RTL-Funktionen gehalten werden, // beim Programm-Ende freigeben, damit nichts gehalten wird. void ClearUnoObjectsInRTL_Impl_Rek( StarBASIC* pBasic ) { // return-Wert von CreateUnoService loeschen static String aName( RTL_CONSTASCII_USTRINGPARAM("CreateUnoService") ); SbxVariable* pVar = pBasic->GetRtl()->Find( aName, SbxCLASS_METHOD ); if( pVar ) pVar->SbxValue::Clear(); // return-Wert von CreateUnoDialog loeschen static String aName2( RTL_CONSTASCII_USTRINGPARAM("CreateUnoDialog") ); pVar = pBasic->GetRtl()->Find( aName2, SbxCLASS_METHOD ); if( pVar ) pVar->SbxValue::Clear(); // return-Wert von CDec loeschen static String aName3( RTL_CONSTASCII_USTRINGPARAM("CDec") ); pVar = pBasic->GetRtl()->Find( aName3, SbxCLASS_METHOD ); if( pVar ) pVar->SbxValue::Clear(); // return-Wert von CreateObject loeschen static String aName4( RTL_CONSTASCII_USTRINGPARAM("CreateObject") ); pVar = pBasic->GetRtl()->Find( aName4, SbxCLASS_METHOD ); if( pVar ) pVar->SbxValue::Clear(); // Ueber alle Sub-Basics gehen SbxArray* pObjs = pBasic->GetObjects(); sal_uInt16 nCount = pObjs->Count(); for( sal_uInt16 i = 0 ; i < nCount ; i++ ) { SbxVariable* pObjVar = pObjs->Get( i ); StarBASIC* pSubBasic = PTR_CAST( StarBASIC, pObjVar ); if( pSubBasic ) ClearUnoObjectsInRTL_Impl_Rek( pSubBasic ); } } void ClearUnoObjectsInRTL_Impl( StarBASIC* pBasic ) { // #67781 Rueckgabewerte der Uno-Methoden loeschen clearUnoMethods(); clearUnoServiceCtors(); ClearUnoObjectsInRTL_Impl_Rek( pBasic ); // Oberstes Basic suchen SbxObject* p = pBasic; while( p->GetParent() ) p = p->GetParent(); if( ((StarBASIC*)p) != pBasic ) ClearUnoObjectsInRTL_Impl_Rek( (StarBASIC*)p ); } sal_Bool SbModule::IsVBACompat() const { return mbVBACompat; } void SbModule::SetVBACompat( sal_Bool bCompat ) { if( mbVBACompat != bCompat ) { mbVBACompat = bCompat; // initialize VBA document API if( mbVBACompat ) try { StarBASIC* pBasic = static_cast< StarBASIC* >( GetParent() ); uno::Reference< lang::XMultiServiceFactory > xFactory( getDocumentModel( pBasic ), uno::UNO_QUERY_THROW ); xFactory->createInstance( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ooo.vba.VBAGlobals" ) ) ); } catch( Exception& ) { } } } // Ausfuehren eines BASIC-Unterprogramms sal_uInt16 SbModule::Run( SbMethod* pMeth ) { static sal_uInt16 nMaxCallLevel = 0; static String aMSOMacroRuntimeLibName = String::CreateFromAscii( "Launcher" ); static String aMSOMacroRuntimeAppSymbol = String::CreateFromAscii( "Application" ); sal_uInt16 nRes = 0; sal_Bool bDelInst = sal_Bool( pINST == NULL ); StarBASICRef xBasic; uno::Reference< frame::XModel > xModel; uno::Reference< script::vba::XVBACompatibility > xVBACompat; if( bDelInst ) { #ifdef DBG_TRACE_BASIC dbg_InitTrace(); #endif // #32779: Basic waehrend der Ausfuehrung festhalten xBasic = (StarBASIC*) GetParent(); pINST = new SbiInstance( (StarBASIC*) GetParent() ); /* If a VBA script in a document is started, get the VBA compatibility interface from the document Basic library container, and notify all VBA script listeners about the started script. */ if( mbVBACompat ) { StarBASIC* pBasic = static_cast< StarBASIC* >( GetParent() ); if( pBasic && pBasic->IsDocBasic() ) try { xModel.set( getDocumentModel( pBasic ), uno::UNO_SET_THROW ); xVBACompat.set( getVBACompatibility( xModel ), uno::UNO_SET_THROW ); xVBACompat->broadcastVBAScriptEvent( script::vba::VBAScriptEventId::SCRIPT_STARTED, GetName() ); } catch( uno::Exception& ) { } } // Launcher problem // i80726 The Find below will genarate an error in Testtool so we reset it unless there was one before already sal_Bool bWasError = SbxBase::GetError() != 0; SbxVariable* pMSOMacroRuntimeLibVar = Find( aMSOMacroRuntimeLibName, SbxCLASS_OBJECT ); if ( !bWasError && (SbxBase::GetError() == SbxERR_PROC_UNDEFINED) ) SbxBase::ResetError(); if( pMSOMacroRuntimeLibVar ) { StarBASIC* pMSOMacroRuntimeLib = PTR_CAST(StarBASIC,pMSOMacroRuntimeLibVar); if( pMSOMacroRuntimeLib ) { sal_uInt16 nGblFlag = pMSOMacroRuntimeLib->GetFlags() & SBX_GBLSEARCH; pMSOMacroRuntimeLib->ResetFlag( SBX_GBLSEARCH ); SbxVariable* pAppSymbol = pMSOMacroRuntimeLib->Find( aMSOMacroRuntimeAppSymbol, SbxCLASS_METHOD ); pMSOMacroRuntimeLib->SetFlag( nGblFlag ); if( pAppSymbol ) { pMSOMacroRuntimeLib->SetFlag( SBX_EXTSEARCH ); // Could have been disabled before GetSbData()->pMSOMacroRuntimLib = pMSOMacroRuntimeLib; } } } // Error-Stack loeschen SbErrorStack*& rErrStack = GetSbData()->pErrStack; delete rErrStack; rErrStack = NULL; if( nMaxCallLevel == 0 ) { #ifdef UNX struct rlimit rl; getrlimit ( RLIMIT_STACK, &rl ); // printf( "RLIMIT_STACK = %ld\n", rl.rlim_cur ); #endif #if defined LINUX // Empiric value, 900 = needed bytes/Basic call level // for Linux including 10% safety margin nMaxCallLevel = rl.rlim_cur / 900; #elif defined SOLARIS // Empiric value, 1650 = needed bytes/Basic call level // for Solaris including 10% safety margin nMaxCallLevel = rl.rlim_cur / 1650; #elif defined WIN32 nMaxCallLevel = 5800; #else nMaxCallLevel = MAXRECURSION; #endif } } // Rekursion zu tief? if( ++pINST->nCallLvl <= nMaxCallLevel ) { // Globale Variable in allen Mods definieren GlobalRunInit( /* bBasicStart = */ bDelInst ); // Trat ein Compiler-Fehler auf? Dann starten wir nicht if( GetSbData()->bGlobalInitErr == sal_False ) { if( bDelInst ) { SendHint( GetParent(), SBX_HINT_BASICSTART, pMeth ); // 16.10.96: #31460 Neues Konzept fuer StepInto/Over/Out // Erklaerung siehe runtime.cxx bei SbiInstance::CalcBreakCallLevel() // BreakCallLevel ermitteln pINST->CalcBreakCallLevel( pMeth->GetDebugFlags() ); } SbModule* pOldMod = pMOD; pMOD = this; SbiRuntime* pRt = new SbiRuntime( this, pMeth, pMeth->nStart ); #ifdef DBG_TRACE_BASIC dbg_traceNotifyCall( this, pMeth, pINST->nCallLvl ); #endif pRt->pNext = pINST->pRun; if( pRt->pNext ) pRt->pNext->block(); pINST->pRun = pRt; if ( mbVBACompat ) { pINST->EnableCompatibility( sal_True ); } while( pRt->Step() ) {} if( pRt->pNext ) pRt->pNext->unblock(); #ifdef DBG_TRACE_BASIC bool bLeave = true; dbg_traceNotifyCall( this, pMeth, pINST->nCallLvl, bLeave ); #endif // #63710 Durch ein anderes Thread-Handling bei Events kann es passieren, // dass show-Aufruf an einem Dialog zurueckkehrt (durch schliessen des // Dialogs per UI), BEVOR ein per Event ausgeloester weitergehender Call, // der in Basic weiter oben im Stack steht und auf einen Basic-Breakpoint // gelaufen ist, zurueckkehrt. Dann wird unten die Instanz zerstoert und // wenn das noch im Call stehende Basic weiterlaeuft, gibt es einen GPF. // Daher muss hier gewartet werden, bis andere Call zurueckkehrt. if( bDelInst ) { // Hier mit 1 statt 0 vergleichen, da vor nCallLvl-- while( pINST->nCallLvl != 1 ) GetpApp()->Yield(); } nRes = sal_True; pINST->pRun = pRt->pNext; pINST->nCallLvl--; // Call-Level wieder runter // Gibt es eine uebergeordnete Runtime-Instanz? // Dann SbDEBUG_BREAK uebernehmen, wenn gesetzt SbiRuntime* pRtNext = pRt->pNext; if( pRtNext && (pRt->GetDebugFlags() & SbDEBUG_BREAK) ) pRtNext->SetDebugFlags( SbDEBUG_BREAK ); delete pRt; pMOD = pOldMod; if( bDelInst ) { // #57841 Uno-Objekte, die in RTL-Funktionen gehalten werden, // beim Programm-Ende freigeben, damit nichts gehalten wird. ClearUnoObjectsInRTL_Impl( xBasic ); clearNativeObjectWrapperVector(); DBG_ASSERT(pINST->nCallLvl==0,"BASIC-Call-Level > 0"); delete pINST, pINST = NULL, bDelInst = sal_False; // #i30690 vos::OGuard aSolarGuard( Application::GetSolarMutex() ); SendHint( GetParent(), SBX_HINT_BASICSTOP, pMeth ); GlobalRunDeInit(); #ifdef DBG_UTIL ResetCapturedAssertions(); #endif if( xVBACompat.is() ) { // notify all VBA script listeners about the stopped script try { xVBACompat->broadcastVBAScriptEvent( script::vba::VBAScriptEventId::SCRIPT_STOPPED, GetName() ); } catch( uno::Exception& ) { } // VBA always ensures screenupdating is enabled after completing ::basic::vba::lockControllersOfAllDocuments( xModel, sal_False ); ::basic::vba::enableContainerWindowsOfAllDocuments( xModel, sal_True ); } #ifdef DBG_TRACE_BASIC dbg_DeInitTrace(); #endif } } else pINST->nCallLvl--; // Call-Level wieder runter } else { pINST->nCallLvl--; // Call-Level wieder runter StarBASIC::FatalError( SbERR_STACK_OVERFLOW ); } StarBASIC* pBasic = PTR_CAST(StarBASIC,GetParent()); if( bDelInst ) { // #57841 Uno-Objekte, die in RTL-Funktionen gehalten werden, // beim Programm-Ende freigeben, damit nichts gehalten wird. ClearUnoObjectsInRTL_Impl( xBasic ); delete pINST; pINST = NULL; } if ( pBasic && pBasic->IsDocBasic() && pBasic->IsQuitApplication() && !pINST ) { Application::PostUserEvent( LINK( &AsyncQuitHandler::instance(), AsyncQuitHandler, OnAsyncQuit ), NULL ); } return nRes; } // Ausfuehren der Init-Methode eines Moduls nach dem Laden // oder der Compilation void SbModule::RunInit() { if( pImage && !pImage->bInit && pImage->GetFlag( SBIMG_INITCODE ) ) { // Flag setzen, dass RunInit aktiv ist (Testtool) GetSbData()->bRunInit = sal_True; // sal_Bool bDelInst = sal_Bool( pINST == NULL ); // if( bDelInst ) // pINST = new SbiInstance( (StarBASIC*) GetParent() ); SbModule* pOldMod = pMOD; pMOD = this; // Der Init-Code beginnt immer hier SbiRuntime* pRt = new SbiRuntime( this, NULL, 0 ); #ifdef DBG_TRACE_BASIC dbg_traceNotifyCall( this, NULL, 0 ); #endif pRt->pNext = pINST->pRun; pINST->pRun = pRt; while( pRt->Step() ) {} #ifdef DBG_TRACE_BASIC bool bLeave = true; dbg_traceNotifyCall( this, NULL, 0, bLeave ); #endif pINST->pRun = pRt->pNext; delete pRt; pMOD = pOldMod; // if( bDelInst ) // delete pINST, pINST = NULL; pImage->bInit = sal_True; pImage->bFirstInit = sal_False; // RunInit ist nicht mehr aktiv GetSbData()->bRunInit = sal_False; } } // Mit private/dim deklarierte Variablen loeschen void SbModule::AddVarName( const String& aName ) { // see if the name is added allready std::vector< String >::iterator it_end = mModuleVariableNames.end(); for ( std::vector< String >::iterator it = mModuleVariableNames.begin(); it != it_end; ++it ) { if ( aName == *it ) return; } mModuleVariableNames.push_back( aName ); } void SbModule::RemoveVars() { std::vector< String >::iterator it_end = mModuleVariableNames.end(); for ( std::vector< String >::iterator it = mModuleVariableNames.begin(); it != it_end; ++it ) { // We don't want a Find being called in a derived class ( e.g. // SbUserform because it could trigger say an initialise event // 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 ) SbxVariableRef p = SbModule::Find( *it, SbxCLASS_PROPERTY ); if( p.Is() ) Remove (p); } } void SbModule::ClearPrivateVars() { for( sal_uInt16 i = 0 ; i < pProps->Count() ; i++ ) { SbProperty* p = PTR_CAST(SbProperty,pProps->Get( i ) ); if( p ) { // Arrays nicht loeschen, sondern nur deren Inhalt if( p->GetType() & SbxARRAY ) { SbxArray* pArray = PTR_CAST(SbxArray,p->GetObject()); if( pArray ) { for( sal_uInt16 j = 0 ; j < pArray->Count() ; j++ ) { SbxVariable* pj = PTR_CAST(SbxVariable,pArray->Get( j )); pj->SbxValue::Clear(); /* sal_uInt16 nFlags = pj->GetFlags(); pj->SetFlags( (nFlags | SBX_WRITE) & (~SBX_FIXED) ); pj->PutEmpty(); pj->SetFlags( nFlags ); */ } } } else { p->SbxValue::Clear(); /* sal_uInt16 nFlags = p->GetFlags(); p->SetFlags( (nFlags | SBX_WRITE) & (~SBX_FIXED) ); p->PutEmpty(); p->SetFlags( nFlags ); */ } } } } void SbModule::implClearIfVarDependsOnDeletedBasic( SbxVariable* pVar, StarBASIC* pDeletedBasic ) { if( pVar->SbxValue::GetType() != SbxOBJECT || pVar->ISA( SbProcedureProperty ) ) return; SbxObject* pObj = PTR_CAST(SbxObject,pVar->GetObject()); if( pObj != NULL ) { SbxObject* p = pObj; SbModule* pMod = PTR_CAST( SbModule, p ); if( pMod != NULL ) pMod->ClearVarsDependingOnDeletedBasic( pDeletedBasic ); while( (p = p->GetParent()) != NULL ) { StarBASIC* pBasic = PTR_CAST( StarBASIC, p ); if( pBasic != NULL && pBasic == pDeletedBasic ) { pVar->SbxValue::Clear(); break; } } } } void SbModule::ClearVarsDependingOnDeletedBasic( StarBASIC* pDeletedBasic ) { (void)pDeletedBasic; for( sal_uInt16 i = 0 ; i < pProps->Count() ; i++ ) { SbProperty* p = PTR_CAST(SbProperty,pProps->Get( i ) ); if( p ) { if( p->GetType() & SbxARRAY ) { SbxArray* pArray = PTR_CAST(SbxArray,p->GetObject()); if( pArray ) { for( sal_uInt16 j = 0 ; j < pArray->Count() ; j++ ) { SbxVariable* pVar = PTR_CAST(SbxVariable,pArray->Get( j )); implClearIfVarDependsOnDeletedBasic( pVar, pDeletedBasic ); } } } else { implClearIfVarDependsOnDeletedBasic( p, pDeletedBasic ); } } } } // Zunaechst in dieses Modul, um 358-faehig zu bleiben // (Branch in sb.cxx vermeiden) void StarBASIC::ClearAllModuleVars( void ) { // Eigene Module initialisieren for ( sal_uInt16 nMod = 0; nMod < pModules->Count(); nMod++ ) { SbModule* pModule = (SbModule*)pModules->Get( nMod ); // Nur initialisieren, wenn der Startcode schon ausgefuehrt wurde if( pModule->pImage && pModule->pImage->bInit && !pModule->isProxyModule() && !pModule->ISA(SbObjModule) ) pModule->ClearPrivateVars(); } /* #88042 This code can delete already used public vars during runtime! // Alle Objekte ueberpruefen, ob es sich um ein Basic handelt // Wenn ja, auch dort initialisieren for ( sal_uInt16 nObj = 0; nObj < pObjs->Count(); nObj++ ) { SbxVariable* pVar = pObjs->Get( nObj ); StarBASIC* pBasic = PTR_CAST(StarBASIC,pVar); if( pBasic ) pBasic->ClearAllModuleVars(); } */ } // Ausfuehren des Init-Codes aller Module void SbModule::GlobalRunInit( sal_Bool bBasicStart ) { // Wenn kein Basic-Start, nur initialisieren, wenn Modul uninitialisiert if( !bBasicStart ) if( !(pImage && !pImage->bInit) ) return; // GlobalInitErr-Flag fuer Compiler-Error initialisieren // Anhand dieses Flags kann in SbModule::Run() nach dem Aufruf // von GlobalRunInit festgestellt werden, ob beim initialisieren // der Module ein Fehler auftrat. Dann wird nicht gestartet. GetSbData()->bGlobalInitErr = sal_False; // Parent vom Modul ist ein Basic StarBASIC *pBasic = PTR_CAST(StarBASIC,GetParent()); if( pBasic ) { pBasic->InitAllModules(); SbxObject* pParent_ = pBasic->GetParent(); if( pParent_ ) { StarBASIC * pParentBasic = PTR_CAST(StarBASIC,pParent_); if( pParentBasic ) { pParentBasic->InitAllModules( pBasic ); // #109018 Parent can also have a parent (library in doc) SbxObject* pParentParent = pParentBasic->GetParent(); if( pParentParent ) { StarBASIC * pParentParentBasic = PTR_CAST(StarBASIC,pParentParent); if( pParentParentBasic ) pParentParentBasic->InitAllModules( pParentBasic ); } } } } } void SbModule::GlobalRunDeInit( void ) { StarBASIC *pBasic = PTR_CAST(StarBASIC,GetParent()); if( pBasic ) { pBasic->DeInitAllModules(); SbxObject* pParent_ = pBasic->GetParent(); if( pParent_ ) pBasic = PTR_CAST(StarBASIC,pParent_); if( pBasic ) pBasic->DeInitAllModules(); } } // Suche nach dem naechsten STMNT-Befehl im Code. Wird vom STMNT- // Opcode verwendet, um die Endspalte zu setzen. const sal_uInt8* SbModule::FindNextStmnt( const sal_uInt8* p, sal_uInt16& nLine, sal_uInt16& nCol ) const { return FindNextStmnt( p, nLine, nCol, sal_False ); } const sal_uInt8* SbModule::FindNextStmnt( const sal_uInt8* p, sal_uInt16& nLine, sal_uInt16& nCol, sal_Bool bFollowJumps, const SbiImage* pImg ) const { sal_uInt32 nPC = (sal_uInt32) ( p - (const sal_uInt8*) pImage->GetCode() ); while( nPC < pImage->GetCodeSize() ) { SbiOpcode eOp = (SbiOpcode ) ( *p++ ); nPC++; if( bFollowJumps && eOp == _JUMP && pImg ) { DBG_ASSERT( pImg, "FindNextStmnt: pImg==NULL with FollowJumps option" ); sal_uInt32 nOp1 = *p++; nOp1 |= *p++ << 8; nOp1 |= *p++ << 16; nOp1 |= *p++ << 24; p = (const sal_uInt8*) pImg->GetCode() + nOp1; } else if( eOp >= SbOP1_START && eOp <= SbOP1_END ) p += 4, nPC += 4; else if( eOp == _STMNT ) { sal_uInt32 nl, nc; nl = *p++; nl |= *p++ << 8; nl |= *p++ << 16 ; nl |= *p++ << 24; nc = *p++; nc |= *p++ << 8; nc |= *p++ << 16 ; nc |= *p++ << 24; nLine = (sal_uInt16)nl; nCol = (sal_uInt16)nc; return p; } else if( eOp >= SbOP2_START && eOp <= SbOP2_END ) p += 8, nPC += 8; else if( !( eOp >= SbOP0_START && eOp <= SbOP0_END ) ) { StarBASIC::FatalError( SbERR_INTERNAL_ERROR ); break; } } return NULL; } // Testen, ob eine Zeile STMNT-Opcodes enthaelt sal_Bool SbModule::IsBreakable( sal_uInt16 nLine ) const { if( !pImage ) return sal_False; const sal_uInt8* p = (const sal_uInt8* ) pImage->GetCode(); sal_uInt16 nl, nc; while( ( p = FindNextStmnt( p, nl, nc ) ) != NULL ) if( nl == nLine ) return sal_True; return sal_False; } size_t SbModule::GetBPCount() const { return pBreaks ? pBreaks->size() : 0; } sal_uInt16 SbModule::GetBP( size_t n ) const { if( pBreaks && n < pBreaks->size() ) return pBreaks->operator[]( n ); else return 0; } sal_Bool SbModule::IsBP( sal_uInt16 nLine ) const { if( pBreaks ) { for( size_t i = 0; i < pBreaks->size(); i++ ) { sal_uInt16 b = pBreaks->operator[]( i ); if( b == nLine ) return sal_True; if( b < nLine ) break; } } return sal_False; } sal_Bool SbModule::SetBP( sal_uInt16 nLine ) { if( !IsBreakable( nLine ) ) return sal_False; if( !pBreaks ) pBreaks = new SbiBreakpoints; size_t i; for( i = 0; i < pBreaks->size(); i++ ) { sal_uInt16 b = pBreaks->operator[]( i ); if( b == nLine ) return sal_True; if( b < nLine ) break; } pBreaks->insert( pBreaks->begin() + i, nLine ); // #38568: Zur Laufzeit auch hier SbDEBUG_BREAK setzen if( pINST && pINST->pRun ) pINST->pRun->SetDebugFlags( SbDEBUG_BREAK ); return IsBreakable( nLine ); } sal_Bool SbModule::ClearBP( sal_uInt16 nLine ) { sal_Bool bRes = sal_False; if( pBreaks ) { for( size_t i = 0; i < pBreaks->size(); i++ ) { sal_uInt16 b = pBreaks->operator[]( i ); if( b == nLine ) { pBreaks->erase( pBreaks->begin() + i ); bRes = sal_True; break; } if( b < nLine ) break; } if( pBreaks->empty() ) delete pBreaks, pBreaks = NULL; } return bRes; } void SbModule::ClearAllBP() { delete pBreaks; pBreaks = NULL; } void SbModule::fixUpMethodStart( bool bCvtToLegacy, SbiImage* pImg ) const { if ( !pImg ) pImg = pImage; for( sal_uInt32 i = 0; i < pMethods->Count(); i++ ) { SbMethod* pMeth = PTR_CAST(SbMethod,pMethods->Get( (sal_uInt16)i ) ); if( pMeth ) { //fixup method start positions if ( bCvtToLegacy ) pMeth->nStart = pImg->CalcLegacyOffset( pMeth->nStart ); else pMeth->nStart = pImg->CalcNewOffset( (sal_uInt16)pMeth->nStart ); } } } sal_Bool SbModule::LoadData( SvStream& rStrm, sal_uInt16 nVer ) { Clear(); if( !SbxObject::LoadData( rStrm, 1 ) ) return sal_False; // Precaution... SetFlag( SBX_EXTSEARCH | SBX_GBLSEARCH ); sal_uInt8 bImage; rStrm >> bImage; if( bImage ) { SbiImage* p = new SbiImage; sal_uInt32 nImgVer = 0; if( !p->Load( rStrm, nImgVer ) ) { delete p; return sal_False; } // If the image is in old format, we fix up the method start offsets if ( nImgVer < B_EXT_IMG_VERSION ) { fixUpMethodStart( false, p ); p->ReleaseLegacyBuffer(); } aComment = p->aComment; SetName( p->aName ); if( p->GetCodeSize() ) { aOUSource = p->aOUSource; // Alte Version: Image weg if( nVer == 1 ) { SetSource32( p->aOUSource ); delete p; } else pImage = p; } else { SetSource32( p->aOUSource ); delete p; } } return sal_True; } sal_Bool SbModule::StoreData( SvStream& rStrm ) const { sal_Bool bFixup = ( pImage && !pImage->ExceedsLegacyLimits() ); if ( bFixup ) fixUpMethodStart( true ); sal_Bool bRet = SbxObject::StoreData( rStrm ); if ( !bRet ) return sal_False; if( pImage ) { pImage->aOUSource = aOUSource; pImage->aComment = aComment; pImage->aName = GetName(); rStrm << (sal_uInt8) 1; // # PCode is saved only for legacy formats only // It should be noted that it probably isn't necessary // It would be better not to store the image ( more flexible with // formats ) bool bRes = pImage->Save( rStrm, B_LEGACYVERSION ); if ( bFixup ) fixUpMethodStart( false ); // restore method starts return bRes; } else { SbiImage aImg; aImg.aOUSource = aOUSource; aImg.aComment = aComment; aImg.aName = GetName(); rStrm << (sal_uInt8) 1; return aImg.Save( rStrm ); } } sal_Bool SbModule::ExceedsLegacyModuleSize() { if ( !IsCompiled() ) Compile(); if ( pImage && pImage->ExceedsLegacyLimits() ) return true; return false; } // Store only image, no source sal_Bool SbModule::StoreBinaryData( SvStream& rStrm ) { return StoreBinaryData( rStrm, 0 ); } sal_Bool SbModule::StoreBinaryData( SvStream& rStrm, sal_uInt16 nVer ) { sal_Bool bRet = Compile(); if( bRet ) { sal_Bool bFixup = ( !nVer && !pImage->ExceedsLegacyLimits() );// save in old image format, fix up method starts if ( bFixup ) // save in old image format, fix up method starts fixUpMethodStart( true ); bRet = SbxObject::StoreData( rStrm ); if( bRet ) { pImage->aOUSource = ::rtl::OUString(); pImage->aComment = aComment; pImage->aName = GetName(); rStrm << (sal_uInt8) 1; if ( nVer ) bRet = pImage->Save( rStrm, B_EXT_IMG_VERSION ); else bRet = pImage->Save( rStrm, B_LEGACYVERSION ); if ( bFixup ) fixUpMethodStart( false ); // restore method starts pImage->aOUSource = aOUSource; } } return bRet; } // Called for >= OO 1.0 passwd protected libraries only // sal_Bool SbModule::LoadBinaryData( SvStream& rStrm ) { ::rtl::OUString aKeepSource = aOUSource; bool bRet = LoadData( rStrm, 2 ); LoadCompleted(); aOUSource = aKeepSource; return bRet; } sal_Bool SbModule::LoadCompleted() { SbxArray* p = GetMethods(); sal_uInt16 i; for( i = 0; i < p->Count(); i++ ) { SbMethod* q = PTR_CAST(SbMethod,p->Get( i ) ); if( q ) q->pMod = this; } p = GetProperties(); for( i = 0; i < p->Count(); i++ ) { SbProperty* q = PTR_CAST(SbProperty,p->Get( i ) ); if( q ) q->pMod = this; } return sal_True; } void SbModule::handleProcedureProperties( SfxBroadcaster& rBC, const SfxHint& rHint ) { bool bDone = false; const SbxHint* pHint = PTR_CAST(SbxHint,&rHint); if( pHint ) { SbxVariable* pVar = pHint->GetVar(); SbProcedureProperty* pProcProperty = PTR_CAST( SbProcedureProperty, pVar ); if( pProcProperty ) { bDone = true; if( pHint->GetId() == SBX_HINT_DATAWANTED ) { String aProcName; aProcName.AppendAscii( "Property Get " ); aProcName += pProcProperty->GetName(); SbxVariable* pMeth = Find( aProcName, SbxCLASS_METHOD ); if( pMeth ) { SbxValues aVals; aVals.eType = SbxVARIANT; SbxArray* pArg = pVar->GetParameters(); sal_uInt16 nVarParCount = (pArg != NULL) ? pArg->Count() : 0; if( nVarParCount > 1 ) { SbxArrayRef xMethParameters = new SbxArray; xMethParameters->Put( pMeth, 0 ); // Method as parameter 0 for( sal_uInt16 i = 1 ; i < nVarParCount ; ++i ) { SbxVariable* pPar = pArg->Get( i ); xMethParameters->Put( pPar, i ); } pMeth->SetParameters( xMethParameters ); pMeth->Get( aVals ); pMeth->SetParameters( NULL ); } else { pMeth->Get( aVals ); } pVar->Put( aVals ); } } else if( pHint->GetId() == SBX_HINT_DATACHANGED ) { SbxVariable* pMeth = NULL; bool bSet = pProcProperty->isSet(); if( bSet ) { pProcProperty->setSet( false ); String aProcName; aProcName.AppendAscii( "Property Set " ); aProcName += pProcProperty->GetName(); pMeth = Find( aProcName, SbxCLASS_METHOD ); } if( !pMeth ) // Let { String aProcName; aProcName.AppendAscii( "Property Let " ); aProcName += pProcProperty->GetName(); pMeth = Find( aProcName, SbxCLASS_METHOD ); } if( pMeth ) { // Setup parameters SbxArrayRef xArray = new SbxArray; xArray->Put( pMeth, 0 ); // Method as parameter 0 xArray->Put( pVar, 1 ); pMeth->SetParameters( xArray ); SbxValues aVals; pMeth->Get( aVals ); pMeth->SetParameters( NULL ); } } } } if( !bDone ) SbModule::Notify( rBC, rHint ); } ///////////////////////////////////////////////////////////////////////// // Implementation SbJScriptModule (Basic-Modul fuer JavaScript-Sourcen) SbJScriptModule::SbJScriptModule( const String& rName ) :SbModule( rName ) { } sal_Bool SbJScriptModule::LoadData( SvStream& rStrm, sal_uInt16 nVer ) { (void)nVer; Clear(); if( !SbxObject::LoadData( rStrm, 1 ) ) return sal_False; // Source-String holen String aTmp; rStrm.ReadByteString( aTmp, gsl_getSystemTextEncoding() ); aOUSource = aTmp; //rStrm >> aSource; return sal_True; } sal_Bool SbJScriptModule::StoreData( SvStream& rStrm ) const { if( !SbxObject::StoreData( rStrm ) ) return sal_False; // Source-String schreiben String aTmp = aOUSource; rStrm.WriteByteString( aTmp, gsl_getSystemTextEncoding() ); //rStrm << aSource; return sal_True; } ///////////////////////////////////////////////////////////////////////// SbMethod::SbMethod( const String& r, SbxDataType t, SbModule* p ) : SbxMethod( r, t ), pMod( p ) { bInvalid = sal_True; nStart = nDebugFlags = nLine1 = nLine2 = 0; refStatics = new SbxArray; // AB: 2.7.1996: HACK wegen 'Referenz kann nicht gesichert werden' SetFlag( SBX_NO_MODIFY ); } SbMethod::SbMethod( const SbMethod& r ) : SvRefBase( r ), SbxMethod( r ) { pMod = r.pMod; bInvalid = r.bInvalid; nStart = r.nStart; nDebugFlags = r.nDebugFlags; nLine1 = r.nLine1; nLine2 = r.nLine2; refStatics = r.refStatics; SetFlag( SBX_NO_MODIFY ); } SbMethod::~SbMethod() { } SbxArray* SbMethod::GetLocals() { if( pINST ) return pINST->GetLocals( this ); else return NULL; } void SbMethod::ClearStatics() { refStatics = new SbxArray; } SbxArray* SbMethod::GetStatics() { return refStatics; } sal_Bool SbMethod::LoadData( SvStream& rStrm, sal_uInt16 nVer ) { if( !SbxMethod::LoadData( rStrm, 1 ) ) return sal_False; sal_Int16 n; rStrm >> n; sal_Int16 nTempStart = (sal_Int16)nStart; // nDebugFlags = n; // AB 16.1.96: Nicht mehr uebernehmen if( nVer == 2 ) rStrm >> nLine1 >> nLine2 >> nTempStart >> bInvalid; // AB: 2.7.1996: HACK wegen 'Referenz kann nicht gesichert werden' SetFlag( SBX_NO_MODIFY ); nStart = nTempStart; return sal_True; } sal_Bool SbMethod::StoreData( SvStream& rStrm ) const { if( !SbxMethod::StoreData( rStrm ) ) return sal_False; rStrm << (sal_Int16) nDebugFlags << (sal_Int16) nLine1 << (sal_Int16) nLine2 << (sal_Int16) nStart << (sal_uInt8) bInvalid; return sal_True; } void SbMethod::GetLineRange( sal_uInt16& l1, sal_uInt16& l2 ) { l1 = nLine1; l2 = nLine2; } // Kann spaeter mal weg SbxInfo* SbMethod::GetInfo() { return pInfo; } // Schnittstelle zum Ausfuehren einer Methode aus den Applikationen // #34191# Mit speziellem RefCounting, damit das Basic nicht durch CloseDocument() // abgeschossen werden kann. Rueckgabewert wird als String geliefert. ErrCode SbMethod::Call( SbxValue* pRet ) { // RefCount vom Modul hochzaehlen SbModule* pMod_ = (SbModule*)GetParent(); pMod_->AddRef(); // RefCount vom Basic hochzaehlen StarBASIC* pBasic = (StarBASIC*)pMod_->GetParent(); pBasic->AddRef(); // Values anlegen, um Return-Wert zu erhalten SbxValues aVals; aVals.eType = SbxVARIANT; // #104083: Compile BEFORE get if( bInvalid && !pMod_->Compile() ) StarBASIC::Error( SbERR_BAD_PROP_VALUE ); Get( aVals ); if ( pRet ) pRet->Put( aVals ); // Gab es einen Error ErrCode nErr = SbxBase::GetError(); SbxBase::ResetError(); // Objekte freigeben pMod_->ReleaseRef(); pBasic->ReleaseRef(); return nErr; } // #100883 Own Broadcast for SbMethod void SbMethod::Broadcast( sal_uIntPtr nHintId ) { if( pCst && !IsSet( SBX_NO_BROADCAST ) && StaticIsEnabledBroadcasting() ) { // Da die Methode von aussen aufrufbar ist, hier noch einmal // die Berechtigung testen if( nHintId & SBX_HINT_DATAWANTED ) if( !CanRead() ) return; if( nHintId & SBX_HINT_DATACHANGED ) if( !CanWrite() ) return; if( pMod && !pMod->IsCompiled() ) pMod->Compile(); // Block broadcasts while creating new method SfxBroadcaster* pSave = pCst; pCst = NULL; SbMethod* pThisCopy = new SbMethod( *this ); SbMethodRef xHolder = pThisCopy; if( mpPar.Is() ) { // this, als Element 0 eintragen, aber den Parent nicht umsetzen! if( GetType() != SbxVOID ) mpPar->PutDirect( pThisCopy, 0 ); SetParameters( NULL ); } pCst = pSave; pSave->Broadcast( SbxHint( nHintId, pThisCopy ) ); sal_uInt16 nSaveFlags = GetFlags(); SetFlag( SBX_READWRITE ); pCst = NULL; Put( pThisCopy->GetValues_Impl() ); pCst = pSave; SetFlags( nSaveFlags ); } } ///////////////////////////////////////////////////////////////////////// // Implementation SbJScriptMethod (Method-Klasse als Wrapper fuer JavaScript-Funktionen) SbJScriptMethod::SbJScriptMethod( const String& r, SbxDataType t, SbModule* p ) : SbMethod( r, t, p ) { } SbJScriptMethod::~SbJScriptMethod() {} ///////////////////////////////////////////////////////////////////////// SbObjModule::SbObjModule( const String& rName, const com::sun::star::script::ModuleInfo& mInfo, bool bIsVbaCompatible ) : SbModule( rName, bIsVbaCompatible ) { SetModuleType( mInfo.ModuleType ); if ( mInfo.ModuleType == script::ModuleType::FORM ) { SetClassName( rtl::OUString::createFromAscii( "Form" ) ); } else if ( mInfo.ModuleObject.is() ) SetUnoObject( uno::makeAny( mInfo.ModuleObject ) ); } SbObjModule::~SbObjModule() { } void SbObjModule::SetUnoObject( const uno::Any& aObj ) throw ( uno::RuntimeException ) { SbUnoObject* pUnoObj = PTR_CAST(SbUnoObject,(SbxVariable*)pDocObject); if ( pUnoObj && pUnoObj->getUnoAny() == aObj ) // object is equal, nothing to do return; pDocObject = new SbUnoObject( GetName(), uno::makeAny( aObj ) ); com::sun::star::uno::Reference< com::sun::star::lang::XServiceInfo > xServiceInfo( aObj, com::sun::star::uno::UNO_QUERY_THROW ); if( xServiceInfo->supportsService( rtl::OUString::createFromAscii( "ooo.vba.excel.Worksheet" ) ) ) { SetClassName( rtl::OUString::createFromAscii( "Worksheet" ) ); } else if( xServiceInfo->supportsService( rtl::OUString::createFromAscii( "ooo.vba.excel.Workbook" ) ) ) { SetClassName( rtl::OUString::createFromAscii( "Workbook" ) ); } } SbxVariable* SbObjModule::GetObject() { return pDocObject; } SbxVariable* SbObjModule::Find( const XubString& rName, SbxClassType t ) { //OSL_TRACE("SbObjectModule find for %s", rtl::OUStringToOString( rName, RTL_TEXTENCODING_UTF8 ).getStr() ); SbxVariable* pVar = NULL; if ( pDocObject) pVar = pDocObject->Find( rName, t ); if ( !pVar ) pVar = SbModule::Find( rName, t ); return pVar; } void SbObjModule::SFX_NOTIFY( SfxBroadcaster& rBC, const TypeId& rBCType, const SfxHint& rHint, const TypeId& rHintType ) { SbModule::handleProcedureProperties( rBC, rHint ); } typedef ::cppu::WeakImplHelper3< awt::XTopWindowListener, awt::XWindowListener, document::XEventListener > FormObjEventListener_BASE; class FormObjEventListenerImpl : public FormObjEventListener_BASE { SbUserFormModule* mpUserForm; uno::Reference< lang::XComponent > mxComponent; uno::Reference< frame::XModel > mxModel; bool mbDisposed; sal_Bool mbOpened; sal_Bool mbActivated; sal_Bool mbShowing; FormObjEventListenerImpl(const FormObjEventListenerImpl&); // not defined FormObjEventListenerImpl& operator=(const FormObjEventListenerImpl&); // not defined public: FormObjEventListenerImpl( SbUserFormModule* pUserForm, const uno::Reference< lang::XComponent >& xComponent, const uno::Reference< frame::XModel >& xModel ) : mpUserForm( pUserForm ), mxComponent( xComponent), mxModel( xModel ), mbDisposed( false ), mbOpened( sal_False ), mbActivated( sal_False ), mbShowing( sal_False ) { if ( mxComponent.is() ) { OSL_TRACE("*********** Registering the listeners"); try { uno::Reference< awt::XTopWindow >( mxComponent, uno::UNO_QUERY_THROW )->addTopWindowListener( this ); } catch( uno::Exception& ) {} try { uno::Reference< awt::XWindow >( mxComponent, uno::UNO_QUERY_THROW )->addWindowListener( this ); } catch( uno::Exception& ) {} } if ( mxModel.is() ) { try { uno::Reference< document::XEventBroadcaster >( mxModel, uno::UNO_QUERY_THROW )->addEventListener( this ); } catch( uno::Exception& ) {} } } virtual ~FormObjEventListenerImpl() { removeListener(); } sal_Bool isShowing() const { return mbShowing; } void removeListener() { if ( mxComponent.is() && !mbDisposed ) { OSL_TRACE("*********** Removing the listeners"); try { uno::Reference< awt::XTopWindow >( mxComponent, uno::UNO_QUERY_THROW )->removeTopWindowListener( this ); } catch( uno::Exception& ) {} try { uno::Reference< awt::XWindow >( mxComponent, uno::UNO_QUERY_THROW )->removeWindowListener( this ); } catch( uno::Exception& ) {} } mxComponent.clear(); if ( mxModel.is() && !mbDisposed ) { try { uno::Reference< document::XEventBroadcaster >( mxModel, uno::UNO_QUERY_THROW )->removeEventListener( this ); } catch( uno::Exception& ) {} } mxModel.clear(); } virtual void SAL_CALL windowOpened( const lang::EventObject& /*e*/ ) throw (uno::RuntimeException) { if ( mpUserForm ) { mbOpened = sal_True; mbShowing = sal_True; if ( mbActivated ) { mbOpened = mbActivated = sal_False; mpUserForm->triggerActivateEvent(); } } } //liuchen 2009-7-21, support Excel VBA Form_QueryClose event virtual void SAL_CALL windowClosing( const lang::EventObject& /*e*/ ) throw (uno::RuntimeException) { #if IN_THE_FUTURE uno::Reference< awt::XDialog > xDialog( e.Source, uno::UNO_QUERY ); if ( xDialog.is() ) { uno::Reference< awt::XControl > xControl( xDialog, uno::UNO_QUERY ); if ( xControl->getPeer().is() ) { uno::Reference< document::XVbaMethodParameter > xVbaMethodParameter( xControl->getPeer(), uno::UNO_QUERY ); if ( xVbaMethodParameter.is() ) { #endif sal_Int8 nCancel = 0; sal_Int8 nCloseMode = ::ooo::vba::VbQueryClose::vbFormControlMenu; Sequence< Any > aParams; aParams.realloc(2); aParams[0] <<= nCancel; aParams[1] <<= nCloseMode; mpUserForm->triggerMethod( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Userform_QueryClose") ), aParams); #if IN_THE_FUTURE xVbaMethodParameter->setVbaMethodParameter( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("Cancel")), aParams[0]); return; } } } #endif } //liuchen 2009-7-21 virtual void SAL_CALL windowClosed( const lang::EventObject& /*e*/ ) throw (uno::RuntimeException) { mbOpened = sal_False; mbShowing = sal_False; } virtual void SAL_CALL windowMinimized( const lang::EventObject& /*e*/ ) throw (uno::RuntimeException) { } virtual void SAL_CALL windowNormalized( const lang::EventObject& /*e*/ ) throw (uno::RuntimeException) { } virtual void SAL_CALL windowActivated( const lang::EventObject& /*e*/ ) throw (uno::RuntimeException) { if ( mpUserForm ) { mbActivated = sal_True; if ( mbOpened ) { mbOpened = mbActivated = sal_False; mpUserForm->triggerActivateEvent(); } } } virtual void SAL_CALL windowDeactivated( const lang::EventObject& /*e*/ ) throw (uno::RuntimeException) { if ( mpUserForm ) mpUserForm->triggerDeactivateEvent(); } virtual void SAL_CALL windowResized( const awt::WindowEvent& /*e*/ ) throw (uno::RuntimeException) { if ( mpUserForm ) { mpUserForm->triggerResizeEvent(); mpUserForm->triggerLayoutEvent(); } } virtual void SAL_CALL windowMoved( const awt::WindowEvent& /*e*/ ) throw (uno::RuntimeException) { if ( mpUserForm ) mpUserForm->triggerLayoutEvent(); } virtual void SAL_CALL windowShown( const lang::EventObject& /*e*/ ) throw (uno::RuntimeException) { } virtual void SAL_CALL windowHidden( const lang::EventObject& /*e*/ ) throw (uno::RuntimeException) { } virtual void SAL_CALL notifyEvent( const document::EventObject& rEvent ) throw (uno::RuntimeException) { // early dosposing on document event "OnUnload", to be sure Basic still exists when calling VBA "UserForm_Terminate" if( rEvent.EventName == GlobalEventConfig::GetEventName( STR_EVENT_CLOSEDOC ) ) { removeListener(); mbDisposed = true; if ( mpUserForm ) mpUserForm->ResetApiObj(); // will trigger "UserForm_Terminate" } } virtual void SAL_CALL disposing( const lang::EventObject& /*Source*/ ) throw (uno::RuntimeException) { OSL_TRACE("** Userform/Dialog disposing"); removeListener(); mbDisposed = true; if ( mpUserForm ) mpUserForm->ResetApiObj( false ); // pass false (too late to trigger VBA events here) } }; SbUserFormModule::SbUserFormModule( const String& rName, const com::sun::star::script::ModuleInfo& mInfo, bool bIsCompat ) : SbObjModule( rName, mInfo, bIsCompat ) , m_mInfo( mInfo ) , mbInit( false ) { m_xModel.set( mInfo.ModuleObject, uno::UNO_QUERY_THROW ); } SbUserFormModule::~SbUserFormModule() { } void SbUserFormModule::ResetApiObj( bool bTriggerTerminateEvent ) { if ( bTriggerTerminateEvent && m_xDialog.is() ) // probably someone close the dialog window { triggerTerminateEvent(); } pDocObject = NULL; m_xDialog = NULL; } void SbUserFormModule::triggerMethod( const String& aMethodToRun ) { Sequence< Any > aArguments; triggerMethod( aMethodToRun, aArguments ); } void SbUserFormModule::triggerMethod( const String& aMethodToRun, Sequence< Any >& aArguments ) { OSL_TRACE("*** trigger %s ***", rtl::OUStringToOString( aMethodToRun, RTL_TEXTENCODING_UTF8 ).getStr() ); // Search method SbxVariable* pMeth = SbObjModule::Find( aMethodToRun, SbxCLASS_METHOD ); if( pMeth ) { if ( aArguments.getLength() > 0 ) // Setup parameters { SbxArrayRef xArray = new SbxArray; xArray->Put( pMeth, 0 ); // Method as parameter 0 for ( sal_Int32 i = 0; i < aArguments.getLength(); ++i ) { SbxVariableRef xSbxVar = new SbxVariable( SbxVARIANT ); unoToSbxValue( static_cast< SbxVariable* >( xSbxVar ), aArguments[i] ); xArray->Put( xSbxVar, static_cast< sal_uInt16 >( i ) + 1 ); // Enable passing by ref if ( xSbxVar->GetType() != SbxVARIANT ) xSbxVar->SetFlag( SBX_FIXED ); } pMeth->SetParameters( xArray ); SbxValues aVals; pMeth->Get( aVals ); for ( sal_Int32 i = 0; i < aArguments.getLength(); ++i ) { aArguments[i] = sbxToUnoValue( xArray->Get( static_cast< sal_uInt16 >(i) + 1) ); } pMeth->SetParameters( NULL ); } else { SbxValues aVals; pMeth->Get( aVals ); } } } void SbUserFormModule::triggerActivateEvent( void ) { OSL_TRACE("**** entering SbUserFormModule::triggerActivate"); triggerMethod( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("UserForm_Activate") ) ); OSL_TRACE("**** leaving SbUserFormModule::triggerActivate"); } void SbUserFormModule::triggerDeactivateEvent( void ) { OSL_TRACE("**** SbUserFormModule::triggerDeactivate"); triggerMethod( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Userform_Deactivate") ) ); } void SbUserFormModule::triggerInitializeEvent( void ) { if ( mbInit ) return; OSL_TRACE("**** SbUserFormModule::triggerInitializeEvent"); static String aInitMethodName( RTL_CONSTASCII_USTRINGPARAM("Userform_Initialize") ); triggerMethod( aInitMethodName ); mbInit = true; } void SbUserFormModule::triggerTerminateEvent( void ) { OSL_TRACE("**** SbUserFormModule::triggerTerminateEvent"); static String aTermMethodName( RTL_CONSTASCII_USTRINGPARAM("Userform_Terminate") ); triggerMethod( aTermMethodName ); mbInit=false; } void SbUserFormModule::triggerLayoutEvent( void ) { static String aMethodName( RTL_CONSTASCII_USTRINGPARAM("Userform_Layout") ); triggerMethod( aMethodName ); } void SbUserFormModule::triggerResizeEvent( void ) { static String aMethodName( RTL_CONSTASCII_USTRINGPARAM("Userform_Resize") ); triggerMethod( aMethodName ); } SbUserFormModuleInstance* SbUserFormModule::CreateInstance() { SbUserFormModuleInstance* pInstance = new SbUserFormModuleInstance( this, GetName(), m_mInfo, IsVBACompat() ); return pInstance; } SbUserFormModuleInstance::SbUserFormModuleInstance( SbUserFormModule* pParentModule, const String& rName, const com::sun::star::script::ModuleInfo& mInfo, bool bIsVBACompat ) : SbUserFormModule( rName, mInfo, bIsVBACompat ) , m_pParentModule( pParentModule ) { } sal_Bool SbUserFormModuleInstance::IsClass( const XubString& rName ) const { sal_Bool bParentNameMatches = m_pParentModule->GetName().EqualsIgnoreCaseAscii( rName ); sal_Bool bRet = bParentNameMatches || SbxObject::IsClass( rName ); return bRet; } SbxVariable* SbUserFormModuleInstance::Find( const XubString& rName, SbxClassType t ) { SbxVariable* pVar = m_pParentModule->Find( rName, t ); return pVar; } void SbUserFormModule::Load() { OSL_TRACE("** load() "); // forces a load if ( !pDocObject ) InitObject(); } //liuchen 2009-7-21 change to accmordate VBA's beheavior void SbUserFormModule::Unload() { OSL_TRACE("** Unload() "); sal_Int8 nCancel = 0; sal_Int8 nCloseMode = ::ooo::vba::VbQueryClose::vbFormCode; Sequence< Any > aParams; aParams.realloc(2); aParams[0] <<= nCancel; aParams[1] <<= nCloseMode; triggerMethod( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Userform_QueryClose") ), aParams); aParams[0] >>= nCancel; if (nCancel != 0) // Basic returns -1 for "True" { return; } if ( m_xDialog.is() ) { triggerTerminateEvent(); } // Search method SbxVariable* pMeth = SbObjModule::Find( String( RTL_CONSTASCII_USTRINGPARAM( "UnloadObject" ) ), SbxCLASS_METHOD ); if( pMeth ) { OSL_TRACE("Attempting too run the UnloadObjectMethod"); m_xDialog.clear(); //release ref to the uno object SbxValues aVals; bool bWaitForDispose = true; // assume dialog is showing if ( m_DialogListener.get() ) { bWaitForDispose = m_DialogListener->isShowing(); OSL_TRACE("Showing %d", bWaitForDispose ); } pMeth->Get( aVals); if ( !bWaitForDispose ) { // we've either already got a dispose or we'er never going to get one ResetApiObj(); } // else wait for dispose OSL_TRACE("UnloadObject completed ( we hope )"); } } //liuchen void registerComponentToBeDisposedForBasic( Reference< XComponent > xComponent, StarBASIC* pBasic ); void SbUserFormModule::InitObject() { try { String aHook( RTL_CONSTASCII_USTRINGPARAM( "VBAGlobals" ) ); SbUnoObject* pGlobs = (SbUnoObject*)GetParent()->Find( aHook, SbxCLASS_DONTCARE ); if ( m_xModel.is() && pGlobs ) { // broadcast INITIALIZE_USERFORM script event before the dialog is created Reference< script::vba::XVBACompatibility > xVBACompat( getVBACompatibility( m_xModel ), uno::UNO_SET_THROW ); xVBACompat->broadcastVBAScriptEvent( script::vba::VBAScriptEventId::INITIALIZE_USERFORM, GetName() ); uno::Reference< lang::XMultiServiceFactory > xVBAFactory( pGlobs->getUnoAny(), uno::UNO_QUERY_THROW ); uno::Reference< lang::XMultiServiceFactory > xFactory = comphelper::getProcessServiceFactory(); uno::Sequence< uno::Any > aArgs(1); aArgs[ 0 ] <<= m_xModel; rtl::OUString sDialogUrl( RTL_CONSTASCII_USTRINGPARAM("vnd.sun.star.script:" ) ); rtl::OUString sProjectName( RTL_CONSTASCII_USTRINGPARAM("Standard") ); if ( this->GetParent()->GetName().Len() ) sProjectName = this->GetParent()->GetName(); sDialogUrl = sDialogUrl.concat( sProjectName ).concat( rtl::OUString( '.') ).concat( GetName() ).concat( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("?location=document") ) ); uno::Reference< awt::XDialogProvider > xProvider( xFactory->createInstanceWithArguments( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.awt.DialogProvider")), aArgs ), uno::UNO_QUERY_THROW ); m_xDialog = xProvider->createDialog( sDialogUrl ); // create vba api object aArgs.realloc( 4 ); aArgs[ 0 ] = uno::Any(); aArgs[ 1 ] <<= m_xDialog; aArgs[ 2 ] <<= m_xModel; aArgs[ 3 ] <<= rtl::OUString( GetParent()->GetName() ); pDocObject = new SbUnoObject( GetName(), uno::makeAny( xVBAFactory->createInstanceWithArguments( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("ooo.vba.msforms.UserForm")), aArgs ) ) ); uno::Reference< lang::XComponent > xComponent( m_xDialog, uno::UNO_QUERY_THROW ); // the dialog must be disposed at the end! StarBASIC* pParentBasic = NULL; SbxObject* pCurObject = this; do { SbxObject* pObjParent = pCurObject->GetParent(); pParentBasic = PTR_CAST( StarBASIC, pObjParent ); pCurObject = pObjParent; } while( pParentBasic == NULL && pCurObject != NULL ); OSL_ASSERT( pParentBasic != NULL ); registerComponentToBeDisposedForBasic( xComponent, pParentBasic ); // if old listener object exists, remove it from dialog and document model if( m_DialogListener.is() ) m_DialogListener->removeListener(); m_DialogListener.set( new FormObjEventListenerImpl( this, xComponent, m_xModel ) ); triggerInitializeEvent(); } } catch( uno::Exception& ) { } } SbxVariable* SbUserFormModule::Find( const XubString& rName, SbxClassType t ) { if ( !pDocObject && !GetSbData()->bRunInit && pINST ) InitObject(); return SbObjModule::Find( rName, t ); } ///////////////////////////////////////////////////////////////////////// SbProperty::SbProperty( const String& r, SbxDataType t, SbModule* p ) : SbxProperty( r, t ), pMod( p ) { bInvalid = sal_False; } SbProperty::~SbProperty() {} ///////////////////////////////////////////////////////////////////////// SbProcedureProperty::~SbProcedureProperty() {}