/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_basic.hxx"

#include <list>

#include <vcl/svapp.hxx>
#include <tools/stream.hxx>
#include <svl/brdcst.hxx>
#include <tools/shl.hxx>
#include <basic/sbx.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 <svtools/syntaxhighlight.hxx>

#include <basic/basrdll.hxx>
#include <osl/mutex.hxx>
#include <basic/sbobjmod.hxx>
#include <cppuhelper/implbase2.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/document/XVbaMethodParameter.hpp>
#include <com/sun/star/beans/XPropertySet.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 <map>
#include <com/sun/star/script/XInvocation.hpp>

 using namespace ::com::sun::star;
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>

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;
        USHORT 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< USHORT >( 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 ( USHORT 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 )
    {
        USHORT 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 )
    {
        USHORT 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)

SV_DECL_VARARR(SbiBreakpoints,USHORT,4,4)
SV_IMPL_VARARR(SbiBreakpoints,USHORT)


SV_IMPL_VARARR(HighlightPortions, HighlightPortion)

bool getDefaultVBAMode( StarBASIC* pb )
{
    bool bResult = false;
    if ( pb && pb->IsDocBasic() )
    {
        uno::Any aDoc;
    if ( pb->GetUNOConstant( "ThisComponent", aDoc ) )
        {
            uno::Reference< beans::XPropertySet > xProp( aDoc, uno::UNO_QUERY );
            if ( xProp.is() )
            {
                uno::Reference< script::vba::XVBACompatibility > xVBAMode( xProp->getPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("BasicLibraries") ) ), uno::UNO_QUERY );
                if ( xVBAMode.is() )
                    bResult = xVBAMode->getVBACompatibilityMode() == sal_True;
            }
        }
    }
    return bResult;
}

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;
}

bool UnlockControllerHack( StarBASIC* pBasic )
{
    bool bRes = false;
    if ( pBasic && pBasic->IsDocBasic() )
    {
        uno::Any aUnoVar;
        ::rtl::OUString sVarName( ::rtl::OUString::createFromAscii( "ThisComponent" ) );
        SbUnoObject* pGlobs = dynamic_cast<SbUnoObject*>( pBasic->Find( sVarName, SbxCLASS_DONTCARE ) );
        if ( pGlobs )
            aUnoVar = pGlobs->getUnoAny();
        uno::Reference< frame::XModel > xModel( aUnoVar, uno::UNO_QUERY);
        if ( xModel.is() )
        {
            try
            {
                xModel->unlockControllers();
                bRes = true;
            }
            catch( uno::Exception& )
            {
            }
        }
    }
    return bRes;
}

/////////////////////////////////////////////////////////////////////////////

// A Basic module has set EXTSEARCH, so that the elements, that the modul contains,
// could be found from other module.

SbModule::SbModule( const String& rName,  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;
}

BOOL SbModule::IsCompiled() const
{
    return BOOL( pImage != 0 );
}

const SbxObject* SbModule::FindType( String aTypeName ) const
{
    return pImage ? pImage->FindType( aTypeName ) : NULL;
}


// From the code generator: deletion of images and the oposite of validation for entries

void SbModule::StartDefinitions()
{
    delete pImage; pImage = NULL;
    if( pClassData )
        pClassData->clear();

    // methods and properties persist, but they are invalid;
    // at least are the information under certain conditions clogged
    USHORT i;
    for( i = 0; i < pMethods->Count(); i++ )
    {
        SbMethod* p = PTR_CAST(SbMethod,pMethods->Get( i ) );
        if( p )
            p->bInvalid = TRUE;
    }
    for( i = 0; i < pProps->Count(); )
    {
        SbProperty* p = PTR_CAST(SbProperty,pProps->Get( i ) );
        if( p )
            pProps->Remove( i );
        else
            i++;
    }
}

// request/create method

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(), TRUE );
    }
    // The method is per default valid, because it could be
    // created from the compiler (code generator) as well.
    pMeth->bInvalid = 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;
}

// request/create property

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(), 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(), 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 = FALSE;
    return pMapperMethod;
}

SbIfaceMapperMethod::~SbIfaceMapperMethod()
{
}

TYPEINIT1(SbIfaceMapperMethod,SbMethod)


// From the code generator: remove invalid entries

