/**************************************************************
 * 
 * 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 <list>

#include <vos/macros.hxx>
#include <vcl/svapp.hxx>
#include <tools/stream.hxx>
#include <svl/brdcst.hxx>
#include <tools/shl.hxx>
#include <basic/sbx.hxx>
#include "sbdiagnose.hxx"
#include "sb.hxx"
#include <sbjsmeth.hxx>
#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 <basic/hilight.hxx>
#include <svtools/syntaxhighlight.hxx>

#include <basic/basrdll.hxx>
#include <vos/mutex.hxx>
#include <basic/sbobjmod.hxx>
#include <basic/vbahelper.hxx>
#include <cppuhelper/implbase3.hxx>
#include <unotools/eventcfg.hxx>
#include <com/sun/star/lang/XServiceInfo.hpp>
#include <com/sun/star/script/ModuleType.hpp>
#include <com/sun/star/script/vba/XVBACompatibility.hpp>
#include <com/sun/star/script/vba/VBAScriptEventId.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/document/XEventBroadcaster.hpp>
#include <com/sun/star/document/XEventListener.hpp>

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 <sys/resource.h>
#endif

#include <stdio.h>
#include <com/sun/star/frame/XDesktop.hpp>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#include <comphelper/processfactory.hxx>
#include <vcl/svapp.hxx>
#include <map>
#include <com/sun/star/reflection/XProxyFactory.hpp>
#include <cppuhelper/implbase1.hxx>
#include <basic/sbobjmod.hxx>
#include <com/sun/star/uno/XAggregation.hpp>
#include <com/sun/star/script/XInvocation.hpp>

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 <com/sun/star/script/XLibraryContainer.hpp>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#include <com/sun/star/awt/XDialogProvider.hpp>
#include <com/sun/star/awt/XTopWindow.hpp>
#include <com/sun/star/awt/XWindow.hpp>
#include <com/sun/star/awt/XControl.hpp>
#include <cppuhelper/implbase1.hxx>
#include <comphelper/anytostring.hxx>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <ooo/vba/VbQueryClose.hpp>

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<m_Types.getLength(); ++i, ++pPtr )
        {
            if ( i == 0 ) 
                *pPtr = XInvocation::static_type( NULL );
            else
                *pPtr = sTypes[ i - 1 ];
        }
    }
    return m_Types;
}

Reference< XIntrospectionAccess > 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<HighlightPortion> 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()
{}

