To mitigate the dangers of silently breaking ADL when moving enums into unnamed
namespaces (see the commit message of 206b5b2661
"New loplugin:external"), note all functions that are affected. (The plan is to
extend loplugin:external further to also warn about classes and class templates,
and the code to identify affected functions already takes that into account, so
some parts of that code are not actually relevant for enums.)
But it appears that none of the functions that are actually affected by the
changes in this commit relied on being found through ADL, so no adaptions were
necessary for them.
(clang::DeclContext::collectAllContexts is non-const, which recursively means
that External's Visit... functions must take non-const Decl*. Which required
compilerplugins/clang/sharedvisitor/analyzer.cxx to be generalized to support
such Visit... functions with non-const Decl* parameters.)
Change-Id: Ia215291402bf850d43defdab3cff4db5b270d1bd
Reviewed-on: https://gerrit.libreoffice.org/83001
Tested-by: Jenkins
Reviewed-by: Stephan Bergmann <sbergman@redhat.com>
4919 lines
167 KiB
C++
4919 lines
167 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 <sal/config.h>
|
|
|
|
#include <o3tl/any.hxx>
|
|
#include <osl/mutex.hxx>
|
|
#include <vcl/svapp.hxx>
|
|
#include <vcl/errcode.hxx>
|
|
#include <svl/hint.hxx>
|
|
|
|
#include <cppuhelper/implbase.hxx>
|
|
#include <cppuhelper/exc_hlp.hxx>
|
|
#include <comphelper/interfacecontainer2.hxx>
|
|
#include <comphelper/extract.hxx>
|
|
#include <comphelper/processfactory.hxx>
|
|
#include <cppuhelper/weakref.hxx>
|
|
|
|
#include <rtl/instance.hxx>
|
|
#include <rtl/ustrbuf.hxx>
|
|
|
|
#include <com/sun/star/script/ArrayWrapper.hpp>
|
|
#include <com/sun/star/script/CannotConvertException.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/Converter.hpp>
|
|
#include <com/sun/star/script/XDefaultProperty.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/XSingletonTypeDescription.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 <rtlproto.hxx>
|
|
|
|
#include <basic/sbstar.hxx>
|
|
#include <basic/sbuno.hxx>
|
|
#include <basic/sberrors.hxx>
|
|
#include <sbunoobj.hxx>
|
|
#include <sbintern.hxx>
|
|
#include <runtime.hxx>
|
|
|
|
#include <algorithm>
|
|
#include <math.h>
|
|
#include <memory>
|
|
#include <unordered_map>
|
|
#include <com/sun/star/reflection/XTypeDescriptionEnumerationAccess.hpp>
|
|
#include <com/sun/star/reflection/XConstantsTypeDescription.hpp>
|
|
|
|
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;
|
|
|
|
|
|
// 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[] = "[]";
|
|
|
|
// Gets the default property for a uno object. Note: There is some
|
|
// redirection built in. The property name specifies the name
|
|
// of the default property.
|
|
|
|
bool SbUnoObject::getDefaultPropName( SbUnoObject const * pUnoObj, OUString& sDfltProp )
|
|
{
|
|
bool bResult = false;
|
|
Reference< XDefaultProperty> xDefaultProp( pUnoObj->maTmpUnoObj, UNO_QUERY );
|
|
if ( xDefaultProp.is() )
|
|
{
|
|
sDfltProp = xDefaultProp->getDefaultPropertyName();
|
|
if ( !sDfltProp.isEmpty() )
|
|
bResult = true;
|
|
}
|
|
return bResult;
|
|
}
|
|
|
|
SbxVariable* getDefaultProp( SbxVariable* pRef )
|
|
{
|
|
SbxVariable* pDefaultProp = nullptr;
|
|
if ( pRef->GetType() == SbxOBJECT )
|
|
{
|
|
SbxObject* pObj = dynamic_cast<SbxObject*>(pRef);
|
|
if (!pObj)
|
|
{
|
|
SbxBase* pObjVarObj = pRef->GetObject();
|
|
pObj = dynamic_cast<SbxObject*>( pObjVarObj );
|
|
}
|
|
if (SbUnoObject* pUnoObj = dynamic_cast<SbUnoObject*>(pObj))
|
|
{
|
|
pDefaultProp = pUnoObj->GetDfltProperty();
|
|
}
|
|
}
|
|
return pDefaultProp;
|
|
}
|
|
|
|
void SetSbUnoObjectDfltPropName( SbxObject* pObj )
|
|
{
|
|
SbUnoObject* pUnoObj = dynamic_cast<SbUnoObject*>( pObj );
|
|
if ( pUnoObj )
|
|
{
|
|
OUString sDfltPropName;
|
|
|
|
if ( SbUnoObject::getDefaultPropName( pUnoObj, sDfltPropName ) )
|
|
{
|
|
pUnoObj->SetDfltProperty( sDfltPropName );
|
|
}
|
|
}
|
|
}
|
|
|
|
// save CoreReflection statically
|
|
static Reference< XIdlReflection > getCoreReflection_Impl()
|
|
{
|
|
return css::reflection::theCoreReflection::get(
|
|
comphelper::getProcessComponentContext());
|
|
}
|
|
|
|
// save CoreReflection statically
|
|
static Reference< XHierarchicalNameAccess > const & getCoreReflection_HierarchicalNameAccess_Impl()
|
|
{
|
|
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
|
|
static Reference< XHierarchicalNameAccess > const & getTypeProvider_Impl()
|
|
{
|
|
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(
|
|
"/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
|
|
static Reference< XTypeConverter > const & getTypeConverter_Impl()
|
|
{
|
|
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.set(
|
|
xSMgr->createInstanceWithContext( "com.sun.star.bridge.OleObjectFactory", xContext ),
|
|
UNO_QUERY );
|
|
}
|
|
}
|
|
|
|
SbUnoObject* pUnoObj = nullptr;
|
|
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() )
|
|
{
|
|
pUnoObj = new SbUnoObject( aType, Any(xOLEObject) );
|
|
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.append( " " );
|
|
}
|
|
}
|
|
}
|
|
|
|
static void implAppendExceptionMsg( OUStringBuffer& _inout_rBuffer, const Exception& _e, const OUString& _rExceptionType, sal_Int32 _nLevel )
|
|
{
|
|
_inout_rBuffer.append( "\n" );
|
|
lcl_indent( _inout_rBuffer, _nLevel );
|
|
_inout_rBuffer.append( "Type: " );
|
|
|
|
if ( _rExceptionType.isEmpty() )
|
|
_inout_rBuffer.append( "Unknown" );
|
|
else
|
|
_inout_rBuffer.append( _rExceptionType );
|
|
|
|
_inout_rBuffer.append( "\n" );
|
|
lcl_indent( _inout_rBuffer, _nLevel );
|
|
_inout_rBuffer.append( "Message: " );
|
|
_inout_rBuffer.append( _e.Message );
|
|
|
|
}
|
|
|
|
// construct an error message for the exception
|
|
static OUString implGetExceptionMsg( const Exception& e, const OUString& aExceptionType_ )
|
|
{
|
|
OUStringBuffer aMessageBuf;
|
|
implAppendExceptionMsg( aMessageBuf, e, aExceptionType_, 0 );
|
|
return aMessageBuf.makeStringAndClear();
|
|
}
|
|
|
|
static OUString implGetExceptionMsg( const Any& _rCaughtException )
|
|
{
|
|
auto e = o3tl::tryAccess<Exception>(_rCaughtException);
|
|
OSL_PRECOND( e, "implGetExceptionMsg: illegal argument!" );
|
|
if ( !e )
|
|
{
|
|
return OUString();
|
|
}
|
|
return implGetExceptionMsg( *e, _rCaughtException.getValueTypeName() );
|
|
}
|
|
|
|
static Any convertAny( const Any& rVal, const Type& aDestType )
|
|
{
|
|
Any aConvertedVal;
|
|
const 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 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_EXCEPTION,
|
|
implGetExceptionMsg( e2, "com.sun.star.lang.IllegalArgumentException" ) );
|
|
return aConvertedVal;
|
|
}
|
|
return aConvertedVal;
|
|
}
|
|
|
|
|
|
// #105565 Special Object to wrap a strongly typed Uno Any
|
|
|
|
|
|
// TODO: source out later
|
|
static Reference<XIdlClass> TypeToIdlClass( const Type& rType )
|
|
{
|
|
return getCoreReflection_Impl()->forName(rType.getTypeName());
|
|
}
|
|
|
|
// Exception type unknown
|
|
template< class EXCEPTION >
|
|
static OUString implGetExceptionMsg( const EXCEPTION& e )
|
|
{
|
|
return implGetExceptionMsg( e, cppu::UnoType<decltype(e)>::get().getTypeName() );
|
|
}
|
|
|
|
static void implHandleBasicErrorException( BasicErrorException const & e )
|
|
{
|
|
ErrCode nError = StarBASIC::GetSfxFromVBError( static_cast<sal_uInt16>(e.ErrorCode) );
|
|
StarBASIC::Error( nError, e.ErrorMessageArgument );
|
|
}
|
|
|
|
static 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;
|
|
|
|
ErrCode 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( static_cast<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.append( "\nTargetException:" );
|
|
|
|
// next round
|
|
aExamine = aWrapped.TargetException;
|
|
++nLevel;
|
|
}
|
|
|
|
if ( auto e = o3tl::tryAccess<Exception>(aExamine) )
|
|
{
|
|
// the last element in the chain is still an exception, but no WrappedTargetException
|
|
implAppendExceptionMsg( aMessageBuf, *e, 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;
|
|
|
|
explicit ObjectItem( SbxObject* pNativeObj )
|
|
: m_xNativeObj( pNativeObj )
|
|
{}
|
|
};
|
|
|
|
typedef std::vector< ObjectItem > NativeObjectWrapperVector;
|
|
class GaNativeObjectWrapperVector : public rtl::Static<NativeObjectWrapperVector, GaNativeObjectWrapperVector> {};
|
|
|
|
void clearNativeObjectWrapperVector()
|
|
{
|
|
GaNativeObjectWrapperVector::get().clear();
|
|
}
|
|
|
|
static sal_uInt32 lcl_registerNativeObjectWrapper( SbxObject* pNativeObj )
|
|
{
|
|
NativeObjectWrapperVector &rNativeObjectWrapperVector = GaNativeObjectWrapperVector::get();
|
|
sal_uInt32 nIndex = rNativeObjectWrapperVector.size();
|
|
rNativeObjectWrapperVector.emplace_back( 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.get();
|
|
}
|
|
|
|
// convert from Uno to Sbx
|
|
static 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;
|
|
}
|
|
|
|
static 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 const * pType )
|
|
{
|
|
const 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 = nullptr;
|
|
aType.getDescription( &pTD );
|
|
Type aElementType( reinterpret_cast<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, static_cast<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.hasElements() )
|
|
{
|
|
// 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( ERRCODE_BASIC_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 )
|
|
{
|
|
auto xVar = tools::make_ref<SbxVariable>( eSbxElementType );
|
|
unoToSbxValue( xVar.get(), aValue );
|
|
|
|
sal_Int32* pIndices = indices.getArray();
|
|
pArray->Put32( xVar.get(), pIndices );
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
void unoToSbxValue( SbxVariable* pVar, const Any& aValue )
|
|
{
|
|
const 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
|
|
SbUnoObject* pSbUnoObject = new SbUnoObject( OUString(), aClassAny );
|
|
SbxObjectRef xWrapper = static_cast<SbxObject*>(pSbUnoObject);
|
|
|
|
// If the object is invalid deliver null
|
|
if( !pSbUnoObject->getUnoAny().hasValue() )
|
|
{
|
|
pVar->PutObject( nullptr );
|
|
}
|
|
else
|
|
{
|
|
pVar->PutObject( xWrapper.get() );
|
|
}
|
|
}
|
|
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 = nullptr;
|
|
Sequence< sal_Int32 > indices;
|
|
Sequence< sal_Int32 > sizes;
|
|
implSequenceToMultiDimArray( pArray, indices, sizes, aWrap.Array, /*dimension*/0, aWrap.IsZeroIndex, nullptr );
|
|
if ( pArray )
|
|
{
|
|
SbxDimArrayRef xArray = pArray;
|
|
SbxFlagBits nFlags = pVar->GetFlags();
|
|
pVar->ResetFlag( SbxFlagBits::Fixed );
|
|
pVar->PutObject( xArray.get() );
|
|
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
|
|
SbUnoObject* pSbUnoObject = new SbUnoObject( OUString(), 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 = static_cast<SbxObject*>(pSbUnoObject);
|
|
|
|
// If the object is invalid deliver null
|
|
if( !pSbUnoObject->getUnoAny().hasValue() )
|
|
{
|
|
pVar->PutObject( nullptr );
|
|
}
|
|
else
|
|
{
|
|
pVar->PutObject( xWrapper.get() );
|
|
}
|
|
}
|
|
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 = nullptr;
|
|
aType.getDescription( &pTD );
|
|
OSL_ASSERT( pTD && pTD->eTypeClass == typelib_TypeClass_SEQUENCE );
|
|
Type aElementType( reinterpret_cast<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, static_cast<sal_uInt32>(i) );
|
|
auto xVar = tools::make_ref<SbxVariable>( eSbxElementType );
|
|
unoToSbxValue( xVar.get(), aElementAny );
|
|
|
|
// put into the Array
|
|
xArray->Put32( xVar.get(), &i );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
xArray->unoAddDim( 0, -1 );
|
|
}
|
|
|
|
// return the Array
|
|
SbxFlagBits nFlags = pVar->GetFlags();
|
|
pVar->ResetFlag( SbxFlagBits::Fixed );
|
|
pVar->PutObject( xArray.get() );
|
|
pVar->SetFlags( nFlags );
|
|
|
|
}
|
|
break;
|
|
|
|
|
|
case TypeClass_BOOLEAN: pVar->PutBool( *o3tl::forceAccess<bool>(aValue) ); break;
|
|
case TypeClass_CHAR:
|
|
{
|
|
pVar->PutChar( *o3tl::forceAccess<sal_Unicode>(aValue) );
|
|
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
|
|
static Type getUnoTypeForSbxBaseType( SbxDataType eType )
|
|
{
|
|
Type aRetType = cppu::UnoType<void>::get();
|
|
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
|
|
static Type getUnoTypeForSbxValue( const SbxValue* pVal )
|
|
{
|
|
Type aRetType = cppu::UnoType<void>::get();
|
|
if( !pVal )
|
|
return aRetType;
|
|
|
|
// convert SbxType to Uno
|
|
SbxDataType eBaseType = pVal->SbxValue::GetType();
|
|
if( eBaseType == SbxOBJECT )
|
|
{
|
|
SbxBaseRef xObj = pVal->GetObject();
|
|
if( !xObj.is() )
|
|
{
|
|
aRetType = cppu::UnoType<XInterface>::get();
|
|
return aRetType;
|
|
}
|
|
|
|
if( auto pArray = dynamic_cast<SbxDimArray*>( xObj.get() ) )
|
|
{
|
|
short nDims = pArray->GetDims();
|
|
Type aElementType = getUnoTypeForSbxBaseType( static_cast<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;
|
|
|
|
for (sal_Int32 aIdx[1] = { nLower }; aIdx[0] <= nUpper; ++aIdx[0])
|
|
{
|
|
SbxVariableRef xVar = pArray->Get32(aIdx);
|
|
Type aType = getUnoTypeForSbxValue( xVar.get() );
|
|
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( xVar.get() );
|
|
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.append(aSeqLevelStr);
|
|
}
|
|
aSeqTypeName.append(aElementType.getTypeName());
|
|
aRetType = Type( TypeClass_SEQUENCE, aSeqTypeName.makeStringAndClear() );
|
|
}
|
|
}
|
|
// No array, but ...
|
|
else if( auto obj = dynamic_cast<SbUnoObject*>( xObj.get() ) )
|
|
{
|
|
aRetType = obj->getUnoAny().getValueType();
|
|
}
|
|
// SbUnoAnyObject?
|
|
else if( auto any = dynamic_cast<SbUnoAnyObject*>( xObj.get() ) )
|
|
{
|
|
aRetType = any->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
|
|
static Any sbxToUnoValueImpl( const SbxValue* pVar, bool bBlockConversionToSmallestType = false )
|
|
{
|
|
SbxDataType eBaseType = pVar->SbxValue::GetType();
|
|
if( eBaseType == SbxOBJECT )
|
|
{
|
|
SbxBaseRef xObj = pVar->GetObject();
|
|
if( xObj.is() )
|
|
{
|
|
if( auto obj = dynamic_cast<SbUnoAnyObject*>( xObj.get() ) )
|
|
return obj->getValue();
|
|
if( auto pClassModuleObj = dynamic_cast<SbClassModuleObject*>( xObj.get() ) )
|
|
{
|
|
Any aRetAny;
|
|
SbModule* pClassModule = pClassModuleObj->getClassModule();
|
|
if( pClassModule->createCOMWrapperForIface( aRetAny, pClassModuleObj ) )
|
|
return aRetAny;
|
|
}
|
|
if( dynamic_cast<const SbUnoObject*>( xObj.get() ) == nullptr )
|
|
{
|
|
// Create NativeObjectWrapper to identify object in case of callbacks
|
|
SbxObject* pObj = dynamic_cast<SbxObject*>( pVar->GetObject() );
|
|
if( pObj != nullptr )
|
|
{
|
|
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" representation for int values
|
|
// because up cast is allowed, downcast not
|
|
switch( eType )
|
|
{
|
|
case TypeClass_FLOAT:
|
|
case TypeClass_DOUBLE:
|
|
{
|
|
double d = pVar->GetDouble();
|
|
if( rtl::math::approxEqual(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.append(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( ERRCODE_BASIC_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;
|
|
|
|
const 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 const * 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 = pVar->GetObject();
|
|
if ( auto obj = dynamic_cast<SbUnoAnyObject*>( xObj.get() ) )
|
|
{
|
|
return obj->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 );
|
|
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 <<= pVar->GetInt64();
|
|
break;
|
|
}
|
|
else if( rType == cppu::UnoType<oleautomation::Date>::get())
|
|
{
|
|
oleautomation::Date aDate;
|
|
aDate.Value = pVar->GetDate();
|
|
aRetVal <<= aDate;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
SbxBaseRef pObj = pVar->GetObject();
|
|
if( auto obj = dynamic_cast<SbUnoObject*>( pObj.get() ) )
|
|
{
|
|
aRetVal = obj->getUnoAny();
|
|
}
|
|
else if( auto structRef = dynamic_cast<SbUnoStructRefObject*>( pObj.get() ) )
|
|
{
|
|
aRetVal = structRef->getUnoAny();
|
|
}
|
|
else
|
|
{
|
|
// null object -> null XInterface
|
|
Reference<XInterface> xInt;
|
|
aRetVal <<= xInt;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case TypeClass_TYPE:
|
|
{
|
|
if( eBaseType == SbxOBJECT )
|
|
{
|
|
// XIdlClass?
|
|
Reference< XIdlClass > xIdlClass;
|
|
|
|
SbxBaseRef pObj = pVar->GetObject();
|
|
if( auto obj = dynamic_cast<SbUnoObject*>( pObj.get() ) )
|
|
{
|
|
Any aUnoAny = obj->getUnoAny();
|
|
aUnoAny >>= xIdlClass;
|
|
}
|
|
|
|
if( xIdlClass.is() )
|
|
{
|
|
OUString aClassName = xIdlClass->getName();
|
|
Type aType( xIdlClass->getTypeClass(), aClassName );
|
|
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 = pVar->GetObject();
|
|
if( auto pArray = dynamic_cast<SbxDimArray*>( xObj.get() ) )
|
|
{
|
|
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 = nullptr;
|
|
typelib_typedescription_getByName( &pSeqTD, aClassName.pData );
|
|
OSL_ASSERT( pSeqTD );
|
|
Type aElemType( reinterpret_cast<typelib_IndirectTypeDescription *>(pSeqTD)->pType );
|
|
|
|
// convert all array member and register them
|
|
sal_Int32 aIdx[1];
|
|
aIdx[0] = nLower;
|
|
for (sal_Int32 i = 0 ; i < nSeqSize; ++i, ++aIdx[0])
|
|
{
|
|
SbxVariableRef xVar = pArray->Get32(aIdx);
|
|
|
|
// Convert the value of Sbx to Uno
|
|
Any aAnyValue = sbxToUnoValue( xVar.get(), 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( ERRCODE_BASIC_OUT_OF_RANGE );
|
|
}
|
|
}
|
|
}
|
|
// #i33795 Map also multi dimensional arrays to corresponding sequences
|
|
else if( nDims > 1 )
|
|
{
|
|
// Element-Type
|
|
typelib_TypeDescription * pSeqTD = nullptr;
|
|
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( reinterpret_cast<typelib_IndirectTypeDescription *>(pSeqTD)->pType );
|
|
nSeqLevel++;
|
|
}
|
|
else
|
|
{
|
|
aElemType = aCurType;
|
|
break;
|
|
}
|
|
}
|
|
while( true );
|
|
|
|
if( nSeqLevel == nDims )
|
|
{
|
|
std::unique_ptr<sal_Int32[]> pLowerBounds(new sal_Int32[nDims]);
|
|
std::unique_ptr<sal_Int32[]> pUpperBounds(new sal_Int32[nDims]);
|
|
std::unique_ptr<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.get(), pLowerBounds.get(), pUpperBounds.get() );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
|
|
// for Any use the class independent converting routine
|
|
case TypeClass_ANY:
|
|
{
|
|
aRetVal = sbxToUnoValueImpl( pVar );
|
|
}
|
|
break;
|
|
|
|
case TypeClass_BOOLEAN:
|
|
{
|
|
aRetVal <<= pVar->GetBool();
|
|
break;
|
|
}
|
|
case TypeClass_CHAR:
|
|
{
|
|
aRetVal <<= pVar->GetChar();
|
|
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 > 255 ) // 128..255 map to -128..-1
|
|
{
|
|
bOverflow = true;
|
|
nVal = 127;
|
|
}
|
|
if( bOverflow )
|
|
StarBASIC::Error( ERRCODE_BASIC_MATH_OVERFLOW );
|
|
|
|
sal_Int8 nByteVal = static_cast<sal_Int8>(nVal);
|
|
aRetVal <<= nByteVal;
|
|
break;
|
|
}
|
|
case TypeClass_SHORT: aRetVal <<= pVar->GetInteger(); break;
|
|
case TypeClass_LONG: aRetVal <<= pVar->GetLong(); break;
|
|
case TypeClass_HYPER: aRetVal <<= pVar->GetInt64(); break;
|
|
case TypeClass_UNSIGNED_SHORT: aRetVal <<= pVar->GetUShort(); break;
|
|
case TypeClass_UNSIGNED_LONG: aRetVal <<= pVar->GetULong(); break;
|
|
case TypeClass_UNSIGNED_HYPER: aRetVal <<= pVar->GetUInt64(); break;
|
|
default: break;
|
|
}
|
|
|
|
return aRetVal;
|
|
}
|
|
|
|
static void processAutomationParams( SbxArray* pParams, Sequence< Any >& args, sal_uInt32 nParamCount )
|
|
{
|
|
AutomationNamedArgsSbxArray* pArgNamesArray = dynamic_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 = static_cast<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( static_cast<sal_uInt16>(i+1) ),
|
|
bBlockConversionToSmallestType );
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
namespace {
|
|
|
|
enum class INVOKETYPE
|
|
{
|
|
GetProp = 0,
|
|
Func
|
|
};
|
|
|
|
}
|
|
|
|
static Any invokeAutomationMethod( const OUString& Name, Sequence< Any > const & args, SbxArray* pParams, sal_uInt32 nParamCount, Reference< XInvocation > const & rxInvocation, INVOKETYPE invokeType )
|
|
{
|
|
Sequence< sal_Int16 > OutParamIndex;
|
|
Sequence< Any > OutParam;
|
|
|
|
Any aRetAny;
|
|
switch( invokeType )
|
|
{
|
|
case INVOKETYPE::Func:
|
|
aRetAny = rxInvocation->invoke( Name, args, OutParamIndex, OutParam );
|
|
break;
|
|
case INVOKETYPE::GetProp:
|
|
{
|
|
Reference< XAutomationInvocation > xAutoInv( rxInvocation, UNO_QUERY );
|
|
aRetAny = xAutoInv->invokeGetProperty( Name, args, OutParamIndex, OutParam );
|
|
break;
|
|
}
|
|
default:
|
|
assert(false); break;
|
|
|
|
}
|
|
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 >= static_cast<sal_Int16>(nParamCount) )
|
|
break;
|
|
unoToSbxValue( pParams->Get( static_cast<sal_uInt16>(j+1) ), pNewValues[ j ] );
|
|
}
|
|
}
|
|
return aRetAny;
|
|
}
|
|
|
|
// Debugging help method to readout the imlemented interfaces of an object
|
|
static 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.append( " " );
|
|
aRetStr.append( xClass->getName() );
|
|
OUString aClassName = xClass->getName();
|
|
Type aClassType( xClass->getTypeClass(), aClassName );
|
|
|
|
// checking if the interface is really supported
|
|
if( !x->queryInterface( aClassType ).hasValue() )
|
|
{
|
|
aRetStr.append( " (ERROR: Not really supported!)\n" );
|
|
}
|
|
// Are there super interfaces?
|
|
else
|
|
{
|
|
aRetStr.append( "\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();
|
|
}
|
|
|
|
static OUString getDbgObjectNameImpl(SbUnoObject& rUnoObj)
|
|
{
|
|
OUString aName = rUnoObj.GetClassName();
|
|
if( aName.isEmpty() )
|
|
{
|
|
Any aToInspectObj = rUnoObj.getUnoAny();
|
|
Reference< XInterface > xObj(aToInspectObj, css::uno::UNO_QUERY);
|
|
if( xObj.is() )
|
|
{
|
|
Reference< XServiceInfo > xServiceInfo( xObj, UNO_QUERY );
|
|
if( xServiceInfo.is() )
|
|
aName = xServiceInfo->getImplementationName();
|
|
}
|
|
}
|
|
return aName;
|
|
}
|
|
|
|
static OUString getDbgObjectName(SbUnoObject& rUnoObj)
|
|
{
|
|
OUString aName = getDbgObjectNameImpl(rUnoObj);
|
|
if( aName.isEmpty() )
|
|
aName += "Unknown";
|
|
|
|
OUStringBuffer aRet;
|
|
if( aName.getLength() > 20 )
|
|
{
|
|
aRet.append( "\n" );
|
|
}
|
|
aRet.append( "\"" );
|
|
aRet.append( aName );
|
|
aRet.append( "\":" );
|
|
return aRet.makeStringAndClear();
|
|
}
|
|
|
|
OUString getBasicObjectTypeName( SbxObject* pObj )
|
|
{
|
|
if (pObj)
|
|
{
|
|
if (SbUnoObject* pUnoObj = dynamic_cast<SbUnoObject*>(pObj))
|
|
{
|
|
return getDbgObjectNameImpl(*pUnoObj);
|
|
}
|
|
else if (SbUnoStructRefObject* pUnoStructObj = dynamic_cast<SbUnoStructRefObject*>(pObj))
|
|
{
|
|
return pUnoStructObj->GetClassName();
|
|
}
|
|
}
|
|
return OUString();
|
|
}
|
|
|
|
namespace {
|
|
|
|
bool matchesBasicTypeName(
|
|
css::uno::Reference<css::reflection::XIdlClass> const & unoType, OUString const & basicTypeName)
|
|
{
|
|
if (unoType->getName().endsWithIgnoreAsciiCase(basicTypeName)) {
|
|
return true;
|
|
}
|
|
auto const sups = unoType->getSuperclasses();
|
|
return std::any_of(
|
|
sups.begin(), sups.end(),
|
|
[&basicTypeName](auto const & t) { return matchesBasicTypeName(t, basicTypeName); });
|
|
}
|
|
|
|
}
|
|
|
|
bool checkUnoObjectType(SbUnoObject& rUnoObj, const OUString& rClass)
|
|
{
|
|
Any aToInspectObj = rUnoObj.getUnoAny();
|
|
|
|
// Return true for XInvocation based objects as interface type names don't count then
|
|
Reference< XInvocation > xInvocation( aToInspectObj, UNO_QUERY );
|
|
if( xInvocation.is() )
|
|
{
|
|
return true;
|
|
}
|
|
bool bResult = false;
|
|
Reference< XTypeProvider > xTypeProvider( aToInspectObj, 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 ) + "X" + rClass.copy( nClassNameDot + 1 );
|
|
}
|
|
else
|
|
{
|
|
aClassName += "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( "$GetTypeName" ) >>= sTypeName;
|
|
if ( sTypeName.isEmpty() || sTypeName == "IDispatch" )
|
|
{
|
|
// can't check type, leave it pass
|
|
bResult = true;
|
|
}
|
|
else
|
|
{
|
|
bResult = sTypeName == rClass;
|
|
}
|
|
}
|
|
break; // finished checking automation object
|
|
}
|
|
|
|
if ( matchesBasicTypeName(xClass, aClassName) )
|
|
{
|
|
bResult = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return bResult;
|
|
}
|
|
|
|
// Debugging help method to readout the imlemented interfaces of an object
|
|
static OUString Impl_GetSupportedInterfaces(SbUnoObject& rUnoObj)
|
|
{
|
|
Any aToInspectObj = rUnoObj.getUnoAny();
|
|
|
|
// allow only TypeClass interface
|
|
OUStringBuffer aRet;
|
|
auto x = o3tl::tryAccess<Reference<XInterface>>(aToInspectObj);
|
|
if( !x )
|
|
{
|
|
aRet.append( ID_DBG_SUPPORTEDINTERFACES );
|
|
aRet.append( " not available.\n(TypeClass is not TypeClass_INTERFACE)\n" );
|
|
}
|
|
else
|
|
{
|
|
Reference< XTypeProvider > xTypeProvider( *x, UNO_QUERY );
|
|
|
|
aRet.append( "Supported interfaces by object " );
|
|
aRet.append(getDbgObjectName(rUnoObj));
|
|
aRet.append( "\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 = nullptr;
|
|
rType.getDescription( &pTD );
|
|
|
|
aRet.append( "*** ERROR: No IdlClass for type \"" );
|
|
aRet.append( pTD->pTypeName );
|
|
aRet.append( "\"\n*** Please check type library\n" );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return aRet.makeStringAndClear();
|
|
}
|
|
|
|
|
|
// Debugging help method SbxDataType -> String
|
|
static OUString Dbg_SbxDataType2String( SbxDataType eType )
|
|
{
|
|
OUStringBuffer aRet;
|
|
switch( +eType )
|
|
{
|
|
case SbxEMPTY: aRet.append("SbxEMPTY"); break;
|
|
case SbxNULL: aRet.append("SbxNULL"); break;
|
|
case SbxINTEGER: aRet.append("SbxINTEGER"); break;
|
|
case SbxLONG: aRet.append("SbxLONG"); break;
|
|
case SbxSINGLE: aRet.append("SbxSINGLE"); break;
|
|
case SbxDOUBLE: aRet.append("SbxDOUBLE"); break;
|
|
case SbxCURRENCY: aRet.append("SbxCURRENCY"); break;
|
|
case SbxDECIMAL: aRet.append("SbxDECIMAL"); break;
|
|
case SbxDATE: aRet.append("SbxDATE"); break;
|
|
case SbxSTRING: aRet.append("SbxSTRING"); break;
|
|
case SbxOBJECT: aRet.append("SbxOBJECT"); break;
|
|
case SbxERROR: aRet.append("SbxERROR"); break;
|
|
case SbxBOOL: aRet.append("SbxBOOL"); break;
|
|
case SbxVARIANT: aRet.append("SbxVARIANT"); break;
|
|
case SbxDATAOBJECT: aRet.append("SbxDATAOBJECT"); break;
|
|
case SbxCHAR: aRet.append("SbxCHAR"); break;
|
|
case SbxBYTE: aRet.append("SbxBYTE"); break;
|
|
case SbxUSHORT: aRet.append("SbxUSHORT"); break;
|
|
case SbxULONG: aRet.append("SbxULONG"); break;
|
|
case SbxSALINT64: aRet.append("SbxINT64"); break;
|
|
case SbxSALUINT64: aRet.append("SbxUINT64"); break;
|
|
case SbxINT: aRet.append("SbxINT"); break;
|
|
case SbxUINT: aRet.append("SbxUINT"); break;
|
|
case SbxVOID: aRet.append("SbxVOID"); break;
|
|
case SbxHRESULT: aRet.append("SbxHRESULT"); break;
|
|
case SbxPOINTER: aRet.append("SbxPOINTER"); break;
|
|
case SbxDIMARRAY: aRet.append("SbxDIMARRAY"); break;
|
|
case SbxCARRAY: aRet.append("SbxCARRAY"); break;
|
|
case SbxUSERDEF: aRet.append("SbxUSERDEF"); break;
|
|
case SbxLPSTR: aRet.append("SbxLPSTR"); break;
|
|
case SbxLPWSTR: aRet.append("SbxLPWSTR"); break;
|
|
case SbxCoreSTRING: aRet.append("SbxCoreSTRING"); break;
|
|
case SbxOBJECT | SbxARRAY: aRet.append("SbxARRAY"); break;
|
|
default: aRet.append("Unknown Sbx-Type!");break;
|
|
}
|
|
return aRet.makeStringAndClear();
|
|
}
|
|
|
|
// Debugging help method to display the properties of a SbUnoObjects
|
|
static OUString Impl_DumpProperties(SbUnoObject& rUnoObj)
|
|
{
|
|
OUStringBuffer aRet;
|
|
aRet.append("Properties of object ");
|
|
aRet.append(getDbgObjectName(rUnoObj));
|
|
|
|
// analyse the Uno-Infos to recognise the arrays
|
|
Reference< XIntrospectionAccess > xAccess = rUnoObj.getIntrospectionAccess();
|
|
if( !xAccess.is() )
|
|
{
|
|
Reference< XInvocation > xInvok = rUnoObj.getInvocation();
|
|
if( xInvok.is() )
|
|
xAccess = xInvok->getIntrospection();
|
|
}
|
|
if( !xAccess.is() )
|
|
{
|
|
aRet.append( "\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 = rUnoObj.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.append( "\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.append( "/void" );
|
|
aPropStr.append( " " );
|
|
aPropStr.append( pVar->GetName() );
|
|
|
|
if( i == nPropCount - 1 )
|
|
aPropStr.append( "\n" );
|
|
else
|
|
aPropStr.append( "; " );
|
|
|
|
aRet.append( aPropStr.makeStringAndClear() );
|
|
}
|
|
}
|
|
return aRet.makeStringAndClear();
|
|
}
|
|
|
|
// Debugging help method to display the methods of an SbUnoObjects
|
|
static OUString Impl_DumpMethods(SbUnoObject& rUnoObj)
|
|
{
|
|
OUStringBuffer aRet;
|
|
aRet.append("Methods of object ");
|
|
aRet.append(getDbgObjectName(rUnoObj));
|
|
|
|
// XIntrospectionAccess, so that the types of the parameter could be outputted
|
|
Reference< XIntrospectionAccess > xAccess = rUnoObj.getIntrospectionAccess();
|
|
if( !xAccess.is() )
|
|
{
|
|
Reference< XInvocation > xInvok = rUnoObj.getInvocation();
|
|
if( xInvok.is() )
|
|
xAccess = xInvok->getIntrospection();
|
|
}
|
|
if( !xAccess.is() )
|
|
{
|
|
aRet.append( "\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 = rUnoObj.GetMethods();
|
|
sal_uInt16 nMethodCount = pMethods->Count();
|
|
if( !nMethodCount )
|
|
{
|
|
aRet.append( "\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.append( "\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.append( " " );
|
|
aRet.append ( pVar->GetName() );
|
|
aRet.append( " ( " );
|
|
|
|
// 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_uInt32 j = 0; j < nParamCount; j++ )
|
|
{
|
|
aRet.append ( Dbg_SbxDataType2String( unoToSbxType( pParams[ j ] ) ) );
|
|
if( j < nParamCount - 1 )
|
|
aRet.append( ", " );
|
|
}
|
|
}
|
|
else
|
|
aRet.append( "void" );
|
|
|
|
aRet.append( " ) " );
|
|
|
|
if( i == nMethodCount - 1 )
|
|
aRet.append( "\n" );
|
|
else
|
|
aRet.append( "; " );
|
|
}
|
|
}
|
|
return aRet.makeStringAndClear();
|
|
}
|
|
|
|
|
|
// Implementation SbUnoObject
|
|
void SbUnoObject::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
|
|
{
|
|
if( bNeedIntrospection )
|
|
doIntrospection();
|
|
|
|
const SbxHint* pHint = dynamic_cast<const SbxHint*>(&rHint);
|
|
if( pHint )
|
|
{
|
|
SbxVariable* pVar = pHint->GetVar();
|
|
SbxArray* pParams = pVar->GetParameters();
|
|
SbUnoProperty* pProp = dynamic_cast<SbUnoProperty*>( pVar );
|
|
SbUnoMethod* pMeth = dynamic_cast<SbUnoMethod*>( pVar );
|
|
if( pProp )
|
|
{
|
|
bool bInvocation = pProp->isInvocationBased();
|
|
if( pHint->GetId() == SfxHintId::BasicDataWanted )
|
|
{
|
|
// 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( ERRCODE_BASIC_PROPERTY_NOT_FOUND );
|
|
}
|
|
else
|
|
{
|
|
if ( pProp->isUnoStruct() )
|
|
{
|
|
SbUnoStructRefObject* pSbUnoObject = new SbUnoStructRefObject( pProp->GetName(), aMember );
|
|
SbxObjectRef xWrapper = static_cast<SbxObject*>(pSbUnoObject);
|
|
pVar->PutObject( xWrapper.get() );
|
|
}
|
|
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 possible 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 ? (static_cast<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, nParamCount );
|
|
aRetAny = invokeAutomationMethod( pProp->GetName(), args, pParams, nParamCount, mxInvocation, INVOKETYPE::GetProp );
|
|
}
|
|
else
|
|
aRetAny = mxInvocation->getValue( pProp->GetName() );
|
|
// take over the value from Uno to Sbx
|
|
unoToSbxValue( pVar, aRetAny );
|
|
if( pParams && bCanBeConsideredAMethod )
|
|
pVar->SetParameters( nullptr );
|
|
|
|
}
|
|
catch( const Exception& )
|
|
{
|
|
implHandleAnyException( ::cppu::getCaughtException() );
|
|
}
|
|
}
|
|
}
|
|
else if( pHint->GetId() == SfxHintId::BasicDataChanged )
|
|
{
|
|
if( !bInvocation && mxUnoAccess.is() )
|
|
{
|
|
if( pProp->aUnoProp.Attributes & PropertyAttribute::READONLY )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_PROP_READONLY );
|
|
return;
|
|
}
|
|
if ( maStructInfo.get() )
|
|
{
|
|
StructRefInfo aMember = maStructInfo->getStructMember( pProp->GetName() );
|
|
if ( aMember.isEmpty() )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_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 possible 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() == SfxHintId::BasicDataWanted )
|
|
{
|
|
// number of Parameter -1 because of Param0 == this
|
|
sal_uInt32 nParamCount = pParams ? (static_cast<sal_uInt32>(pParams->Count()) - 1) : 0;
|
|
Sequence<Any> args;
|
|
bool bOutParams = false;
|
|
|
|
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( sal_uInt32 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( ERRCODE_BASIC_NOT_OPTIONAL );
|
|
}
|
|
}
|
|
if( !bError )
|
|
nAllocParamCount = nUnoParamCount;
|
|
}
|
|
}
|
|
|
|
if( nAllocParamCount > 0 )
|
|
{
|
|
args.realloc( nAllocParamCount );
|
|
Any* pAnyArgs = args.getArray();
|
|
for( sal_uInt32 i = 0 ; i < nParamCount ; i++ )
|
|
{
|
|
const ParamInfo& rInfo = pParamInfos[i];
|
|
const Reference< XIdlClass >& rxClass = rInfo.aType;
|
|
|
|
css::uno::Type aType( rxClass->getTypeClass(), rxClass->getName() );
|
|
|
|
// ATTENTION: Don't forget for Sbx-Parameter the offset!
|
|
pAnyArgs[i] = sbxToUnoValue( pParams->Get( static_cast<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() )
|
|
{
|
|
processAutomationParams( pParams, args, 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( pParams->Get( static_cast<sal_uInt16>(j+1) ), pAnyArgs[ j ] );
|
|
}
|
|
}
|
|
}
|
|
else if( bInvocation && mxInvocation.is() )
|
|
{
|
|
Any aRetAny = invokeAutomationMethod( pMeth->GetName(), args, pParams, nParamCount, mxInvocation, INVOKETYPE::Func );
|
|
unoToSbxValue( pVar, aRetAny );
|
|
}
|
|
|
|
// remove parameter here, because this was not done anymore in unoToSbxValue()
|
|
// for arrays
|
|
if( pParams )
|
|
pVar->SetParameters( nullptr );
|
|
}
|
|
catch( const Exception& )
|
|
{
|
|
implHandleAnyException( ::cppu::getCaughtException() );
|
|
}
|
|
GetSbData()->bBlockCompilerError = false; // #106433 Unblock compiler errors
|
|
}
|
|
}
|
|
else
|
|
SbxObject::Notify( rBC, rHint );
|
|
}
|
|
}
|
|
|
|
|
|
SbUnoObject::SbUnoObject( const OUString& aName_, const Any& aUnoObj_ )
|
|
: SbxObject( aName_ )
|
|
, bNeedIntrospection( true )
|
|
, bNativeCOMObject( false )
|
|
{
|
|
// beat out again the default properties of Sbx
|
|
Remove( "Name", SbxClassType::DontCare );
|
|
Remove( "Parent", SbxClassType::DontCare );
|
|
|
|
// check the type of the objects
|
|
TypeClass eType = aUnoObj_.getValueType().getTypeClass();
|
|
Reference< XInterface > x;
|
|
if( eType == TypeClass_INTERFACE )
|
|
{
|
|
// get the interface from the Any
|
|
aUnoObj_ >>= x;
|
|
if( !x.is() )
|
|
return;
|
|
}
|
|
|
|
Reference< XTypeProvider > xTypeProvider;
|
|
// Did the object have an invocation itself?
|
|
mxInvocation.set( x, UNO_QUERY );
|
|
|
|
xTypeProvider.set( x, UNO_QUERY );
|
|
|
|
if( mxInvocation.is() )
|
|
{
|
|
|
|
// get the ExactName
|
|
mxExactNameInvocation.set( mxInvocation, UNO_QUERY );
|
|
|
|
// 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;
|
|
}
|
|
StructRefInfo aThisStruct( maTmpUnoObj, maTmpUnoObj.getValueType(), 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()
|
|
{
|
|
if( !bNeedIntrospection )
|
|
return;
|
|
|
|
Reference<XComponentContext> xContext = comphelper::getProcessComponentContext();
|
|
|
|
if (!xContext.is())
|
|
return;
|
|
|
|
|
|
// get the introspection service
|
|
Reference<XIntrospection> xIntrospection;
|
|
|
|
try
|
|
{
|
|
xIntrospection = theIntrospection::get(xContext);
|
|
}
|
|
catch ( const css::uno::DeploymentException& )
|
|
{
|
|
}
|
|
|
|
if (!xIntrospection.is())
|
|
return;
|
|
|
|
bNeedIntrospection = false;
|
|
|
|
// 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.set( mxUnoAccess, UNO_QUERY );
|
|
|
|
// get ExactName from access
|
|
mxExactName.set( mxUnoAccess, UNO_QUERY );
|
|
}
|
|
|
|
|
|
// Start of a list of all SbUnoMethod-Instances
|
|
static SbUnoMethod* pFirst = nullptr;
|
|
|
|
void clearUnoMethodsForBasic( StarBASIC const * pBasic )
|
|
{
|
|
SbUnoMethod* pMeth = pFirst;
|
|
while( pMeth )
|
|
{
|
|
SbxObject* pObject = 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 = nullptr;
|
|
pMeth->pNext = nullptr;
|
|
|
|
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()
|
|
{
|
|
SbUnoMethod* pMeth = pFirst;
|
|
while( pMeth )
|
|
{
|
|
pMeth->SbxValue::Clear();
|
|
pMeth = pMeth->pNext;
|
|
}
|
|
}
|
|
|
|
|
|
SbUnoMethod::SbUnoMethod
|
|
(
|
|
const OUString& aName_,
|
|
SbxDataType eSbxType,
|
|
Reference< XIdlMethod > const & xUnoMethod_,
|
|
bool bInvocation
|
|
)
|
|
: SbxMethod( aName_, eSbxType )
|
|
, mbInvocation( bInvocation )
|
|
{
|
|
m_xUnoMethod = xUnoMethod_;
|
|
pParamInfoSeq = nullptr;
|
|
|
|
// enregister the method in a list
|
|
pNext = pFirst;
|
|
pPrev = nullptr;
|
|
pFirst = this;
|
|
if( pNext )
|
|
pNext->pPrev = this;
|
|
}
|
|
|
|
SbUnoMethod::~SbUnoMethod()
|
|
{
|
|
pParamInfoSeq.reset();
|
|
|
|
if( this == pFirst )
|
|
pFirst = pNext;
|
|
else if( pPrev )
|
|
pPrev->pNext = pNext;
|
|
if( pNext )
|
|
pNext->pPrev = pPrev;
|
|
}
|
|
|
|
SbxInfo* SbUnoMethod::GetInfo()
|
|
{
|
|
if( !pInfo.is() && 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;
|
|
|
|
pInfo->AddParam( aParamName, SbxVARIANT, SbxFlagBits::Read );
|
|
}
|
|
}
|
|
}
|
|
return pInfo.get();
|
|
}
|
|
|
|
const Sequence<ParamInfo>& SbUnoMethod::getParamInfos()
|
|
{
|
|
if (!pParamInfoSeq)
|
|
{
|
|
Sequence<ParamInfo> aTmp;
|
|
if (m_xUnoMethod.is())
|
|
aTmp = m_xUnoMethod->getParameterInfos();
|
|
pParamInfoSeq.reset( 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 a dummy array so that SbiRuntime::CheckArray() works
|
|
static SbxArrayRef xDummyArray = new SbxArray( SbxVARIANT );
|
|
if( eSbxType & SbxARRAY )
|
|
PutObject( xDummyArray.get() );
|
|
}
|
|
|
|
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
|
|
auto pProp = tools::make_ref<SbUnoProperty>( rProp.Name, eSbxType, eRealSbxType, rProp, 0, false, ( rProp.Type.getTypeClass() == css::uno::TypeClass_STRUCT ) );
|
|
QuickInsert( pProp.get() );
|
|
pRes = pProp.get();
|
|
}
|
|
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
|
|
auto xMethRef = tools::make_ref<SbUnoMethod>( rxMethod->getName(),
|
|
unoToSbxType( rxMethod->getReturnType() ), rxMethod, false );
|
|
QuickInsert( xMethRef.get() );
|
|
pRes = xMethRef.get();
|
|
}
|
|
|
|
// If nothing was found check via XNameAccess
|
|
if( !pRes )
|
|
{
|
|
try
|
|
{
|
|
Reference< XNameAccess > xNameAccess( mxUnoAccess->queryAdapter( cppu::UnoType<XPropertySet>::get()), UNO_QUERY );
|
|
|
|
if( xNameAccess.is() && xNameAccess->hasByName( rName ) )
|
|
{
|
|
Any aAny = xNameAccess->getByName( rName );
|
|
|
|
// 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,
|
|
// which 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 exception error will not be overwritten
|
|
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
|
|
auto xVarRef = tools::make_ref<SbUnoProperty>( aUName, SbxVARIANT, SbxVARIANT, aDummyProp, 0, true, false );
|
|
QuickInsert( xVarRef.get() );
|
|
pRes = xVarRef.get();
|
|
}
|
|
else if( mxInvocation->hasMethod( aUName ) )
|
|
{
|
|
// create SbUnoMethode and superimpose it
|
|
auto xMethRef = tools::make_ref<SbUnoMethod>( aUName, SbxVARIANT, xDummyMethod, true );
|
|
QuickInsert( xMethRef.get() );
|
|
pRes = xMethRef.get();
|
|
}
|
|
else
|
|
{
|
|
Reference< XDirectInvocation > xDirectInvoke( mxInvocation, UNO_QUERY );
|
|
if ( xDirectInvoke.is() && xDirectInvoke->hasMember( aUName ) )
|
|
{
|
|
auto xMethRef = tools::make_ref<SbUnoMethod>( aUName, SbxVARIANT, xDummyMethod, true );
|
|
QuickInsert( xMethRef.get() );
|
|
pRes = xMethRef.get();
|
|
}
|
|
|
|
}
|
|
}
|
|
catch( const RuntimeException& e )
|
|
{
|
|
// Establish so that the exception error will not be overwritten
|
|
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, SbxClassType::DontCare );
|
|
}
|
|
}
|
|
return pRes;
|
|
}
|
|
|
|
|
|
// help method to create the dbg_-Properties
|
|
void SbUnoObject::implCreateDbgProperties()
|
|
{
|
|
Property aProp;
|
|
|
|
// Id == -1: display the implemented interfaces corresponding the ClassProvider
|
|
auto xVarRef = tools::make_ref<SbUnoProperty>( OUString(ID_DBG_SUPPORTEDINTERFACES), SbxSTRING, SbxSTRING, aProp, -1, false, false );
|
|
QuickInsert( xVarRef.get() );
|
|
|
|
// Id == -2: output the properties
|
|
xVarRef = tools::make_ref<SbUnoProperty>( OUString(ID_DBG_PROPERTIES), SbxSTRING, SbxSTRING, aProp, -2, false, false );
|
|
QuickInsert( xVarRef.get() );
|
|
|
|
// Id == -3: output the Methods
|
|
xVarRef = tools::make_ref<SbUnoProperty>( OUString(ID_DBG_METHODS), SbxSTRING, SbxSTRING, aProp, -3, false, false );
|
|
QuickInsert( xVarRef.get() );
|
|
}
|
|
|
|
void SbUnoObject::implCreateAll()
|
|
{
|
|
// throw away all existing methods and properties
|
|
pMethods = tools::make_ref<SbxArray>();
|
|
pProps = tools::make_ref<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
|
|
auto xVarRef = tools::make_ref<SbUnoProperty>( rProp.Name, eSbxType, eRealSbxType, rProp, i, false, ( rProp.Type.getTypeClass() == css::uno::TypeClass_STRUCT ) );
|
|
QuickInsert( xVarRef.get() );
|
|
}
|
|
|
|
// 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
|
|
auto xMethRef = tools::make_ref<SbUnoMethod>
|
|
( rxMethod->getName(), unoToSbxType( rxMethod->getReturnType() ), rxMethod, false );
|
|
QuickInsert( xMethRef.get() );
|
|
}
|
|
}
|
|
|
|
|
|
// output the value
|
|
Any SbUnoObject::getUnoAny()
|
|
{
|
|
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 a Uno-Struct per CoreReflection
|
|
static SbUnoObject* Impl_CreateUnoStruct( const OUString& aClassName )
|
|
{
|
|
// get CoreReflection
|
|
Reference< XIdlReflection > xCoreReflection = getCoreReflection_Impl();
|
|
if( !xCoreReflection.is() )
|
|
return nullptr;
|
|
|
|
// search for the class
|
|
Reference< XIdlClass > xClass;
|
|
const Reference< XHierarchicalNameAccess >& xHarryName =
|
|
getCoreReflection_HierarchicalNameAccess_Impl();
|
|
if( xHarryName.is() && xHarryName->hasByHierarchicalName( aClassName ) )
|
|
xClass = xCoreReflection->forName( aClassName );
|
|
if( !xClass.is() )
|
|
return nullptr;
|
|
|
|
// Is it really a struct?
|
|
TypeClass eType = xClass->getTypeClass();
|
|
if ( ( eType != TypeClass_STRUCT ) && ( eType != TypeClass_EXCEPTION ) )
|
|
return nullptr;
|
|
|
|
// 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 nullptr;
|
|
}
|
|
|
|
SbxObject* SbUnoFactory::CreateObject( const OUString& rClassName )
|
|
{
|
|
return Impl_CreateUnoStruct( rClassName );
|
|
}
|
|
|
|
|
|
// Provisional interface for the UNO-Connection
|
|
// Deliver a SbxObject, that wrap a 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 = dynamic_cast<SbUnoObject*>( pObj );
|
|
SbUnoStructRefObject* pUnoStructObj = dynamic_cast<SbUnoStructRefObject*>( pObj );
|
|
if( pUnoObj )
|
|
{
|
|
pUnoObj->createAllProperties();
|
|
}
|
|
else if ( pUnoStructObj )
|
|
{
|
|
pUnoStructObj->createAllProperties();
|
|
}
|
|
}
|
|
|
|
|
|
void RTL_Impl_CreateUnoStruct( SbxArray& rPar )
|
|
{
|
|
// We need 1 parameter minimum
|
|
if ( rPar.Count() < 2 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_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.is() )
|
|
{
|
|
return;
|
|
}
|
|
// return the object
|
|
SbxVariableRef refVar = rPar.Get(0);
|
|
refVar->PutObject( xUnoObj.get() );
|
|
}
|
|
|
|
void RTL_Impl_CreateUnoService( SbxArray& rPar )
|
|
{
|
|
// We need 1 Parameter minimum
|
|
if ( rPar.Count() < 2 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
return;
|
|
}
|
|
|
|
// get the name of the class of the struct
|
|
OUString aServiceName = rPar.Get(1)->GetOUString();
|
|
|
|
// search for the service and instantiate 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() )
|
|
{
|
|
// Create a SbUnoObject out of it and return it
|
|
SbUnoObjectRef xUnoObj = new SbUnoObject( aServiceName, Any(xInterface) );
|
|
if( xUnoObj->getUnoAny().hasValue() )
|
|
{
|
|
// return the object
|
|
refVar->PutObject( xUnoObj.get() );
|
|
}
|
|
else
|
|
{
|
|
refVar->PutObject( nullptr );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
refVar->PutObject( nullptr );
|
|
}
|
|
}
|
|
|
|
void RTL_Impl_CreateUnoServiceWithArguments( SbxArray& rPar )
|
|
{
|
|
// We need 2 parameter minimum
|
|
if ( rPar.Count() < 3 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
return;
|
|
}
|
|
|
|
// get the name of the class of the struct
|
|
OUString aServiceName = rPar.Get(1)->GetOUString();
|
|
Any aArgAsAny = sbxToUnoValue( rPar.Get(2),
|
|
cppu::UnoType<Sequence<Any>>::get() );
|
|
Sequence< Any > aArgs;
|
|
aArgAsAny >>= aArgs;
|
|
|
|
// search for the service and instantiate 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() )
|
|
{
|
|
// Create a SbUnoObject out of it and return it
|
|
SbUnoObjectRef xUnoObj = new SbUnoObject( aServiceName, Any(xInterface) );
|
|
if( xUnoObj->getUnoAny().hasValue() )
|
|
{
|
|
// return the object
|
|
refVar->PutObject( xUnoObj.get() );
|
|
}
|
|
else
|
|
{
|
|
refVar->PutObject( nullptr );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
refVar->PutObject( nullptr );
|
|
}
|
|
}
|
|
|
|
void RTL_Impl_GetProcessServiceManager( SbxArray& rPar )
|
|
{
|
|
SbxVariableRef refVar = rPar.Get(0);
|
|
|
|
// get the global service manager
|
|
Reference< XMultiServiceFactory > xFactory( comphelper::getProcessServiceFactory() );
|
|
|
|
// Create a SbUnoObject out of it and return it
|
|
SbUnoObjectRef xUnoObj = new SbUnoObject( "ProcessServiceManager", Any(xFactory) );
|
|
refVar->PutObject( xUnoObj.get() );
|
|
}
|
|
|
|
void RTL_Impl_HasInterfaces( SbxArray& rPar )
|
|
{
|
|
// We need 2 parameter minimum
|
|
sal_uInt16 nParCount = rPar.Count();
|
|
if( nParCount < 3 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
return;
|
|
}
|
|
|
|
// variable for the return value
|
|
SbxVariableRef refVar = rPar.Get(0);
|
|
refVar->PutBool( false );
|
|
|
|
// get the Uno-Object
|
|
SbxBaseRef pObj = rPar.Get( 1 )->GetObject();
|
|
auto obj = dynamic_cast<SbUnoObject*>( pObj.get() );
|
|
if( obj == nullptr )
|
|
{
|
|
return;
|
|
}
|
|
Any aAny = obj->getUnoAny();
|
|
auto x = o3tl::tryAccess<Reference<XInterface>>(aAny);
|
|
if( !x )
|
|
{
|
|
return;
|
|
}
|
|
|
|
// 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 );
|
|
if( !(*x)->queryInterface( aClassType ).hasValue() )
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Everything works; then return TRUE
|
|
refVar->PutBool( true );
|
|
}
|
|
|
|
void RTL_Impl_IsUnoStruct( SbxArray& rPar )
|
|
{
|
|
// We need 1 parameter minimum
|
|
if ( rPar.Count() < 2 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_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 = rPar.Get( 1 )->GetObject();
|
|
auto obj = dynamic_cast<SbUnoObject*>( pObj.get() );
|
|
if( obj == nullptr )
|
|
{
|
|
return;
|
|
}
|
|
Any aAny = obj->getUnoAny();
|
|
TypeClass eType = aAny.getValueType().getTypeClass();
|
|
if( eType == TypeClass_STRUCT )
|
|
{
|
|
refVar->PutBool( true );
|
|
}
|
|
}
|
|
|
|
|
|
void RTL_Impl_EqualUnoObjects( SbxArray& rPar )
|
|
{
|
|
if ( rPar.Count() < 3 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_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 = xParam1->GetObject();
|
|
auto obj1 = dynamic_cast<SbUnoObject*>( pObj1.get() );
|
|
if( obj1 == nullptr )
|
|
{
|
|
return;
|
|
}
|
|
Any aAny1 = obj1->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 = xParam2->GetObject();
|
|
auto obj2 = dynamic_cast<SbUnoObject*>( pObj2.get() );
|
|
if( obj2 == nullptr )
|
|
{
|
|
return;
|
|
}
|
|
Any aAny2 = obj2->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
|
|
|
|
static 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;
|
|
}
|
|
|
|
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( "ooo.vba", 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;
|
|
|
|
for (auto const& elem : aConstCache)
|
|
{
|
|
if( rName.equalsIgnoreAsciiCase(elem) )
|
|
{
|
|
bConstant = true;
|
|
break;
|
|
}
|
|
}
|
|
return bConstant;
|
|
}
|
|
|
|
SbxVariable*
|
|
VBAConstantHelper::getVBAConstant( const OUString& rName )
|
|
{
|
|
SbxVariable* pConst = nullptr;
|
|
init();
|
|
|
|
auto it = aConstHash.find( rName.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 = nullptr;
|
|
|
|
const 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, SbxClassType::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(?)
|
|
Reference< XIdlField > xField = m_xClass->getField( rName );
|
|
if( xField.is() )
|
|
{
|
|
try
|
|
{
|
|
Any aAny = xField->get( {} ); //TODO: does this make sense?
|
|
|
|
// 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()
|
|
+ "."
|
|
+ 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< XIdlClass > xClass( aValue, UNO_QUERY );
|
|
if( xClass.is() )
|
|
{
|
|
pRes = new SbxVariable( SbxVARIANT );
|
|
SbxObjectRef xWrapper = static_cast<SbxObject*>(new SbUnoClass( aNewName, xClass ));
|
|
pRes->PutObject( xWrapper.get() );
|
|
}
|
|
}
|
|
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 = static_cast<SbxObject*>(pNewClass);
|
|
pRes->PutObject( xWrapper.get() );
|
|
}
|
|
}
|
|
|
|
// A UNO service?
|
|
if( !pRes )
|
|
{
|
|
SbUnoService* pUnoService = findUnoService( aNewName );
|
|
if( pUnoService )
|
|
{
|
|
pRes = new SbxVariable( SbxVARIANT );
|
|
SbxObjectRef xWrapper = static_cast<SbxObject*>(pUnoService);
|
|
pRes->PutObject( xWrapper.get() );
|
|
}
|
|
}
|
|
|
|
// A UNO singleton?
|
|
if( !pRes )
|
|
{
|
|
SbUnoSingleton* pUnoSingleton = findUnoSingleton( aNewName );
|
|
if( pUnoSingleton )
|
|
{
|
|
pRes = new SbxVariable( SbxVARIANT );
|
|
SbxObjectRef xWrapper = static_cast<SbxObject*>(pUnoSingleton);
|
|
pRes->PutObject( xWrapper.get() );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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 = nullptr;
|
|
|
|
const 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, SbxClassType::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( xSbCtorRef.get() );
|
|
}
|
|
}
|
|
pRes = SbxObject::Find( rName, SbxClassType::Method );
|
|
}
|
|
}
|
|
|
|
return pRes;
|
|
}
|
|
|
|
void SbUnoService::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
|
|
{
|
|
const SbxHint* pHint = dynamic_cast<const SbxHint*>(&rHint);
|
|
if( pHint )
|
|
{
|
|
SbxVariable* pVar = pHint->GetVar();
|
|
SbxArray* pParams = pVar->GetParameters();
|
|
SbUnoServiceCtor* pUnoCtor = dynamic_cast<SbUnoServiceCtor*>( pVar );
|
|
if( pUnoCtor && pHint->GetId() == SfxHintId::BasicDataWanted )
|
|
{
|
|
// Parameter count -1 because of Param0 == this
|
|
sal_uInt32 nParamCount = pParams ? (static_cast<sal_uInt32>(pParams->Count()) - 1) : 0;
|
|
Sequence<Any> args;
|
|
|
|
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( ERRCODE_BASIC_NOT_OPTIONAL );
|
|
}
|
|
}
|
|
|
|
if( !bParameterError )
|
|
{
|
|
bool bOutParams = false;
|
|
if( nAllocParamCount > 0 )
|
|
{
|
|
args.realloc( nAllocParamCount );
|
|
Any* pAnyArgs = args.getArray();
|
|
for( sal_uInt32 i = 0 ; i < nEffectiveParamCount ; i++ )
|
|
{
|
|
sal_uInt16 iSbx = static_cast<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;
|
|
css::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 && 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( pParams->Get( static_cast<sal_uInt16>(j+1) ), pAnyArgs[ j ] );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
SbxObject::Notify( rBC, rHint );
|
|
}
|
|
}
|
|
|
|
|
|
SbUnoServiceCtor::SbUnoServiceCtor( const OUString& aName_, Reference< XServiceConstructorDescription > const & xServiceCtorDesc )
|
|
: SbxMethod( aName_, SbxOBJECT )
|
|
, m_xServiceCtorDesc( xServiceCtorDesc )
|
|
{
|
|
}
|
|
|
|
SbUnoServiceCtor::~SbUnoServiceCtor()
|
|
{
|
|
}
|
|
|
|
SbxInfo* SbUnoServiceCtor::GetInfo()
|
|
{
|
|
SbxInfo* pRet = nullptr;
|
|
|
|
return pRet;
|
|
}
|
|
|
|
|
|
SbUnoSingleton* findUnoSingleton( const OUString& rName )
|
|
{
|
|
SbUnoSingleton* pSbUnoSingleton = nullptr;
|
|
|
|
const 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 );
|
|
}
|
|
}
|
|
}
|
|
return pSbUnoSingleton;
|
|
}
|
|
|
|
SbUnoSingleton::SbUnoSingleton( const OUString& aName_ )
|
|
: SbxObject( aName_ )
|
|
{
|
|
SbxVariableRef xGetMethodRef = new SbxMethod( "get", SbxOBJECT );
|
|
QuickInsert( xGetMethodRef.get() );
|
|
}
|
|
|
|
void SbUnoSingleton::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
|
|
{
|
|
const SbxHint* pHint = dynamic_cast<const SbxHint*>(&rHint);
|
|
if( pHint )
|
|
{
|
|
SbxVariable* pVar = pHint->GetVar();
|
|
SbxArray* pParams = pVar->GetParameters();
|
|
sal_uInt32 nParamCount = pParams ? (static_cast<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( ERRCODE_BASIC_BAD_ARGUMENT );
|
|
return;
|
|
}
|
|
|
|
Any aRetAny;
|
|
if( xContextToUse.is() )
|
|
{
|
|
OUString aSingletonName = "/singletons/"
|
|
+ GetName();
|
|
Reference < XInterface > xRet;
|
|
xContextToUse->getValueByName( aSingletonName ) >>= xRet;
|
|
aRetAny <<= xRet;
|
|
}
|
|
unoToSbxValue( pVar, aRetAny );
|
|
}
|
|
else
|
|
{
|
|
SbxObject::Notify( rBC, rHint );
|
|
}
|
|
}
|
|
|
|
|
|
// Implementation of an EventAttacher-drawn AllListener, which
|
|
// solely transmits several events to a general AllListener
|
|
class BasicAllListener_Impl : public WeakImplHelper< XAllListener >
|
|
{
|
|
void firing_impl(const AllEventObject& Event, Any* pRet);
|
|
|
|
public:
|
|
SbxObjectRef xSbxObj;
|
|
OUString aPrefixName;
|
|
|
|
explicit BasicAllListener_Impl( const OUString& aPrefixName );
|
|
|
|
// Methods of XAllListener
|
|
virtual void SAL_CALL firing(const AllEventObject& Event) override;
|
|
virtual Any SAL_CALL approveFiring(const AllEventObject& Event) override;
|
|
|
|
// Methods of XEventListener
|
|
virtual void SAL_CALL disposing(const EventObject& Source) override;
|
|
};
|
|
|
|
|
|
BasicAllListener_Impl::BasicAllListener_Impl(const OUString& aPrefixName_)
|
|
: aPrefixName( aPrefixName_ )
|
|
{
|
|
}
|
|
|
|
void BasicAllListener_Impl::firing_impl( const AllEventObject& Event, Any* pRet )
|
|
{
|
|
SolarMutexGuard guard;
|
|
|
|
if( xSbxObj.is() )
|
|
{
|
|
OUString aMethodName = aPrefixName + Event.MethodName;
|
|
|
|
SbxVariable * pP = xSbxObj.get();
|
|
while( pP->GetParent() )
|
|
{
|
|
pP = pP->GetParent();
|
|
StarBASIC * pLib = dynamic_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( xVar.get(), pArgs[i] );
|
|
xSbxArray->Put( xVar.get(), sal::static_int_cast< sal_uInt16 >(i+1) );
|
|
}
|
|
|
|
pLib->Call( aMethodName, xSbxArray.get() );
|
|
|
|
// get the return value from the Param-Array, if requested
|
|
if( pRet )
|
|
{
|
|
SbxVariable* pVar = xSbxArray->Get( 0 );
|
|
if( pVar )
|
|
{
|
|
// #95792 Avoid a second call
|
|
SbxFlagBits nFlags = pVar->GetFlags();
|
|
pVar->SetFlag( SbxFlagBits::NoBroadcast );
|
|
*pRet = sbxToUnoValueImpl( pVar );
|
|
pVar->SetFlags( nFlags );
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Methods of Listener
|
|
void BasicAllListener_Impl::firing( const AllEventObject& Event )
|
|
{
|
|
firing_impl( Event, nullptr );
|
|
}
|
|
|
|
Any BasicAllListener_Impl::approveFiring( const AllEventObject& Event )
|
|
{
|
|
Any aRetAny;
|
|
firing_impl( Event, &aRetAny );
|
|
return aRetAny;
|
|
}
|
|
|
|
|
|
// Methods of XEventListener
|
|
void BasicAllListener_Impl ::disposing(const EventObject& )
|
|
{
|
|
SolarMutexGuard guard;
|
|
|
|
xSbxObj.clear();
|
|
}
|
|
|
|
|
|
// class InvocationToAllListenerMapper
|
|
// helper class to map XInvocation to XAllListener (also in project eventattacher!)
|
|
|
|
class InvocationToAllListenerMapper : public WeakImplHelper< XInvocation >
|
|
{
|
|
public:
|
|
InvocationToAllListenerMapper( const Reference< XIdlClass >& ListenerType,
|
|
const Reference< XAllListener >& AllListener, const Any& Helper );
|
|
|
|
// XInvocation
|
|
virtual Reference< XIntrospectionAccess > SAL_CALL getIntrospection() override;
|
|
virtual Any SAL_CALL invoke(const OUString& FunctionName, const Sequence< Any >& Params, Sequence< sal_Int16 >& OutParamIndex, Sequence< Any >& OutParam) override;
|
|
virtual void SAL_CALL setValue(const OUString& PropertyName, const Any& Value) override;
|
|
virtual Any SAL_CALL getValue(const OUString& PropertyName) override;
|
|
virtual sal_Bool SAL_CALL hasMethod(const OUString& Name) override;
|
|
virtual sal_Bool SAL_CALL hasProperty(const OUString& Name) override;
|
|
|
|
private:
|
|
Reference< XAllListener > m_xAllListener;
|
|
Reference< XIdlClass > m_xListenerType;
|
|
Any m_Helper;
|
|
};
|
|
|
|
|
|
// Function to replace AllListenerAdapterService::createAllListerAdapter
|
|
static 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 =
|
|
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()
|
|
{
|
|
return Reference< XIntrospectionAccess >();
|
|
}
|
|
|
|
|
|
Any SAL_CALL InvocationToAllListenerMapper::invoke(const OUString& FunctionName, const Sequence< Any >& Params,
|
|
Sequence< sal_Int16 >&, Sequence< Any >&)
|
|
{
|
|
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.hasElements() )
|
|
{
|
|
bApproveFiring = true;
|
|
}
|
|
else
|
|
{
|
|
Sequence< ParamInfo > aParamSeq = xMethod->getParameterInfos();
|
|
sal_uInt32 nParamCount = aParamSeq.getLength();
|
|
if( nParamCount > 1 )
|
|
{
|
|
const ParamInfo* pInfo = aParamSeq.getConstArray();
|
|
for( sal_uInt32 i = 0 ; i < nParamCount ; i++ )
|
|
{
|
|
if( pInfo[ i ].aMode != ParamMode_IN )
|
|
{
|
|
bApproveFiring = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
AllEventObject aAllEvent;
|
|
aAllEvent.Source = static_cast<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&, const Any&)
|
|
{}
|
|
|
|
|
|
Any SAL_CALL InvocationToAllListenerMapper::getValue(const OUString&)
|
|
{
|
|
return Any();
|
|
}
|
|
|
|
|
|
sal_Bool SAL_CALL InvocationToAllListenerMapper::hasMethod(const OUString& Name)
|
|
{
|
|
Reference< XIdlMethod > xMethod = m_xListenerType->getMethod( Name );
|
|
return xMethod.is();
|
|
}
|
|
|
|
|
|
sal_Bool SAL_CALL InvocationToAllListenerMapper::hasProperty(const OUString& Name)
|
|
{
|
|
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)
|
|
{
|
|
// We need 2 parameters
|
|
if ( rPar.Count() != 3 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_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 );
|
|
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.get() );
|
|
}
|
|
|
|
|
|
// Represents the DefaultContext property of the ProcessServiceManager
|
|
// in the Basic runtime system.
|
|
void RTL_Impl_GetDefaultContext( SbxArray& rPar )
|
|
{
|
|
SbxVariableRef refVar = rPar.Get(0);
|
|
|
|
Any aContextAny( comphelper::getProcessComponentContext() );
|
|
|
|
SbUnoObjectRef xUnoObj = new SbUnoObject( "DefaultContext", aContextAny );
|
|
refVar->PutObject( xUnoObj.get() );
|
|
}
|
|
|
|
|
|
// 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( SbxArray& rPar )
|
|
{
|
|
// 2 parameters needed
|
|
if ( rPar.Count() != 3 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_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 == "type" )
|
|
{
|
|
SbxDataType eBaseType = pVal->SbxValue::GetType();
|
|
OUString aValTypeName;
|
|
if( eBaseType == SbxSTRING )
|
|
{
|
|
aValTypeName = pVal->GetOUString();
|
|
}
|
|
else if( eBaseType == SbxOBJECT )
|
|
{
|
|
// XIdlClass?
|
|
Reference< XIdlClass > xIdlClass;
|
|
|
|
SbxBaseRef pObj = pVal->GetObject();
|
|
if( auto obj = dynamic_cast<SbUnoObject*>( pObj.get() ) )
|
|
{
|
|
Any aUnoAny = obj->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.get() );
|
|
}
|
|
return;
|
|
}
|
|
|
|
// Check the type
|
|
const Reference< XHierarchicalNameAccess >& xTypeAccess = getTypeProvider_Impl();
|
|
Any aRet;
|
|
try
|
|
{
|
|
aRet = xTypeAccess->getByHierarchicalName( aTypeName );
|
|
}
|
|
catch( const NoSuchElementException& e1 )
|
|
{
|
|
StarBASIC::Error( ERRCODE_BASIC_EXCEPTION,
|
|
implGetExceptionMsg( e1, "com.sun.star.container.NoSuchElementException" ) );
|
|
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.get() );
|
|
}
|
|
|
|
|
|
class ModuleInvocationProxy : public WeakImplHelper< XInvocation, XComponent >
|
|
{
|
|
::osl::Mutex m_aMutex;
|
|
OUString m_aPrefix;
|
|
SbxObjectRef m_xScopeObj;
|
|
bool m_bProxyIsClassModuleObject;
|
|
|
|
::comphelper::OInterfaceContainerHelper2 m_aListeners;
|
|
|
|
public:
|
|
ModuleInvocationProxy( OUString const & aPrefix, SbxObjectRef const & xScopeObj );
|
|
|
|
// XInvocation
|
|
virtual Reference< XIntrospectionAccess > SAL_CALL getIntrospection() override;
|
|
virtual void SAL_CALL setValue( const OUString& rProperty, const Any& rValue ) override;
|
|
virtual Any SAL_CALL getValue( const OUString& rProperty ) override;
|
|
virtual sal_Bool SAL_CALL hasMethod( const OUString& rName ) override;
|
|
virtual sal_Bool SAL_CALL hasProperty( const OUString& rProp ) override;
|
|
|
|
virtual Any SAL_CALL invoke( const OUString& rFunction,
|
|
const Sequence< Any >& rParams,
|
|
Sequence< sal_Int16 >& rOutParamIndex,
|
|
Sequence< Any >& rOutParam ) override;
|
|
|
|
// XComponent
|
|
virtual void SAL_CALL dispose() override;
|
|
virtual void SAL_CALL addEventListener( const Reference< XEventListener >& xListener ) override;
|
|
virtual void SAL_CALL removeEventListener( const Reference< XEventListener >& aListener ) override;
|
|
};
|
|
|
|
ModuleInvocationProxy::ModuleInvocationProxy( OUString const & aPrefix, SbxObjectRef const & xScopeObj )
|
|
: m_aMutex()
|
|
, m_aPrefix( aPrefix + "_" )
|
|
, m_xScopeObj( xScopeObj )
|
|
, m_aListeners( m_aMutex )
|
|
{
|
|
m_bProxyIsClassModuleObject = xScopeObj.is() && dynamic_cast<const SbClassModuleObject*>( xScopeObj.get() ) != nullptr;
|
|
}
|
|
|
|
Reference< XIntrospectionAccess > SAL_CALL ModuleInvocationProxy::getIntrospection()
|
|
{
|
|
return Reference< XIntrospectionAccess >();
|
|
}
|
|
|
|
void SAL_CALL ModuleInvocationProxy::setValue(const OUString& rProperty, const Any& rValue)
|
|
{
|
|
if( !m_bProxyIsClassModuleObject )
|
|
throw UnknownPropertyException();
|
|
|
|
SolarMutexGuard guard;
|
|
|
|
OUString aPropertyFunctionName = "Property Set "
|
|
+ m_aPrefix
|
|
+ rProperty;
|
|
|
|
SbxVariable* p = m_xScopeObj->Find( aPropertyFunctionName, SbxClassType::Method );
|
|
SbMethod* pMeth = dynamic_cast<SbMethod*>( p );
|
|
if( pMeth == nullptr )
|
|
{
|
|
// TODO: Check vba behavior concerning missing function
|
|
//StarBASIC::Error( ERRCODE_BASIC_NO_METHOD, aFunctionName );
|
|
throw UnknownPropertyException(aPropertyFunctionName);
|
|
}
|
|
|
|
// Setup parameter
|
|
SbxArrayRef xArray = new SbxArray;
|
|
SbxVariableRef xVar = new SbxVariable( SbxVARIANT );
|
|
unoToSbxValue( xVar.get(), rValue );
|
|
xArray->Put( xVar.get(), 1 );
|
|
|
|
// Call property method
|
|
SbxVariableRef xValue = new SbxVariable;
|
|
pMeth->SetParameters( xArray.get() );
|
|
pMeth->Call( xValue.get() );
|
|
pMeth->SetParameters( nullptr );
|
|
|
|
// TODO: OutParameter?
|
|
|
|
|
|
}
|
|
|
|
Any SAL_CALL ModuleInvocationProxy::getValue(const OUString& rProperty)
|
|
{
|
|
if( !m_bProxyIsClassModuleObject )
|
|
{
|
|
throw UnknownPropertyException();
|
|
}
|
|
SolarMutexGuard guard;
|
|
|
|
OUString aPropertyFunctionName = "Property Get "
|
|
+ m_aPrefix
|
|
+ rProperty;
|
|
|
|
SbxVariable* p = m_xScopeObj->Find( aPropertyFunctionName, SbxClassType::Method );
|
|
SbMethod* pMeth = dynamic_cast<SbMethod*>( p );
|
|
if( pMeth == nullptr )
|
|
{
|
|
// TODO: Check vba behavior concerning missing function
|
|
//StarBASIC::Error( ERRCODE_BASIC_NO_METHOD, aFunctionName );
|
|
throw UnknownPropertyException(aPropertyFunctionName);
|
|
}
|
|
|
|
// Call method
|
|
SbxVariableRef xValue = new SbxVariable;
|
|
pMeth->Call( xValue.get() );
|
|
Any aRet = sbxToUnoValue( xValue.get() );
|
|
return aRet;
|
|
}
|
|
|
|
sal_Bool SAL_CALL ModuleInvocationProxy::hasMethod( const OUString& )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
sal_Bool SAL_CALL ModuleInvocationProxy::hasProperty( const OUString& )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
Any SAL_CALL ModuleInvocationProxy::invoke( const OUString& rFunction,
|
|
const Sequence< Any >& rParams,
|
|
Sequence< sal_Int16 >&,
|
|
Sequence< Any >& )
|
|
{
|
|
SolarMutexGuard guard;
|
|
|
|
Any aRet;
|
|
SbxObjectRef xScopeObj = m_xScopeObj;
|
|
if( !xScopeObj.is() )
|
|
{
|
|
return aRet;
|
|
}
|
|
OUString aFunctionName = m_aPrefix
|
|
+ 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, SbxClassType::Method );
|
|
SbMethod* pMeth = dynamic_cast<SbMethod*>( p );
|
|
if( pMeth == nullptr )
|
|
{
|
|
// TODO: Check vba behavior concerning missing function
|
|
//StarBASIC::Error( ERRCODE_BASIC_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( xVar.get(), pArgs[i] );
|
|
xArray->Put( xVar.get(), sal::static_int_cast< sal_uInt16 >(i+1) );
|
|
}
|
|
}
|
|
|
|
// Call method
|
|
SbxVariableRef xValue = new SbxVariable;
|
|
if( xArray.is() )
|
|
pMeth->SetParameters( xArray.get() );
|
|
pMeth->Call( xValue.get() );
|
|
aRet = sbxToUnoValue( xValue.get() );
|
|
pMeth->SetParameters( nullptr );
|
|
|
|
if( bSetRescheduleBack )
|
|
pInst->EnableReschedule( bOldReschedule );
|
|
|
|
// TODO: OutParameter?
|
|
|
|
return aRet;
|
|
}
|
|
|
|
void SAL_CALL ModuleInvocationProxy::dispose()
|
|
{
|
|
::osl::MutexGuard aGuard( m_aMutex );
|
|
|
|
EventObject aEvent( static_cast<XComponent*>(this) );
|
|
m_aListeners.disposeAndClear( aEvent );
|
|
|
|
m_xScopeObj = nullptr;
|
|
}
|
|
|
|
void SAL_CALL ModuleInvocationProxy::addEventListener( const Reference< XEventListener >& xListener )
|
|
{
|
|
m_aListeners.addInterface( xListener );
|
|
}
|
|
|
|
void SAL_CALL ModuleInvocationProxy::removeEventListener( const Reference< XEventListener >& xListener )
|
|
{
|
|
m_aListeners.removeInterface( xListener );
|
|
}
|
|
|
|
|
|
Reference< XInterface > createComListener( const Any& aControlAny, const OUString& aVBAType,
|
|
const OUString& aPrefix, const 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(
|
|
"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;
|
|
|
|
explicit StarBasicDisposeItem( StarBASIC* pBasic )
|
|
: m_pBasic( pBasic )
|
|
, m_pRegisteredVariables(new SbxArray())
|
|
{
|
|
}
|
|
};
|
|
|
|
typedef std::vector< StarBasicDisposeItem* > DisposeItemVector;
|
|
|
|
static DisposeItemVector GaDisposeItemVector;
|
|
|
|
static DisposeItemVector::iterator lcl_findItemForBasic( StarBASIC const * pBasic )
|
|
{
|
|
return std::find_if(GaDisposeItemVector.begin(), GaDisposeItemVector.end(),
|
|
[&pBasic](StarBasicDisposeItem* pItem) { return pItem->m_pBasic == pBasic; });
|
|
}
|
|
|
|
static StarBasicDisposeItem* lcl_getOrCreateItemForBasic( StarBASIC* pBasic )
|
|
{
|
|
DisposeItemVector::iterator it = lcl_findItemForBasic( pBasic );
|
|
StarBasicDisposeItem* pItem = (it != GaDisposeItemVector.end()) ? *it : nullptr;
|
|
if( pItem == nullptr )
|
|
{
|
|
pItem = new StarBasicDisposeItem( pBasic );
|
|
GaDisposeItemVector.push_back( pItem );
|
|
}
|
|
return pItem;
|
|
}
|
|
|
|
void registerComponentToBeDisposedForBasic
|
|
( const Reference< XComponent >& xComponent, StarBASIC* pBasic )
|
|
{
|
|
StarBasicDisposeItem* pItem = lcl_getOrCreateItemForBasic( pBasic );
|
|
pItem->m_vComImplementsObjects.emplace_back(xComponent );
|
|
}
|
|
|
|
void registerComListenerVariableForBasic( SbxVariable* pVar, StarBASIC* pBasic )
|
|
{
|
|
StarBasicDisposeItem* pItem = lcl_getOrCreateItemForBasic( pBasic );
|
|
SbxArray* pArray = pItem->m_pRegisteredVariables.get();
|
|
pArray->Put( pVar, pArray->Count() );
|
|
}
|
|
|
|
void disposeComVariablesForBasic( StarBASIC const * pBasic )
|
|
{
|
|
DisposeItemVector::iterator it = lcl_findItemForBasic( pBasic );
|
|
if( it != GaDisposeItemVector.end() )
|
|
{
|
|
StarBasicDisposeItem* pItem = *it;
|
|
|
|
SbxArray* pArray = pItem->m_pRegisteredVariables.get();
|
|
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;
|
|
for (auto const& elem : rv)
|
|
{
|
|
Reference< XComponent > xComponent( elem.get(), UNO_QUERY );
|
|
if (xComponent.is())
|
|
xComponent->dispose();
|
|
}
|
|
|
|
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( "com.sun.star.custom.ComImplementsFactory", xContext ),
|
|
UNO_QUERY
|
|
);
|
|
if( !xComImplementsFactory.is() )
|
|
return false;
|
|
|
|
bool bSuccess = false;
|
|
|
|
SbxArray* pModIfaces = pClassData->mxIfaces.get();
|
|
sal_uInt16 nCount = pModIfaces->Count();
|
|
for( sal_uInt16 i = 0 ; i < nCount ; ++i )
|
|
{
|
|
SbxVariable* pVar = pModIfaces->Get( i );
|
|
const 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;
|
|
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 = nullptr;
|
|
SbxObject* pCurObject = this;
|
|
do
|
|
{
|
|
SbxObject* pObjParent = pCurObject->GetParent();
|
|
pParentBasic = dynamic_cast<StarBASIC*>( pObjParent );
|
|
pCurObject = pObjParent;
|
|
}
|
|
while( pParentBasic == nullptr && pCurObject != nullptr );
|
|
|
|
OSL_ASSERT( pParentBasic != nullptr );
|
|
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;
|
|
|
|
if( auto pUnoObj = dynamic_cast<SbUnoObject*>( pObj) )
|
|
{
|
|
// Only for native COM objects
|
|
if( pUnoObj->isNativeCOMObject() )
|
|
{
|
|
SbxVariableRef pMeth = pObj->Find( "toString", SbxClassType::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) );
|
|
typelib_TypeDescription * pTD = nullptr;
|
|
maType.getDescription(&pTD);
|
|
uno_any_construct(
|
|
&aRet, getInst(), pTD,
|
|
reinterpret_cast< uno_AcquireFunc >(cpp_acquire) );
|
|
typelib_typedescription_release(pTD);
|
|
return aRet;
|
|
}
|
|
|
|
void StructRefInfo::setValue( const Any& rValue )
|
|
{
|
|
bool bSuccess = uno_type_assignData( getInst(),
|
|
maType.getTypeLibType(),
|
|
const_cast<void*>(rValue.getValue()),
|
|
rValue.getValueTypeRef(),
|
|
reinterpret_cast< uno_QueryInterfaceFunc >(cpp_queryInterface),
|
|
reinterpret_cast< uno_AcquireFunc >(cpp_acquire),
|
|
reinterpret_cast< uno_ReleaseFunc >(cpp_release) );
|
|
OSL_ENSURE(bSuccess,
|
|
"StructRefInfo::setValue: ooops... the value could not be assigned!");
|
|
}
|
|
|
|
OUString StructRefInfo::getTypeName() const
|
|
{
|
|
return maType.getTypeName();
|
|
}
|
|
|
|
void* StructRefInfo::getInst()
|
|
{
|
|
return const_cast<char *>(static_cast<char const *>(maAny.getValue()) + mnPos);
|
|
}
|
|
|
|
TypeClass StructRefInfo::getTypeClass() const
|
|
{
|
|
return maType.getTypeClass();
|
|
}
|
|
|
|
SbUnoStructRefObject::SbUnoStructRefObject( const OUString& aName_, const StructRefInfo& rMemberInfo ) : SbxObject( aName_ ), maMemberInfo( rMemberInfo ), mbMemberCacheInit( false )
|
|
{
|
|
SetClassName( maMemberInfo.getTypeName() );
|
|
}
|
|
|
|
SbUnoStructRefObject::~SbUnoStructRefObject()
|
|
{
|
|
}
|
|
|
|
void SbUnoStructRefObject::initMemberCache()
|
|
{
|
|
if ( mbMemberCacheInit )
|
|
return;
|
|
typelib_TypeDescription * pTD = nullptr;
|
|
maMemberInfo.getType().getDescription(&pTD);
|
|
typelib_CompoundTypeDescription * pCompTypeDescr = reinterpret_cast<typelib_CompoundTypeDescription *>(pTD);
|
|
for ( pCompTypeDescr = reinterpret_cast<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--; )
|
|
{
|
|
OUString aName( ppNames[nPos] );
|
|
maFields[ aName ] = std::make_unique<StructRefInfo>( maMemberInfo.getRootAnyRef(), ppTypeRefs[nPos], maMemberInfo.getPos() + pMemberOffsets[nPos] );
|
|
}
|
|
}
|
|
typelib_typedescription_release(pTD);
|
|
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( rName );
|
|
if ( it != maFields.end() )
|
|
{
|
|
SbxDataType eSbxType;
|
|
eSbxType = unoToSbxType( it->second->getTypeClass() );
|
|
SbxDataType eRealSbxType = eSbxType;
|
|
Property aProp;
|
|
aProp.Name = rName;
|
|
aProp.Type = css::uno::Type( it->second->getTypeClass(), it->second->getTypeName() );
|
|
SbUnoProperty* pProp = new SbUnoProperty( rName, eSbxType, eRealSbxType, aProp, 0, false, ( aProp.Type.getTypeClass() == css::uno::TypeClass_STRUCT) );
|
|
SbxVariableRef xVarRef = pProp;
|
|
QuickInsert( xVarRef.get() );
|
|
pRes = xVarRef.get();
|
|
}
|
|
}
|
|
|
|
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, SbxClassType::DontCare );
|
|
}
|
|
}
|
|
|
|
return pRes;
|
|
}
|
|
|
|
// help method to create the dbg_-Properties
|
|
void SbUnoStructRefObject::implCreateDbgProperties()
|
|
{
|
|
Property aProp;
|
|
|
|
// Id == -1: display the implemented interfaces corresponding the ClassProvider
|
|
SbxVariableRef xVarRef = new SbUnoProperty( ID_DBG_SUPPORTEDINTERFACES, SbxSTRING, SbxSTRING, aProp, -1, false, false );
|
|
QuickInsert( xVarRef.get() );
|
|
|
|
// Id == -2: output the properties
|
|
xVarRef = new SbUnoProperty( ID_DBG_PROPERTIES, SbxSTRING, SbxSTRING, aProp, -2, false, false );
|
|
QuickInsert( xVarRef.get() );
|
|
|
|
// Id == -3: output the Methods
|
|
xVarRef = new SbUnoProperty( ID_DBG_METHODS, SbxSTRING, SbxSTRING, aProp, -3, false, false );
|
|
QuickInsert( xVarRef.get() );
|
|
}
|
|
|
|
void SbUnoStructRefObject::implCreateAll()
|
|
{
|
|
// throw away all existing methods and properties
|
|
pMethods = new SbxArray;
|
|
pProps = new SbxArray;
|
|
|
|
if (!mbMemberCacheInit)
|
|
initMemberCache();
|
|
|
|
for (auto const& field : maFields)
|
|
{
|
|
const OUString& rName = field.first;
|
|
SbxDataType eSbxType;
|
|
eSbxType = unoToSbxType( field.second->getTypeClass() );
|
|
SbxDataType eRealSbxType = eSbxType;
|
|
Property aProp;
|
|
aProp.Name = rName;
|
|
aProp.Type = css::uno::Type( field.second->getTypeClass(), field.second->getTypeName() );
|
|
SbUnoProperty* pProp = new SbUnoProperty( rName, eSbxType, eRealSbxType, aProp, 0, false, ( aProp.Type.getTypeClass() == css::uno::TypeClass_STRUCT) );
|
|
SbxVariableRef xVarRef = pProp;
|
|
QuickInsert( xVarRef.get() );
|
|
}
|
|
|
|
// Create Dbg_-Properties
|
|
implCreateDbgProperties();
|
|
}
|
|
|
|
// output the value
|
|
Any SbUnoStructRefObject::getUnoAny()
|
|
{
|
|
return maMemberInfo.getValue();
|
|
}
|
|
|
|
OUString SbUnoStructRefObject::Impl_DumpProperties()
|
|
{
|
|
OUStringBuffer aRet;
|
|
aRet.append("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.append( "\n" );
|
|
}
|
|
// output the type and name
|
|
// Is it in Uno a sequence?
|
|
SbxDataType eType = pVar->GetFullType();
|
|
|
|
const 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 ) );
|
|
|
|
aPropStr.append( " " );
|
|
aPropStr.append( pVar->GetName() );
|
|
|
|
if( i == nPropCount - 1 )
|
|
{
|
|
aPropStr.append( "\n" );
|
|
}
|
|
else
|
|
{
|
|
aPropStr.append( "; " );
|
|
}
|
|
aRet.append( aPropStr.makeStringAndClear() );
|
|
}
|
|
}
|
|
return aRet.makeStringAndClear();
|
|
}
|
|
|
|
void SbUnoStructRefObject::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
|
|
{
|
|
if ( !mbMemberCacheInit )
|
|
initMemberCache();
|
|
const SbxHint* pHint = dynamic_cast<const SbxHint*>(&rHint);
|
|
if( pHint )
|
|
{
|
|
SbxVariable* pVar = pHint->GetVar();
|
|
SbUnoProperty* pProp = dynamic_cast<SbUnoProperty*>( pVar );
|
|
if( pProp )
|
|
{
|
|
StructFieldInfo::iterator it = maFields.find( pProp->GetName() );
|
|
// handle get/set of members of struct
|
|
if( pHint->GetId() == SfxHintId::BasicDataWanted )
|
|
{
|
|
// 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 aRet = OUStringLiteral( ID_DBG_SUPPORTEDINTERFACES )
|
|
+ " not available.\n(TypeClass is not TypeClass_INTERFACE)\n";
|
|
|
|
pVar->PutString( aRet );
|
|
}
|
|
// 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();
|
|
OUString aRet = "Methods of object "
|
|
+ getDbgObjectName()
|
|
+ "\nNo methods found\n";
|
|
pVar->PutString( aRet );
|
|
}
|
|
return;
|
|
}
|
|
|
|
if ( it != maFields.end() )
|
|
{
|
|
Any aRetAny = it->second->getValue();
|
|
unoToSbxValue( pVar, aRetAny );
|
|
}
|
|
else
|
|
StarBASIC::Error( ERRCODE_BASIC_PROPERTY_NOT_FOUND );
|
|
}
|
|
else if( pHint->GetId() == SfxHintId::BasicDataChanged )
|
|
{
|
|
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( ERRCODE_BASIC_PROPERTY_NOT_FOUND );
|
|
}
|
|
}
|
|
else
|
|
SbxObject::Notify( rBC, rHint );
|
|
}
|
|
}
|
|
|
|
StructRefInfo SbUnoStructRefObject::getStructMember( const OUString& rMemberName )
|
|
{
|
|
if (!mbMemberCacheInit)
|
|
{
|
|
initMemberCache();
|
|
}
|
|
StructFieldInfo::iterator it = maFields.find( rMemberName );
|
|
|
|
css::uno::Type aFoundType;
|
|
sal_Int32 nFoundPos = -1;
|
|
|
|
if ( it != maFields.end() )
|
|
{
|
|
aFoundType = it->second->getType();
|
|
nFoundPos = it->second->getPos();
|
|
}
|
|
StructRefInfo aRet( maMemberInfo.getRootAnyRef(), aFoundType, nFoundPos );
|
|
return aRet;
|
|
}
|
|
|
|
OUString SbUnoStructRefObject::getDbgObjectName() const
|
|
{
|
|
OUString aName = GetClassName();
|
|
if( aName.isEmpty() )
|
|
{
|
|
aName += "Unknown";
|
|
}
|
|
OUStringBuffer aRet;
|
|
if( aName.getLength() > 20 )
|
|
{
|
|
aRet.append( "\n" );
|
|
}
|
|
aRet.append( "\"" );
|
|
aRet.append( aName );
|
|
aRet.append( "\":" );
|
|
return aRet.makeStringAndClear();
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|