void SbModule::EndDefinitions( BOOL bNewState )
{
    for( USHORT 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( 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 and BASIC are one!

void SbModule::SetParent( SbxObject* p )
{
    // #118083: Assertion is not valid any more
    // DBG_ASSERT( !p || p->IsA( TYPE(StarBASIC) ), "Register SbModules only in BASIC" );
    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);
        SbProcedureProperty* pProcProperty = PTR_CAST( SbProcedureProperty, pVar );
        if( pProcProperty )
        {

            if( pHint->GetId() == SBX_HINT_DATAWANTED )
            {
                String aProcName;
                aProcName.AppendAscii( "Property Get " );
                aProcName += pProcProperty->GetName();

                SbxVariable* pMethVar = Find( aProcName, SbxCLASS_METHOD );
                if( pMethVar )
                {
                    SbxValues aVals;
                    aVals.eType = SbxVARIANT;

                    SbxArray* pArg = pVar->GetParameters();
                    USHORT nVarParCount = (pArg != NULL) ? pArg->Count() : 0;
                    if( nVarParCount > 1 )
                    {
                        SbxArrayRef xMethParameters = new SbxArray;
                        xMethParameters->Put( pMethVar, 0 );	// Method as parameter 0
                        for( USHORT i = 1 ; i < nVarParCount ; ++i )
                        {
                            SbxVariable* pPar = pArg->Get( i );
                            xMethParameters->Put( pPar, i );
                        }

                        pMethVar->SetParameters( xMethParameters );
                        pMethVar->Get( aVals );
                        pMethVar->SetParameters( NULL );
                    }
                    else
                    {
                        pMethVar->Get( aVals );
                    }

                    pVar->Put( aVals );
                }
            }
            else if( pHint->GetId() == SBX_HINT_DATACHANGED )
            {
                SbxVariable* pMethVar = NULL;

                bool bSet = pProcProperty->isSet();
                if( bSet )
                {
                    pProcProperty->setSet( false );

                    String aProcName;
                    aProcName.AppendAscii( "Property Set " );
                    aProcName += pProcProperty->GetName();
                    pMethVar = Find( aProcName, SbxCLASS_METHOD );
                }
                if( !pMethVar )	// Let
                {
                    String aProcName;
                    aProcName.AppendAscii( "Property Let " );
                    aProcName += pProcProperty->GetName();
                    pMethVar = Find( aProcName, SbxCLASS_METHOD );
                }

                if( pMethVar )
                {
                    // Setup parameters
                    SbxArrayRef xArray = new SbxArray;
                    xArray->Put( pMethVar, 0 );	// Method as parameter 0
                    xArray->Put( pVar, 1 );
                    pMethVar->SetParameters( xArray );

                    SbxValues aVals;
                    pMethVar->Get( aVals );
                    pMethVar->SetParameters( NULL );
                }
            }
        }
        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 has not worked!
                    StarBASIC::Error( SbERR_BAD_PROP_VALUE );
                else
                {
                    // Call of a subprogram
                    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;

            ULONG 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 );
        }
    }
}

// The setting of the source makes the image invalid
// and scans the method definitions newly in

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 );
        aTok.SetCompatible( IsVBACompat() );
    while( !aTok.IsEof() )
    {
        SbiToken eEndTok = NIL;

        // Searching for SUB or FUNCTION
        SbiToken eLastTok = NIL;
        while( !aTok.IsEof() )
        {
            // #32385: not by 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 ) )
                    {
                            BOOL bIsVBA = ( aTok.GetDbl()== 1 );
                            SetVBACompat( bIsVBA );
                        aTok.SetCompatible( bIsVBA );
                    }
                }
            }
            eLastTok = eCurTok;
        }
        // Definition of the method
        SbMethod* pMeth = NULL;
        if( eEndTok != NIL )
        {
            USHORT 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;
                // The method is for a start VALID
                pMeth->bInvalid = FALSE;
            }
            else
                eEndTok = NIL;
        }
        // Skip up to 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( TRUE );
}

void SbModule::SetComment( const String& r )
{
    aComment = r;
    SetModified( TRUE );
}

