Files
libreoffice/basic/source/classes/sbunoobj.cxx
Stephan Bergmann b8a329989c Fix memory leak (missing typelib_TypeDescription_release)
...by radically simplifying TypeToIdlClass().  It is unclear to me why this was
so complicated.  The only mildly plausible reaons would be that the old code
was careful to return null instead of throwing an exception for an unknown type,
but the TypeToIdlClass-call-sites either strongly expect a non-null return value
(by dereferencing it without any further checking) or use OSL_ASSERT or similar
to verify it.  So lets hope this is good.

Change-Id: I3e24eb6117e84c9d33f4c5f0e2fa88da4c4f2c30
2014-05-28 14:34:12 +02:00

5127 lines
176 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* 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 .
*/
#include <osl/mutex.hxx>
#include <vcl/svapp.hxx>
#include <tools/errcode.hxx>
#include <svl/hint.hxx>
#include <cppuhelper/implbase1.hxx>
#include <cppuhelper/implbase2.hxx>
#include <cppuhelper/exc_hlp.hxx>
#include <cppuhelper/typeprovider.hxx>
#include <cppuhelper/interfacecontainer.hxx>
#include <comphelper/extract.hxx>
#include <comphelper/processfactory.hxx>
#include <rtl/instance.hxx>
#include <rtl/strbuf.hxx>
#include <rtl/ustrbuf.hxx>
#include <com/sun/star/script/ArrayWrapper.hpp>
#include <com/sun/star/script/NativeObjectWrapper.hpp>
#include <com/sun/star/uno/XComponentContext.hpp>
#include <com/sun/star/uno/DeploymentException.hpp>
#include <com/sun/star/lang/XTypeProvider.hpp>
#include <com/sun/star/lang/XSingleServiceFactory.hpp>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#include <com/sun/star/lang/XServiceInfo.hpp>
#include <com/sun/star/beans/PropertyAttribute.hpp>
#include <com/sun/star/beans/PropertyConcept.hpp>
#include <com/sun/star/beans/MethodConcept.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/beans/theIntrospection.hpp>
#include <com/sun/star/script/BasicErrorException.hpp>
#include <com/sun/star/script/InvocationAdapterFactory.hpp>
#include <com/sun/star/script/XAllListener.hpp>
#include <com/sun/star/script/XInvocationAdapterFactory.hpp>
#include <com/sun/star/script/Converter.hpp>
#include <com/sun/star/script/XDefaultProperty.hpp>
#include <com/sun/star/script/XDefaultMethod.hpp>
#include <com/sun/star/script/XDirectInvocation.hpp>
#include <com/sun/star/container/XNameAccess.hpp>
#include <com/sun/star/container/XHierarchicalNameAccess.hpp>
#include <com/sun/star/reflection/XIdlArray.hpp>
#include <com/sun/star/reflection/XIdlReflection.hpp>
#include <com/sun/star/reflection/XServiceConstructorDescription.hpp>
#include <com/sun/star/reflection/theCoreReflection.hpp>
#include <com/sun/star/bridge/oleautomation/NamedArgument.hpp>
#include <com/sun/star/bridge/oleautomation/Date.hpp>
#include <com/sun/star/bridge/oleautomation/Decimal.hpp>
#include <com/sun/star/bridge/oleautomation/Currency.hpp>
#include <com/sun/star/bridge/oleautomation/XAutomationObject.hpp>
#include <com/sun/star/script/XAutomationInvocation.hpp>
#include <basic/codecompletecache.hxx>
#include <rtlproto.hxx>
using com::sun::star::uno::Reference;
using namespace com::sun::star::uno;
using namespace com::sun::star::lang;
using namespace com::sun::star::reflection;
using namespace com::sun::star::beans;
using namespace com::sun::star::script;
using namespace com::sun::star::container;
using namespace com::sun::star::bridge;
using namespace cppu;
#include <basic/sbstar.hxx>
#include <basic/sbuno.hxx>
#include <basic/sberrors.hxx>
#include <sbunoobj.hxx>
#include "sbjsmod.hxx"
#include <basic/basmgr.hxx>
#include <sbintern.hxx>
#include <runtime.hxx>
#include <math.h>
#include <boost/unordered_map.hpp>
#include <com/sun/star/reflection/XTypeDescriptionEnumerationAccess.hpp>
#include <com/sun/star/reflection/XConstantsTypeDescription.hpp>
TYPEINIT1(SbUnoMethod,SbxMethod)
TYPEINIT1(SbUnoProperty,SbxProperty)
TYPEINIT1(SbUnoObject,SbxObject)
TYPEINIT1(SbUnoStructRefObject,SbxObject)
TYPEINIT1(SbUnoClass,SbxObject)
TYPEINIT1(SbUnoService,SbxObject)
TYPEINIT1(SbUnoServiceCtor,SbxMethod)
TYPEINIT1(SbUnoSingleton,SbxObject)
typedef WeakImplHelper1< XAllListener > BasicAllListenerHelper;
// Identifiers for creating the strings for dbg_Properties
static char const ID_DBG_SUPPORTEDINTERFACES[] = "Dbg_SupportedInterfaces";
static char const ID_DBG_PROPERTIES[] = "Dbg_Properties";
static char const ID_DBG_METHODS[] = "Dbg_Methods";
static char const aSeqLevelStr[] = "[]";
static char const defaultNameSpace[] = "ooo.vba";
// Gets the default property for an uno object. Note: There is some
// redirection built in. The property name specifies the name
// of the default property.
bool SbUnoObject::getDefaultPropName( SbUnoObject* pUnoObj, OUString& sDfltProp )
{
bool result = false;
Reference< XDefaultProperty> xDefaultProp( pUnoObj->maTmpUnoObj, UNO_QUERY );
if ( xDefaultProp.is() )
{
sDfltProp = xDefaultProp->getDefaultPropertyName();
if ( !sDfltProp.isEmpty() )
result = true;
}
return result;
}
SbxVariable* getDefaultProp( SbxVariable* pRef )
{
SbxVariable* pDefaultProp = NULL;
if ( pRef->GetType() == SbxOBJECT )
{
SbxObject* pObj = PTR_CAST(SbxObject,(SbxVariable*) pRef);
if ( !pObj )
{
SbxBase* pObjVarObj = pRef->GetObject();
pObj = PTR_CAST(SbxObject,pObjVarObj);
}
if ( pObj && pObj->ISA(SbUnoObject) )
{
SbUnoObject* pUnoObj = PTR_CAST(SbUnoObject,(SbxObject*)pObj);
pDefaultProp = pUnoObj->GetDfltProperty();
}
}
return pDefaultProp;
}
void SetSbUnoObjectDfltPropName( SbxObject* pObj )
{
SbUnoObject* pUnoObj = PTR_CAST(SbUnoObject,(SbxObject*) pObj);
if ( pUnoObj )
{
OUString sDfltPropName;
if ( SbUnoObject::getDefaultPropName( pUnoObj, sDfltPropName ) )
{
OSL_TRACE("SetSbUnoObjectDfltPropName setting default prop for %s", OUStringToOString( pObj->GetName(), RTL_TEXTENCODING_UTF8 ).getStr() );
pUnoObj->SetDfltProperty( sDfltPropName );
}
}
}
// save CoreReflection statically
Reference< XIdlReflection > getCoreReflection_Impl( void )
{
return css::reflection::theCoreReflection::get(
comphelper::getProcessComponentContext());
}
// save CoreReflection statically
Reference< XHierarchicalNameAccess > getCoreReflection_HierarchicalNameAccess_Impl( void )
{
static Reference< XHierarchicalNameAccess > xCoreReflection_HierarchicalNameAccess;
if( !xCoreReflection_HierarchicalNameAccess.is() )
{
Reference< XIdlReflection > xCoreReflection = getCoreReflection_Impl();
if( xCoreReflection.is() )
{
xCoreReflection_HierarchicalNameAccess =
Reference< XHierarchicalNameAccess >( xCoreReflection, UNO_QUERY );
}
}
return xCoreReflection_HierarchicalNameAccess;
}
// Hold TypeProvider statically
Reference< XHierarchicalNameAccess > getTypeProvider_Impl( void )
{
static Reference< XHierarchicalNameAccess > xAccess;
// Do we have already CoreReflection; if not obtain it
if( !xAccess.is() )
{
Reference< XComponentContext > xContext(
comphelper::getProcessComponentContext() );
if( xContext.is() )
{
xContext->getValueByName(
OUString( "/singletons/com.sun.star.reflection.theTypeDescriptionManager" ) )
>>= xAccess;
OSL_ENSURE( xAccess.is(), "### TypeDescriptionManager singleton not accessible!?" );
}
if( !xAccess.is() )
{
throw DeploymentException(
"/singletons/com.sun.star.reflection.theTypeDescriptionManager singleton not accessible" );
}
}
return xAccess;
}
// Hold TypeConverter statically
Reference< XTypeConverter > getTypeConverter_Impl( void )
{
static Reference< XTypeConverter > xTypeConverter;
// Do we have already CoreReflection; if not obtain it
if( !xTypeConverter.is() )
{
Reference< XComponentContext > xContext(
comphelper::getProcessComponentContext() );
if( xContext.is() )
{
xTypeConverter = Converter::create(xContext);
}
if( !xTypeConverter.is() )
{
throw DeploymentException(
"com.sun.star.script.Converter service not accessible" );
}
}
return xTypeConverter;
}
// #111851 factory function to create an OLE object
SbUnoObject* createOLEObject_Impl( const OUString& aType )
{
static Reference< XMultiServiceFactory > xOLEFactory;
static bool bNeedsInit = true;
if( bNeedsInit )
{
bNeedsInit = false;
Reference< XComponentContext > xContext(
comphelper::getProcessComponentContext() );
if( xContext.is() )
{
Reference<XMultiComponentFactory> xSMgr = xContext->getServiceManager();
xOLEFactory = Reference<XMultiServiceFactory>(
xSMgr->createInstanceWithContext(
OUString( "com.sun.star.bridge.OleObjectFactory"),
xContext ), UNO_QUERY );
}
}
SbUnoObject* pUnoObj = NULL;
if( xOLEFactory.is() )
{
// some type names available in VBA can not be directly used in COM
OUString aOLEType = aType;
if ( aOLEType == "SAXXMLReader30" )
{
aOLEType = "Msxml2.SAXXMLReader.3.0";
}
Reference< XInterface > xOLEObject = xOLEFactory->createInstance( aOLEType );
if( xOLEObject.is() )
{
Any aAny;
aAny <<= xOLEObject;
pUnoObj = new SbUnoObject( aType, aAny );
OUString sDfltPropName;
if ( SbUnoObject::getDefaultPropName( pUnoObj, sDfltPropName ) )
pUnoObj->SetDfltProperty( sDfltPropName );
}
}
return pUnoObj;
}
namespace
{
void lcl_indent( OUStringBuffer& _inout_rBuffer, sal_Int32 _nLevel )
{
while ( _nLevel-- > 0 )
{
_inout_rBuffer.appendAscii( " " );
}
}
}
void implAppendExceptionMsg( OUStringBuffer& _inout_rBuffer, const Exception& _e, const OUString& _rExceptionType, sal_Int32 _nLevel )
{
_inout_rBuffer.appendAscii( "\n" );
lcl_indent( _inout_rBuffer, _nLevel );
_inout_rBuffer.appendAscii( "Type: " );
if ( _rExceptionType.isEmpty() )
_inout_rBuffer.appendAscii( "Unknown" );
else
_inout_rBuffer.append( _rExceptionType );
_inout_rBuffer.appendAscii( "\n" );
lcl_indent( _inout_rBuffer, _nLevel );
_inout_rBuffer.appendAscii( "Message: " );
_inout_rBuffer.append( _e.Message );
}
// construct an error message for the exception
OUString implGetExceptionMsg( const Exception& e, const OUString& aExceptionType_ )
{
OUStringBuffer aMessageBuf;
implAppendExceptionMsg( aMessageBuf, e, aExceptionType_, 0 );
return aMessageBuf.makeStringAndClear();
}
OUString implGetExceptionMsg( const Any& _rCaughtException )
{
OSL_PRECOND( _rCaughtException.getValueTypeClass() == TypeClass_EXCEPTION, "implGetExceptionMsg: illegal argument!" );
if ( _rCaughtException.getValueTypeClass() != TypeClass_EXCEPTION )
{
return OUString();
}
return implGetExceptionMsg( *static_cast< const Exception* >( _rCaughtException.getValue() ), _rCaughtException.getValueTypeName() );
}
Any convertAny( const Any& rVal, const Type& aDestType )
{
Any aConvertedVal;
Reference< XTypeConverter > xConverter = getTypeConverter_Impl();
try
{
aConvertedVal = xConverter->convertTo( rVal, aDestType );
}
catch( const IllegalArgumentException& )
{
StarBASIC::Error( ERRCODE_BASIC_EXCEPTION,
implGetExceptionMsg( ::cppu::getCaughtException() ) );
return aConvertedVal;
}
catch( const CannotConvertException& e2 )
{
OUString aCannotConvertExceptionName( "com.sun.star.lang.IllegalArgumentException");
StarBASIC::Error( ERRCODE_BASIC_EXCEPTION,
implGetExceptionMsg( e2, aCannotConvertExceptionName ) );
return aConvertedVal;
}
return aConvertedVal;
}
// #105565 Special Object to wrap a strongly typed Uno Any
TYPEINIT1(SbUnoAnyObject,SbxObject)
// TODO: source out later
Reference<XIdlClass> TypeToIdlClass( const Type& rType )
{
return getCoreReflection_Impl()->forName(rType.getTypeName());
}
// Exception type unknown
template< class EXCEPTION >
OUString implGetExceptionMsg( const EXCEPTION& e )
{
return implGetExceptionMsg( e, ::getCppuType( &e ).getTypeName() );
}
void implHandleBasicErrorException( BasicErrorException& e )
{
SbError nError = StarBASIC::GetSfxFromVBError( (sal_uInt16)e.ErrorCode );
StarBASIC::Error( nError, e.ErrorMessageArgument );
}
void implHandleWrappedTargetException( const Any& _rWrappedTargetException )
{
Any aExamine( _rWrappedTargetException );
// completely strip the first InvocationTargetException, its error message isn't of any
// interest to the user, it just says something like "invoking the UNO method went wrong.".
InvocationTargetException aInvocationError;
if ( aExamine >>= aInvocationError )
aExamine = aInvocationError.TargetException;
BasicErrorException aBasicError;
SbError nError( ERRCODE_BASIC_EXCEPTION );
OUStringBuffer aMessageBuf;
// strip any other WrappedTargetException instances, but this time preserve the error messages.
WrappedTargetException aWrapped;
sal_Int32 nLevel = 0;
while ( aExamine >>= aWrapped )
{
// special handling for BasicErrorException errors
if ( aWrapped.TargetException >>= aBasicError )
{
nError = StarBASIC::GetSfxFromVBError( (sal_uInt16)aBasicError.ErrorCode );
aMessageBuf.append( aBasicError.ErrorMessageArgument );
aExamine.clear();
break;
}
// append this round's message
implAppendExceptionMsg( aMessageBuf, aWrapped, aExamine.getValueTypeName(), nLevel );
if ( aWrapped.TargetException.getValueTypeClass() == TypeClass_EXCEPTION )
// there is a next chain element
aMessageBuf.appendAscii( "\nTargetException:" );
// next round
aExamine = aWrapped.TargetException;
++nLevel;
}
if ( aExamine.getValueTypeClass() == TypeClass_EXCEPTION )
{
// the last element in the chain is still an exception, but no WrappedTargetException
implAppendExceptionMsg( aMessageBuf, *static_cast< const Exception* >( aExamine.getValue() ), aExamine.getValueTypeName(), nLevel );
}
StarBASIC::Error( nError, aMessageBuf.makeStringAndClear() );
}
static void implHandleAnyException( const Any& _rCaughtException )
{
BasicErrorException aBasicError;
WrappedTargetException aWrappedError;
if ( _rCaughtException >>= aBasicError )
{
implHandleBasicErrorException( aBasicError );
}
else if ( _rCaughtException >>= aWrappedError )
{
implHandleWrappedTargetException( _rCaughtException );
}
else
{
StarBASIC::Error( ERRCODE_BASIC_EXCEPTION, implGetExceptionMsg( _rCaughtException ) );
}
}
// NativeObjectWrapper handling
struct ObjectItem
{
SbxObjectRef m_xNativeObj;
ObjectItem( SbxObject* pNativeObj )
: m_xNativeObj( pNativeObj )
{}
};
typedef std::vector< ObjectItem > NativeObjectWrapperVector;
class GaNativeObjectWrapperVector : public rtl::Static<NativeObjectWrapperVector, GaNativeObjectWrapperVector> {};
void clearNativeObjectWrapperVector( void )
{
GaNativeObjectWrapperVector::get().clear();
}
static sal_uInt32 lcl_registerNativeObjectWrapper( SbxObject* pNativeObj )
{
NativeObjectWrapperVector &rNativeObjectWrapperVector = GaNativeObjectWrapperVector::get();
sal_uInt32 nIndex = rNativeObjectWrapperVector.size();
rNativeObjectWrapperVector.push_back( ObjectItem( pNativeObj ) );
return nIndex;
}
static SbxObject* lcl_getNativeObject( sal_uInt32 nIndex )
{
SbxObjectRef xRetObj;
NativeObjectWrapperVector &rNativeObjectWrapperVector = GaNativeObjectWrapperVector::get();
if( nIndex < rNativeObjectWrapperVector.size() )
{
ObjectItem& rItem = rNativeObjectWrapperVector[ nIndex ];
xRetObj = rItem.m_xNativeObj;
}
return xRetObj;
}
// convert from Uno to Sbx
SbxDataType unoToSbxType( TypeClass eType )
{
SbxDataType eRetType = SbxVOID;
switch( eType )
{
case TypeClass_INTERFACE:
case TypeClass_TYPE:
case TypeClass_STRUCT:
case TypeClass_EXCEPTION: eRetType = SbxOBJECT; break;
case TypeClass_ENUM: eRetType = SbxLONG; break;
case TypeClass_SEQUENCE:
eRetType = (SbxDataType) ( SbxOBJECT | SbxARRAY );
break;
case TypeClass_ANY: eRetType = SbxVARIANT; break;
case TypeClass_BOOLEAN: eRetType = SbxBOOL; break;
case TypeClass_CHAR: eRetType = SbxCHAR; break;
case TypeClass_STRING: eRetType = SbxSTRING; break;
case TypeClass_FLOAT: eRetType = SbxSINGLE; break;
case TypeClass_DOUBLE: eRetType = SbxDOUBLE; break;
case TypeClass_BYTE: eRetType = SbxINTEGER; break;
case TypeClass_SHORT: eRetType = SbxINTEGER; break;
case TypeClass_LONG: eRetType = SbxLONG; break;
case TypeClass_HYPER: eRetType = SbxSALINT64; break;
case TypeClass_UNSIGNED_SHORT: eRetType = SbxUSHORT; break;
case TypeClass_UNSIGNED_LONG: eRetType = SbxULONG; break;
case TypeClass_UNSIGNED_HYPER: eRetType = SbxSALUINT64;break;
default: break;
}
return eRetType;
}
SbxDataType unoToSbxType( const Reference< XIdlClass >& xIdlClass )
{
SbxDataType eRetType = SbxVOID;
if( xIdlClass.is() )
{
TypeClass eType = xIdlClass->getTypeClass();
eRetType = unoToSbxType( eType );
}
return eRetType;
}
static void implSequenceToMultiDimArray( SbxDimArray*& pArray, Sequence< sal_Int32 >& indices, Sequence< sal_Int32 >& sizes, const Any& aValue, sal_Int32& dimension, bool bIsZeroIndex, Type* pType = NULL )
{
Type aType = aValue.getValueType();
TypeClass eTypeClass = aType.getTypeClass();
sal_Int32 dimCopy = dimension;
if ( eTypeClass == TypeClass_SEQUENCE )
{
Reference< XIdlClass > xIdlTargetClass = TypeToIdlClass( aType );
Reference< XIdlArray > xIdlArray = xIdlTargetClass->getArray();
typelib_TypeDescription * pTD = 0;
aType.getDescription( &pTD );
Type aElementType( ((typelib_IndirectTypeDescription *)pTD)->pType );
::typelib_typedescription_release( pTD );
sal_Int32 nLen = xIdlArray->getLen( aValue );
for ( sal_Int32 index = 0; index < nLen; ++index )
{
Any aElementAny = xIdlArray->get( aValue, (sal_uInt32)index );
// This detects the dimension were currently processing
if ( dimCopy == dimension )
{
++dimCopy;
if ( sizes.getLength() < dimCopy )
{
sizes.realloc( sizes.getLength() + 1 );
sizes[ sizes.getLength() - 1 ] = nLen;
indices.realloc( indices.getLength() + 1 );
}
}
if ( bIsZeroIndex )
indices[ dimCopy - 1 ] = index;
else
indices[ dimCopy - 1] = index + 1;
implSequenceToMultiDimArray( pArray, indices, sizes, aElementAny, dimCopy, bIsZeroIndex, &aElementType );
}
}
else
{
if ( indices.getLength() < 1 )
{
// Should never ever get here ( indices.getLength()
// should equal number of dimensions in the array )
// And that should at least be 1 !
// #QUESTION is there a better error?
StarBASIC::Error( SbERR_INVALID_OBJECT );
return;
}
SbxDataType eSbxElementType = unoToSbxType( pType ? pType->getTypeClass() : aValue.getValueTypeClass() );
if ( !pArray )
{
pArray = new SbxDimArray( eSbxElementType );
sal_Int32 nIndexLen = indices.getLength();
// Dimension the array
for ( sal_Int32 index = 0; index < nIndexLen; ++index )
{
if ( bIsZeroIndex )
pArray->unoAddDim32( 0, sizes[ index ] - 1);
else
pArray->unoAddDim32( 1, sizes[ index ] );
}
}
if ( pArray )
{
SbxVariableRef xVar = new SbxVariable( eSbxElementType );
unoToSbxValue( (SbxVariable*)xVar, aValue );
sal_Int32* pIndices = indices.getArray();
pArray->Put32( (SbxVariable*)xVar, pIndices );
}
}
}
void unoToSbxValue( SbxVariable* pVar, const Any& aValue )
{
Type aType = aValue.getValueType();
TypeClass eTypeClass = aType.getTypeClass();
switch( eTypeClass )
{
case TypeClass_TYPE:
{
// Map Type to IdlClass
Type aType_;
aValue >>= aType_;
Reference<XIdlClass> xClass = TypeToIdlClass( aType_ );
Any aClassAny;
aClassAny <<= xClass;
// instantiate SbUnoObject
OUString aName;
SbUnoObject* pSbUnoObject = new SbUnoObject( aName, aClassAny );
SbxObjectRef xWrapper = (SbxObject*)pSbUnoObject;
// If the object is invalid deliver null
if( pSbUnoObject->getUnoAny().getValueType().getTypeClass() == TypeClass_VOID )
{
pVar->PutObject( NULL );
}
else
{
pVar->PutObject( xWrapper );
}
}
break;
// Interfaces and Structs must be wrapped in a SbUnoObject
case TypeClass_INTERFACE:
case TypeClass_STRUCT:
case TypeClass_EXCEPTION:
{
if( eTypeClass == TypeClass_STRUCT )
{
ArrayWrapper aWrap;
NativeObjectWrapper aNativeObjectWrapper;
if ( (aValue >>= aWrap) )
{
SbxDimArray* pArray = NULL;
Sequence< sal_Int32 > indices;
Sequence< sal_Int32 > sizes;
sal_Int32 dimension = 0;
implSequenceToMultiDimArray( pArray, indices, sizes, aWrap.Array, dimension, aWrap.IsZeroIndex );
if ( pArray )
{
SbxDimArrayRef xArray = pArray;
sal_uInt16 nFlags = pVar->GetFlags();
pVar->ResetFlag( SBX_FIXED );
pVar->PutObject( (SbxDimArray*)xArray );
pVar->SetFlags( nFlags );
}
else
pVar->PutEmpty();
break;
}
else if ( (aValue >>= aNativeObjectWrapper) )
{
sal_uInt32 nIndex = 0;
if( (aNativeObjectWrapper.ObjectId >>= nIndex) )
{
SbxObject* pObj = lcl_getNativeObject( nIndex );
pVar->PutObject( pObj );
}
else
pVar->PutEmpty();
break;
}
else
{
SbiInstance* pInst = GetSbData()->pInst;
if( pInst && pInst->IsCompatibility() )
{
oleautomation::Date aDate;
if( (aValue >>= aDate) )
{
pVar->PutDate( aDate.Value );
break;
}
else
{
oleautomation::Decimal aDecimal;
if( (aValue >>= aDecimal) )
{
pVar->PutDecimal( aDecimal );
break;
}
else
{
oleautomation::Currency aCurrency;
if( (aValue >>= aCurrency) )
{
pVar->PutCurrency( aCurrency.Value );
break;
}
}
}
}
}
}
// instantiate a SbUnoObject
OUString aName;
SbUnoObject* pSbUnoObject = new SbUnoObject( aName, aValue );
//If this is called externally e.g. from the scripting
//framework then there is no 'active' runtime the default property will not be set up
//only a vba object will have XDefaultProp set anyway so... this
//test seems a bit of overkill
//if ( SbiRuntime::isVBAEnabled() )
{
OUString sDfltPropName;
if ( SbUnoObject::getDefaultPropName( pSbUnoObject, sDfltPropName ) )
{
pSbUnoObject->SetDfltProperty( sDfltPropName );
}
}
SbxObjectRef xWrapper = (SbxObject*)pSbUnoObject;
// If the object is invalid deliver null
if( pSbUnoObject->getUnoAny().getValueType().getTypeClass() == TypeClass_VOID )
{
pVar->PutObject( NULL );
}
else
{
pVar->PutObject( xWrapper );
}
}
break;
case TypeClass_ENUM:
{
sal_Int32 nEnum = 0;
enum2int( nEnum, aValue );
pVar->PutLong( nEnum );
}
break;
case TypeClass_SEQUENCE:
{
Reference< XIdlClass > xIdlTargetClass = TypeToIdlClass( aType );
Reference< XIdlArray > xIdlArray = xIdlTargetClass->getArray();
sal_Int32 i, nLen = xIdlArray->getLen( aValue );
typelib_TypeDescription * pTD = 0;
aType.getDescription( &pTD );
OSL_ASSERT( pTD && pTD->eTypeClass == typelib_TypeClass_SEQUENCE );
Type aElementType( ((typelib_IndirectTypeDescription *)pTD)->pType );
::typelib_typedescription_release( pTD );
// build an Array in Basic
SbxDimArrayRef xArray;
SbxDataType eSbxElementType = unoToSbxType( aElementType.getTypeClass() );
xArray = new SbxDimArray( eSbxElementType );
if( nLen > 0 )
{
xArray->unoAddDim32( 0, nLen - 1 );
// register the elements as variables
for( i = 0 ; i < nLen ; i++ )
{
// convert elements
Any aElementAny = xIdlArray->get( aValue, (sal_uInt32)i );
SbxVariableRef xVar = new SbxVariable( eSbxElementType );
unoToSbxValue( (SbxVariable*)xVar, aElementAny );
// put into the Array
xArray->Put32( (SbxVariable*)xVar, &i );
}
}
else
{
xArray->unoAddDim( 0, -1 );
}
// return the Array
sal_uInt16 nFlags = pVar->GetFlags();
pVar->ResetFlag( SBX_FIXED );
pVar->PutObject( (SbxDimArray*)xArray );
pVar->SetFlags( nFlags );
}
break;
case TypeClass_BOOLEAN: pVar->PutBool( *(sal_Bool*)aValue.getValue() ); break;
case TypeClass_CHAR:
{
pVar->PutChar( *(sal_Unicode*)aValue.getValue() );
break;
}
case TypeClass_STRING: { OUString val; aValue >>= val; pVar->PutString( val ); } break;
case TypeClass_FLOAT: { float val = 0; aValue >>= val; pVar->PutSingle( val ); } break;
case TypeClass_DOUBLE: { double val = 0; aValue >>= val; pVar->PutDouble( val ); } break;
case TypeClass_BYTE: { sal_Int8 val = 0; aValue >>= val; pVar->PutInteger( val ); } break;
case TypeClass_SHORT: { sal_Int16 val = 0; aValue >>= val; pVar->PutInteger( val ); } break;
case TypeClass_LONG: { sal_Int32 val = 0; aValue >>= val; pVar->PutLong( val ); } break;
case TypeClass_HYPER: { sal_Int64 val = 0; aValue >>= val; pVar->PutInt64( val ); } break;
case TypeClass_UNSIGNED_SHORT: { sal_uInt16 val = 0; aValue >>= val; pVar->PutUShort( val ); } break;
case TypeClass_UNSIGNED_LONG: { sal_uInt32 val = 0; aValue >>= val; pVar->PutULong( val ); } break;
case TypeClass_UNSIGNED_HYPER: { sal_uInt64 val = 0; aValue >>= val; pVar->PutUInt64( val ); } break;
default: pVar->PutEmpty(); break;
}
}
// Deliver the reflection for Sbx types
Type getUnoTypeForSbxBaseType( SbxDataType eType )
{
Type aRetType = getCppuVoidType();
switch( eType )
{
case SbxNULL: aRetType = cppu::UnoType<XInterface>::get(); break;
case SbxINTEGER: aRetType = cppu::UnoType<sal_Int16>::get(); break;
case SbxLONG: aRetType = cppu::UnoType<sal_Int32>::get(); break;
case SbxSINGLE: aRetType = cppu::UnoType<float>::get(); break;
case SbxDOUBLE: aRetType = cppu::UnoType<double>::get(); break;
case SbxCURRENCY: aRetType = cppu::UnoType<oleautomation::Currency>::get(); break;
case SbxDECIMAL: aRetType = cppu::UnoType<oleautomation::Decimal>::get(); break;
case SbxDATE: {
SbiInstance* pInst = GetSbData()->pInst;
if( pInst && pInst->IsCompatibility() )
aRetType = cppu::UnoType<double>::get();
else
aRetType = cppu::UnoType<oleautomation::Date>::get();
}
break;
case SbxSTRING: aRetType = cppu::UnoType<OUString>::get(); break;
case SbxBOOL: aRetType = cppu::UnoType<sal_Bool>::get(); break;
case SbxVARIANT: aRetType = cppu::UnoType<Any>::get(); break;
case SbxCHAR: aRetType = cppu::UnoType<cppu::UnoCharType>::get(); break;
case SbxBYTE: aRetType = cppu::UnoType<sal_Int8>::get(); break;
case SbxUSHORT: aRetType = cppu::UnoType<cppu::UnoUnsignedShortType>::get(); break;
case SbxULONG: aRetType = ::cppu::UnoType<sal_uInt32>::get(); break;
// map machine-dependent ones to long for consistency
case SbxINT: aRetType = ::cppu::UnoType<sal_Int32>::get(); break;
case SbxUINT: aRetType = ::cppu::UnoType<sal_uInt32>::get(); break;
default: break;
}
return aRetType;
}
// Converting of Sbx to Uno without a know target class for TypeClass_ANY
Type getUnoTypeForSbxValue( const SbxValue* pVal )
{
Type aRetType = getCppuVoidType();
if( !pVal )
return aRetType;
// convert SbxType to Uno
SbxDataType eBaseType = pVal->SbxValue::GetType();
if( eBaseType == SbxOBJECT )
{
SbxBaseRef xObj = (SbxBase*)pVal->GetObject();
if( !xObj )
{
aRetType = cppu::UnoType<XInterface>::get();
return aRetType;
}
if( xObj->ISA(SbxDimArray) )
{
SbxBase* pObj = (SbxBase*)xObj;
SbxDimArray* pArray = (SbxDimArray*)pObj;
short nDims = pArray->GetDims();
Type aElementType = getUnoTypeForSbxBaseType( (SbxDataType)(pArray->GetType() & 0xfff) );
TypeClass eElementTypeClass = aElementType.getTypeClass();
// Normal case: One dimensional array
sal_Int32 nLower, nUpper;
if( nDims == 1 && pArray->GetDim32( 1, nLower, nUpper ) )
{
if( eElementTypeClass == TypeClass_VOID || eElementTypeClass == TypeClass_ANY )
{
// If all elements of the arrays are from the same type, take
// this one - otherwise the whole will be considered as Any-Sequence
bool bNeedsInit = true;
sal_Int32 nSize = nUpper - nLower + 1;
sal_Int32 nIdx = nLower;
for( sal_Int32 i = 0 ; i < nSize ; i++,nIdx++ )
{
SbxVariableRef xVar = pArray->Get32( &nIdx );
Type aType = getUnoTypeForSbxValue( (SbxVariable*)xVar );
if( bNeedsInit )
{
if( aType.getTypeClass() == TypeClass_VOID )
{
// if only first element is void: different types -> []any
// if all elements are void: []void is not allowed -> []any
aElementType = cppu::UnoType<Any>::get();
break;
}
aElementType = aType;
bNeedsInit = false;
}
else if( aElementType != aType )
{
// different types -> AnySequence
aElementType = cppu::UnoType<Any>::get();
break;
}
}
}
OUString aSeqTypeName = aSeqLevelStr + aElementType.getTypeName();
aRetType = Type( TypeClass_SEQUENCE, aSeqTypeName );
}
// #i33795 Map also multi dimensional arrays to corresponding sequences
else if( nDims > 1 )
{
if( eElementTypeClass == TypeClass_VOID || eElementTypeClass == TypeClass_ANY )
{
// For this check the array's dim structure does not matter
sal_uInt32 nFlatArraySize = pArray->Count32();
bool bNeedsInit = true;
for( sal_uInt32 i = 0 ; i < nFlatArraySize ; i++ )
{
SbxVariableRef xVar = pArray->SbxArray::Get32( i );
Type aType = getUnoTypeForSbxValue( (SbxVariable*)xVar );
if( bNeedsInit )
{
if( aType.getTypeClass() == TypeClass_VOID )
{
// if only first element is void: different types -> []any
// if all elements are void: []void is not allowed -> []any
aElementType = cppu::UnoType<Any>::get();
break;
}
aElementType = aType;
bNeedsInit = false;
}
else if( aElementType != aType )
{
// different types -> AnySequence
aElementType = cppu::UnoType<Any>::get();
break;
}
}
}
OUStringBuffer aSeqTypeName;
for( short iDim = 0 ; iDim < nDims ; iDim++ )
{
aSeqTypeName.appendAscii(aSeqLevelStr);
}
aSeqTypeName.append(aElementType.getTypeName());
aRetType = Type( TypeClass_SEQUENCE, aSeqTypeName.makeStringAndClear() );
}
}
// No array, but ...
else if( xObj->ISA(SbUnoObject) )
{
aRetType = ((SbUnoObject*)(SbxBase*)xObj)->getUnoAny().getValueType();
}
// SbUnoAnyObject?
else if( xObj->ISA(SbUnoAnyObject) )
{
aRetType = ((SbUnoAnyObject*)(SbxBase*)xObj)->getValue().getValueType();
}
// Otherwise it is a No-Uno-Basic-Object -> default==deliver void
}
// No object, convert basic type
else
{
aRetType = getUnoTypeForSbxBaseType( eBaseType );
}
return aRetType;
}
// converting of Sbx to Uno without known target class for TypeClass_ANY
Any sbxToUnoValueImpl( const SbxValue* pVar, bool bBlockConversionToSmallestType = false )
{
SbxDataType eBaseType = pVar->SbxValue::GetType();
if( eBaseType == SbxOBJECT )
{
SbxBaseRef xObj = (SbxBase*)pVar->GetObject();
if( xObj.Is() )
{
if( xObj->ISA(SbUnoAnyObject) )
return ((SbUnoAnyObject*)(SbxBase*)xObj)->getValue();
if( xObj->ISA(SbClassModuleObject) )
{
Any aRetAny;
SbClassModuleObject* pClassModuleObj = (SbClassModuleObject*)(SbxBase*)xObj;
SbModule* pClassModule = pClassModuleObj->getClassModule();
if( pClassModule->createCOMWrapperForIface( aRetAny, pClassModuleObj ) )
return aRetAny;
}
if( !xObj->ISA(SbUnoObject) )
{
// Create NativeObjectWrapper to identify object in case of callbacks
SbxObject* pObj = PTR_CAST(SbxObject,pVar->GetObject());
if( pObj != NULL )
{
NativeObjectWrapper aNativeObjectWrapper;
sal_uInt32 nIndex = lcl_registerNativeObjectWrapper( pObj );
aNativeObjectWrapper.ObjectId <<= nIndex;
Any aRetAny;
aRetAny <<= aNativeObjectWrapper;
return aRetAny;
}
}
}
}
Type aType = getUnoTypeForSbxValue( pVar );
TypeClass eType = aType.getTypeClass();
if( !bBlockConversionToSmallestType )
{
// #79615 Choose "smallest" represention for int values
// because up cast is allowed, downcast not
switch( eType )
{
case TypeClass_FLOAT:
case TypeClass_DOUBLE:
{
double d = pVar->GetDouble();
if( d == floor( d ) )
{
if( d >= -128 && d <= 127 )
aType = ::cppu::UnoType<sal_Int8>::get();
else if( d >= SbxMININT && d <= SbxMAXINT )
aType = ::cppu::UnoType<sal_Int16>::get();
else if( d >= -SbxMAXLNG && d <= SbxMAXLNG )
aType = ::cppu::UnoType<sal_Int32>::get();
}
break;
}
case TypeClass_SHORT:
{
sal_Int16 n = pVar->GetInteger();
if( n >= -128 && n <= 127 )
aType = ::cppu::UnoType<sal_Int8>::get();
break;
}
case TypeClass_LONG:
{
sal_Int32 n = pVar->GetLong();
if( n >= -128 && n <= 127 )
aType = ::cppu::UnoType<sal_Int8>::get();
else if( n >= SbxMININT && n <= SbxMAXINT )
aType = ::cppu::UnoType<sal_Int16>::get();
break;
}
case TypeClass_UNSIGNED_SHORT:
{
sal_uInt16 n = pVar->GetUShort();
if( n <= 255 )
aType = cppu::UnoType<sal_uInt8>::get();
break;
}
case TypeClass_UNSIGNED_LONG:
{
sal_uInt32 n = pVar->GetLong();
if( n <= 255 )
aType = cppu::UnoType<sal_uInt8>::get();
else if( n <= SbxMAXUINT )
aType = cppu::UnoType<cppu::UnoUnsignedShortType>::get();
break;
}
// TODO: need to add hyper types ?
default: break;
}
}
return sbxToUnoValue( pVar, aType );
}
// Helper function for StepREDIMP
static Any implRekMultiDimArrayToSequence( SbxDimArray* pArray,
const Type& aElemType, short nMaxDimIndex, short nActualDim,
sal_Int32* pActualIndices, sal_Int32* pLowerBounds, sal_Int32* pUpperBounds )
{
sal_Int32 nSeqLevel = nMaxDimIndex - nActualDim + 1;
OUStringBuffer aSeqTypeName;
sal_Int32 i;
for( i = 0 ; i < nSeqLevel ; i++ )
{
aSeqTypeName.appendAscii(aSeqLevelStr);
}
aSeqTypeName.append(aElemType.getTypeName());
Type aSeqType( TypeClass_SEQUENCE, aSeqTypeName.makeStringAndClear() );
// Create Sequence instance
Any aRetVal;
Reference< XIdlClass > xIdlTargetClass = TypeToIdlClass( aSeqType );
xIdlTargetClass->createObject( aRetVal );
// Alloc sequence according to array bounds
sal_Int32 nUpper = pUpperBounds[nActualDim];
sal_Int32 nLower = pLowerBounds[nActualDim];
sal_Int32 nSeqSize = nUpper - nLower + 1;
Reference< XIdlArray > xArray = xIdlTargetClass->getArray();
xArray->realloc( aRetVal, nSeqSize );
sal_Int32& ri = pActualIndices[nActualDim];
for( ri = nLower,i = 0 ; ri <= nUpper ; ri++,i++ )
{
Any aElementVal;
if( nActualDim < nMaxDimIndex )
{
aElementVal = implRekMultiDimArrayToSequence( pArray, aElemType,
nMaxDimIndex, nActualDim + 1, pActualIndices, pLowerBounds, pUpperBounds );
}
else
{
SbxVariable* pSource = pArray->Get32( pActualIndices );
aElementVal = sbxToUnoValue( pSource, aElemType );
}
try
{
// transfer to the sequence
xArray->set( aRetVal, i, aElementVal );
}
catch( const IllegalArgumentException& )
{
StarBASIC::Error( ERRCODE_BASIC_EXCEPTION,
implGetExceptionMsg( ::cppu::getCaughtException() ) );
}
catch (const IndexOutOfBoundsException&)
{
StarBASIC::Error( SbERR_OUT_OF_RANGE );
}
}
return aRetVal;
}
// Map old interface
Any sbxToUnoValue( const SbxValue* pVar )
{
return sbxToUnoValueImpl( pVar );
}
// function to find a global identifier in
// the UnoScope and to wrap it for Sbx
static bool implGetTypeByName( const OUString& rName, Type& rRetType )
{
bool bSuccess = false;
Reference< XHierarchicalNameAccess > xTypeAccess = getTypeProvider_Impl();
if( xTypeAccess->hasByHierarchicalName( rName ) )
{
Any aRet = xTypeAccess->getByHierarchicalName( rName );
Reference< XTypeDescription > xTypeDesc;
aRet >>= xTypeDesc;
if( xTypeDesc.is() )
{
rRetType = Type( xTypeDesc->getTypeClass(), xTypeDesc->getName() );
bSuccess = true;
}
}
return bSuccess;
}
// converting of Sbx to Uno with known target class
Any sbxToUnoValue( const SbxValue* pVar, const Type& rType, Property* pUnoProperty )
{
Any aRetVal;
// #94560 No conversion of empty/void for MAYBE_VOID properties
if( pUnoProperty && pUnoProperty->Attributes & PropertyAttribute::MAYBEVOID )
{
if( pVar->IsEmpty() )
return aRetVal;
}
SbxDataType eBaseType = pVar->SbxValue::GetType();
if( eBaseType == SbxOBJECT )
{
SbxBaseRef xObj = (SbxBase*)pVar->GetObject();
if( xObj.Is() && xObj->ISA(SbUnoAnyObject) )
{
return ((SbUnoAnyObject*)(SbxBase*)xObj)->getValue();
}
}
TypeClass eType = rType.getTypeClass();
switch( eType )
{
case TypeClass_INTERFACE:
case TypeClass_STRUCT:
case TypeClass_EXCEPTION:
{
Reference< XIdlClass > xIdlTargetClass = TypeToIdlClass( rType );
// null reference?
if( pVar->IsNull() && eType == TypeClass_INTERFACE )
{
Reference< XInterface > xRef;
OUString aClassName = xIdlTargetClass->getName();
Type aClassType( xIdlTargetClass->getTypeClass(), aClassName.getStr() );
aRetVal.setValue( &xRef, aClassType );
}
else
{
// #112368 Special conversion for Decimal, Currency and Date
if( eType == TypeClass_STRUCT )
{
SbiInstance* pInst = GetSbData()->pInst;
if( pInst && pInst->IsCompatibility() )
{
if( rType == cppu::UnoType<oleautomation::Decimal>::get())
{
oleautomation::Decimal aDecimal;
pVar->fillAutomationDecimal( aDecimal );
aRetVal <<= aDecimal;
break;
}
else if( rType == cppu::UnoType<oleautomation::Currency>::get())
{
// assumes per previous code that ole Currency is Int64
aRetVal <<= (sal_Int64)( pVar->GetInt64() );
break;
}
else if( rType == cppu::UnoType<oleautomation::Date>::get())
{
oleautomation::Date aDate;
aDate.Value = pVar->GetDate();
aRetVal <<= aDate;
break;
}
}
}
SbxBaseRef pObj = (SbxBase*)pVar->GetObject();
if( pObj && pObj->ISA(SbUnoObject) )
{
aRetVal = ((SbUnoObject*)(SbxBase*)pObj)->getUnoAny();
}
else if( pObj && pObj->ISA(SbUnoStructRefObject) )
{
aRetVal = ((SbUnoStructRefObject*)(SbxBase*)pObj)->getUnoAny();
}
else
{
// null object -> null XInterface
Reference<XInterface> xInt;
aRetVal <<= xInt;
}
}
}
break;
case TypeClass_TYPE:
{
if( eBaseType == SbxOBJECT )
{
// XIdlClass?
Reference< XIdlClass > xIdlClass;
SbxBaseRef pObj = (SbxBase*)pVar->GetObject();
if( pObj && pObj->ISA(SbUnoObject) )
{
Any aUnoAny = ((SbUnoObject*)(SbxBase*)pObj)->getUnoAny();
aUnoAny >>= xIdlClass;
}
if( xIdlClass.is() )
{
OUString aClassName = xIdlClass->getName();
Type aType( xIdlClass->getTypeClass(), aClassName.getStr() );
aRetVal <<= aType;
}
}
else if( eBaseType == SbxSTRING )
{
OUString aTypeName = pVar->GetOUString();
Type aType;
bool bSuccess = implGetTypeByName( aTypeName, aType );
if( bSuccess )
{
aRetVal <<= aType;
}
}
}
break;
case TypeClass_ENUM:
{
aRetVal = int2enum( pVar->GetLong(), rType );
}
break;
case TypeClass_SEQUENCE:
{
SbxBaseRef xObj = (SbxBase*)pVar->GetObject();
if( xObj && xObj->ISA(SbxDimArray) )
{
SbxBase* pObj = (SbxBase*)xObj;
SbxDimArray* pArray = (SbxDimArray*)pObj;
short nDims = pArray->GetDims();
// Normal case: One dimensional array
sal_Int32 nLower, nUpper;
if( nDims == 1 && pArray->GetDim32( 1, nLower, nUpper ) )
{
sal_Int32 nSeqSize = nUpper - nLower + 1;
// create the instance of the required sequence
Reference< XIdlClass > xIdlTargetClass = TypeToIdlClass( rType );
xIdlTargetClass->createObject( aRetVal );
Reference< XIdlArray > xArray = xIdlTargetClass->getArray();
xArray->realloc( aRetVal, nSeqSize );
// Element-Type
OUString aClassName = xIdlTargetClass->getName();
typelib_TypeDescription * pSeqTD = 0;
typelib_typedescription_getByName( &pSeqTD, aClassName.pData );
OSL_ASSERT( pSeqTD );
Type aElemType( ((typelib_IndirectTypeDescription *)pSeqTD)->pType );
// convert all array member and register them
sal_Int32 nIdx = nLower;
for( sal_Int32 i = 0 ; i < nSeqSize ; i++,nIdx++ )
{
SbxVariableRef xVar = pArray->Get32( &nIdx );
// Convert the value of Sbx to Uno
Any aAnyValue = sbxToUnoValue( (SbxVariable*)xVar, aElemType );
try
{
// insert in the sequence
xArray->set( aRetVal, i, aAnyValue );
}
catch( const IllegalArgumentException& )
{
StarBASIC::Error( ERRCODE_BASIC_EXCEPTION,
implGetExceptionMsg( ::cppu::getCaughtException() ) );
}
catch (const IndexOutOfBoundsException&)
{
StarBASIC::Error( SbERR_OUT_OF_RANGE );
}
}
}
// #i33795 Map also multi dimensional arrays to corresponding sequences
else if( nDims > 1 )
{
// Element-Type
typelib_TypeDescription * pSeqTD = 0;
Type aCurType( rType );
sal_Int32 nSeqLevel = 0;
Type aElemType;
do
{
OUString aTypeName = aCurType.getTypeName();
typelib_typedescription_getByName( &pSeqTD, aTypeName.pData );
OSL_ASSERT( pSeqTD );
if( pSeqTD->eTypeClass == typelib_TypeClass_SEQUENCE )
{
aCurType = Type( ((typelib_IndirectTypeDescription *)pSeqTD)->pType );
nSeqLevel++;
}
else
{
aElemType = aCurType;
break;
}
}
while( true );
if( nSeqLevel == nDims )
{
sal_Int32* pLowerBounds = new sal_Int32[nDims];
sal_Int32* pUpperBounds = new sal_Int32[nDims];
sal_Int32* pActualIndices = new sal_Int32[nDims];
for( short i = 1 ; i <= nDims ; i++ )
{
sal_Int32 lBound, uBound;
pArray->GetDim32( i, lBound, uBound );
short j = i - 1;
pActualIndices[j] = pLowerBounds[j] = lBound;
pUpperBounds[j] = uBound;
}
aRetVal = implRekMultiDimArrayToSequence( pArray, aElemType,
nDims - 1, 0, pActualIndices, pLowerBounds, pUpperBounds );
delete[] pUpperBounds;
delete[] pLowerBounds;
delete[] pActualIndices;
}
}
}
}
break;
// for Any use the class independent converting routine
case TypeClass_ANY:
{
aRetVal = sbxToUnoValueImpl( pVar );
}
break;
case TypeClass_BOOLEAN:
{
sal_Bool b = pVar->GetBool();
aRetVal.setValue( &b, getBooleanCppuType() );
break;
}
case TypeClass_CHAR:
{
sal_Unicode c = pVar->GetChar();
aRetVal.setValue( &c , getCharCppuType() );
break;
}
case TypeClass_STRING: aRetVal <<= pVar->GetOUString(); break;
case TypeClass_FLOAT: aRetVal <<= pVar->GetSingle(); break;
case TypeClass_DOUBLE: aRetVal <<= pVar->GetDouble(); break;
case TypeClass_BYTE:
{
sal_Int16 nVal = pVar->GetInteger();
bool bOverflow = false;
if( nVal < -128 )
{
bOverflow = true;
nVal = -128;
}
else if( nVal > 127 )
{
bOverflow = true;
nVal = 127;
}
if( bOverflow )
StarBASIC::Error( ERRCODE_BASIC_MATH_OVERFLOW );
sal_Int8 nByteVal = (sal_Int8)nVal;
aRetVal <<= nByteVal;
break;
}
case TypeClass_SHORT: aRetVal <<= (sal_Int16)( pVar->GetInteger() ); break;
case TypeClass_LONG: aRetVal <<= (sal_Int32)( pVar->GetLong() ); break;
case TypeClass_HYPER: aRetVal <<= (sal_Int64)( pVar->GetInt64() ); break;
case TypeClass_UNSIGNED_SHORT: aRetVal <<= (sal_uInt16)( pVar->GetUShort() ); break;
case TypeClass_UNSIGNED_LONG: aRetVal <<= (sal_uInt32)( pVar->GetULong() ); break;
case TypeClass_UNSIGNED_HYPER: aRetVal <<= (sal_uInt64)( pVar->GetUInt64() ); break;
default: break;
}
return aRetVal;
}
void processAutomationParams( SbxArray* pParams, Sequence< Any >& args, bool bOLEAutomation, sal_uInt32 nParamCount )
{
AutomationNamedArgsSbxArray* pArgNamesArray = NULL;
if( bOLEAutomation )
pArgNamesArray = PTR_CAST(AutomationNamedArgsSbxArray,pParams);
args.realloc( nParamCount );
Any* pAnyArgs = args.getArray();
bool bBlockConversionToSmallestType = GetSbData()->pInst->IsCompatibility();
sal_uInt32 i = 0;
if( pArgNamesArray )
{
Sequence< OUString >& rNameSeq = pArgNamesArray->getNames();
OUString* pNames = rNameSeq.getArray();
Any aValAny;
for( i = 0 ; i < nParamCount ; i++ )
{
sal_uInt16 iSbx = (sal_uInt16)(i+1);
aValAny = sbxToUnoValueImpl( pParams->Get( iSbx ),
bBlockConversionToSmallestType );
OUString aParamName = pNames[iSbx];
if( !aParamName.isEmpty() )
{
oleautomation::NamedArgument aNamedArgument;
aNamedArgument.Name = aParamName;
aNamedArgument.Value = aValAny;
pAnyArgs[i] <<= aNamedArgument;
}
else
{
pAnyArgs[i] = aValAny;
}
}
}
else
{
for( i = 0 ; i < nParamCount ; i++ )
{
pAnyArgs[i] = sbxToUnoValueImpl( pParams->Get( (sal_uInt16)(i+1) ),
bBlockConversionToSmallestType );
}
}
}
enum INVOKETYPE
{
GetProp = 0,
SetProp,
Func
};
Any invokeAutomationMethod( const OUString& Name, Sequence< Any >& args, SbxArray* pParams, sal_uInt32 nParamCount, Reference< XInvocation >& rxInvocation, INVOKETYPE invokeType = Func )
{
Sequence< sal_Int16 > OutParamIndex;
Sequence< Any > OutParam;
Any aRetAny;
switch( invokeType )
{
case Func:
aRetAny = rxInvocation->invoke( Name, args, OutParamIndex, OutParam );
break;
case GetProp:
{
Reference< XAutomationInvocation > xAutoInv( rxInvocation, UNO_QUERY );
aRetAny = xAutoInv->invokeGetProperty( Name, args, OutParamIndex, OutParam );
break;
}
case SetProp:
{
Reference< XAutomationInvocation > xAutoInv( rxInvocation, UNO_QUERY_THROW );
aRetAny = xAutoInv->invokePutProperty( Name, args, OutParamIndex, OutParam );
break;
}
default:
break; // should introduce an error here
}
const sal_Int16* pIndices = OutParamIndex.getConstArray();
sal_uInt32 nLen = OutParamIndex.getLength();
if( nLen )
{
const Any* pNewValues = OutParam.getConstArray();
for( sal_uInt32 j = 0 ; j < nLen ; j++ )
{
sal_Int16 iTarget = pIndices[ j ];
if( iTarget >= (sal_Int16)nParamCount )
break;
unoToSbxValue( (SbxVariable*)pParams->Get( (sal_uInt16)(j+1) ), pNewValues[ j ] );
}
}
return aRetAny;
}
// Debugging help method to readout the imlemented interfaces of an object
OUString Impl_GetInterfaceInfo( const Reference< XInterface >& x, const Reference< XIdlClass >& xClass, sal_uInt16 nRekLevel )
{
Type aIfaceType = cppu::UnoType<XInterface>::get();
static Reference< XIdlClass > xIfaceClass = TypeToIdlClass( aIfaceType );
OUStringBuffer aRetStr;
for( sal_uInt16 i = 0 ; i < nRekLevel ; i++ )
aRetStr.appendAscii( " " );
aRetStr.append( xClass->getName() );
OUString aClassName = xClass->getName();
Type aClassType( xClass->getTypeClass(), aClassName.getStr() );
// checking if the interface is really supported
if( !x->queryInterface( aClassType ).hasValue() )
{
aRetStr.appendAscii( " (ERROR: Not really supported!)\n" );
}
// Are there super interfaces?
else
{
aRetStr.appendAscii( "\n" );
// get the super interfaces
Sequence< Reference< XIdlClass > > aSuperClassSeq = xClass->getSuperclasses();
const Reference< XIdlClass >* pClasses = aSuperClassSeq.getConstArray();
sal_uInt32 nSuperIfaceCount = aSuperClassSeq.getLength();
for( sal_uInt32 j = 0 ; j < nSuperIfaceCount ; j++ )
{
const Reference< XIdlClass >& rxIfaceClass = pClasses[j];
if( !rxIfaceClass->equals( xIfaceClass ) )
aRetStr.append( Impl_GetInterfaceInfo( x, rxIfaceClass, nRekLevel + 1 ) );
}
}
return aRetStr.makeStringAndClear();
}
OUString getDbgObjectNameImpl( SbUnoObject* pUnoObj )
{
OUString aName;
if( pUnoObj )
{
aName = pUnoObj->GetClassName();
if( aName.isEmpty() )
{
Any aToInspectObj = pUnoObj->getUnoAny();
TypeClass eType = aToInspectObj.getValueType().getTypeClass();
Reference< XInterface > xObj;
if( eType == TypeClass_INTERFACE )
xObj = *(Reference< XInterface >*)aToInspectObj.getValue();
if( xObj.is() )
{
Reference< XServiceInfo > xServiceInfo( xObj, UNO_QUERY );
if( xServiceInfo.is() )
aName = xServiceInfo->getImplementationName();
}
}
}
return aName;
}
OUString getDbgObjectName( SbUnoObject* pUnoObj )
{
OUString aName = getDbgObjectNameImpl( pUnoObj );
if( aName.isEmpty() )
aName += "Unknown";
OUStringBuffer aRet;
if( aName.getLength() > 20 )
{
aRet.appendAscii( "\n" );
}
aRet.appendAscii( "\"" );
aRet.append( aName );
aRet.appendAscii( "\":" );
return aRet.makeStringAndClear();
}
OUString getBasicObjectTypeName( SbxObject* pObj )
{
OUString aName;
if( pObj )
{
SbUnoObject* pUnoObj = PTR_CAST(SbUnoObject,pObj);
SbUnoStructRefObject* pUnoStructObj = PTR_CAST(SbUnoStructRefObject,pObj);
if( pUnoObj )
aName = getDbgObjectNameImpl( pUnoObj );
else if ( pUnoStructObj )
aName = pUnoStructObj->GetClassName();
}
return aName;
}
bool checkUnoObjectType( SbUnoObject* pUnoObj, const OUString& rClass )
{
Any aToInspectObj = pUnoObj->getUnoAny();
TypeClass eType = aToInspectObj.getValueType().getTypeClass();
if( eType != TypeClass_INTERFACE )
{
return false;
}
const Reference< XInterface > x = *(Reference< XInterface >*)aToInspectObj.getValue();
// Return true for XInvocation based objects as interface type names don't count then
Reference< XInvocation > xInvocation( x, UNO_QUERY );
if( xInvocation.is() )
{
return true;
}
bool result = false;
Reference< XTypeProvider > xTypeProvider( x, UNO_QUERY );
if( xTypeProvider.is() )
{
/* Although interfaces in the ooo.vba namespace obey the IDL rules and
have a leading 'X', in Basic we want to be able to do something
like 'Dim wb As Workbooks' or 'Dim lb As MSForms.Label'. Here we
add a leading 'X' to the class name and a leading dot to the entire
type name. This results e.g. in '.XWorkbooks' or '.MSForms.XLabel'
which matches the interface names 'ooo.vba.excel.XWorkbooks' or
'ooo.vba.msforms.XLabel'.
*/
OUString aClassName;
if ( SbiRuntime::isVBAEnabled() )
{
aClassName = ".";
sal_Int32 nClassNameDot = rClass.lastIndexOf( '.' );
if( nClassNameDot >= 0 )
{
aClassName += rClass.copy( 0, nClassNameDot + 1 ) + OUString( 'X' ) + rClass.copy( nClassNameDot + 1 );
}
else
{
aClassName += OUString( 'X' ) + rClass;
}
}
else // assume extended type declaration support for basic ( can't get here
// otherwise.
aClassName = rClass;
Sequence< Type > aTypeSeq = xTypeProvider->getTypes();
const Type* pTypeArray = aTypeSeq.getConstArray();
sal_uInt32 nIfaceCount = aTypeSeq.getLength();
for( sal_uInt32 j = 0 ; j < nIfaceCount ; j++ )
{
const Type& rType = pTypeArray[j];
Reference<XIdlClass> xClass = TypeToIdlClass( rType );
if( !xClass.is() )
{
OSL_FAIL("failed to get XIdlClass for type");
break;
}
OUString aInterfaceName = xClass->getName();
if ( aInterfaceName == "com.sun.star.bridge.oleautomation.XAutomationObject" )
{
// there is a hack in the extensions/source/ole/oleobj.cxx to return the typename of the automation object, lets check if it
// matches
Reference< XInvocation > xInv( aToInspectObj, UNO_QUERY );
if ( xInv.is() )
{
OUString sTypeName;
xInv->getValue( OUString( "$GetTypeName" ) ) >>= sTypeName;
if ( sTypeName.isEmpty() || sTypeName == "IDispatch" )
{
// can't check type, leave it pass
result = true;
}
else
{
result = sTypeName.equals( rClass );
}
}
break; // finished checking automation object
}
// match interface name with passed class name
OSL_TRACE("Checking if object implements %s", OUStringToOString( aClassName, RTL_TEXTENCODING_UTF8 ).getStr() );
if ( (aClassName.getLength() <= aInterfaceName.getLength()) &&
aInterfaceName.endsWithIgnoreAsciiCase( aClassName ) )
{
result = true;
break;
}
}
}
return result;
}
// Debugging help method to readout the imlemented interfaces of an object
OUString Impl_GetSupportedInterfaces( SbUnoObject* pUnoObj )
{
Any aToInspectObj = pUnoObj->getUnoAny();
// allow only TypeClass interface
TypeClass eType = aToInspectObj.getValueType().getTypeClass();
OUStringBuffer aRet;
if( eType != TypeClass_INTERFACE )
{
aRet.appendAscii( ID_DBG_SUPPORTEDINTERFACES );
aRet.appendAscii( " not available.\n(TypeClass is not TypeClass_INTERFACE)\n" );
}
else
{
// get the interface from the Any
const Reference< XInterface > x = *(Reference< XInterface >*)aToInspectObj.getValue();
Reference< XTypeProvider > xTypeProvider( x, UNO_QUERY );
aRet.appendAscii( "Supported interfaces by object " );
aRet.append( getDbgObjectName( pUnoObj ) );
aRet.appendAscii( "\n" );
if( xTypeProvider.is() )
{
// get the interfaces of the implementation
Sequence< Type > aTypeSeq = xTypeProvider->getTypes();
const Type* pTypeArray = aTypeSeq.getConstArray();
sal_uInt32 nIfaceCount = aTypeSeq.getLength();
for( sal_uInt32 j = 0 ; j < nIfaceCount ; j++ )
{
const Type& rType = pTypeArray[j];
Reference<XIdlClass> xClass = TypeToIdlClass( rType );
if( xClass.is() )
{
aRet.append( Impl_GetInterfaceInfo( x, xClass, 1 ) );
}
else
{
typelib_TypeDescription * pTD = 0;
rType.getDescription( &pTD );
aRet.appendAscii( "*** ERROR: No IdlClass for type \"" );
aRet.append( pTD->pTypeName );
aRet.appendAscii( "\"\n*** Please check type library\n" );
}
}
}
}
return aRet.makeStringAndClear();
}
// Debugging help method SbxDataType -> String
OUString Dbg_SbxDataType2String( SbxDataType eType )
{
OUStringBuffer aRet;
switch( +eType )
{
case SbxEMPTY: aRet.appendAscii("SbxEMPTY"); break;
case SbxNULL: aRet.appendAscii("SbxNULL"); break;
case SbxINTEGER: aRet.appendAscii("SbxINTEGER"); break;
case SbxLONG: aRet.appendAscii("SbxLONG"); break;
case SbxSINGLE: aRet.appendAscii("SbxSINGLE"); break;
case SbxDOUBLE: aRet.appendAscii("SbxDOUBLE"); break;
case SbxCURRENCY: aRet.appendAscii("SbxCURRENCY"); break;
case SbxDECIMAL: aRet.appendAscii("SbxDECIMAL"); break;
case SbxDATE: aRet.appendAscii("SbxDATE"); break;
case SbxSTRING: aRet.appendAscii("SbxSTRING"); break;
case SbxOBJECT: aRet.appendAscii("SbxOBJECT"); break;
case SbxERROR: aRet.appendAscii("SbxERROR"); break;
case SbxBOOL: aRet.appendAscii("SbxBOOL"); break;
case SbxVARIANT: aRet.appendAscii("SbxVARIANT"); break;
case SbxDATAOBJECT: aRet.appendAscii("SbxDATAOBJECT"); break;
case SbxCHAR: aRet.appendAscii("SbxCHAR"); break;
case SbxBYTE: aRet.appendAscii("SbxBYTE"); break;
case SbxUSHORT: aRet.appendAscii("SbxUSHORT"); break;
case SbxULONG: aRet.appendAscii("SbxULONG"); break;
case SbxSALINT64: aRet.appendAscii("SbxINT64"); break;
case SbxSALUINT64: aRet.appendAscii("SbxUINT64"); break;
case SbxINT: aRet.appendAscii("SbxINT"); break;
case SbxUINT: aRet.appendAscii("SbxUINT"); break;
case SbxVOID: aRet.appendAscii("SbxVOID"); break;
case SbxHRESULT: aRet.appendAscii("SbxHRESULT"); break;
case SbxPOINTER: aRet.appendAscii("SbxPOINTER"); break;
case SbxDIMARRAY: aRet.appendAscii("SbxDIMARRAY"); break;
case SbxCARRAY: aRet.appendAscii("SbxCARRAY"); break;
case SbxUSERDEF: aRet.appendAscii("SbxUSERDEF"); break;
case SbxLPSTR: aRet.appendAscii("SbxLPSTR"); break;
case SbxLPWSTR: aRet.appendAscii("SbxLPWSTR"); break;
case SbxCoreSTRING: aRet.appendAscii("SbxCoreSTRING"); break;
case SbxOBJECT | SbxARRAY: aRet.appendAscii("SbxARRAY"); break;
default: aRet.appendAscii("Unknown Sbx-Type!");break;
}
return aRet.makeStringAndClear();
}
// Debugging help method to display the properties of a SbUnoObjects
OUString Impl_DumpProperties( SbUnoObject* pUnoObj )
{
OUStringBuffer aRet;
aRet.appendAscii("Properties of object ");
aRet.append( getDbgObjectName( pUnoObj ) );
// analyse the Uno-Infos to recognise the arrays
Reference< XIntrospectionAccess > xAccess = pUnoObj->getIntrospectionAccess();
if( !xAccess.is() )
{
Reference< XInvocation > xInvok = pUnoObj->getInvocation();
if( xInvok.is() )
xAccess = xInvok->getIntrospection();
}
if( !xAccess.is() )
{
aRet.appendAscii( "\nUnknown, no introspection available\n" );
return aRet.makeStringAndClear();
}
Sequence<Property> props = xAccess->getProperties( PropertyConcept::ALL - PropertyConcept::DANGEROUS );
sal_uInt32 nUnoPropCount = props.getLength();
const Property* pUnoProps = props.getConstArray();
SbxArray* pProps = pUnoObj->GetProperties();
sal_uInt16 nPropCount = pProps->Count();
sal_uInt16 nPropsPerLine = 1 + nPropCount / 30;
for( sal_uInt16 i = 0; i < nPropCount; i++ )
{
SbxVariable* pVar = pProps->Get( i );
if( pVar )
{
OUStringBuffer aPropStr;
if( (i % nPropsPerLine) == 0 )
aPropStr.appendAscii( "\n" );
// output the type and name
// Is it in Uno a sequence?
SbxDataType eType = pVar->GetFullType();
bool bMaybeVoid = false;
if( i < nUnoPropCount )
{
const Property& rProp = pUnoProps[ i ];
// For MAYBEVOID freshly convert the type from Uno,
// so not just SbxEMPTY is returned.
if( rProp.Attributes & PropertyAttribute::MAYBEVOID )
{
eType = unoToSbxType( rProp.Type.getTypeClass() );
bMaybeVoid = true;
}
if( eType == SbxOBJECT )
{
Type aType = rProp.Type;
if( aType.getTypeClass() == TypeClass_SEQUENCE )
eType = (SbxDataType) ( SbxOBJECT | SbxARRAY );
}
}
aPropStr.append( Dbg_SbxDataType2String( eType ) );
if( bMaybeVoid )
aPropStr.appendAscii( "/void" );
aPropStr.appendAscii( " " );
aPropStr.append( pVar->GetName() );
if( i == nPropCount - 1 )
aPropStr.appendAscii( "\n" );
else
aPropStr.appendAscii( "; " );
aRet.append( aPropStr.makeStringAndClear() );
}
}
return aRet.makeStringAndClear();
}
// Debugging help method to display the methods of an SbUnoObjects
OUString Impl_DumpMethods( SbUnoObject* pUnoObj )
{
OUStringBuffer aRet;
aRet.appendAscii("Methods of object ");
aRet.append( getDbgObjectName( pUnoObj ) );
// XIntrospectionAccess, so that the types of the parameter could be outputed
Reference< XIntrospectionAccess > xAccess = pUnoObj->getIntrospectionAccess();
if( !xAccess.is() )
{
Reference< XInvocation > xInvok = pUnoObj->getInvocation();
if( xInvok.is() )
xAccess = xInvok->getIntrospection();
}
if( !xAccess.is() )
{
aRet.appendAscii( "\nUnknown, no introspection available\n" );
return aRet.makeStringAndClear();
}
Sequence< Reference< XIdlMethod > > methods = xAccess->getMethods
( MethodConcept::ALL - MethodConcept::DANGEROUS );
const Reference< XIdlMethod >* pUnoMethods = methods.getConstArray();
SbxArray* pMethods = pUnoObj->GetMethods();
sal_uInt16 nMethodCount = pMethods->Count();
if( !nMethodCount )
{
aRet.appendAscii( "\nNo methods found\n" );
return aRet.makeStringAndClear();
}
sal_uInt16 nPropsPerLine = 1 + nMethodCount / 30;
for( sal_uInt16 i = 0; i < nMethodCount; i++ )
{
SbxVariable* pVar = pMethods->Get( i );
if( pVar )
{
if( (i % nPropsPerLine) == 0 )
aRet.appendAscii( "\n" );
// address the method
const Reference< XIdlMethod >& rxMethod = pUnoMethods[i];
// Is it in Uno a sequence?
SbxDataType eType = pVar->GetFullType();
if( eType == SbxOBJECT )
{
Reference< XIdlClass > xClass = rxMethod->getReturnType();
if( xClass.is() && xClass->getTypeClass() == TypeClass_SEQUENCE )
eType = (SbxDataType) ( SbxOBJECT | SbxARRAY );
}
// output the name and the type
aRet.append( Dbg_SbxDataType2String( eType ) );
aRet.appendAscii( " " );
aRet.append ( pVar->GetName() );
aRet.appendAscii( " ( " );
// the get-method mustn't have a parameter
Sequence< Reference< XIdlClass > > aParamsSeq = rxMethod->getParameterTypes();
sal_uInt32 nParamCount = aParamsSeq.getLength();
const Reference< XIdlClass >* pParams = aParamsSeq.getConstArray();
if( nParamCount > 0 )
{
for( sal_uInt16 j = 0; j < nParamCount; j++ )
{
aRet.append ( Dbg_SbxDataType2String( unoToSbxType( pParams[ j ] ) ) );
if( j < nParamCount - 1 )
aRet.appendAscii( ", " );
}
}
else
aRet.appendAscii( "void" );
aRet.appendAscii( " ) " );
if( i == nMethodCount - 1 )
aRet.appendAscii( "\n" );
else
aRet.appendAscii( "; " );
}
}
return aRet.makeStringAndClear();
}
TYPEINIT1(AutomationNamedArgsSbxArray,SbxArray)
// Implementation SbUnoObject
void SbUnoObject::SFX_NOTIFY( SfxBroadcaster& rBC, const TypeId& rBCType,
const SfxHint& rHint, const TypeId& rHintType )
{
if( bNeedIntrospection )
doIntrospection();
const SbxHint* pHint = PTR_CAST(SbxHint,&rHint);
if( pHint )
{
SbxVariable* pVar = pHint->GetVar();
SbxArray* pParams = pVar->GetParameters();
SbUnoProperty* pProp = PTR_CAST(SbUnoProperty,pVar);
SbUnoMethod* pMeth = PTR_CAST(SbUnoMethod,pVar);
if( pProp )
{
bool bInvocation = pProp->isInvocationBased();
if( pHint->GetId() == SBX_HINT_DATAWANTED )
{
// Test-Properties
sal_Int32 nId = pProp->nId;
if( nId < 0 )
{
// Id == -1: Display implemented interfaces according the ClassProvider
if( nId == -1 ) // Property ID_DBG_SUPPORTEDINTERFACES"
{
OUString aRetStr = Impl_GetSupportedInterfaces( this );
pVar->PutString( aRetStr );
}
// Id == -2: output properties
else if( nId == -2 ) // Property ID_DBG_PROPERTIES
{
// now all properties must be created
implCreateAll();
OUString aRetStr = Impl_DumpProperties( this );
pVar->PutString( aRetStr );
}
// Id == -3: output the methods
else if( nId == -3 ) // Property ID_DBG_METHODS
{
// now all properties must be created
implCreateAll();
OUString aRetStr = Impl_DumpMethods( this );
pVar->PutString( aRetStr );
}
return;
}
if( !bInvocation && mxUnoAccess.is() )
{
try
{
if ( maStructInfo.get() )
{
StructRefInfo aMember = maStructInfo->getStructMember( pProp->GetName() );
if ( aMember.isEmpty() )
{
StarBASIC::Error( SbERR_PROPERTY_NOT_FOUND );
}
else
{
if ( pProp->isUnoStruct() )
{
SbUnoStructRefObject* pSbUnoObject = new SbUnoStructRefObject( pProp->GetName(), aMember );
SbxObjectRef xWrapper = (SbxObject*)pSbUnoObject;
pVar->PutObject( xWrapper );
}
else
{
Any aRetAny = aMember.getValue();
// take over the value from Uno to Sbx
unoToSbxValue( pVar, aRetAny );
}
return;
}
}
// get the value
Reference< XPropertySet > xPropSet( mxUnoAccess->queryAdapter( cppu::UnoType<XPropertySet>::get()), UNO_QUERY );
Any aRetAny = xPropSet->getPropertyValue( pProp->GetName() );
// The use of getPropertyValue (instead of using the index) is
// suboptimal, but the refactoring to XInvocation is already pending
// Otherwise it is posible to use FastPropertySet
// take over the value from Uno to Sbx
unoToSbxValue( pVar, aRetAny );
}
catch( const Exception& )
{
implHandleAnyException( ::cppu::getCaughtException() );
}
}
else if( bInvocation && mxInvocation.is() )
{
try
{
sal_uInt32 nParamCount = pParams ? ((sal_uInt32)pParams->Count() - 1) : 0;
bool bCanBeConsideredAMethod = mxInvocation->hasMethod( pProp->GetName() );
Any aRetAny;
if ( bCanBeConsideredAMethod && nParamCount )
{
// Automation properties have methods, so.. we need to invoke this through
// XInvocation
Sequence<Any> args;
processAutomationParams( pParams, args, true, nParamCount );
aRetAny = invokeAutomationMethod( pProp->GetName(), args, pParams, nParamCount, mxInvocation, GetProp );
}
else
aRetAny = mxInvocation->getValue( pProp->GetName() );
// take over the value from Uno to Sbx
unoToSbxValue( pVar, aRetAny );
if( pParams && bCanBeConsideredAMethod )
pVar->SetParameters( NULL );
}
catch( const Exception& )
{
implHandleAnyException( ::cppu::getCaughtException() );
}
}
}
else if( pHint->GetId() == SBX_HINT_DATACHANGED )
{
if( !bInvocation && mxUnoAccess.is() )
{
if( pProp->aUnoProp.Attributes & PropertyAttribute::READONLY )
{
StarBASIC::Error( SbERR_PROP_READONLY );
return;
}
if ( maStructInfo.get() )
{
StructRefInfo aMember = maStructInfo->getStructMember( pProp->GetName() );
if ( aMember.isEmpty() )
{
StarBASIC::Error( SbERR_PROPERTY_NOT_FOUND );
}
else
{
Any aAnyValue = sbxToUnoValue( pVar, pProp->aUnoProp.Type, &pProp->aUnoProp );
aMember.setValue( aAnyValue );
}
return;
}
// take over the value from Uno to Sbx
Any aAnyValue = sbxToUnoValue( pVar, pProp->aUnoProp.Type, &pProp->aUnoProp );
try
{
// set the value
Reference< XPropertySet > xPropSet( mxUnoAccess->queryAdapter( cppu::UnoType<XPropertySet>::get()), UNO_QUERY );
xPropSet->setPropertyValue( pProp->GetName(), aAnyValue );
// The use of getPropertyValue (instead of using the index) is
// suboptimal, but the refactoring to XInvocation is already pending
// Otherwise it is posible to use FastPropertySet
}
catch( const Exception& )
{
implHandleAnyException( ::cppu::getCaughtException() );
}
}
else if( bInvocation && mxInvocation.is() )
{
// take over the value from Uno to Sbx
Any aAnyValue = sbxToUnoValueImpl( pVar );
try
{
// set the value
mxInvocation->setValue( pProp->GetName(), aAnyValue );
}
catch( const Exception& )
{
implHandleAnyException( ::cppu::getCaughtException() );
}
}
}
}
else if( pMeth )
{
bool bInvocation = pMeth->isInvocationBased();
if( pHint->GetId() == SBX_HINT_DATAWANTED )
{
// number of Parameter -1 because of Param0 == this
sal_uInt32 nParamCount = pParams ? ((sal_uInt32)pParams->Count() - 1) : 0;
Sequence<Any> args;
bool bOutParams = false;
sal_uInt32 i;
if( !bInvocation && mxUnoAccess.is() )
{
// get info
const Sequence<ParamInfo>& rInfoSeq = pMeth->getParamInfos();
const ParamInfo* pParamInfos = rInfoSeq.getConstArray();
sal_uInt32 nUnoParamCount = rInfoSeq.getLength();
sal_uInt32 nAllocParamCount = nParamCount;
// ignore surplus parameter; alternative: throw an error
if( nParamCount > nUnoParamCount )
{
nParamCount = nUnoParamCount;
nAllocParamCount = nParamCount;
}
else if( nParamCount < nUnoParamCount )
{
SbiInstance* pInst = GetSbData()->pInst;
if( pInst && pInst->IsCompatibility() )
{
// Check types
bool bError = false;
for( i = nParamCount ; i < nUnoParamCount ; i++ )
{
const ParamInfo& rInfo = pParamInfos[i];
const Reference< XIdlClass >& rxClass = rInfo.aType;
if( rxClass->getTypeClass() != TypeClass_ANY )
{
bError = true;
StarBASIC::Error( SbERR_NOT_OPTIONAL );
}
}
if( !bError )
nAllocParamCount = nUnoParamCount;
}
}
if( nAllocParamCount > 0 )
{
args.realloc( nAllocParamCount );
Any* pAnyArgs = args.getArray();
for( i = 0 ; i < nParamCount ; i++ )
{
const ParamInfo& rInfo = pParamInfos[i];
const Reference< XIdlClass >& rxClass = rInfo.aType;
com::sun::star::uno::Type aType( rxClass->getTypeClass(), rxClass->getName() );
// ATTENTION: Don't forget for Sbx-Parameter the offset!
pAnyArgs[i] = sbxToUnoValue( pParams->Get( (sal_uInt16)(i+1) ), aType );
// If it is not certain check whether the out-parameter are available.
if( !bOutParams )
{
ParamMode aParamMode = rInfo.aMode;
if( aParamMode != ParamMode_IN )
bOutParams = true;
}
}
}
}
else if( bInvocation && pParams && mxInvocation.is() )
{
bool bOLEAutomation = true;
processAutomationParams( pParams, args, bOLEAutomation, nParamCount );
}
// call the method
GetSbData()->bBlockCompilerError = true; // #106433 Block compiler errors for API calls
try
{
if( !bInvocation && mxUnoAccess.is() )
{
Any aRetAny = pMeth->m_xUnoMethod->invoke( getUnoAny(), args );
// take over the value from Uno to Sbx
unoToSbxValue( pVar, aRetAny );
// Did we to copy back the Out-Parameter?
if( bOutParams )
{
const Any* pAnyArgs = args.getConstArray();
// get info
const Sequence<ParamInfo>& rInfoSeq = pMeth->getParamInfos();
const ParamInfo* pParamInfos = rInfoSeq.getConstArray();
sal_uInt32 j;
for( j = 0 ; j < nParamCount ; j++ )
{
const ParamInfo& rInfo = pParamInfos[j];
ParamMode aParamMode = rInfo.aMode;
if( aParamMode != ParamMode_IN )
unoToSbxValue( (SbxVariable*)pParams->Get( (sal_uInt16)(j+1) ), pAnyArgs[ j ] );
}
}
}
else if( bInvocation && mxInvocation.is() )
{
Any aRetAny = invokeAutomationMethod( pMeth->GetName(), args, pParams, nParamCount, mxInvocation );
unoToSbxValue( pVar, aRetAny );
}
// remove parameter here, because this was not done anymore in unoToSbxValue()
// for arrays
if( pParams )
pVar->SetParameters( NULL );
}
catch( const Exception& )
{
implHandleAnyException( ::cppu::getCaughtException() );
}
GetSbData()->bBlockCompilerError = false; // #106433 Unblock compiler errors
}
}
else
SbxObject::SFX_NOTIFY( rBC, rBCType, rHint, rHintType );
}
}
SbUnoObject::SbUnoObject( const OUString& aName_, const Any& aUnoObj_ )
: SbxObject( aName_ )
, bNeedIntrospection( true )
, bNativeCOMObject( false )
{
static Reference< XIntrospection > xIntrospection;
// beat out again the default properties of Sbx
Remove( OUString("Name"), SbxCLASS_DONTCARE );
Remove( OUString("Parent"), SbxCLASS_DONTCARE );
// check the type of the ojekts
TypeClass eType = aUnoObj_.getValueType().getTypeClass();
Reference< XInterface > x;
if( eType == TypeClass_INTERFACE )
{
// get the interface from the Any
x = *(Reference< XInterface >*)aUnoObj_.getValue();
if( !x.is() )
return;
}
Reference< XTypeProvider > xTypeProvider;
// Did the object have an invocation itself?
mxInvocation = Reference< XInvocation >( x, UNO_QUERY );
xTypeProvider = Reference< XTypeProvider >( x, UNO_QUERY );
if( mxInvocation.is() )
{
// get the ExactName
mxExactNameInvocation = Reference< XExactName >::query( mxInvocation );
// The remainder refers only to the introspection
if( !xTypeProvider.is() )
{
bNeedIntrospection = false;
return;
}
// Ignore introspection based members for COM objects to avoid
// hiding of equally named COM symbols, e.g. XInvocation::getValue
Reference< oleautomation::XAutomationObject > xAutomationObject( aUnoObj_, UNO_QUERY );
if( xAutomationObject.is() )
bNativeCOMObject = true;
}
maTmpUnoObj = aUnoObj_;
//*** Define the name ***
bool bFatalError = true;
// Is it an interface or a struct?
bool bSetClassName = false;
OUString aClassName_;
if( eType == TypeClass_STRUCT || eType == TypeClass_EXCEPTION )
{
// Struct is Ok
bFatalError = false;
// insert the real name of the class
if( aName_.isEmpty() )
{
aClassName_ = aUnoObj_.getValueType().getTypeName();
bSetClassName = true;
}
typelib_TypeDescription * pDeclTD = 0;
typelib_typedescription_getByName( &pDeclTD, maTmpUnoObj.getValueTypeName().pData );
StructRefInfo aThisStruct( maTmpUnoObj, pDeclTD, 0 );
maStructInfo.reset( new SbUnoStructRefObject( GetName(), aThisStruct ) );
}
else if( eType == TypeClass_INTERFACE )
{
// Interface works always through the type in the Any
bFatalError = false;
}
if( bSetClassName )
SetClassName( aClassName_ );
// Neither interface nor Struct -> FatalError
if( bFatalError )
{
StarBASIC::FatalError( ERRCODE_BASIC_EXCEPTION );
return;
}
// pass the introspection primal on demand
}
SbUnoObject::~SbUnoObject()
{
}
// pass the introspection on Demand
void SbUnoObject::doIntrospection( void )
{
static Reference< XIntrospection > xIntrospection;
if( !bNeedIntrospection )
return;
bNeedIntrospection = false;
if( !xIntrospection.is() )
{
// get the introspection service
Reference< XComponentContext > xContext( comphelper::getProcessComponentContext() );
xIntrospection = theIntrospection::get( xContext );
}
// pass the introspection
try
{
mxUnoAccess = xIntrospection->inspect( maTmpUnoObj );
}
catch( const RuntimeException& e )
{
StarBASIC::Error( ERRCODE_BASIC_EXCEPTION, implGetExceptionMsg( e ) );
}
if( !mxUnoAccess.is() )
{
// #51475 mark to indicate an invalid object (no mxMaterialHolder)
return;
}
// get MaterialHolder from access
mxMaterialHolder = Reference< XMaterialHolder >::query( mxUnoAccess );
// get ExactName from access
mxExactName = Reference< XExactName >::query( mxUnoAccess );
}
// Start of a list of all SbUnoMethod-Instances
static SbUnoMethod* pFirst = NULL;
void clearUnoMethodsForBasic( StarBASIC* pBasic )
{
SbUnoMethod* pMeth = pFirst;
while( pMeth )
{
SbxObject* pObject = dynamic_cast< SbxObject* >( pMeth->GetParent() );
if ( pObject )
{
StarBASIC* pModBasic = dynamic_cast< StarBASIC* >( pObject->GetParent() );
if ( pModBasic == pBasic )
{
// for now the solution is to remove the method from the list and to clear it,
// but in case the element should be correctly transferred to another StarBASIC,
// we should either set module parent to NULL without clearing it, or even
// set the new StarBASIC as the parent of the module
// pObject->SetParent( NULL );
if( pMeth == pFirst )
pFirst = pMeth->pNext;
else if( pMeth->pPrev )
pMeth->pPrev->pNext = pMeth->pNext;
if( pMeth->pNext )
pMeth->pNext->pPrev = pMeth->pPrev;
pMeth->pPrev = NULL;
pMeth->pNext = NULL;
pMeth->SbxValue::Clear();
pObject->SbxValue::Clear();
// start from the beginning after object clearing, the cycle will end since the method is removed each time
pMeth = pFirst;
}
else
pMeth = pMeth->pNext;
}
else
pMeth = pMeth->pNext;
}
}
void clearUnoMethods( void )
{
SbUnoMethod* pMeth = pFirst;
while( pMeth )
{
pMeth->SbxValue::Clear();
pMeth = pMeth->pNext;
}
}
SbUnoMethod::SbUnoMethod
(
const OUString& aName_,
SbxDataType eSbxType,
Reference< XIdlMethod > xUnoMethod_,
bool bInvocation,
bool bDirect
)
: SbxMethod( aName_, eSbxType )
, mbInvocation( bInvocation )
, mbDirectInvocation( bDirect )
{
m_xUnoMethod = xUnoMethod_;
pParamInfoSeq = NULL;
// enregister the method in a list
pNext = pFirst;
pPrev = NULL;
pFirst = this;
if( pNext )
pNext->pPrev = this;
}
SbUnoMethod::~SbUnoMethod()
{
delete pParamInfoSeq;
if( this == pFirst )
pFirst = pNext;
else if( pPrev )
pPrev->pNext = pNext;
if( pNext )
pNext->pPrev = pPrev;
}
SbxInfo* SbUnoMethod::GetInfo()
{
if( !pInfo && m_xUnoMethod.is() )
{
SbiInstance* pInst = GetSbData()->pInst;
if( pInst && pInst->IsCompatibility() )
{
pInfo = new SbxInfo();
const Sequence<ParamInfo>& rInfoSeq = getParamInfos();
const ParamInfo* pParamInfos = rInfoSeq.getConstArray();
sal_uInt32 nParamCount = rInfoSeq.getLength();
for( sal_uInt32 i = 0 ; i < nParamCount ; i++ )
{
const ParamInfo& rInfo = pParamInfos[i];
OUString aParamName = rInfo.aName;
SbxDataType t = SbxVARIANT;
sal_uInt16 nFlags_ = SBX_READ;
pInfo->AddParam( aParamName, t, nFlags_ );
}
}
}
return pInfo;
}
const Sequence<ParamInfo>& SbUnoMethod::getParamInfos( void )
{
if( !pParamInfoSeq && m_xUnoMethod.is() )
{
Sequence<ParamInfo> aTmp = m_xUnoMethod->getParameterInfos() ;
pParamInfoSeq = new Sequence<ParamInfo>( aTmp );
}
return *pParamInfoSeq;
}
SbUnoProperty::SbUnoProperty
(
const OUString& aName_,
SbxDataType eSbxType,
SbxDataType eRealSbxType,
const Property& aUnoProp_,
sal_Int32 nId_,
bool bInvocation,
bool bUnoStruct
)
: SbxProperty( aName_, eSbxType )
, aUnoProp( aUnoProp_ )
, nId( nId_ )
, mbInvocation( bInvocation )
, mRealType( eRealSbxType )
, mbUnoStruct( bUnoStruct )
{
// as needed establish an dummy array so that SbiRuntime::CheckArray() works
static SbxArrayRef xDummyArray = new SbxArray( SbxVARIANT );
if( eSbxType & SbxARRAY )
PutObject( xDummyArray );
}
SbUnoProperty::~SbUnoProperty()
{}
SbxVariable* SbUnoObject::Find( const OUString& rName, SbxClassType t )
{
static Reference< XIdlMethod > xDummyMethod;
static Property aDummyProp;
SbxVariable* pRes = SbxObject::Find( rName, t );
if( bNeedIntrospection )
doIntrospection();
// New 1999-03-04: Create properties on demand. Therefore search now via
// IntrospectionAccess if a property or a method of the required name exist
if( !pRes )
{
OUString aUName( rName );
if( mxUnoAccess.is() && !bNativeCOMObject )
{
if( mxExactName.is() )
{
OUString aUExactName = mxExactName->getExactName( aUName );
if( !aUExactName.isEmpty() )
{
aUName = aUExactName;
}
}
if( mxUnoAccess->hasProperty( aUName, PropertyConcept::ALL - PropertyConcept::DANGEROUS ) )
{
const Property& rProp = mxUnoAccess->
getProperty( aUName, PropertyConcept::ALL - PropertyConcept::DANGEROUS );
// If the property could be void the type had to be set to Variant
SbxDataType eSbxType;
if( rProp.Attributes & PropertyAttribute::MAYBEVOID )
eSbxType = SbxVARIANT;
else
eSbxType = unoToSbxType( rProp.Type.getTypeClass() );
SbxDataType eRealSbxType = ( ( rProp.Attributes & PropertyAttribute::MAYBEVOID ) ? unoToSbxType( rProp.Type.getTypeClass() ) : eSbxType );
// create the property and superimpose it
SbUnoProperty* pProp = new SbUnoProperty( rProp.Name, eSbxType, eRealSbxType, rProp, 0, false, ( rProp.Type.getTypeClass() == com::sun::star::uno::TypeClass_STRUCT ) );
SbxVariableRef xVarRef = pProp;
QuickInsert( (SbxVariable*)xVarRef );
pRes = xVarRef;
}
else if( mxUnoAccess->hasMethod( aUName,
MethodConcept::ALL - MethodConcept::DANGEROUS ) )
{
// address the method
const Reference< XIdlMethod >& rxMethod = mxUnoAccess->
getMethod( aUName, MethodConcept::ALL - MethodConcept::DANGEROUS );
// create SbUnoMethod and superimpose it
SbxVariableRef xMethRef = new SbUnoMethod( rxMethod->getName(),
unoToSbxType( rxMethod->getReturnType() ), rxMethod, false );
QuickInsert( (SbxVariable*)xMethRef );
pRes = xMethRef;
}
// If nothing was found check via XNameAccess
if( !pRes )
{
try
{
Reference< XNameAccess > xNameAccess( mxUnoAccess->queryAdapter( cppu::UnoType<XPropertySet>::get()), UNO_QUERY );
OUString aUName2( rName );
if( xNameAccess.is() && xNameAccess->hasByName( aUName2 ) )
{
Any aAny = xNameAccess->getByName( aUName2 );
// ATTENTION: Because of XNameAccess, the variable generated here
// may not be included as a fixed property in the object and therefore
// won't be stored anywhere.
// If this leads to problems, it has to be created
// synthetically or a class SbUnoNameAccessProperty,
// witch checks the existence on access and which
// is disposed if the name is not found anymore.
pRes = new SbxVariable( SbxVARIANT );
unoToSbxValue( pRes, aAny );
}
}
catch( const NoSuchElementException& e )
{
StarBASIC::Error( ERRCODE_BASIC_EXCEPTION, implGetExceptionMsg( e ) );
}
catch( const Exception& )
{
// Establish so that the exeption error will not be overwriten
if( !pRes )
pRes = new SbxVariable( SbxVARIANT );
implHandleAnyException( ::cppu::getCaughtException() );
}
}
}
if( !pRes && mxInvocation.is() )
{
if( mxExactNameInvocation.is() )
{
OUString aUExactName = mxExactNameInvocation->getExactName( aUName );
if( !aUExactName.isEmpty() )
{
aUName = aUExactName;
}
}
try
{
if( mxInvocation->hasProperty( aUName ) )
{
// create a property and superimpose it
SbxVariableRef xVarRef = new SbUnoProperty( aUName, SbxVARIANT, SbxVARIANT, aDummyProp, 0, true, false );
QuickInsert( (SbxVariable*)xVarRef );
pRes = xVarRef;
}
else if( mxInvocation->hasMethod( aUName ) )
{
// create SbUnoMethode and superimpose it
SbxVariableRef xMethRef = new SbUnoMethod( aUName, SbxVARIANT, xDummyMethod, true );
QuickInsert( (SbxVariable*)xMethRef );
pRes = xMethRef;
}
else
{
Reference< XDirectInvocation > xDirectInvoke( mxInvocation, UNO_QUERY );
if ( xDirectInvoke.is() && xDirectInvoke->hasMember( aUName ) )
{
SbxVariableRef xMethRef = new SbUnoMethod( aUName, SbxVARIANT, xDummyMethod, true, true );
QuickInsert( (SbxVariable*)xMethRef );
pRes = xMethRef;
}
}
}
catch( const RuntimeException& e )
{
// Establish so that the exeption error will not be overwriten
if( !pRes )
pRes = new SbxVariable( SbxVARIANT );
StarBASIC::Error( ERRCODE_BASIC_EXCEPTION, implGetExceptionMsg( e ) );
}
}
}
// At the very end checking if the Dbg_-Properties are meant
if( !pRes )
{
if( rName.equalsIgnoreAsciiCase(ID_DBG_SUPPORTEDINTERFACES) ||
rName.equalsIgnoreAsciiCase(ID_DBG_PROPERTIES) ||
rName.equalsIgnoreAsciiCase(ID_DBG_METHODS) )
{
// Create
implCreateDbgProperties();
// Now they have to be found regular
pRes = SbxObject::Find( rName, SbxCLASS_DONTCARE );
}
}
return pRes;
}
// help method to create the dbg_-Properties
void SbUnoObject::implCreateDbgProperties( void )
{
Property aProp;
// Id == -1: display the implemented interfaces corresponding the ClassProvider
SbxVariableRef xVarRef = new SbUnoProperty( OUString(ID_DBG_SUPPORTEDINTERFACES), SbxSTRING, SbxSTRING, aProp, -1, false, false );
QuickInsert( (SbxVariable*)xVarRef );
// Id == -2: output the properties
xVarRef = new SbUnoProperty( OUString(ID_DBG_PROPERTIES), SbxSTRING, SbxSTRING, aProp, -2, false, false );
QuickInsert( (SbxVariable*)xVarRef );
// Id == -3: output the Methods
xVarRef = new SbUnoProperty( OUString(ID_DBG_METHODS), SbxSTRING, SbxSTRING, aProp, -3, false, false );
QuickInsert( (SbxVariable*)xVarRef );
}
void SbUnoObject::implCreateAll( void )
{
// throw away all existing methods and properties
pMethods = new SbxArray;
pProps = new SbxArray;
if( bNeedIntrospection ) doIntrospection();
// get introspection
Reference< XIntrospectionAccess > xAccess = mxUnoAccess;
if( !xAccess.is() || bNativeCOMObject )
{
if( mxInvocation.is() )
xAccess = mxInvocation->getIntrospection();
else if( bNativeCOMObject )
return;
}
if( !xAccess.is() )
return;
// Establish properties
Sequence<Property> props = xAccess->getProperties( PropertyConcept::ALL - PropertyConcept::DANGEROUS );
sal_uInt32 nPropCount = props.getLength();
const Property* pProps_ = props.getConstArray();
sal_uInt32 i;
for( i = 0 ; i < nPropCount ; i++ )
{
const Property& rProp = pProps_[ i ];
// If the property could be void the type had to be set to Variant
SbxDataType eSbxType;
if( rProp.Attributes & PropertyAttribute::MAYBEVOID )
eSbxType = SbxVARIANT;
else
eSbxType = unoToSbxType( rProp.Type.getTypeClass() );
SbxDataType eRealSbxType = ( ( rProp.Attributes & PropertyAttribute::MAYBEVOID ) ? unoToSbxType( rProp.Type.getTypeClass() ) : eSbxType );
// Create property and superimpose it
SbxVariableRef xVarRef = new SbUnoProperty( rProp.Name, eSbxType, eRealSbxType, rProp, i, false, ( rProp.Type.getTypeClass() == com::sun::star::uno::TypeClass_STRUCT ) );
QuickInsert( (SbxVariable*)xVarRef );
}
// Create Dbg_-Properties
implCreateDbgProperties();
// Create methods
Sequence< Reference< XIdlMethod > > aMethodSeq = xAccess->getMethods
( MethodConcept::ALL - MethodConcept::DANGEROUS );
sal_uInt32 nMethCount = aMethodSeq.getLength();
const Reference< XIdlMethod >* pMethods_ = aMethodSeq.getConstArray();
for( i = 0 ; i < nMethCount ; i++ )
{
// address method
const Reference< XIdlMethod >& rxMethod = pMethods_[i];
// Create SbUnoMethod and superimpose it
SbxVariableRef xMethRef = new SbUnoMethod
( rxMethod->getName(), unoToSbxType( rxMethod->getReturnType() ), rxMethod, false );
QuickInsert( (SbxVariable*)xMethRef );
}
}
// output the value
Any SbUnoObject::getUnoAny( void )
{
Any aRetAny;
if( bNeedIntrospection ) doIntrospection();
if ( maStructInfo.get() )
aRetAny = maTmpUnoObj;
else if( mxMaterialHolder.is() )
aRetAny = mxMaterialHolder->getMaterial();
else if( mxInvocation.is() )
aRetAny <<= mxInvocation;
return aRetAny;
}
// help method to create an Uno-Struct per CoreReflection
SbUnoObject* Impl_CreateUnoStruct( const OUString& aClassName )
{
// get CoreReflection
Reference< XIdlReflection > xCoreReflection = getCoreReflection_Impl();
if( !xCoreReflection.is() )
return NULL;
// search for the class
Reference< XIdlClass > xClass;
Reference< XHierarchicalNameAccess > xHarryName =
getCoreReflection_HierarchicalNameAccess_Impl();
if( xHarryName.is() && xHarryName->hasByHierarchicalName( aClassName ) )
xClass = xCoreReflection->forName( aClassName );
if( !xClass.is() )
return NULL;
// Is it really a struct?
TypeClass eType = xClass->getTypeClass();
if ( ( eType != TypeClass_STRUCT ) && ( eType != TypeClass_EXCEPTION ) )
return NULL;
// create an instance
Any aNewAny;
xClass->createObject( aNewAny );
// make a SbUnoObject out of it
SbUnoObject* pUnoObj = new SbUnoObject( aClassName, aNewAny );
return pUnoObj;
}
// Factory-Class to create Uno-Structs per DIM AS NEW
SbxBase* SbUnoFactory::Create( sal_uInt16, sal_uInt32 )
{
// Via SbxId nothing works in Uno
return NULL;
}
SbxObject* SbUnoFactory::CreateObject( const OUString& rClassName )
{
return Impl_CreateUnoStruct( rClassName );
}
// Provisional interface for the UNO-Connection
// Deliver a SbxObject, that wrap an Uno-Interface
SbxObjectRef GetSbUnoObject( const OUString& aName, const Any& aUnoObj_ )
{
return new SbUnoObject( aName, aUnoObj_ );
}
// Force creation of all properties for debugging
void createAllObjectProperties( SbxObject* pObj )
{
if( !pObj )
return;
SbUnoObject* pUnoObj = PTR_CAST(SbUnoObject,pObj);
SbUnoStructRefObject* pUnoStructObj = PTR_CAST(SbUnoStructRefObject,pObj);
if( pUnoObj )
{
pUnoObj->createAllProperties();
}
else if ( pUnoStructObj )
{
pUnoStructObj->createAllProperties();
}
else
{
pObj->GetAll( SbxCLASS_DONTCARE );
}
}
void RTL_Impl_CreateUnoStruct( StarBASIC* pBasic, SbxArray& rPar, bool bWrite )
{
(void)pBasic;
(void)bWrite;
// We need 1 parameter minimum
if ( rPar.Count() < 2 )
{
StarBASIC::Error( SbERR_BAD_ARGUMENT );
return;
}
// get the name of the class of the struct
OUString aClassName = rPar.Get(1)->GetOUString();
// try to create Struct with the same name
SbUnoObjectRef xUnoObj = Impl_CreateUnoStruct( aClassName );
if( !xUnoObj )
{
return;
}
// return the object
SbxVariableRef refVar = rPar.Get(0);
refVar->PutObject( (SbUnoObject*)xUnoObj );
}
void RTL_Impl_CreateUnoService( StarBASIC* pBasic, SbxArray& rPar, bool bWrite )
{
(void)pBasic;
(void)bWrite;
// We need 1 Parameter minimum
if ( rPar.Count() < 2 )
{
StarBASIC::Error( SbERR_BAD_ARGUMENT );
return;
}
// get the name of the class of the struct
OUString aServiceName = rPar.Get(1)->GetOUString();
// search for the service and instatiate it
Reference< XMultiServiceFactory > xFactory( comphelper::getProcessServiceFactory() );
Reference< XInterface > xInterface;
try
{
xInterface = xFactory->createInstance( aServiceName );
}
catch( const Exception& )
{
implHandleAnyException( ::cppu::getCaughtException() );
}
SbxVariableRef refVar = rPar.Get(0);
if( xInterface.is() )
{
Any aAny;
aAny <<= xInterface;
// Create a SbUnoObject out of it and return it
SbUnoObjectRef xUnoObj = new SbUnoObject( aServiceName, aAny );
if( xUnoObj->getUnoAny().getValueType().getTypeClass() != TypeClass_VOID )
{
// return the object
refVar->PutObject( (SbUnoObject*)xUnoObj );
}
else
{
refVar->PutObject( NULL );
}
}
else
{
refVar->PutObject( NULL );
}
}
void RTL_Impl_CreateUnoServiceWithArguments( StarBASIC* pBasic, SbxArray& rPar, bool bWrite )
{
(void)pBasic;
(void)bWrite;
// We need 2 parameter minimum
if ( rPar.Count() < 3 )
{
StarBASIC::Error( SbERR_BAD_ARGUMENT );
return;
}
// get the name of the class of the struct
OUString aServiceName = rPar.Get(1)->GetOUString();
Any aArgAsAny = sbxToUnoValue( rPar.Get(2),
getCppuType( (Sequence<Any>*)0 ) );
Sequence< Any > aArgs;
aArgAsAny >>= aArgs;
// search for the service and instatiate it
Reference< XMultiServiceFactory > xFactory( comphelper::getProcessServiceFactory() );
Reference< XInterface > xInterface;
try
{
xInterface = xFactory->createInstanceWithArguments( aServiceName, aArgs );
}
catch( const Exception& )
{
implHandleAnyException( ::cppu::getCaughtException() );
}
SbxVariableRef refVar = rPar.Get(0);
if( xInterface.is() )
{
Any aAny;
aAny <<= xInterface;
// Create a SbUnoObject out of it and return it
SbUnoObjectRef xUnoObj = new SbUnoObject( aServiceName, aAny );
if( xUnoObj->getUnoAny().getValueType().getTypeClass() != TypeClass_VOID )
{
// return the object
refVar->PutObject( (SbUnoObject*)xUnoObj );
}
else
{
refVar->PutObject( NULL );
}
}
else
{
refVar->PutObject( NULL );
}
}
void RTL_Impl_GetProcessServiceManager( StarBASIC* pBasic, SbxArray& rPar, bool bWrite )
{
(void)pBasic;
(void)bWrite;
SbxVariableRef refVar = rPar.Get(0);
// get the global service manager
Reference< XMultiServiceFactory > xFactory( comphelper::getProcessServiceFactory() );
Any aAny;
aAny <<= xFactory;
// Create a SbUnoObject out of it and return it
SbUnoObjectRef xUnoObj = new SbUnoObject( OUString( "ProcessServiceManager" ), aAny );
refVar->PutObject( (SbUnoObject*)xUnoObj );
}
void RTL_Impl_HasInterfaces( StarBASIC* pBasic, SbxArray& rPar, bool bWrite )
{
(void)pBasic;
(void)bWrite;
// We need 2 parameter minimum
sal_uInt16 nParCount = rPar.Count();
if( nParCount < 3 )
{
StarBASIC::Error( SbERR_BAD_ARGUMENT );
return;
}
// variable for the return value
SbxVariableRef refVar = rPar.Get(0);
refVar->PutBool( false );
// get the Uno-Object
SbxBaseRef pObj = (SbxBase*)rPar.Get( 1 )->GetObject();
if( !(pObj && pObj->ISA(SbUnoObject)) )
{
return;
}
Any aAny = ((SbUnoObject*)(SbxBase*)pObj)->getUnoAny();
TypeClass eType = aAny.getValueType().getTypeClass();
if( eType != TypeClass_INTERFACE )
{
return;
}
// get the interface out of the Any
Reference< XInterface > x = *(Reference< XInterface >*)aAny.getValue();
// get CoreReflection
Reference< XIdlReflection > xCoreReflection = getCoreReflection_Impl();
if( !xCoreReflection.is() )
{
return;
}
for( sal_uInt16 i = 2 ; i < nParCount ; i++ )
{
// get the name of the interface of the struct
OUString aIfaceName = rPar.Get( i )->GetOUString();
// search for the class
Reference< XIdlClass > xClass = xCoreReflection->forName( aIfaceName );
if( !xClass.is() )
{
return;
}
// check if the interface will be supported
OUString aClassName = xClass->getName();
Type aClassType( xClass->getTypeClass(), aClassName.getStr() );
if( !x->queryInterface( aClassType ).hasValue() )
{
return;
}
}
// Every thing works; then return TRUE
refVar->PutBool( true );
}
void RTL_Impl_IsUnoStruct( StarBASIC* pBasic, SbxArray& rPar, bool bWrite )
{
(void)pBasic;
(void)bWrite;
// We need 1 parameter minimum
if ( rPar.Count() < 2 )
{
StarBASIC::Error( SbERR_BAD_ARGUMENT );
return;
}
// variable for the return value
SbxVariableRef refVar = rPar.Get(0);
refVar->PutBool( false );
// get the Uno-Object
SbxVariableRef xParam = rPar.Get( 1 );
if( !xParam->IsObject() )
{
return;
}
SbxBaseRef pObj = (SbxBase*)rPar.Get( 1 )->GetObject();
if( !(pObj && pObj->ISA(SbUnoObject)) )
{
return;
}
Any aAny = ((SbUnoObject*)(SbxBase*)pObj)->getUnoAny();
TypeClass eType = aAny.getValueType().getTypeClass();
if( eType == TypeClass_STRUCT )
{
refVar->PutBool( true );
}
}
void RTL_Impl_EqualUnoObjects( StarBASIC* pBasic, SbxArray& rPar, bool bWrite )
{
(void)pBasic;
(void)bWrite;
if ( rPar.Count() < 3 )
{
StarBASIC::Error( SbERR_BAD_ARGUMENT );
return;
}
// variable for the return value
SbxVariableRef refVar = rPar.Get(0);
refVar->PutBool( false );
// get the Uno-Objects
SbxVariableRef xParam1 = rPar.Get( 1 );
if( !xParam1->IsObject() )
{
return;
}
SbxBaseRef pObj1 = (SbxBase*)xParam1->GetObject();
if( !(pObj1 && pObj1->ISA(SbUnoObject)) )
{
return;
}
Any aAny1 = ((SbUnoObject*)(SbxBase*)pObj1)->getUnoAny();
TypeClass eType1 = aAny1.getValueType().getTypeClass();
if( eType1 != TypeClass_INTERFACE )
{
return;
}
Reference< XInterface > x1;
aAny1 >>= x1;
SbxVariableRef xParam2 = rPar.Get( 2 );
if( !xParam2->IsObject() )
{
return;
}
SbxBaseRef pObj2 = (SbxBase*)xParam2->GetObject();
if( !(pObj2 && pObj2->ISA(SbUnoObject)) )
{
return;
}
Any aAny2 = ((SbUnoObject*)(SbxBase*)pObj2)->getUnoAny();
TypeClass eType2 = aAny2.getValueType().getTypeClass();
if( eType2 != TypeClass_INTERFACE )
{
return;
}
Reference< XInterface > x2;
aAny2 >>= x2;
if( x1 == x2 )
{
refVar->PutBool( true );
}
}
// helper wrapper function to interact with TypeProvider and
// XTypeDescriptionEnumerationAccess.
// if it fails for whatever reason
// returned Reference<> be null e.g. .is() will be false
Reference< XTypeDescriptionEnumeration > getTypeDescriptorEnumeration( const OUString& sSearchRoot,
const Sequence< TypeClass >& types,
TypeDescriptionSearchDepth depth )
{
Reference< XTypeDescriptionEnumeration > xEnum;
Reference< XTypeDescriptionEnumerationAccess> xTypeEnumAccess( getTypeProvider_Impl(), UNO_QUERY );
if ( xTypeEnumAccess.is() )
{
try
{
xEnum = xTypeEnumAccess->createTypeDescriptionEnumeration(
sSearchRoot, types, depth );
}
catch(const NoSuchTypeNameException& /*nstne*/ ) {}
catch(const InvalidTypeNameException& /*nstne*/ ) {}
}
return xEnum;
}
typedef boost::unordered_map< OUString, Any, OUStringHash, ::std::equal_to< OUString > > VBAConstantsHash;
VBAConstantHelper&
VBAConstantHelper::instance()
{
static VBAConstantHelper aHelper;
return aHelper;
}
void VBAConstantHelper::init()
{
if ( !isInited )
{
Sequence< TypeClass > types(1);
types[ 0 ] = TypeClass_CONSTANTS;
Reference< XTypeDescriptionEnumeration > xEnum = getTypeDescriptorEnumeration( OUString(defaultNameSpace), types, TypeDescriptionSearchDepth_INFINITE );
if ( !xEnum.is())
{
return; //NULL;
}
while ( xEnum->hasMoreElements() )
{
Reference< XConstantsTypeDescription > xConstants( xEnum->nextElement(), UNO_QUERY );
if ( xConstants.is() )
{
// store constant group name
OUString sFullName = xConstants->getName();
sal_Int32 indexLastDot = sFullName.lastIndexOf('.');
OUString sLeafName( sFullName );
if ( indexLastDot > -1 )
{
sLeafName = sFullName.copy( indexLastDot + 1);
}
aConstCache.push_back( sLeafName ); // assume constant group names are unique
Sequence< Reference< XConstantTypeDescription > > aConsts = xConstants->getConstants();
for (sal_Int32 i = 0; i != aConsts.getLength(); ++i)
{
// store constant member name
sFullName = aConsts[i]->getName();
indexLastDot = sFullName.lastIndexOf('.');
sLeafName = sFullName;
if ( indexLastDot > -1 )
{
sLeafName = sFullName.copy( indexLastDot + 1);
}
aConstHash[ sLeafName.toAsciiLowerCase() ] = aConsts[i]->getConstantValue();
}
}
}
isInited = true;
}
}
bool
VBAConstantHelper::isVBAConstantType( const OUString& rName )
{
init();
bool bConstant = false;
OUString sKey( rName );
VBAConstantsVector::const_iterator it = aConstCache.begin();
for( ; it != aConstCache.end(); ++it )
{
if( sKey.equalsIgnoreAsciiCase( *it ) )
{
bConstant = true;
break;
}
}
return bConstant;
}
SbxVariable*
VBAConstantHelper::getVBAConstant( const OUString& rName )
{
SbxVariable* pConst = NULL;
init();
OUString sKey( rName );
VBAConstantsHash::const_iterator it = aConstHash.find( sKey.toAsciiLowerCase() );
if ( it != aConstHash.end() )
{
pConst = new SbxVariable( SbxVARIANT );
pConst->SetName( rName );
unoToSbxValue( pConst, it->second );
}
return pConst;
}
// Function to search for a global identifier in the
// UnoScope and to wrap it for Sbx
SbUnoClass* findUnoClass( const OUString& rName )
{
// #105550 Check if module exists
SbUnoClass* pUnoClass = NULL;
Reference< XHierarchicalNameAccess > xTypeAccess = getTypeProvider_Impl();
if( xTypeAccess->hasByHierarchicalName( rName ) )
{
Any aRet = xTypeAccess->getByHierarchicalName( rName );
Reference< XTypeDescription > xTypeDesc;
aRet >>= xTypeDesc;
if( xTypeDesc.is() )
{
TypeClass eTypeClass = xTypeDesc->getTypeClass();
if( eTypeClass == TypeClass_MODULE || eTypeClass == TypeClass_CONSTANTS )
{
pUnoClass = new SbUnoClass( rName );
}
}
}
return pUnoClass;
}
SbxVariable* SbUnoClass::Find( const OUString& rName, SbxClassType )
{
SbxVariable* pRes = SbxObject::Find( rName, SbxCLASS_VARIABLE );
// If nothing were located the submodule isn't known yet
if( !pRes )
{
// If it is already a class, ask for the field
if( m_xClass.is() )
{
// Is it a field(?)
OUString aUStr( rName );
Reference< XIdlField > xField = m_xClass->getField( aUStr );
Reference< XIdlClass > xClass;
if( xField.is() )
{
try
{
Any aAny;
aAny = xField->get( aAny );
// Convert to Sbx
pRes = new SbxVariable( SbxVARIANT );
pRes->SetName( rName );
unoToSbxValue( pRes, aAny );
}
catch( const Exception& )
{
implHandleAnyException( ::cppu::getCaughtException() );
}
}
}
else
{
// expand fully qualified name
OUString aNewName = GetName();
aNewName += ".";
aNewName += rName;
// get CoreReflection
Reference< XIdlReflection > xCoreReflection = getCoreReflection_Impl();
if( xCoreReflection.is() )
{
// Is it a constant?
Reference< XHierarchicalNameAccess > xHarryName( xCoreReflection, UNO_QUERY );
if( xHarryName.is() )
{
try
{
Any aValue = xHarryName->getByHierarchicalName( aNewName );
TypeClass eType = aValue.getValueType().getTypeClass();
// Interface located? Then it is a class
if( eType == TypeClass_INTERFACE )
{
Reference< XInterface > xIface = *(Reference< XInterface >*)aValue.getValue();
Reference< XIdlClass > xClass( xIface, UNO_QUERY );
if( xClass.is() )
{
pRes = new SbxVariable( SbxVARIANT );
SbxObjectRef xWrapper = (SbxObject*)new SbUnoClass( aNewName, xClass );
pRes->PutObject( xWrapper );
}
}
else
{
pRes = new SbxVariable( SbxVARIANT );
unoToSbxValue( pRes, aValue );
}
}
catch( const NoSuchElementException& )
{
}
}
// Otherwise take it again as class
if( !pRes )
{
SbUnoClass* pNewClass = findUnoClass( aNewName );
if( pNewClass )
{
pRes = new SbxVariable( SbxVARIANT );
SbxObjectRef xWrapper = (SbxObject*)pNewClass;
pRes->PutObject( xWrapper );
}
}
// An UNO service?
if( !pRes )
{
SbUnoService* pUnoService = findUnoService( aNewName );
if( pUnoService )
{
pRes = new SbxVariable( SbxVARIANT );
SbxObjectRef xWrapper = (SbxObject*)pUnoService;
pRes->PutObject( xWrapper );
}
}
// An UNO singleton?
if( !pRes )
{
SbUnoSingleton* pUnoSingleton = findUnoSingleton( aNewName );
if( pUnoSingleton )
{
pRes = new SbxVariable( SbxVARIANT );
SbxObjectRef xWrapper = (SbxObject*)pUnoSingleton;
pRes->PutObject( xWrapper );
}
}
}
}
if( pRes )
{
pRes->SetName( rName );
// Insert variable, so that it could be found later
QuickInsert( pRes );
// Take us out as listener at once,
// the values are all constant
if( pRes->IsBroadcaster() )
EndListening( pRes->GetBroadcaster(), true );
}
}
return pRes;
}
SbUnoService* findUnoService( const OUString& rName )
{
SbUnoService* pSbUnoService = NULL;
Reference< XHierarchicalNameAccess > xTypeAccess = getTypeProvider_Impl();
if( xTypeAccess->hasByHierarchicalName( rName ) )
{
Any aRet = xTypeAccess->getByHierarchicalName( rName );
Reference< XTypeDescription > xTypeDesc;
aRet >>= xTypeDesc;
if( xTypeDesc.is() )
{
TypeClass eTypeClass = xTypeDesc->getTypeClass();
if( eTypeClass == TypeClass_SERVICE )
{
Reference< XServiceTypeDescription2 > xServiceTypeDesc( xTypeDesc, UNO_QUERY );
if( xServiceTypeDesc.is() )
pSbUnoService = new SbUnoService( rName, xServiceTypeDesc );
}
}
}
return pSbUnoService;
}
SbxVariable* SbUnoService::Find( const OUString& rName, SbxClassType )
{
SbxVariable* pRes = SbxObject::Find( rName, SbxCLASS_METHOD );
if( !pRes )
{
// If it is already a class ask for a field
if( m_bNeedsInit && m_xServiceTypeDesc.is() )
{
m_bNeedsInit = false;
Sequence< Reference< XServiceConstructorDescription > > aSCDSeq = m_xServiceTypeDesc->getConstructors();
const Reference< XServiceConstructorDescription >* pCtorSeq = aSCDSeq.getConstArray();
int nCtorCount = aSCDSeq.getLength();
for( int i = 0 ; i < nCtorCount ; ++i )
{
Reference< XServiceConstructorDescription > xCtor = pCtorSeq[i];
OUString aName( xCtor->getName() );
if( aName.isEmpty() )
{
if( xCtor->isDefaultConstructor() )
{
aName = "create";
}
}
if( !aName.isEmpty() )
{
// Create and insert SbUnoServiceCtor
SbxVariableRef xSbCtorRef = new SbUnoServiceCtor( aName, xCtor );
QuickInsert( (SbxVariable*)xSbCtorRef );
}
}
pRes = SbxObject::Find( rName, SbxCLASS_METHOD );
}
}
return pRes;
}
void SbUnoService::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();
SbxArray* pParams = pVar->GetParameters();
SbUnoServiceCtor* pUnoCtor = PTR_CAST(SbUnoServiceCtor,pVar);
if( pUnoCtor && pHint->GetId() == SBX_HINT_DATAWANTED )
{
// Parameter count -1 because of Param0 == this
sal_uInt32 nParamCount = pParams ? ((sal_uInt32)pParams->Count() - 1) : 0;
Sequence<Any> args;
bool bOutParams = false;
Reference< XServiceConstructorDescription > xCtor = pUnoCtor->getServiceCtorDesc();
Sequence< Reference< XParameter > > aParameterSeq = xCtor->getParameters();
const Reference< XParameter >* pParameterSeq = aParameterSeq.getConstArray();
sal_uInt32 nUnoParamCount = aParameterSeq.getLength();
// Default: Ignore not needed parameters
bool bParameterError = false;
// Is the last parameter a rest parameter?
bool bRestParameterMode = false;
if( nUnoParamCount > 0 )
{
Reference< XParameter > xLastParam = pParameterSeq[ nUnoParamCount - 1 ];
if( xLastParam.is() )
{
if( xLastParam->isRestParameter() )
bRestParameterMode = true;
}
}
// Too many parameters with context as first parameter?
sal_uInt16 nSbxParameterOffset = 1;
sal_uInt16 nParameterOffsetByContext = 0;
Reference < XComponentContext > xFirstParamContext;
if( nParamCount > nUnoParamCount )
{
// Check if first parameter is a context and use it
// then in createInstanceWithArgumentsAndContext
Any aArg0 = sbxToUnoValue( pParams->Get( nSbxParameterOffset ) );
if( (aArg0 >>= xFirstParamContext) && xFirstParamContext.is() )
nParameterOffsetByContext = 1;
}
sal_uInt32 nEffectiveParamCount = nParamCount - nParameterOffsetByContext;
sal_uInt32 nAllocParamCount = nEffectiveParamCount;
if( nEffectiveParamCount > nUnoParamCount )
{
if( !bRestParameterMode )
{
nEffectiveParamCount = nUnoParamCount;
nAllocParamCount = nUnoParamCount;
}
}
// Not enough parameters?
else if( nUnoParamCount > nEffectiveParamCount )
{
// RestParameterMode only helps if one (the last) parameter is missing
int nDiff = nUnoParamCount - nEffectiveParamCount;
if( !bRestParameterMode || nDiff > 1 )
{
bParameterError = true;
StarBASIC::Error( SbERR_NOT_OPTIONAL );
}
}
if( !bParameterError )
{
if( nAllocParamCount > 0 )
{
args.realloc( nAllocParamCount );
Any* pAnyArgs = args.getArray();
for( sal_uInt32 i = 0 ; i < nEffectiveParamCount ; i++ )
{
sal_uInt16 iSbx = (sal_uInt16)(i + nSbxParameterOffset + nParameterOffsetByContext);
// bRestParameterMode allows nEffectiveParamCount > nUnoParamCount
Reference< XParameter > xParam;
if( i < nUnoParamCount )
{
xParam = pParameterSeq[i];
if( !xParam.is() )
continue;
Reference< XTypeDescription > xParamTypeDesc = xParam->getType();
if( !xParamTypeDesc.is() )
continue;
com::sun::star::uno::Type aType( xParamTypeDesc->getTypeClass(), xParamTypeDesc->getName() );
// sbx parameter needs offset 1
pAnyArgs[i] = sbxToUnoValue( pParams->Get( iSbx ), aType );
// Check for out parameter if not already done
if( !bOutParams )
{
if( xParam->isOut() )
bOutParams = true;
}
}
else
{
pAnyArgs[i] = sbxToUnoValue( pParams->Get( iSbx ) );
}
}
}
// "Call" ctor using createInstanceWithArgumentsAndContext
Reference < XComponentContext > xContext(
xFirstParamContext.is()
? xFirstParamContext
: comphelper::getProcessComponentContext() );
Reference< XMultiComponentFactory > xServiceMgr( xContext->getServiceManager() );
Any aRetAny;
OUString aServiceName = GetName();
Reference < XInterface > xRet;
try
{
xRet = xServiceMgr->createInstanceWithArgumentsAndContext( aServiceName, args, xContext );
}
catch( const Exception& )
{
implHandleAnyException( ::cppu::getCaughtException() );
}
aRetAny <<= xRet;
unoToSbxValue( pVar, aRetAny );
// Copy back out parameters?
if( bOutParams )
{
const Any* pAnyArgs = args.getConstArray();
for( sal_uInt32 j = 0 ; j < nUnoParamCount ; j++ )
{
Reference< XParameter > xParam = pParameterSeq[j];
if( !xParam.is() )
continue;
if( xParam->isOut() )
unoToSbxValue( (SbxVariable*)pParams->Get( (sal_uInt16)(j+1) ), pAnyArgs[ j ] );
}
}
}
}
else
SbxObject::SFX_NOTIFY( rBC, rBCType, rHint, rHintType );
}
}
static SbUnoServiceCtor* pFirstCtor = NULL;
void clearUnoServiceCtors( void )
{
SbUnoServiceCtor* pCtor = pFirstCtor;
while( pCtor )
{
pCtor->SbxValue::Clear();
pCtor = pCtor->pNext;
}
}
SbUnoServiceCtor::SbUnoServiceCtor( const OUString& aName_, Reference< XServiceConstructorDescription > xServiceCtorDesc )
: SbxMethod( aName_, SbxOBJECT )
, m_xServiceCtorDesc( xServiceCtorDesc )
, pNext(0)
{
}
SbUnoServiceCtor::~SbUnoServiceCtor()
{
}
SbxInfo* SbUnoServiceCtor::GetInfo()
{
SbxInfo* pRet = NULL;
return pRet;
}
SbUnoSingleton* findUnoSingleton( const OUString& rName )
{
SbUnoSingleton* pSbUnoSingleton = NULL;
Reference< XHierarchicalNameAccess > xTypeAccess = getTypeProvider_Impl();
if( xTypeAccess->hasByHierarchicalName( rName ) )
{
Any aRet = xTypeAccess->getByHierarchicalName( rName );
Reference< XTypeDescription > xTypeDesc;
aRet >>= xTypeDesc;
if( xTypeDesc.is() )
{
TypeClass eTypeClass = xTypeDesc->getTypeClass();
if( eTypeClass == TypeClass_SINGLETON )
{
Reference< XSingletonTypeDescription > xSingletonTypeDesc( xTypeDesc, UNO_QUERY );
if( xSingletonTypeDesc.is() )
pSbUnoSingleton = new SbUnoSingleton( rName, xSingletonTypeDesc );
}
}
}
return pSbUnoSingleton;
}
SbUnoSingleton::SbUnoSingleton( const OUString& aName_,
const Reference< XSingletonTypeDescription >& xSingletonTypeDesc )
: SbxObject( aName_ )
, m_xSingletonTypeDesc( xSingletonTypeDesc )
{
SbxVariableRef xGetMethodRef = new SbxMethod( OUString( "get" ), SbxOBJECT );
QuickInsert( (SbxVariable*)xGetMethodRef );
}
void SbUnoSingleton::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();
SbxArray* pParams = pVar->GetParameters();
sal_uInt32 nParamCount = pParams ? ((sal_uInt32)pParams->Count() - 1) : 0;
sal_uInt32 nAllowedParamCount = 1;
Reference < XComponentContext > xContextToUse;
if( nParamCount > 0 )
{
// Check if first parameter is a context and use it then
Reference < XComponentContext > xFirstParamContext;
Any aArg1 = sbxToUnoValue( pParams->Get( 1 ) );
if( (aArg1 >>= xFirstParamContext) && xFirstParamContext.is() )
xContextToUse = xFirstParamContext;
}
if( !xContextToUse.is() )
{
xContextToUse = comphelper::getProcessComponentContext();
--nAllowedParamCount;
}
if( nParamCount > nAllowedParamCount )
{
StarBASIC::Error( SbERR_BAD_ARGUMENT );
return;
}
Any aRetAny;
if( xContextToUse.is() )
{
OUString aSingletonName( "/singletons/" );
aSingletonName += GetName();
Reference < XInterface > xRet;
xContextToUse->getValueByName( aSingletonName ) >>= xRet;
aRetAny <<= xRet;
}
unoToSbxValue( pVar, aRetAny );
}
else
{
SbxObject::SFX_NOTIFY( rBC, rBCType, rHint, rHintType );
}
}
// Implementation of an EventAttacher-drawn AllListener, which
// solely transmits several events to an general AllListener
class BasicAllListener_Impl : public BasicAllListenerHelper
{
virtual void firing_impl(const AllEventObject& Event, Any* pRet);
public:
SbxObjectRef xSbxObj;
OUString aPrefixName;
BasicAllListener_Impl( const OUString& aPrefixName );
virtual ~BasicAllListener_Impl();
// Methods of XAllListener
virtual void SAL_CALL firing(const AllEventObject& Event) throw ( RuntimeException, std::exception ) SAL_OVERRIDE;
virtual Any SAL_CALL approveFiring(const AllEventObject& Event) throw ( RuntimeException, std::exception ) SAL_OVERRIDE;
// Methods of XEventListener
virtual void SAL_CALL disposing(const EventObject& Source) throw ( RuntimeException, std::exception ) SAL_OVERRIDE;
};
BasicAllListener_Impl::BasicAllListener_Impl(const OUString& aPrefixName_)
: aPrefixName( aPrefixName_ )
{
}
BasicAllListener_Impl::~BasicAllListener_Impl()
{
}
void BasicAllListener_Impl::firing_impl( const AllEventObject& Event, Any* pRet )
{
SolarMutexGuard guard;
if( xSbxObj.Is() )
{
OUString aMethodName = aPrefixName;
aMethodName = aMethodName + Event.MethodName;
SbxVariable * pP = xSbxObj;
while( pP->GetParent() )
{
pP = pP->GetParent();
StarBASIC * pLib = PTR_CAST(StarBASIC,pP);
if( pLib )
{
// Create in a Basic Array
SbxArrayRef xSbxArray = new SbxArray( SbxVARIANT );
const Any * pArgs = Event.Arguments.getConstArray();
sal_Int32 nCount = Event.Arguments.getLength();
for( sal_Int32 i = 0; i < nCount; i++ )
{
// Convert elements
SbxVariableRef xVar = new SbxVariable( SbxVARIANT );
unoToSbxValue( (SbxVariable*)xVar, pArgs[i] );
xSbxArray->Put( xVar, sal::static_int_cast< sal_uInt16 >(i+1) );
}
pLib->Call( aMethodName, xSbxArray );
// get the return value from the Param-Array, if requested
if( pRet )
{
SbxVariable* pVar = xSbxArray->Get( 0 );
if( pVar )
{
// #95792 Avoid a second call
sal_uInt16 nFlags = pVar->GetFlags();
pVar->SetFlag( SBX_NO_BROADCAST );
*pRet = sbxToUnoValueImpl( pVar );
pVar->SetFlags( nFlags );
}
}
break;
}
}
}
}
// Methods of Listener
void BasicAllListener_Impl::firing( const AllEventObject& Event ) throw ( RuntimeException, std::exception )
{
firing_impl( Event, NULL );
}
Any BasicAllListener_Impl::approveFiring( const AllEventObject& Event ) throw ( RuntimeException, std::exception )
{
Any aRetAny;
firing_impl( Event, &aRetAny );
return aRetAny;
}
// Methods of XEventListener
void BasicAllListener_Impl ::disposing(const EventObject& ) throw ( RuntimeException, std::exception )
{
SolarMutexGuard guard;
xSbxObj.Clear();
}
// class InvocationToAllListenerMapper
// helper class to map XInvocation to XAllListener (also in project eventattacher!)
class InvocationToAllListenerMapper : public WeakImplHelper1< XInvocation >
{
public:
InvocationToAllListenerMapper( const Reference< XIdlClass >& ListenerType,
const Reference< XAllListener >& AllListener, const Any& Helper );
// XInvocation
virtual Reference< XIntrospectionAccess > SAL_CALL getIntrospection(void) throw( RuntimeException, std::exception ) SAL_OVERRIDE;
virtual Any SAL_CALL invoke(const OUString& FunctionName, const Sequence< Any >& Params, Sequence< sal_Int16 >& OutParamIndex, Sequence< Any >& OutParam)
throw( IllegalArgumentException, CannotConvertException, InvocationTargetException, RuntimeException, std::exception ) SAL_OVERRIDE;
virtual void SAL_CALL setValue(const OUString& PropertyName, const Any& Value)
throw( UnknownPropertyException, CannotConvertException, InvocationTargetException, RuntimeException, std::exception ) SAL_OVERRIDE;
virtual Any SAL_CALL getValue(const OUString& PropertyName) throw( UnknownPropertyException, RuntimeException, std::exception ) SAL_OVERRIDE;
virtual sal_Bool SAL_CALL hasMethod(const OUString& Name) throw( RuntimeException, std::exception ) SAL_OVERRIDE;
virtual sal_Bool SAL_CALL hasProperty(const OUString& Name) throw( RuntimeException, std::exception ) SAL_OVERRIDE;
private:
Reference< XIdlReflection > m_xCoreReflection;
Reference< XAllListener > m_xAllListener;
Reference< XIdlClass > m_xListenerType;
Any m_Helper;
};
// Function to replace AllListenerAdapterService::createAllListerAdapter
Reference< XInterface > createAllListenerAdapter
(
const Reference< XInvocationAdapterFactory2 >& xInvocationAdapterFactory,
const Reference< XIdlClass >& xListenerType,
const Reference< XAllListener >& xListener,
const Any& Helper
)
{
Reference< XInterface > xAdapter;
if( xInvocationAdapterFactory.is() && xListenerType.is() && xListener.is() )
{
Reference< XInvocation > xInvocationToAllListenerMapper =
(XInvocation*)new InvocationToAllListenerMapper( xListenerType, xListener, Helper );
Type aListenerType( xListenerType->getTypeClass(), xListenerType->getName() );
Sequence<Type> arg2(1);
arg2[0] = aListenerType;
xAdapter = xInvocationAdapterFactory->createAdapter( xInvocationToAllListenerMapper, arg2 );
}
return xAdapter;
}
// InvocationToAllListenerMapper
InvocationToAllListenerMapper::InvocationToAllListenerMapper
( const Reference< XIdlClass >& ListenerType, const Reference< XAllListener >& AllListener, const Any& Helper )
: m_xAllListener( AllListener )
, m_xListenerType( ListenerType )
, m_Helper( Helper )
{
}
Reference< XIntrospectionAccess > SAL_CALL InvocationToAllListenerMapper::getIntrospection(void)
throw( RuntimeException, std::exception )
{
return Reference< XIntrospectionAccess >();
}
Any SAL_CALL InvocationToAllListenerMapper::invoke(const OUString& FunctionName, const Sequence< Any >& Params,
Sequence< sal_Int16 >& OutParamIndex, Sequence< Any >& OutParam)
throw( IllegalArgumentException, CannotConvertException,
InvocationTargetException, RuntimeException, std::exception )
{
(void)OutParamIndex;
(void)OutParam ;
Any aRet;
// Check if to firing or approveFiring has to be called
Reference< XIdlMethod > xMethod = m_xListenerType->getMethod( FunctionName );
bool bApproveFiring = false;
if( !xMethod.is() )
return aRet;
Reference< XIdlClass > xReturnType = xMethod->getReturnType();
Sequence< Reference< XIdlClass > > aExceptionSeq = xMethod->getExceptionTypes();
if( ( xReturnType.is() && xReturnType->getTypeClass() != TypeClass_VOID ) ||
aExceptionSeq.getLength() > 0 )
{
bApproveFiring = true;
}
else
{
Sequence< ParamInfo > aParamSeq = xMethod->getParameterInfos();
sal_uInt32 nParamCount = aParamSeq.getLength();
if( nParamCount > 1 )
{
const ParamInfo* pInfos = aParamSeq.getConstArray();
for( sal_uInt32 i = 0 ; i < nParamCount ; i++ )
{
if( pInfos[ i ].aMode != ParamMode_IN )
{
bApproveFiring = true;
break;
}
}
}
}
AllEventObject aAllEvent;
aAllEvent.Source = (OWeakObject*) this;
aAllEvent.Helper = m_Helper;
aAllEvent.ListenerType = Type(m_xListenerType->getTypeClass(), m_xListenerType->getName() );
aAllEvent.MethodName = FunctionName;
aAllEvent.Arguments = Params;
if( bApproveFiring )
aRet = m_xAllListener->approveFiring( aAllEvent );
else
m_xAllListener->firing( aAllEvent );
return aRet;
}
void SAL_CALL InvocationToAllListenerMapper::setValue(const OUString& PropertyName, const Any& Value)
throw( UnknownPropertyException, CannotConvertException,
InvocationTargetException, RuntimeException, std::exception )
{
(void)PropertyName;
(void)Value;
}
Any SAL_CALL InvocationToAllListenerMapper::getValue(const OUString& PropertyName)
throw( UnknownPropertyException, RuntimeException, std::exception )
{
(void)PropertyName;
return Any();
}
sal_Bool SAL_CALL InvocationToAllListenerMapper::hasMethod(const OUString& Name)
throw( RuntimeException, std::exception )
{
Reference< XIdlMethod > xMethod = m_xListenerType->getMethod( Name );
return xMethod.is();
}
sal_Bool SAL_CALL InvocationToAllListenerMapper::hasProperty(const OUString& Name)
throw( RuntimeException, std::exception )
{
Reference< XIdlField > xField = m_xListenerType->getField( Name );
return xField.is();
}
// create Uno-Service
// 1. Parameter == Prefix-Name of the macro
// 2. Parameter == fully qualified name of the listener
void SbRtl_CreateUnoListener( StarBASIC* pBasic, SbxArray& rPar, bool bWrite )
//RTLFUNC(CreateUnoListener)
{
(void)bWrite;
// We need 2 parameters
if ( rPar.Count() != 3 )
{
StarBASIC::Error( SbERR_BAD_ARGUMENT );
return;
}
// get the name of the class of the struct
OUString aPrefixName = rPar.Get(1)->GetOUString();
OUString aListenerClassName = rPar.Get(2)->GetOUString();
// get the CoreReflection
Reference< XIdlReflection > xCoreReflection = getCoreReflection_Impl();
if( !xCoreReflection.is() )
return;
// get the AllListenerAdapterService
Reference< XComponentContext > xContext( comphelper::getProcessComponentContext() );
// search the class
Reference< XIdlClass > xClass = xCoreReflection->forName( aListenerClassName );
if( !xClass.is() )
return;
// From 1999-11-30: get the InvocationAdapterFactory
Reference< XInvocationAdapterFactory2 > xInvocationAdapterFactory =
InvocationAdapterFactory::create( xContext );
BasicAllListener_Impl * p;
Reference< XAllListener > xAllLst = p = new BasicAllListener_Impl( aPrefixName );
Any aTmp;
Reference< XInterface > xLst = createAllListenerAdapter( xInvocationAdapterFactory, xClass, xAllLst, aTmp );
if( !xLst.is() )
return;
OUString aClassName = xClass->getName();
Type aClassType( xClass->getTypeClass(), aClassName.getStr() );
aTmp = xLst->queryInterface( aClassType );
if( !aTmp.hasValue() )
return;
SbUnoObject* pUnoObj = new SbUnoObject( aListenerClassName, aTmp );
p->xSbxObj = pUnoObj;
p->xSbxObj->SetParent( pBasic );
// #100326 Register listener object to set Parent NULL in Dtor
SbxArrayRef xBasicUnoListeners = pBasic->getUnoListeners();
xBasicUnoListeners->Insert( pUnoObj, xBasicUnoListeners->Count() );
// return the object
SbxVariableRef refVar = rPar.Get(0);
refVar->PutObject( p->xSbxObj );
}
// Represents the DefaultContext property of the ProcessServiceManager
// in the Basic runtime system.
void RTL_Impl_GetDefaultContext( StarBASIC* pBasic, SbxArray& rPar, bool bWrite )
{
(void)pBasic;
(void)bWrite;
SbxVariableRef refVar = rPar.Get(0);
Any aContextAny( comphelper::getProcessComponentContext() );
SbUnoObjectRef xUnoObj = new SbUnoObject( OUString( "DefaultContext" ), aContextAny );
refVar->PutObject( (SbUnoObject*)xUnoObj );
}
// Creates a Basic wrapper object for a strongly typed Uno value
// 1. parameter: Uno type as full qualified type name, e.g. "byte[]"
void RTL_Impl_CreateUnoValue( StarBASIC* pBasic, SbxArray& rPar, bool bWrite )
{
(void)pBasic;
(void)bWrite;
static OUString aTypeTypeString( "type" );
// 2 parameters needed
if ( rPar.Count() != 3 )
{
StarBASIC::Error( SbERR_BAD_ARGUMENT );
return;
}
// get the name of the class of the struct
OUString aTypeName = rPar.Get(1)->GetOUString();
SbxVariable* pVal = rPar.Get(2);
if( aTypeName == aTypeTypeString )
{
SbxDataType eBaseType = pVal->SbxValue::GetType();
OUString aValTypeName;
if( eBaseType == SbxSTRING )
{
aValTypeName = pVal->GetOUString();
}
else if( eBaseType == SbxOBJECT )
{
// XIdlClass?
Reference< XIdlClass > xIdlClass;
SbxBaseRef pObj = (SbxBase*)pVal->GetObject();
if( pObj && pObj->ISA(SbUnoObject) )
{
Any aUnoAny = ((SbUnoObject*)(SbxBase*)pObj)->getUnoAny();
aUnoAny >>= xIdlClass;
}
if( xIdlClass.is() )
{
aValTypeName = xIdlClass->getName();
}
}
Type aType;
bool bSuccess = implGetTypeByName( aValTypeName, aType );
if( bSuccess )
{
Any aTypeAny( aType );
SbxVariableRef refVar = rPar.Get(0);
SbxObjectRef xUnoAnyObject = new SbUnoAnyObject( aTypeAny );
refVar->PutObject( xUnoAnyObject );
}
return;
}
// Check the type
Reference< XHierarchicalNameAccess > xTypeAccess = getTypeProvider_Impl();
Any aRet;
try
{
aRet = xTypeAccess->getByHierarchicalName( aTypeName );
}
catch( const NoSuchElementException& e1 )
{
OUString aNoSuchElementExceptionName( "com.sun.star.container.NoSuchElementException" );
StarBASIC::Error( ERRCODE_BASIC_EXCEPTION,
implGetExceptionMsg( e1, aNoSuchElementExceptionName ) );
return;
}
Reference< XTypeDescription > xTypeDesc;
aRet >>= xTypeDesc;
TypeClass eTypeClass = xTypeDesc->getTypeClass();
Type aDestType( eTypeClass, aTypeName );
// Preconvert value
Any aVal = sbxToUnoValueImpl( pVal );
Any aConvertedVal = convertAny( aVal, aDestType );
SbxVariableRef refVar = rPar.Get(0);
SbxObjectRef xUnoAnyObject = new SbUnoAnyObject( aConvertedVal );
refVar->PutObject( xUnoAnyObject );
}
namespace {
class OMutexBasis
{
protected:
// this mutex is necessary for OInterfaceContainerHelper
::osl::Mutex m_aMutex;
};
} // namespace
typedef WeakImplHelper2< XInvocation, XComponent > ModuleInvocationProxyHelper;
class ModuleInvocationProxy : public OMutexBasis,
public ModuleInvocationProxyHelper
{
OUString m_aPrefix;
SbxObjectRef m_xScopeObj;
bool m_bProxyIsClassModuleObject;
::cppu::OInterfaceContainerHelper m_aListeners;
public:
ModuleInvocationProxy( const OUString& aPrefix, SbxObjectRef xScopeObj );
virtual ~ModuleInvocationProxy()
{}
// XInvocation
virtual Reference< XIntrospectionAccess > SAL_CALL getIntrospection() throw(std::exception) SAL_OVERRIDE;
virtual void SAL_CALL setValue( const OUString& rProperty, const Any& rValue )
throw( UnknownPropertyException, std::exception ) SAL_OVERRIDE;
virtual Any SAL_CALL getValue( const OUString& rProperty )
throw( UnknownPropertyException, std::exception ) SAL_OVERRIDE;
virtual sal_Bool SAL_CALL hasMethod( const OUString& rName ) throw(std::exception) SAL_OVERRIDE;
virtual sal_Bool SAL_CALL hasProperty( const OUString& rProp ) throw(std::exception) SAL_OVERRIDE;
virtual Any SAL_CALL invoke( const OUString& rFunction,
const Sequence< Any >& rParams,
Sequence< sal_Int16 >& rOutParamIndex,
Sequence< Any >& rOutParam )
throw( CannotConvertException, InvocationTargetException, std::exception ) SAL_OVERRIDE;
// XComponent
virtual void SAL_CALL dispose() throw(RuntimeException, std::exception) SAL_OVERRIDE;
virtual void SAL_CALL addEventListener( const Reference< XEventListener >& xListener ) throw (RuntimeException, std::exception) SAL_OVERRIDE;
virtual void SAL_CALL removeEventListener( const Reference< XEventListener >& aListener ) throw (RuntimeException, std::exception) SAL_OVERRIDE;
};
ModuleInvocationProxy::ModuleInvocationProxy( const OUString& aPrefix, SbxObjectRef xScopeObj )
: m_aPrefix( aPrefix + OUString( "_" ) )
, m_xScopeObj( xScopeObj )
, m_aListeners( m_aMutex )
{
m_bProxyIsClassModuleObject = xScopeObj.Is() && xScopeObj->ISA(SbClassModuleObject);
}
Reference< XIntrospectionAccess > SAL_CALL ModuleInvocationProxy::getIntrospection() throw(std::exception)
{
return Reference< XIntrospectionAccess >();
}
void SAL_CALL ModuleInvocationProxy::setValue( const OUString& rProperty, const Any& rValue ) throw( UnknownPropertyException, std::exception )
{
if( !m_bProxyIsClassModuleObject )
throw UnknownPropertyException();
SolarMutexGuard guard;
OUString aPropertyFunctionName( "Property Set " );
aPropertyFunctionName += m_aPrefix;
aPropertyFunctionName += rProperty;
SbxVariable* p = m_xScopeObj->Find( aPropertyFunctionName, SbxCLASS_METHOD );
SbMethod* pMeth = p != NULL ? PTR_CAST(SbMethod,p) : NULL;
if( pMeth == NULL )
{
// TODO: Check vba behavior concernig missing function
//StarBASIC::Error( SbERR_NO_METHOD, aFunctionName );
throw UnknownPropertyException();
}
// Setup parameter
SbxArrayRef xArray = new SbxArray;
SbxVariableRef xVar = new SbxVariable( SbxVARIANT );
unoToSbxValue( (SbxVariable*)xVar, rValue );
xArray->Put( xVar, 1 );
// Call property method
SbxVariableRef xValue = new SbxVariable;
pMeth->SetParameters( xArray );
pMeth->Call( xValue );
pMeth->SetParameters( NULL );
// TODO: OutParameter?
}
Any SAL_CALL ModuleInvocationProxy::getValue( const OUString& rProperty ) throw( UnknownPropertyException, std::exception )
{
if( !m_bProxyIsClassModuleObject )
{
throw UnknownPropertyException();
}
SolarMutexGuard guard;
OUString aPropertyFunctionName( "Property Get " );
aPropertyFunctionName += m_aPrefix;
aPropertyFunctionName += rProperty;
SbxVariable* p = m_xScopeObj->Find( aPropertyFunctionName, SbxCLASS_METHOD );
SbMethod* pMeth = p != NULL ? PTR_CAST(SbMethod,p) : NULL;
if( pMeth == NULL )
{
// TODO: Check vba behavior concernig missing function
//StarBASIC::Error( SbERR_NO_METHOD, aFunctionName );
throw UnknownPropertyException();
}
// Call method
SbxVariableRef xValue = new SbxVariable;
pMeth->Call( xValue );
Any aRet = sbxToUnoValue( xValue );
return aRet;
}
sal_Bool SAL_CALL ModuleInvocationProxy::hasMethod( const OUString& ) throw(std::exception)
{
return sal_False;
}
sal_Bool SAL_CALL ModuleInvocationProxy::hasProperty( const OUString& ) throw(std::exception)
{
return sal_False;
}
Any SAL_CALL ModuleInvocationProxy::invoke( const OUString& rFunction,
const Sequence< Any >& rParams,
Sequence< sal_Int16 >&,
Sequence< Any >& )
throw( CannotConvertException, InvocationTargetException, std::exception )
{
SolarMutexGuard guard;
Any aRet;
SbxObjectRef xScopeObj = m_xScopeObj;
if( !xScopeObj.Is() )
{
return aRet;
}
OUString aFunctionName = m_aPrefix;
aFunctionName += rFunction;
bool bSetRescheduleBack = false;
bool bOldReschedule = true;
SbiInstance* pInst = GetSbData()->pInst;
if( pInst && pInst->IsCompatibility() )
{
bOldReschedule = pInst->IsReschedule();
if ( bOldReschedule )
{
pInst->EnableReschedule( false );
bSetRescheduleBack = true;
}
}
SbxVariable* p = xScopeObj->Find( aFunctionName, SbxCLASS_METHOD );
SbMethod* pMeth = p != NULL ? PTR_CAST(SbMethod,p) : NULL;
if( pMeth == NULL )
{
// TODO: Check vba behavior concernig missing function
//StarBASIC::Error( SbERR_NO_METHOD, aFunctionName );
return aRet;
}
// Setup parameters
SbxArrayRef xArray;
sal_Int32 nParamCount = rParams.getLength();
if( nParamCount )
{
xArray = new SbxArray;
const Any *pArgs = rParams.getConstArray();
for( sal_Int32 i = 0 ; i < nParamCount ; i++ )
{
SbxVariableRef xVar = new SbxVariable( SbxVARIANT );
unoToSbxValue( (SbxVariable*)xVar, pArgs[i] );
xArray->Put( xVar, sal::static_int_cast< sal_uInt16 >(i+1) );
}
}
// Call method
SbxVariableRef xValue = new SbxVariable;
if( xArray.Is() )
pMeth->SetParameters( xArray );
pMeth->Call( xValue );
aRet = sbxToUnoValue( xValue );
pMeth->SetParameters( NULL );
if( bSetRescheduleBack )
pInst->EnableReschedule( bOldReschedule );
// TODO: OutParameter?
return aRet;
}
void SAL_CALL ModuleInvocationProxy::dispose()
throw(RuntimeException, std::exception)
{
::osl::MutexGuard aGuard( m_aMutex );
EventObject aEvent( (XComponent*)this );
m_aListeners.disposeAndClear( aEvent );
m_xScopeObj = NULL;
}
void SAL_CALL ModuleInvocationProxy::addEventListener( const Reference< XEventListener >& xListener )
throw (RuntimeException, std::exception)
{
m_aListeners.addInterface( xListener );
}
void SAL_CALL ModuleInvocationProxy::removeEventListener( const Reference< XEventListener >& xListener )
throw (RuntimeException, std::exception)
{
m_aListeners.removeInterface( xListener );
}
Reference< XInterface > createComListener( const Any& aControlAny, const OUString& aVBAType,
const OUString& aPrefix, SbxObjectRef xScopeObj )
{
Reference< XInterface > xRet;
Reference< XComponentContext > xContext(
comphelper::getProcessComponentContext() );
Reference< XMultiComponentFactory > xServiceMgr( xContext->getServiceManager() );
Reference< XInvocation > xProxy = new ModuleInvocationProxy( aPrefix, xScopeObj );
Sequence<Any> args( 3 );
args[0] <<= aControlAny;
args[1] <<= aVBAType;
args[2] <<= xProxy;
try
{
xRet = xServiceMgr->createInstanceWithArgumentsAndContext(
OUString( "com.sun.star.custom.UnoComListener"),
args, xContext );
}
catch( const Exception& )
{
implHandleAnyException( ::cppu::getCaughtException() );
}
return xRet;
}
typedef std::vector< WeakReference< XComponent > > ComponentRefVector;
struct StarBasicDisposeItem
{
StarBASIC* m_pBasic;
SbxArrayRef m_pRegisteredVariables;
ComponentRefVector m_vComImplementsObjects;
StarBasicDisposeItem( StarBASIC* pBasic )
: m_pBasic( pBasic )
{
m_pRegisteredVariables = new SbxArray();
}
};
typedef std::vector< StarBasicDisposeItem* > DisposeItemVector;
static DisposeItemVector GaDisposeItemVector;
static DisposeItemVector::iterator lcl_findItemForBasic( StarBASIC* pBasic )
{
DisposeItemVector::iterator it;
for( it = GaDisposeItemVector.begin() ; it != GaDisposeItemVector.end() ; ++it )
{
StarBasicDisposeItem* pItem = *it;
if( pItem->m_pBasic == pBasic )
return it;
}
return GaDisposeItemVector.end();
}
static StarBasicDisposeItem* lcl_getOrCreateItemForBasic( StarBASIC* pBasic )
{
DisposeItemVector::iterator it = lcl_findItemForBasic( pBasic );
StarBasicDisposeItem* pItem = (it != GaDisposeItemVector.end()) ? *it : NULL;
if( pItem == NULL )
{
pItem = new StarBasicDisposeItem( pBasic );
GaDisposeItemVector.push_back( pItem );
}
return pItem;
}
void registerComponentToBeDisposedForBasic
( Reference< XComponent > xComponent, StarBASIC* pBasic )
{
StarBasicDisposeItem* pItem = lcl_getOrCreateItemForBasic( pBasic );
pItem->m_vComImplementsObjects.push_back( xComponent );
}
void registerComListenerVariableForBasic( SbxVariable* pVar, StarBASIC* pBasic )
{
StarBasicDisposeItem* pItem = lcl_getOrCreateItemForBasic( pBasic );
SbxArray* pArray = pItem->m_pRegisteredVariables;
pArray->Put( pVar, pArray->Count() );
}
void disposeComVariablesForBasic( StarBASIC* pBasic )
{
DisposeItemVector::iterator it = lcl_findItemForBasic( pBasic );
if( it != GaDisposeItemVector.end() )
{
StarBasicDisposeItem* pItem = *it;
SbxArray* pArray = pItem->m_pRegisteredVariables;
sal_uInt16 nCount = pArray->Count();
for( sal_uInt16 i = 0 ; i < nCount ; ++i )
{
SbxVariable* pVar = pArray->Get( i );
pVar->ClearComListener();
}
ComponentRefVector& rv = pItem->m_vComImplementsObjects;
ComponentRefVector::iterator itCRV;
for( itCRV = rv.begin() ; itCRV != rv.end() ; ++itCRV )
{
try
{
Reference< XComponent > xComponent( (*itCRV).get(), UNO_QUERY_THROW );
xComponent->dispose();
}
catch(const Exception& )
{}
}
delete pItem;
GaDisposeItemVector.erase( it );
}
}
// Handle module implements mechanism for OLE types
bool SbModule::createCOMWrapperForIface( Any& o_rRetAny, SbClassModuleObject* pProxyClassModuleObject )
{
// For now: Take first interface that allows to instantiate COM wrapper
// TODO: Check if support for multiple interfaces is needed
Reference< XComponentContext > xContext(
comphelper::getProcessComponentContext() );
Reference< XMultiComponentFactory > xServiceMgr( xContext->getServiceManager() );
Reference< XSingleServiceFactory > xComImplementsFactory
(
xServiceMgr->createInstanceWithContext(
OUString( "com.sun.star.custom.ComImplementsFactory"), xContext ),
UNO_QUERY
);
if( !xComImplementsFactory.is() )
return false;
bool bSuccess = false;
SbxArray* pModIfaces = pClassData->mxIfaces;
sal_uInt16 nCount = pModIfaces->Count();
for( sal_uInt16 i = 0 ; i < nCount ; ++i )
{
SbxVariable* pVar = pModIfaces->Get( i );
OUString aIfaceName = pVar->GetName();
if( !aIfaceName.isEmpty() )
{
OUString aPureIfaceName = aIfaceName;
sal_Int32 indexLastDot = aIfaceName.lastIndexOf('.');
if ( indexLastDot > -1 )
{
aPureIfaceName = aIfaceName.copy( indexLastDot + 1 );
}
Reference< XInvocation > xProxy = new ModuleInvocationProxy( aPureIfaceName, pProxyClassModuleObject );
Sequence<Any> args( 2 );
args[0] <<= aIfaceName;
args[1] <<= xProxy;
Reference< XInterface > xRet;
bSuccess = false;
try
{
xRet = xComImplementsFactory->createInstanceWithArguments( args );
bSuccess = true;
}
catch( const Exception& )
{
implHandleAnyException( ::cppu::getCaughtException() );
}
if( bSuccess )
{
Reference< XComponent > xComponent( xProxy, UNO_QUERY );
if( xComponent.is() )
{
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 );
}
o_rRetAny <<= xRet;
break;
}
}
}
return bSuccess;
}
// Due to an incorrect behavior IE returns an object instead of a string
// in some scenarios. Calling toString at the object may correct this.
// Helper function used in sbxvalue.cxx
bool handleToStringForCOMObjects( SbxObject* pObj, SbxValue* pVal )
{
bool bSuccess = false;
SbUnoObject* pUnoObj = NULL;
if( pObj != NULL && (pUnoObj = PTR_CAST(SbUnoObject,(SbxObject*)pObj)) != NULL )
{
// Only for native COM objects
if( pUnoObj->isNativeCOMObject() )
{
SbxVariableRef pMeth = pObj->Find( OUString( "toString" ), SbxCLASS_METHOD );
if ( pMeth.Is() )
{
SbxValues aRes;
pMeth->Get( aRes );
pVal->Put( aRes );
bSuccess = true;
}
}
}
return bSuccess;
}
Any StructRefInfo::getValue()
{
Any aRet;
uno_any_destruct(
&aRet, reinterpret_cast< uno_ReleaseFunc >(cpp_release) );
uno_any_construct(
&aRet, getInst(), mpTD,
reinterpret_cast< uno_AcquireFunc >(cpp_acquire) );
return aRet;
}
void StructRefInfo::setValue( const Any& rValue )
{
uno_type_assignData( getInst(),
mpTD->pWeakRef,
(void*)rValue.getValue(),
rValue.getValueTypeRef(),
reinterpret_cast< uno_QueryInterfaceFunc >(cpp_queryInterface),
reinterpret_cast< uno_AcquireFunc >(cpp_acquire),
reinterpret_cast< uno_ReleaseFunc >(cpp_release) );
}
OUString StructRefInfo::getTypeName() const
{
OUString sTypeName;
if ( mpTD )
{
sTypeName = mpTD->pTypeName;
}
return sTypeName;
}
void* StructRefInfo::getInst()
{
return ((char*)maAny.getValue() + mnPos );
}
TypeClass StructRefInfo::getTypeClass() const
{
TypeClass t = TypeClass_VOID;
if ( mpTD )
t = (TypeClass)mpTD->eTypeClass;
return t;
}
SbUnoStructRefObject::SbUnoStructRefObject( const OUString& aName_, const StructRefInfo& rMemberInfo ) : SbxObject( aName_ ), maMemberInfo( rMemberInfo ), mbMemberCacheInit( false )
{
SetClassName( OUString( maMemberInfo.getTypeName() ) );
}
SbUnoStructRefObject::~SbUnoStructRefObject()
{
for ( StructFieldInfo::iterator it = maFields.begin(), it_end = maFields.end(); it != it_end; ++it )
delete it->second;
}
void SbUnoStructRefObject::initMemberCache()
{
if ( mbMemberCacheInit )
return;
sal_Int32 nAll = 0;
typelib_TypeDescription * pTD = maMemberInfo.getTD();
typelib_CompoundTypeDescription * pCompTypeDescr = (typelib_CompoundTypeDescription *)pTD;
for ( ; pCompTypeDescr; pCompTypeDescr = pCompTypeDescr->pBaseTypeDescription )
nAll += pCompTypeDescr->nMembers;
for ( pCompTypeDescr = (typelib_CompoundTypeDescription *)pTD; pCompTypeDescr;
pCompTypeDescr = pCompTypeDescr->pBaseTypeDescription )
{
typelib_TypeDescriptionReference ** ppTypeRefs = pCompTypeDescr->ppTypeRefs;
rtl_uString ** ppNames = pCompTypeDescr->ppMemberNames;
sal_Int32 * pMemberOffsets = pCompTypeDescr->pMemberOffsets;
for ( sal_Int32 nPos = pCompTypeDescr->nMembers; nPos--; )
{
typelib_TypeDescription * pMemberTD = 0;
TYPELIB_DANGER_GET( &pMemberTD, ppTypeRefs[nPos] );
OSL_ENSURE( pMemberTD, "### cannot get field in struct!" );
if (pMemberTD)
{
OUString aName( ppNames[nPos] );
TYPELIB_DANGER_RELEASE( pMemberTD );
maFields[ aName ] = new StructRefInfo( maMemberInfo.getRootAnyRef(), pMemberTD, maMemberInfo.getPos() + pMemberOffsets[nPos] );
}
}
}
mbMemberCacheInit = true;
}
SbxVariable* SbUnoStructRefObject::Find( const OUString& rName, SbxClassType t )
{
SbxVariable* pRes = SbxObject::Find( rName, t );
if ( !pRes )
{
if ( !mbMemberCacheInit )
initMemberCache();
StructFieldInfo::iterator it = maFields.find( OUString( rName ).toAsciiUpperCase() );
if ( it != maFields.end() )
{
SbxDataType eSbxType;
eSbxType = unoToSbxType( it->second->getTypeClass() );
SbxDataType eRealSbxType = eSbxType;
Property aProp;
aProp.Name = rName;
aProp.Type = com::sun::star::uno::Type( it->second->getTypeClass(), it->second->getTypeName() );
SbUnoProperty* pProp = new SbUnoProperty( rName, eSbxType, eRealSbxType, aProp, 0, false, ( aProp.Type.getTypeClass() == com::sun::star::uno::TypeClass_STRUCT) );
SbxVariableRef xVarRef = pProp;
QuickInsert( (SbxVariable*)xVarRef );
pRes = xVarRef;
}
}
if( !pRes )
{
if( rName.equalsIgnoreAsciiCase(ID_DBG_SUPPORTEDINTERFACES) ||
rName.equalsIgnoreAsciiCase(ID_DBG_PROPERTIES) ||
rName.equalsIgnoreAsciiCase(ID_DBG_METHODS) )
{
// Create
implCreateDbgProperties();
// Now they have to be found regular
pRes = SbxObject::Find( rName, SbxCLASS_DONTCARE );
}
}
return pRes;
}
// help method to create the dbg_-Properties
void SbUnoStructRefObject::implCreateDbgProperties( void )
{
Property aProp;
// Id == -1: display the implemented interfaces corresponding the ClassProvider
SbxVariableRef xVarRef = new SbUnoProperty( OUString(ID_DBG_SUPPORTEDINTERFACES), SbxSTRING, SbxSTRING, aProp, -1, false, false );
QuickInsert( (SbxVariable*)xVarRef );
// Id == -2: output the properties
xVarRef = new SbUnoProperty( OUString(ID_DBG_PROPERTIES), SbxSTRING, SbxSTRING, aProp, -2, false, false );
QuickInsert( (SbxVariable*)xVarRef );
// Id == -3: output the Methods
xVarRef = new SbUnoProperty( OUString(ID_DBG_METHODS), SbxSTRING, SbxSTRING, aProp, -3, false, false );
QuickInsert( (SbxVariable*)xVarRef );
}
void SbUnoStructRefObject::implCreateAll()
{
// throw away all existing methods and properties
pMethods = new SbxArray;
pProps = new SbxArray;
if (!mbMemberCacheInit)
initMemberCache();
for ( StructFieldInfo::iterator it = maFields.begin(), it_end = maFields.end(); it != it_end; ++it )
{
const OUString& rName = it->first;
SbxDataType eSbxType;
eSbxType = unoToSbxType( it->second->getTypeClass() );
SbxDataType eRealSbxType = eSbxType;
Property aProp;
aProp.Name = rName;
aProp.Type = com::sun::star::uno::Type( it->second->getTypeClass(), it->second->getTypeName() );
SbUnoProperty* pProp = new SbUnoProperty( rName, eSbxType, eRealSbxType, aProp, 0, false, ( aProp.Type.getTypeClass() == com::sun::star::uno::TypeClass_STRUCT) );
SbxVariableRef xVarRef = pProp;
QuickInsert( (SbxVariable*)xVarRef );
}
// Create Dbg_-Properties
implCreateDbgProperties();
}
// output the value
Any SbUnoStructRefObject::getUnoAny( void )
{
return maMemberInfo.getValue();
}
OUString SbUnoStructRefObject::Impl_DumpProperties()
{
OUStringBuffer aRet;
aRet.appendAscii("Properties of object ");
aRet.append( getDbgObjectName() );
sal_uInt16 nPropCount = pProps->Count();
sal_uInt16 nPropsPerLine = 1 + nPropCount / 30;
for( sal_uInt16 i = 0; i < nPropCount; i++ )
{
SbxVariable* pVar = pProps->Get( i );
if( pVar )
{
OUStringBuffer aPropStr;
if( (i % nPropsPerLine) == 0 )
{
aPropStr.appendAscii( "\n" );
}
// output the type and name
// Is it in Uno a sequence?
SbxDataType eType = pVar->GetFullType();
bool bMaybeVoid = false;
OUString aName( pVar->GetName() );
StructFieldInfo::iterator it = maFields.find( aName );
if ( it != maFields.end() )
{
const StructRefInfo& rPropInfo = *it->second;
if( eType == SbxOBJECT )
{
if( rPropInfo.getTypeClass() == TypeClass_SEQUENCE )
{
eType = (SbxDataType) ( SbxOBJECT | SbxARRAY );
}
}
}
aPropStr.append( Dbg_SbxDataType2String( eType ) );
if( bMaybeVoid )
{
aPropStr.appendAscii( "/void" );
}
aPropStr.appendAscii( " " );
aPropStr.append( pVar->GetName() );
if( i == nPropCount - 1 )
{
aPropStr.appendAscii( "\n" );
}
else
{
aPropStr.appendAscii( "; " );
}
aRet.append( aPropStr.makeStringAndClear() );
}
}
return aRet.makeStringAndClear();
}
void SbUnoStructRefObject::SFX_NOTIFY( SfxBroadcaster& rBC, const TypeId& rBCType,
const SfxHint& rHint, const TypeId& rHintType )
{
if ( !mbMemberCacheInit )
initMemberCache();
const SbxHint* pHint = PTR_CAST(SbxHint,&rHint);
if( pHint )
{
SbxVariable* pVar = pHint->GetVar();
SbUnoProperty* pProp = PTR_CAST(SbUnoProperty,pVar);
if( pProp )
{
StructFieldInfo::iterator it = maFields.find( pProp->GetName() );
// handle get/set of members of struct
if( pHint->GetId() == SBX_HINT_DATAWANTED )
{
// Test-Properties
sal_Int32 nId = pProp->nId;
if( nId < 0 )
{
// Id == -1: Display implemented interfaces according the ClassProvider
if( nId == -1 ) // Property ID_DBG_SUPPORTEDINTERFACES"
{
OUStringBuffer aRet;
aRet.appendAscii( ID_DBG_SUPPORTEDINTERFACES );
aRet.appendAscii( " not available.\n(TypeClass is not TypeClass_INTERFACE)\n" );
pVar->PutString( aRet.makeStringAndClear() );
}
// Id == -2: output properties
else if( nId == -2 ) // Property ID_DBG_PROPERTIES
{
// by now all properties must be established
implCreateAll();
OUString aRetStr = Impl_DumpProperties();
pVar->PutString( aRetStr );
}
// Id == -3: output the methods
else if( nId == -3 ) // Property ID_DBG_METHODS
{
// by now all properties must be established
implCreateAll();
OUStringBuffer aRet;
aRet.appendAscii("Methods of object ");
aRet.append( getDbgObjectName() );
aRet.appendAscii( "\nNo methods found\n" );
pVar->PutString( aRet.makeStringAndClear() );
}
return;
}
if ( it != maFields.end() )
{
Any aRetAny = it->second->getValue();
unoToSbxValue( pVar, aRetAny );
}
else
StarBASIC::Error( SbERR_PROPERTY_NOT_FOUND );
}
else if( pHint->GetId() == SBX_HINT_DATACHANGED )
{
if ( it != maFields.end() )
{
// take over the value from Uno to Sbx
Any aAnyValue = sbxToUnoValue( pVar, pProp->aUnoProp.Type, &pProp->aUnoProp );
it->second->setValue( aAnyValue );
}
else
StarBASIC::Error( SbERR_PROPERTY_NOT_FOUND );
}
}
else
SbxObject::SFX_NOTIFY( rBC, rBCType, rHint, rHintType );
}
}
StructRefInfo SbUnoStructRefObject::getStructMember( const OUString& rMemberName )
{
if (!mbMemberCacheInit)
{
initMemberCache();
}
StructFieldInfo::iterator it = maFields.find( rMemberName );
typelib_TypeDescription * pFoundTD = NULL;
sal_Int32 nFoundPos = -1;
if ( it != maFields.end() )
{
pFoundTD = it->second->getTD();
nFoundPos = it->second->getPos();
}
StructRefInfo aRet( maMemberInfo.getRootAnyRef(), pFoundTD, nFoundPos );
return aRet;
}
OUString SbUnoStructRefObject::getDbgObjectName()
{
OUString aName = GetClassName();
if( aName.isEmpty() )
{
aName += "Unknown";
}
OUStringBuffer aRet;
if( aName.getLength() > 20 )
{
aRet.appendAscii( "\n" );
}
aRet.appendAscii( "\"" );
aRet.append( aName );
aRet.appendAscii( "\":" );
return aRet.makeStringAndClear();
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */