4a9100592c
2005/09/05 12:59:32 rt 1.13.148.1: #i54170# Change license header: remove SISSL
2211 lines
84 KiB
C++
2211 lines
84 KiB
C++
/*************************************************************************
|
|
*
|
|
* OpenOffice.org - a multi-platform office productivity suite
|
|
*
|
|
* $RCSfile: oleobjw.cxx,v $
|
|
*
|
|
* $Revision: 1.14 $
|
|
*
|
|
* last change: $Author: rt $ $Date: 2005-09-08 19:44:09 $
|
|
*
|
|
* The Contents of this file are made available subject to
|
|
* the terms of GNU Lesser General Public License Version 2.1.
|
|
*
|
|
*
|
|
* GNU Lesser General Public License Version 2.1
|
|
* =============================================
|
|
* Copyright 2005 by Sun Microsystems, Inc.
|
|
* 901 San Antonio Road, Palo Alto, CA 94303, USA
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License version 2.1, as published by the Free Software Foundation.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
|
* MA 02111-1307 USA
|
|
*
|
|
************************************************************************/
|
|
#include "ole2uno.hxx"
|
|
#include "rtl/ustrbuf.hxx"
|
|
|
|
|
|
#include "osl/diagnose.h"
|
|
#include "osl/doublecheckedlocking.h"
|
|
#include "osl/thread.h"
|
|
|
|
#include "boost/scoped_array.hpp"
|
|
|
|
#ifndef _COM_SUN_STAR_SCRIPT_FAILREASON_HPP_
|
|
#include <com/sun/star/script/FailReason.hpp>
|
|
#endif
|
|
#ifndef _COM_SUN_STAR_BEANS_XMATERIALHOLDER_HPP_
|
|
#include <com/sun/star/beans/XMaterialHolder.hpp>
|
|
#endif
|
|
#ifndef _COM_SUN_STAR_SCRIPT_XTYPECONVERTER_HPP_
|
|
#include <com/sun/star/script/XTypeConverter.hpp>
|
|
#endif
|
|
#ifndef _COM_SUN_STAR_SCRIPT_FINISHENGINEEVENT_HPP_
|
|
#include <com/sun/star/script/FinishEngineEvent.hpp>
|
|
#endif
|
|
#ifndef _COM_SUN_STAR_SCRIPT_INTERRUPTREASON_HPP_
|
|
#include <com/sun/star/script/InterruptReason.hpp>
|
|
#endif
|
|
#ifndef _COM_SUN_STAR_SCRIPT_XENGINELISTENER_HPP_
|
|
#include <com/sun/star/script/XEngineListener.hpp>
|
|
#endif
|
|
#ifndef _COM_SUN_STAR_SCRIPT_XDEBUGGING_HPP_
|
|
#include <com/sun/star/script/XDebugging.hpp>
|
|
#endif
|
|
#ifndef _COM_SUN_STAR_SCRIPT_XINVOCATION_HPP_
|
|
#include <com/sun/star/script/XInvocation.hpp>
|
|
#endif
|
|
#ifndef _COM_SUN_STAR_SCRIPT_CONTEXTINFORMATION_HPP_
|
|
#include <com/sun/star/script/ContextInformation.hpp>
|
|
#endif
|
|
#ifndef _COM_SUN_STAR_SCRIPT_FINISHREASON_HPP_
|
|
#include <com/sun/star/script/FinishReason.hpp>
|
|
#endif
|
|
#ifndef _COM_SUN_STAR_SCRIPT_XENGINE_HPP_
|
|
#include <com/sun/star/script/XEngine.hpp>
|
|
#endif
|
|
#ifndef _COM_SUN_STAR_SCRIPT_INTERRUPTENGINEEVENT_HPP_
|
|
#include <com/sun/star/script/InterruptEngineEvent.hpp>
|
|
#endif
|
|
#ifndef _COM_SUN_STAR_SCRIPT_XLIBRARYACCESS_HPP_
|
|
#include <com/sun/star/script/XLibraryAccess.hpp>
|
|
#endif
|
|
|
|
#ifndef _COM_SUN_STAR_BRIDGE_MODELDEPENDENT_HPP_
|
|
#include <com/sun/star/bridge/ModelDependent.hpp>
|
|
#endif
|
|
|
|
#include "com/sun/star/bridge/oleautomation/NamedArgument.hpp"
|
|
#include "com/sun/star/bridge/oleautomation/PropertyPutArgument.hpp"
|
|
|
|
#include <typelib/typedescription.hxx>
|
|
#include <rtl/uuid.h>
|
|
#include <rtl/memory.h>
|
|
#ifndef _RTL_USTRING_
|
|
#include <rtl/ustring>
|
|
#endif
|
|
|
|
#include "jscriptclasses.hxx"
|
|
|
|
#include "oleobjw.hxx"
|
|
#include "unoobjw.hxx"
|
|
#include <stdio.h>
|
|
using namespace std;
|
|
using namespace boost;
|
|
using namespace osl;
|
|
using namespace rtl;
|
|
using namespace cppu;
|
|
using namespace com::sun::star::lang;
|
|
using namespace com::sun::star::bridge;
|
|
using namespace com::sun::star::bridge::oleautomation;
|
|
using namespace com::sun::star::bridge::ModelDependent;
|
|
|
|
#define JSCRIPT_ID_PROPERTY L"_environment"
|
|
#define JSCRIPT_ID L"jscript"
|
|
namespace ole_adapter
|
|
{
|
|
|
|
|
|
// key: XInterface pointer created by Invocation Adapter Factory
|
|
// value: XInterface pointer to the wrapper class.
|
|
// Entries to the map are made within
|
|
// Any createOleObjectWrapper(IUnknown* pUnknown, const Type& aType);
|
|
// Entries are being deleted if the wrapper class's destructor has been
|
|
// called.
|
|
// Before UNO object is wrapped to COM object this map is checked
|
|
// to see if the UNO object is already a wrapper.
|
|
hash_map<sal_uInt32, sal_uInt32> AdapterToWrapperMap;
|
|
// key: XInterface of the wrapper object.
|
|
// value: XInterface of the Interface created by the Invocation Adapter Factory.
|
|
// A COM wrapper is responsible for removing the corresponding entry
|
|
// in AdapterToWrappperMap if it is being destroyed. Because the wrapper does not
|
|
// know about its adapted interface it uses WrapperToAdapterMap to get the
|
|
// adapted interface which is then used to locate the entry in AdapterToWrapperMap.
|
|
hash_map<sal_uInt32,sal_uInt32> WrapperToAdapterMap;
|
|
|
|
hash_map<sal_uInt32, WeakReference<XInterface> > ComPtrToWrapperMap;
|
|
/*****************************************************************************
|
|
|
|
class implementation IUnknownWrapper_Impl
|
|
|
|
*****************************************************************************/
|
|
|
|
IUnknownWrapper_Impl::IUnknownWrapper_Impl( Reference<XMultiServiceFactory>& xFactory,
|
|
sal_uInt8 unoWrapperClass, sal_uInt8 comWrapperClass):
|
|
UnoConversionUtilities<IUnknownWrapper_Impl>( xFactory, unoWrapperClass, comWrapperClass),
|
|
m_pxIdlClass( NULL), m_eJScript( JScriptUndefined),
|
|
m_bComTlbIndexInit(false)
|
|
{
|
|
}
|
|
|
|
|
|
IUnknownWrapper_Impl::~IUnknownWrapper_Impl()
|
|
{
|
|
o2u_attachCurrentThread();
|
|
MutexGuard guard(getBridgeMutex());
|
|
XInterface * xIntRoot = (OWeakObject *)this;
|
|
#if OSL_DEBUG_LEVEL > 0
|
|
acquire(); // make sure we don't delete us twice because of Reference
|
|
OSL_ASSERT( Reference<XInterface>( static_cast<XWeak*>(this), UNO_QUERY).get() == xIntRoot );
|
|
#endif
|
|
|
|
// remove entries in global maps
|
|
typedef hash_map<sal_uInt32, sal_uInt32>::iterator _IT;
|
|
_IT it= WrapperToAdapterMap.find( (sal_uInt32) xIntRoot);
|
|
if( it != WrapperToAdapterMap.end())
|
|
{
|
|
sal_uInt32 adapter= it->second;
|
|
|
|
AdapterToWrapperMap.erase( adapter);
|
|
WrapperToAdapterMap.erase( it);
|
|
}
|
|
|
|
IT_Com it_c= ComPtrToWrapperMap.find( (sal_uInt32) m_spUnknown.p);
|
|
if(it_c != ComPtrToWrapperMap.end())
|
|
ComPtrToWrapperMap.erase(it_c);
|
|
|
|
#if OSL_DEBUG_LEVEL > 0
|
|
fprintf(stderr,"[automation bridge] ComPtrToWrapperMap contains: %i \n",
|
|
ComPtrToWrapperMap.size());
|
|
#endif
|
|
}
|
|
|
|
Any IUnknownWrapper_Impl::queryInterface(const Type& t)
|
|
throw (RuntimeException)
|
|
{
|
|
if (t == getCppuType(static_cast<Reference<XInvocation>*>( 0)))
|
|
{
|
|
if (m_spDispatch)
|
|
return WeakImplHelper4<XInvocation, XBridgeSupplier2,
|
|
XInitialization, XAutomationObject>::queryInterface(t);
|
|
else
|
|
return Any();
|
|
}
|
|
|
|
return WeakImplHelper4<XInvocation, XBridgeSupplier2,
|
|
XInitialization, XAutomationObject>::queryInterface(t);
|
|
}
|
|
|
|
Reference<XIntrospectionAccess> SAL_CALL IUnknownWrapper_Impl::getIntrospection(void)
|
|
throw (RuntimeException )
|
|
{
|
|
Reference<XIntrospectionAccess> ret;
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
|
|
Any SAL_CALL IUnknownWrapper_Impl::invoke( const OUString& aFunctionName,
|
|
const Sequence< Any >& aParams, Sequence< sal_Int16 >& aOutParamIndex,
|
|
Sequence< Any >& aOutParam )
|
|
throw(IllegalArgumentException, CannotConvertException, InvocationTargetException,
|
|
RuntimeException)
|
|
{
|
|
if ( ! m_spDispatch )
|
|
{
|
|
throw RuntimeException(
|
|
OUSTR("[automation bridge] The object does not have an IDispatch interface"),
|
|
Reference<XInterface>());
|
|
}
|
|
|
|
Any ret;
|
|
|
|
try
|
|
{
|
|
o2u_attachCurrentThread();
|
|
|
|
TypeDescription methodDesc;
|
|
getMethodInfo(aFunctionName, methodDesc);
|
|
if( methodDesc.is())
|
|
{
|
|
ret = invokeWithDispIdUnoTlb(aFunctionName,
|
|
aParams,
|
|
aOutParamIndex,
|
|
aOutParam);
|
|
}
|
|
else
|
|
{
|
|
ret= invokeWithDispIdComTlb( aFunctionName,
|
|
aParams,
|
|
aOutParamIndex,
|
|
aOutParam);
|
|
}
|
|
}
|
|
catch (IllegalArgumentException &)
|
|
{
|
|
throw;
|
|
}
|
|
catch (CannotConvertException &)
|
|
{
|
|
throw;
|
|
}
|
|
catch (BridgeRuntimeError & e)
|
|
{
|
|
throw RuntimeException(e.message, Reference<XInterface>());
|
|
}
|
|
catch (Exception & e)
|
|
{
|
|
throw RuntimeException(OUSTR("[automation bridge] unexpected exception in "
|
|
"IUnknownWrapper_Impl::invoke ! Message : \n") +
|
|
e.Message, Reference<XInterface>());
|
|
|
|
}
|
|
catch(...)
|
|
{
|
|
throw RuntimeException(
|
|
OUSTR("[automation bridge] unexpected exception in "
|
|
"IUnknownWrapper_Impl::Invoke !"), Reference<XInterface>());
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
void SAL_CALL IUnknownWrapper_Impl::setValue( const OUString& aPropertyName,
|
|
const Any& aValue )
|
|
throw(UnknownPropertyException, CannotConvertException, InvocationTargetException,
|
|
RuntimeException)
|
|
{
|
|
if ( ! m_spDispatch )
|
|
{
|
|
throw RuntimeException(
|
|
OUSTR("[automation bridge] The object does not have an IDispatch interface"),
|
|
Reference<XInterface>());
|
|
}
|
|
try
|
|
{
|
|
o2u_attachCurrentThread();
|
|
|
|
ITypeInfo * pInfo = getTypeInfo();
|
|
FuncDesc aDescGet(pInfo);
|
|
FuncDesc aDescPut(pInfo);
|
|
VarDesc aVarDesc(pInfo);
|
|
getPropDesc(aPropertyName, & aDescGet, & aDescPut, & aVarDesc);
|
|
//check if there is such a property at all or if it is read only
|
|
if ( ! aDescPut && ! aDescGet && ! aVarDesc)
|
|
{
|
|
OUString msg(OUSTR("[automation bridge]Property \"") + aPropertyName +
|
|
OUSTR("\" is not supported"));
|
|
throw UnknownPropertyException(msg, Reference<XInterface>());
|
|
}
|
|
|
|
if ( (! aDescPut && aDescGet) || aVarDesc
|
|
&& aVarDesc->wVarFlags == VARFLAG_FREADONLY )
|
|
{
|
|
//read-only
|
|
OUString msg(OUSTR("[automation bridge] Property ") + aPropertyName +
|
|
OUSTR(" is read-only"));
|
|
OString sMsg = OUStringToOString(msg, osl_getThreadTextEncoding());
|
|
OSL_ENSURE(0, sMsg.getStr());
|
|
// ignore silently
|
|
return;
|
|
}
|
|
|
|
HRESULT hr= S_OK;
|
|
DISPPARAMS dispparams;
|
|
CComVariant varArg;
|
|
CComVariant varRefArg;
|
|
CComVariant varResult;
|
|
ExcepInfo excepinfo;
|
|
unsigned int uArgErr;
|
|
|
|
// converting UNO value to OLE variant
|
|
DISPID dispidPut= DISPID_PROPERTYPUT;
|
|
dispparams.rgdispidNamedArgs = &dispidPut;
|
|
dispparams.cArgs = 1;
|
|
dispparams.cNamedArgs = 1;
|
|
dispparams.rgvarg = & varArg;
|
|
|
|
OSL_ASSERT(aDescPut || aVarDesc);
|
|
|
|
VARTYPE vt = 0;
|
|
DISPID dispid = 0;
|
|
INVOKEKIND invkind = INVOKE_PROPERTYPUT;
|
|
//determine the expected type, dispid, invoke kind (DISPATCH_PROPERTYPUT,
|
|
//DISPATCH_PROPERTYPUTREF)
|
|
if (aDescPut)
|
|
{
|
|
vt = getElementTypeDesc(& aDescPut->lprgelemdescParam[0].tdesc);
|
|
dispid = aDescPut->memid;
|
|
invkind = aDescPut->invkind;
|
|
}
|
|
else
|
|
{
|
|
vt = getElementTypeDesc( & aVarDesc->elemdescVar.tdesc);
|
|
dispid = aVarDesc->memid;
|
|
if (vt == VT_UNKNOWN || vt == VT_DISPATCH ||
|
|
(vt & VT_ARRAY) || (vt & VT_BYREF))
|
|
{
|
|
invkind = INVOKE_PROPERTYPUTREF;
|
|
}
|
|
}
|
|
|
|
// convert the uno argument
|
|
if (vt & VT_BYREF)
|
|
{
|
|
anyToVariant( & varRefArg, aValue, vt ^ VT_BYREF);
|
|
varArg.vt = vt;
|
|
if( (vt & VT_TYPEMASK) == VT_VARIANT)
|
|
varArg.byref = & varRefArg;
|
|
else if ((vt & VT_TYPEMASK) == VT_DECIMAL)
|
|
varArg.byref = & varRefArg.decVal;
|
|
else
|
|
varArg.byref = & varRefArg.byref;
|
|
}
|
|
else
|
|
{
|
|
anyToVariant(& varArg, aValue, vt);
|
|
}
|
|
// call to IDispatch
|
|
hr = m_spDispatch->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, invkind,
|
|
&dispparams, & varResult, & excepinfo, &uArgErr);
|
|
|
|
// lookup error code
|
|
switch (hr)
|
|
{
|
|
case S_OK:
|
|
break;
|
|
case DISP_E_BADPARAMCOUNT:
|
|
throw RuntimeException();
|
|
break;
|
|
case DISP_E_BADVARTYPE:
|
|
throw RuntimeException();
|
|
break;
|
|
case DISP_E_EXCEPTION:
|
|
throw InvocationTargetException();
|
|
break;
|
|
case DISP_E_MEMBERNOTFOUND:
|
|
throw UnknownPropertyException();
|
|
break;
|
|
case DISP_E_NONAMEDARGS:
|
|
throw RuntimeException();
|
|
break;
|
|
case DISP_E_OVERFLOW:
|
|
throw CannotConvertException(L"call to OLE object failed", static_cast<XInterface*>(
|
|
static_cast<XWeak*>(this)), TypeClass_UNKNOWN, FailReason::OUT_OF_RANGE, uArgErr);
|
|
break;
|
|
case DISP_E_PARAMNOTFOUND:
|
|
throw IllegalArgumentException(L"call to OLE object failed", static_cast<XInterface*>(
|
|
static_cast<XWeak*>(this)), uArgErr) ;
|
|
break;
|
|
case DISP_E_TYPEMISMATCH:
|
|
throw CannotConvertException(L"call to OLE object failed", static_cast<XInterface*>(
|
|
static_cast<XWeak*>(this)), TypeClass_UNKNOWN, FailReason::UNKNOWN, uArgErr);
|
|
break;
|
|
case DISP_E_UNKNOWNINTERFACE:
|
|
throw RuntimeException();
|
|
break;
|
|
case DISP_E_UNKNOWNLCID:
|
|
throw RuntimeException();
|
|
break;
|
|
case DISP_E_PARAMNOTOPTIONAL:
|
|
throw CannotConvertException(L"call to OLE object failed",static_cast<XInterface*>(
|
|
static_cast<XWeak*>(this)) , TypeClass_UNKNOWN, FailReason::NO_DEFAULT_AVAILABLE, uArgErr);
|
|
break;
|
|
default:
|
|
throw RuntimeException();
|
|
break;
|
|
}
|
|
}
|
|
catch (CannotConvertException &)
|
|
{
|
|
throw;
|
|
}
|
|
catch (UnknownPropertyException &)
|
|
{
|
|
throw;
|
|
}
|
|
catch (BridgeRuntimeError& e)
|
|
{
|
|
throw RuntimeException(
|
|
e.message, Reference<XInterface>());
|
|
}
|
|
catch (Exception & e)
|
|
{
|
|
throw RuntimeException(OUSTR("[automation bridge] unexpected exception in "
|
|
"IUnknownWrapper_Impl::setValue ! Message : \n") +
|
|
e.Message, Reference<XInterface>());
|
|
|
|
}
|
|
catch (...)
|
|
{
|
|
throw RuntimeException(
|
|
OUSTR("[automation bridge] unexpected exception in "
|
|
"IUnknownWrapper_Impl::setValue !"), Reference<XInterface>());
|
|
}
|
|
}
|
|
|
|
Any SAL_CALL IUnknownWrapper_Impl::getValue( const OUString& aPropertyName )
|
|
throw(UnknownPropertyException, RuntimeException)
|
|
{
|
|
if ( ! m_spDispatch )
|
|
{
|
|
throw RuntimeException(
|
|
OUSTR("[automation bridge] The object does not have an IDispatch interface"),
|
|
Reference<XInterface>());
|
|
}
|
|
Any ret;
|
|
try
|
|
{
|
|
o2u_attachCurrentThread();
|
|
ITypeInfo * pInfo = getTypeInfo();
|
|
FuncDesc aDescGet(pInfo);
|
|
FuncDesc aDescPut(pInfo);
|
|
VarDesc aVarDesc(pInfo);
|
|
getPropDesc(aPropertyName, & aDescGet, & aDescPut, & aVarDesc);
|
|
if ( ! aDescGet && ! aDescPut && ! aVarDesc)
|
|
{
|
|
//property not found
|
|
OUString msg(OUSTR("[automation bridge]Property \"") + aPropertyName +
|
|
OUSTR("\" is not supported"));
|
|
throw UnknownPropertyException(msg, Reference<XInterface>());
|
|
}
|
|
// write-only should not be possible
|
|
OSL_ASSERT( aDescGet || ! aDescPut);
|
|
|
|
HRESULT hr;
|
|
DISPPARAMS dispparams = {0, 0, 0, 0};
|
|
CComVariant varResult;
|
|
ExcepInfo excepinfo;
|
|
unsigned int uArgErr;
|
|
DISPID dispid;
|
|
if (aDescGet)
|
|
dispid = aDescGet->memid;
|
|
else if (aVarDesc)
|
|
dispid = aVarDesc->memid;
|
|
else
|
|
dispid = aDescPut->memid;
|
|
|
|
hr = m_spDispatch->Invoke(dispid,
|
|
IID_NULL,
|
|
LOCALE_USER_DEFAULT,
|
|
DISPATCH_PROPERTYGET,
|
|
&dispparams,
|
|
&varResult,
|
|
&excepinfo,
|
|
&uArgErr);
|
|
|
|
// converting return value and out parameter back to UNO
|
|
if (hr == S_OK)
|
|
{
|
|
// If the com object implements uno interfaces then we have
|
|
// to convert the attribute into the expected type.
|
|
TypeDescription attrInfo;
|
|
getAttributeInfo(aPropertyName, attrInfo);
|
|
if( attrInfo.is() )
|
|
variantToAny( &varResult, ret, Type( attrInfo.get()->pWeakRef));
|
|
else
|
|
variantToAny(&varResult, ret);
|
|
}
|
|
|
|
// lookup error code
|
|
switch (hr)
|
|
{
|
|
case S_OK:
|
|
break;
|
|
case DISP_E_BADPARAMCOUNT:
|
|
throw RuntimeException(OUString(excepinfo.bstrDescription),
|
|
Reference<XInterface>());
|
|
break;
|
|
case DISP_E_BADVARTYPE:
|
|
throw RuntimeException(OUString(excepinfo.bstrDescription),
|
|
Reference<XInterface>());
|
|
break;
|
|
case DISP_E_EXCEPTION:
|
|
throw RuntimeException(OUString(excepinfo.bstrDescription),
|
|
Reference<XInterface>());
|
|
break;
|
|
case DISP_E_MEMBERNOTFOUND:
|
|
throw UnknownPropertyException(OUString(excepinfo.bstrDescription),
|
|
Reference<XInterface>());
|
|
break;
|
|
case DISP_E_NONAMEDARGS:
|
|
throw RuntimeException(OUString(excepinfo.bstrDescription),
|
|
Reference<XInterface>());
|
|
break;
|
|
case DISP_E_OVERFLOW:
|
|
throw RuntimeException(OUString(excepinfo.bstrDescription),
|
|
Reference<XInterface>());
|
|
break;
|
|
case DISP_E_PARAMNOTFOUND:
|
|
throw RuntimeException(OUString(excepinfo.bstrDescription),
|
|
Reference<XInterface>());
|
|
break;
|
|
case DISP_E_TYPEMISMATCH:
|
|
throw RuntimeException(OUString(excepinfo.bstrDescription),
|
|
Reference<XInterface>());
|
|
break;
|
|
case DISP_E_UNKNOWNINTERFACE:
|
|
throw RuntimeException(OUString(excepinfo.bstrDescription),
|
|
Reference<XInterface>());
|
|
break;
|
|
case DISP_E_UNKNOWNLCID:
|
|
throw RuntimeException(OUString(excepinfo.bstrDescription),
|
|
Reference<XInterface>());
|
|
break;
|
|
case DISP_E_PARAMNOTOPTIONAL:
|
|
throw RuntimeException(OUString(excepinfo.bstrDescription),
|
|
Reference<XInterface>());
|
|
break;
|
|
default:
|
|
throw RuntimeException(OUString(excepinfo.bstrDescription),
|
|
Reference<XInterface>());
|
|
break;
|
|
}
|
|
}
|
|
catch (UnknownPropertyException& )
|
|
{
|
|
throw;
|
|
}
|
|
catch (BridgeRuntimeError& e)
|
|
{
|
|
throw RuntimeException(
|
|
e.message, Reference<XInterface>());
|
|
}
|
|
catch (Exception & e)
|
|
{
|
|
throw RuntimeException(OUSTR("[automation bridge] unexpected exception in "
|
|
"IUnknownWrapper_Impl::getValue ! Message : \n") +
|
|
e.Message, Reference<XInterface>());
|
|
}
|
|
catch (...)
|
|
{
|
|
throw RuntimeException(
|
|
OUSTR("[automation bridge] unexpected exception in "
|
|
"IUnknownWrapper_Impl::getValue !"), Reference<XInterface>());
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
sal_Bool SAL_CALL IUnknownWrapper_Impl::hasMethod( const OUString& aName )
|
|
throw(RuntimeException)
|
|
{
|
|
if ( ! m_spDispatch )
|
|
{
|
|
throw RuntimeException(
|
|
OUSTR("[automation bridge] The object does not have an IDispatch interface"),
|
|
Reference<XInterface>());
|
|
}
|
|
sal_Bool ret = sal_False;
|
|
|
|
try
|
|
{
|
|
o2u_attachCurrentThread();
|
|
ITypeInfo* pInfo = getTypeInfo();
|
|
FuncDesc aDesc(pInfo);
|
|
getFuncDesc(aName, & aDesc);
|
|
// Automation properties can have arguments. Those are treated as methods and
|
|
//are called through XInvocation::invoke.
|
|
if ( ! aDesc)
|
|
{
|
|
FuncDesc aDescGet(pInfo);
|
|
FuncDesc aDescPut(pInfo);
|
|
VarDesc aVarDesc(pInfo);
|
|
getPropDesc( aName, & aDescGet, & aDescPut, & aVarDesc);
|
|
if (aDescGet && aDescGet->cParams > 0
|
|
|| aDescPut && aDescPut->cParams > 0)
|
|
ret = sal_True;
|
|
}
|
|
else
|
|
ret = sal_True;
|
|
}
|
|
catch (BridgeRuntimeError& e)
|
|
{
|
|
throw RuntimeException(e.message, Reference<XInterface>());
|
|
}
|
|
catch (Exception & e)
|
|
{
|
|
throw RuntimeException(OUSTR("[automation bridge] unexpected exception in "
|
|
"IUnknownWrapper_Impl::hasMethod ! Message : \n") +
|
|
e.Message, Reference<XInterface>());
|
|
}
|
|
catch (...)
|
|
{
|
|
throw RuntimeException(OUSTR("[automation bridge] unexpected exception in "
|
|
"IUnknownWrapper_Impl::hasMethod !"), Reference<XInterface>());;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
sal_Bool SAL_CALL IUnknownWrapper_Impl::hasProperty( const OUString& aName )
|
|
throw(RuntimeException)
|
|
{
|
|
if ( ! m_spDispatch )
|
|
{
|
|
throw RuntimeException(OUSTR("[automation bridge] The object does not have an "
|
|
"IDispatch interface"), Reference<XInterface>());
|
|
return sal_False;
|
|
}
|
|
sal_Bool ret = sal_False;
|
|
try
|
|
{
|
|
o2u_attachCurrentThread();
|
|
|
|
ITypeInfo * pInfo = getTypeInfo();
|
|
FuncDesc aDescGet(pInfo);
|
|
FuncDesc aDescPut(pInfo);
|
|
VarDesc aVarDesc(pInfo);
|
|
getPropDesc(aName, & aDescGet, & aDescPut, & aVarDesc);
|
|
// Automation properties can have parameters. If so, we access them through
|
|
// XInvocation::invoke. Thas is, hasProperty must return false for such a
|
|
// property
|
|
if (aVarDesc
|
|
|| aDescPut && aDescPut->cParams == 0
|
|
|| aDescGet && aDescGet->cParams == 0)
|
|
{
|
|
ret = sal_True;
|
|
}
|
|
}
|
|
catch (BridgeRuntimeError& e)
|
|
{
|
|
throw RuntimeException(e.message, Reference<XInterface>());
|
|
}
|
|
catch (Exception & e)
|
|
{
|
|
throw RuntimeException(OUSTR("[automation bridge] unexpected exception in "
|
|
"IUnknownWrapper_Impl::hasProperty ! Message : \n") +
|
|
e.Message, Reference<XInterface>());
|
|
|
|
}
|
|
catch (...)
|
|
{
|
|
throw RuntimeException(OUSTR("[automation bridge] unexpected exception in "
|
|
"IUnknownWrapper_Impl::hasProperty !"), Reference<XInterface>());
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
Any SAL_CALL IUnknownWrapper_Impl::createBridge( const Any& modelDepObject,
|
|
const Sequence< sal_Int8 >& aProcessId, sal_Int16 sourceModelType,
|
|
sal_Int16 destModelType )
|
|
throw( IllegalArgumentException, RuntimeException)
|
|
{
|
|
Any ret;
|
|
o2u_attachCurrentThread();
|
|
|
|
if (
|
|
(sourceModelType == UNO) &&
|
|
(destModelType == OLE) &&
|
|
(modelDepObject.getValueTypeClass() == TypeClass_INTERFACE)
|
|
)
|
|
{
|
|
Reference<XInterface> xInt( *(XInterface**) modelDepObject.getValue());
|
|
Reference<XInterface> xSelf( (OWeakObject*)this);
|
|
|
|
if (xInt == xSelf)
|
|
{
|
|
VARIANT* pVariant = (VARIANT*) CoTaskMemAlloc(sizeof(VARIANT));
|
|
|
|
VariantInit(pVariant);
|
|
if (m_bOriginalDispatch == sal_True)
|
|
{
|
|
pVariant->vt = VT_DISPATCH;
|
|
pVariant->pdispVal = m_spDispatch;
|
|
pVariant->pdispVal->AddRef();
|
|
}
|
|
else
|
|
{
|
|
pVariant->vt = VT_UNKNOWN;
|
|
pVariant->punkVal = m_spUnknown;
|
|
pVariant->punkVal->AddRef();
|
|
}
|
|
|
|
ret.setValue((void*)&pVariant, getCppuType( (sal_uInt32*) 0));
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
/** @internal
|
|
@exception IllegalArgumentException
|
|
@exception CannotConvertException
|
|
@exception InvocationTargetException
|
|
@RuntimeException
|
|
*/
|
|
Any IUnknownWrapper_Impl::invokeWithDispIdUnoTlb(const OUString& sFunctionName,
|
|
const Sequence< Any >& Params,
|
|
Sequence< sal_Int16 >& OutParamIndex,
|
|
Sequence< Any >& OutParam)
|
|
{
|
|
Any ret;
|
|
HRESULT hr= S_OK;
|
|
|
|
sal_Int32 parameterCount= Params.getLength();
|
|
sal_Int32 outParameterCount= 0;
|
|
typelib_InterfaceMethodTypeDescription* pMethod= NULL;
|
|
TypeDescription methodDesc;
|
|
getMethodInfo(sFunctionName, methodDesc);
|
|
|
|
// We need to know whether the IDispatch is from a JScript object.
|
|
// Then out and in/out parameters have to be treated differently than
|
|
// with common COM objects.
|
|
sal_Bool bJScriptObject= isJScriptObject();
|
|
scoped_array<CComVariant> sarParams;
|
|
scoped_array<CComVariant> sarParamsRef;
|
|
CComVariant *pVarParams= NULL;
|
|
CComVariant *pVarParamsRef= NULL;
|
|
sal_Bool bConvRet= sal_True;
|
|
|
|
if( methodDesc.is())
|
|
{
|
|
pMethod = (typelib_InterfaceMethodTypeDescription* )methodDesc.get();
|
|
parameterCount = pMethod->nParams;
|
|
// Create the Array for the array being passed in DISPPARAMS
|
|
// the array also contains the outparameter (but not the values)
|
|
if( pMethod->nParams > 0)
|
|
{
|
|
sarParams.reset(new CComVariant[ parameterCount]);
|
|
pVarParams = sarParams.get();
|
|
}
|
|
|
|
// Create the Array for the out an in/out parameter. These values
|
|
// are referenced by the VT_BYREF VARIANTs in DISPPARAMS.
|
|
// We need to find out the number of out and in/out parameter.
|
|
for( sal_Int32 i=0; i < parameterCount; i++)
|
|
{
|
|
if( pMethod->pParams[i].bOut)
|
|
outParameterCount++;
|
|
}
|
|
|
|
if( !bJScriptObject)
|
|
{
|
|
sarParamsRef.reset(new CComVariant[outParameterCount]);
|
|
pVarParamsRef = sarParamsRef.get();
|
|
// build up the parameters for IDispatch::Invoke
|
|
sal_Int32 outParamIndex=0;
|
|
int i = 0;
|
|
try
|
|
{
|
|
for( i= 0; i < parameterCount; i++)
|
|
{
|
|
// In parameter
|
|
if( pMethod->pParams[i].bIn == sal_True && ! pMethod->pParams[i].bOut)
|
|
{
|
|
anyToVariant( &pVarParams[parameterCount - i -1], Params.getConstArray()[i]);
|
|
}
|
|
// Out parameter + in/out parameter
|
|
else if( pMethod->pParams[i].bOut == sal_True)
|
|
{
|
|
CComVariant var;
|
|
if(pMethod->pParams[i].bIn)
|
|
{
|
|
anyToVariant( & var,Params[i]);
|
|
pVarParamsRef[outParamIndex] = var;
|
|
}
|
|
|
|
switch( pMethod->pParams[i].pTypeRef->eTypeClass)
|
|
{
|
|
case TypeClass_INTERFACE:
|
|
case TypeClass_STRUCT:
|
|
if( ! pMethod->pParams[i].bIn)
|
|
{
|
|
pVarParamsRef[ outParamIndex].vt= VT_DISPATCH;
|
|
pVarParamsRef[ outParamIndex].pdispVal= 0;
|
|
}
|
|
pVarParams[parameterCount - i -1].vt = VT_DISPATCH | VT_BYREF;
|
|
pVarParams[parameterCount - i -1].ppdispVal= &pVarParamsRef[outParamIndex].pdispVal;
|
|
break;
|
|
case TypeClass_ENUM:
|
|
case TypeClass_LONG:
|
|
case TypeClass_UNSIGNED_LONG:
|
|
if( ! pMethod->pParams[i].bIn)
|
|
{
|
|
pVarParamsRef[ outParamIndex].vt = VT_I4;
|
|
pVarParamsRef[ outParamIndex].lVal = 0;
|
|
}
|
|
pVarParams[parameterCount - i -1].vt = VT_I4 | VT_BYREF;
|
|
pVarParams[parameterCount - i -1].plVal= &pVarParamsRef[outParamIndex].lVal;
|
|
break;
|
|
case TypeClass_SEQUENCE:
|
|
if( ! pMethod->pParams[i].bIn)
|
|
{
|
|
pVarParamsRef[ outParamIndex].vt = VT_ARRAY| VT_VARIANT;
|
|
pVarParamsRef[ outParamIndex].parray= NULL;
|
|
}
|
|
pVarParams[parameterCount - i -1].vt = VT_ARRAY| VT_BYREF | VT_VARIANT;
|
|
pVarParams[parameterCount - i -1].pparray= &pVarParamsRef[outParamIndex].parray;
|
|
break;
|
|
case TypeClass_ANY:
|
|
if( ! pMethod->pParams[i].bIn)
|
|
{
|
|
pVarParamsRef[ outParamIndex].vt = VT_EMPTY;
|
|
pVarParamsRef[ outParamIndex].lVal = 0;
|
|
}
|
|
pVarParams[parameterCount - i -1].vt = VT_VARIANT | VT_BYREF;
|
|
pVarParams[parameterCount - i -1].pvarVal = &pVarParamsRef[outParamIndex];
|
|
break;
|
|
case TypeClass_BOOLEAN:
|
|
if( ! pMethod->pParams[i].bIn)
|
|
{
|
|
pVarParamsRef[ outParamIndex].vt = VT_BOOL;
|
|
pVarParamsRef[ outParamIndex].boolVal = 0;
|
|
}
|
|
pVarParams[parameterCount - i -1].vt = VT_BOOL| VT_BYREF;
|
|
pVarParams[parameterCount - i -1].pboolVal =
|
|
& pVarParamsRef[outParamIndex].boolVal;
|
|
break;
|
|
|
|
case TypeClass_STRING:
|
|
if( ! pMethod->pParams[i].bIn)
|
|
{
|
|
pVarParamsRef[ outParamIndex].vt = VT_BSTR;
|
|
pVarParamsRef[ outParamIndex].bstrVal= 0;
|
|
}
|
|
pVarParams[parameterCount - i -1].vt = VT_BSTR| VT_BYREF;
|
|
pVarParams[parameterCount - i -1].pbstrVal=
|
|
& pVarParamsRef[outParamIndex].bstrVal;
|
|
break;
|
|
|
|
case TypeClass_FLOAT:
|
|
if( ! pMethod->pParams[i].bIn)
|
|
{
|
|
pVarParamsRef[ outParamIndex].vt = VT_R4;
|
|
pVarParamsRef[ outParamIndex].fltVal= 0;
|
|
}
|
|
pVarParams[parameterCount - i -1].vt = VT_R4| VT_BYREF;
|
|
pVarParams[parameterCount - i -1].pfltVal =
|
|
& pVarParamsRef[outParamIndex].fltVal;
|
|
break;
|
|
case TypeClass_DOUBLE:
|
|
if( ! pMethod->pParams[i].bIn)
|
|
{
|
|
pVarParamsRef[ outParamIndex].vt = VT_R8;
|
|
pVarParamsRef[ outParamIndex].dblVal= 0;
|
|
}
|
|
pVarParams[parameterCount - i -1].vt = VT_R8| VT_BYREF;
|
|
pVarParams[parameterCount - i -1].pdblVal=
|
|
& pVarParamsRef[outParamIndex].dblVal;
|
|
break;
|
|
case TypeClass_BYTE:
|
|
if( ! pMethod->pParams[i].bIn)
|
|
{
|
|
pVarParamsRef[ outParamIndex].vt = VT_UI1;
|
|
pVarParamsRef[ outParamIndex].bVal= 0;
|
|
}
|
|
pVarParams[parameterCount - i -1].vt = VT_UI1| VT_BYREF;
|
|
pVarParams[parameterCount - i -1].pbVal=
|
|
& pVarParamsRef[outParamIndex].bVal;
|
|
break;
|
|
case TypeClass_CHAR:
|
|
case TypeClass_SHORT:
|
|
case TypeClass_UNSIGNED_SHORT:
|
|
if( ! pMethod->pParams[i].bIn)
|
|
{
|
|
pVarParamsRef[ outParamIndex].vt = VT_I2;
|
|
pVarParamsRef[ outParamIndex].iVal = 0;
|
|
}
|
|
pVarParams[parameterCount - i -1].vt = VT_I2| VT_BYREF;
|
|
pVarParams[parameterCount - i -1].piVal=
|
|
& pVarParamsRef[outParamIndex].iVal;
|
|
break;
|
|
|
|
default:
|
|
if( ! pMethod->pParams[i].bIn)
|
|
{
|
|
pVarParamsRef[ outParamIndex].vt = VT_EMPTY;
|
|
pVarParamsRef[ outParamIndex].lVal = 0;
|
|
}
|
|
pVarParams[parameterCount - i -1].vt = VT_VARIANT | VT_BYREF;
|
|
pVarParams[parameterCount - i -1].pvarVal =
|
|
& pVarParamsRef[outParamIndex];
|
|
}
|
|
outParamIndex++;
|
|
} // end else if
|
|
} // end for
|
|
}
|
|
catch (IllegalArgumentException & e)
|
|
{
|
|
e.ArgumentPosition = i;
|
|
throw;
|
|
}
|
|
catch (CannotConvertException & e)
|
|
{
|
|
e.ArgumentIndex = i;
|
|
throw;
|
|
}
|
|
}
|
|
else // it is an JScriptObject
|
|
{
|
|
int i;
|
|
try
|
|
{
|
|
for(i = 0; i< parameterCount; i++)
|
|
{
|
|
// In parameter
|
|
if( pMethod->pParams[i].bIn == sal_True && ! pMethod->pParams[i].bOut)
|
|
{
|
|
anyToVariant( &pVarParams[parameterCount - i -1], Params.getConstArray()[i]);
|
|
}
|
|
// Out parameter + in/out parameter
|
|
else if( pMethod->pParams[i].bOut == sal_True)
|
|
{
|
|
CComObject<JScriptOutParam>* pParamObject;
|
|
if( SUCCEEDED( CComObject<JScriptOutParam>::CreateInstance( &pParamObject)))
|
|
{
|
|
CComPtr<IUnknown> pUnk(pParamObject->GetUnknown());
|
|
CComQIPtr<IDispatch> pDisp( pUnk);
|
|
|
|
pVarParams[ parameterCount - i -1].vt= VT_DISPATCH;
|
|
pVarParams[ parameterCount - i -1].pdispVal= pDisp;
|
|
pVarParams[ parameterCount - i -1].pdispVal->AddRef();
|
|
// if the param is in/out then put the parameter on index 0
|
|
if( pMethod->pParams[i].bIn == sal_True ) // in / out
|
|
{
|
|
CComVariant varParam;
|
|
anyToVariant( &varParam, Params.getConstArray()[i]);
|
|
CComDispatchDriver dispDriver( pDisp);
|
|
if(FAILED( dispDriver.PutPropertyByName( L"0", &varParam)))
|
|
throw BridgeRuntimeError(
|
|
OUSTR("[automation bridge]IUnknownWrapper_Impl::"
|
|
"invokeWithDispIdUnoTlb\n"
|
|
"Could not set property \"0\" for the in/out "
|
|
"param!"));
|
|
|
|
}
|
|
}
|
|
else
|
|
{
|
|
throw BridgeRuntimeError(
|
|
OUSTR("[automation bridge]IUnknownWrapper_Impl::"
|
|
"invokeWithDispIdUnoTlb\n"
|
|
"Could not create out parameter at index: ") +
|
|
OUString::valueOf((sal_Int32) i));
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
catch (IllegalArgumentException & e)
|
|
{
|
|
e.ArgumentPosition = i;
|
|
throw;
|
|
}
|
|
catch (CannotConvertException & e)
|
|
{
|
|
e.ArgumentIndex = i;
|
|
throw;
|
|
}
|
|
}
|
|
}
|
|
// No type description Available, that is we have to deal with a COM component,
|
|
// that does not implements UNO interfaces ( IDispatch based)
|
|
else
|
|
{
|
|
//We should not run into this block, because invokeWithDispIdComTlb should
|
|
//have been called instead.
|
|
OSL_ASSERT(0);
|
|
}
|
|
|
|
|
|
CComVariant varResult;
|
|
ExcepInfo excepinfo;
|
|
unsigned int uArgErr;
|
|
DISPPARAMS dispparams= { pVarParams, NULL, parameterCount, 0};
|
|
// Get the DISPID
|
|
FuncDesc aDesc(getTypeInfo());
|
|
getFuncDesc(sFunctionName, & aDesc);
|
|
// invoking OLE method
|
|
hr = m_spDispatch->Invoke(aDesc->memid,
|
|
IID_NULL,
|
|
LOCALE_USER_DEFAULT,
|
|
DISPATCH_METHOD,
|
|
&dispparams,
|
|
&varResult,
|
|
&excepinfo,
|
|
&uArgErr);
|
|
|
|
// converting return value and out parameter back to UNO
|
|
if (hr == S_OK)
|
|
{
|
|
if( outParameterCount && pMethod)
|
|
{
|
|
OutParamIndex.realloc( outParameterCount);
|
|
OutParam.realloc( outParameterCount);
|
|
sal_Int32 outIndex=0;
|
|
int i;
|
|
try
|
|
{
|
|
for( i = 0; i < parameterCount; i++)
|
|
{
|
|
if( pMethod->pParams[i].bOut )
|
|
{
|
|
OutParamIndex[outIndex]= (sal_Int16) i;
|
|
Any outAny;
|
|
if( !bJScriptObject)
|
|
{
|
|
variantToAny( &pVarParamsRef[outIndex], outAny,
|
|
Type(pMethod->pParams[i].pTypeRef), sal_False);
|
|
OutParam[outIndex++]= outAny;
|
|
}
|
|
else //JScriptObject
|
|
{
|
|
if( pVarParams[i].vt= VT_DISPATCH)
|
|
{
|
|
CComDispatchDriver pDisp( pVarParams[i].pdispVal);
|
|
if( pDisp)
|
|
{
|
|
CComVariant varOut;
|
|
if( SUCCEEDED( pDisp.GetPropertyByName( L"0", &varOut)))
|
|
{
|
|
variantToAny( &varOut, outAny,
|
|
Type(pMethod->pParams[parameterCount - 1 - i].pTypeRef), sal_False);
|
|
OutParam[outParameterCount - 1 - outIndex++]= outAny;
|
|
}
|
|
else
|
|
bConvRet= sal_False;
|
|
}
|
|
else
|
|
bConvRet= sal_False;
|
|
}
|
|
else
|
|
bConvRet= sal_False;
|
|
}
|
|
}
|
|
if( !bConvRet) break;
|
|
}
|
|
}
|
|
catch(IllegalArgumentException & e)
|
|
{
|
|
e.ArgumentPosition = i;
|
|
throw;
|
|
}
|
|
catch(CannotConvertException & e)
|
|
{
|
|
e.ArgumentIndex = i;
|
|
throw;
|
|
}
|
|
}
|
|
// return value, no type information available
|
|
if ( bConvRet)
|
|
{
|
|
try
|
|
{
|
|
if( pMethod )
|
|
variantToAny(&varResult, ret, Type( pMethod->pReturnTypeRef), sal_False);
|
|
else
|
|
variantToAny(&varResult, ret, sal_False);
|
|
}
|
|
catch (IllegalArgumentException & e)
|
|
{
|
|
e.Message =
|
|
OUSTR("[automation bridge]IUnknownWrapper_Impl::invokeWithDispIdUnoTlb\n"
|
|
"Could not convert return value! \n Message: \n") + e.Message;
|
|
throw;
|
|
}
|
|
catch (CannotConvertException & e)
|
|
{
|
|
e.Message =
|
|
OUSTR("[automation bridge]IUnknownWrapper_Impl::invokeWithDispIdUnoTlb\n"
|
|
"Could not convert return value! \n Message: \n") + e.Message;
|
|
throw;
|
|
}
|
|
}
|
|
}
|
|
|
|
if( !bConvRet) // conversion of return or out parameter failed
|
|
throw CannotConvertException( L"Call to COM object failed. Conversion of return or out value failed",
|
|
Reference<XInterface>( static_cast<XWeak*>(this), UNO_QUERY ), TypeClass_UNKNOWN,
|
|
FailReason::UNKNOWN, 0);// lookup error code
|
|
// conversion of return or out parameter failed
|
|
switch (hr)
|
|
{
|
|
case S_OK:
|
|
break;
|
|
case DISP_E_BADPARAMCOUNT:
|
|
throw IllegalArgumentException();
|
|
break;
|
|
case DISP_E_BADVARTYPE:
|
|
throw RuntimeException();
|
|
break;
|
|
case DISP_E_EXCEPTION:
|
|
throw InvocationTargetException();
|
|
break;
|
|
case DISP_E_MEMBERNOTFOUND:
|
|
throw IllegalArgumentException();
|
|
break;
|
|
case DISP_E_NONAMEDARGS:
|
|
throw IllegalArgumentException();
|
|
break;
|
|
case DISP_E_OVERFLOW:
|
|
throw CannotConvertException(L"call to OLE object failed", static_cast<XInterface*>(
|
|
static_cast<XWeak*>(this)), TypeClass_UNKNOWN, FailReason::OUT_OF_RANGE, uArgErr);
|
|
break;
|
|
case DISP_E_PARAMNOTFOUND:
|
|
throw IllegalArgumentException(L"call to OLE object failed", static_cast<XInterface*>(
|
|
static_cast<XWeak*>(this)), uArgErr);
|
|
break;
|
|
case DISP_E_TYPEMISMATCH:
|
|
throw CannotConvertException(L"call to OLE object failed",static_cast<XInterface*>(
|
|
static_cast<XWeak*>(this)) , TypeClass_UNKNOWN, FailReason::UNKNOWN, uArgErr);
|
|
break;
|
|
case DISP_E_UNKNOWNINTERFACE:
|
|
throw RuntimeException() ;
|
|
break;
|
|
case DISP_E_UNKNOWNLCID:
|
|
throw RuntimeException() ;
|
|
break;
|
|
case DISP_E_PARAMNOTOPTIONAL:
|
|
throw CannotConvertException(L"call to OLE object failed", static_cast<XInterface*>(
|
|
static_cast<XWeak*>(this)), TypeClass_UNKNOWN, FailReason::NO_DEFAULT_AVAILABLE, uArgErr);
|
|
break;
|
|
default:
|
|
throw RuntimeException();
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
|
|
// --------------------------
|
|
// XInitialization
|
|
void SAL_CALL IUnknownWrapper_Impl::initialize( const Sequence< Any >& aArguments ) throw(Exception, RuntimeException)
|
|
{
|
|
// 1.parameter is IUnknown
|
|
// 2.parameter is a boolean which indicates if the the COM pointer was a IUnknown or IDispatch
|
|
// 3.parameter is a Sequence<Type>
|
|
HRESULT result;
|
|
o2u_attachCurrentThread();
|
|
OSL_ASSERT(aArguments.getLength() == 3);
|
|
|
|
m_spUnknown= *(IUnknown**) aArguments[0].getValue();
|
|
m_spUnknown.QueryInterface( & m_spDispatch.p);
|
|
|
|
aArguments[1] >>= m_bOriginalDispatch;
|
|
aArguments[2] >>= m_seqTypes;
|
|
}
|
|
|
|
// UnoConversionUtilities --------------------------------------------------------------------------------
|
|
Reference< XInterface > IUnknownWrapper_Impl::createUnoWrapperInstance()
|
|
{
|
|
if( m_nUnoWrapperClass == INTERFACE_OLE_WRAPPER_IMPL)
|
|
{
|
|
Reference<XWeak> xWeak= static_cast<XWeak*>( new InterfaceOleWrapper_Impl(
|
|
m_smgr, m_nUnoWrapperClass, m_nComWrapperClass));
|
|
return Reference<XInterface>( xWeak, UNO_QUERY);
|
|
}
|
|
else if( m_nUnoWrapperClass == UNO_OBJECT_WRAPPER_REMOTE_OPT)
|
|
{
|
|
Reference<XWeak> xWeak= static_cast<XWeak*>( new UnoObjectWrapperRemoteOpt(
|
|
m_smgr, m_nUnoWrapperClass, m_nComWrapperClass));
|
|
return Reference<XInterface>( xWeak, UNO_QUERY);
|
|
}
|
|
else
|
|
return Reference<XInterface>();
|
|
}
|
|
Reference<XInterface> IUnknownWrapper_Impl::createComWrapperInstance()
|
|
{
|
|
Reference<XWeak> xWeak= static_cast<XWeak*>( new IUnknownWrapper_Impl(
|
|
m_smgr, m_nUnoWrapperClass, m_nComWrapperClass));
|
|
return Reference<XInterface>( xWeak, UNO_QUERY);
|
|
}
|
|
|
|
|
|
|
|
void IUnknownWrapper_Impl::getMethodInfo(const OUString& sName, TypeDescription& methodInfo)
|
|
{
|
|
TypeDescription desc= getInterfaceMemberDescOfCurrentCall(sName);
|
|
if( desc.is())
|
|
{
|
|
typelib_TypeDescription* pMember= desc.get();
|
|
if( pMember->eTypeClass == TypeClass_INTERFACE_METHOD )
|
|
methodInfo= pMember;
|
|
}
|
|
}
|
|
|
|
void IUnknownWrapper_Impl::getAttributeInfo(const OUString& sName, TypeDescription& attributeInfo)
|
|
{
|
|
TypeDescription desc= getInterfaceMemberDescOfCurrentCall(sName);
|
|
if( desc.is())
|
|
{
|
|
typelib_TypeDescription* pMember= desc.get();
|
|
if( pMember->eTypeClass == TypeClass_INTERFACE_ATTRIBUTE )
|
|
{
|
|
attributeInfo= ((typelib_InterfaceAttributeTypeDescription*)pMember)->pAttributeTypeRef;
|
|
}
|
|
}
|
|
}
|
|
TypeDescription IUnknownWrapper_Impl::getInterfaceMemberDescOfCurrentCall(const OUString& sName)
|
|
{
|
|
TypeDescription ret;
|
|
|
|
for( sal_Int32 i=0; i < m_seqTypes.getLength(); i++)
|
|
{
|
|
TypeDescription _curDesc( m_seqTypes[i]);
|
|
_curDesc.makeComplete();
|
|
typelib_InterfaceTypeDescription * pInterface= (typelib_InterfaceTypeDescription*) _curDesc.get();
|
|
if( pInterface)
|
|
{
|
|
typelib_InterfaceMemberTypeDescription* pMember= NULL;
|
|
//find the member description of the current call
|
|
for( int i=0; i < pInterface->nAllMembers; i++)
|
|
{
|
|
typelib_TypeDescriptionReference* pTypeRefMember = pInterface->ppAllMembers[i];
|
|
typelib_TypeDescription* pDescMember= NULL;
|
|
TYPELIB_DANGER_GET( &pDescMember, pTypeRefMember)
|
|
|
|
typelib_InterfaceMemberTypeDescription* pInterfaceMember=
|
|
(typelib_InterfaceMemberTypeDescription*) pDescMember;
|
|
if( OUString( pInterfaceMember->pMemberName) == sName)
|
|
{
|
|
pMember= pInterfaceMember;
|
|
break;
|
|
}
|
|
TYPELIB_DANGER_RELEASE( pDescMember)
|
|
}
|
|
|
|
if( pMember)
|
|
{
|
|
ret= (typelib_TypeDescription*)pMember;
|
|
TYPELIB_DANGER_RELEASE( (typelib_TypeDescription*)pMember);
|
|
}
|
|
}
|
|
if( ret.is())
|
|
break;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
sal_Bool IUnknownWrapper_Impl::isJScriptObject()
|
|
{
|
|
if( m_eJScript == JScriptUndefined)
|
|
{
|
|
CComDispatchDriver disp( m_spDispatch);
|
|
if( disp)
|
|
{
|
|
CComVariant result;
|
|
if( SUCCEEDED( disp.GetPropertyByName( JSCRIPT_ID_PROPERTY, &result)))
|
|
{
|
|
if(result.vt == VT_BSTR)
|
|
{
|
|
CComBSTR name( result.bstrVal);
|
|
name.ToLower();
|
|
if( name == JSCRIPT_ID)
|
|
m_eJScript= IsJScript;
|
|
}
|
|
}
|
|
}
|
|
if( m_eJScript == JScriptUndefined)
|
|
m_eJScript= NoJScript;
|
|
}
|
|
|
|
return m_eJScript == NoJScript ? sal_False : sal_True;
|
|
}
|
|
|
|
|
|
|
|
/** @internal
|
|
The function ultimately calls IDispatch::Invoke on the wrapped COM object.
|
|
The COM object does not implement UNO Interfaces ( via IDispatch). This
|
|
is the case when the OleObjectFactory service has been used to create a
|
|
component.
|
|
@exception IllegalArgumentException
|
|
@exception CannotConvertException
|
|
@InvocationTargetException
|
|
@RuntimeException
|
|
@BridgeRuntimeError
|
|
*/
|
|
Any IUnknownWrapper_Impl::invokeWithDispIdComTlb(const OUString& sFuncName,
|
|
const Sequence< Any >& Params,
|
|
Sequence< sal_Int16 >& OutParamIndex,
|
|
Sequence< Any >& OutParam)
|
|
{
|
|
Any ret;
|
|
HRESULT result;
|
|
|
|
DISPPARAMS dispparams = {NULL, NULL, 0, 0};
|
|
CComVariant varResult;
|
|
ExcepInfo excepinfo;
|
|
unsigned int uArgErr;
|
|
sal_Int32 i;
|
|
sal_Int32 nUnoArgs = Params.getLength();
|
|
DISPID idPropertyPut = DISPID_PROPERTYPUT;
|
|
scoped_array<DISPID> arDispidNamedArgs;
|
|
scoped_array<CComVariant> ptrArgs;
|
|
scoped_array<CComVariant> ptrRefArgs; // referenced arguments
|
|
CComVariant * arArgs = NULL;
|
|
CComVariant * arRefArgs = NULL;
|
|
sal_Int32 revIndex = 0;
|
|
bool bVarargParam = false;
|
|
|
|
// Get type info for the call. It can be a method call or property put or
|
|
// property get operation.
|
|
FuncDesc aFuncDesc(getTypeInfo());
|
|
getFuncDescForInvoke(sFuncName, Params, & aFuncDesc);
|
|
|
|
//Set the array of DISPIDs for named args if it is a property put operation.
|
|
//If there are other named arguments another array is set later on.
|
|
if (aFuncDesc->invkind == INVOKE_PROPERTYPUT
|
|
|| aFuncDesc->invkind == INVOKE_PROPERTYPUTREF)
|
|
dispparams.rgdispidNamedArgs = & idPropertyPut;
|
|
|
|
//Determine the number of named arguments
|
|
for (int iParam = 0; iParam < nUnoArgs; iParam ++)
|
|
{
|
|
const Any & curArg = Params[iParam];
|
|
if (curArg.getValueType() == getCppuType((NamedArgument*) 0))
|
|
dispparams.cNamedArgs ++;
|
|
}
|
|
//In a property put operation a property value is a named argument (DISPID_PROPERTYPUT).
|
|
//Therefore the number of named arguments is increased by one.
|
|
//Although named, the argument is not named in a actual language, such as Basic,
|
|
//therefore it is never a com.sun.star.bridge.oleautomation.NamedArgument
|
|
if (aFuncDesc->invkind == DISPATCH_PROPERTYPUT
|
|
|| aFuncDesc->invkind == DISPATCH_PROPERTYPUTREF)
|
|
dispparams.cNamedArgs ++;
|
|
|
|
//Determine the number of all arguments and named arguments
|
|
if (aFuncDesc->cParamsOpt == -1)
|
|
{
|
|
//Attribute vararg is set on this method. "Unlimited" number of args
|
|
//supported. There can be no optional or defaultvalue on any of the arguments.
|
|
dispparams.cArgs = nUnoArgs;
|
|
}
|
|
else
|
|
{
|
|
//If there are namesd arguments, then the dispparams.cArgs
|
|
//is the number of supplied args, otherwise it is the expected number.
|
|
if (dispparams.cNamedArgs)
|
|
dispparams.cArgs = nUnoArgs;
|
|
else
|
|
dispparams.cArgs = aFuncDesc->cParams;
|
|
}
|
|
|
|
//check if there are not to many arguments supplied
|
|
if (nUnoArgs > dispparams.cArgs)
|
|
{
|
|
OUStringBuffer buf(256);
|
|
buf.appendAscii("[automation bridge] There are too many arguments for this method");
|
|
throw IllegalArgumentException( buf.makeStringAndClear(),
|
|
Reference<XInterface>(), (sal_Int16) dispparams.cArgs);
|
|
}
|
|
|
|
//Set up the array of DISPIDs (DISPPARAMS::rgdispidNamedArgs)
|
|
//for the named arguments.
|
|
//If there is only one named arg and if it is because of a property put
|
|
//operation, then we need not set up the DISPID array.
|
|
if (dispparams.cNamedArgs > 0 &&
|
|
! (dispparams.cNamedArgs == 1 &&
|
|
(aFuncDesc->invkind == INVOKE_PROPERTYPUT ||
|
|
aFuncDesc->invkind == INVOKE_PROPERTYPUT)))
|
|
{
|
|
//set up an array containing the member and parameter names
|
|
//which is then used in ITypeInfo::GetIDsOfNames
|
|
//First determine the size of the array of names which is passed to
|
|
//ITypeInfo::GetIDsOfNames. It must hold the method names + the named
|
|
//args.
|
|
int nSizeAr = dispparams.cNamedArgs + 1;
|
|
if (aFuncDesc->invkind == INVOKE_PROPERTYPUT
|
|
|| aFuncDesc->invkind == INVOKE_PROPERTYPUTREF)
|
|
{
|
|
nSizeAr = dispparams.cNamedArgs; //counts the DISID_PROPERTYPUT
|
|
}
|
|
|
|
scoped_array<OLECHAR*> saNames(new OLECHAR*[nSizeAr]);
|
|
OLECHAR ** arNames = saNames.get();
|
|
arNames[0] = const_cast<OLECHAR*>(sFuncName.getStr());
|
|
|
|
int cNamedArg = 0;
|
|
for (int iParams = 0; iParams < dispparams.cArgs; iParams ++)
|
|
{
|
|
const Any & curArg = Params[iParams];
|
|
if (curArg.getValueType() == getCppuType((NamedArgument*) 0))
|
|
{
|
|
const NamedArgument& arg = *(NamedArgument const*) curArg.getValue();
|
|
//We put the parameter names in reverse order into the array,
|
|
//so we can use the DISPID array for DISPPARAMS::rgdispidNamedArgs
|
|
//The first name in the array is the method name
|
|
arNames[nSizeAr - 1 - cNamedArg++] = const_cast<OLECHAR*>(arg.Name.getStr());
|
|
}
|
|
}
|
|
|
|
//Prepare the array of DISPIDs for ITypeInfo::GetIDsOfNames
|
|
//it must be big enough to contain the DISPIDs of the member + parameters
|
|
arDispidNamedArgs.reset(new DISPID[nSizeAr]);
|
|
HRESULT hr = getTypeInfo()->GetIDsOfNames(arNames, nSizeAr,
|
|
arDispidNamedArgs.get());
|
|
if (hr == S_OK)
|
|
{
|
|
// In a "property put" operation, the property value is a named param with the
|
|
//special DISPID DISPID_PROPERTYPUT
|
|
if (aFuncDesc->invkind == DISPATCH_PROPERTYPUT
|
|
|| aFuncDesc->invkind == DISPATCH_PROPERTYPUTREF)
|
|
{
|
|
//Element at index 0 in the DISPID array must be DISPID_PROPERTYPUT
|
|
//The first item in the array arDispidNamedArgs is the DISPID for
|
|
//the method. We replace it with DISPID_PROPERTYPUT.
|
|
DISPID* arIDs = arDispidNamedArgs.get();
|
|
arIDs[0] = DISPID_PROPERTYPUT;
|
|
dispparams.rgdispidNamedArgs = arIDs;
|
|
}
|
|
else
|
|
{
|
|
//The first item in the array arDispidNamedArgs is the DISPID for
|
|
//the method. It must be removed
|
|
DISPID* arIDs = arDispidNamedArgs.get();
|
|
dispparams.rgdispidNamedArgs = & arIDs[1];
|
|
}
|
|
}
|
|
else if (hr == DISP_E_UNKNOWNNAME)
|
|
{
|
|
throw IllegalArgumentException(
|
|
OUSTR("[automation bridge]One of the named arguments is wrong!"),
|
|
Reference<XInterface>(), 0);
|
|
}
|
|
else
|
|
{
|
|
throw InvocationTargetException(
|
|
OUSTR("[automation bridge] ITypeInfo::GetIDsOfNames returned error ")
|
|
+ OUString::valueOf((sal_Int32) hr, 16), Reference<XInterface>(), Any());
|
|
}
|
|
}
|
|
|
|
//Convert arguments
|
|
ptrArgs.reset(new CComVariant[dispparams.cArgs]);
|
|
ptrRefArgs.reset(new CComVariant[dispparams.cArgs]);
|
|
arArgs = ptrArgs.get();
|
|
arRefArgs = ptrRefArgs.get();
|
|
try
|
|
{
|
|
for (i = 0; i < (sal_Int32) dispparams.cArgs; i++)
|
|
{
|
|
revIndex= dispparams.cArgs - i -1;
|
|
arRefArgs[revIndex].byref=0;
|
|
Any anyArg;
|
|
if ( i < nUnoArgs)
|
|
anyArg= Params.getConstArray()[i];
|
|
|
|
//Test if the current parameter is a "vararg" parameter.
|
|
if (bVarargParam || (aFuncDesc->cParamsOpt == -1 &&
|
|
aFuncDesc->cParams == (i + 1)))
|
|
{ //This parameter is from the variable argument list. There is no
|
|
//type info available, except that it must be a VARIANT
|
|
bVarargParam = true;
|
|
}
|
|
|
|
unsigned short paramFlags = PARAMFLAG_FOPT | PARAMFLAG_FIN;
|
|
VARTYPE varType = VT_VARIANT;
|
|
if ( ! bVarargParam)
|
|
{
|
|
paramFlags =
|
|
aFuncDesc->lprgelemdescParam[i].paramdesc.wParamFlags;
|
|
varType = getElementTypeDesc(
|
|
& aFuncDesc->lprgelemdescParam[i].tdesc);
|
|
}
|
|
//Make sure that there is a UNO parameter for every
|
|
// expected parameter. If there is no UNO parameter where the
|
|
// called function expects one, then it must be optional. Otherwise
|
|
// its a UNO programming error.
|
|
if (i >= nUnoArgs && !(paramFlags & PARAMFLAG_FOPT))
|
|
{
|
|
OUStringBuffer buf(256);
|
|
buf.appendAscii("ole automation bridge: The called function expects an argument at"
|
|
"position: "); //a different number of arguments")),
|
|
buf.append(OUString::valueOf((sal_Int32) i));
|
|
buf.appendAscii(" (index starting at 0).");
|
|
throw IllegalArgumentException( buf.makeStringAndClear(),
|
|
Reference<XInterface>(), (sal_Int16) i);
|
|
}
|
|
//make sure we get no void any for an in parameter. In StarBasic
|
|
//this may be caused by
|
|
// Dim arg
|
|
// obj.func(arg)
|
|
//A void any is allowed if the parameter is optional
|
|
if ( ! (aFuncDesc->lprgelemdescParam[i].paramdesc.wParamFlags & PARAMFLAG_FOPT)
|
|
&& (i < nUnoArgs) && (paramFlags & PARAMFLAG_FIN) &&
|
|
Params.getConstArray()[i].getValueTypeClass() == TypeClass_VOID)
|
|
{
|
|
OUStringBuffer buf(256);
|
|
buf.appendAscii("ole automation bridge: The argument at position: ");
|
|
buf.append(OUString::valueOf((sal_Int32) i));
|
|
buf.appendAscii(" (index starts with 0) is uninitialized.");
|
|
throw IllegalArgumentException( buf.makeStringAndClear(),
|
|
Reference<XInterface>(), (sal_Int16) i);
|
|
}
|
|
|
|
// Property Put arguments
|
|
if (anyArg.getValueType() == getCppuType((PropertyPutArgument*)0))
|
|
{
|
|
PropertyPutArgument arg;
|
|
anyArg >>= arg;
|
|
anyArg <<= arg.Value;
|
|
}
|
|
// named argument
|
|
if (anyArg.getValueType() == getCppuType((NamedArgument*) 0))
|
|
{
|
|
NamedArgument aNamedArgument;
|
|
anyArg >>= aNamedArgument;
|
|
anyArg <<= aNamedArgument.Value;
|
|
}
|
|
// out param
|
|
if (paramFlags & PARAMFLAG_FOUT &&
|
|
! (paramFlags & PARAMFLAG_FIN) )
|
|
{
|
|
VARTYPE type= varType ^ VT_BYREF;
|
|
if (i < nUnoArgs)
|
|
{
|
|
arRefArgs[revIndex].vt= type;
|
|
}
|
|
else
|
|
{
|
|
//optional arg
|
|
arRefArgs[revIndex].vt = VT_ERROR;
|
|
arRefArgs[revIndex].scode = DISP_E_PARAMNOTFOUND;
|
|
}
|
|
if( type == VT_VARIANT )
|
|
{
|
|
arArgs[revIndex].vt= VT_VARIANT | VT_BYREF;
|
|
arArgs[revIndex].byref= &arRefArgs[revIndex];
|
|
}
|
|
else
|
|
{
|
|
arArgs[revIndex].vt= varType;
|
|
if (type == VT_DECIMAL)
|
|
arArgs[revIndex].byref= & arRefArgs[revIndex].decVal;
|
|
else
|
|
arArgs[revIndex].byref= & arRefArgs[revIndex].byref;
|
|
}
|
|
}
|
|
// in/out + in byref params
|
|
else if (varType & VT_BYREF)
|
|
{
|
|
VARTYPE type = varType ^ VT_BYREF;
|
|
CComVariant var;
|
|
|
|
if (i < nUnoArgs && anyArg.getValueTypeClass() != TypeClass_VOID)
|
|
{
|
|
anyToVariant( & arRefArgs[revIndex], anyArg, type);
|
|
}
|
|
else if (paramFlags & PARAMFLAG_FHASDEFAULT)
|
|
{
|
|
//optional arg with default
|
|
VariantCopy( & arRefArgs[revIndex],
|
|
& aFuncDesc->lprgelemdescParam[i].paramdesc.
|
|
pparamdescex->varDefaultValue);
|
|
}
|
|
else
|
|
{
|
|
//optional arg
|
|
//e.g: call func(x) in basic : func() ' no arg supplied
|
|
OSL_ASSERT(paramFlags & PARAMFLAG_FOPT);
|
|
arRefArgs[revIndex].vt = VT_ERROR;
|
|
arRefArgs[revIndex].scode = DISP_E_PARAMNOTFOUND;
|
|
}
|
|
|
|
// Set the converted arguments in the array which will be
|
|
// DISPPARAMS::rgvarg
|
|
// byref arg VT_XXX |VT_BYREF
|
|
arArgs[revIndex].vt = varType;
|
|
if (revIndex == 0 && aFuncDesc->invkind == INVOKE_PROPERTYPUT)
|
|
{
|
|
arArgs[revIndex] = arRefArgs[revIndex];
|
|
}
|
|
else if (type == VT_DECIMAL)
|
|
{
|
|
arArgs[revIndex].byref= & arRefArgs[revIndex].decVal;
|
|
}
|
|
else if (type == VT_VARIANT)
|
|
{
|
|
if ( ! (paramFlags & PARAMFLAG_FOUT))
|
|
arArgs[revIndex] = arRefArgs[revIndex];
|
|
else
|
|
arArgs[revIndex].byref = & arRefArgs[revIndex];
|
|
}
|
|
else
|
|
{
|
|
arArgs[revIndex].byref = & arRefArgs[revIndex].byref;
|
|
arArgs[revIndex].vt = arRefArgs[revIndex].vt | VT_BYREF;
|
|
}
|
|
|
|
}
|
|
// in parameter no VT_BYREF except for array, interfaces
|
|
else
|
|
{ // void any stands for optional param
|
|
if (i < nUnoArgs && anyArg.getValueTypeClass() != TypeClass_VOID)
|
|
{
|
|
anyToVariant( & arArgs[revIndex], anyArg, varType);
|
|
}
|
|
//optional arg but no void any supplied
|
|
//Basic: obj.func() ' first parameter left out because it is optional
|
|
else if (paramFlags & PARAMFLAG_FHASDEFAULT)
|
|
{
|
|
//optional arg with defaulteithter as direct arg : VT_XXX or
|
|
VariantCopy( & arArgs[revIndex],
|
|
& aFuncDesc->lprgelemdescParam[i].paramdesc.
|
|
pparamdescex->varDefaultValue);
|
|
}
|
|
else
|
|
{
|
|
OSL_ASSERT(paramFlags & PARAMFLAG_FOPT);
|
|
arArgs[revIndex].vt = VT_ERROR;
|
|
arArgs[revIndex].scode = DISP_E_PARAMNOTFOUND;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (IllegalArgumentException & e)
|
|
{
|
|
e.ArgumentPosition = i;
|
|
throw;
|
|
}
|
|
catch (CannotConvertException & e)
|
|
{
|
|
e.ArgumentIndex = i;
|
|
throw;
|
|
}
|
|
dispparams.rgvarg= arArgs;
|
|
// invoking OLE method
|
|
DWORD localeId = LOCALE_USER_DEFAULT;
|
|
result = m_spDispatch->Invoke(aFuncDesc->memid,
|
|
IID_NULL,
|
|
localeId,
|
|
aFuncDesc->invkind,
|
|
&dispparams,
|
|
&varResult,
|
|
&excepinfo,
|
|
&uArgErr);
|
|
|
|
// converting return value and out parameter back to UNO
|
|
if (result == S_OK)
|
|
{
|
|
|
|
// allocate space for the out param Sequence and indices Sequence
|
|
int outParamsCount= 0; // includes in/out parameter
|
|
for (int i = 0; i < aFuncDesc->cParams; i++)
|
|
{
|
|
if (aFuncDesc->lprgelemdescParam[i].paramdesc.wParamFlags &
|
|
PARAMFLAG_FOUT)
|
|
outParamsCount++;
|
|
}
|
|
|
|
OutParamIndex.realloc(outParamsCount);
|
|
OutParam.realloc(outParamsCount);
|
|
// Convert out params
|
|
if (outParamsCount)
|
|
{
|
|
int outParamIndex=0;
|
|
for (int paramIndex = 0; paramIndex < nUnoArgs; paramIndex ++)
|
|
{
|
|
//Determine the index within the method sinature
|
|
int realParamIndex = paramIndex;
|
|
int revParamIndex = dispparams.cArgs - paramIndex - 1;
|
|
if (Params[paramIndex].getValueType()
|
|
== getCppuType((NamedArgument*) 0))
|
|
{
|
|
//dispparams.rgdispidNamedArgs contains the mapping from index
|
|
//of named args list to index of parameter list
|
|
realParamIndex = dispparams.rgdispidNamedArgs[revParamIndex];
|
|
}
|
|
|
|
// no named arg, always come before named args
|
|
if (! (aFuncDesc->lprgelemdescParam[realParamIndex].paramdesc.wParamFlags
|
|
& PARAMFLAG_FOUT))
|
|
continue;
|
|
Any outAny;
|
|
// variantToAny is called with the "reduce range" parameter set to sal_False.
|
|
// That causes VT_I4 values not to be converted down to a "lower" type. That
|
|
// feature exist for JScript only because it only uses VT_I4 for integer types.
|
|
try
|
|
{
|
|
variantToAny( & arRefArgs[revParamIndex], outAny, sal_False );
|
|
}
|
|
catch (IllegalArgumentException & e)
|
|
{
|
|
e.ArgumentPosition = paramIndex;
|
|
throw;
|
|
}
|
|
catch (CannotConvertException & e)
|
|
{
|
|
e.ArgumentIndex = paramIndex;
|
|
throw;
|
|
}
|
|
OutParam[outParamIndex] = outAny;
|
|
OutParamIndex[outParamIndex] = paramIndex;
|
|
outParamIndex++;
|
|
}
|
|
OutParam.realloc(outParamIndex);
|
|
OutParamIndex.realloc(outParamIndex);
|
|
}
|
|
// Return value
|
|
variantToAny(&varResult, ret, sal_False);
|
|
}
|
|
|
|
// map error codes to exceptions
|
|
OUString message;
|
|
switch (result)
|
|
{
|
|
case S_OK:
|
|
break;
|
|
case DISP_E_BADPARAMCOUNT:
|
|
throw IllegalArgumentException(OUSTR("[automation bridge] Wrong "
|
|
"number of arguments. Object returned DISP_E_BADPARAMCOUNT."),
|
|
0, 0);
|
|
break;
|
|
case DISP_E_BADVARTYPE:
|
|
throw RuntimeException(OUSTR("[automation bridge] One or more "
|
|
"arguments have the wrong type. Object returned "
|
|
"DISP_E_BADVARTYPE."), 0);
|
|
break;
|
|
case DISP_E_EXCEPTION:
|
|
message = OUSTR("[automation bridge]: ");
|
|
message += OUString(excepinfo.bstrDescription,
|
|
::SysStringLen(excepinfo.bstrDescription));
|
|
throw InvocationTargetException(message, Reference<XInterface>(), Any());
|
|
break;
|
|
case DISP_E_MEMBERNOTFOUND:
|
|
message = OUSTR("[automation bridge]: A function with the name \"")
|
|
+ sFuncName + OUSTR("\" is not supported. Object returned "
|
|
"DISP_E_MEMBERNOTFOUND.");
|
|
throw IllegalArgumentException(message, 0, 0);
|
|
break;
|
|
case DISP_E_NONAMEDARGS:
|
|
throw IllegalArgumentException(OUSTR("[automation bridge] Object "
|
|
"returned DISP_E_NONAMEDARGS"),0, uArgErr);
|
|
break;
|
|
case DISP_E_OVERFLOW:
|
|
throw CannotConvertException(L"[automation bridge] Call failed.",
|
|
static_cast<XInterface*>(
|
|
static_cast<XWeak*>(this)), TypeClass_UNKNOWN, FailReason::OUT_OF_RANGE, uArgErr);
|
|
break;
|
|
case DISP_E_PARAMNOTFOUND:
|
|
throw IllegalArgumentException(OUSTR("[automation bridge]Call failed."
|
|
"Object returned DISP_E_PARAMNOTFOUND."),
|
|
0, uArgErr);
|
|
break;
|
|
case DISP_E_TYPEMISMATCH:
|
|
throw CannotConvertException(OUSTR("[automation bridge] Call failed. "
|
|
"Object returned DISP_E_TYPEMISMATCH"),
|
|
static_cast<XInterface*>(
|
|
static_cast<XWeak*>(this)) , TypeClass_UNKNOWN, FailReason::UNKNOWN, uArgErr);
|
|
break;
|
|
case DISP_E_UNKNOWNINTERFACE:
|
|
throw RuntimeException(OUSTR("[automation bridge] Call failed. "
|
|
"Object returned DISP_E_UNKNOWNINTERFACE."),0);
|
|
break;
|
|
case DISP_E_UNKNOWNLCID:
|
|
throw RuntimeException(OUSTR("[automation bridge] Call failed. "
|
|
"Object returned DISP_E_UNKNOWNLCID."),0);
|
|
break;
|
|
case DISP_E_PARAMNOTOPTIONAL:
|
|
throw CannotConvertException(OUSTR("[automation bridge] Call failed."
|
|
"Object returned DISP_E_PARAMNOTOPTIONAL"),
|
|
static_cast<XInterface*>(static_cast<XWeak*>(this)),
|
|
TypeClass_UNKNOWN, FailReason::NO_DEFAULT_AVAILABLE, uArgErr);
|
|
break;
|
|
default:
|
|
throw RuntimeException();
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
void IUnknownWrapper_Impl::getFuncDescForInvoke(const OUString & sFuncName,
|
|
const Sequence<Any> & seqArgs,
|
|
FUNCDESC** pFuncDesc)
|
|
{
|
|
int nUnoArgs = seqArgs.getLength();
|
|
const Any * arArgs = seqArgs.getConstArray();
|
|
ITypeInfo* pInfo = getTypeInfo();
|
|
|
|
//If the last of the positional arguments is a PropertyPutArgument
|
|
//then obtain the type info for the property put operation.
|
|
|
|
//The property value is always the last argument, in a positional argument list
|
|
//or in a list of named arguments. A PropertyPutArgument is actually a named argument
|
|
//hence it must not be put in an extra NamedArgument structure
|
|
if (nUnoArgs > 0 &&
|
|
arArgs[nUnoArgs - 1].getValueType() == getCppuType((PropertyPutArgument*) 0))
|
|
{
|
|
// DISPATCH_PROPERTYPUT
|
|
FuncDesc aDescGet(pInfo);
|
|
FuncDesc aDescPut(pInfo);
|
|
VarDesc aVarDesc(pInfo);
|
|
getPropDesc(sFuncName, & aDescGet, & aDescPut, & aVarDesc);
|
|
if ( ! aDescPut)
|
|
{
|
|
throw IllegalArgumentException(
|
|
OUSTR("[automation bridge] The object does not have a writeable property: ")
|
|
+ sFuncName, Reference<XInterface>(), 0);
|
|
}
|
|
*pFuncDesc = aDescPut.Detach();
|
|
}
|
|
else
|
|
{ // DISPATCH_METHOD
|
|
FuncDesc aFuncDesc(pInfo);
|
|
getFuncDesc(sFuncName, & aFuncDesc);
|
|
if ( ! aFuncDesc)
|
|
{
|
|
// Fallback: DISPATCH_PROPERTYGET can mostly be called as
|
|
// DISPATCH_METHOD
|
|
ITypeInfo * pInfo = getTypeInfo();
|
|
FuncDesc aDescPut(pInfo);
|
|
VarDesc aVarDesc(pInfo);
|
|
getPropDesc(sFuncName, & aFuncDesc, & aDescPut, & aVarDesc);
|
|
if ( ! aFuncDesc )
|
|
{
|
|
throw IllegalArgumentException(
|
|
OUSTR("[automation bridge] The object does not have a function"
|
|
"or readable property \"")
|
|
+ sFuncName, Reference<XInterface>(), 0);
|
|
}
|
|
}
|
|
*pFuncDesc = aFuncDesc.Detach();
|
|
}
|
|
}
|
|
bool IUnknownWrapper_Impl::getDispid(const OUString& sFuncName, DISPID * id)
|
|
{
|
|
OSL_ASSERT(m_spDispatch);
|
|
LPOLESTR lpsz = const_cast<LPOLESTR> (sFuncName.getStr());
|
|
HRESULT hr = m_spDispatch->GetIDsOfNames(IID_NULL, &lpsz, 1, LOCALE_USER_DEFAULT, id);
|
|
return hr == S_OK ? true : false;
|
|
}
|
|
void IUnknownWrapper_Impl::getFuncDesc(const OUString & sFuncName, FUNCDESC ** pFuncDesc)
|
|
|
|
{
|
|
OSL_ASSERT( * pFuncDesc == 0);
|
|
buildComTlbIndex();
|
|
typedef TLBFuncIndexMap::const_iterator cit;
|
|
typedef TLBFuncIndexMap::iterator it;
|
|
//We assume there is only one entry with the function name. A property
|
|
//would have two entries.
|
|
cit itIndex= m_mapComFunc.find(sFuncName);
|
|
if (itIndex == m_mapComFunc.end())
|
|
{
|
|
//try case insensive with IDispatch::GetIDsOfNames
|
|
DISPID id;
|
|
if (getDispid(sFuncName, &id))
|
|
{
|
|
CComBSTR memberName;
|
|
unsigned int pcNames=0;
|
|
// get the case sensitive name
|
|
if( SUCCEEDED(getTypeInfo()->GetNames( id, & memberName, 1, &pcNames)))
|
|
{
|
|
//get the associated index and add an entry to the map
|
|
//with the name sFuncName which differs in the casing of the letters to
|
|
//the actual name as obtained from ITypeInfo
|
|
cit itOrg = m_mapComFunc.find(OUString(memberName));
|
|
OSL_ASSERT(itOrg != m_mapComFunc.end());
|
|
itIndex =
|
|
m_mapComFunc.insert( TLBFuncIndexMap::value_type
|
|
( make_pair(sFuncName, itOrg->second ) ));
|
|
}
|
|
}
|
|
}
|
|
|
|
#if OSL_DEBUG_LEVEL >= 1
|
|
// There must only be one entry if sFuncName represents a function or two
|
|
// if it is a property
|
|
pair<cit, cit> p = m_mapComFunc.equal_range(sFuncName.toAsciiLowerCase());
|
|
int numEntries = 0;
|
|
for ( ;p.first != p.second; p.first ++, numEntries ++);
|
|
OSL_ASSERT( ! (numEntries > 3) );
|
|
#endif
|
|
if( itIndex != m_mapComFunc.end())
|
|
{
|
|
ITypeInfo* pType= getTypeInfo();
|
|
FUNCDESC * pDesc = NULL;
|
|
if (SUCCEEDED(pType->GetFuncDesc(itIndex->second, & pDesc)))
|
|
{
|
|
if (pDesc->invkind == INVOKE_FUNC)
|
|
{
|
|
(*pFuncDesc) = pDesc;
|
|
}
|
|
else
|
|
{
|
|
pType->ReleaseFuncDesc(pDesc);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
throw BridgeRuntimeError(OUSTR("[automation bridge] Could not get "
|
|
"FUNCDESC for ") + sFuncName);
|
|
}
|
|
}
|
|
//else no entry found for sFuncName, pFuncDesc will not be filled in
|
|
}
|
|
|
|
void IUnknownWrapper_Impl::getPropDesc(const OUString & sFuncName, FUNCDESC ** pFuncDescGet,
|
|
FUNCDESC** pFuncDescPut, VARDESC** pVarDesc)
|
|
{
|
|
OSL_ASSERT( * pFuncDescGet == 0 && * pFuncDescPut == 0);
|
|
buildComTlbIndex();
|
|
typedef TLBFuncIndexMap::const_iterator cit;
|
|
pair<cit, cit> p = m_mapComFunc.equal_range(sFuncName);
|
|
if (p.first == m_mapComFunc.end())
|
|
{
|
|
//try case insensive with IDispatch::GetIDsOfNames
|
|
DISPID id;
|
|
if (getDispid(sFuncName, &id))
|
|
{
|
|
CComBSTR memberName;
|
|
unsigned int pcNames=0;
|
|
// get the case sensitive name
|
|
if( SUCCEEDED(getTypeInfo()->GetNames( id, & memberName, 1, &pcNames)))
|
|
{
|
|
//As opposed to getFuncDesc, we do not add the value because we would
|
|
// need to find the get and set description for the property. This would
|
|
//mean to iterate over all FUNCDESCs again.
|
|
p = m_mapComFunc.equal_range(OUString(memberName));
|
|
}
|
|
}
|
|
}
|
|
|
|
for ( int i = 0 ;p.first != p.second; p.first ++, i ++)
|
|
{
|
|
// There are a maximum of two entries, property put and property get
|
|
OSL_ASSERT( ! (i > 2) );
|
|
ITypeInfo* pType= getTypeInfo();
|
|
FUNCDESC * pFuncDesc = NULL;
|
|
if (SUCCEEDED( pType->GetFuncDesc(p.first->second, & pFuncDesc)))
|
|
{
|
|
if (pFuncDesc->invkind == INVOKE_PROPERTYGET)
|
|
{
|
|
(*pFuncDescGet) = pFuncDesc;
|
|
}
|
|
else if (pFuncDesc->invkind == INVOKE_PROPERTYPUT ||
|
|
pFuncDesc->invkind == INVOKE_PROPERTYPUTREF)
|
|
{
|
|
//a property can have 3 entries, put, put ref, get
|
|
// If INVOKE_PROPERTYPUTREF or INVOKE_PROPERTYPUT is used
|
|
//depends on what is found first.
|
|
if ( * pFuncDescPut)
|
|
{
|
|
//we already have found one
|
|
pType->ReleaseFuncDesc(pFuncDesc);
|
|
}
|
|
else
|
|
{
|
|
(*pFuncDescPut) = pFuncDesc;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pType->ReleaseFuncDesc(pFuncDesc);
|
|
}
|
|
}
|
|
//ITypeInfo::GetFuncDesc may even provide a funcdesc for a VARDESC
|
|
// with invkind = INVOKE_FUNC. Since this function should only return
|
|
//a value for a real property (XInvokation::hasMethod, ..::hasProperty
|
|
//we need to make sure that sFuncName represents a real property.
|
|
VARDESC * pVD = NULL;
|
|
if (SUCCEEDED(pType->GetVarDesc(p.first->second, & pVD)))
|
|
(*pVarDesc) = pVD;
|
|
}
|
|
//else no entry for sFuncName, pFuncDesc will not be filled in
|
|
}
|
|
|
|
VARTYPE IUnknownWrapper_Impl::getElementTypeDesc(const TYPEDESC *desc)
|
|
{
|
|
VARTYPE _type;
|
|
|
|
if (desc->vt == VT_PTR)
|
|
{
|
|
_type = getElementTypeDesc(desc->lptdesc);
|
|
_type |= VT_BYREF;
|
|
}
|
|
else if (desc->vt == VT_SAFEARRAY)
|
|
{
|
|
_type = getElementTypeDesc(desc->lptdesc);
|
|
_type |= VT_ARRAY;
|
|
}
|
|
else if (desc->vt == VT_USERDEFINED)
|
|
{
|
|
ITypeInfo* thisInfo = getTypeInfo(); //kept by this instance
|
|
CComPtr<ITypeInfo> spRefInfo;
|
|
thisInfo->GetRefTypeInfo(desc->hreftype, & spRefInfo.p);
|
|
if (spRefInfo)
|
|
{
|
|
TypeAttr attr(spRefInfo);
|
|
spRefInfo->GetTypeAttr( & attr);
|
|
if (attr->typekind == TKIND_ENUM)
|
|
{
|
|
//We use the type of the first enum value.
|
|
if (attr->cVars == 0)
|
|
{
|
|
throw BridgeRuntimeError(OUSTR("[automation bridge] Could "
|
|
"not obtain type description"));
|
|
}
|
|
VarDesc var(spRefInfo);
|
|
spRefInfo->GetVarDesc(0, & var);
|
|
_type = var->lpvarValue->vt;
|
|
}
|
|
else if (attr->typekind == TKIND_INTERFACE)
|
|
{
|
|
_type = VT_UNKNOWN;
|
|
}
|
|
else if (attr->typekind == TKIND_DISPATCH)
|
|
{
|
|
_type = VT_DISPATCH;
|
|
}
|
|
else
|
|
{
|
|
throw BridgeRuntimeError(OUSTR("[automation bridge] "
|
|
"Unhandled user defined type."));
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_type = desc->vt;
|
|
}
|
|
return _type;
|
|
}
|
|
|
|
void IUnknownWrapper_Impl::buildComTlbIndex()
|
|
{
|
|
if ( ! m_bComTlbIndexInit)
|
|
{
|
|
MutexGuard guard(getBridgeMutex());
|
|
{
|
|
if ( ! m_bComTlbIndexInit)
|
|
{
|
|
OUString sError;
|
|
ITypeInfo* pType= getTypeInfo();
|
|
TypeAttr typeAttr(pType);
|
|
if( SUCCEEDED( pType->GetTypeAttr( &typeAttr)))
|
|
{
|
|
for( long i= 0; i < typeAttr->cFuncs; i++)
|
|
{
|
|
FuncDesc funcDesc(pType);
|
|
if( SUCCEEDED( pType->GetFuncDesc( i, &funcDesc)))
|
|
{
|
|
CComBSTR memberName;
|
|
unsigned int pcNames=0;
|
|
if( SUCCEEDED(pType->GetNames( funcDesc->memid, & memberName, 1, &pcNames)))
|
|
{
|
|
OUString usName(memberName);
|
|
m_mapComFunc.insert( TLBFuncIndexMap::value_type( usName, i));
|
|
}
|
|
else
|
|
{
|
|
sError = OUSTR("[automation bridge] IUnknownWrapper_Impl::buildComTlbIndex, " \
|
|
"ITypeInfo::GetNames failed.");
|
|
}
|
|
}
|
|
else
|
|
sError = OUSTR("[automation bridge] IUnknownWrapper_Impl::buildComTlbIndex, " \
|
|
"ITypeInfo::GetFuncDesc failed.");
|
|
}
|
|
|
|
//If we create an Object in JScript and a a property then it
|
|
//has VARDESC instead of FUNCDESC
|
|
for (long i = 0; i < typeAttr->cVars; i++)
|
|
{
|
|
VarDesc varDesc(pType);
|
|
if (SUCCEEDED(pType->GetVarDesc(i, & varDesc)))
|
|
{
|
|
CComBSTR memberName;
|
|
unsigned int pcNames = 0;
|
|
if (SUCCEEDED(pType->GetNames(varDesc->memid, & memberName, 1, &pcNames)))
|
|
{
|
|
if (varDesc->varkind == VAR_DISPATCH)
|
|
{
|
|
OUString usName(memberName);
|
|
m_mapComFunc.insert(TLBFuncIndexMap::value_type(
|
|
usName, i));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
sError = OUSTR("[automation bridge] IUnknownWrapper_Impl::buildComTlbIndex, " \
|
|
"ITypeInfo::GetNames failed.");
|
|
}
|
|
}
|
|
else
|
|
sError = OUSTR("[automation bridge] IUnknownWrapper_Impl::buildComTlbIndex, " \
|
|
"ITypeInfo::GetVarDesc failed.");
|
|
|
|
}
|
|
}
|
|
else
|
|
sError = OUSTR("[automation bridge] IUnknownWrapper_Impl::buildComTlbIndex, " \
|
|
"ITypeInfo::GetTypeAttr failed.");
|
|
|
|
if (sError.getLength())
|
|
{
|
|
throw BridgeRuntimeError(sError);
|
|
}
|
|
|
|
m_bComTlbIndexInit = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
ITypeInfo* IUnknownWrapper_Impl::getTypeInfo()
|
|
{
|
|
HRESULT hr= S_OK;
|
|
if( !m_spDispatch)
|
|
{
|
|
throw BridgeRuntimeError(OUSTR("The object has no IDispatch interface!"));
|
|
}
|
|
|
|
if( !m_spTypeInfo )
|
|
{
|
|
MutexGuard guard(getBridgeMutex());
|
|
if( ! m_spTypeInfo)
|
|
{
|
|
CComPtr< ITypeInfo > spType;
|
|
if( SUCCEEDED( m_spDispatch->GetTypeInfo( 0, LOCALE_USER_DEFAULT, &spType.p)))
|
|
|
|
{
|
|
OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
|
|
|
|
//If this is a dual interface then TYPEATTR::typekind is usually TKIND_INTERFACE
|
|
//We need to get the type description for TKIND_DISPATCH
|
|
TypeAttr typeAttr(spType.p);
|
|
if( SUCCEEDED(spType->GetTypeAttr( &typeAttr)))
|
|
{
|
|
if (typeAttr->typekind == TKIND_INTERFACE &&
|
|
typeAttr->wTypeFlags & TYPEFLAG_FDUAL)
|
|
{
|
|
HREFTYPE refDispatch;
|
|
if (SUCCEEDED(spType->GetRefTypeOfImplType(-1, &refDispatch)))
|
|
{
|
|
CComPtr<ITypeInfo> spTypeDisp;
|
|
if (SUCCEEDED(spType->GetRefTypeInfo(refDispatch, & spTypeDisp)))
|
|
m_spTypeInfo= spTypeDisp;
|
|
}
|
|
else
|
|
{
|
|
throw BridgeRuntimeError(
|
|
OUSTR("[automation bridge] Could not obtain type information "
|
|
"for dispatch interface." ));
|
|
}
|
|
}
|
|
else if (typeAttr->typekind == TKIND_DISPATCH)
|
|
{
|
|
m_spTypeInfo= spType;
|
|
}
|
|
else
|
|
{
|
|
throw BridgeRuntimeError(
|
|
OUSTR("[automation bridge] Automation object does not "
|
|
"provide type information."));
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
throw BridgeRuntimeError(OUSTR("[automation bridge]The dispatch object does not "
|
|
"support ITypeInfo!"));
|
|
}
|
|
}
|
|
}
|
|
return m_spTypeInfo;
|
|
}
|
|
|
|
} // end namespace
|
|
|