SbMethod* SbModule::GetFunctionForLine( USHORT nLine )
{
    for( USHORT 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;
}

// Broadcast of a hint to all Basics

static void _SendHint( SbxObject* pObj, ULONG nId, SbMethod* p )
{
    // Self a BASIC?
    if( pObj->IsA( TYPE(StarBASIC) ) && pObj->IsBroadcaster() )
        pObj->GetBroadcaster().Broadcast( SbxHint( nId, p ) );
    // Then ask for the subobjects
    SbxArray* pObjs = pObj->GetObjects();
    for( USHORT 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, ULONG nId, SbMethod* p )
{
    while( pObj->GetParent() )
        pObj = pObj->GetParent();
    _SendHint( pObj, nId, p );
}

// #57841 Clear Uno-Objects, which were helt in RTL functions,
// at the end of the program, so that nothing were helt.
void ClearUnoObjectsInRTL_Impl_Rek( StarBASIC* pBasic )
{
    // delete the return value of CreateUnoService
    static String aName( RTL_CONSTASCII_USTRINGPARAM("CreateUnoService") );
    SbxVariable* pVar = pBasic->GetRtl()->Find( aName, SbxCLASS_METHOD );
    if( pVar )
        pVar->SbxValue::Clear();

    // delete the return value of CreateUnoDialog
    static String aName2( RTL_CONSTASCII_USTRINGPARAM("CreateUnoDialog") );
    pVar = pBasic->GetRtl()->Find( aName2, SbxCLASS_METHOD );
    if( pVar )
        pVar->SbxValue::Clear();

    // delete the return value of CDec
    static String aName3( RTL_CONSTASCII_USTRINGPARAM("CDec") );
    pVar = pBasic->GetRtl()->Find( aName3, SbxCLASS_METHOD );
    if( pVar )
        pVar->SbxValue::Clear();

    // delete return value of CreateObject
    static String aName4( RTL_CONSTASCII_USTRINGPARAM("CreateObject") );
    pVar = pBasic->GetRtl()->Find( aName4, SbxCLASS_METHOD );
    if( pVar )
        pVar->SbxValue::Clear();

    // Go over all Sub-Basics
    SbxArray* pObjs = pBasic->GetObjects();
    USHORT nCount = pObjs->Count();
    for( USHORT 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 Delete return values of the Uno-methods
    clearUnoMethods();
    clearUnoServiceCtors();

    ClearUnoObjectsInRTL_Impl_Rek( pBasic );

    // Search for the topmost Basic
    SbxObject* p = pBasic;
    while( p->GetParent() )
        p = p->GetParent();
    if( ((StarBASIC*)p) != pBasic )
        ClearUnoObjectsInRTL_Impl_Rek( (StarBASIC*)p );
}
BOOL SbModule::IsVBACompat() const
{
    return mbVBACompat;
}

void SbModule::SetVBACompat( BOOL bCompat )
{
    mbVBACompat = bCompat;
}
// Run a Basic-subprogram
USHORT SbModule::Run( SbMethod* pMeth )
{
    OSL_TRACE("About to run %s, vba compatmode is %d", rtl::OUStringToOString( pMeth->GetName(), RTL_TEXTENCODING_UTF8 ).getStr(), mbVBACompat );
    static USHORT nMaxCallLevel = 0;
    static String aMSOMacroRuntimeLibName = String::CreateFromAscii( "Launcher" );
    static String aMSOMacroRuntimeAppSymbol = String::CreateFromAscii( "Application" );

    USHORT nRes = 0;
    BOOL bDelInst = BOOL( pINST == NULL );
        bool bQuit = false;
    StarBASICRef xBasic;
    if( bDelInst )
    {
#ifdef DBG_TRACE_BASIC
        dbg_InitTrace();
#endif
        // #32779: Hold Basic during the execution
        xBasic = (StarBASIC*) GetParent();

        pINST = new SbiInstance( (StarBASIC*) GetParent() );

        // Delete the Error-Stack
        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
        }
    }

    // Recursion to deep?
    if( ++pINST->nCallLvl <= nMaxCallLevel )
    {
        // Define a globale variable in all Mods
        GlobalRunInit( /* bBasicStart = */ bDelInst );

        // Appeared a compiler error? Then we don't launch
        if( GetSbData()->bGlobalInitErr == FALSE )
        {
            if( bDelInst )
            {
                SendHint( GetParent(), SBX_HINT_BASICSTART, pMeth );

                // 1996-10-16: #31460 New concept for StepInto/Over/Out
                // For an explanation see runtime.cxx at SbiInstance::CalcBreakCallLevel()
                // Identify the BreakCallLevel
                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( 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 It can happen by an another thread handling at events,
            // that the show call returns to an dialog (by closing the
            // dialog per UI), before a by an event triggered further call returned,
            // which stands in Basic more top in the stack and that had been run on
            // a  Basic-Breakpoint. Then would the instance below destroyed. And if the Basic,
            // that stand still in the call, further runs, there is a GPF.
            // Thus here had to be wait until the other call comes back.
            if( bDelInst )
            {
                // Compare here with 1 instead of 0, because before nCallLvl--
                while( pINST->nCallLvl != 1 )
                    GetpApp()->Yield();
            }

            nRes = TRUE;
            pINST->pRun = pRt->pNext;
            pINST->nCallLvl--;			// Call-Level down again

            // Exist an higher-ranking runtime instance?
            // Then take over SbDEBUG_BREAK, if set
            SbiRuntime* pRtNext = pRt->pNext;
            if( pRtNext && (pRt->GetDebugFlags() & SbDEBUG_BREAK) )
                pRtNext->SetDebugFlags( SbDEBUG_BREAK );

            delete pRt;
            pMOD = pOldMod;
            if ( pINST->nCallLvl == 0 && IsVBACompat() )
            {
                // VBA always ensure screenupdating is enabled after completing
                StarBASIC* pBasic = PTR_CAST(StarBASIC,GetParent());
                if ( pBasic && pBasic->IsDocBasic() )
                {
                    UnlockControllerHack( pBasic );
                }
            }
            if( bDelInst )
            {
                // #57841 Clear Uno-Objects, which were helt in RTL functions,
                // at the end of the program, so that nothing were helt.
                ClearUnoObjectsInRTL_Impl( xBasic );

                DBG_ASSERT(pINST->nCallLvl==0,"BASIC-Call-Level > 0");
                delete pINST, pINST = NULL, bDelInst = FALSE;

                // #i30690
                SolarMutexGuard aSolarGuard;
                SendHint( GetParent(), SBX_HINT_BASICSTOP, pMeth );

                GlobalRunDeInit();
            }
        }
        else
               pINST->nCallLvl--;			// Call-Level down again
    }
    else
    {
        pINST->nCallLvl--;			// Call-Level down again
        StarBASIC::FatalError( SbERR_STACK_OVERFLOW );
    }

    // VBA always ensure screenupdating is enabled after completing
    StarBASIC* pBasic = PTR_CAST(StarBASIC,GetParent());
    if ( pBasic && pBasic->IsDocBasic() && !pINST )
        UnlockControllerHack( pBasic );
    if( bDelInst )
    {
       // #57841 Clear Uno-Objects, which were helt in RTL functions,
       // the end of the program, so that nothing were helt.
        ClearUnoObjectsInRTL_Impl( xBasic );

        delete pINST;
        pINST = NULL;
    }
    if ( pBasic && pBasic->IsDocBasic() && pBasic->IsQuitApplication() && !pINST )
            bQuit = true;
        if ( bQuit )
    {
        Application::PostUserEvent( LINK( &AsyncQuitHandler::instance(), AsyncQuitHandler, OnAsyncQuit ), NULL );
    }

    return nRes;
}

// Execute of the init method of a module after the loading
// or the compilation

void SbModule::RunInit()
{
    if( pImage
     && !pImage->bInit
     && pImage->GetFlag( SBIMG_INITCODE ) )
    {
        // Set flag, so that RunInit get activ (Testtool)
        GetSbData()->bRunInit = TRUE;

        // BOOL bDelInst = BOOL( pINST == NULL );
        // if( bDelInst )
            // pINST = new SbiInstance( (StarBASIC*) GetParent() );
        SbModule* pOldMod = pMOD;
        pMOD = this;
        // The init code starts always here
        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 = TRUE;
        pImage->bFirstInit = FALSE;

        // RunInit is not activ anymore
        GetSbData()->bRunInit = FALSE;
    }
}

// Delete with private/dim declared variables

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( USHORT i = 0 ; i < pProps->Count() ; i++ )
    {
        SbProperty* p = PTR_CAST(SbProperty,pProps->Get( i ) );
        if( p )
        {
            // Delete not the arrays, only their content
            if( p->GetType() & SbxARRAY )
            {
                SbxArray* pArray = PTR_CAST(SbxArray,p->GetObject());
                if( pArray )
                {
                    for( USHORT j = 0 ; j < pArray->Count() ; j++ )
                    {
                        SbxVariable* pj = PTR_CAST(SbxVariable,pArray->Get( j ));
                        pj->SbxValue::Clear();
                        /*
                        USHORT nFlags = pj->GetFlags();
                        pj->SetFlags( (nFlags | SBX_WRITE) & (~SBX_FIXED) );
                        pj->PutEmpty();
                        pj->SetFlags( nFlags );
                        */
                    }
                }
            }
            else
            {
                p->SbxValue::Clear();
                /*
                USHORT nFlags = p->GetFlags();
                p->SetFlags( (nFlags | SBX_WRITE) & (~SBX_FIXED) );
                p->PutEmpty();
                p->SetFlags( nFlags );
                */
            }
        }
    }
}

// At first in this module, to remain 358-capable
// (Avoid branch in sb.cxx)
void StarBASIC::ClearAllModuleVars( void )
{
    // Initialise the own module
    for ( USHORT nMod = 0; nMod < pModules->Count(); nMod++ )
    {
        SbModule* pModule = (SbModule*)pModules->Get( nMod );
        // Initialise only, if the startcode was already executed
        if( pModule->pImage && pModule->pImage->bInit )
            pModule->ClearPrivateVars();
    }

}

// Execution of the init-code of all module
void SbModule::GlobalRunInit( BOOL bBasicStart )
{
    // If no Basic-Start, only initialise, if the module is not initialised
    if( !bBasicStart )
        if( !(pImage && !pImage->bInit) )
            return;

    // Initialise GlobalInitErr-Flag for Compiler-Error
    // With the help of this flags could be located in SbModule::Run() after the call of
    // GlobalRunInit, if at the intialising of the module
    // an error occured. Then it will not be launched.
    GetSbData()->bGlobalInitErr = FALSE;

    // Parent of the module is a 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();
    }
}

// Search for the next STMNT-Command in the code. This was used from the STMNT-
// Opcode to set the endcolumn.

const BYTE* SbModule::FindNextStmnt( const BYTE* p, USHORT& nLine, USHORT& nCol ) const
{
    return FindNextStmnt( p, nLine, nCol, FALSE );
}

const BYTE* SbModule::FindNextStmnt( const BYTE* p, USHORT& nLine, USHORT& nCol,
    BOOL bFollowJumps, const SbiImage* pImg ) const
{
    UINT32 nPC = (UINT32) ( p - (const BYTE*) 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" );
            UINT32 nOp1 = *p++; nOp1 |= *p++ << 8;
            nOp1 |= *p++ << 16; nOp1 |= *p++ << 24;
            p = (const BYTE*) pImg->GetCode() + nOp1;
        }
        else if( eOp >= SbOP1_START && eOp <= SbOP1_END )
            p += 4, nPC += 4;
        else if( eOp == _STMNT )
        {
            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 = (USHORT)nl; nCol = (USHORT)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;
}

// Test, if a line contains STMNT-Opcodes

BOOL SbModule::IsBreakable( USHORT nLine ) const
{
    if( !pImage )
        return FALSE;
    const BYTE* p = (const BYTE* ) pImage->GetCode();
    USHORT nl, nc;
    while( ( p = FindNextStmnt( p, nl, nc ) ) != NULL )
        if( nl == nLine )
            return TRUE;
    return FALSE;
}

USHORT SbModule::GetBPCount() const
{
    return pBreaks ? pBreaks->Count() : 0;
}

USHORT SbModule::GetBP( USHORT n ) const
{
    if( pBreaks && n < pBreaks->Count() )
        return pBreaks->GetObject( n );
    else
        return 0;
}

BOOL SbModule::IsBP( USHORT nLine ) const
{
    if( pBreaks )
    {
        const USHORT* p = pBreaks->GetData();
        USHORT n = pBreaks->Count();
        for( USHORT i = 0; i < n; i++, p++ )
        {
            USHORT b = *p;
            if( b == nLine )
                return TRUE;
            if( b < nLine )
                break;
        }
    }
    return FALSE;
}

BOOL SbModule::SetBP( USHORT nLine )
{
    if( !IsBreakable( nLine ) )
        return FALSE;
    if( !pBreaks )
        pBreaks = new SbiBreakpoints;
    const USHORT* p = pBreaks->GetData();
    USHORT n = pBreaks->Count();
    USHORT i;
    for( i = 0; i < n; i++, p++ )
    {
        USHORT b = *p;
        if( b == nLine )
            return TRUE;
        if( b < nLine )
            break;
    }
    pBreaks->Insert( &nLine, 1, i );

    // #38568: Set during runtime as well here SbDEBUG_BREAK
    if( pINST && pINST->pRun )
        pINST->pRun->SetDebugFlags( SbDEBUG_BREAK );

    return IsBreakable( nLine );
}

BOOL SbModule::ClearBP( USHORT nLine )
{
    BOOL bRes = FALSE;
    if( pBreaks )
    {
        const USHORT* p = pBreaks->GetData();
        USHORT n = pBreaks->Count();
        for( USHORT i = 0; i < n; i++, p++ )
        {
            USHORT b = *p;
            if( b == nLine )
            {
                pBreaks->Remove( i, 1 ); bRes = TRUE; break;
            }
            if( b < nLine )
                break;
        }
        if( !pBreaks->Count() )
            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( UINT32 i = 0; i < pMethods->Count(); i++ )
        {
            SbMethod* pMeth = PTR_CAST(SbMethod,pMethods->Get( (USHORT)i ) );
            if( pMeth )
            {
                //fixup method start positions
                if ( bCvtToLegacy )
                    pMeth->nStart = pImg->CalcLegacyOffset( pMeth->nStart );
                else
                    pMeth->nStart = pImg->CalcNewOffset( (USHORT)pMeth->nStart );
            }
        }

}

BOOL SbModule::LoadData( SvStream& rStrm, USHORT nVer )
{
    Clear();
    if( !SbxObject::LoadData( rStrm, 1 ) )
        return FALSE;
    // As a precaution...
    SetFlag( SBX_EXTSEARCH | SBX_GBLSEARCH );
    BYTE bImage;
    rStrm >> bImage;
    if( bImage )
    {
        SbiImage* p = new SbiImage;
        UINT32 nImgVer = 0;

        if( !p->Load( rStrm, nImgVer ) )
        {
            delete p;
            return 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;
            // Old version: image away
            if( nVer == 1 )
            {
                SetSource32( p->aOUSource );
                delete p;
            }
            else
                pImage = p;
        }
        else
        {
            SetSource32( p->aOUSource );
            delete p;
        }
    }
    return TRUE;
}

BOOL SbModule::StoreData( SvStream& rStrm ) const
{
    BOOL bFixup = ( pImage && !pImage->ExceedsLegacyLimits() );
    if ( bFixup )
        fixUpMethodStart( true );
    BOOL bRet = SbxObject::StoreData( rStrm );
    if ( !bRet )
        return FALSE;

    if( pImage )
    {
        pImage->aOUSource = aOUSource;
        pImage->aComment = aComment;
        pImage->aName = GetName();
        rStrm << (BYTE) 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 << (BYTE) 1;
        return aImg.Save( rStrm );
    }
}

BOOL SbModule::ExceedsLegacyModuleSize()
{
    if ( !IsCompiled() )
        Compile();
    if ( pImage && pImage->ExceedsLegacyLimits() )
        return true;
    return false;
}

class ErrorHdlResetter
{
    Link    mErrHandler;
    bool mbError;
    public:
    ErrorHdlResetter() : mbError( false )
    {
        // save error handler
        mErrHandler = StarBASIC::GetGlobalErrorHdl();
        // set new error handler
        StarBASIC::SetGlobalErrorHdl( LINK( this, ErrorHdlResetter, BasicErrorHdl ) );
    }
    ~ErrorHdlResetter()
    {
        // restore error handler
        StarBASIC::SetGlobalErrorHdl(mErrHandler);
    }
    DECL_LINK( BasicErrorHdl, StarBASIC * );
    bool HasError() { return mbError; }
};
IMPL_LINK( ErrorHdlResetter, BasicErrorHdl, StarBASIC *, /*pBasic*/)
{
    mbError = true;
    return 0;
}

bool SbModule::HasExeCode()
{
    // And empty Image always has the Global Chain set up
    static const unsigned char pEmptyImage[] = { 0x45, 0x0 , 0x0, 0x0, 0x0 };
    // lets be stricter for the moment than VBA

    if (!IsCompiled())
    {
        ErrorHdlResetter aGblErrHdl;
        Compile();
        if (aGblErrHdl.HasError()) //assume unsafe on compile error
            return true;
    }

    bool bRes = false;
    if (pImage && !(pImage->GetCodeSize() == 5 && (memcmp(pImage->GetCode(), pEmptyImage, pImage->GetCodeSize()) == 0 )))
        bRes = true;

    return bRes;
}

// Store only image, no source
BOOL SbModule::StoreBinaryData( SvStream& rStrm )
{
    return StoreBinaryData( rStrm, 0 );
}

BOOL SbModule::StoreBinaryData( SvStream& rStrm, USHORT nVer )
{
    BOOL bRet = Compile();
    if( bRet )
    {
        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 << (BYTE) 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
//

BOOL SbModule::LoadBinaryData( SvStream& rStrm )
{
    ::rtl::OUString aKeepSource = aOUSource;
    bool bRet = LoadData( rStrm, 2 );
    LoadCompleted();
    aOUSource = aKeepSource;
    return bRet;
}

BOOL SbModule::LoadCompleted()
{
    SbxArray* p = GetMethods();
    USHORT 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 TRUE;
}

/////////////////////////////////////////////////////////////////////////
// Implementation SbJScriptModule (Basic-Modul fuer JavaScript-Sourcen)
SbJScriptModule::SbJScriptModule( const String& rName )
    :SbModule( rName )
{
}

BOOL SbJScriptModule::LoadData( SvStream& rStrm, USHORT nVer )
{
    (void)nVer;

    Clear();
    if( !SbxObject::LoadData( rStrm, 1 ) )
        return FALSE;

    // Get the source string
    String aTmp;
    rStrm.ReadByteString( aTmp, gsl_getSystemTextEncoding() );
    aOUSource = aTmp;
    //rStrm >> aSource;
    return TRUE;
}

BOOL SbJScriptModule::StoreData( SvStream& rStrm ) const
{
    if( !SbxObject::StoreData( rStrm ) )
        return FALSE;

    // Write the source string
    String aTmp = aOUSource;
    rStrm.WriteByteString( aTmp, gsl_getSystemTextEncoding() );
    //rStrm << aSource;
    return TRUE;
}


/////////////////////////////////////////////////////////////////////////

SbMethod::SbMethod( const String& r, SbxDataType t, SbModule* p )
        : SbxMethod( r, t ), pMod( p )
{
    bInvalid	 = TRUE;
    nStart		 =
    nDebugFlags  =
    nLine1		 =
    nLine2		 = 0;
    refStatics = new SbxArray;
    mCaller          = 0;
    // From: 1996-07.02: HACK due to 'Referenz could not be saved'
    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;
    mCaller          = r.mCaller;
    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;
}

BOOL SbMethod::LoadData( SvStream& rStrm, USHORT nVer )
{
    if( !SbxMethod::LoadData( rStrm, 1 ) )
        return FALSE;
    INT16 n;
    rStrm >> n;
    INT16 nTempStart = (INT16)nStart;
    // nDebugFlags = n; 	// From 1996-01-16: no longer take over
    if( nVer == 2 )
        rStrm >> nLine1 >> nLine2 >> nTempStart >> bInvalid;
    // From: 1996-07-02: HACK ue to 'Referenz could not be saved'
    SetFlag( SBX_NO_MODIFY );
    nStart = nTempStart;
    return TRUE;
}

BOOL SbMethod::StoreData( SvStream& rStrm ) const
{
    if( !SbxMethod::StoreData( rStrm ) )
        return FALSE;
    rStrm << (INT16) nDebugFlags
          << (INT16) nLine1
          << (INT16) nLine2
          << (INT16) nStart
          << (BYTE)  bInvalid;
    return TRUE;
}

void SbMethod::GetLineRange( USHORT& l1, USHORT& l2 )
{
    l1 = nLine1; l2 = nLine2;
}

// Could later be deleted

SbxInfo* SbMethod::GetInfo()
{
    return pInfo;
}

// Interface to execute a method of the applications
// #34191# With special RefCounting, damit so that the Basic was not fired of by CloseDocument()
// The return value will be delivered as string.
ErrCode SbMethod::Call( SbxValue* pRet, SbxVariable* pCaller )
{
    if ( pCaller )
    {
        OSL_TRACE("SbMethod::Call Have been passed a caller 0x%x", pCaller );
        mCaller = pCaller;
    }
    // RefCount vom Modul hochzaehlen
    SbModule* pMod_ = (SbModule*)GetParent();
    pMod_->AddRef();

    // Increment the RefCount of the Basic
    StarBASIC* pBasic = (StarBASIC*)pMod_->GetParent();
    pBasic->AddRef();

    // Establish the values to get the return value
    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 );

    // Was there an error
    ErrCode nErr = SbxBase::GetError();
    SbxBase::ResetError();

    // Release objects
    pMod_->ReleaseRef();
    pBasic->ReleaseRef();
    mCaller = 0;
    return nErr;
}


// #100883 Own Broadcast for SbMethod
void SbMethod::Broadcast( ULONG nHintId )
{
    if( pCst && !IsSet( SBX_NO_BROADCAST ) && StaticIsEnabledBroadcasting() )
    {
        // Because the method could be called from outside, test here once again
        // the authorisation
        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() )
        {
            // Enrigister this as element 0, but don't reset the parent!
            if( GetType() != SbxVOID )
                mpPar->PutDirect( pThisCopy, 0 );
               SetParameters( NULL );
        }

        pCst = pSave;
        pSave->Broadcast( SbxHint( nHintId, pThisCopy ) );

        USHORT nSaveFlags = GetFlags();
        SetFlag( SBX_READWRITE );
        pCst = NULL;
        Put( pThisCopy->GetValues_Impl() );
        pCst = pSave;
        SetFlags( nSaveFlags );
    }
}

/////////////////////////////////////////////////////////////////////////

// Implementation of SbJScriptMethod (method class as a wrapper for JavaScript-functions)

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 ) );
}
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;
}

typedef ::cppu::WeakImplHelper2< awt::XTopWindowListener, awt::XWindowListener > FormObjEventListener_BASE;

class FormObjEventListenerImpl : public FormObjEventListener_BASE
{
    SbUserFormModule* mpUserForm;
    uno::Reference< lang::XComponent > mxComponent;
    bool mbDisposed;
    sal_Bool mbOpened;
    sal_Bool mbActivated;
    sal_Bool mbShowing;
    FormObjEventListenerImpl(); // not defined
    FormObjEventListenerImpl(const FormObjEventListenerImpl&); // not defined

public:
    FormObjEventListenerImpl( SbUserFormModule* pUserForm, const uno::Reference< lang::XComponent >& xComponent ) :
        mpUserForm( pUserForm ), mxComponent( xComponent) ,
        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& ) {}
        }
    }

    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();
    }

    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();
            }
        }
    }


    virtual void SAL_CALL windowClosing( const lang::EventObject& e ) throw (uno::RuntimeException)
    {
        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() )
                {
                    sal_Int8 nCancel = 0;
                    sal_Int8 nCloseMode = 0;

                    Sequence< Any > aParams;
                    aParams.realloc(2);
                    aParams[0] <<= nCancel;
                    aParams[1] <<= nCloseMode;

                    mpUserForm->triggerMethod( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Userform_QueryClose") ),
                                                aParams);
                    xVbaMethodParameter->setVbaMethodParameter( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("Cancel")), aParams[0]);
                    return;

                }
            }
        }

        mpUserForm->triggerMethod( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Userform_QueryClose") ) );
    }


    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 disposing( const lang::EventObject& /*Source*/ ) throw (uno::RuntimeException)
    {
        OSL_TRACE("** Userform/Dialog disposing");
        mbDisposed = true;
        mxComponent.clear();
        if ( mpUserForm )
            mpUserForm->ResetApiObj();
    }
};

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()
{
    if (  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< USHORT >( 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< USHORT >(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 )
{
}

BOOL SbUserFormModuleInstance::IsClass( const XubString& rName ) const
{
    BOOL bParentNameMatches = m_pParentModule->GetName().EqualsIgnoreCaseAscii( rName );
    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();
}


void SbUserFormModule::Unload()
{
    OSL_TRACE("** Unload() ");

    sal_Int8 nCancel = 0;
    sal_Int8 nCloseMode = 1;

    Sequence< Any > aParams;
    aParams.realloc(2);
    aParams[0] <<= nCancel;
    aParams[1] <<= nCloseMode;

    triggerMethod( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Userform_QueryClose") ), aParams);

    aParams[0] >>= nCancel;
    // basic boolean ( and what the user might use ) can be ambiguous ( e.g. basic true = -1 )
    // test agains 0 ( false ) and assume anything else is true
    // ( Note: ) this used to work ( something changes somewhere )
    if (nCancel != 0)
    {
        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 )");
    }
}


void SbUserFormModule::InitObject()
{
    try
    {

        String aHook( RTL_CONSTASCII_USTRINGPARAM( "VBAGlobals" ) );
        SbUnoObject* pGlobs = (SbUnoObject*)GetParent()->Find( aHook, SbxCLASS_DONTCARE );
        if ( m_xModel.is() && pGlobs )
        {

            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 ] <<= sProjectName;
            pDocObject = new SbUnoObject( GetName(), uno::makeAny( xVBAFactory->createInstanceWithArguments( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("ooo.vba.msforms.UserForm")), aArgs  ) ) );
            uno::Reference< lang::XComponent > xComponent( aArgs[ 1 ], uno::UNO_QUERY_THROW );
            // remove old listener if it exists
            if ( m_DialogListener.get() )
                m_DialogListener->removeListener();
            m_DialogListener = new FormObjEventListenerImpl( this, xComponent );

            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 = FALSE;
}

SbProperty::~SbProperty()
{}

/////////////////////////////////////////////////////////////////////////

SbProcedureProperty::~SbProcedureProperty()
{}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
