diff options
Diffstat (limited to 'extensions/source/ole')
21 files changed, 9924 insertions, 0 deletions
diff --git a/extensions/source/ole/comifaces.hxx b/extensions/source/ole/comifaces.hxx new file mode 100644 index 000000000000..d33f350b8f70 --- /dev/null +++ b/extensions/source/ole/comifaces.hxx @@ -0,0 +1,72 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef __COMIFACES_HXX +#define __COMIFACES_HXX + +#include <com/sun/star/uno/XInterface.hpp> + +using namespace com::sun::star::uno; + +#ifdef __MINGW32__ +DEFINE_GUID(IID_IJScriptValueObject, 0xe40a2331, 0x3bc1, 0x11d4, 0x83, 0x21, 0x00, 0x50, 0x04, 0x52, 0x6a, 0xb4); +DEFINE_GUID(IID_IUnoObjectWrapper, 0x7B5C3410, 0x66FA, 0x11d4, 0x83, 0x2A, 0x00, 0x50, 0x04, 0x52, 0x6A, 0xB4); +DEFINE_GUID(IID_IUnoTypeWrapper, 0x8BB66591, 0xA544, 0x4de9, 0x82, 0x2C, 0x57, 0xAB, 0x57, 0xBC, 0xED, 0x1C); +#endif +MIDL_INTERFACE("e40a2331-3bc1-11d4-8321-005004526ab4") +IJScriptValueObject: public IUnknown +{ + STDMETHOD( Set)( VARIANT type, VARIANT value)= 0; + STDMETHOD( Get)( VARIANT *val)= 0; + STDMETHOD( InitOutParam)()= 0; + STDMETHOD( InitInOutParam)( VARIANT type, VARIANT value)= 0; + STDMETHOD( IsOutParam)( VARIANT_BOOL * flag)= 0; + STDMETHOD( IsInOutParam)( VARIANT_BOOL * flag)= 0; + STDMETHOD( GetValue)( BSTR* type, VARIANT *value)= 0; + +}; + +MIDL_INTERFACE("7B5C3410-66FA-11d4-832A-005004526AB4") +IUnoObjectWrapper: public IUnknown +{ + STDMETHOD( getWrapperXInterface)( Reference<XInterface>* pInt)=0; + STDMETHOD( getOriginalUnoObject)( Reference<XInterface>* pInt)=0; + STDMETHOD( getOriginalUnoStruct)( Any * pStruct)=0; + +}; + +MIDL_INTERFACE("8BB66591-A544-4de9-822C-57AB57BCED1C") +IUnoTypeWrapper: public IUnknown +{ + STDMETHOD(put_Name)(BSTR val) = 0; + STDMETHOD(get_Name)(BSTR* pVal) = 0; +}; + + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/ole/jscriptclasses.cxx b/extensions/source/ole/jscriptclasses.cxx new file mode 100644 index 000000000000..5b5083a0c848 --- /dev/null +++ b/extensions/source/ole/jscriptclasses.cxx @@ -0,0 +1,324 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_extensions.hxx" +#include "jscriptclasses.hxx" + +//======================================================================== +// JScriptValue +//======================================================================== +JScriptValue::JScriptValue(): m_bOutParam(0), m_bInOutParam(0) +{ +} + +JScriptValue::~JScriptValue() +{ +} + + +// JScriptValue, IDispatch -------------------------------------------- +STDMETHODIMP JScriptValue::GetTypeInfoCount(UINT* /*pctinfo*/) +{ + return E_NOTIMPL; +} + +// JScriptValue, IDispatch -------------------------------------------- +STDMETHODIMP JScriptValue::GetTypeInfo( UINT /*iTInfo*/, + LCID /*lcid*/, + ITypeInfo** /*ppTInfo*/) +{ + return E_NOTIMPL; +} + +// JScriptValue, IDispatch -------------------------------------------- +STDMETHODIMP JScriptValue::GetIDsOfNames( REFIID /*riid*/, + LPOLESTR *rgszNames, + UINT /*cNames*/, + LCID /*lcid*/, + DISPID *rgDispId) +{ + if( !rgDispId) + return E_POINTER; + + + HRESULT ret= S_OK; + CComBSTR name(*rgszNames); + name.ToLower(); + + if( name == CComBSTR( L"set") ) + *rgDispId= 1; + else if( name == CComBSTR( L"get") ) + *rgDispId= 2; + else if( name == CComBSTR( L"initoutparam") ) + *rgDispId= 3; + else if( name == CComBSTR( L"initinoutparam") ) + *rgDispId= 4; + else + ret= DISP_E_UNKNOWNNAME; + + return ret; +} + +// JScriptValue, IDispatch -------------------------------------------- +STDMETHODIMP JScriptValue::Invoke( DISPID dispIdMember, + REFIID /*riid*/, + LCID /*lcid*/, + WORD wFlags, + DISPPARAMS *pDispParams, + VARIANT *pVarResult, + EXCEPINFO* /*pExcepInfo*/, + UINT* /*puArgErr*/) +{ + if( pDispParams->cNamedArgs) + return DISP_E_NONAMEDARGS; + + + HRESULT ret= S_OK; + switch( dispIdMember) + { + case 0: // DISPID_VALUE + if( wFlags & DISPATCH_PROPERTYGET && pVarResult) + { + if( FAILED( VariantCopy( pVarResult, &m_varValue))) + ret= E_FAIL; + } + else + ret= E_POINTER; + break; + case 1: + if( wFlags & DISPATCH_METHOD) + ret= Set( pDispParams->rgvarg[1], pDispParams->rgvarg[0]); + if( FAILED( ret)) + ret= DISP_E_EXCEPTION; + break; + case 2: + if( wFlags & DISPATCH_METHOD) + ret= Get( pVarResult); + if( FAILED( ret)) + ret= DISP_E_EXCEPTION; + break; + case 3: + if( wFlags & DISPATCH_METHOD) + ret= InitOutParam(); + if( FAILED( ret)) + ret= DISP_E_EXCEPTION; + break; + case 4: + if( wFlags & DISPATCH_METHOD) + ret= InitInOutParam( pDispParams->rgvarg[1], pDispParams->rgvarg[0]); + if( FAILED( ret)) + ret= DISP_E_EXCEPTION; + break; + default: + ret= DISP_E_MEMBERNOTFOUND; + break; + } + + return ret; +} + +// JScriptValue, IScriptOutParam----------------------- +STDMETHODIMP JScriptValue::Set( VARIANT type, VARIANT value) +{ + Lock(); + HRESULT hr= S_OK; + m_varValue.Clear(); + hr= VariantCopyInd( &m_varValue, &value); + VARIANT var; + VariantInit( &var); + if( SUCCEEDED( hr= VariantChangeType( &var, &type, 0, VT_BSTR))) + m_bstrType= var.bstrVal; + Unlock(); + return hr; +} +// JScriptValue, IScriptOutParam----------------------- +STDMETHODIMP JScriptValue::Get( VARIANT *val) +{ + Lock(); + if( !val) + return E_POINTER; + HRESULT hr= VariantCopy( val, &m_varValue); + Unlock(); + return hr; +} + +STDMETHODIMP JScriptValue::InitOutParam() +{ + Lock(); + m_varValue.Clear(); + m_bOutParam= true; + m_bInOutParam= false; + Unlock(); + return S_OK; +} + +STDMETHODIMP JScriptValue::InitInOutParam( VARIANT type, VARIANT value) +{ + Lock(); + m_bInOutParam= true; + m_bOutParam= false; + Unlock(); + return Set( type, value); +} + +STDMETHODIMP JScriptValue::IsOutParam( VARIANT_BOOL * flag) +{ + Lock(); + if( !flag) + return E_POINTER; + *flag= m_bOutParam ? VARIANT_TRUE : VARIANT_FALSE; + Unlock(); + return S_OK; +} + +STDMETHODIMP JScriptValue::IsInOutParam( VARIANT_BOOL * flag) +{ + Lock(); + if( !flag) + return E_POINTER; + *flag= m_bInOutParam ? VARIANT_TRUE : VARIANT_FALSE; + Unlock(); + return S_OK; +} + +STDMETHODIMP JScriptValue::GetValue( BSTR* type, VARIANT *value) +{ + Lock(); + if( !type || !value) + return E_POINTER; + HRESULT hr; + if( SUCCEEDED( hr= m_bstrType.CopyTo( type))) + hr= VariantCopy( value, &m_varValue); + Unlock(); + return hr; +} + +//########################################################################################## +// JScriptOutValue +//########################################################################################## + +JScriptOutParam::JScriptOutParam() +{ +} + +JScriptOutParam::~JScriptOutParam() +{ +} + + +// JScriptOutParam, IDispatch -------------------------------------------- +STDMETHODIMP JScriptOutParam::GetTypeInfoCount(UINT* /*pctinfo*/) +{ + return E_NOTIMPL; +} + +// JScriptOutParam, IDispatch -------------------------------------------- +STDMETHODIMP JScriptOutParam::GetTypeInfo( UINT /*iTInfo*/, + LCID /*lcid*/, + ITypeInfo** /*ppTInfo*/) +{ + return E_NOTIMPL; +} + +// JScriptOutParam, IDispatch -------------------------------------------- +STDMETHODIMP JScriptOutParam::GetIDsOfNames( REFIID /*riid*/, + LPOLESTR *rgszNames, + UINT /*cNames*/, + LCID /*lcid*/, + DISPID *rgDispId) +{ + if( !rgDispId) + return E_POINTER; + + + HRESULT ret= S_OK; + CComBSTR name(*rgszNames); + name.ToLower(); + + if( name == CComBSTR( L"0") ) + *rgDispId= 1; + else + ret= DISP_E_UNKNOWNNAME; + + return ret; +} + +// JScriptOutParam, IDispatch -------------------------------------------- +STDMETHODIMP JScriptOutParam::Invoke( DISPID dispIdMember, + REFIID /*riid*/, + LCID /*lcid*/, + WORD wFlags, + DISPPARAMS *pDispParams, + VARIANT *pVarResult, + EXCEPINFO* /*pExcepInfo*/, + UINT* /*puArgErr*/) +{ + HRESULT ret= S_OK; + switch( dispIdMember) + { + case 0: // DISPID_VALUE + if( wFlags & DISPATCH_PROPERTYGET && pVarResult) + { + if( FAILED( VariantCopy( pVarResult, &m_varValue))) + ret= E_FAIL; + } + else if( wFlags & DISPATCH_PROPERTYPUT || wFlags & DISPATCH_PROPERTYPUTREF) + { + m_varValue.Clear(); + if( FAILED( VariantCopyInd( &m_varValue, &pDispParams->rgvarg[0]))) + ret= E_FAIL; + } + else + ret= E_POINTER; + break; + case 1: // + if( wFlags & DISPATCH_PROPERTYGET && pVarResult) + { + if( FAILED( VariantCopy( pVarResult, &m_varValue))) + ret= E_FAIL; + } + else if( wFlags & DISPATCH_PROPERTYPUT || wFlags & DISPATCH_PROPERTYPUTREF) + { + m_varValue.Clear(); + if( FAILED( VariantCopyInd( &m_varValue, &pDispParams->rgvarg[0]))) + ret= E_FAIL; + } + else + ret= E_POINTER; + break; + + default: + ret= DISP_E_MEMBERNOTFOUND; + break; + } + + return ret; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/ole/jscriptclasses.hxx b/extensions/source/ole/jscriptclasses.hxx new file mode 100644 index 000000000000..7eab4bd8c8aa --- /dev/null +++ b/extensions/source/ole/jscriptclasses.hxx @@ -0,0 +1,163 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef __JSCRIPTCLASSES_HXX +#define __JSCRIPTCLASSES_HXX + + +#pragma warning (push,1) +#pragma warning (disable:4548) + +#include <tools/presys.h> +#define STRICT +#define _WIN32_WINNT 0x0403 +#define _WIN32_DCOM +#if OSL_DEBUG_LEVEL > 0 +//#define _ATL_DEBUG_INTERFACES +#endif +#include <atlbase.h> +extern CComModule _Module; +#include <atlcom.h> +#include <tools/postsys.h> + +#pragma warning (pop) +#pragma warning (disable:4505) + // disable "unreferenced local function has been removed" globally + +#include "comifaces.hxx" + + + +// Sequences are represented by prepending "[]", e.g. []char, [][]byte, [][][]object, etc. + +// To make a JScriptValue object to an out parameter, call +// "InitOutParam" and to make it a in/out parameter call +// "InitInOutParam" + +// If the object represents an out parameter then the value can after the call +// be retrived by "Get". + +// From JavaScript the functions Get, Set, InitOutParam and InitInOutParam are +// used, that is they are accessible through IDispatch. The functions are used +// by the bridge. + +class JScriptValue: + public CComObjectRootEx<CComMultiThreadModel>, + public IJScriptValueObject, + public IDispatch +{ +public: + JScriptValue(); + virtual ~JScriptValue(); + + BEGIN_COM_MAP(JScriptValue) + COM_INTERFACE_ENTRY(IDispatch) + COM_INTERFACE_ENTRY(IJScriptValueObject) + END_COM_MAP() + + // IDispatch ------------------------------------------- + STDMETHOD( GetTypeInfoCount)(UINT *pctinfo); + + STDMETHOD( GetTypeInfo)( UINT iTInfo, + LCID lcid, + ITypeInfo **ppTInfo); + + STDMETHOD( GetIDsOfNames)( REFIID riid, + LPOLESTR *rgszNames, + UINT cNames, + LCID lcid, + DISPID *rgDispId); + + STDMETHOD( Invoke)( DISPID dispIdMember, + REFIID riid, + LCID lcid, + WORD wFlags, + DISPPARAMS *pDispParams, + VARIANT *pVarResult, + EXCEPINFO *pExcepInfo, + UINT *puArgErr); + // IJScriptOutParam -------------------------------------- + + STDMETHOD( Set)( VARIANT type, VARIANT value); + STDMETHOD( Get)( VARIANT *val); + STDMETHOD( InitOutParam)(); + STDMETHOD( InitInOutParam)( VARIANT type, VARIANT value); + STDMETHOD( IsOutParam)( VARIANT_BOOL * flag); + STDMETHOD( IsInOutParam)( VARIANT_BOOL * flag); + STDMETHOD( GetValue)( BSTR* type, VARIANT *value); + + + CComVariant m_varValue; + CComBSTR m_bstrType; + unsigned m_bOutParam: 1; + unsigned m_bInOutParam: 1; + +}; + +// If a class is implemented in JScript, then its method +class JScriptOutParam: + public CComObjectRootEx<CComMultiThreadModel>, + public IDispatch +{ +public: + JScriptOutParam(); + virtual ~JScriptOutParam(); + + BEGIN_COM_MAP(JScriptOutParam) + COM_INTERFACE_ENTRY(IDispatch) + END_COM_MAP() + + // IDispatch ------------------------------------------- + STDMETHOD( GetTypeInfoCount)(UINT *pctinfo); + + STDMETHOD( GetTypeInfo)( UINT iTInfo, + LCID lcid, + ITypeInfo **ppTInfo); + + STDMETHOD( GetIDsOfNames)( REFIID riid, + LPOLESTR *rgszNames, + UINT cNames, + LCID lcid, + DISPID *rgDispId); + + STDMETHOD( Invoke)( DISPID dispIdMember, + REFIID riid, + LCID lcid, + WORD wFlags, + DISPPARAMS *pDispParams, + VARIANT *pVarResult, + EXCEPINFO *pExcepInfo, + UINT *puArgErr); + + +private: + CComVariant m_varValue; +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/ole/makefile.mk b/extensions/source/ole/makefile.mk new file mode 100644 index 000000000000..e20e83e0f1e7 --- /dev/null +++ b/extensions/source/ole/makefile.mk @@ -0,0 +1,129 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* +PRJ=..$/.. + +# ----------------------------------------------------------------- + +PRJNAME=extensions +TARGET=oleautobridge.uno +TARGET2=oleautobridge2.uno + +ENABLE_EXCEPTIONS=TRUE + +.INCLUDE : $(PRJ)$/util$/makefile.pmk + +LIBTARGET=NO +USE_DEFFILE=YES + +USE_DEFFILE=TRUE + +INCPRE+= $(foreach,i,$(ATL_INCLUDE) -I$(i)) + +# --- Settings ----------------------------------------------------- + +.IF "$(GUI)" == "WNT" && "$(DISABLE_ATL)"=="" + +.IF "$(USE_STLP_DEBUG)"!="" +CDEFS+=-D_DEBUG +.ENDIF # "$(USE_STLP_DEBUG)"!="" + +SLOFILES= \ + $(SLO)$/servreg.obj \ + $(SLO)$/servprov.obj \ + $(SLO)$/unoobjw.obj \ + $(SLO)$/oleobjw.obj \ + $(SLO)$/olethread.obj \ + $(SLO)$/oledll.obj \ + $(SLO)$/jscriptclasses.obj \ + $(SLO)$/ole2uno.obj \ + $(SLO)$/windata.obj \ + $(SLO)$/unotypewrapper.obj + +SECOND_BUILD=OWNGUID +OWNGUID_SLOFILES=$(SLOFILES) +OWNGUIDCDEFS+= -DOWNGUID + +# the original library +SHL1TARGET=$(TARGET) +SHL1STDLIBS=\ + $(SALLIB) \ + $(CPPULIB) \ + $(CPPUHELPERLIB) \ + $(OLE32LIB) \ + $(UUIDLIB) \ + $(ADVAPI32LIB) \ + $(OLEAUT32LIB) + +.IF "$(COM)"=="MSC" +.IF "$(WINDOWS_VISTA_PSDK)"!="" || "$(CCNUMVER)"<="001399999999" +.IF "$(USE_STLP_DEBUG)" != "" + SHL1STDLIBS+= $(ATL_LIB)$/atlsd.lib +.ELSE + SHL1STDLIBS+= $(ATL_LIB)$/atls.lib +.ENDIF +.ENDIF # "$(WINDOWS_VISTA_PSDK)"!="" || "$(CCNUMVER)"<="001399999999" +.ENDIF # "$(COM)"=="MSC" + +SHL1LIBS= +SHL1OBJS=$(SLOFILES) + +DEF1NAME=$(SHL1TARGET) +DEF1EXPORTFILE=$(SHL1TARGET).dxp + +# the second library +SHL2TARGET=$(TARGET2) +SHL2STDLIBS=\ + $(SALLIB) \ + $(CPPULIB) \ + $(CPPUHELPERLIB) \ + $(OLE32LIB) \ + $(UUIDLIB) \ + $(ADVAPI32LIB) \ + $(OLEAUT32LIB) + +.IF "$(COM)"=="MSC" +.IF "$(WINDOWS_VISTA_PSDK)"!="" || "$(CCNUMVER)"<="001399999999" +.IF "$(USE_STLP_DEBUG)" != "" + SHL2STDLIBS+= $(ATL_LIB)$/atlsd.lib +.ELSE + SHL2STDLIBS+= $(ATL_LIB)$/atls.lib +.ENDIF +.ENDIF # "$(WINDOWS_VISTA_PSDK)"!="" || "$(CCNUMVER)"<="001399999999" +.ENDIF # "$(COM)"=="MSC" + +SHL2LIBS= +SHL2OBJS=$(REAL_OWNGUID_SLOFILES) + +DEF2NAME=$(SHL2TARGET) +DEF2EXPORTFILE=$(TARGET).dxp + +.ENDIF + +#---------------------------------------------------------------- + +.INCLUDE : target.mk + diff --git a/extensions/source/ole/ole2uno.cxx b/extensions/source/ole/ole2uno.cxx new file mode 100644 index 000000000000..16060432ac75 --- /dev/null +++ b/extensions/source/ole/ole2uno.cxx @@ -0,0 +1,76 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_extensions.hxx" +#include "osl/getglobalmutex.hxx" +#include "rtl/instance.hxx" +#include "ole2uno.hxx" + +using namespace osl; +namespace ole_adapter +{ + +struct MutexInit +{ + Mutex * operator () () + { + static Mutex aInstance; + return &aInstance; + } +}; + + +Mutex * getBridgeMutex() +{ + return rtl_Instance< Mutex, MutexInit, ::osl::MutexGuard, + ::osl::GetGlobalMutex >::create( + MutexInit(), ::osl::GetGlobalMutex()); +} + + +// Mutex* getBridgeMutex() +// { +// static Mutex* pMutex= NULL; + +// if( ! pMutex) +// { +// MutexGuard guard( Mutex::getGlobalMutex() ); +// if( !pMutex) +// { +// static Mutex aMutex; +// pMutex= &aMutex; +// } +// } +// return pMutex; +// } + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/ole/ole2uno.hxx b/extensions/source/ole/ole2uno.hxx new file mode 100644 index 000000000000..fc3ad87ce0b5 --- /dev/null +++ b/extensions/source/ole/ole2uno.hxx @@ -0,0 +1,147 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _OLE2UNO_HXX +#define _OLE2UNO_HXX + + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#define STRICT +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0400 +#endif + +#define _WIN32_DCOM +#if OSL_DEBUG_LEVEL > 0 +//#define _ATL_DEBUG_INTERFACES +#endif + +#pragma warning (push,1) +#pragma warning (disable:4917) +#pragma warning (disable:4005) +#pragma warning (disable:4548) + +#include <tools/prewin.h> +#include <tchar.h> +#if (_MSC_VER >= 1200) || defined(__MINGW32__) +#include <dispex.h> +#endif +#include <tools/postwin.h> + +#include <tools/presys.h> +#include <list> +#include <tools/postsys.h> + +#pragma warning (pop) +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/lang/XSingleServiceFactory.hpp> +#include <com/sun/star/script/XInvocation.hpp> +#include <com/sun/star/registry/XRegistryKey.hpp> +#include <com/sun/star/bridge/XBridgeSupplier2.hpp> +#include <com/sun/star/bridge/ModelDependent.hpp> +#include <com/sun/star/reflection/InvocationTargetException.hpp> +#include <com/sun/star/uno/Exception.hpp> +#include <com/sun/star/beans/UnknownPropertyException.hpp> +#include <cppuhelper/implbase2.hxx> +#include <cppuhelper/implbase1.hxx> +#include <cppuhelper/typeprovider.hxx> +#include <cppuhelper/factory.hxx> +#include <sal/types.h> +#include <typelib/typeclass.h> +#include <osl/diagnose.h> +#include <osl/mutex.hxx> +#include <com/sun/star/uno/Reference.h> +#include <rtl/process.h> +#include <rtl/uuid.h> + +#define UNO_2_OLE_EXCEPTIONCODE 1001 +#define OUSTR(x) ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(x) ) +using namespace com::sun::star::uno; +using namespace com::sun::star::lang; +using namespace com::sun::star::script; +using namespace com::sun::star::registry; +using namespace com::sun::star::reflection; +using namespace com::sun::star::beans; +using namespace osl; +using namespace rtl; +using namespace std; + + + +namespace ole_adapter +{ + +const VARTYPE getVarType( const Any& val); +/* creates a Type object for a given type name. + + The function returns false if the name does not represent + a valid type. +*/ +bool getType( BSTR name, Type & type); +void o2u_attachCurrentThread(); + +struct equalOUString_Impl +{ + bool operator()(const OUString & s1, const OUString & s2) const + { + return s1 == s2; + } +}; + +struct hashOUString_Impl +{ + size_t operator()(const OUString & rName) const + { + return rName.hashCode(); + } +}; + + +class BridgeRuntimeError +{ +public: + BridgeRuntimeError(const OUString& sMessage) + { + message = sMessage; + } + OUString message; +}; + + +Mutex* getBridgeMutex(); + +} // end namespace + + + +#endif // _OLE2UNO_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/ole/oleautobridge.uno.dxp b/extensions/source/ole/oleautobridge.uno.dxp new file mode 100644 index 000000000000..e7947188aa92 --- /dev/null +++ b/extensions/source/ole/oleautobridge.uno.dxp @@ -0,0 +1,4 @@ +component_writeInfo @100 +component_getFactory @101 +component_getImplementationEnvironment @102 +component_canUnload @103 diff --git a/extensions/source/ole/oledll.cxx b/extensions/source/ole/oledll.cxx new file mode 100644 index 000000000000..5346aa940cf7 --- /dev/null +++ b/extensions/source/ole/oledll.cxx @@ -0,0 +1,72 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_extensions.hxx" + +#define STRICT +#define _WIN32_WINNT 0x0403 +#define _WIN32_DCOM + +#pragma warning (push,1) +#pragma warning (disable:4548) + +#if defined(_MSC_VER) && (_MSC_VER >= 1300) && !defined(_STLP_DEBUG) +#undef _DEBUG +#endif +#ifdef __MINGW32__ +#define _INIT_ATL_COMMON_VARS +#endif +#include <atlbase.h> +CComModule _Module; +#include <atlcom.h> + +#pragma warning (pop) + +BEGIN_OBJECT_MAP(ObjectMap) +END_OBJECT_MAP() + +///////////////////////////////////////////////////////////////////////////// +// DLL Entry Point + +extern "C" +BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/) +{ + if (dwReason == DLL_PROCESS_ATTACH) + { + _Module.Init(ObjectMap, hInstance, NULL); + DisableThreadLibraryCalls(hInstance); + } + else if (dwReason == DLL_PROCESS_DETACH) + { + _Module.Term(); + } + return TRUE; // ok +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/ole/oleobjw.cxx b/extensions/source/ole/oleobjw.cxx new file mode 100644 index 000000000000..20359a21901b --- /dev/null +++ b/extensions/source/ole/oleobjw.cxx @@ -0,0 +1,2391 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_extensions.hxx" +#include "ole2uno.hxx" +#include "rtl/ustrbuf.hxx" + + +#include "osl/diagnose.h" +#include "osl/doublecheckedlocking.h" +#include "osl/thread.h" + +#include "boost/scoped_array.hpp" +#include <com/sun/star/script/FailReason.hpp> +#include <com/sun/star/beans/XMaterialHolder.hpp> +#include <com/sun/star/script/XTypeConverter.hpp> +#include <com/sun/star/script/FinishEngineEvent.hpp> +#include <com/sun/star/script/InterruptReason.hpp> +#include <com/sun/star/script/XEngineListener.hpp> +#include <com/sun/star/script/XDebugging.hpp> +#include <com/sun/star/script/XInvocation.hpp> +#include <com/sun/star/script/ContextInformation.hpp> +#include <com/sun/star/script/FinishReason.hpp> +#include <com/sun/star/script/XEngine.hpp> +#include <com/sun/star/script/InterruptEngineEvent.hpp> +#include <com/sun/star/script/XLibraryAccess.hpp> +#include <com/sun/star/script/BasicErrorException.hpp> +#include <com/sun/star/bridge/ModelDependent.hpp> + +#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> +#include <rtl/ustring.hxx> + +#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::script; +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), m_bHasDfltMethod(false), m_bHasDfltProperty(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<XDefaultMethod>*>( 0)) && !m_bHasDfltMethod ) + return Any(); + if (t == getCppuType(static_cast<Reference<XDefaultProperty>*>( 0)) && !m_bHasDfltProperty ) + return Any(); + if ( ( t == getCppuType(static_cast<Reference<XInvocation>*>( 0)) || t == getCppuType(static_cast<Reference<XAutomationInvocation>*>( 0)) ) && !m_spDispatch) + return Any(); + + return WeakImplHelper6<XAutomationInvocation, XBridgeSupplier2, + XInitialization, XAutomationObject, XDefaultProperty, XDefaultMethod>::queryInterface(t); +} + +Reference<XIntrospectionAccess> SAL_CALL IUnknownWrapper_Impl::getIntrospection(void) + throw (RuntimeException ) +{ + Reference<XIntrospectionAccess> ret; + + return ret; +} + +Any SAL_CALL IUnknownWrapper_Impl::invokeGetProperty( const OUString& aPropertyName, const Sequence< Any >& aParams, Sequence< sal_Int16 >& aOutParamIndex, Sequence< Any >& aOutParam ) +{ + Any aResult; + try + { + o2u_attachCurrentThread(); + ITypeInfo * pInfo = getTypeInfo(); + FuncDesc aDescGet(pInfo); + FuncDesc aDescPut(pInfo); + VarDesc aVarDesc(pInfo); + getPropDesc(aPropertyName, & aDescGet, & aDescPut, & aVarDesc); + if ( !aDescGet ) + { + OUString msg(OUSTR("[automation bridge]Property \"") + aPropertyName + + OUSTR("\" is not supported")); + throw UnknownPropertyException(msg, Reference<XInterface>()); + } + aResult = invokeWithDispIdComTlb( aDescGet, aPropertyName, aParams, aOutParamIndex, aOutParam ); + } + catch ( Exception& e ) + { + throw RuntimeException(OUSTR("[automation bridge] unexpected exception in " + "IUnknownWrapper_Impl::invokeGetProperty ! Message : \n") + + e.Message, Reference<XInterface>()); + } + return aResult; +} + +Any SAL_CALL IUnknownWrapper_Impl::invokePutProperty( const OUString& aPropertyName, const Sequence< Any >& aParams, Sequence< sal_Int16 >& aOutParamIndex, Sequence< Any >& aOutParam ) +{ + Any aResult; + try + { + o2u_attachCurrentThread(); + ITypeInfo * pInfo = getTypeInfo(); + FuncDesc aDescGet(pInfo); + FuncDesc aDescPut(pInfo); + VarDesc aVarDesc(pInfo); + getPropDesc(aPropertyName, & aDescGet, & aDescPut, & aVarDesc); + if ( !aDescPut ) + { + OUString msg(OUSTR("[automation bridge]Property \"") + aPropertyName + + OUSTR("\" is not supported")); + throw UnknownPropertyException(msg, Reference<XInterface>()); + } + aResult = invokeWithDispIdComTlb( aDescPut, aPropertyName, aParams, aOutParamIndex, aOutParam ); + } + catch ( Exception& e ) + { + throw RuntimeException(OUSTR("[automation bridge] unexpected exception in " + "IUnknownWrapper_Impl::invokePutProperty ! Message : \n") + + e.Message, Reference<XInterface>()); + } + return aResult; +} + + +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 (InvocationTargetException &) + { + 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, ::sal::static_int_cast< VARTYPE, int >( 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, ::sal::static_int_cast< WORD, INVOKEKIND >( 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(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("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(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("call to OLE object failed")), static_cast<XInterface*>( + static_cast<XWeak*>(this)), ::sal::static_int_cast< sal_Int16, unsigned int >( uArgErr )) ; + break; + case DISP_E_TYPEMISMATCH: + throw CannotConvertException(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("call to OLE object failed")), static_cast<XInterface*>( + static_cast<XWeak*>(this)), TypeClass_UNKNOWN, FailReason::UNKNOWN, ::sal::static_int_cast< sal_Int16, unsigned int >( uArgErr )); + break; + case DISP_E_UNKNOWNINTERFACE: + throw RuntimeException(); + break; + case DISP_E_UNKNOWNLCID: + throw RuntimeException(); + break; + case DISP_E_PARAMNOTOPTIONAL: + throw CannotConvertException(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("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(); + // I was going to implement an XServiceInfo interface to allow the type + // of the automation object to be exposed.. but it seems + // from looking at comments in the code that it is possible for + // this object to actually wrap an UNO object ( I guess if automation is + // used from MSO to create Openoffice objects ) Therefore, those objects + // will more than likely already have their own XServiceInfo interface. + // Instead here I chose a name that should be illegal both in COM and + // UNO ( from an IDL point of view ) therefore I think this is a safe + // hack + if ( aPropertyName.equals( rtl::OUString::createFromAscii("$GetTypeName") )) + { + if ( pInfo && m_sTypeName.getLength() == 0 ) + { + m_sTypeName = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("IDispatch") ); + CComBSTR sName; + + if ( SUCCEEDED( pInfo->GetDocumentation( -1, &sName, NULL, NULL, NULL ) ) ) + { + rtl::OUString sTmp( reinterpret_cast<const sal_Unicode*>(LPCOLESTR(sName))); + if ( sTmp.indexOf('_') == 0 ) + sTmp = sTmp.copy(1); + // do we own the memory for pTypeLib, msdn doco is vague + // I'll assume we do + CComPtr< ITypeLib > pTypeLib; + unsigned int index; + if ( SUCCEEDED( pInfo->GetContainingTypeLib( &pTypeLib.p, &index )) ) + { + if ( SUCCEEDED( pTypeLib->GetDocumentation( -1, &sName, NULL, NULL, NULL ) ) ) + { + rtl::OUString sLibName( reinterpret_cast<const sal_Unicode*>(LPCOLESTR(sName))); + m_sTypeName = sLibName.concat( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(".") ) ).concat( sTmp ); + + } + } + } + + } + ret <<= m_sTypeName; + return ret; + } + 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(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription)), + Reference<XInterface>()); + break; + case DISP_E_BADVARTYPE: + throw RuntimeException(OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription)), + Reference<XInterface>()); + break; + case DISP_E_EXCEPTION: + throw RuntimeException(OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription)), + Reference<XInterface>()); + break; + case DISP_E_MEMBERNOTFOUND: + throw UnknownPropertyException(OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription)), + Reference<XInterface>()); + break; + case DISP_E_NONAMEDARGS: + throw RuntimeException(OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription)), + Reference<XInterface>()); + break; + case DISP_E_OVERFLOW: + throw RuntimeException(OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription)), + Reference<XInterface>()); + break; + case DISP_E_PARAMNOTFOUND: + throw RuntimeException(OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription)), + Reference<XInterface>()); + break; + case DISP_E_TYPEMISMATCH: + throw RuntimeException(OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription)), + Reference<XInterface>()); + break; + case DISP_E_UNKNOWNINTERFACE: + throw RuntimeException(OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription)), + Reference<XInterface>()); + break; + case DISP_E_UNKNOWNLCID: + throw RuntimeException(OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription)), + Reference<XInterface>()); + break; + case DISP_E_PARAMNOTOPTIONAL: + throw RuntimeException(OUString(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription)), + Reference<XInterface>()); + break; + default: + throw RuntimeException(OUString(reinterpret_cast<const sal_Unicode*>(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); + + // we should probably just check the funckind + // basic has been modified to handle properties ( 'get' ) props at + // least with paramaters + // additionally you can call invoke(Get|Set)Property on the bridge + // you can determine if a property has parameter is hasMethod + // returns true for the name + if (aVarDesc + || aDescPut + || aDescGet ) + { + 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 = ::sal::static_int_cast< sal_Int16, int >( i ); + throw; + } + catch (CannotConvertException & e) + { + e.ArgumentIndex = i; + throw; + } + } + else // it is an JScriptObject + { + int i = 0; + try + { + for( ; 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()); +#ifdef __MINGW32__ + CComQIPtr<IDispatch, &__uuidof(IDispatch)> pDisp( pUnk); +#else + CComQIPtr<IDispatch> pDisp( pUnk); +#endif + + 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 = ::sal::static_int_cast< sal_Int16, int >( 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 = 0; + try + { + for( ; 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 = ::sal::static_int_cast< sal_Int16, int >( 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( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("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(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("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(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("call to OLE object failed")), static_cast<XInterface*>( + static_cast<XWeak*>(this)), ::sal::static_int_cast< sal_Int16, unsigned int >( uArgErr )); + break; + case DISP_E_TYPEMISMATCH: + throw CannotConvertException(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("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(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("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> + o2u_attachCurrentThread(); + OSL_ASSERT(aArguments.getLength() == 3); + + m_spUnknown= *(IUnknown**) aArguments[0].getValue(); +#ifdef __MINGW32__ + m_spUnknown->QueryInterface(IID_IDispatch, reinterpret_cast<LPVOID*>( & m_spDispatch.p)); +#else + m_spUnknown.QueryInterface( & m_spDispatch.p); +#endif + + aArguments[1] >>= m_bOriginalDispatch; + aArguments[2] >>= m_seqTypes; + + ITypeInfo* pType = NULL; + try + { + // a COM object implementation that has no TypeInfo is still a legal COM object; + // such objects can at least be transported through UNO using the bridge + // so we should allow to create wrappers for them as well + pType = getTypeInfo(); + } + catch( BridgeRuntimeError& ) + {} + catch( Exception& ) + {} + + if ( pType ) + { + try + { + // Get Default member + CComBSTR defaultMemberName; + if ( SUCCEEDED( pType->GetDocumentation(0, &defaultMemberName, 0, 0, 0 ) ) ) + { + OUString usName(reinterpret_cast<const sal_Unicode*>(LPCOLESTR(defaultMemberName))); + FuncDesc aDescGet(pType); + FuncDesc aDescPut(pType); + VarDesc aVarDesc(pType); + // see if this is a property first ( more likely to be a property then a method ) + getPropDesc( usName, & aDescGet, & aDescPut, & aVarDesc); + + if ( !aDescGet && !aDescPut ) + { + getFuncDesc( usName, &aDescGet ); + if ( !aDescGet ) + throw BridgeRuntimeError( OUSTR("[automation bridge]IUnknownWrapper_Impl::initialize() Failed to get Function or Property desc. for " ) + usName ); + } + // now for some funny heuristics to make basic understand what to do + // a single aDescGet ( that doesn't take any params ) would be + // a read only ( defaultmember ) property e.g. this object + // should implement XDefaultProperty + // a single aDescGet ( that *does* ) take params is basically a + // default method e.g. implement XDefaultMethod + + // a DescPut ( I guess we only really support a default param with '1' param ) as a setValue ( but I guess we can leave it through, the object will fail if we don't get it right anyway ) + if ( aDescPut || ( aDescGet && aDescGet->cParams == 0 ) ) + m_bHasDfltProperty = true; + if ( aDescGet->cParams > 0 ) + m_bHasDfltMethod = true; + if ( m_bHasDfltProperty || m_bHasDfltMethod ) + m_sDefaultMember = usName; + } + } + catch ( BridgeRuntimeError & e ) + { + throw RuntimeException( e.message, Reference<XInterface>() ); + } + catch( Exception& e ) + { + throw RuntimeException( + OUSTR("[automation bridge] unexpected exception in IUnknownWrapper_Impl::initialiase() error message: \n") + e.Message, + Reference<XInterface>() ); + } + } +} + +// 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 == CComBSTR(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) +{ + // 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); + return invokeWithDispIdComTlb( aFuncDesc, sFuncName, Params, OutParamIndex, OutParam ); +} + +Any IUnknownWrapper_Impl::invokeWithDispIdComTlb(FuncDesc& aFuncDesc, + 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 = 0; + 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; + + + //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 (::sal::static_int_cast< sal_uInt32, int >( 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*>(reinterpret_cast<LPCOLESTR>(sFuncName.getStr())); + + int cNamedArg = 0; + for (size_t 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*>(reinterpret_cast<LPCOLESTR>(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 == E_NOTIMPL ) + hr = m_spDispatch->GetIDsOfNames(IID_NULL, arNames, nSizeAr, LOCALE_USER_DEFAULT, 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 = ::sal::static_int_cast< VARTYPE, int >( 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 = ::sal::static_int_cast< VARTYPE, int >( 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 = ::sal::static_int_cast< VARTYPE, int >( 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 = ::sal::static_int_cast< sal_Int16, sal_Int32 >( 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, + ::sal::static_int_cast< WORD, INVOKEKIND >( 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 = (sal_Int16)paramIndex; + throw; + } + catch (CannotConvertException & e) + { + e.ArgumentIndex = paramIndex; + throw; + } + OutParam[outParamIndex] = outAny; + OutParamIndex[outParamIndex] = ::sal::static_int_cast< sal_Int16, int >( 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(reinterpret_cast<const sal_Unicode*>(excepinfo.bstrDescription), + ::SysStringLen(excepinfo.bstrDescription)); + + // Add for VBA, to throw an exception with the correct error code and message. + sal_Int32 nErrorCode = excepinfo.wCode; + if ( nErrorCode == 0 ) + { + // The low 16-bit of scode describing the error or warning. + nErrorCode = ( excepinfo.scode & 0xFFFF ); + } + BasicErrorException aBasicErrExp(message, Reference<XInterface>(), nErrorCode, message); + throw InvocationTargetException(message, Reference<XInterface>(), makeAny(aBasicErrExp)); + // End add + + 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, ::sal::static_int_cast< sal_Int16, unsigned int >( uArgErr )); + break; + case DISP_E_OVERFLOW: + throw CannotConvertException(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("[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, ::sal::static_int_cast< sal_Int16, unsigned int >( 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> (reinterpret_cast<LPCOLESTR>(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 + OUString sRealName(reinterpret_cast<const sal_Unicode*>(LPCOLESTR(memberName))); + cit itOrg = m_mapComFunc.find(sRealName); + OSL_ASSERT(itOrg != m_mapComFunc.end()); + // maybe this is a property, if so we need + // to store either both id's ( put/get ) or + // just the get. Storing both is more consistent + pair<cit, cit> pItems = m_mapComFunc.equal_range( sRealName ); + for ( ;pItems.first != pItems.second; ++pItems.first ) + m_mapComFunc.insert( TLBFuncIndexMap::value_type ( make_pair(sFuncName, pItems.first->second ) )); + itIndex = + m_mapComFunc.find( sFuncName ); + } + } + } + +#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(reinterpret_cast<const sal_Unicode*>(LPCOLESTR(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::getUserDefinedElementType( ITypeInfo* pTypeInfo, const DWORD nHrefType ) +{ + VARTYPE _type( VT_NULL ); + if ( pTypeInfo ) + { + CComPtr<ITypeInfo> spRefInfo; + pTypeInfo->GetRefTypeInfo( nHrefType, &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 if ( attr->typekind == TKIND_ALIAS ) + { + // TKIND_ALIAS is a type that is an alias for another type. So get that alias type. + _type = getUserDefinedElementType( pTypeInfo, attr->tdescAlias.hreftype ); + } + else + { + throw BridgeRuntimeError( OUSTR("[automation bridge] Unhandled user defined type.") ); + } + } + } + return _type; +} + +VARTYPE IUnknownWrapper_Impl::getElementTypeDesc(const TYPEDESC *desc) +{ + VARTYPE _type( VT_NULL ); + + 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 + _type = getUserDefinedElementType( thisInfo, desc->hreftype ); + } + 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(reinterpret_cast<const sal_Unicode*>(LPCOLESTR(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(reinterpret_cast<const sal_Unicode*>(LPCOLESTR(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() +{ + 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(::sal::static_int_cast< UINT, int >( -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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/ole/oleobjw.hxx b/extensions/source/ole/oleobjw.hxx new file mode 100644 index 000000000000..0f926695eaab --- /dev/null +++ b/extensions/source/ole/oleobjw.hxx @@ -0,0 +1,284 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef __OLEOBJW_HXX +#define __OLEOBJW_HXX +#include "ole2uno.hxx" + +#ifdef _MSC_VER +#pragma warning (push,1) +#pragma warning (disable:4548) +#endif + +#include <tools/presys.h> +#define _WIN32_WINNT 0x0403 + +#if defined(_MSC_VER) && (_MSC_VER >= 1300) +#undef _DEBUG +#endif +#include <atlbase.h> +#include <vector> +#include <hash_map> +#include <tools/postsys.h> + +#ifdef _MSC_VER +#pragma warning (pop) +#endif +#include <cppuhelper/implbase3.hxx> +#include <cppuhelper/implbase4.hxx> +#include <cppuhelper/implbase6.hxx> + +#include <com/sun/star/lang/XInitialization.hpp> +#include <com/sun/star/bridge/oleautomation/XAutomationObject.hpp> +#include <com/sun/star/script//XAutomationInvocation.hpp> +#include <rtl/ustring.hxx> + +#include <com/sun/star/script/XDefaultProperty.hpp> +#include <com/sun/star/script/XDefaultMethod.hpp> + +#include <typelib/typedescription.hxx> +#include "unoconversionutilities.hxx" +#include "windata.hxx" +using namespace cppu; +using namespace rtl; +using namespace std; +using namespace com::sun::star::lang; +using namespace com::sun::star::bridge; +using namespace com::sun::star::bridge::oleautomation; + +namespace ole_adapter +{ + + + +typedef hash_map<OUString, pair<DISPID, unsigned short>, hashOUString_Impl, equalOUString_Impl> DispIdMap; + +typedef hash_multimap<OUString, unsigned int, hashOUString_Impl, equalOUString_Impl> TLBFuncIndexMap; + +// This class wraps an IDispatch and maps XInvocation calls to IDispatch calls on the wrapped object. +// If m_TypeDescription is set then this class represents an UNO interface implemented in a COM component. +// The interface is not a real interface in terms of an abstract class but is realized through IDispatch. +class IUnknownWrapper_Impl : public WeakImplHelper6<XAutomationInvocation, XBridgeSupplier2, XInitialization, XAutomationObject, XDefaultProperty, XDefaultMethod>, + + public UnoConversionUtilities<IUnknownWrapper_Impl> + +{ +public: + IUnknownWrapper_Impl(Reference<XMultiServiceFactory> &xFactory, + sal_uInt8 unoWrapperClass, sal_uInt8 comWrapperClass); + + ~IUnknownWrapper_Impl(); + + //XInterface + Any SAL_CALL queryInterface(const Type& t) + throw (RuntimeException); + + // XInvokation + virtual Reference< XIntrospectionAccess > SAL_CALL getIntrospection( ) + throw(RuntimeException); + virtual Any SAL_CALL invoke( const OUString& aFunctionName, + const Sequence< Any >& aParams, + Sequence< sal_Int16 >& aOutParamIndex, + Sequence< Any >& aOutParam ) + throw(IllegalArgumentException, CannotConvertException, + InvocationTargetException, RuntimeException); + virtual void SAL_CALL setValue( const OUString& aPropertyName, + const Any& aValue ) + throw(UnknownPropertyException, CannotConvertException, + InvocationTargetException, RuntimeException); + virtual Any SAL_CALL getValue( const OUString& aPropertyName ) + throw(UnknownPropertyException, RuntimeException); + virtual sal_Bool SAL_CALL hasMethod( const OUString& aName ) + throw(RuntimeException); + virtual sal_Bool SAL_CALL hasProperty( const OUString& aName ) + throw(RuntimeException); + + // XBridgeSupplier2 + // This interface is implemented to provide a safe way to obtain the original + // IUnknown or IDispatch within the function anyToVariant. The function asks + // every UNO object for its XBridgeSupplier2 and if it is available uses it to convert + // the object with its own supplier. + virtual Any SAL_CALL createBridge( const Any& modelDepObject, + const Sequence< sal_Int8 >& aProcessId, + sal_Int16 sourceModelType, + sal_Int16 destModelType ) + throw(IllegalArgumentException, RuntimeException); + + // XInitialization + virtual void SAL_CALL initialize( const Sequence< Any >& aArguments ) + throw(Exception, RuntimeException); + virtual ::rtl::OUString SAL_CALL getDefaultPropertyName( ) throw (::com::sun::star::uno::RuntimeException) { return m_sDefaultMember; } +protected: + virtual ::rtl::OUString SAL_CALL getDefaultMethodName( ) throw (::com::sun::star::uno::RuntimeException) { return m_sDefaultMember; } + + virtual ::com::sun::star::uno::Any SAL_CALL invokeGetProperty( const ::rtl::OUString& aFunctionName, const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any >& aParams, ::com::sun::star::uno::Sequence< ::sal_Int16 >& aOutParamIndex, ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any >& aOutParam ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::script::CannotConvertException, ::com::sun::star::reflection::InvocationTargetException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Any SAL_CALL invokePutProperty( const ::rtl::OUString& aFunctionName, const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any >& aParams, ::com::sun::star::uno::Sequence< ::sal_Int16 >& aOutParamIndex, ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any >& aOutParam ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::script::CannotConvertException, ::com::sun::star::reflection::InvocationTargetException, ::com::sun::star::uno::RuntimeException); + + // ---------------------------------------------------------------------------- + virtual Any invokeWithDispIdUnoTlb(const OUString& sFunctionName, + const Sequence< Any >& Params, + Sequence<sal_Int16 >& OutParamIndex, + Sequence< Any >& OutParam); + // Is used for OleObjectFactory service + virtual Any invokeWithDispIdComTlb(const OUString& sFuncName, + const Sequence< Any >& Params, + Sequence< sal_Int16 >& OutParamIndex, + Sequence< Any >& OutParam); + + Any IUnknownWrapper_Impl::invokeWithDispIdComTlb(FuncDesc& aFuncDesc, + const OUString& sFuncName, + const Sequence< Any >& Params, + Sequence< sal_Int16 >& OutParamIndex, + Sequence< Any >& OutParam); + +// virtual void setValueWithDispId(DISPID dispID, const Any& Value); + +// virtual Any getValueWithDispId(const OUString& sName, DISPID dispID); + + + // UnoConversionUtilities ------------------------------------------------------------------------------- + virtual Reference<XInterface> createUnoWrapperInstance(); + virtual Reference<XInterface> createComWrapperInstance(); + + /**Obtains a FUNCDESC structure for a function. + Fills the FUNCDESC structure if ITypeInfo provides information for + the function of name sFuncName or pFuncDesc will not be filled in. + May throw a BridgeRuntimeError. + */ + void getFuncDesc(const OUString & sFuncName, FUNCDESC ** pFuncDesc); + /**Obtains a FUNCDESC structures or a VARDESC structure + for a property. pFuncDescPut may also contain + a structure for a "propertyputref" operation. If pFuncDesc contains a + "put ref" or "put" FUNCDESC depends on what was found first in the type + description. + Fills the FUNCDESC structure if ITypeInfo provides information for + the respective property functions or the structures will not be filled in. + May throw a BridgeRuntimeError. + */ + void getPropDesc(const OUString & sFuncName, FUNCDESC ** pFuncDescGet, + FUNCDESC** pFuncDescPut, VARDESC ** pVarDesc); + // These functions are for the case if an object of this class wraps an IDispatch + // object that implements UNO interfaces. In that case the member m_seqTypes + // is set through XInitialization::initialize. + void getMethodInfo(const OUString& sName, TypeDescription& methodDescription); + // After return attributInfo contains typelib_InterfaceAttributeTypeDescription::pAttributeTypeRef + void getAttributeInfo(const OUString& sName, TypeDescription& attributeInfo); + // used by get MethodInfo + TypeDescription getInterfaceMemberDescOfCurrentCall(const OUString& sName); + /** Returns alway a valid ITypeInfo interface or throws a BridgeRuntimeError. + The returned interface does not need to be AddRef'ed as long as it is locally + used. The interface is kept in the instance of this class. + */ + ITypeInfo* getTypeInfo(); + + /** Returns the DISPID for a function or property name. If true is returned then + id contains a valid DISPID. + */ + + bool getDispid(const OUString& sFuncName, DISPID * id); + + VARTYPE getUserDefinedElementType( ITypeInfo* pTypeInfo, const DWORD nHrefType ); + + /** Gets the element type in a VARIANT like style. E.g. if desc->lptdesc contains + a VT_PTR than it is replaced by VT_BYREF and VT_SAFEARRAY is replaced by VT_ARRAY + If the TYPEDESC describes an SAFEARRAY then varType is a combination of VT_ARRAY + and the element type. + The argument desc must be obtained from FUNCDESC::lprgelemdescParam[i].tdesc where + FUNCDESC was obtained from the ITypeInfo belonging to wrapped IDispatch. + */ + VARTYPE getElementTypeDesc( const TYPEDESC *desc); + /** Iterates over all functions and put the names and indices into the map + m_mapComFunc of type TLBFuncIndexMap. + Call the function every time before accessing the map. + Throws a BridgeRuntimeError on failure. + */ + void buildComTlbIndex(); + + /** Returns a FUNCDESC structure which contains type information about the + current XInvocation::invoke call. The FUNCDESC either describes a method, + a property put or a property get operation. + It uses the types com.sun.star.bridge.oleautomation.PropertyPutArgument + which can be + contained in the sequence of in-arguments of invoke to determine if the call is + a property put or property get operation. + If no adequate FUNCDESC was found, an IllegalArgumentException is thrown. + Therefore it is safe to assume that the returned FUNCDESC* is not NULL. + + @exception IllegalArgumentException + Thrown if no adequate FUNCDESC could be found. + */ + void getFuncDescForInvoke(const OUString & sFuncName, + const Sequence<Any> & seqArgs, FUNCDESC** pFuncDesc); + + // Finds out wheter the wrapped IDispatch is an JScript Object. This is is + // done by + // asking for the property "_environment". If it has the value "JScript" + // (case insensitive) then the IDispatch is considered a JScript object. + sal_Bool isJScriptObject(); + // ------------------------------------------------------------------------------- + + // If UNO interfaces are implemented in JScript objects, VB or C++ COM objects + // and those are passed as parameter to a UNO interface function, then + // the IDispatch* are wrapped by objects of this class. Assuming that the functions + // implemented by the IDispatch object returns another UNO interface then + // it has to be wrapped to this type. But this is only possible if an object of this + // wrapper class knows what type it is represting. The member m_TypeDescription holds this + // information. + // m_TypeDescription is only useful when an object wraps an IDispatch object that implements + // an UNO interface. The value is set during a call to XInitialization::initialize. + Sequence<Type> m_seqTypes; + CComPtr<IUnknown> m_spUnknown; + CComPtr<IDispatch> m_spDispatch; + rtl::OUString m_sTypeName; // is "" ( not initialised ), "IDispatch" ( we have no idea ) or "SomeLibrary.SomeTypeName" if we managed to get a type + /** This value is set dureing XInitialization::initialize. It indicates that the COM interface + was transported as VT_DISPATCH in a VARIANT rather then a VT_UNKNOWN + */ + sal_Bool m_bOriginalDispatch; + DispIdMap m_dispIdMap; + Reference<XIdlClass>* m_pxIdlClass; + + + // used by isJScriptObject + enum JScriptDetermination{ JScriptUndefined=0, NoJScript, IsJScript}; + JScriptDetermination m_eJScript; + // The map is filled by buildComTlbIndex + // It maps Uno Function names to an index which is used in ITypeInfo::GetFuncDesc + TLBFuncIndexMap m_mapComFunc; + // used for synchroizing the computation of the content for m_mapComFunc + bool m_bComTlbIndexInit; + // Keeps the ITypeInfo obtained from IDispatch::GetTypeInfo + CComPtr< ITypeInfo > m_spTypeInfo; + rtl::OUString m_sDefaultMember; + bool m_bHasDfltMethod; + bool m_bHasDfltProperty; +}; + +} // end namespace +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/ole/olethread.cxx b/extensions/source/ole/olethread.cxx new file mode 100644 index 000000000000..bd6f5fbceeec --- /dev/null +++ b/extensions/source/ole/olethread.cxx @@ -0,0 +1,79 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_extensions.hxx" +#if defined _MSC_VER && ( _MSC_VER >= 1200 ) +#define _WIN32_WINNT 0x0400 +#endif + +#include "ole2uno.hxx" + +#include <tools/presys.h> +#include <tools/postsys.h> + +#include <osl/thread.hxx> + +using namespace std; + +namespace ole_adapter +{ +// CoInitializeEx * +typedef DECLSPEC_IMPORT HRESULT (STDAPICALLTYPE *ptrCoInitEx)( LPVOID, DWORD); +// CoInitialize * +typedef DECLSPEC_IMPORT HRESULT (STDAPICALLTYPE *ptrCoInit)( LPVOID); + +void o2u_attachCurrentThread() +{ + static osl::ThreadData oleThreadData; + + if ((sal_Bool)(sal_IntPtr)oleThreadData.getData() != sal_True) + { + HINSTANCE inst= LoadLibrary( _T("ole32.dll")); + if( inst ) + { + HRESULT hr; + // Try DCOM + ptrCoInitEx initFuncEx= (ptrCoInitEx)GetProcAddress( inst, _T("CoInitializeEx")); + if( initFuncEx) + hr= initFuncEx( NULL, COINIT_MULTITHREADED); + // No DCOM, try COM + else + { + ptrCoInit initFunc= (ptrCoInit)GetProcAddress( inst,_T("CoInitialize")); + if( initFunc) + hr= initFunc( NULL); + } + } + oleThreadData.setData((void*)sal_True); + } +} + +} // end namespace + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/ole/servprov.cxx b/extensions/source/ole/servprov.cxx new file mode 100644 index 000000000000..ecf45a4ce074 --- /dev/null +++ b/extensions/source/ole/servprov.cxx @@ -0,0 +1,757 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_extensions.hxx" + +#ifdef __MINGW32__ +#define INITGUID +#include <initguid.h> +#else +#include "ole2uno.hxx" +#include "unoconversionutilities.hxx" +#endif +#include "servprov.hxx" +#include "unoobjw.hxx" +#include "oleobjw.hxx" +#include <rtl/unload.h> + +#include <tools/presys.h> +#define _WIN32_WINNT 0x0403 + +#if defined(_MSC_VER) && (_MSC_VER >= 1300) +#undef _DEBUG +#endif +#include <atlbase.h> +extern CComModule _Module; +#include <atlcom.h> +#include <tools/postsys.h> + + +using namespace std; +using namespace cppu; +using namespace rtl; +using namespace osl; +using namespace com::sun::star::lang; +using namespace com::sun::star::uno; +using namespace com::sun::star::bridge; +using namespace com::sun::star::bridge::ModelDependent; + + + +namespace ole_adapter +{ + +#include <initguid.h> +// prior 5.2 ( src569 ver m) +// {3ECF78F0-B149-11D2-8EBE-00105AD848AF} +//DEFINE_GUID(OID_ServiceManager, 0x3ECF78F0, 0xB149, 0x11d2, 0x8E, 0xBE, 0x00, 0x10, 0x5A, 0xD8, 0x48, 0xAF); + +#ifndef OWNGUID +// GUID used since 5.2 ( src569 m) +// {82154420-0FBF-11d4-8313-005004526AB4} +DEFINE_GUID(OID_ServiceManager, 0x82154420, 0xfbf, 0x11d4, 0x83, 0x13, 0x0, 0x50, 0x4, 0x52, 0x6a, 0xb4); +#else +// Alternative GUID +// {D9BB9D1D-BFA9-4357-9F11-9A2E9061F06E} +DEFINE_GUID(OID_ServiceManager, 0xd9bb9d1d, 0xbfa9, 0x4357, 0x9f, 0x11, 0x9a, 0x2e, 0x90, 0x61, 0xf0, 0x6e); +#endif + +extern rtl_StandardModuleCount globalModuleCount; + +/***************************************************************************** + + class implementation ProviderOleWrapper_Impl + +*****************************************************************************/ + +ProviderOleWrapper_Impl::ProviderOleWrapper_Impl(const Reference<XMultiServiceFactory>& smgr, + const Reference<XSingleServiceFactory>& xSFact, GUID* pGuid) + : m_xSingleServiceFactory(xSFact), + m_smgr( smgr) +{ + m_guid = *pGuid; + + Reference<XInterface> xInt = smgr->createInstance(reinterpret_cast<const sal_Unicode*>(L"com.sun.star.bridge.oleautomation.BridgeSupplier")); + + if (xInt.is()) + { + Any a= xInt->queryInterface( ::getCppuType( reinterpret_cast< + Reference< XBridgeSupplier2>* >(0))); + a >>= m_bridgeSupplier; + + } +} + +ProviderOleWrapper_Impl::~ProviderOleWrapper_Impl() +{ +} + +sal_Bool ProviderOleWrapper_Impl::registerClass() +{ + HRESULT hresult; + + o2u_attachCurrentThread(); + + hresult = CoRegisterClassObject( + m_guid, + this, + CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER, + REGCLS_MULTIPLEUSE, + &m_factoryHandle); + + return (hresult == NOERROR); +} + +sal_Bool ProviderOleWrapper_Impl::deregisterClass() +{ + HRESULT hresult = CoRevokeClassObject(m_factoryHandle); + + return (hresult == NOERROR); +} + +STDMETHODIMP ProviderOleWrapper_Impl::QueryInterface(REFIID riid, void FAR* FAR* ppv) +{ + if(IsEqualIID(riid, IID_IUnknown)) + { + AddRef(); + *ppv = (IUnknown*) (IClassFactory*) this; + return NOERROR; + } + else if (IsEqualIID(riid, IID_IClassFactory)) + { + AddRef(); + *ppv = (IClassFactory*) this; + return NOERROR; + } + + *ppv = NULL; + return ResultFromScode(E_NOINTERFACE); +} + +STDMETHODIMP_(ULONG) ProviderOleWrapper_Impl::AddRef() +{ + return osl_incrementInterlockedCount( &m_refCount); +} + +STDMETHODIMP_(ULONG) ProviderOleWrapper_Impl::Release() +{ + MutexGuard aGuard( Mutex::getGlobalMutex()); + ULONG refCount = --m_refCount; + if (m_refCount == 0) + { + delete this; + } + + return refCount; +} + +STDMETHODIMP ProviderOleWrapper_Impl::CreateInstance(IUnknown FAR* punkOuter, + REFIID riid, + void FAR* FAR* ppv) +{ + HRESULT ret = ResultFromScode(E_UNEXPECTED); + punkOuter = NULL; + + Reference<XInterface> xInstance; + + if (m_xSingleServiceFactory.is()) + { + xInstance = m_xSingleServiceFactory->createInstance(); + + if (xInstance.is()) + { + Any usrAny(&xInstance, getCppuType( & xInstance)); + + sal_uInt8 arId[16]; + rtl_getGlobalProcessId( arId ); + Any oleAny = m_bridgeSupplier->createBridge(usrAny, + Sequence<sal_Int8>((sal_Int8*)arId, 16), + UNO, + OLE); + + + if (oleAny.getValueTypeClass() == getCppuType( (sal_uInt32 *)0).getTypeClass()) + { + VARIANT* pVariant = *(VARIANT**)oleAny.getValue(); + + if (pVariant->vt == VT_DISPATCH) + { + ret = pVariant->pdispVal->QueryInterface(riid, ppv); + } + + VariantClear(pVariant); + CoTaskMemFree(pVariant); + } + } + } + + return ret; +} + +STDMETHODIMP ProviderOleWrapper_Impl::LockServer(int /*fLock*/) +{ + return NOERROR; +} + +/***************************************************************************** + + class implementation OneInstanceOleWrapper_Impl + +*****************************************************************************/ + +OneInstanceOleWrapper_Impl::OneInstanceOleWrapper_Impl( const Reference<XMultiServiceFactory>& smgr, + const Reference<XInterface>& xInst, + GUID* pGuid, + sal_Bool bAsApplication ) + : m_xInst(xInst), m_refCount(0), + m_smgr( smgr), + m_factoryHandle( 0 ), + m_bAsApplication( bAsApplication ), + m_nApplRegHandle( 0 ) +{ + m_guid = *pGuid; + + Reference<XInterface> xInt = m_smgr->createInstance(reinterpret_cast<const sal_Unicode*>(L"com.sun.star.bridge.oleautomation.BridgeSupplier")); + + if (xInt.is()) + { + Any a= xInt->queryInterface( getCppuType( + reinterpret_cast< Reference<XBridgeSupplier2>*>(0))); + a >>= m_bridgeSupplier; + } +} + +OneInstanceOleWrapper_Impl::~OneInstanceOleWrapper_Impl() +{ +} + +sal_Bool OneInstanceOleWrapper_Impl::registerClass() +{ + HRESULT hresult; + + o2u_attachCurrentThread(); + + hresult = CoRegisterClassObject( + m_guid, + this, + CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER, + REGCLS_MULTIPLEUSE, + &m_factoryHandle); + + if ( hresult == NOERROR && m_bAsApplication ) + hresult = RegisterActiveObject( this, m_guid, ACTIVEOBJECT_WEAK, &m_nApplRegHandle ); + + return (hresult == NOERROR); +} + +sal_Bool OneInstanceOleWrapper_Impl::deregisterClass() +{ + HRESULT hresult1 = NOERROR; + if ( m_bAsApplication ) + hresult1 = RevokeActiveObject( m_nApplRegHandle, NULL ); + + HRESULT hresult2 = CoRevokeClassObject(m_factoryHandle); + + return (hresult1 == NOERROR && hresult2 == NOERROR); +} + +STDMETHODIMP OneInstanceOleWrapper_Impl::QueryInterface(REFIID riid, void FAR* FAR* ppv) +{ + if(IsEqualIID(riid, IID_IUnknown)) + { + AddRef(); + *ppv = (IUnknown*) (IClassFactory*) this; + return NOERROR; + } + else if (IsEqualIID(riid, IID_IClassFactory)) + { + AddRef(); + *ppv = (IClassFactory*) this; + return NOERROR; + } + + *ppv = NULL; + return ResultFromScode(E_NOINTERFACE); +} + +STDMETHODIMP_(ULONG) OneInstanceOleWrapper_Impl::AddRef() +{ + return osl_incrementInterlockedCount( &m_refCount); +} + +STDMETHODIMP_(ULONG) OneInstanceOleWrapper_Impl::Release() +{ + MutexGuard oGuard( Mutex::getGlobalMutex()); + ULONG refCount = --m_refCount; + if ( m_refCount == 0) + { + delete this; + } + + return refCount; +} + +STDMETHODIMP OneInstanceOleWrapper_Impl::CreateInstance(IUnknown FAR* punkOuter, + REFIID riid, + void FAR* FAR* ppv) +{ + HRESULT ret = ResultFromScode(E_UNEXPECTED); + punkOuter = NULL; + + if (m_xInst.is()) + { + Any usrAny(&m_xInst, getCppuType( &m_xInst)); + sal_uInt8 arId[16]; + rtl_getGlobalProcessId( arId); + Any oleAny = m_bridgeSupplier->createBridge(usrAny, + Sequence<sal_Int8>( (sal_Int8*)arId, 16), + UNO, + OLE); + + + if (oleAny.getValueTypeClass() == TypeClass_UNSIGNED_LONG) + { + VARIANT* pVariant = *(VARIANT**)oleAny.getValue(); + + if ((pVariant->vt == VT_UNKNOWN) || (pVariant->vt == VT_DISPATCH)) + { + ret = pVariant->punkVal->QueryInterface(riid, ppv); + } + + VariantClear(pVariant); + CoTaskMemFree(pVariant); + } + } + + return ret; +} + +STDMETHODIMP OneInstanceOleWrapper_Impl::LockServer(int /*fLock*/) +{ + return NOERROR; +} + + +/***************************************************************************** + + class implementation OleConverter_Impl2 + +*****************************************************************************/ + +OleConverter_Impl2::OleConverter_Impl2( const Reference<XMultiServiceFactory> &smgr): + UnoConversionUtilities<OleConverter_Impl2>( smgr) + +{ + // library unloading support + globalModuleCount.modCnt.acquire( &globalModuleCount.modCnt); +} + +// The XMultiServiceFactory is later set by XInitialization +OleConverter_Impl2::OleConverter_Impl2( const Reference<XMultiServiceFactory>& smgr, sal_uInt8 unoWrapperClass, sal_uInt8 comWrapperClass ): + UnoConversionUtilities<OleConverter_Impl2>( smgr, unoWrapperClass, comWrapperClass ) + +{ + //library unloading support + globalModuleCount.modCnt.acquire( &globalModuleCount.modCnt); +} + +OleConverter_Impl2::~OleConverter_Impl2() +{ + globalModuleCount.modCnt.release( &globalModuleCount.modCnt); +} + +// XBridgeSupplier -------------------------------------------------------------- +Any SAL_CALL OleConverter_Impl2::createBridge(const Any& modelDepObject, + const Sequence< sal_Int8 >& ProcessId, + sal_Int16 sourceModelType, + sal_Int16 destModelType) + throw (IllegalArgumentException, + RuntimeException ) +{ + Any ret; + sal_uInt8 arId[16]; + rtl_getGlobalProcessId( arId ); + + Sequence< sal_Int8 > seqProcessId( (sal_Int8*)arId, 16); + + if ( seqProcessId == ProcessId) + { + if (sourceModelType == UNO) + { + if (destModelType == UNO) + { + // same model -> copy value only + ret = modelDepObject; + } + else if (destModelType == OLE) + { + // convert UNO any into variant + VARIANT* pVariant = (VARIANT*) CoTaskMemAlloc(sizeof(VARIANT)); + VariantInit( pVariant); + try + { + anyToVariant( pVariant, modelDepObject); + } + catch(...) + { + CoTaskMemFree(pVariant); + throw IllegalArgumentException(); + } + ret.setValue((void*) &pVariant, getCppuType((sal_uInt32*)0)); + } + else + throw IllegalArgumentException(); + } + else if (sourceModelType == OLE) + { + if (modelDepObject.getValueType() != getCppuType((sal_uInt32*)0)) + { + throw IllegalArgumentException(); + } + else if (destModelType == OLE) + { + // same model -> copy value only + VARIANT* pVariant = (VARIANT*) CoTaskMemAlloc(sizeof(VARIANT)); + + if (NOERROR != VariantCopy(pVariant, *(VARIANT**)modelDepObject.getValue())) + { + CoTaskMemFree(pVariant); + throw(IllegalArgumentException()); + } + else + { + ret.setValue((void*) &pVariant, getCppuType((sal_uInt32*)0)); + } + } + else if (destModelType == UNO) + { + // convert variant into UNO any + VARIANT* pVariant = *(VARIANT**)modelDepObject.getValue(); + try + { + variantToAny(pVariant, ret); + } + catch (CannotConvertException & e) + { + throw IllegalArgumentException( + e.Message, 0, -1); + } + } + else + throw IllegalArgumentException(); + + } + else + throw IllegalArgumentException(); + } + + return ret; +} + + +// XInitialize ------------------------------------------------------------------------------ +// the first argument is an XMultiServiceFactory if at all +void SAL_CALL OleConverter_Impl2::initialize( const Sequence< Any >& aArguments ) + throw(Exception, RuntimeException) +{ + if( aArguments.getLength() == 1 && aArguments[0].getValueTypeClass() == TypeClass_INTERFACE) + { + Reference < XInterface > xInt; + aArguments[0] >>= xInt; + Reference <XMultiServiceFactory> xMulti( xInt, UNO_QUERY); + m_smgrRemote= xMulti; + } +} + +// UnoConversionUtilities ------------------------------------------------------------------- +Reference< XInterface > OleConverter_Impl2::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 > OleConverter_Impl2::createComWrapperInstance() +{ + Reference<XWeak> xWeak= static_cast<XWeak*>( new IUnknownWrapper_Impl( + m_smgr, m_nUnoWrapperClass, m_nComWrapperClass)); + return Reference<XInterface>( xWeak, UNO_QUERY); +} + + + +/***************************************************************************** + + class implementation OleClient_Impl + +*****************************************************************************/ + +OleClient_Impl::OleClient_Impl( const Reference<XMultiServiceFactory>& smgr): + UnoConversionUtilities<OleClient_Impl>( smgr) +{ + // library unloading support + globalModuleCount.modCnt.acquire( &globalModuleCount.modCnt); + Reference<XInterface> xInt;// = m_smgr->createInstance(L"com.sun.star.bridge.OleBridgeSupplier2"); + + if (xInt.is()) + { + Any a= xInt->queryInterface(getCppuType( + reinterpret_cast<Reference<XBridgeSupplier2>*>(0))); + a >>= m_bridgeSupplier; + } +} + +OleClient_Impl::~OleClient_Impl() +{ + // library unloading support + globalModuleCount.modCnt.release( &globalModuleCount.modCnt); +} + +Sequence< OUString > SAL_CALL OleClient_Impl::getAvailableServiceNames() throw( RuntimeException ) +{ + Sequence< OUString > ret; + + return ret; +} + + +OUString OleClient_Impl::getImplementationName() +{ + return OUString(reinterpret_cast<const sal_Unicode*>(L"com.sun.star.comp.ole.OleClient")); +} + +Reference<XInterface> SAL_CALL OleClient_Impl::createInstance(const OUString& ServiceSpecifier) throw (Exception, RuntimeException ) +{ + Reference<XInterface> ret; + HRESULT result; + IUnknown* pUnknown = NULL; + CLSID classId; + + o2u_attachCurrentThread(); + + result = CLSIDFromProgID( + reinterpret_cast<LPCWSTR>(ServiceSpecifier.getStr()), //Pointer to the ProgID + &classId); //Pointer to the CLSID + + + if (result == NOERROR) + { + result = CoCreateInstance( + classId, //Class identifier (CLSID) of the object + NULL, //Pointer to whether object is or isn't part of an aggregate + CLSCTX_SERVER, //Context for running executable code + IID_IUnknown, //Reference to the identifier of the interface + (void**)&pUnknown); //Address of output variable that receives + // the interface pointer requested in riid + } + + if (pUnknown != NULL) + { + Any any; + CComVariant variant; + + V_VT(&variant) = VT_UNKNOWN; + V_UNKNOWN(&variant) = pUnknown; + // AddRef for Variant + pUnknown->AddRef(); + + // When the object is wrapped, then its refcount is increased + variantToAny(&variant, any); + if (any.getValueTypeClass() == TypeClass_INTERFACE) + { + any >>= ret; + } + pUnknown->Release(); // CoCreateInstance + } + + return ret; +} + +Reference<XInterface> SAL_CALL OleClient_Impl::createInstanceWithArguments(const OUString& ServiceSpecifier, const Sequence< Any >& /*Arguments*/) throw (Exception, RuntimeException) +{ + return createInstance( ServiceSpecifier); +} + +// UnoConversionUtilities ----------------------------------------------------------------------------- +Reference< XInterface > OleClient_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>(); +} +// UnoConversionUtilities ----------------------------------------------------------------------------- +Reference< XInterface > OleClient_Impl::createComWrapperInstance( ) +{ + Reference<XWeak> xWeak= static_cast<XWeak*>( new IUnknownWrapper_Impl( + m_smgr, m_nUnoWrapperClass, m_nComWrapperClass)); + return Reference<XInterface>( xWeak, UNO_QUERY); +} + + + +/***************************************************************************** + + class implementation OleServer_Impl + +*****************************************************************************/ + +OleServer_Impl::OleServer_Impl( const Reference<XMultiServiceFactory>& smgr): + m_smgr( smgr) +{ + //library unloading support + globalModuleCount.modCnt.acquire( &globalModuleCount.modCnt); + Reference<XInterface> xInt = m_smgr->createInstance(reinterpret_cast<const sal_Unicode*>(L"com.sun.star.bridge.oleautomation.BridgeSupplier")); + + if (xInt.is()) + { + Any a= xInt->queryInterface( getCppuType( + reinterpret_cast< Reference<XBridgeSupplier2>*>(0))); + a >>= m_bridgeSupplier; + } + +#ifndef OWNGUID + sal_Bool bOLERegister = sal_False; +#else + sal_Bool bOLERegister = sal_True; +#endif + sal_Bool ret = provideInstance( m_smgr, (GUID*)&OID_ServiceManager, bOLERegister ); + (void)ret; +} + +OleServer_Impl::~OleServer_Impl() +{ + while (!m_wrapperList.empty()) + { + (*m_wrapperList.begin())->deregisterClass(); + (*m_wrapperList.begin())->Release(); + m_wrapperList.pop_front(); + } + //library unloading support + globalModuleCount.modCnt.release( &globalModuleCount.modCnt); +} +// XInterface -------------------------------------------------- +Any SAL_CALL OleServer_Impl::queryInterface( const Type& aType ) throw(RuntimeException) +{ + Any a= ::cppu::queryInterface( aType, static_cast<XTypeProvider*>(this)); + if( a == Any()) + return OWeakObject::queryInterface( aType); + else + return a; +} +void SAL_CALL OleServer_Impl::acquire( ) throw() +{ + OWeakObject::acquire(); +} +void SAL_CALL OleServer_Impl::release( ) throw () +{ + OWeakObject::release(); +} + + +// XTypeProvider -------------------------------------------------- +Sequence< Type > SAL_CALL OleServer_Impl::getTypes( ) throw(RuntimeException) +{ + static OTypeCollection *pCollection = 0; + if( ! pCollection ) + { + MutexGuard guard( Mutex::getGlobalMutex() ); + if( ! pCollection ) + { + static OTypeCollection collection( + getCppuType(reinterpret_cast< Reference< XWeak>*>(0)), + getCppuType(reinterpret_cast< Reference< XTypeProvider>*>(0)) ); + pCollection = &collection; + } + } + return (*pCollection).getTypes(); +} +Sequence< sal_Int8 > SAL_CALL OleServer_Impl::getImplementationId() throw(RuntimeException) +{ + static OImplementationId *pId = 0; + if( ! pId ) + { + MutexGuard guard( Mutex::getGlobalMutex() ); + if( ! pId ) + { + static OImplementationId id( sal_False ); + pId = &id; + } + } + return (*pId).getImplementationId(); +} + + +sal_Bool OleServer_Impl::provideService(const Reference<XSingleServiceFactory>& xSFact, GUID* guid) +{ + IClassFactoryWrapper* pFac = new ProviderOleWrapper_Impl( m_smgr, xSFact, guid); + + pFac->AddRef(); + + m_wrapperList.push_back(pFac); + + return pFac->registerClass(); +} + +sal_Bool OleServer_Impl::provideInstance(const Reference<XInterface>& xInst, GUID* guid, sal_Bool bAsApplication ) +{ + IClassFactoryWrapper* pFac = new OneInstanceOleWrapper_Impl( m_smgr, xInst, guid, bAsApplication ); + + pFac->AddRef(); + m_wrapperList.push_back(pFac); + + return pFac->registerClass(); +} + + + +} // end namespace + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/ole/servprov.hxx b/extensions/source/ole/servprov.hxx new file mode 100644 index 000000000000..49091b1fcd38 --- /dev/null +++ b/extensions/source/ole/servprov.hxx @@ -0,0 +1,279 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _SERVPROV_HXX +#define _SERVPROV_HXX + +#include <com/sun/star/lang/XInitialization.hpp> +#include <cppuhelper/implbase2.hxx> + +#include "ole2uno.hxx" +#include "unoconversionutilities.hxx" + + +using namespace com::sun::star::bridge; +using namespace cppu; +using namespace std; + +namespace ole_adapter +{ +Reference< XInterface> SAL_CALL ConverterProvider_CreateInstance( const Reference<XMultiServiceFactory> & xSMgr) + throw( Exception); +Reference< XInterface> SAL_CALL ConverterProvider_CreateInstance2( const Reference<XMultiServiceFactory> & xSMgr) + throw( Exception); +Reference< XInterface> SAL_CALL ConverterProvider_CreateInstanceVar1( const Reference<XMultiServiceFactory> & xSMgr) + throw( Exception); +Reference<XInterface> SAL_CALL OleClient_CreateInstance( const Reference<XMultiServiceFactory> & xSMgr) + throw( Exception); +Reference<XInterface> SAL_CALL OleServer_CreateInstance( const Reference<XMultiServiceFactory> & xSMgr) + throw( Exception); +/***************************************************************************** + + class declaration IClassFactoryWrapper + + Specify abstract helper methods on class factories, which provide + UNO objects. These methods are used by objects of class OleServer_Impl, + to handle the OLE registration of different class factories. + +*****************************************************************************/ + +class IClassFactoryWrapper : public IClassFactory +{ +public: + + virtual sal_Bool registerClass() = 0; + virtual sal_Bool deregisterClass() = 0; +}; + +/***************************************************************************** + + class declaration ProviderOleWrapper_Impl + + Provides an UNO service provider as OLE class factory. Handle the + OLE registration by overloading the abstract methods from + IClassFactoryWrapper. + + Acts as a COM class factory. When IClassFactory::CreateInstance is being called + then it creates an service by help of the XSingleServiceFactory member and maps + maps it to a COM object. + +*****************************************************************************/ + +class ProviderOleWrapper_Impl : public IClassFactoryWrapper +{ +public: + + ProviderOleWrapper_Impl( const Reference<XMultiServiceFactory>& smgr, + const Reference<XSingleServiceFactory>& xSFactory, GUID* pGuid); + virtual ~ProviderOleWrapper_Impl(); + + sal_Bool registerClass(); + sal_Bool deregisterClass(); + + /* IUnknown methods */ + STDMETHOD(QueryInterface)(REFIID riid, LPVOID FAR * ppvObj); + STDMETHOD_(ULONG, AddRef)(); + STDMETHOD_(ULONG, Release)(); + + /* IClassFactory methods */ + STDMETHOD(CreateInstance)(IUnknown FAR* punkOuter, REFIID riid, void FAR* FAR* ppv); + STDMETHOD(LockServer)(int fLock); + +protected: + + oslInterlockedCount m_refCount; + Reference<XSingleServiceFactory> m_xSingleServiceFactory; + GUID m_guid; + DWORD m_factoryHandle; + Reference<XBridgeSupplier2> m_bridgeSupplier; + Reference<XMultiServiceFactory> m_smgr; +}; + +/***************************************************************************** + + class declaration OneInstanceOleWrapper_Impl + + Provides an single UNO object as OLE object. Handle the + OLE registration by overloading the abstract methods from + IClassFactoryWrapper. + + Acts as a COM class factory. When IClassFactory::CreateInstance is being called + then it maps the XInstance member it to a COM object. + +*****************************************************************************/ + +class OneInstanceOleWrapper_Impl : public IClassFactoryWrapper +{ +public: + + OneInstanceOleWrapper_Impl( const Reference<XMultiServiceFactory>& smgr, const Reference<XInterface>& xInst, GUID* pGuid, sal_Bool bAsApplication ); + virtual ~OneInstanceOleWrapper_Impl(); + + sal_Bool registerClass(); + sal_Bool deregisterClass(); + + /* IUnknown methods */ + STDMETHOD(QueryInterface)(REFIID riid, LPVOID FAR * ppvObj); + STDMETHOD_(ULONG, AddRef)(); + STDMETHOD_(ULONG, Release)(); + + /* IClassFactory methods */ + STDMETHOD(CreateInstance)(IUnknown FAR* punkOuter, REFIID riid, void FAR* FAR* ppv); + STDMETHOD(LockServer)(int fLock); + +protected: + + oslInterlockedCount m_refCount; + Reference<XInterface> m_xInst; + GUID m_guid; + DWORD m_factoryHandle; + Reference<XBridgeSupplier2> m_bridgeSupplier; + Reference<XMultiServiceFactory> m_smgr; + unsigned long m_nApplRegHandle; + sal_Bool m_bAsApplication; +}; + +/***************************************************************************** + + class declaration OleConverter_Impl2 + + Implementation of the UNO service com.sun.star.bridge.OleBridgeSupplier2. + +*****************************************************************************/ + +// This class realizes the service com.sun.star.bridge.OleBridgeSupplier2 and +// com.sun.star.bridge.OleBridgeSupplierVar1. The class implements XBridgeSupplier2 +// instead of XBridgeSuppplier as done by class OleConverter_Impl. The XBridgeSupplier2 +// interface does not need a Maschine Id in its createBridge function anymore, +// If an UNO interface is to be converted then the member m_nUnoWrapperClass determines +// what wrapper class is to be used. There are currently InterfaceOleWrapper_Impl and +// UnoObjectWrapperRemoteOpt. The first is used for the OleBridgeSupplier2 and the +// latter for OleBridgeSupplierVar1. +// The m_nComWrapperClass specifies the class which is used as wrapper for COM interfaces. +// Currently there is only one class available ( IUnknownWrapper_Impl). +class OleConverter_Impl2 : public WeakImplHelper2<XBridgeSupplier2, XInitialization>, + public UnoConversionUtilities<OleConverter_Impl2> +{ +public: + OleConverter_Impl2( const Reference<XMultiServiceFactory>& smgr); + OleConverter_Impl2( const Reference<XMultiServiceFactory>& smgr, sal_uInt8 unoWrapperClass, sal_uInt8 comWrapperClass ); + virtual ~OleConverter_Impl2(); + + // XBridgeSupplier2 --------------------------------------------------- + + virtual Any SAL_CALL createBridge(const Any& modelDepObject, + const Sequence<sal_Int8>& ProcessId, + sal_Int16 sourceModelType, + sal_Int16 destModelType) + throw (IllegalArgumentException, RuntimeException); + + // XInitialization + virtual void SAL_CALL initialize( const Sequence< Any >& aArguments ) throw(Exception, RuntimeException); + + // Abstract struct UnoConversionUtilities + virtual Reference< XInterface > createUnoWrapperInstance(); + virtual Reference< XInterface > createComWrapperInstance(); +protected: + +}; + + +/***************************************************************************** + + class declaration OleClient_Impl + + Implementation of the UNO service com.sun.star.bridge.OleObjectFactory. + +*****************************************************************************/ + + +class OleClient_Impl : public WeakImplHelper1<XMultiServiceFactory>, + public UnoConversionUtilities<OleClient_Impl> +{ +public: + OleClient_Impl( const Reference<XMultiServiceFactory>& smgr); + ~OleClient_Impl(); + + // XMultiServiceFactory + virtual Reference<XInterface> SAL_CALL createInstance(const OUString& ServiceSpecifier) throw( Exception, RuntimeException); + virtual Reference<XInterface> SAL_CALL createInstanceWithArguments(const OUString& ServiceSpecifier, const Sequence< Any >& Arguments) throw (Exception, RuntimeException); + Sequence< OUString > SAL_CALL getAvailableServiceNames() throw (RuntimeException); + + // Abstract struct UnoConversionUtilities + virtual Reference< XInterface > createUnoWrapperInstance(); + virtual Reference< XInterface > createComWrapperInstance(); + + + OUString getImplementationName(); +protected: + Reference<XBridgeSupplier2> m_bridgeSupplier; +}; + +/***************************************************************************** + + class declaration OleServer_Impl + + Implementation of the UNO service com.sun.star.bridge.OleApplicationRegistration. + Register the calling application as OLE automation server for + standard OLE object. The objects will be registered while instanciating + this implementation and deregistrated, if this implementation is destroyed. + +*****************************************************************************/ + +class OleServer_Impl : public OWeakObject, XTypeProvider +{ +public: + OleServer_Impl( const Reference<XMultiServiceFactory> &smgr); + ~OleServer_Impl(); + + // XInterface + virtual Any SAL_CALL queryInterface( const Type& aType ) throw(RuntimeException); + virtual void SAL_CALL acquire( ) throw (); + virtual void SAL_CALL release( ) throw (); + + // XTypeProvider + virtual Sequence< Type > SAL_CALL getTypes( ) throw(RuntimeException); + virtual Sequence< sal_Int8 > SAL_CALL getImplementationId() throw(RuntimeException); + +protected: + + sal_Bool provideService(const Reference<XSingleServiceFactory>& xMulFact, GUID* guid); + sal_Bool provideInstance(const Reference<XInterface>& xInst, GUID* guid, sal_Bool bAsApplication ); + + list< IClassFactoryWrapper* > m_wrapperList; + Reference< XBridgeSupplier2 > m_bridgeSupplier; + + Reference<XMultiServiceFactory> m_smgr; +}; + +} // end namespace +#endif + + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/ole/servreg.cxx b/extensions/source/ole/servreg.cxx new file mode 100644 index 000000000000..16a99df48fa4 --- /dev/null +++ b/extensions/source/ole/servreg.cxx @@ -0,0 +1,176 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_extensions.hxx" +#include <rtl/unload.h> +#include <osl/time.h> +#include "ole2uno.hxx" +#include "servprov.hxx" +#include <rtl/ustring.hxx> +#include <cppuhelper/factory.hxx> +using namespace rtl; +using namespace ole_adapter; +using namespace cppu; + +namespace ole_adapter +{ +rtl_StandardModuleCount globalModuleCount= MODULE_COUNT_INIT; + + + +Reference<XInterface> SAL_CALL ConverterProvider_CreateInstance2( const Reference<XMultiServiceFactory> & xSMgr) + throw(Exception) +{ + Reference<XInterface> xService = *new OleConverter_Impl2( xSMgr); + return xService; +} + +Reference<XInterface> SAL_CALL ConverterProvider_CreateInstanceVar1( const Reference<XMultiServiceFactory> & xSMgr) + throw(Exception) +{ + Reference<XInterface> xService = *new OleConverter_Impl2( xSMgr, UNO_OBJECT_WRAPPER_REMOTE_OPT, IUNKNOWN_WRAPPER_IMPL); + return xService; +} + +Reference<XInterface> SAL_CALL OleClient_CreateInstance( const Reference<XMultiServiceFactory> & xSMgr) + throw(Exception) +{ + Reference<XInterface> xService = *new OleClient_Impl( xSMgr); + return xService; +} + +Reference<XInterface> SAL_CALL OleServer_CreateInstance( const Reference<XMultiServiceFactory> & xSMgr) + throw (Exception) +{ + Reference<XInterface > xService = *new OleServer_Impl(xSMgr); + return xService; +} +} // end namespace + +extern "C" void * SAL_CALL component_getFactory( + const sal_Char * pImplName, void * pServiceManager, void * /*pRegistryKey*/ ) +{ + void * pRet = 0; + + OUString aImplName( OUString::createFromAscii( pImplName ) ); + Reference< XSingleServiceFactory > xFactory; + Sequence<OUString> seqServiceNames; + if (pServiceManager && aImplName.equals( reinterpret_cast<const sal_Unicode*>(L"com.sun.star.comp.ole.OleConverter2") )) + { + xFactory= createSingleFactory( reinterpret_cast< XMultiServiceFactory*>(pServiceManager), + OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.comp.ole.OleConverter2")), + ConverterProvider_CreateInstance2, seqServiceNames, + &globalModuleCount.modCnt ); + } + else if (pServiceManager && aImplName.equals( reinterpret_cast<const sal_Unicode*>(L"com.sun.star.comp.ole.OleConverterVar1") )) + { + xFactory= createSingleFactory( reinterpret_cast<XMultiServiceFactory*>(pServiceManager), + OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.comp.ole.OleConverterVar1")), + ConverterProvider_CreateInstanceVar1, seqServiceNames, + &globalModuleCount.modCnt ); + } + else if(pServiceManager && aImplName.equals(reinterpret_cast<const sal_Unicode*>(L"com.sun.star.comp.ole.OleClient"))) + { + xFactory= createSingleFactory( reinterpret_cast< XMultiServiceFactory*>(pServiceManager), + OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.comp.ole.OleClient")), + OleClient_CreateInstance, seqServiceNames, + &globalModuleCount.modCnt); + } + else if(pServiceManager && aImplName.equals(reinterpret_cast<const sal_Unicode*>(L"com.sun.star.comp.ole.OleServer"))) + { + xFactory= createOneInstanceFactory( reinterpret_cast< XMultiServiceFactory*>(pServiceManager), + OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.comp.ole.OleServer")), + OleServer_CreateInstance, seqServiceNames, + &globalModuleCount.modCnt); + } + + if (xFactory.is()) + { + xFactory->acquire(); + pRet = xFactory.get(); + } + + return pRet; +} + + +extern "C" sal_Bool SAL_CALL component_writeInfo( void * /*pServiceManager*/, void * pRegistryKey ) +{ + if (pRegistryKey) + { + try + { + //deprecated + Reference<XRegistryKey> xNewKey = + reinterpret_cast<XRegistryKey*>( pRegistryKey)->createKey(reinterpret_cast<const sal_Unicode*>(L"/com.sun.star.comp.ole.OleConverter2/UNO/SERVICES")); + xNewKey->createKey(reinterpret_cast<const sal_Unicode*>(L"com.sun.star.bridge.OleBridgeSupplier2")); + + xNewKey->createKey(reinterpret_cast<const sal_Unicode*>(L"com.sun.star.bridge.oleautomation.BridgeSupplier")); + + //deprecated + xNewKey = + reinterpret_cast<XRegistryKey*>( pRegistryKey)->createKey(reinterpret_cast<const sal_Unicode*>(L"/com.sun.star.comp.ole.OleConverterVar1/UNO/SERVICES")); + xNewKey->createKey(reinterpret_cast<const sal_Unicode*>(L"com.sun.star.bridge.OleBridgeSupplierVar1")); + + //deprecated + xNewKey = + reinterpret_cast<XRegistryKey*>( pRegistryKey)->createKey(reinterpret_cast<const sal_Unicode*>(L"/com.sun.star.comp.ole.OleClient/UNO/SERVICES")); + xNewKey->createKey(reinterpret_cast<const sal_Unicode*>(L"com.sun.star.bridge.OleObjectFactory")); + + xNewKey->createKey(reinterpret_cast<const sal_Unicode*>(L"com.sun.star.bridge.oleautomation.Factory")); + //deprecated + xNewKey = + reinterpret_cast<XRegistryKey*>( pRegistryKey)->createKey(reinterpret_cast<const sal_Unicode*>(L"/com.sun.star.comp.ole.OleServer/UNO/SERVICES")); + xNewKey->createKey(reinterpret_cast<const sal_Unicode*>(L"com.sun.star.bridge.OleApplicationRegistration")); + + xNewKey->createKey(reinterpret_cast<const sal_Unicode*>(L"com.sun.star.bridge.oleautomation.ApplicationRegistration")); + + return sal_True; + } + catch (InvalidRegistryException &) + { + OSL_ENSURE( sal_False, "### InvalidRegistryException!" ); + } + } + return sal_False; +} + +extern "C" void SAL_CALL component_getImplementationEnvironment( + const sal_Char ** ppEnvTypeName, uno_Environment ** /*ppEnv*/ ) +{ + *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME; +} + + +extern "C" sal_Bool component_canUnload( TimeValue* libUnused) +{ + return globalModuleCount.canUnload( &globalModuleCount, libUnused); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/ole/unoconversionutilities.hxx b/extensions/source/ole/unoconversionutilities.hxx new file mode 100644 index 000000000000..1970b08fd843 --- /dev/null +++ b/extensions/source/ole/unoconversionutilities.hxx @@ -0,0 +1,2452 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _UNO_CONVERSION_UTILITIES +#define _UNO_CONVERSION_UTILITIES + +#include "boost/scoped_array.hpp" +#include "com/sun/star/script/XInvocationAdapterFactory.hpp" +#include "com/sun/star/script/XInvocationAdapterFactory2.hpp" +#include "com/sun/star/script/XTypeConverter.hpp" +#include "com/sun/star/script/FailReason.hpp" +#include "com/sun/star/bridge/oleautomation/Date.hpp" +#include "com/sun/star/bridge/oleautomation/Currency.hpp" +#include "com/sun/star/bridge/oleautomation/SCode.hpp" +#include "com/sun/star/bridge/oleautomation/Decimal.hpp" +#include "typelib/typedescription.hxx" +#include "ole2uno.hxx" + +#include "unotypewrapper.hxx" +#include <hash_map> + +// for some reason DECIMAL_NEG (wtypes.h) which contains BYTE is not resolved. +typedef unsigned char BYTE; +// classes for wrapping uno objects +#define INTERFACE_OLE_WRAPPER_IMPL 1 +#define UNO_OBJECT_WRAPPER_REMOTE_OPT 2 + +#define INVOCATION_SERVICE reinterpret_cast<const sal_Unicode*>(L"com.sun.star.script.Invocation") + + +// classes for wrapping ole objects +#define IUNKNOWN_WRAPPER_IMPL 1 + +#define INTERFACE_ADAPTER_FACTORY reinterpret_cast<const sal_Unicode*>(L"com.sun.star.script.InvocationAdapterFactory") +// COM or JScript objects implementing UNO interfaces have to implement this property +#define SUPPORTED_INTERFACES_PROP L"_implementedInterfaces" +// Second property without leading underscore for use in VB +#define SUPPORTED_INTERFACES_PROP2 L"Bridge_ImplementedInterfaces" + +using namespace com::sun::star::script; +using namespace com::sun::star::beans; +using namespace com::sun::star::uno; +#ifdef __MINGW32__ +using namespace com::sun::star::bridge; +using namespace com::sun::star::bridge::ModelDependent; +#endif +using namespace com::sun::star::bridge::oleautomation; +using namespace boost; +namespace ole_adapter +{ +extern hash_map<sal_uInt32, sal_uInt32> AdapterToWrapperMap; +extern hash_map<sal_uInt32, sal_uInt32> WrapperToAdapterMap; +typedef hash_map<sal_uInt32, sal_uInt32>::iterator IT_Wrap; +typedef hash_map<sal_uInt32, sal_uInt32>::iterator CIT_Wrap; +//Maps IUnknown pointers to a weak reference of the respective wrapper class (e.g. +// IUnknownWrapperImpl. It is the responsibility of the wrapper to remove the entry when +// it is being destroyed. +// Used to ensure that an Automation object is always mapped to the same UNO objects. +extern hash_map<sal_uInt32, WeakReference<XInterface> > ComPtrToWrapperMap; +typedef hash_map<sal_uInt32, WeakReference<XInterface> >::iterator IT_Com; +typedef hash_map<sal_uInt32, WeakReference<XInterface> >::const_iterator CIT_Com; + +// Maps XInterface pointers to a weak reference of its wrapper class (i.e. +// InterfaceOleWrapper_Impl). It is the responsibility of the wrapper to remove the entry when +// it is being destroyed. It is used to ensure the identity of objects. That is, an UNO interface +// is mapped to IDispatch which is kept alive in the COM environment. If the same +// UNO interface is mapped again to COM then the IDispach of the first mapped instance +// must be returned. +extern hash_map<sal_uInt32, WeakReference<XInterface> > UnoObjToWrapperMap; +typedef hash_map<sal_uInt32, WeakReference<XInterface> >::iterator IT_Uno; +typedef hash_map<sal_uInt32, WeakReference<XInterface> >::const_iterator CIT_Uno; +#ifdef __MINGW32__ +inline void reduceRange( Any& any); +#endif + + + + +// createUnoObjectWrapper gets a wrapper instance by calling createUnoWrapperInstance + // and initializes it via XInitialization. The wrapper object is required to implement + // XBridgeSupplier so that it can convert itself to IDispatch. + // class T: Deriving class ( must implement XInterface ) +/** All methods are allowed to throw at least a BridgeRuntimeError. + */ +template< class > +class UnoConversionUtilities +{ +public: + UnoConversionUtilities( const Reference<XMultiServiceFactory> & smgr): + m_nUnoWrapperClass( INTERFACE_OLE_WRAPPER_IMPL), + m_nComWrapperClass( IUNKNOWN_WRAPPER_IMPL), + m_smgr( smgr) + {} + + UnoConversionUtilities( const Reference<XMultiServiceFactory> & xFactory, sal_uInt8 unoWrapperClass, sal_uInt8 comWrapperClass ) + : m_smgr( xFactory), m_nComWrapperClass( comWrapperClass), m_nUnoWrapperClass( unoWrapperClass) + {} + + virtual ~UnoConversionUtilities() {} + /** converts only into oleautomation types, that is there is no VT_I1, VT_UI2, VT_UI4 + a sal_Unicode character is converted into a BSTR. + @exception com.sun.star.lang.IllegalArgumentException + If the any was inappropriate for conversion. + @exception com.sun.star.script.CannotConvertException + The any contains a type class for which no conversion is provided. + */ + void anyToVariant(VARIANT* pVariant, const Any& rAny); + void anyToVariant(VARIANT* pVariant, const Any& rAny, VARTYPE type); + + /** @exception com.sun.star.lang.IllegalArgumentException + If rSeq does not contain a sequence then the exception is thrown. + */ + SAFEARRAY* createUnoSequenceWrapper(const Any& rSeq); + /** @exception com.sun.star.lang.IllegalArgumentException + If rSeq does not contain a sequence or elemtype has no proper value + then the exception is thrown. + */ + SAFEARRAY* createUnoSequenceWrapper(const Any& rSeq, VARTYPE elemtype); + /** + @exception com.sun.star.lang.IllegalArgumentException + If rObj does not contain a struct or interface + */ + void createUnoObjectWrapper(const Any & rObj, VARIANT * pVar); + /** @exception CannotConvertException + Thrown if the VARIANT contains a type that cannot be coerced in the expected Any. + ArgumentIndex is 0. + @IllegalArgumentException + Thrown if the VARIANT is inappropriate for conversion. ArgumentPosition is -1, + */ + void variantToAny(const VARIANT* pVariant, Any& rAny, sal_Bool bReduceValueRange = sal_True); + /** This method converts variants arguments in calls from COM -> UNO. Only then + the expected UNO type is known. + @exception CannotConvertException + Thrown if the VARIANT contains a type that cannot be coerced in the expected Any. + ArgumentIndex is 0. + @IllegalArgumentException + Thrown if the VARIANT is inappropriate for conversion. ArgumentPosition is -1, + */ + void variantToAny( const VARIANTARG* pArg, Any& rAny, const Type& ptype, sal_Bool bReduceValueRange = sal_True); + + /** + @exception IllegalArgumentException + -if pVar does not contain VT_UNKNOWN or VT_DISPATCH or + pVar is used for a particular UNO type which is not supported by pVar + */ + Any createOleObjectWrapper(VARIANT* pVar, const Type& aType= Type()); + + /* + Return true means var contained a ValueObject, and it was successfully converted. + The result is in any. It an error occurred a BridgeRuntimeError will be thrown. + */ + bool convertValueObject( const VARIANTARG *var, Any& any); + void dispatchExObject2Sequence( const VARIANTARG* pvar, Any& anySeq, const Type& type); + + Sequence<Any> createOleArrayWrapperOfDim(SAFEARRAY* pArray, unsigned int dimCount, unsigned int actDim, long* index, + VARTYPE type, const Type& unotype); + Sequence<Any> createOleArrayWrapper(SAFEARRAY* pArray, VARTYPE type, const Type& unotype= Type()); + + + VARTYPE mapTypeClassToVartype( TypeClass type); + Reference< XSingleServiceFactory > getInvocationFactory(const Any& anyObject); + + + virtual Reference< XInterface > createUnoWrapperInstance()=0; + virtual Reference< XInterface > createComWrapperInstance()=0; + + static sal_Bool isJScriptArray(const VARIANT* pvar); + + Sequence<Type> getImplementedInterfaces(IUnknown* pUnk); + +protected: + Reference<XInterface> createAdapter(const Sequence<Type>& types, const Reference<XInterface>& receiver); + + // helper function for Sequence conversion + void getElementCountAndTypeOfSequence( const Any& rSeq, sal_Int32 dim, Sequence< sal_Int32 >& seqElementCounts, TypeDescription& typeDesc); + // helper function for Sequence conversion + sal_Bool incrementMultidimensionalIndex(sal_Int32 dimensions, const sal_Int32 * parDimensionLength, + sal_Int32 * parMultidimensionalIndex); + // helper function for Sequence conversion + size_t getOleElementSize( VARTYPE type); + + Type getElementTypeOfSequence( const Type& seqType); + + //Provides a typeconverter + Reference<XTypeConverter> getTypeConverter(); + + // This member determines what class is used to convert a UNO object + // or struct to a COM object. It is passed along to the o2u_anyToVariant + // function in the createBridge function implementation + sal_uInt8 m_nUnoWrapperClass; + sal_uInt8 m_nComWrapperClass; + + // The servicemanager is either a local smgr or remote when the service + // com.sun.star.bridge.OleBridgeSupplierVar1 is used. This service can be + // created by createInstanceWithArguments where one can supply a service + // manager that is to be used. + // Local service manager as supplied by the loader when the creator function + // of the service is being called. + Reference<XMultiServiceFactory> m_smgr; + // An explicitly supplied service manager when the service + // com.sun.star.bridge.OleBridgeSupplierVar1 is used. That can be a remote + // manager. + Reference<XMultiServiceFactory> m_smgrRemote; + Reference<XSingleServiceFactory> m_xInvocationFactoryLocal; + Reference<XSingleServiceFactory> m_xInvocationFactoryRemote; + +private: + // Holds the type converter which is used for sequence conversion etc. + // Use the getTypeConverter function to obtain the interface. + Reference<XTypeConverter> m_typeConverter; + + +}; + +// ask the object for XBridgeSupplier2 and on success bridges +// the uno object to IUnknown or IDispatch. +// return true the UNO object supports +template < class T > +bool convertSelfToCom( T& unoInterface, VARIANT * pVar) +{ + bool ret = false; + Reference< XInterface > xInt( unoInterface, UNO_QUERY); + if( xInt.is()) + { + Reference< XBridgeSupplier2 > xSupplier( xInt, UNO_QUERY); + if( xSupplier.is()) + { + sal_Int8 arId[16]; + rtl_getGlobalProcessId( (sal_uInt8*)arId); + Sequence<sal_Int8> seqId( arId, 16); + Any anySource; + anySource <<= xInt; + Any anyDisp= xSupplier->createBridge( anySource, seqId, UNO, OLE); + if( anyDisp.getValueTypeClass() == TypeClass_UNSIGNED_LONG) + { + VARIANT* pvariant= *(VARIANT**)anyDisp.getValue(); + HRESULT hr; + if (FAILED(hr = VariantCopy(pVar, pvariant))) + throw BridgeRuntimeError( + OUSTR("[automation bridge] convertSelfToCom\n" + "VariantCopy failed! Error: ") + + OUString::valueOf(hr)); + VariantClear( pvariant); + CoTaskMemFree( pvariant); + ret = true; + } + } + } + return ret; +} + + + +// Gets the invocation factory depending on the Type in the Any. +// The factory can be created by a local or remote multi service factory. +// In case there is a remote multi service factory available there are +// some services or types for which the local factory is used. The exceptions +// are: all structs. +// Param anyObject - contains the object ( interface, struct) for what we need an invocation object. +// +template<class T> +Reference< XSingleServiceFactory > UnoConversionUtilities<T>::getInvocationFactory(const Any& anyObject) +{ + Reference< XSingleServiceFactory > retVal; + MutexGuard guard( getBridgeMutex()); + if( anyObject.getValueTypeClass() != TypeClass_STRUCT && + m_smgrRemote.is() ) + { + if( ! m_xInvocationFactoryRemote.is() ) + m_xInvocationFactoryRemote= Reference<XSingleServiceFactory>( + m_smgrRemote->createInstance( INVOCATION_SERVICE), UNO_QUERY); + retVal= m_xInvocationFactoryRemote; + } + else + { + if( ! m_xInvocationFactoryLocal.is() ) + m_xInvocationFactoryLocal= Reference<XSingleServiceFactory>( + m_smgr->createInstance(INVOCATION_SERVICE ), UNO_QUERY); + retVal= m_xInvocationFactoryLocal; + } + return retVal; +} + +template<class T> +void UnoConversionUtilities<T>::variantToAny( const VARIANTARG* pArg, Any& rAny, const Type& ptype, sal_Bool bReduceValueRange /* = sal_True */) +{ + try + { + HRESULT hr; + bool bFail = false; + bool bCannotConvert = false; + CComVariant var; + + // There is no need to support indirect values, since they're not supported by UNO + if( FAILED(hr= VariantCopyInd( &var, const_cast<VARIANTARG*>(pArg)))) // remove VT_BYREF + throw BridgeRuntimeError( + OUSTR("[automation bridge] UnoConversionUtilities<T>::variantToAny \n" + "VariantCopyInd failed for reason : ") + OUString::valueOf(hr)); + bool bHandled = convertValueObject( & var, rAny); + if( bHandled) + OSL_ENSURE( rAny.getValueType() == ptype, "type in Value Object must match the type parameter"); + + if( ! bHandled) + { + // convert into a variant type that is the equivalent to the type + // the sequence expects. Thus variantToAny produces the correct type + // E.g. An Array object contains VT_I4 and the sequence expects shorts + // than the vartype must be changed. The reason is, you can't specify the + // type in JavaScript and the script engine determines the type beeing used. + switch( ptype.getTypeClass()) + { + case TypeClass_CHAR: // could be: new Array( 12, 'w', "w") + if( var.vt == VT_BSTR) + { + if(SUCCEEDED( hr= VariantChangeType( &var, &var, 0, VT_BSTR))) + rAny.setValue( (void*)V_BSTR( &var), ptype); + else if (hr == DISP_E_TYPEMISMATCH) + bCannotConvert = true; + else + bFail = true; + } + else + { + if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_I2))) + rAny.setValue((void*) & var.iVal, ptype); + else if (hr == DISP_E_TYPEMISMATCH) + bCannotConvert = true; + else + bFail = true; + } + break; + case TypeClass_INTERFACE: // could also be an IUnknown + case TypeClass_STRUCT: + { + rAny = createOleObjectWrapper( & var, ptype); + break; + } + case TypeClass_ENUM: + if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_I4))) + rAny.setValue((void*) & var.lVal, ptype); + else if (hr == DISP_E_TYPEMISMATCH) + bCannotConvert = true; + else + bFail = true; + break; + case TypeClass_SEQUENCE: + // There are different ways of receiving a sequence: + // 1: JScript, VARTYPE: VT_DISPATCH + // 2. VBScript simple arraysVT_VARIANT|VT_BYREF the referenced VARIANT contains + // a VT_ARRAY| <type> + // 3. VBSrcript multi dimensional arrays: VT_ARRAY|VT_BYREF + if( pArg->vt == VT_DISPATCH) + { + dispatchExObject2Sequence( pArg, rAny, ptype); + } + else + { + if ((var.vt & VT_ARRAY) != 0) + { + VARTYPE oleType = ::sal::static_int_cast< VARTYPE, int >( var.vt ^ VT_ARRAY ); + Sequence<Any> unoSeq = createOleArrayWrapper( var.parray, oleType, ptype); + Reference<XTypeConverter> conv = getTypeConverter(); + if (conv.is()) + { + try + { + Any anySeq = makeAny(unoSeq); + Any convAny = conv->convertTo(anySeq, ptype); + rAny = convAny; + } + catch (IllegalArgumentException& e) + { + throw BridgeRuntimeError( + OUSTR("[automation bridge]com.sun.star.lang.IllegalArgumentException " + "in UnoConversionUtilities<T>::variantToAny! Message: ") + + e.Message); + } + catch (CannotConvertException& e) + { + throw BridgeRuntimeError( + OUSTR("[automation bridge]com.sun.star.script.CannotConvertException " + "in UnoConversionUtilities<T>::variantToAny! Message: ") + + e.Message); + } + } + } + } + break; + case TypeClass_VOID: + rAny.setValue(NULL,Type()); + break; + case TypeClass_ANY: // Any + // There could be a JScript Array that needs special handling + // If an Any is expected and this Any must contain a Sequence + // then we cannot figure out what element type is required. + // Therefore we convert to Sequence< Any > + if( pArg->vt == VT_DISPATCH && isJScriptArray( pArg)) + { + dispatchExObject2Sequence( pArg, rAny, + getCppuType((Sequence<Any>*) 0)); + } + else if (pArg->vt == VT_DECIMAL) + { + //Decimal maps to hyper in calls from COM -> UNO + // It does not matter if we create a sal_uInt64 or sal_Int64, + // because the UNO object is called through invocation which + //will do a type conversion if necessary + if (var.decVal.sign == 0) + { + // positive value + variantToAny( & var, rAny, getCppuType( (sal_uInt64*) 0), + bReduceValueRange); + } + else + { + //negative value + variantToAny( & var, rAny, getCppuType( (sal_Int64*) 0), + bReduceValueRange); + } + } + else + { + variantToAny( & var, rAny); + } + break; + case TypeClass_BOOLEAN: // VARIANT could be VARIANT_BOOL or other + if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_BOOL))) + variantToAny( & var, rAny); + else if (hr == DISP_E_TYPEMISMATCH) + bCannotConvert = true; + else + bFail = true; + break; + case TypeClass_STRING: // UString + if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_BSTR))) + variantToAny( & var, rAny); + else if (hr == DISP_E_TYPEMISMATCH) + bCannotConvert = true; + else + bFail = true; + break; + case TypeClass_FLOAT: // float + if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_R4))) + variantToAny( & var, rAny); + else if (hr == DISP_E_TYPEMISMATCH) + bCannotConvert = true; + else + bFail = true; + break; + case TypeClass_DOUBLE: // double + if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_R8))) + variantToAny(& var, rAny); + else if (hr == DISP_E_TYPEMISMATCH) + bCannotConvert = true; + else + bFail = true; + break; + case TypeClass_BYTE: // BYTE + if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_I1))) + variantToAny( & var, rAny); + else if (hr == DISP_E_TYPEMISMATCH) + bCannotConvert = true; + else + bFail = true; + break; + case TypeClass_SHORT: // INT16 + if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_I2))) + variantToAny( & var, rAny); + else if (hr == DISP_E_TYPEMISMATCH) + bCannotConvert = true; + else + bFail = true; + break; + case TypeClass_LONG: + if(SUCCEEDED(hr = VariantChangeType(& var, &var, 0, VT_I4))) + variantToAny( & var, rAny, bReduceValueRange); + else if (hr == DISP_E_TYPEMISMATCH) + bCannotConvert = true; + else + bFail = true; + break; + case TypeClass_HYPER: + if(SUCCEEDED(hr = VariantChangeType(& var, &var, 0, VT_DECIMAL))) + { + if (var.decVal.Lo64 > SAL_CONST_UINT64(0x8000000000000000) + || var.decVal.Hi32 > 0 + || var.decVal.scale > 0) + { + bFail = true; + break; + } + sal_Int64 value = var.decVal.Lo64; + if (var.decVal.sign == DECIMAL_NEG) + value |= SAL_CONST_UINT64(0x8000000000000000); + rAny <<= value; + } + else if (hr == DISP_E_TYPEMISMATCH) + bCannotConvert = true; + else + bFail = true; + break; + case TypeClass_UNSIGNED_SHORT: // UINT16 + if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_UI2))) + variantToAny( & var, rAny); + else if (hr == DISP_E_TYPEMISMATCH) + bCannotConvert = true; + else + bFail = true; + break; + case TypeClass_UNSIGNED_LONG: + if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_UI4))) + variantToAny( & var, rAny, bReduceValueRange); + else if (hr == DISP_E_TYPEMISMATCH) + bCannotConvert = true; + else + bFail = true; + break; + case TypeClass_UNSIGNED_HYPER: + if(SUCCEEDED(hr = VariantChangeType(& var, &var, 0, VT_DECIMAL))) + { + if (var.decVal.Hi32 > 0 || var.decVal.scale > 0) + { + bFail = true; + break; + } + rAny <<= var.decVal.Lo64; + } + else if (hr == DISP_E_TYPEMISMATCH) + bCannotConvert = true; + else + bFail = true; + break; + case TypeClass_TYPE: + if(SUCCEEDED(hr = VariantChangeType(& var, &var, 0, VT_UNKNOWN))) + variantToAny( & var, rAny); + else if (hr == DISP_E_TYPEMISMATCH) + bCannotConvert = true; + else + bFail = true; + break; + default: +// case TypeClass_SERVICE: break; // meta construct +// case TypeClass_TYPEDEF: break; +// case TypeClass_UNION: break; +// case TypeClass_MODULE: break; // module +// case TypeClass_EXCEPTION: break; +// case TypeClass_ARRAY: break; // there's no Array at the moment +// case TypeClass_UNKNOWN: break; + bCannotConvert = true; + break; + } + } + if (bCannotConvert) + throw CannotConvertException( + OUSTR("[automation bridge]UnoConversionUtilities<T>::variantToAny \n" + "Cannot convert the value of vartype :\"") + + OUString::valueOf((sal_Int32) var.vt) + + OUSTR("\" to the expected UNO type of type class: ") + + OUString::valueOf((sal_Int32) ptype.getTypeClass()), + 0, TypeClass_UNKNOWN, FailReason::TYPE_NOT_SUPPORTED,0); + + if (bFail) + throw IllegalArgumentException( + OUSTR("[automation bridge]UnoConversionUtilities<T>:variantToAny\n" + "The provided VARIANT of type\" ") + OUString::valueOf((sal_Int32) var.vt) + + OUSTR("\" is unappropriate for conversion!"), Reference<XInterface>(), -1); + } + catch (CannotConvertException &) + { + throw; + } + catch (IllegalArgumentException &) + { + throw; + } + catch (BridgeRuntimeError &) + { + throw; + } + catch (Exception & e) + { + throw BridgeRuntimeError(OUSTR("[automation bridge] unexpected exception in " + "UnoConversionUtilities<T>::variantToAny ! Message : \n") + + e.Message); + } + catch(...) + { + throw BridgeRuntimeError( + OUSTR("[automation bridge] unexpected exception in " + "UnoConversionUtilities<T>::variantToAny !")); + } +} + +// The function only converts Sequences to SAFEARRAYS with elements of the type +// specified by the parameter type. Everything else is forwarded to +// anyToVariant(VARIANT* pVariant, const Any& rAny) +// Param type must not be VT_BYREF +template<class T> +void UnoConversionUtilities<T>::anyToVariant(VARIANT* pVariant, const Any& rAny, VARTYPE type) +{ + try + { + HRESULT hr= S_OK; + + OSL_ASSERT( (type & VT_BYREF) == 0); + if (type & VT_ARRAY) + { + type ^= VT_ARRAY; + SAFEARRAY* ar= createUnoSequenceWrapper( rAny, type); + if( ar) + { + VariantClear( pVariant); + pVariant->vt= ::sal::static_int_cast< VARTYPE, int >( VT_ARRAY | type ); + pVariant->byref= ar; + } + } + else if(type == VT_VARIANT) + { + anyToVariant(pVariant, rAny); + } + else + { + CComVariant var; + anyToVariant( &var, rAny); + if(FAILED(hr = VariantChangeType(&var, &var, 0, type))) + { + if (hr == DISP_E_TYPEMISMATCH) + throw CannotConvertException( + OUSTR("[automation bridge]UnoConversionUtilities<T>::anyToVariant \n" + "Cannot convert the value of type :\"") + + rAny.getValueTypeName() + + OUSTR("\" to the expected Automation type of VARTYPE: ") + + OUString::valueOf((sal_Int32)type), + 0, TypeClass_UNKNOWN, FailReason::TYPE_NOT_SUPPORTED,0); + + throw BridgeRuntimeError( + OUSTR("[automation bridge]UnoConversionUtilities<T>::anyToVariant \n" + "Conversion of any with ") + + rAny.getValueType().getTypeName() + + OUSTR(" to VARIANT with type: ") + OUString::valueOf((sal_Int32) type) + + OUSTR(" failed! Error code: ") + OUString::valueOf(hr)); + + } + if(FAILED(hr = VariantCopy(pVariant, &var))) + { + throw BridgeRuntimeError( + OUSTR("[automation bridge]UnoConversionUtilities<T>::anyToVariant \n" + "VariantCopy failed for reason: ") + OUString::valueOf(hr)); + } + } + } + catch (IllegalArgumentException &) + { + throw; + } + catch (CannotConvertException & ) + { + throw; + } + catch (BridgeRuntimeError&) + { + throw; + } + catch(Exception & e) + { + throw BridgeRuntimeError( + OUSTR("[automation bridge]UnoConversionUtilities<T>::anyToVariant \n" + "Unexpected exception occurred. Message: ") + e.Message); + } + catch(...) + { + throw BridgeRuntimeError( + OUSTR("[automation bridge]UnoConversionUtilities<T>::anyToVariant \n" + "Unexpected exception occurred.")); + } +} + +template<class T> +void UnoConversionUtilities<T>::anyToVariant(VARIANT* pVariant, const Any& rAny) +{ + bool bIllegal = false; + try + { + switch (rAny.getValueTypeClass()) + { + case TypeClass_INTERFACE: + { + Reference<XInterface> xInt; + if (rAny >>= xInt) + { + createUnoObjectWrapper(rAny, pVariant); + } + else + { + bIllegal = true; + } + break; + } + case TypeClass_STRUCT: + { + if (rAny.getValueType() == getCppuType((Date*)0)) + { + Date d; + if (rAny >>= d) + { + pVariant->vt = VT_DATE; + pVariant->date = d.Value; + } + else + { + bIllegal = true; + } + } + else if(rAny.getValueType() == getCppuType((Decimal*)0)) + { + Decimal d; + if (rAny >>= d) + { + pVariant->vt = VT_DECIMAL; + pVariant->decVal.scale = d.Scale; + pVariant->decVal.sign = d.Sign; + pVariant->decVal.Lo32 = d.LowValue; + pVariant->decVal.Mid32 = d.MiddleValue; + pVariant->decVal.Hi32 = d.HighValue; + } + else + { + bIllegal = true; + } + } + else if (rAny.getValueType() == getCppuType((Currency*)0)) + { + Currency c; + if (rAny >>= c) + { + pVariant->vt = VT_CY; + pVariant->cyVal.int64 = c.Value; + } + else + { + bIllegal = true; + } + } + else if(rAny.getValueType() == getCppuType((SCode*)0)) + { + SCode s; + if (rAny >>= s) + { + pVariant->vt = VT_ERROR; + pVariant->scode = s.Value; + } + else + { + bIllegal = true; + } + } + else + { + createUnoObjectWrapper(rAny, pVariant); + } + break; + } + case TypeClass_SEQUENCE: // sequence ??? SafeArray descriptor + { + SAFEARRAY* pArray = createUnoSequenceWrapper(rAny); + if (pArray) + { + V_VT(pVariant) = VT_ARRAY | VT_VARIANT; + V_ARRAY(pVariant) = pArray; + } + else + { + bIllegal = true; + } + break; + } + case TypeClass_VOID: + { + HRESULT hr = S_OK; + if (FAILED(hr = VariantClear(pVariant))) + { + throw BridgeRuntimeError( + OUSTR("[automation bridge]UnoConversionUtilities<T>::anyToVariant\n" + "VariantClear failed with error:") + OUString::valueOf(hr)); + } + break; + } + case TypeClass_BOOLEAN: + { + sal_Bool value; + if (rAny >>= value) + { + pVariant->vt = VT_BOOL; + pVariant->boolVal = value == sal_True? VARIANT_TRUE: VARIANT_FALSE; + } + else + { + bIllegal = true; + } + break; + } + case TypeClass_CHAR: + { + // Because VT_UI2 does not conform to oleautomation we convert into VT_I2 instead + sal_uInt16 value = *(sal_Unicode*) rAny.getValue(); + pVariant->vt = VT_I2; + pVariant->iVal = value; + break; + } + case TypeClass_STRING: + { + OUString value; + if (rAny >>= value) + { + pVariant->vt = VT_BSTR; + pVariant->bstrVal = SysAllocString(reinterpret_cast<LPCOLESTR>(value.getStr())); + } + else + { + bIllegal = true; + } + break; + } + case TypeClass_FLOAT: + { + float value; + if (rAny >>= value) + { + pVariant->vt = VT_R4; + pVariant->fltVal = value; + } + else + { + bIllegal = true; + } + break; + } + case TypeClass_DOUBLE: + { + double value; + if (rAny >>= value) + { + pVariant->vt = VT_R8; + pVariant->dblVal = value; + } + else + { + bIllegal = true; + } + break; + } + case TypeClass_BYTE: + { + // ole automation does not know a signed char but only unsigned char + sal_Int8 value; + if (rAny >>= value) + { + pVariant->vt = VT_UI1; + pVariant->bVal = value; + } + else + { + bIllegal = true; + } + break; + } + case TypeClass_SHORT: // INT16 + case TypeClass_UNSIGNED_SHORT: // UINT16 + { + sal_Int16 value; + if (rAny >>= value) + { + pVariant->vt = VT_I2; + pVariant->iVal = value; + } + else + { + bIllegal = true; + } + break; + } + case TypeClass_ENUM: + { + sal_Int32 value = *(sal_Int32*) rAny.getValue(); + pVariant->vt = VT_I4; + pVariant->lVal= value; + break; + } + case TypeClass_LONG: + case TypeClass_UNSIGNED_LONG: + { + sal_Int32 value; + if (rAny >>= value) + { + pVariant->vt = VT_I4; + pVariant->lVal= value; + } + else + { + bIllegal = true; + } + break; + } + case TypeClass_HYPER: + { + + pVariant->vt = VT_DECIMAL; + pVariant->decVal.scale = 0; + pVariant->decVal.sign = 0; + pVariant->decVal.Hi32 = 0; + + sal_Int64 value; + rAny >>= value; + + if (value & SAL_CONST_UINT64(0x8000000000000000)) + pVariant->decVal.sign = DECIMAL_NEG; + + pVariant->decVal.Lo64 = value; + break; + } + case TypeClass_UNSIGNED_HYPER: + { + pVariant->vt = VT_DECIMAL; + pVariant->decVal.scale = 0; + pVariant->decVal.sign = 0; + pVariant->decVal.Hi32 = 0; + + sal_uInt64 value; + rAny >>= value; + pVariant->decVal.Lo64 = value; + break; + } + case TypeClass_TYPE: + { + Type type; + rAny >>= type; + CComVariant var; + if (createUnoTypeWrapper(type.getTypeName(), & var) == false) + throw BridgeRuntimeError( + OUSTR("[automation bridge] UnoConversionUtilities<T>::anyToVariant \n" + "Error during conversion of UNO type to Automation object!")); + + if (FAILED(VariantCopy(pVariant, &var))) + throw BridgeRuntimeError( + OUSTR("[automation bridge] UnoConversionUtilities<T>::anyToVariant \n" + "Unexpected error!")); + break; + } + default: + //TypeClass_SERVICE: + //TypeClass_EXCEPTION: + //When a InvocationTargetException is thrown when calling XInvocation::invoke + //on a UNO object, then the target exception is directly used to create a + //EXEPINFO structure + //TypeClass_TYPEDEF + //TypeClass_ANY: + //TypeClass_UNKNOWN: + //TypeClass_UNSIGNED_OCTET: + // TypeClass_UNION: + // TypeClass_ARRAY: + // TypeClass_UNSIGNED_INT: + // TypeClass_UNSIGNED_BYTE: + // TypeClass_MODULE: + throw CannotConvertException( + OUSTR("[automation bridge]UnoConversionUtilities<T>::anyToVariant\n" + "There is no conversion for this UNO type to a Automation type." + "The destination type class is the type class of the UNO " + "argument which was to be converted."), + Reference<XInterface>(), rAny.getValueTypeClass(), + FailReason::TYPE_NOT_SUPPORTED, 0); + + break; + } + if (bIllegal) + { + throw IllegalArgumentException( + OUSTR("[automation bridge]UnoConversionUtilities<T>::anyToVariant\n" + "The provided any of type\" ") + rAny.getValueType().getTypeName() + + OUSTR("\" is unappropriate for conversion!"), Reference<XInterface>(), -1); + + } + } + catch (CannotConvertException & ) + { + throw; + } + catch (IllegalArgumentException & ) + { + throw; + } + catch(BridgeRuntimeError&) + { + throw; + } + catch(Exception & e) + { + throw BridgeRuntimeError( + OUSTR("[automation bridge]UnoConversionUtilities<T>::anyToVariant \n" + "Unexpected exception occurred. Message: ") + e.Message); + } + catch(...) + { + throw BridgeRuntimeError( + OUSTR("[automation bridge]UnoConversionUtilities<T>::anyToVariant \n" + "Unexpected exception occurred. ") ); + } +} + +// Creates an SAFEARRAY of the specified element and if necessary +// creates a SAFEARRAY whith multiple dimensions. +// Used by sal_Bool anyToVariant(VARIANT* pVariant, const Any& rAny, VARTYPE type); +template<class T> +SAFEARRAY* UnoConversionUtilities<T>::createUnoSequenceWrapper(const Any& rSeq, VARTYPE elemtype) +{ + if (rSeq.getValueTypeClass() != TypeClass_SEQUENCE) + throw IllegalArgumentException( + OUSTR("[automation bridge]UnoConversionUtilities<T>::createUnoSequenceWrapper \n" + "The any does not contain a sequence!"), 0, 0); + if (elemtype == VT_NULL || elemtype == VT_EMPTY) + throw IllegalArgumentException( + OUSTR("[automation bridge]UnoConversionUtilities<T>::createUnoSequenceWrapper \n" + "No element type supplied!"),0, -1); + SAFEARRAY* pArray= NULL; + // Get the dimensions. This is done by examining the type name string + // The count of brackets determines the dimensions. + OUString sTypeName= rSeq.getValueType().getTypeName(); + sal_Int32 dims=0; + for(sal_Int32 lastIndex=0;(lastIndex= sTypeName.indexOf( L'[', lastIndex)) != -1; lastIndex++,dims++); + + //get the maximum number of elements per dimensions and the typedescription of the elements + Sequence<sal_Int32> seqElementCounts( dims); + TypeDescription elementTypeDesc; + getElementCountAndTypeOfSequence( rSeq, 1, seqElementCounts, elementTypeDesc ); + + if( elementTypeDesc.is() ) + { + // set up the SAFEARRAY + scoped_array<SAFEARRAYBOUND> sarSafeArrayBound(new SAFEARRAYBOUND[dims]); + SAFEARRAYBOUND* prgsabound= sarSafeArrayBound.get(); + for( sal_Int32 i=0; i < dims; i++) + { + //prgsabound[0] is the right most dimension + prgsabound[dims - i - 1].lLbound = 0; + prgsabound[dims - i - 1].cElements = seqElementCounts[i]; + } + + typelib_TypeDescription* rawTypeDesc= elementTypeDesc.get(); + sal_Int32 elementSize= rawTypeDesc->nSize; + size_t oleElementSize= getOleElementSize( elemtype); + // SafeArrayCreate clears the memory for the data itself. + pArray = SafeArrayCreate(elemtype, dims, prgsabound); + + // convert the Sequence's elements and populate the SAFEARRAY + if( pArray) + { + // Iterate over every Sequence that contains the actual elements + void* pSAData; + if( SUCCEEDED( SafeArrayAccessData( pArray, &pSAData))) + { + const sal_Int32* parElementCount= seqElementCounts.getConstArray(); + uno_Sequence * pMultiSeq= *(uno_Sequence* const*) rSeq.getValue(); + sal_Int32 dimsSeq= dims - 1; + + // arDimSeqIndizes contains the current index of a block of data. + // E.g. Sequence<Sequence<sal_Int32>> , the index would refer to Sequence<sal_Int32> + // In this case arDimSeqIndices would have the size 1. That is the elements are not counted + // but the Sequences that contain those elements. + // The indices ar 0 based + scoped_array<sal_Int32> sarDimsSeqIndices; + sal_Int32* arDimsSeqIndices= NULL; + if( dimsSeq > 0) + { + sarDimsSeqIndices.reset(new sal_Int32[dimsSeq]); + arDimsSeqIndices = sarDimsSeqIndices.get(); + memset( arDimsSeqIndices, 0, sizeof( sal_Int32 ) * dimsSeq); + } + + char* psaCurrentData= (char*)pSAData; + + do + { + // Get the Sequence at the current index , see arDimsSeqIndices + uno_Sequence * pCurrentSeq= pMultiSeq; + sal_Int32 curDim=1; // 1 based + sal_Bool skipSeq= sal_False; + while( curDim <= dimsSeq ) + { + // get the Sequence at the index if valid + if( pCurrentSeq->nElements > arDimsSeqIndices[ curDim - 1] ) // don't point to Nirvana + { + // size of Sequence is 4 + sal_Int32 offset= arDimsSeqIndices[ curDim - 1] * 4; + pCurrentSeq= *(uno_Sequence**) &pCurrentSeq->elements[ offset]; + curDim++; + } + else + { + // There is no Sequence at this index, so skip this index + skipSeq= sal_True; + break; + } + } + + if( skipSeq) + continue; + + // Calculate the current position within the datablock of the SAFEARRAY + // for the next Sequence. + sal_Int32 memOffset= 0; + sal_Int32 dimWeight= parElementCount[ dims - 1]; // size of the rightmost dimension + for(sal_Int16 idims=0; idims < dimsSeq; idims++ ) + { + memOffset+= arDimsSeqIndices[dimsSeq - 1 - idims] * dimWeight; + // now determine the weight of the dimension to the left of the current. + if( dims - 2 - idims >=0) + dimWeight*= parElementCount[dims - 2 - idims]; + } + psaCurrentData= (char*)pSAData + memOffset * oleElementSize; + // convert the Sequence and put the elements into the Safearray + for( sal_Int32 i= 0; i < pCurrentSeq->nElements; i++) + { + Any unoElement( pCurrentSeq->elements + i * elementSize, rawTypeDesc ); + // The any is being converted into an VARIANT which value is then copied + // to the SAFEARRAY's data block. When copying one has to follow the rules for + // copying certain types, as are VT_DISPATCH, VT_UNKNOWN, VT_VARIANT, VT_BSTR. + // To increase performance, we just do a memcpy of VARIANT::byref. This is possible + // because anyToVariant has already followed the copying rules. To make this + // work there must not be a VariantClear. + // One Exception is VARIANT because I don't know how VariantCopy works. + + VARIANT var; + VariantInit( &var); + anyToVariant( &var, unoElement); + if( elemtype == VT_VARIANT ) + { + VariantCopy( ( VARIANT*)psaCurrentData, &var); + VariantClear( &var); + } + else + memcpy( psaCurrentData, &var.byref, oleElementSize); + + psaCurrentData+= oleElementSize; + } + } + while( incrementMultidimensionalIndex( dimsSeq, parElementCount, arDimsSeqIndices)); + + SafeArrayUnaccessData( pArray); + } + } + } + return pArray; +} + +// Increments a multi dimensional index. +// Returns true as long as the index has been successfully incremented, false otherwise. +// False is also returned if an overflow of the most significant dimension occurs. E.g. +// assume an array with the dimensions (2,2), then the lowest index is (0,0) and the highest +// index is (1,1). If the function is being called with the index (1,1) then the overflow would +// occur, with the result (0,0) and a sal_False as return value. +// Param dimensions - number of dimensions +// Param parDimensionsLength - The array contains the size of each dimension, that is the +// size of the array equals the parameter dimensions. +// The rightmost dimensions is the least significant one +// ( parDimensionsLengths[ dimensions -1 ] ). +// Param parMultiDimensionalIndex - The array contains the index. Each dimension index is +// 0 based. +template<class T> +sal_Bool UnoConversionUtilities<T>::incrementMultidimensionalIndex(sal_Int32 dimensions, + const sal_Int32 * parDimensionLengths, + sal_Int32 * parMultidimensionalIndex) +{ + if( dimensions < 1) + return sal_False; + + sal_Bool ret= sal_True; + sal_Bool carry= sal_True; // to get into the while loop + + sal_Int32 currentDimension= dimensions; //most significant is 1 + while( carry) + { + parMultidimensionalIndex[ currentDimension - 1]++; + // if carryover, set index to 0 and handle carry on a level above + if( parMultidimensionalIndex[ currentDimension - 1] > (parDimensionLengths[ currentDimension - 1] - 1)) + parMultidimensionalIndex[ currentDimension - 1]= 0; + else + carry= sal_False; + + currentDimension --; + // if dimensions drops below 1 and carry is set than then all indices are 0 again + // this is signalled by returning sal_False + if( currentDimension < 1 && carry) + { + carry= sal_False; + ret= sal_False; + } + } + return ret; +} + +// Determines the size of a certain OLE type. The function takes +// only those types into account which are oleautomation types and +// can have a value ( unless VT_NULL, VT_EMPTY, VT_ARRAY, VT_BYREF). +// Currently used in createUnoSequenceWrapper to calculate addresses +// for data within a SAFEARRAY. +template<class T> +size_t UnoConversionUtilities<T>::getOleElementSize( VARTYPE type) +{ + size_t size; + switch( type) + { + case VT_BOOL: size= sizeof( VARIANT_BOOL);break; + case VT_UI1: size= sizeof( unsigned char);break; + case VT_R8: size= sizeof( double);break; + case VT_R4: size= sizeof( float);break; + case VT_I2: size= sizeof( short);break; + case VT_I4: size= sizeof( long);break; + case VT_BSTR: size= sizeof( BSTR); break; + case VT_ERROR: size= sizeof( SCODE); break; + case VT_DISPATCH: + case VT_UNKNOWN: size= sizeof( IUnknown*); break; + case VT_VARIANT: size= sizeof( VARIANT);break; + default: size= 0; + } + return size; +} + +//If a Sequence is being converted into a SAFEARRAY then we possibly have +// to create a SAFEARRAY with multiple dimensions. This is the case when a +// Sequence contains Sequences ( Sequence< Sequence < XXX > > ). The leftmost +// Sequence in the declaration is assumed to represent dimension 1. Because +// all Sequence elements of a Sequence can have different length, we have to +// determine the maximum length which is then the length of the respective +// dimension. +// getElementCountAndTypeOfSequence determines the length of each dimension and calls itself recursively +// in the process. +// param rSeq - an Any that has to contain a Sequence +// param dim - the dimension for which the number of elements is being determined, +// must be one. +// param seqElementCounts - countains the maximum number of elements for each +// dimension. Index 0 contains the number of dimension one. +// After return the Sequence contains the maximum number of +// elements for each dimension. +// The length of the Sequence must equal the number of dimensions. +// param typeClass - TypeClass of the element type that is no Sequence, e.g. +// Sequence< Sequence <Sequence <sal_Int32> > > - type is sal_Int32) +template<class T> +void UnoConversionUtilities<T>::getElementCountAndTypeOfSequence( const Any& rSeq, sal_Int32 dim, + Sequence< sal_Int32 >& seqElementCounts, TypeDescription& typeDesc) +{ + sal_Int32 dimCount= (*(uno_Sequence* const *) rSeq.getValue())->nElements; + if( dimCount > seqElementCounts[ dim-1]) + seqElementCounts[ dim-1]= dimCount; + + // we need the element type to construct the any that is + // passed into getElementCountAndTypeOfSequence again + typelib_TypeDescription* pSeqDesc= NULL; + rSeq.getValueTypeDescription( &pSeqDesc); + typelib_TypeDescriptionReference* pElementDescRef= ((typelib_IndirectTypeDescription*)pSeqDesc)->pType; + + // if the elements are Sequences than do recursion + if( dim < seqElementCounts.getLength() ) + { + uno_Sequence* pSeq = *(uno_Sequence* const*) rSeq.getValue(); + uno_Sequence** arSequences= (uno_Sequence**)pSeq->elements; + for( sal_Int32 i=0; i < dimCount; i++) + { + uno_Sequence* arElement= arSequences[ i]; + getElementCountAndTypeOfSequence( Any( &arElement, pElementDescRef), dim + 1 , seqElementCounts, typeDesc); + } + } + else + { + // determine the element type ( e.g. Sequence< Sequence <Sequence <sal_Int32> > > - type is sal_Int32) + typeDesc= pElementDescRef; + } + typelib_typedescription_release( pSeqDesc); +} + + +template<class T> +SAFEARRAY* UnoConversionUtilities<T>::createUnoSequenceWrapper(const Any& rSeq) +{ + SAFEARRAY* pArray = NULL; + sal_uInt32 n = 0; + + if( rSeq.getValueTypeClass() != TypeClass_SEQUENCE ) + throw IllegalArgumentException( + OUSTR("[automation bridge]UnoConversionUtilities<T>::createUnoSequenceWrapper\n" + "The UNO argument is not a sequence"), 0, -1); + + uno_Sequence * punoSeq= *(uno_Sequence**) rSeq.getValue(); + + typelib_TypeDescriptionReference* pSeqTypeRef= rSeq.getValueTypeRef(); + typelib_TypeDescription* pSeqType= NULL; + TYPELIB_DANGER_GET( &pSeqType, pSeqTypeRef); + typelib_IndirectTypeDescription * pSeqIndDec= (typelib_IndirectTypeDescription*) pSeqType; + + + typelib_TypeDescriptionReference * pSeqElementTypeRef= pSeqIndDec->pType; + TYPELIB_DANGER_RELEASE( pSeqType); + + typelib_TypeDescription* pSeqElementDesc= NULL; + TYPELIB_DANGER_GET( &pSeqElementDesc, pSeqElementTypeRef); + + // try to find VARIANT type that is related to the UNO type of the sequence elements + // the sequence as a sequence element should be handled in a special way + VARTYPE eTargetElementType = VT_EMPTY; + if ( pSeqElementDesc->eTypeClass != TypeClass_SEQUENCE ) + eTargetElementType = mapTypeClassToVartype( static_cast< TypeClass >( pSeqElementDesc->eTypeClass ) ); + + if ( eTargetElementType != VT_EMPTY ) + pArray = createUnoSequenceWrapper( rSeq, eTargetElementType ); + + if ( !pArray ) + { + sal_Int32 nElementSize= pSeqElementDesc->nSize; + n= punoSeq->nElements; + + SAFEARRAYBOUND rgsabound[1]; + rgsabound[0].lLbound = 0; + rgsabound[0].cElements = n; + VARIANT oleElement; + long safeI[1]; + + pArray = SafeArrayCreate(VT_VARIANT, 1, rgsabound); + + Any unoElement; + // sal_uInt8 * pSeqData= (sal_uInt8*) punoSeq->pElements; + sal_uInt8 * pSeqData= (sal_uInt8*) punoSeq->elements; + + for (sal_uInt32 i = 0; i < n; i++) + { + unoElement.setValue( pSeqData + i * nElementSize, pSeqElementDesc); + VariantInit(&oleElement); + + anyToVariant(&oleElement, unoElement); + + safeI[0] = i; + SafeArrayPutElement(pArray, safeI, &oleElement); + + VariantClear(&oleElement); + } + } + + TYPELIB_DANGER_RELEASE( pSeqElementDesc); + + return pArray; +} + +/* The argument rObj can contain +- UNO struct +- UNO interface +- UNO interface created by this bridge (adapter factory) +- UNO interface created by this bridge ( COM Wrapper) + +pVar must be initialized. +*/ +template<class T> +void UnoConversionUtilities<T>::createUnoObjectWrapper(const Any & rObj, VARIANT * pVar) +{ + MutexGuard guard(getBridgeMutex()); + + Reference<XInterface> xInt; + + TypeClass tc = rObj.getValueTypeClass(); + if (tc != TypeClass_INTERFACE && tc != TypeClass_STRUCT) + throw IllegalArgumentException( + OUSTR("[automation bridge]UnoConversionUtilities<T>::createUnoObjectWrapper \n" + "Cannot create an Automation interface for a UNO type which is not " + "a struct or interface!"), 0, -1); + + if (rObj.getValueTypeClass() == TypeClass_INTERFACE) + { + if (! (rObj >>= xInt)) + throw IllegalArgumentException( + OUSTR("[automation bridge] UnoConversionUtilities<T>::createUnoObjectWrapper\n " + "Could not create wrapper object for UNO object!"), 0, -1); + //If XInterface is NULL, which is a valid value, then simply return NULL. + if ( ! xInt.is()) + { + pVar->vt = VT_UNKNOWN; + pVar->punkVal = NULL; + return; + } + //make sure we have the main XInterface which is used with a map + xInt = Reference<XInterface>(xInt, UNO_QUERY); + //If there is already a wrapper for the UNO object then use it + + Reference<XInterface> xIntWrapper; + // Does a UNO wrapper exist already ? + IT_Uno it_uno = UnoObjToWrapperMap.find( (sal_uInt32) xInt.get()); + if(it_uno != UnoObjToWrapperMap.end()) + { + xIntWrapper = it_uno->second; + if (xIntWrapper.is()) + { + convertSelfToCom(xIntWrapper, pVar); + return; + } + } + // Is the object a COM wrapper ( either XInvocation, or Adapter object) + // or does it suppy an IDispatch by its own ? + else + { + Reference<XInterface> xIntComWrapper = xInt; + typedef hash_map<sal_uInt32,sal_uInt32>::iterator _IT; + // Adapter? then get the COM wrapper to which the adapter delegates its calls + _IT it= AdapterToWrapperMap.find( (sal_uInt32) xInt.get()); + if( it != AdapterToWrapperMap.end() ) + xIntComWrapper= reinterpret_cast<XInterface*>(it->second); + + if (convertSelfToCom(xIntComWrapper, pVar)) + return; + } + } + // If we have no UNO wrapper nor the IDispatch yet then we have to create + // a wrapper. For that we need an XInvocation from the UNO object. + + // get an XInvocation or create one using the invocation service + Reference<XInvocation> xInv(xInt, UNO_QUERY); + if ( ! xInv.is()) + { + Reference<XSingleServiceFactory> xInvFactory= getInvocationFactory(rObj); + if (xInvFactory.is()) + { + Sequence<Any> params(1); + params.getArray()[0] = rObj; + Reference<XInterface> xInt = xInvFactory->createInstanceWithArguments(params); + xInv= Reference<XInvocation>(xInt, UNO_QUERY); + } + } + + if (xInv.is()) + { + Reference<XInterface> xNewWrapper = createUnoWrapperInstance(); + Reference<XInitialization> xInitWrapper(xNewWrapper, UNO_QUERY); + if (xInitWrapper.is()) + { + VARTYPE vartype= getVarType( rObj); + + if (xInt.is()) + { + Any params[3]; + params[0] <<= xInv; + params[1] <<= xInt; + params[2] <<= vartype; + xInitWrapper->initialize( Sequence<Any>(params, 3)); + } + else + { + Any params[2]; + params[0] <<= xInv; + params[1] <<= vartype; + xInitWrapper->initialize( Sequence<Any>(params, 2)); + } + + // put the newly created object into a map. If the same object will + // be mapped again and there is already a wrapper then the old wrapper + // will be used. + if(xInt.is()) // only interfaces + UnoObjToWrapperMap[(sal_uInt32) xInt.get()]= xNewWrapper; + convertSelfToCom(xNewWrapper, pVar); + return; + } + } +} + +template<class T> +void UnoConversionUtilities<T>::variantToAny( const VARIANT* pVariant, Any& rAny, + sal_Bool bReduceValueRange /* = sal_True */) +{ + HRESULT hr = S_OK; + try + { + CComVariant var; + + // There is no need to support indirect values, since they're not supported by UNO + if( FAILED(hr= VariantCopyInd( &var, const_cast<VARIANTARG*>(pVariant)))) // remove VT_BYREF + throw BridgeRuntimeError( + OUSTR("[automation bridge] UnoConversionUtilities<T>::variantToAny \n" + "VariantCopyInd failed for reason : ") + OUString::valueOf(hr)); + + if ( ! convertValueObject( & var, rAny)) + { + if ((var.vt & VT_ARRAY) > 0) + { + VARTYPE oleTypeFlags = ::sal::static_int_cast< VARTYPE, int >( var.vt ^ VT_ARRAY ); + + Sequence<Any> unoSeq = createOleArrayWrapper(var.parray, oleTypeFlags); + rAny.setValue( &unoSeq, getCppuType( &unoSeq)); + } + else + { + switch (var.vt) + { + case VT_EMPTY: + rAny.setValue(NULL, Type()); + break; + case VT_NULL: + rAny.setValue(NULL, Type()); + break; + case VT_I2: + rAny.setValue( & var.iVal, getCppuType( (sal_Int16*)0)); + break; + case VT_I4: + rAny.setValue( & var.lVal, getCppuType( (sal_Int32*)0)); + // necessary for use in JavaScript ( see "reduceRange") + if( bReduceValueRange) + reduceRange(rAny); + break; + case VT_R4: + rAny.setValue( & var.fltVal, getCppuType( (float*)0)); + break; + case VT_R8: + rAny.setValue(& var.dblVal, getCppuType( (double*)0)); + break; + case VT_CY: + { + Currency cy(var.cyVal.int64); + rAny <<= cy; + break; + } + case VT_DATE: + { + Date d(var.date); + rAny <<= d; + break; + } + case VT_BSTR: + { + OUString b(reinterpret_cast<const sal_Unicode*>(var.bstrVal)); + rAny.setValue( &b, getCppuType( &b)); + break; + } + case VT_UNKNOWN: + case VT_DISPATCH: + { + //check if it is a UNO type +#ifdef __MINGW32__ + CComQIPtr<IUnoTypeWrapper, &__uuidof(IUnoTypeWrapper)> spType((IUnknown*) var.byref); +#else + CComQIPtr<IUnoTypeWrapper> spType((IUnknown*) var.byref); +#endif + if (spType) + { + CComBSTR sName; + if (FAILED(spType->get_Name(&sName))) + throw BridgeRuntimeError( + OUSTR("[automation bridge]UnoConversionUtilities<T>::variantToAny \n" + "Failed to get the type name from a UnoTypeWrapper!")); + Type type; + if (getType(sName, type) == false) + { + throw CannotConvertException( + OUSTR("[automation bridge]UnoConversionUtilities<T>::variantToAny \n" + "A UNO type with the name: ") + OUString(reinterpret_cast<const sal_Unicode*>(LPCOLESTR(sName))) + + OUSTR("does not exist!"), + 0, TypeClass_UNKNOWN, FailReason::TYPE_NOT_SUPPORTED,0); + } + rAny <<= type; + } + else + { + rAny = createOleObjectWrapper( & var); + } + break; + } + case VT_ERROR: + { + SCode scode(var.scode); + rAny <<= scode; + break; + } + case VT_BOOL: + { + sal_Bool b= var.boolVal == VARIANT_TRUE; + rAny.setValue( &b, getCppuType( &b)); + break; + } + case VT_I1: + rAny.setValue( & var.cVal, getCppuType((sal_Int8*)0)); + break; + case VT_UI1: // there is no unsigned char in UNO + rAny.setValue( & var.bVal, getCppuType( (sal_Int8*)0)); + break; + case VT_UI2: + rAny.setValue( & var.uiVal, getCppuType( (sal_uInt16*)0)); + break; + case VT_UI4: + rAny.setValue( & var.ulVal, getCppuType( (sal_uInt32*)0)); + break; + case VT_INT: + rAny.setValue( & var.intVal, getCppuType( (sal_Int32*)0)); + break; + case VT_UINT: + rAny.setValue( & var.uintVal, getCppuType( (sal_uInt32*)0)); + break; + case VT_VOID: + rAny.setValue( NULL, Type()); + break; + case VT_DECIMAL: + { + Decimal dec; + dec.Scale = var.decVal.scale; + dec.Sign = var.decVal.sign; + dec.LowValue = var.decVal.Lo32; + dec.MiddleValue = var.decVal.Mid32; + dec.HighValue = var.decVal.Hi32; + rAny <<= dec; + break; + } + + default: + break; + } + } + } + } + catch (IllegalArgumentException & ) + { + throw; + } + catch (CannotConvertException &) + { + throw; + } + catch (BridgeRuntimeError & ) + { + throw; + } + catch (Exception & e) + { + throw BridgeRuntimeError(OUSTR("[automation bridge] unexpected exception in " + "UnoConversionUtilities<T>::variantToAny ! Message : \n") + + e.Message); + } + catch(...) + { + throw BridgeRuntimeError( + OUSTR("[automation bridge] unexpected exception in " + "UnoConversionUtilities<T>::variantToAny !")); + } + +} +// The function converts an IUnknown* into an UNO interface or struct. The +// IUnknown pointer can constitute different kind of objects: +// 1. a wrapper of an UNO struct (the wrapper was created by this bridge) +// 2. a wrapper of an UNO interface (created by this bridge) +// 3. a dispatch object that implements UNO interfaces +// 4. a dispatch object. + +// If the parameter "aType" has a value then the COM object ( pUnknown) is supposed to +// implement the interface described by "aType". Moreover it ( pUnknown) can implement +// several other +// UNO interfaces in which case it has to support the SUPPORTED_INTERFACES_PROP (see +// #define) property. That property contains all names of interfaces. +// "pUnknown" is wrapped by a COM wrapper object that implements XInvocation, e.g. +// IUnknownWrapper_Impl. Additionally an object of type "aType" is created by help +// of the INTERFACE_ADAPTER_FACTORY (see #define) service. The implementation of +// "aType" calls on the COM wrapper's XInvocation::invoke. If the COM object supports +// more then one UNO interfaces, as can be determined by the property +// SUPPORTED_INTERFACES_PROP, then the INTERFACE_ADAPTER_FACTORY creates an object that +// implements all these interfaces. +// This is only done if "pUnknown" is not already a UNO wrapper, +// that is it is actually NOT an UNO object that was converted to a COM object. If it is an +// UNO wrapper than the original UNO object is being extracted, queried for "aType" (if +// it is no struct) and returned. +template<class T> +#ifdef __MINGW32__ +Any UnoConversionUtilities<T>::createOleObjectWrapper(VARIANT* pVar, const Type& aType) +#else +Any UnoConversionUtilities<T>::createOleObjectWrapper(VARIANT* pVar, const Type& aType= Type()) +#endif +{ + //To allow passing "Nothing" in VS 2008 we need to accept VT_EMPTY + if (pVar->vt != VT_UNKNOWN && pVar->vt != VT_DISPATCH && pVar->vt != VT_EMPTY) + throw IllegalArgumentException( + OUSTR("[automation bridge]UnoConversionUtilities<T>::createOleObjectWrapper \n" + "The VARIANT does not contain an object type! "), 0, -1); + + MutexGuard guard( getBridgeMutex()); + + CComPtr<IUnknown> spUnknown; + CComPtr<IDispatch> spDispatch; + + if (pVar->vt == VT_UNKNOWN) + { + spUnknown = pVar->punkVal; + if (spUnknown) +#ifdef __MINGW32__ + spUnknown->QueryInterface( IID_IDispatch, reinterpret_cast<LPVOID*>( & spDispatch.p)); +#else + spUnknown.QueryInterface( & spDispatch.p); +#endif + } + else if (pVar->vt == VT_DISPATCH && pVar->pdispVal != NULL) + { + CComPtr<IDispatch> spDispatch(pVar->pdispVal); + if (spDispatch) +#ifdef __MINGW32__ + spDispatch->QueryInterface( IID_IUnknown, reinterpret_cast<LPVOID*>( & spUnknown.p)); +#else + spDispatch.QueryInterface( & spUnknown.p); +#endif + } + + static Type VOID_TYPE= Type(); + Any ret; + //If no Type is provided and pVar contains IUnknown then we return a XInterface. + //If pVar contains an IDispatch then we return a XInvocation. + Type desiredType = aType; + + if (aType == VOID_TYPE) + { + switch (pVar->vt) + { + case VT_EMPTY: + case VT_UNKNOWN: + desiredType = getCppuType((Reference<XInterface>*) 0); + break; + case VT_DISPATCH: + desiredType = getCppuType((Reference<XInvocation>*) 0); + break; + default: + desiredType = aType; + } + } + + // COM pointer are NULL, no wrapper required + if (spUnknown == NULL) + { + Reference<XInterface> xInt; + if( aType.getTypeClass() == TypeClass_INTERFACE) + ret.setValue( &xInt, aType); + else if( aType.getTypeClass() == TypeClass_STRUCT) + ret.setValue( NULL, aType); + else + ret <<= xInt; + return ret; + } + + + // Check if "spUnknown" is a UNO wrapper, that is an UNO object that has been + // passed to COM. Then it supports IUnoObjectWrapper + // and we extract the original UNO object. +#ifdef __MINGW32__ + CComQIPtr<IUnoObjectWrapper, &__uuidof(IUnoObjectWrapper)> spUno( spUnknown); +#else + CComQIPtr<IUnoObjectWrapper> spUno( spUnknown); +#endif + if( spUno) + { // it is a wrapper + Reference<XInterface> xInt; + if( SUCCEEDED( spUno->getOriginalUnoObject( &xInt))) + { + ret <<= xInt; + } + else + { + Any any; + if( SUCCEEDED( spUno->getOriginalUnoStruct(&any))) + ret= any; + } + return ret; + } + + // "spUnknown" is a real COM object. + // Before we create a new wrapper object we check if there is an existing wrapper + // There can be two kinds of wrappers, those who wrap dispatch - UNO objects, and those who + // wrap ordinary dispatch objects. The dispatch-UNO objects usually are adapted to represent + // particular UNO interfaces. + Reference<XInterface> xIntWrapper; + CIT_Com cit_currWrapper= ComPtrToWrapperMap.find( reinterpret_cast<sal_uInt32>(spUnknown.p)); + if(cit_currWrapper != ComPtrToWrapperMap.end()) + xIntWrapper = cit_currWrapper->second; + if (xIntWrapper.is()) + { + //Try to find an adapter for the wrapper + //find the proper Adapter. The pointer in the WrapperToAdapterMap are valid as long as + //we get a pointer to the wrapper from ComPtrToWrapperMap, because the Adapter hold references + //to the wrapper. + CIT_Wrap it = WrapperToAdapterMap.find((sal_uInt32) xIntWrapper.get()); + if (it == WrapperToAdapterMap.end()) + { + // No adapter available. + //The COM component could be a UNO object. Then we need to provide + // a proxy that implements all interfaces + Sequence<Type> seqTypes= getImplementedInterfaces(spUnknown); + Reference<XInterface> xIntAdapter; + if (seqTypes.getLength() > 0) + { + //It is a COM UNO object + xIntAdapter = createAdapter(seqTypes, xIntWrapper); + } + else + { + // Some ordinary COM object + xIntAdapter = xIntWrapper; + } + // return the wrapper directly, return XInterface or XInvocation + ret = xIntWrapper->queryInterface(desiredType); + if ( ! ret.hasValue()) + throw IllegalArgumentException( + OUSTR("[automation bridge]UnoConversionUtilities<T>::createOleObjectWrapper \n" + "The COM object is not suitable for the UNO type: ") + + desiredType.getTypeName(), 0, -1); + } + else + { + //There is an adapter available + Reference<XInterface> xIntAdapter((XInterface*) it->second); + ret = xIntAdapter->queryInterface( desiredType); + if ( ! ret.hasValue()) + throw IllegalArgumentException( + OUSTR("[automation bridge]UnoConversionUtilities<T>::createOleObjectWrapper \n" + "The COM object is not suitable for the UNO type: ") + + desiredType.getTypeName(), 0, -1); + } + + return ret; + } + // No existing wrapper. Therefore create a new proxy. + // If the object implements UNO interfaces then get the types. + Sequence<Type> seqTypes = getImplementedInterfaces(spUnknown); + if (seqTypes.getLength() == 0 && + aType != VOID_TYPE && aType != getCppuType((Reference<XInvocation>*)0)) + { + seqTypes = Sequence<Type>( & aType, 1); + } + + //There is no existing wrapper, therefore we create one for the real COM object + Reference<XInterface> xIntNewProxy= createComWrapperInstance(); + if ( ! xIntNewProxy.is()) + throw BridgeRuntimeError( + OUSTR("[automation bridge]UnoConversionUtilities<T>::createOleObjectWrapper \n" + "Could not create proxy object for COM object!")); + + // initialize the COM wrapper + Reference<XInitialization> xInit( xIntNewProxy, UNO_QUERY); + OSL_ASSERT( xInit.is()); + + Any params[3]; +#ifdef __MINGW32__ + params[0] <<= reinterpret_cast<sal_uInt32>( spUnknown.p ); +#else + params[0] <<= (sal_uInt32) spUnknown.p; +#endif + sal_Bool bDisp = pVar->vt == VT_DISPATCH ? sal_True : sal_False; + params[1].setValue( & bDisp, getBooleanCppuType()); + params[2] <<= seqTypes; + + xInit->initialize( Sequence<Any>( params, 3)); +#ifdef __MINGW32__ + ComPtrToWrapperMap[reinterpret_cast<sal_uInt32>( spUnknown.p )]= xIntNewProxy; +#else + ComPtrToWrapperMap[reinterpret_cast<sal_uInt32>(spUnknown.p)]= xIntNewProxy; +#endif + + // we have a wrapper object + //The wrapper implements already XInvocation and XInterface. If + //param aType is void then the object is supposed to have XInvocation. + if (aType == getCppuType((Reference<XInvocation>*)0) || + (aType == VOID_TYPE && seqTypes.getLength() == 0 )) + { + ret = xIntNewProxy->queryInterface(desiredType); + } + else + { + Reference<XInterface> xIntAdapter = + createAdapter(seqTypes, xIntNewProxy); + ret = xIntAdapter->queryInterface(desiredType); + } + return ret; +} +template<class T> +Reference<XInterface> UnoConversionUtilities<T>::createAdapter(const Sequence<Type>& seqTypes, + const Reference<XInterface>& receiver) +{ + Reference< XInterface> xIntAdapterFac; + xIntAdapterFac= m_smgr->createInstance(INTERFACE_ADAPTER_FACTORY); + // We create an adapter object that does not only implement the required type but also + // all types that the COM object pretends to implement. An COM object must therefore + // support the property "_implementedInterfaces". + Reference<XInterface> xIntAdapted; + Reference<XInvocation> xInv(receiver, UNO_QUERY); + Reference<XInvocationAdapterFactory2> xAdapterFac( xIntAdapterFac, UNO_QUERY); + if( xAdapterFac.is()) + xIntAdapted= xAdapterFac->createAdapter( xInv, seqTypes); + + if( xIntAdapted.is()) + { + // Put the pointer to the wrapper object and the interface pointer of the adapted interface + // in a global map. Thus we can determine in a call to createUnoObjectWrapper whether the UNO + // object is a wrapped COM object. In that case we extract the original COM object rather than + // creating a wrapper around the UNO object. + typedef hash_map<sal_uInt32,sal_uInt32>::value_type VALUE; + AdapterToWrapperMap.insert( VALUE( (sal_uInt32) xIntAdapted.get(), (sal_uInt32) receiver.get())); + WrapperToAdapterMap.insert( VALUE( (sal_uInt32) receiver.get(), (sal_uInt32) xIntAdapted.get())); + } + else + { + throw BridgeRuntimeError( + OUSTR("[automation bridge]UnoConversionUtilities<T>::createOleObjectWrapper \n" + "Could not create a proxy for COM object! Creation of adapter failed.")); + } + return xIntAdapted; +} +// "convertValueObject" converts a JScriptValue object contained in "var" into +// an any. The type contained in the any is stipulated by a "type value" thas +// was set within the JScript script on the value object ( see JScriptValue). +template<class T> +bool UnoConversionUtilities<T>::convertValueObject( const VARIANTARG *var, Any& any) +{ + bool ret = false; + try + { + bool bFail = false; + HRESULT hr= S_OK; + CComVariant varDisp; + + if(SUCCEEDED(hr = varDisp.ChangeType( VT_DISPATCH, var))) + { + CComPtr <IJScriptValueObject> spValue; + VARIANT_BOOL varBool; + CComBSTR bstrType; + CComVariant varValue; + CComPtr<IDispatch> spDisp( varDisp.pdispVal); + if(spDisp) + { + if(SUCCEEDED( spDisp->QueryInterface( __uuidof( IJScriptValueObject), + reinterpret_cast<void**> (&spValue)))) + { + ret = true; // is is a ValueObject + //If it is an out - param then it does not need to be converted. In/out and + // in params does so. + if (SUCCEEDED(hr= spValue->IsOutParam( &varBool))) + { + // if varBool == true then no conversion needed because out param + if (varBool == VARIANT_FALSE) + { + if(SUCCEEDED(hr = spValue->GetValue( & bstrType, & varValue))) + { + Type type; + if (getType(bstrType, type)) + variantToAny( & varValue, any, type); + else + bFail = true; + } + else + bFail = true; + } + } + else + bFail = true;; + } + } + } + else if( hr != DISP_E_TYPEMISMATCH && hr != E_NOINTERFACE) + bFail = true; + + if (bFail) + throw BridgeRuntimeError( + OUSTR("[automation bridge] Conversion of ValueObject failed ")); + } + catch (BridgeRuntimeError &) + { + throw; + } + catch (Exception & e) + { + throw BridgeRuntimeError(OUSTR("[automation bridge] unexpected exception in " + "UnoConversionUtilities<T>::convertValueObject ! Message : \n") + + e.Message); + } + catch(...) + { + throw BridgeRuntimeError( + OUSTR("[automation bridge] unexpected exception in " + "UnoConversionUtilities<T>::convertValueObject !")); + } + return ret; +} + +template<class T> +void UnoConversionUtilities<T>::dispatchExObject2Sequence( const VARIANTARG* pvar, Any& anySeq, const Type& type) +{ + try + { + bool bFail = false; + if( pvar->vt != VT_DISPATCH) + throw BridgeRuntimeError(OUSTR("[automation bridge] UnoConversionUtilities<T>::dispatchExObject2Sequence \n" + "Conversion of dispatch object to Sequence failed!")); + IDispatchEx* pdispEx; + HRESULT hr; + if( FAILED( hr= pvar->pdispVal->QueryInterface( IID_IDispatchEx, + reinterpret_cast<void**>( &pdispEx)))) + throw BridgeRuntimeError(OUSTR("[automation bridge] UnoConversionUtilities<T>::dispatchExObject2Sequence \n" + "Conversion of dispatch object to Sequence failed!")); + + DISPID dispid; + OUString sindex; + DISPPARAMS param= {0,0,0,0}; + CComVariant result; + + OLECHAR* sLength= L"length"; + + // Get the length of the array. Can also be obtained throu GetNextDispID. The + // method only returns DISPIDs of the array data. Their names are like "0", "1" etc. + if( FAILED( hr= pdispEx->GetIDsOfNames(IID_NULL, &sLength , 1, LOCALE_USER_DEFAULT, &dispid))) + throw BridgeRuntimeError(OUSTR("[automation bridge] UnoConversionUtilities<T>::dispatchExObject2Sequence \n" + "Conversion of dispatch object to Sequence failed!")); + if( FAILED( hr= pdispEx->InvokeEx(dispid, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET, + ¶m, &result, NULL, NULL))) + throw BridgeRuntimeError(OUSTR("[automation bridge] UnoConversionUtilities<T>::dispatchExObject2Sequence \n" + "Conversion of dispatch object to Sequence failed!")); + if( FAILED( VariantChangeType( &result, &result, 0, VT_I4))) + throw BridgeRuntimeError(OUSTR("[automation bridge] UnoConversionUtilities<T>::dispatchExObject2Sequence \n" + "Conversion of dispatch object to Sequence failed!")); + long length= result.lVal; + + result.Clear(); + + // get a few basic facts about the sequence, and reallocate: + // create the Sequences + // get the size of the elements + typelib_TypeDescription *pDesc= NULL; + type.getDescription( &pDesc); + + typelib_IndirectTypeDescription *pSeqDesc= reinterpret_cast<typelib_IndirectTypeDescription*>(pDesc); + typelib_TypeDescriptionReference *pSeqElemDescRef= pSeqDesc->pType; // type of the Sequence' elements + Type elemType( pSeqElemDescRef); + _typelib_TypeDescription* pSeqElemDesc=NULL; + TYPELIB_DANGER_GET( &pSeqElemDesc, pSeqElemDescRef) + sal_uInt32 nelementSize= pSeqElemDesc->nSize; + TYPELIB_DANGER_RELEASE( pSeqElemDesc) + + uno_Sequence *p_uno_Seq; + uno_sequence_construct( &p_uno_Seq, pDesc, NULL, length, cpp_acquire); + + typelib_TypeClass typeElement= pSeqDesc->pType->eTypeClass; + char *pArray= p_uno_Seq->elements; + + // Get All properties in the object, convert their values to the expected type and + // put them into the passed in sequence + for( sal_Int32 i= 0; i< length; i++) + { + OUString ousIndex=OUString::valueOf( i); + OLECHAR* sindex = (OLECHAR*)ousIndex.getStr(); + + if( FAILED( hr= pdispEx->GetIDsOfNames(IID_NULL, &sindex , 1, LOCALE_USER_DEFAULT, &dispid))) + { + throw BridgeRuntimeError(OUSTR("[automation bridge] UnoConversionUtilities<T>::dispatchExObject2Sequence \n" + "Conversion of dispatch object to Sequence failed!")); + } + if( FAILED( hr= pdispEx->InvokeEx(dispid, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET, + ¶m, &result, NULL, NULL))) + { + throw BridgeRuntimeError(OUSTR("[automation bridge] UnoConversionUtilities<T>::dispatchExObject2Sequence \n" + "Conversion of dispatch object to Sequence failed!")); + } + + // If the result is VT_DISPATCH than the Sequence's element type could be Sequence + // Look that up in the CoreReflection to make clear. + // That requires a recursiv conversion + Any any; + // Destination address within the out-Sequence "anySeq" where to copy the next converted element + void* pDest= (void*)(pArray + (i * nelementSize)); + + if( result.vt & VT_DISPATCH && typeElement == typelib_TypeClass_SEQUENCE) + { + variantToAny( &result, any, elemType, sal_False); + // copy the converted VARIANT, that is a Sequence to the Sequence + uno_Sequence * p_unoSeq= *(uno_Sequence**)any.getValue(); + // just copy the pointer of the uno_Sequence + // nelementSize should be 4 !!!! + memcpy( pDest, &p_unoSeq, nelementSize); + osl_incrementInterlockedCount( &p_unoSeq->nRefCount); + } + else // Element type is no Sequence -> do one conversion + { + variantToAny( &result, any, elemType, sal_False); + if( typeElement == typelib_TypeClass_ANY) + { + // copy the converted VARIANT to the Sequence + uno_type_assignData( pDest, pSeqElemDescRef , &any, pSeqElemDescRef,cpp_queryInterface, + cpp_acquire, cpp_release); + } + else + { + // type after conversion must be the element type of the sequence + OSL_ENSURE( (any.getValueTypeClass() == typeElement), "wrong conversion"); + uno_type_assignData( pDest, pSeqElemDescRef,const_cast<void*>( any.getValue()), any.getValueTypeRef(), + cpp_queryInterface, cpp_acquire, cpp_release); + } + } + } // else + result.Clear(); + anySeq.setValue( &p_uno_Seq, pDesc); + uno_destructData( &p_uno_Seq, pDesc, cpp_release); + typelib_typedescription_release( pDesc); + + if (bFail) + throw BridgeRuntimeError( + OUSTR("[automation bridge] Conversion of ValueObject failed ")); + } + catch (BridgeRuntimeError & ) + { + throw; + } + catch (Exception & e) + { + throw BridgeRuntimeError(OUSTR("[automation bridge] unexpected exception in " + "UnoConversionUtilities<T>::convertValueObject ! Message : \n") + + e.Message); + } + catch(...) + { + throw BridgeRuntimeError( + OUSTR("[automation bridge] unexpected exception in " + "UnoConversionUtilities<T>::convertValueObject !")); + } +} + +/* The argument unotype is the type that is expected by the currently called UNO function. + For example: []long, [][]long. If the function calls itself recursively then the element type + is passed on. For example a two dimensional SAFEARRAY of type VT_I4 is to be converted. Then + unotype has to be either void or [][]long. When the function calls itself recursivly then + it passes the element type which is []long. +*/ +template<class T> +Sequence<Any> UnoConversionUtilities<T>::createOleArrayWrapperOfDim(SAFEARRAY* pArray, + unsigned int dimCount, unsigned int actDim, long* index, VARTYPE type, const Type& unotype) +{ + HRESULT hr= S_OK; + long lBound; + long uBound; + long nCountElements; + + SafeArrayGetLBound(pArray, actDim, &lBound); + SafeArrayGetUBound(pArray, actDim, &uBound); + nCountElements= uBound - lBound +1; + + Sequence<Any> anySeq(nCountElements); + Any* pUnoArray = anySeq.getArray(); + + for (index[actDim - 1] = lBound; index[actDim - 1] <= uBound; index[actDim - 1]++) + { + if (actDim > 1 ) + { + Sequence<Any> element = createOleArrayWrapperOfDim(pArray, dimCount, + actDim - 1, index, type, getElementTypeOfSequence(unotype)); + + pUnoArray[index[actDim - 1] - lBound].setValue(&element, getCppuType(&element)); + } + else + { + VARIANT variant; + + VariantInit(&variant); + + V_VT(&variant) = type; + + switch (type) + { + case VT_I2: + SafeArrayGetElement(pArray, index, &V_I2(&variant)); + break; + case VT_I4: + SafeArrayGetElement(pArray, index, &V_I4(&variant)); + break; + case VT_R4: + SafeArrayGetElement(pArray, index, &V_R4(&variant)); + break; + case VT_R8: + SafeArrayGetElement(pArray, index, &V_R8(&variant)); + break; + case VT_CY: + SafeArrayGetElement(pArray, index, &V_CY(&variant)); + break; + case VT_DATE: + SafeArrayGetElement(pArray, index, &V_DATE(&variant)); + break; + case VT_BSTR: + hr= SafeArrayGetElement(pArray, index, &V_BSTR(&variant)); + break; + case VT_DISPATCH: + SafeArrayGetElement(pArray, index, &V_DISPATCH(&variant)); + break; + case VT_ERROR: + SafeArrayGetElement(pArray, index, &V_ERROR(&variant)); + break; + case VT_BOOL: + SafeArrayGetElement(pArray, index, &V_BOOL(&variant)); + break; + case VT_VARIANT: + SafeArrayGetElement(pArray, index, &variant); + break; + case VT_UNKNOWN: + SafeArrayGetElement(pArray, index, &V_UNKNOWN(&variant)); + break; + case VT_I1: + SafeArrayGetElement(pArray, index, &V_I1(&variant)); + break; + case VT_UI1: + SafeArrayGetElement(pArray, index, &V_UI1(&variant)); + break; + case VT_UI2: + SafeArrayGetElement(pArray, index, &V_UI2(&variant)); + break; + case VT_UI4: + SafeArrayGetElement(pArray, index, &V_UI4(&variant)); + break; + default: + break; + } + + if( unotype.getTypeClass() == TypeClass_VOID) + // the function was called without specifying the destination type + variantToAny(&variant, pUnoArray[index[actDim - 1] - lBound], sal_False); + else + variantToAny(&variant, pUnoArray[index[actDim - 1] - lBound], + getElementTypeOfSequence(unotype), sal_False); + + VariantClear(&variant); + } + } + return anySeq; +} + +template<class T> +Type UnoConversionUtilities<T>::getElementTypeOfSequence( const Type& seqType) +{ + Type retValue; + if( seqType.getTypeClass() != TypeClass_VOID) + { + OSL_ASSERT( seqType.getTypeClass() == TypeClass_SEQUENCE); + typelib_IndirectTypeDescription* pDescSeq= NULL; + seqType.getDescription((typelib_TypeDescription** ) & pDescSeq); + retValue = Type(pDescSeq->pType); + typelib_typedescription_release( (typelib_TypeDescription*) pDescSeq); + } + return retValue; +} +template<class T> +Sequence<Any> UnoConversionUtilities<T>::createOleArrayWrapper(SAFEARRAY* pArray, VARTYPE type, const Type& unoType) +{ + sal_uInt32 dim = SafeArrayGetDim(pArray); + + Sequence<Any> ret; + + if (dim > 0) + { + scoped_array<long> sarIndex(new long[dim]); + long * index = sarIndex.get(); + + for (unsigned int i = 0; i < dim; i++) + { + index[i] = 0; + } + + ret = createOleArrayWrapperOfDim(pArray, dim, dim, index, type, unoType); + } + + return ret; +} + +// If an VARIANT has the type VT_DISPATCH it can either be an JScript Array +// or some other object. This function finds out if it is such an array or +// not. Currently there's no way to make sure it's an array +// so we assume that when the object has a property "0" then it is an Array. +// An JScript has property like "0", "1", "2" etc. which represent the +// value at the corresponding index of the array +template<class T> +sal_Bool UnoConversionUtilities<T>::isJScriptArray(const VARIANT* rvar) +{ + OSL_ENSURE( rvar->vt == VT_DISPATCH, "param is not a VT_DISPATCH"); + HRESULT hr; + OLECHAR* sindex= L"0"; + DISPID id; + if ( rvar->vt == VT_DISPATCH && rvar->pdispVal ) + { + hr= rvar->pdispVal->GetIDsOfNames( IID_NULL, &sindex, 1, + LOCALE_USER_DEFAULT, &id); + + if( SUCCEEDED ( hr) ) + return sal_True; + } + + return sal_False; +} + +template<class T> +VARTYPE UnoConversionUtilities<T>::mapTypeClassToVartype( TypeClass type) +{ + VARTYPE ret; + switch( type) + { + case TypeClass_INTERFACE: ret= VT_DISPATCH; + break; + case TypeClass_STRUCT: ret= VT_DISPATCH; + break; + case TypeClass_ENUM: ret= VT_I4; + break; + case TypeClass_SEQUENCE: ret= VT_ARRAY; + break; + case TypeClass_ANY: ret= VT_VARIANT; + break; + case TypeClass_BOOLEAN: ret= VT_BOOL; + break; + case TypeClass_CHAR: ret= VT_I2; + break; + case TypeClass_STRING: ret= VT_BSTR; + break; + case TypeClass_FLOAT: ret= VT_R4; + break; + case TypeClass_DOUBLE: ret= VT_R8; + break; + case TypeClass_BYTE: ret= VT_UI1; + break; + case TypeClass_SHORT: ret= VT_I2; + break; + case TypeClass_LONG: ret= VT_I4; + break; + case TypeClass_UNSIGNED_SHORT: ret= VT_UI2; + break; + case TypeClass_UNSIGNED_LONG: ret= VT_UI4; + break; + default: + ret= VT_EMPTY; + } + return ret; +} + +template<class T> +Sequence<Type> UnoConversionUtilities<T>::getImplementedInterfaces(IUnknown* pUnk) +{ + Sequence<Type> seqTypes; + CComDispatchDriver disp( pUnk); + if( disp) + { + CComVariant var; + HRESULT hr= S_OK; + // There are two different property names possible. + if( FAILED( hr= disp.GetPropertyByName( SUPPORTED_INTERFACES_PROP, &var))) + { + hr= disp.GetPropertyByName( SUPPORTED_INTERFACES_PROP2, &var); + } + if (SUCCEEDED( hr)) + { + // we exspect an array( SafeArray or IDispatch) of Strings. + Any anyNames; + variantToAny( &var, anyNames, getCppuType( (Sequence<Any>*) 0)); + Sequence<Any> seqAny; + if( anyNames >>= seqAny) + { + seqTypes.realloc( seqAny.getLength()); + for( sal_Int32 i=0; i < seqAny.getLength(); i++) + { + OUString typeName; + seqAny[i] >>= typeName; + seqTypes[i]= Type( TypeClass_INTERFACE, typeName); + } + } + } + } + return seqTypes; +} +template<class T> +Reference<XTypeConverter> UnoConversionUtilities<T>::getTypeConverter() +{ + if ( ! m_typeConverter.is()) + { + MutexGuard guard(getBridgeMutex()); + if ( ! m_typeConverter.is()) + { + Reference<XInterface> xIntConverter = + m_smgr->createInstance(OUSTR("com.sun.star.script.Converter")); + if (xIntConverter.is()) + m_typeConverter = Reference<XTypeConverter>(xIntConverter, UNO_QUERY); + } + } + return m_typeConverter; +} + +// This function tries to the change the type of a value (contained in the Any) +// to the smallest possible that can hold the value. This is actually done only +// for types of VT_I4 (see o2u_variantToAny). The reason is the following: +// JavaScript passes integer values always as VT_I4. If there is a parameter or +// property of type any then the bridge converts the any's content according +// to "o2u_variantToAny". Because the VARTYPE is VT_I4 the value would be converted +// to TypeClass_LONG. Say the method XPropertySet::setPropertyValue( string name, any value) +// would be called on an object and the property actually is of TypeClass_SHORT. +// After conversion of the VARIANT parameter the Any would contain type +// TypeClass_LONG. Because the corereflection does not cast from long to short +// the "setPropertValue" would fail as the value has not the right type. + +// The corereflection does convert small integer types to bigger types. +// Therefore we can reduce the type if possible and avoid the above mentioned +// problem. + +// The function is not used when elements are to be converted for Sequences. + +#ifndef _REDUCE_RANGE +#define _REDUCE_RANGE +inline void reduceRange( Any& any) +{ + OSL_ASSERT( any.getValueTypeClass() == TypeClass_LONG); + + sal_Int32 value= *(sal_Int32*)any.getValue(); + if( value <= 0x7f && value >= -0x80) + {// -128 bis 127 + sal_Int8 charVal= static_cast<sal_Int8>( value); + any.setValue( &charVal, getCppuType( (sal_Int8*)0)); + } + else if( value <= 0x7fff && value >= -0x8000) + {// -32768 bis 32767 + sal_Int16 shortVal= static_cast<sal_Int16>( value); + any.setValue( &shortVal, getCppuType( (sal_Int16*)0)); + } +} +#endif + + + +} // end namespace +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/ole/unoobjw.cxx b/extensions/source/ole/unoobjw.cxx new file mode 100644 index 000000000000..9cd131487dc4 --- /dev/null +++ b/extensions/source/ole/unoobjw.cxx @@ -0,0 +1,1690 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_extensions.hxx" + +#include "ole2uno.hxx" +#include <stdio.h> +#include <tools/presys.h> +#include <olectl.h> +#include <vector> +#include <list> +#include <hash_map> +#include "comifaces.hxx" +#include <tools/postsys.h> + + +#include <osl/diagnose.h> +#include <salhelper/simplereferenceobject.hxx> +#include <tools/debug.hxx> +#include <rtl/ustring.hxx> +#include <com/sun/star/beans/MethodConcept.hpp> +#include <com/sun/star/beans/PropertyConcept.hpp> +#include <com/sun/star/script/FailReason.hpp> +#include <com/sun/star/reflection/ParamInfo.hpp> +#include <com/sun/star/beans/XExactName.hpp> +#include <com/sun/star/container/NoSuchElementException.hpp> + +#include <com/sun/star/beans/XMaterialHolder.hpp> +#include <com/sun/star/script/XInvocation2.hpp> +#include <com/sun/star/script/MemberType.hpp> +#include <com/sun/star/reflection/XIdlReflection.hpp> +#include <osl/interlck.h> +#include <com/sun/star/uno/genfunc.h> +#include <cppuhelper/implbase1.hxx> + +#include "comifaces.hxx" +#include "jscriptclasses.hxx" +#include "unotypewrapper.hxx" +#include "oleobjw.hxx" +#include "unoobjw.hxx" +#include "servprov.hxx" + +using namespace std; +using namespace rtl; +using namespace osl; +using namespace cppu; +using namespace com::sun::star::uno; +using namespace com::sun::star::beans; +using namespace com::sun::star::container; +using namespace com::sun::star::script; +using namespace com::sun::star::lang; +using namespace com::sun::star::bridge::ModelDependent; +using namespace com::sun::star::reflection; + + + +#if _MSC_VER < 1200 +extern "C" const GUID IID_IDispatchEx; +#endif + +namespace ole_adapter +{ +hash_map<sal_uInt32, WeakReference<XInterface> > UnoObjToWrapperMap; +static sal_Bool writeBackOutParameter(VARIANTARG* pDest, VARIANT* pSource); +static sal_Bool writeBackOutParameter2( VARIANTARG* pDest, VARIANT* pSource); +static HRESULT mapCannotConvertException( CannotConvertException e, unsigned int * puArgErr); + + +/* Does not throw any exceptions. + Param pInfo can be NULL. + */ +static void writeExcepinfo(EXCEPINFO * pInfo, const OUString& message) +{ + if (pInfo != NULL) + { + pInfo->wCode = UNO_2_OLE_EXCEPTIONCODE; + pInfo->bstrSource = SysAllocString(L"[automation bridge] "); + pInfo->bstrDescription = SysAllocString(reinterpret_cast<LPCOLESTR>(message.getStr())); + } +} + +/***************************************************************************** + + class implementation: InterfaceOleWrapper_Impl + +*****************************************************************************/ +InterfaceOleWrapper_Impl::InterfaceOleWrapper_Impl( Reference<XMultiServiceFactory>& xFactory, + sal_uInt8 unoWrapperClass, sal_uInt8 comWrapperClass): + m_defaultValueType( 0), + UnoConversionUtilities<InterfaceOleWrapper_Impl>( xFactory, unoWrapperClass, comWrapperClass) +{ +} + +InterfaceOleWrapper_Impl::~InterfaceOleWrapper_Impl() +{ + MutexGuard guard(getBridgeMutex()); + // remove entries in global map + IT_Uno it= UnoObjToWrapperMap.find( (sal_uInt32) m_xOrigin.get()); + if(it != UnoObjToWrapperMap.end()) + UnoObjToWrapperMap.erase(it); +#if OSL_DEBUG_LEVEL > 0 + fprintf(stderr,"[automation bridge] UnoObjToWrapperMap contains: %i \n", + UnoObjToWrapperMap.size()); +#endif + +} + +STDMETHODIMP InterfaceOleWrapper_Impl::QueryInterface(REFIID riid, LPVOID FAR * ppv) +{ + HRESULT ret= S_OK; + + if( !ppv) + return E_POINTER; + + if(IsEqualIID(riid, IID_IUnknown)) + { + AddRef(); + *ppv = (IUnknown*) (IDispatch*) this; + } + else if (IsEqualIID(riid, IID_IDispatch)) + { + AddRef(); + *ppv = (IDispatch*) this; + } + else if( IsEqualIID( riid, __uuidof( IUnoObjectWrapper))) + { + AddRef(); + *ppv= (IUnoObjectWrapper*) this; + } + else + ret= E_NOINTERFACE; + return ret; +} + +STDMETHODIMP_(ULONG) InterfaceOleWrapper_Impl::AddRef() +{ + acquire(); + // does not need to guard because one should not rely on the return value of + // AddRef anyway + return m_refCount; +} + +STDMETHODIMP_(ULONG) InterfaceOleWrapper_Impl::Release() +{ + ULONG n= m_refCount; + release(); + return n - 1; +} + +// IUnoObjectWrapper -------------------------------------------------------- +STDMETHODIMP InterfaceOleWrapper_Impl::getWrapperXInterface( Reference<XInterface>* pXInt) +{ + *pXInt= Reference<XInterface>( static_cast<XWeak*>( this), UNO_QUERY); + return pXInt->is() ? S_OK : E_FAIL; +} +STDMETHODIMP InterfaceOleWrapper_Impl::getOriginalUnoObject( Reference<XInterface>* pXInt) +{ + *pXInt= m_xOrigin; + return m_xOrigin.is() ? S_OK : E_FAIL; +} +STDMETHODIMP InterfaceOleWrapper_Impl::getOriginalUnoStruct( Any * pStruct) +{ + HRESULT ret= E_FAIL; + if( !m_xOrigin.is()) + { + Reference<XMaterialHolder> xMatHolder( m_xInvocation, UNO_QUERY); + if( xMatHolder.is()) + { + Any any = xMatHolder->getMaterial(); + if( any.getValueTypeClass() == TypeClass_STRUCT) + { + *pStruct= any; + ret= S_OK; + } + } + } + return ret; +} + +STDMETHODIMP InterfaceOleWrapper_Impl::GetTypeInfoCount( unsigned int * /*pctinfo*/ ) +{ + return E_NOTIMPL ; +} + +STDMETHODIMP InterfaceOleWrapper_Impl::GetTypeInfo(unsigned int /*itinfo*/, LCID /*lcid*/, ITypeInfo ** /*pptinfo*/) +{ + return E_NOTIMPL; +} + +STDMETHODIMP InterfaceOleWrapper_Impl::GetIDsOfNames(REFIID /*riid*/, + OLECHAR ** rgszNames, + unsigned int cNames, + LCID /*lcid*/, + DISPID * rgdispid ) +{ + HRESULT ret = DISP_E_UNKNOWNNAME; + try + { + MutexGuard guard( getBridgeMutex()); + if( ! rgdispid) + return E_POINTER; + + // ---------------------------------------- + if( ! _wcsicmp( *rgszNames, JSCRIPT_VALUE_FUNC) || + ! _wcsicmp( *rgszNames, BRIDGE_VALUE_FUNC)) + { + *rgdispid= DISPID_JSCRIPT_VALUE_FUNC; + return S_OK; + } + else if( ! _wcsicmp( *rgszNames, GET_STRUCT_FUNC) || + ! _wcsicmp( *rgszNames, BRIDGE_GET_STRUCT_FUNC)) + { + *rgdispid= DISPID_GET_STRUCT_FUNC; + return S_OK; + } + else if( ! _wcsicmp( *rgszNames, BRIDGE_CREATE_TYPE_FUNC)) + { + *rgdispid= DISPID_CREATE_TYPE_FUNC; + return S_OK; + } + + // ---------------------------------------- + if (m_xInvocation.is() && (cNames > 0)) + { + OUString name(reinterpret_cast<const sal_Unicode*>(rgszNames[0])); + NameToIdMap::iterator iter = m_nameToDispIdMap.find(name); + + if (iter == m_nameToDispIdMap.end()) + { + OUString exactName; + + if (m_xExactName.is()) + { + exactName = m_xExactName->getExactName(name); + } + else + { + exactName = name; + } + + MemberInfo d(0, exactName); + + if (m_xInvocation->hasProperty(exactName)) + { + d.flags |= DISPATCH_PROPERTYGET; + d.flags |= DISPATCH_PROPERTYPUT; + d.flags |= DISPATCH_PROPERTYPUTREF; + } + + if (m_xInvocation->hasMethod(exactName)) + { + d.flags |= DISPATCH_METHOD; + } + + if (d.flags != 0) + { + m_MemberInfos.push_back(d); + iter = m_nameToDispIdMap.insert(NameToIdMap::value_type(exactName, (DISPID)m_MemberInfos.size())).first; + + if (exactName != name) + { + iter = m_nameToDispIdMap.insert(NameToIdMap::value_type(name, (DISPID)m_MemberInfos.size())).first; + } + } + } + + if (iter == m_nameToDispIdMap.end()) + { + ret = DISP_E_UNKNOWNNAME; + } + else + { + *rgdispid = (*iter).second; + ret = S_OK; + } + } + } + catch(BridgeRuntimeError& ) + { + OSL_ASSERT(0); + } + catch(Exception& ) + { + OSL_ASSERT(0); + } + catch(...) + { + OSL_ASSERT(0); + } + + return ret; +} + +// "convertDispparamsArgs" converts VARIANTS to their respecting Any counterparts +// The parameters "id", "wFlags" and "pdispparams" equal those as used in +// IDispatch::Invoke. The function handles special JavaScript +// cases where a VARIANT of type VT_DISPATCH is ambiguous and could represent +// an object, array ( JavaScript Array object), out parameter and in/out ( JavaScript Array object) +// parameter (JavaScript Array object) +// Because all those VT_DISPATCH objects need a different conversion +// we have to find out what the object is supposed to be. The function does this +// by either using type information or by help of a specialized ValueObject object. + +// A. Type Information +// ----------------------------------------------------------------------------- +// With the help of type information the kind of parameter can be exactly determined +// and an appropriate conversion can be choosen. A problem arises if a method expects +// an Any. Then the type info does not tell what the type of the value, that is kept +// by the any, should be. In this situation the decision wheter the param is a +// sequence or an object is made upon the fact if the object has a property "0" +// ( see function "isJScriptArray"). Since this is unsafe it is recommended to use +// the JScript value objects within a JScript script on such an occasion. + +// B. JavaScript Value Object ( class JScriptValue ) +// ----------------------------------------------------------------------------- +// A JScriptValue (ValueObject) object is a COM object in that it implements IDispatch and the +// IJScriptValue object interface. Such objects are provided by all UNO wrapper +// objects used within a JScript script. To obtain an instance one has to call +// "_GetValueObject() or Bridge_GetValueObject()" on an UNO wrapper object (class InterfaceOleWrapper_Impl). +// A value object is appropriately initialized within the script and passed as +// parameter to an UNO object method or property. The convertDispparamsArgs function +// can easily find out that a param is such an object by queriing for the +// IJScriptValue interface. By this interface one the type and kind ( out, in/out) +// can be determined and the right conversion can be applied. +// Using ValueObjects we spare us the effort of aquiring and examining type information +// in order to figure out what the an IDispatch parameter is meant for. + +// Normal JScript object parameter can be mixed with JScriptValue object. If an +// VARIANT contains an VT_DISPATCH that is no JScriptValue than the type information +// is used to find out about the reqired type. +void InterfaceOleWrapper_Impl::convertDispparamsArgs(DISPID id, + unsigned short /*wFlags*/, DISPPARAMS* pdispparams, Sequence<Any>& rSeq) +{ + HRESULT hr= S_OK; + sal_Int32 countArgs= pdispparams->cArgs; + if( countArgs == 0) + return; + + rSeq.realloc( countArgs); + Any* pParams = rSeq.getArray(); + + Any anyParam; + + //Get type information for the current call + InvocationInfo info; + if( ! getInvocationInfoForCall( id, info)) + throw BridgeRuntimeError( + OUSTR("[automation bridge]InterfaceOleWrapper_Impl::convertDispparamsArgs \n" + "Could not obtain type information for current call.")); + + for (int i = 0; i < countArgs; i++) + { + if (info.eMemberType == MemberType_METHOD && + info.aParamModes[ countArgs - i -1 ] == ParamMode_OUT) + continue; + + if(convertValueObject( & pdispparams->rgvarg[i], anyParam)) + { //a param is a ValueObject and could be converted + pParams[countArgs - (i + 1)] = anyParam; + continue; + } + + // If the param is an out, in/out parameter in + // JScript (Array object, with value at index 0) then we + // extract Array[0] and put the value into varParam. At the end of the loop varParam + // is converted if it contains a value otherwise the VARIANT from + // DISPPARAMS is converted. + CComVariant varParam; + + // Check for JScript out and in/out paramsobjects (VT_DISPATCH). + // To find them out we use typeinformation of the function being called. + if( pdispparams->rgvarg[i].vt == VT_DISPATCH ) + { + if( info.eMemberType == MemberType_METHOD && info.aParamModes[ countArgs - i -1 ] == ParamMode_INOUT) + { + // INOUT-param + // Index ( property) "0" contains the actual IN-param. The object is a JScript + // Array object. + // Get the IN-param at index "0" + IDispatch* pdisp= pdispparams->rgvarg[i].pdispVal; + + OLECHAR* sindex= L"0"; + DISPID id; + DISPPARAMS noParams= {0,0,0,0}; + if(SUCCEEDED( hr= pdisp->GetIDsOfNames( IID_NULL, &sindex, 1, LOCALE_USER_DEFAULT, &id))) + hr= pdisp->Invoke( id, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET, + & noParams, & varParam, NULL, NULL); + if( FAILED( hr)) + { + throw BridgeRuntimeError( + OUSTR("[automation bridge] Could not determine " + "if the object has a member \"0\". Error: ") + + OUString::valueOf(hr)); + } + } + } + + if( varParam.vt == VT_EMPTY) // then it was no in/out parameter + varParam= pdispparams->rgvarg[i]; + + if(info.eMemberType == MemberType_METHOD) + variantToAny( & varParam, anyParam, + info.aParamTypes[ countArgs - i - 1]); + else if(info.eMemberType == MemberType_PROPERTY) + variantToAny( & varParam, anyParam, info.aType); + else + OSL_ASSERT(0); + + pParams[countArgs - (i + 1)]= anyParam; + }// end for / iterating over all parameters +} + +sal_Bool InterfaceOleWrapper_Impl::getInvocationInfoForCall( DISPID id, InvocationInfo& info) +{ + sal_Bool bTypesAvailable= sal_False; + + if( !m_xInvocation.is() )return false; + Reference<XInvocation2> inv2( m_xInvocation, UNO_QUERY); + if( inv2.is()) + { + // We need the name of the property or method to get its type information. + // The name can be identified through the param "id" + // that is kept as value in the map m_nameToDispIdMap. + // Proplem: the Windows JScript engine sometimes changes small letters to capital + // letters as happens in xidlclass_obj.createObject( var) // in JScript. + // IDispatch::GetIdsOfNames is then called with "CreateObject" !!! + // m_nameToDispIdMap can contain several names for one DISPID but only one is + // the exact one. If there's no m_xExactName and therefore no exact name then + // there's only one entry in the map. + typedef NameToIdMap::const_iterator cit; + OUString sMemberName; + + for(cit ci1= m_nameToDispIdMap.begin(); ci1 != m_nameToDispIdMap.end(); ci1++) + { + if( (*ci1).second == id) // iterator is a pair< OUString, DISPID> + { + sMemberName= (*ci1).first; + break; + } + } + // Get information for the current call ( property or method). + // There could be similar names which only differ in the cases + // of letters. First we assume that the name which was passed into + // GetIDsOfNames is correct. If we won't get information with that + // name then we have the invocation service use the XExactName interface. + sal_Bool validInfo= sal_True; + InvocationInfo invInfo; + try{ + invInfo= inv2->getInfoForName( sMemberName, sal_False); + } + catch( IllegalArgumentException ) + { + validInfo= sal_False; + } + + if( ! validInfo) + { + invInfo= inv2->getInfoForName( sMemberName, sal_True); + } + if( invInfo.aName.pData) + { + bTypesAvailable= sal_True; + info= invInfo; + } + } + return bTypesAvailable; +} +// XBridgeSupplier2 --------------------------------------------------- +// only bridges itself ( this instance of InterfaceOleWrapper_Impl)from UNO to IDispatch +// If sourceModelType is UNO than any UNO interface implemented by InterfaceOleWrapper_Impl +// can bridged to IDispatch ( if destModelType == OLE). The IDispatch is +// implemented by this class. +Any SAL_CALL InterfaceOleWrapper_Impl::createBridge(const Any& modelDepObject, + const Sequence<sal_Int8>& /*ProcessId*/, + sal_Int16 sourceModelType, + sal_Int16 destModelType) + throw (IllegalArgumentException, RuntimeException) +{ + + Any retAny; + if( sourceModelType == UNO && destModelType == OLE && + modelDepObject.getValueTypeClass() == TypeClass_INTERFACE ) + { + Reference<XInterface> xInt; + if( modelDepObject >>= xInt ) + { + if( xInt == Reference<XInterface>( static_cast<XWeak*>( this), UNO_QUERY)) + { + VARIANT *pVar= (VARIANT*)CoTaskMemAlloc( sizeof( VARIANT)); + if( pVar) + { + pVar->vt= VT_DISPATCH; + pVar->pdispVal= static_cast<IDispatch*>( this); + AddRef(); + + retAny<<= reinterpret_cast< sal_uInt32 >( pVar); + } + } + } + } + + return retAny; +} + + +// XInitialization -------------------------------------------------- +void SAL_CALL InterfaceOleWrapper_Impl::initialize( const Sequence< Any >& aArguments ) + throw(Exception, RuntimeException) +{ + switch( aArguments.getLength() ) + { + case 2: // the object wraps an UNO struct + aArguments[0] >>= m_xInvocation; + aArguments[1] >>= m_defaultValueType; + break; + case 3: // the object wraps an UNO interface + aArguments[0] >>= m_xInvocation; + aArguments[1] >>= m_xOrigin; + aArguments[2] >>= m_defaultValueType; + break; + } + + m_xExactName= Reference<XExactName>( m_xInvocation, UNO_QUERY); +} + +Reference< XInterface > InterfaceOleWrapper_Impl::createUnoWrapperInstance() +{ + Reference<XWeak> xWeak= static_cast<XWeak*>( new InterfaceOleWrapper_Impl( + m_smgr, m_nUnoWrapperClass, m_nComWrapperClass)); + return Reference<XInterface>( xWeak, UNO_QUERY); +} + +Reference<XInterface> InterfaceOleWrapper_Impl::createComWrapperInstance() +{ + Reference<XWeak> xWeak= static_cast<XWeak*>( new IUnknownWrapper_Impl( + m_smgr, m_nUnoWrapperClass, m_nComWrapperClass)); + return Reference<XInterface>( xWeak, UNO_QUERY); +} + + + +// "getType" is used in convertValueObject to map the string denoting the type +// to an actual Type object. +bool getType( const BSTR name, Type & type) +{ + Type retType; + bool ret = false; + typelib_TypeDescription * pDesc= NULL; + OUString str( reinterpret_cast<const sal_Unicode*>(name)); + typelib_typedescription_getByName( &pDesc, str.pData ); + if( pDesc) + { + type = Type( pDesc->pWeakRef ); + typelib_typedescription_release( pDesc); + ret = true; + } + return ret; +} + +static sal_Bool writeBackOutParameter2( VARIANTARG* pDest, VARIANT* pSource) +{ + sal_Bool ret = sal_False; + HRESULT hr; + + // Handle JScriptValue objects and JScript out params ( Array object ) + CComVariant varDest( *pDest); + + if( SUCCEEDED( varDest.ChangeType(VT_DISPATCH))) + { + CComPtr<IDispatch> spDispDest(varDest.pdispVal); + + // special Handling for a JScriptValue object +#ifdef __MINGW32__ + CComQIPtr<IJScriptValueObject, &__uuidof(IJScriptValueObject)> spValueDest(spDispDest); +#else + CComQIPtr<IJScriptValueObject> spValueDest(spDispDest); +#endif + if (spValueDest) + { + VARIANT_BOOL varBool= VARIANT_FALSE; + if( SUCCEEDED( hr= spValueDest->IsOutParam( &varBool) ) + && varBool == VARIANT_TRUE || + SUCCEEDED(hr= spValueDest->IsInOutParam( &varBool) ) + && varBool == VARIANT_TRUE ) + { + if( SUCCEEDED( spValueDest->Set( CComVariant(), *pSource))) + ret= sal_True; + } + } + else if (pDest->vt == VT_DISPATCH)// VT_DISPATCH -> JScript out param + { + // We use IDispatchEx because its GetDispID function causes the creation + // of a property if it does not exist already. This is convenient for + // out parameters in JScript. Then the user must not specify propery "0" + // explicitly +#ifdef __MINGW32__ + CComQIPtr<IDispatchEx, &__uuidof(IDispatchEx)> spDispEx( spDispDest); +#else + CComQIPtr<IDispatchEx> spDispEx( spDispDest); +#endif + if( spDispEx) + { + CComBSTR nullProp(L"0"); + DISPID dwDispID; + if( SUCCEEDED( spDispEx->GetDispID( nullProp, fdexNameEnsure, &dwDispID))) + { + DISPPARAMS dispparams = {NULL, NULL, 1, 1}; + dispparams.rgvarg = pSource; + DISPID dispidPut = DISPID_PROPERTYPUT; + dispparams.rgdispidNamedArgs = &dispidPut; + + if (pSource->vt == VT_UNKNOWN || pSource->vt == VT_DISPATCH || + (pSource->vt & VT_ARRAY) || (pSource->vt & VT_BYREF)) + hr = spDispEx->InvokeEx(dwDispID, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYPUTREF, + &dispparams, NULL, NULL, NULL); + else + hr= spDispEx->InvokeEx(dwDispID, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYPUT, + &dispparams, NULL, NULL, NULL); + if( SUCCEEDED(hr)) + ret= sal_True; + } + } + } + else + ret= writeBackOutParameter( pDest, pSource); + } + else // The param can't be a JScript out-parameter ( an Array object), it could be a VBScript + { // param. The function checks itself for correct VBScript params + ret= writeBackOutParameter( pDest, pSource); + } + return ret; +} +// VisualBasic Script passes arguments as VT_VARIANT | VT_BYREF be it in or out parameter. +// Thus we are in charge of freeing an eventual value contained by the inner VARIANT +// Please note: VariantCopy doesn't free a VT_BYREF value +// The out parameters are expected to have always a valid type +static sal_Bool writeBackOutParameter(VARIANTARG* pDest, VARIANT* pSource) +{ + HRESULT hr; + sal_Bool ret = FALSE; + // Out parameter must be VT_BYREF + if ((V_VT(pDest) & VT_BYREF) != 0 ) + { + VARTYPE oleTypeFlags = V_VT(pSource); + + // if caller accept VARIANT as out parameter, any value must be converted + if (V_VT(pDest) == (VT_VARIANT | VT_BYREF)) + { + // When the user provides a VARIANT rather then a concrete type + // we just copy the source to the out, in/out parameter + // VT_DISPATCH, VT_UNKNOWN, VT_ARRAY, VT_BSTR in the VARIANT that + // is contained in pDest are released by VariantCopy + VariantCopy(V_VARIANTREF(pDest), pSource); + ret = sal_True; + } + else + { + // variantarg and variant must have same type + if ((V_VT(pDest) & oleTypeFlags) == oleTypeFlags) + { + if ((oleTypeFlags & VT_ARRAY) != 0) + { + // In / Out Param + if( *V_ARRAYREF(pDest) != NULL) + hr= SafeArrayCopyData( V_ARRAY(pSource), *V_ARRAYREF(pDest)); + else + // Out Param + hr= SafeArrayCopy(V_ARRAY(pSource), V_ARRAYREF(pDest)) == NOERROR; + if( SUCCEEDED( hr)) + ret = sal_True; + } + else + { + // copy base type + switch (V_VT(pSource)) + { + case VT_I2: + { + *V_I2REF(pDest) = V_I2(pSource); + ret = sal_True; + break; + } + case VT_I4: + *V_I4REF(pDest) = V_I4(pSource); + ret = sal_True; + break; + case VT_R4: + *V_R4REF(pDest) = V_R4(pSource); + ret = sal_True; + break; + case VT_R8: + *V_R8REF(pDest) = V_R8(pSource); + ret = sal_True; + break; + case VT_CY: + *V_CYREF(pDest) = V_CY(pSource); + ret = sal_True; + break; + case VT_DATE: + *V_DATEREF(pDest) = V_DATE(pSource); + ret = sal_True; + break; + case VT_BSTR: + SysFreeString( *pDest->pbstrVal); + + *V_BSTRREF(pDest) = SysAllocString(V_BSTR(pSource)); + ret = sal_True; + break; + case VT_DISPATCH: + if (*V_DISPATCHREF(pDest) != NULL) + (*V_DISPATCHREF(pDest))->Release(); + + *V_DISPATCHREF(pDest) = V_DISPATCH(pSource); + + if (*V_DISPATCHREF(pDest) != NULL) + (*V_DISPATCHREF(pDest))->AddRef(); + + ret = sal_True; + break; + case VT_ERROR: + *V_ERRORREF(pDest) = V_ERROR(pSource); + ret = sal_True; + break; + case VT_BOOL: + *V_BOOLREF(pDest) = V_BOOL(pSource); + ret = sal_True; + break; + case VT_UNKNOWN: + if (*V_UNKNOWNREF(pDest) != NULL) + (*V_UNKNOWNREF(pDest))->Release(); + + *V_UNKNOWNREF(pDest) = V_UNKNOWN(pSource); + + if (*V_UNKNOWNREF(pDest) != NULL) + (*V_UNKNOWNREF(pDest))->AddRef(); + + ret = sal_True; + break; + case VT_I1: + *V_I1REF(pDest) = V_I1(pSource); + ret = sal_True; + break; + case VT_UI1: + *V_UI1REF(pDest) = V_UI1(pSource); + ret = sal_True; + break; + case VT_UI2: + *V_UI2REF(pDest) = V_UI2(pSource); + ret = sal_True; + break; + case VT_UI4: + *V_UI4REF(pDest) = V_UI4(pSource); + ret = sal_True; + break; + case VT_INT: + *V_INTREF(pDest) = V_INT(pSource); + ret = sal_True; + break; + case VT_UINT: + *V_UINTREF(pDest) = V_UINT(pSource); + ret = sal_True; + break; + case VT_DECIMAL: + memcpy(pDest->pdecVal, pSource, sizeof(DECIMAL)); + ret = sal_True; + break; + default: + break; + } + } + } + else + { + // Handling of special cases + // Destination and source types are different + if( pDest->vt == (VT_BSTR | VT_BYREF) + && pSource->vt == VT_I2) + { + // When the user provides a String as out our in/out parameter + // and the type is char (TypeClass_CHAR) then we convert to a BSTR + // instead of VT_I2 as is done otherwise + OLECHAR buff[]= {0,0}; + buff[0]= pSource->iVal; + + SysFreeString( *pDest->pbstrVal); + *pDest->pbstrVal= SysAllocString( buff); + ret = sal_True; + } + } + } + } + return ret; +} + +STDMETHODIMP InterfaceOleWrapper_Impl::Invoke(DISPID dispidMember, + REFIID /*riid*/, + LCID /*lcid*/, + unsigned short wFlags, + DISPPARAMS * pdispparams, + VARIANT * pvarResult, + EXCEPINFO * pexcepinfo, + unsigned int * puArgErr ) +{ + HRESULT ret = S_OK; + + try + { + sal_Bool bHandled= sal_False; + ret= InvokeGeneral( dispidMember, wFlags, pdispparams, pvarResult, pexcepinfo, + puArgErr, bHandled); + if( bHandled) + return ret; + + if ((dispidMember > 0) && ((size_t)dispidMember <= m_MemberInfos.size()) && m_xInvocation.is()) + { + MemberInfo d = m_MemberInfos[dispidMember - 1]; + DWORD flags = wFlags & d.flags; + + if (flags != 0) + { + if ((flags & DISPATCH_METHOD) != 0) + { + if (pdispparams->cNamedArgs > 0) + ret = DISP_E_NONAMEDARGS; + else + { + Sequence<Any> params; + + convertDispparamsArgs(dispidMember, wFlags, pdispparams , params ); + + ret= doInvoke(pdispparams, pvarResult, + pexcepinfo, puArgErr, d.name, params); + } + } + else if ((flags & DISPATCH_PROPERTYGET) != 0) + { + ret= doGetProperty( pdispparams, pvarResult, + pexcepinfo, d.name); + } + else if ((flags & DISPATCH_PROPERTYPUT || flags & DISPATCH_PROPERTYPUTREF) != 0) + { + if (pdispparams->cArgs != 1) + ret = DISP_E_BADPARAMCOUNT; + else + { + Sequence<Any> params; + convertDispparamsArgs(dispidMember, wFlags, pdispparams, params ); + if(params.getLength() > 0) + ret= doSetProperty( pdispparams, pvarResult, pexcepinfo, puArgErr, d.name, params); + else + ret = DISP_E_BADVARTYPE; + } + } + } + else + ret= DISP_E_MEMBERNOTFOUND; + } + else + ret = DISP_E_MEMBERNOTFOUND; + } + catch(BridgeRuntimeError& e) + { + writeExcepinfo(pexcepinfo, e.message); + ret = DISP_E_EXCEPTION; + } + catch(Exception& e) + { + OUString message= OUSTR("InterfaceOleWrapper_Impl::Invoke : \n") + + e.Message; + writeExcepinfo(pexcepinfo, message); + ret = DISP_E_EXCEPTION; + } + catch(...) + { + OUString message= OUSTR("InterfaceOleWrapper_Impl::Invoke : \n" + "Unexpected exception"); + writeExcepinfo(pexcepinfo, message); + ret = DISP_E_EXCEPTION; + } + + return ret; +} + +HRESULT InterfaceOleWrapper_Impl::doInvoke( DISPPARAMS * pdispparams, VARIANT * pvarResult, + EXCEPINFO * pexcepinfo, unsigned int * puArgErr, OUString& name, Sequence<Any>& params) +{ + + + HRESULT ret= S_OK; + try + { + Sequence<INT16> outIndex; + Sequence<Any> outParams; + Any returnValue; + + if (pdispparams->cNamedArgs > 0) + return DISP_E_NONAMEDARGS; + + // invoke method and take care of exceptions + returnValue = m_xInvocation->invoke(name, + params, + outIndex, + outParams); + + // try to write back out parameter + if (outIndex.getLength() > 0) + { + const INT16* pOutIndex = outIndex.getConstArray(); + const Any* pOutParams = outParams.getConstArray(); + + for (sal_Int32 i = 0; i < outIndex.getLength(); i++) + { + CComVariant variant; + // Currently a Sequence is converted to an SafeArray of VARIANTs. + anyToVariant( &variant, pOutParams[i]); + + // out parameter need special handling if they are VT_DISPATCH + // and used in JScript + int outindex= pOutIndex[i]; + writeBackOutParameter2(&(pdispparams->rgvarg[pdispparams->cArgs - 1 - outindex]), + &variant ); + } + } + + // write back return value + if (pvarResult != NULL) + anyToVariant(pvarResult, returnValue); + } + catch(IllegalArgumentException & e) //XInvocation::invoke + { + writeExcepinfo(pexcepinfo, e.Message); + ret = DISP_E_TYPEMISMATCH; + } + catch(CannotConvertException & e) //XInvocation::invoke + { + writeExcepinfo(pexcepinfo, e.Message); + ret = mapCannotConvertException( e, puArgErr); + } + catch(InvocationTargetException & e) //XInvocation::invoke + { + const Any& org = e.TargetException; + Exception excTarget; + org >>= excTarget; + OUString message= + org.getValueType().getTypeName() + OUSTR(": ") + excTarget.Message; + writeExcepinfo(pexcepinfo, message); + ret = DISP_E_EXCEPTION; + } + catch(NoSuchMethodException & e) //XInvocation::invoke + { + writeExcepinfo(pexcepinfo, e.Message); + ret = DISP_E_MEMBERNOTFOUND; + } + catch(BridgeRuntimeError & e) + { + writeExcepinfo(pexcepinfo, e.message); + ret = DISP_E_EXCEPTION; + } + catch(Exception & e) + { + OUString message= OUSTR("InterfaceOleWrapper_Impl::doInvoke : \n") + + e.Message; + writeExcepinfo(pexcepinfo, message); + ret = DISP_E_EXCEPTION; + } + catch( ... ) + { + OUString message= OUSTR("InterfaceOleWrapper_Impl::doInvoke : \n" + "Unexpected exception"); + writeExcepinfo(pexcepinfo, message); + ret = DISP_E_EXCEPTION; + } + return ret; +} + +HRESULT InterfaceOleWrapper_Impl::doGetProperty( DISPPARAMS * /*pdispparams*/, VARIANT * pvarResult, + EXCEPINFO * pexcepinfo, OUString& name) +{ + HRESULT ret= S_OK; + + Any value; + try + { + Any returnValue = m_xInvocation->getValue( name); + // write back return value + if (pvarResult) + anyToVariant(pvarResult, returnValue); + } + catch(UnknownPropertyException e) //XInvocation::getValue + { + writeExcepinfo(pexcepinfo, e.Message); + ret = DISP_E_MEMBERNOTFOUND; + } + catch(BridgeRuntimeError& e) + { + writeExcepinfo(pexcepinfo, e.message); + ret = DISP_E_EXCEPTION; + } + catch(Exception& e) + { + OUString message= OUSTR("InterfaceOleWrapper_Impl::doGetProperty : \n") + + e.Message; + writeExcepinfo(pexcepinfo, message); + } + catch( ... ) + { + OUString message= OUSTR("InterfaceOleWrapper_Impl::doInvoke : \n" + "Unexpected exception"); + writeExcepinfo(pexcepinfo, message); + ret = DISP_E_EXCEPTION; + } + return ret; +} + +HRESULT InterfaceOleWrapper_Impl::doSetProperty( DISPPARAMS * /*pdispparams*/, VARIANT * /*pvarResult*/, + EXCEPINFO * pexcepinfo, unsigned int * puArgErr, OUString& name, Sequence<Any> params) +{ + HRESULT ret= S_OK; + + try + { + m_xInvocation->setValue( name, params.getConstArray()[0]); + } + catch(UnknownPropertyException ) + { + ret = DISP_E_MEMBERNOTFOUND; + } + catch(CannotConvertException e) + { + ret= mapCannotConvertException( e, puArgErr); + } + catch(InvocationTargetException e) + { + if (pexcepinfo != NULL) + { + Any org = e.TargetException; + + pexcepinfo->wCode = UNO_2_OLE_EXCEPTIONCODE; + pexcepinfo->bstrSource = SysAllocString(L"any ONE component"); + pexcepinfo->bstrDescription = SysAllocString( + reinterpret_cast<LPCOLESTR>(org.getValueType().getTypeName().getStr())); + } + ret = DISP_E_EXCEPTION; + } + catch( ... ) + { + ret= DISP_E_EXCEPTION; + } + return ret; +} + +HRESULT InterfaceOleWrapper_Impl::InvokeGeneral( DISPID dispidMember, unsigned short wFlags, + DISPPARAMS * pdispparams, VARIANT * pvarResult, EXCEPINFO * pexcepinfo, + unsigned int * /*puArgErr*/, sal_Bool& bHandled) +{ + HRESULT ret= S_OK; + try + { +// DISPID_VALUE | The DEFAULT Value is required in JScript when the situation +// is that we put an object into an Array object ( out parameter). We have to return +// IDispatch otherwise the object cannot be accessed from the Script. + if( dispidMember == DISPID_VALUE && wFlags == DISPATCH_PROPERTYGET + && m_defaultValueType != VT_EMPTY && pvarResult != NULL) + { + bHandled= sal_True; + if( m_defaultValueType == VT_DISPATCH) + { + pvarResult->vt= VT_DISPATCH; + pvarResult->pdispVal= static_cast<IDispatch*>( this); + AddRef(); + ret= S_OK; + } + } +// --------- + // function: _GetValueObject + else if( dispidMember == DISPID_JSCRIPT_VALUE_FUNC) + { + bHandled= sal_True; + if( !pvarResult) + ret= E_POINTER; + CComObject< JScriptValue>* pValue; + if( SUCCEEDED( CComObject<JScriptValue>::CreateInstance( &pValue))) + { + pValue->AddRef(); + pvarResult->vt= VT_DISPATCH; +#ifdef __MINGW32__ + pvarResult->pdispVal= CComQIPtr<IDispatch, &__uuidof(IDispatch)>(pValue->GetUnknown()); +#else + pvarResult->pdispVal= CComQIPtr<IDispatch>(pValue->GetUnknown()); +#endif + ret= S_OK; + } + else + ret= DISP_E_EXCEPTION; + } + else if( dispidMember == DISPID_GET_STRUCT_FUNC) + { + bHandled= sal_True; + sal_Bool bStruct= sal_False; + + + Reference<XInterface> xIntCore= m_smgr->createInstance( OUString::createFromAscii("com.sun.star.reflection.CoreReflection")); + Reference<XIdlReflection> xRefl( xIntCore, UNO_QUERY); + if( xRefl.is() ) + { + // the first parameter is in DISPPARAMS rgvargs contains the name of the struct. + CComVariant arg; + if( pdispparams->cArgs == 1 && SUCCEEDED( arg.ChangeType( VT_BSTR, &pdispparams->rgvarg[0])) ) + { + Reference<XIdlClass> classStruct= xRefl->forName( reinterpret_cast<const sal_Unicode*>(arg.bstrVal)); + if( classStruct.is()) + { + Any anyStruct; + classStruct->createObject( anyStruct); + CComVariant var; + anyToVariant( &var, anyStruct ); + + if( var.vt == VT_DISPATCH) + { + VariantCopy( pvarResult, & var); + bStruct= sal_True; + } + } + } + } + ret= bStruct == sal_True ? S_OK : DISP_E_EXCEPTION; + } + else if (dispidMember == DISPID_CREATE_TYPE_FUNC) + { + bHandled= sal_True; + if( !pvarResult) + ret= E_POINTER; + // the first parameter is in DISPPARAMS rgvargs contains the name of the struct. + CComVariant arg; + if( pdispparams->cArgs != 1) + return DISP_E_BADPARAMCOUNT; + if (FAILED( arg.ChangeType( VT_BSTR, &pdispparams->rgvarg[0]))) + return DISP_E_BADVARTYPE; + + //check if the provided name represents a valid type + Type type; + if (getType(arg.bstrVal, type) == false) + { + writeExcepinfo(pexcepinfo,OUString( + OUSTR("[automation bridge] A UNO type with the name ") + + OUString(reinterpret_cast<const sal_Unicode*>(arg.bstrVal)) + OUSTR(" does not exist!"))); + return DISP_E_EXCEPTION; + } + + if (createUnoTypeWrapper(arg.bstrVal, pvarResult) == false) + { + writeExcepinfo(pexcepinfo,OUSTR("[automation bridge] InterfaceOleWrapper_Impl::InvokeGeneral\n" + "Could not initialize UnoTypeWrapper object!")); + return DISP_E_EXCEPTION; + } + } + } + catch(BridgeRuntimeError & e) + { + writeExcepinfo(pexcepinfo, e.message); + ret = DISP_E_EXCEPTION; + } + catch(Exception & e) + { + OUString message= OUSTR("InterfaceOleWrapper_Impl::InvokeGeneral : \n") + + e.Message; + writeExcepinfo(pexcepinfo, message); + ret = DISP_E_EXCEPTION; + } + catch( ... ) + { + OUString message= OUSTR("InterfaceOleWrapper_Impl::InvokeGeneral : \n" + "Unexpected exception"); + writeExcepinfo(pexcepinfo, message); + ret = DISP_E_EXCEPTION; + } + return ret; +} + + + + +STDMETHODIMP InterfaceOleWrapper_Impl::GetDispID(BSTR /*bstrName*/, DWORD /*grfdex*/, DISPID __RPC_FAR* /*pid*/) +{ + HRESULT ret = ResultFromScode(E_NOTIMPL); + + return ret; +} + +STDMETHODIMP InterfaceOleWrapper_Impl::InvokeEx( + /* [in] */ DISPID /*id*/, + /* [in] */ LCID /*lcid*/, + /* [in] */ WORD /*wFlags*/, + /* [in] */ DISPPARAMS __RPC_FAR* /*pdp*/, + /* [out] */ VARIANT __RPC_FAR* /*pvarRes*/, + /* [out] */ EXCEPINFO __RPC_FAR* /*pei*/, + /* [unique][in] */ IServiceProvider __RPC_FAR* /*pspCaller*/) +{ + HRESULT ret = ResultFromScode(E_NOTIMPL); + + return ret; +} + + +STDMETHODIMP InterfaceOleWrapper_Impl::DeleteMemberByName( + /* [in] */ BSTR /*bstr*/, + /* [in] */ DWORD /*grfdex*/) +{ + HRESULT ret = ResultFromScode(E_NOTIMPL); + + return ret; +} + +STDMETHODIMP InterfaceOleWrapper_Impl::DeleteMemberByDispID(DISPID /*id*/) +{ + HRESULT ret = ResultFromScode(E_NOTIMPL); + + return ret; +} + +STDMETHODIMP InterfaceOleWrapper_Impl::GetMemberProperties( + /* [in] */ DISPID /*id*/, + /* [in] */ DWORD /*grfdexFetch*/, + /* [out] */ DWORD __RPC_FAR* /*pgrfdex*/) +{ + HRESULT ret = ResultFromScode(E_NOTIMPL); + + return ret; +} + +STDMETHODIMP InterfaceOleWrapper_Impl::GetMemberName( + /* [in] */ DISPID /*id*/, + /* [out] */ BSTR __RPC_FAR* /*pbstrName*/) +{ + HRESULT ret = ResultFromScode(E_NOTIMPL); + + return ret; +} + +STDMETHODIMP InterfaceOleWrapper_Impl::GetNextDispID( + /* [in] */ DWORD /*grfdex*/, + /* [in] */ DISPID /*id*/, + /* [out] */ DISPID __RPC_FAR* /*pid*/) +{ + HRESULT ret = ResultFromScode(E_NOTIMPL); + + return ret; +} + +STDMETHODIMP InterfaceOleWrapper_Impl::GetNameSpaceParent( + /* [out] */ IUnknown __RPC_FAR *__RPC_FAR* /*ppunk*/) +{ + HRESULT ret = ResultFromScode(E_NOTIMPL); + + return ret; +} + + +/************************************************************************* + + UnoObjectWrapperRemoteOpt + +*************************************************************************/ +UnoObjectWrapperRemoteOpt::UnoObjectWrapperRemoteOpt( Reference<XMultiServiceFactory>& aFactory, + sal_uInt8 unoWrapperClass, sal_uInt8 comWrapperClass): +InterfaceOleWrapper_Impl( aFactory, unoWrapperClass, comWrapperClass), +m_currentId(1) + +{ +} +UnoObjectWrapperRemoteOpt::~UnoObjectWrapperRemoteOpt() +{ +} + +// UnoConversionUtilities +Reference< XInterface > UnoObjectWrapperRemoteOpt::createUnoWrapperInstance() +{ + Reference<XWeak> xWeak= static_cast<XWeak*>( new UnoObjectWrapperRemoteOpt( + m_smgr, m_nUnoWrapperClass, m_nComWrapperClass)); + return Reference<XInterface>( xWeak, UNO_QUERY); +} + +STDMETHODIMP UnoObjectWrapperRemoteOpt::GetIDsOfNames ( REFIID /*riid*/, OLECHAR ** rgszNames, unsigned int cNames, + LCID /*lcid*/, DISPID * rgdispid ) +{ + MutexGuard guard( getBridgeMutex()); + + if( ! rgdispid) + return E_POINTER; + HRESULT ret = E_UNEXPECTED; + // ---------------------------------------- + // _GetValueObject + if( ! wcscmp( *rgszNames, JSCRIPT_VALUE_FUNC)) + { + *rgdispid= DISPID_JSCRIPT_VALUE_FUNC; + return S_OK; + } + else if( ! wcscmp( *rgszNames, GET_STRUCT_FUNC)) + { + *rgdispid= DISPID_GET_STRUCT_FUNC; + return S_OK; + } + + // ---------------------------------------- + if (m_xInvocation.is() && (cNames > 0)) + { + OUString name(reinterpret_cast<const sal_Unicode*>(rgszNames[0])); + // has this name been determined as "bad" + BadNameMap::iterator badIter= m_badNameMap.find( name); + if( badIter == m_badNameMap.end() ) + { + // name has not been bad before( member exists + typedef NameToIdMap::iterator ITnames; + pair< ITnames, bool > pair_id= m_nameToDispIdMap.insert( NameToIdMap::value_type(name, m_currentId++)); + // new ID inserted ? + if( pair_id.second ) + {// yes, now create MemberInfo and ad to IdToMemberInfoMap + MemberInfo d(0, name); + m_idToMemberInfoMap.insert( IdToMemberInfoMap::value_type( m_currentId - 1, d)); + } + + *rgdispid = pair_id.first->second; + ret = S_OK; + } + else + ret= DISP_E_UNKNOWNNAME; + } + return ret; +} + +STDMETHODIMP UnoObjectWrapperRemoteOpt::Invoke ( DISPID dispidMember, REFIID /*riid*/, LCID /*lcid*/, unsigned short wFlags, + DISPPARAMS * pdispparams, VARIANT * pvarResult, EXCEPINFO * pexcepinfo, + unsigned int * puArgErr ) +{ + HRESULT ret = S_OK; + try + { + sal_Bool bHandled= sal_False; + ret= InvokeGeneral( dispidMember, wFlags, pdispparams, pvarResult, pexcepinfo, + puArgErr, bHandled); + if( bHandled) + return ret; + + if ( dispidMember > 0 && m_xInvocation.is()) + { + + IdToMemberInfoMap::iterator it_MemberInfo= m_idToMemberInfoMap.find( dispidMember); + if( it_MemberInfo != m_idToMemberInfoMap.end() ) + { + MemberInfo& info= it_MemberInfo->second; + + Sequence<Any> params; // holds converted any s + if( ! info.flags ) + { // DISPID called for the first time + if( wFlags == DISPATCH_METHOD ) + { + convertDispparamsArgs(dispidMember, wFlags, pdispparams, params ); + + if( FAILED( ret= doInvoke( pdispparams, pvarResult, + pexcepinfo, puArgErr, info.name, params)) + && ret == DISP_E_MEMBERNOTFOUND) + { + // try to get the exact name + OUString exactName; + if (m_xExactName.is()) + { + exactName = m_xExactName->getExactName( info.name); + // invoke again + if( exactName.getLength() != 0) + { + if( SUCCEEDED( ret= doInvoke( pdispparams, pvarResult, + pexcepinfo, puArgErr, exactName, params))) + info.name= exactName; + } + } + } + if( SUCCEEDED( ret ) ) + info.flags= DISPATCH_METHOD; + } //if( wFlags == DISPATCH_METHOD ) + + else if( wFlags == DISPATCH_PROPERTYPUT || wFlags == DISPATCH_PROPERTYPUTREF) + { + convertDispparamsArgs(dispidMember, wFlags, pdispparams, params ); + if( FAILED( ret= doSetProperty( pdispparams, pvarResult, + pexcepinfo, puArgErr, info.name, params)) + && ret == DISP_E_MEMBERNOTFOUND) + { + // try to get the exact name + OUString exactName; + if (m_xExactName.is()) + { + exactName = m_xExactName->getExactName( info.name); + // invoke again + if( exactName.getLength() != 0) + { + if( SUCCEEDED( ret= doSetProperty( pdispparams, pvarResult, + pexcepinfo, puArgErr, exactName, params))) + info.name= exactName; + } + } + } + if( SUCCEEDED( ret ) ) + info.flags= DISPATCH_PROPERTYPUT | DISPATCH_PROPERTYGET; + } + + else if( wFlags == DISPATCH_PROPERTYGET) + { + if( FAILED( ret= doGetProperty( pdispparams, pvarResult, + pexcepinfo, info.name)) + && ret == DISP_E_MEMBERNOTFOUND) + { + // try to get the exact name + OUString exactName; + if (m_xExactName.is()) + { + exactName = m_xExactName->getExactName( info.name); + // invoke again + if( exactName.getLength() != 0) + { + if( SUCCEEDED( ret= doGetProperty( pdispparams, pvarResult, + pexcepinfo, exactName))) + info.name= exactName; + } + } + } + if( SUCCEEDED( ret ) ) + info.flags= DISPATCH_PROPERTYGET | DISPATCH_PROPERTYPUT; + } + else if( wFlags & DISPATCH_METHOD && + (wFlags & DISPATCH_PROPERTYPUT || wFlags & DISPATCH_PROPERTYPUTREF)) + { + + OUString exactName; + // convert params for DISPATCH_METHOD or DISPATCH_PROPERTYPUT + convertDispparamsArgs(dispidMember, wFlags, pdispparams, params ); + // try first as method + if( FAILED( ret= doInvoke( pdispparams, pvarResult, + pexcepinfo, puArgErr, info.name, params)) + && ret == DISP_E_MEMBERNOTFOUND) + { + // try to get the exact name + if (m_xExactName.is()) + { + exactName = m_xExactName->getExactName( info.name); + // invoke again + if( exactName.getLength() != 0) + { + if( SUCCEEDED( ret= doInvoke( pdispparams, pvarResult, + pexcepinfo, puArgErr, exactName, params))) + info.name= exactName; + } + } + } + if( SUCCEEDED( ret ) ) + info.flags= DISPATCH_METHOD; + + // try as property + if( FAILED( ret) && pdispparams->cArgs == 1) + { + if( FAILED( ret= doSetProperty( pdispparams, pvarResult, + pexcepinfo, puArgErr, info.name, params)) + && ret == DISP_E_MEMBERNOTFOUND) + { + // try to get the exact name + if( exactName.getLength() != 0) + { + if( SUCCEEDED( ret= doSetProperty( pdispparams, pvarResult, + pexcepinfo, puArgErr, exactName, params))) + info.name= exactName; + } + } + if( SUCCEEDED( ret ) ) + info.flags= DISPATCH_PROPERTYPUT | DISPATCH_PROPERTYGET; + } + } + else if( wFlags & DISPATCH_METHOD && wFlags & DISPATCH_PROPERTYGET) + { + OUString exactName; + convertDispparamsArgs(dispidMember, wFlags, pdispparams, params ); + + if( FAILED( ret= doInvoke( pdispparams, pvarResult, + pexcepinfo, puArgErr, info.name, params)) + && ret == DISP_E_MEMBERNOTFOUND) + { + // try to get the exact name + if (m_xExactName.is()) + { + exactName = m_xExactName->getExactName( info.name); + // invoke again + if( exactName.getLength() != 0) + { + if( SUCCEEDED( ret= doInvoke( pdispparams, pvarResult, + pexcepinfo, puArgErr, exactName, params))) + info.name= exactName; + } + } + } + if( SUCCEEDED( ret ) ) + info.flags= DISPATCH_METHOD; + + // try as property + if( FAILED( ret) && pdispparams->cArgs == 1) + { + if( FAILED( ret= doGetProperty( pdispparams, pvarResult, + pexcepinfo, info.name)) + && ret == DISP_E_MEMBERNOTFOUND) + { + if( exactName.getLength() != 0) + { + if( SUCCEEDED( ret= doSetProperty( pdispparams, pvarResult, + pexcepinfo, puArgErr, exactName, params))) + info.name= exactName; + } + } + if( SUCCEEDED( ret ) ) + info.flags= DISPATCH_PROPERTYGET; + } + } + + // update ínformation about this member + if( ret == DISP_E_MEMBERNOTFOUND) + { + // Remember the name as not existing + // and remove the MemberInfo + m_badNameMap[info.name]= sal_False; + m_idToMemberInfoMap.erase( it_MemberInfo); + } + } // if( ! info.flags ) + else // IdToMemberInfoMap contains a MemberInfo + { + if( wFlags & DISPATCH_METHOD && info.flags == DISPATCH_METHOD) + { + convertDispparamsArgs(dispidMember, wFlags, pdispparams, params ); + ret= doInvoke( pdispparams, pvarResult, + pexcepinfo, puArgErr, info.name, params); + } + else if( (wFlags & DISPATCH_PROPERTYPUT || wFlags & DISPATCH_PROPERTYPUTREF ) && + info.flags & DISPATCH_PROPERTYPUT) + { + convertDispparamsArgs(dispidMember, wFlags, pdispparams, params ); + ret= doSetProperty( pdispparams, pvarResult, + pexcepinfo, puArgErr, info.name, params); + } + else if( (wFlags & DISPATCH_PROPERTYGET) && ( info.flags & DISPATCH_PROPERTYGET)) + { + ret= doGetProperty( pdispparams, pvarResult, + pexcepinfo, info.name); + } + else + { + ret= DISP_E_MEMBERNOTFOUND; + } + } + }// if( it_MemberInfo != m_idToMemberInfoMap.end() ) + else + ret= DISP_E_MEMBERNOTFOUND; + } + } + catch(BridgeRuntimeError& e) + { + writeExcepinfo(pexcepinfo, e.message); + ret = DISP_E_EXCEPTION; + } + catch(Exception& e) + { + OUString message= OUSTR("UnoObjectWrapperRemoteOpt::Invoke : \n") + + e.Message; + writeExcepinfo(pexcepinfo, message); + ret = DISP_E_EXCEPTION; + } + catch(...) + { + OUString message= OUSTR("UnoObjectWrapperRemoteOpt::Invoke : \n" + "Unexpected exception"); + writeExcepinfo(pexcepinfo, message); + ret = DISP_E_EXCEPTION; + } + + return ret; +} + +HRESULT UnoObjectWrapperRemoteOpt::methodInvoke( DISPID /*dispidMember*/, DISPPARAMS * /*pdispparams*/, VARIANT * /*pvarResult*/, + EXCEPINFO * /*pexcepinfo*/, unsigned int * /*puArgErr*/, Sequence<Any> params) +{ + return S_OK; +} + + +// The returned HRESULT is only appropriate for IDispatch::Invoke +static HRESULT mapCannotConvertException( CannotConvertException e, unsigned int * puArgErr) +{ + HRESULT ret; + sal_Bool bWriteIndex= sal_True; + + switch ( e.Reason) + { + case FailReason::OUT_OF_RANGE: + ret = DISP_E_OVERFLOW; + break; + case FailReason::IS_NOT_NUMBER: + ret = DISP_E_TYPEMISMATCH; + break; + case FailReason::IS_NOT_ENUM: + ret = DISP_E_TYPEMISMATCH; + break; + case FailReason::IS_NOT_BOOL: + ret = DISP_E_TYPEMISMATCH; + break; + case FailReason::NO_SUCH_INTERFACE: + ret = DISP_E_TYPEMISMATCH; + break; + case FailReason::SOURCE_IS_NO_DERIVED_TYPE: + ret = DISP_E_TYPEMISMATCH; + break; + case FailReason::TYPE_NOT_SUPPORTED: + ret = DISP_E_TYPEMISMATCH; + break; + case FailReason::INVALID: + ret = DISP_E_TYPEMISMATCH; + break; + case FailReason::NO_DEFAULT_AVAILABLE: + ret = DISP_E_BADPARAMCOUNT; + break; + case FailReason::UNKNOWN: + ret = E_UNEXPECTED; + break; + default: + ret = E_UNEXPECTED; + bWriteIndex= sal_False; + break; + } + + if( bWriteIndex && puArgErr != NULL) + *puArgErr = e.ArgumentIndex; + return ret; +} + +// The function maps the TypeClass of the any to VARTYPE: If +// the Any contains STRUCT or INTERFACE then the return value +// is VT_DISPATCH. The function is used from o2u_createUnoObjectWrapper +// and the result is put into the constructor of the uno - wrapper +// object. If a client asks the object for DISPID_VALUE and this +// funtion returned VT_DISPATCH then the IDispatch of the same +// object is being returned. +// See InterfaceOleWrapper_Impl::Invoke, InterfaceOleWrapper_Impl::m_defaultValueType +const VARTYPE getVarType( const Any& value) +{ + VARTYPE ret= VT_EMPTY; + + switch ( value.getValueTypeClass()) + { + case TypeClass_STRUCT: ret= VT_DISPATCH; break; + case TypeClass_INTERFACE: ret= VT_DISPATCH; break; + default: break; + } + return ret; +} + + + + +} // end namespace + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/ole/unoobjw.hxx b/extensions/source/ole/unoobjw.hxx new file mode 100644 index 000000000000..e007dd662883 --- /dev/null +++ b/extensions/source/ole/unoobjw.hxx @@ -0,0 +1,302 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _UNOOBJW_HXX +#define _UNOOBJW_HXX + +#include <com/sun/star/bridge/XBridgeSupplier2.hpp> +#include <com/sun/star/beans/XExactName.hpp> +#include <com/sun/star/lang/XInitialization.hpp> +#include <com/sun/star/script/InvocationInfo.hpp> +#include <salhelper/simplereferenceobject.hxx> + +#include <tools/presys.h> +#include "comifaces.hxx" +#include <tools/postsys.h> + +#include "ole2uno.hxx" +#include "unoconversionutilities.hxx" + +//#define INVOCATION_SERVICE L"com.sun.star.script.Invocation" +#define JSCRIPT_VALUE_FUNC L"_GetValueObject" +#define GET_STRUCT_FUNC L"_GetStruct" +#define BRIDGE_VALUE_FUNC L"Bridge_GetValueObject" +#define BRIDGE_GET_STRUCT_FUNC L"Bridge_GetStruct" +#define BRIDGE_CREATE_TYPE_FUNC L"Bridge_CreateType" + +#define DISPID_JSCRIPT_VALUE_FUNC -10l +#define DISPID_GET_STRUCT_FUNC -102 +#define DISPID_CREATE_TYPE_FUNC -103 + +using namespace std; +using namespace cppu; +using namespace com::sun::star::bridge; +using namespace com::sun::star::script; +namespace ole_adapter +{ + + + +struct hash_IUnknown_Impl +{ + size_t operator()(const IUnknown* p) const + { + return (size_t)p; + } +}; + +struct equal_to_IUnknown_Impl +{ + bool operator()(const IUnknown* s1, const IUnknown* s2) const + { + return s1 == s2; + } +}; + + + +struct MemberInfo +{ + MemberInfo() : flags(0), name() {} + MemberInfo(WORD f, const OUString& n) : flags(f), name(n) {} + + WORD flags; + OUString name; +}; + +typedef hash_map +< + OUString, + DISPID, + hashOUString_Impl, + equalOUString_Impl +> NameToIdMap; + +typedef hash_map +< + OUString, + sal_Bool, + hashOUString_Impl, + equalOUString_Impl +> BadNameMap; + +typedef hash_map +< + DISPID, + MemberInfo +> IdToMemberInfoMap; + +/***************************************************************************** + + class declaration: InterfaceOleWrapper_Impl + +*****************************************************************************/ + +class InterfaceOleWrapper_Impl : public WeakImplHelper2<XBridgeSupplier2, XInitialization>, + public IDispatchEx, + public UnoConversionUtilities<InterfaceOleWrapper_Impl>, + public IUnoObjectWrapper +{ +public: + + + InterfaceOleWrapper_Impl(Reference<XMultiServiceFactory>& xFactory, sal_uInt8 unoWrapperClass, sal_uInt8 comWrapperClass); + ~InterfaceOleWrapper_Impl(); + + /* IUnknown methods */ + STDMETHOD(QueryInterface)(REFIID riid, LPVOID FAR * ppvObj); + STDMETHOD_(ULONG, AddRef)(); + STDMETHOD_(ULONG, Release)(); + + /* IDispatch methods */ + STDMETHOD( GetTypeInfoCount )( unsigned int * pctinfo ); + STDMETHOD( GetTypeInfo )( unsigned int itinfo, LCID lcid, ITypeInfo ** pptinfo ); + STDMETHOD( GetIDsOfNames )( REFIID riid, OLECHAR ** rgszNames, unsigned int cNames, + LCID lcid, DISPID * rgdispid ); + STDMETHOD( Invoke )( DISPID dispidMember, REFIID riid, LCID lcid, unsigned short wFlags, + DISPPARAMS * pdispparams, VARIANT * pvarResult, EXCEPINFO * pexcepinfo, + unsigned int * puArgErr ); + + /* IDispatchEx methods */ + + virtual HRESULT STDMETHODCALLTYPE GetDispID( + /* [in] */ BSTR bstrName, + /* [in] */ DWORD grfdex, + /* [out] */ DISPID __RPC_FAR *pid); + + virtual /* [local] */ HRESULT STDMETHODCALLTYPE InvokeEx( + /* [in] */ DISPID id, + /* [in] */ LCID lcid, + /* [in] */ WORD wFlags, + /* [in] */ DISPPARAMS __RPC_FAR *pdp, + /* [out] */ VARIANT __RPC_FAR *pvarRes, + /* [out] */ EXCEPINFO __RPC_FAR *pei, + /* [unique][in] */ IServiceProvider __RPC_FAR *pspCaller); + + virtual HRESULT STDMETHODCALLTYPE DeleteMemberByName( + /* [in] */ BSTR bstr, + /* [in] */ DWORD grfdex); + + virtual HRESULT STDMETHODCALLTYPE DeleteMemberByDispID( + /* [in] */ DISPID id); + + virtual HRESULT STDMETHODCALLTYPE GetMemberProperties( + /* [in] */ DISPID id, + /* [in] */ DWORD grfdexFetch, + /* [out] */ DWORD __RPC_FAR *pgrfdex); + + virtual HRESULT STDMETHODCALLTYPE GetMemberName( + /* [in] */ DISPID id, + /* [out] */ BSTR __RPC_FAR *pbstrName); + + virtual HRESULT STDMETHODCALLTYPE GetNextDispID( + /* [in] */ DWORD grfdex, + /* [in] */ DISPID id, + /* [out] */ DISPID __RPC_FAR *pid); + + virtual HRESULT STDMETHODCALLTYPE GetNameSpaceParent( + /* [out] */ IUnknown __RPC_FAR *__RPC_FAR *ppunk); + + // XBridgeSupplier2 --------------------------------------------------- + virtual Any SAL_CALL createBridge(const Any& modelDepObject, + const Sequence<sal_Int8>& ProcessId, + sal_Int16 sourceModelType, + sal_Int16 destModelType) + throw (IllegalArgumentException, RuntimeException); + + //XInitialization ----------------------------------------------------- + virtual void SAL_CALL initialize( const Sequence< Any >& aArguments ) throw(Exception, RuntimeException); + + // IUnoObjectWrapper + STDMETHOD( getWrapperXInterface)( Reference<XInterface>* pXInt); + STDMETHOD( getOriginalUnoObject)( Reference<XInterface>* pXInt); + STDMETHOD( getOriginalUnoStruct)( Any * pStruct); + + // UnoConversionUtility + virtual Reference< XInterface > createUnoWrapperInstance(); + virtual Reference< XInterface > createComWrapperInstance(); + + +protected: + virtual HRESULT doInvoke( DISPPARAMS * pdispparams, VARIANT * pvarResult, + EXCEPINFO * pexcepinfo, unsigned int * puArgErr, OUString & name, Sequence<Any>& params); + + virtual HRESULT doGetProperty( DISPPARAMS * pdispparams, VARIANT * pvarResult, + EXCEPINFO * pexcepinfo, OUString & name ); + + virtual HRESULT doSetProperty( DISPPARAMS * pdispparams, VARIANT * pvarResult, + EXCEPINFO * pexcepinfo, unsigned int * puArgErr, OUString & name, Sequence<Any> params); + + virtual HRESULT InvokeGeneral( DISPID dispidMember, unsigned short wFlags, + DISPPARAMS * pdispparams, VARIANT * pvarResult, EXCEPINFO * pexcepinfo, + unsigned int * puArgErr, sal_Bool& bHandled); + + void convertDispparamsArgs( DISPID id, unsigned short wFlags, DISPPARAMS* pdispparams, + Sequence<Any>& rSeq); + + sal_Bool getInvocationInfoForCall(DISPID id, InvocationInfo& info); + + Reference<XInvocation> m_xInvocation; + Reference<XExactName> m_xExactName; + Reference<XInterface> m_xOrigin; + NameToIdMap m_nameToDispIdMap; + vector<MemberInfo> m_MemberInfos; + // This member is used to determine the default value + // denoted by DISPID_VALUE (0). For proper results in JavaScript + // we have to return the default value when we write an object + // as out parameter. That is, we get an JScript Array as parameter + // and put a wrapped object on index null. The array object tries + // to detect the default value. The wrapped object must then return + // its own IDispatch* otherwise we cannot access it within the script. + // see InterfaceOleWrapper_Impl::Invoke + VARTYPE m_defaultValueType; + +}; + +/***************************************************************************** + + class declaration: UnoObjectWrapperRemoteOpt + ( Uno Object Wrapper Remote Optimized) + This is the UNO wrapper used in the service com.sun.star.bridge.OleBridgeSupplierVar1. + Key features: + DISPIDs are passed out blindly. That is in GetIDsOfNames is no name checking carried out. + Only if Invoke fails the name is being checked. Moreover Invoke tries to figure out + if a call is made to a property or method if the flags are DISPATCH_METHOD | DISPATCH_PROPERTYPUT. + If something has been found out about a property or member than it is saved + in a MemberInfo structure hold by a IdToMemberInfoMap stl map. + +*****************************************************************************/ +class UnoObjectWrapperRemoteOpt: public InterfaceOleWrapper_Impl +{ +public: + UnoObjectWrapperRemoteOpt( Reference<XMultiServiceFactory>& aFactory, sal_uInt8 unoWrapperClass, sal_uInt8 comWrapperClass); + ~UnoObjectWrapperRemoteOpt(); + + STDMETHOD( GetIDsOfNames )( REFIID riid, OLECHAR ** rgszNames, unsigned int cNames, + LCID lcid, DISPID * rgdispid ); + STDMETHOD( Invoke )( DISPID dispidMember, REFIID riid, LCID lcid, unsigned short wFlags, + DISPPARAMS * pdispparams, VARIANT * pvarResult, EXCEPINFO * pexcepinfo, + unsigned int * puArgErr ); + + // UnoConversionUtility + // If UNO interfaces are converted in methods of this class then + // they are always wrapped with instances of this class + virtual Reference< XInterface > createUnoWrapperInstance(); + +protected: + + HRESULT methodInvoke( DISPID dispidMember, DISPPARAMS * pdispparams, VARIANT * pvarResult, + EXCEPINFO * pexcepinfo, unsigned int * puArgErr, Sequence<Any> params); + // In GetIDsOfNames are blindly passed out, that is without verifying + // the name. If two names are passed in during different calls to + // GetIDsOfNames and the names differ only in their cases then different + // id's are passed out ( e.g. "doSomethingMethod" or "dosomethingmethod"). + // In Invoke the DISPID is remapped to the name passed to GetIDsOfNames + // and the name is used as parameter for XInvocation::invoke. If invoke + // fails because of a wrong name, then m_xExactName ( XExactName) is used + // to verify the name. The correct name is then inserted to m_MemberInfos + // ( vector<MemberInfo> ). During the next call to Invoke the right name + // is used. . + + + BadNameMap m_badNameMap; + + IdToMemberInfoMap m_idToMemberInfoMap; + + DISPID m_currentId; + + +}; + + + +} // end namespace + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/ole/unotypewrapper.cxx b/extensions/source/ole/unotypewrapper.cxx new file mode 100644 index 000000000000..7461d7d0e62f --- /dev/null +++ b/extensions/source/ole/unotypewrapper.cxx @@ -0,0 +1,181 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_extensions.hxx" +#include "unotypewrapper.hxx" +#include "rtl/ustring.hxx" + + +bool createUnoTypeWrapper(BSTR sTypeName, VARIANT * pVar) +{ + bool ret = false; + OSL_ASSERT(sTypeName && pVar); + CComObject< UnoTypeWrapper>* pObj; + VariantClear(pVar); + if( SUCCEEDED( CComObject<UnoTypeWrapper>::CreateInstance( &pObj))) + { + pObj->AddRef(); + pVar->vt= VT_DISPATCH; +#ifdef __MINGW32__ + pVar->pdispVal= CComQIPtr<IDispatch, &__uuidof(IDispatch)>(pObj->GetUnknown()); +#else + pVar->pdispVal= CComQIPtr<IDispatch>(pObj->GetUnknown()); +#endif + //now set the value, e.i. the name of the type +#ifdef __MINGW32__ + CComQIPtr<IUnoTypeWrapper, &__uuidof(IUnoTypeWrapper)> spType(pVar->pdispVal); +#else + CComQIPtr<IUnoTypeWrapper> spType(pVar->pdispVal); +#endif + OSL_ASSERT(spType); + if (SUCCEEDED(spType->put_Name(sTypeName))) + { + ret = true; + } + } + return ret; +} + + +bool createUnoTypeWrapper(const rtl::OUString& sTypeName, VARIANT * pVar) +{ + CComBSTR bstr(reinterpret_cast<LPCOLESTR>(sTypeName.getStr())); + return createUnoTypeWrapper(bstr, pVar); +} + +UnoTypeWrapper::UnoTypeWrapper() +{ +} + +UnoTypeWrapper::~UnoTypeWrapper() +{ +} + + +// UnoTypeWrapper, IDispatch -------------------------------------------- +STDMETHODIMP UnoTypeWrapper::GetTypeInfoCount(UINT* /*pctinfo*/) +{ + return E_NOTIMPL; +} + +// UnoTypeWrapper, IDispatch -------------------------------------------- +STDMETHODIMP UnoTypeWrapper::GetTypeInfo( UINT /*iTInfo*/, + LCID /*lcid*/, + ITypeInfo** /*ppTInfo*/) +{ + return E_NOTIMPL; +} + +// UnoTypeWrapper, IDispatch -------------------------------------------- +STDMETHODIMP UnoTypeWrapper::GetIDsOfNames( REFIID /*riid*/, + LPOLESTR *rgszNames, + UINT /*cNames*/, + LCID /*lcid*/, + DISPID *rgDispId) +{ + if( !rgDispId) + return E_POINTER; + + HRESULT ret= S_OK; + CComBSTR name(*rgszNames); + name.ToLower(); + + if( name == CComBSTR( L"name") ) + *rgDispId= DISPID_VALUE; + else + ret= DISP_E_UNKNOWNNAME; + + return ret; +} + +// UnoTypeWrapper, IDispatch -------------------------------------------- +STDMETHODIMP UnoTypeWrapper::Invoke( DISPID dispIdMember, + REFIID /*riid*/, + LCID /*lcid*/, + WORD wFlags, + DISPPARAMS *pDispParams, + VARIANT *pVarResult, + EXCEPINFO* /*pExcepInfo*/, + UINT* /*puArgErr*/) +{ + if (pDispParams == NULL) + return DISP_E_EXCEPTION; + + if( pDispParams->cNamedArgs) + return DISP_E_NONAMEDARGS; + + + HRESULT ret= S_OK; + switch( dispIdMember) + { + case DISPID_VALUE: // DISPID_VALUE + if (wFlags & DISPATCH_PROPERTYGET) + { + if (pVarResult == NULL) + { + ret = E_POINTER; + break; + } + get_Name( & pVarResult->bstrVal); + pVarResult->vt = VT_BSTR; + } + break; + default: + ret= DISP_E_MEMBERNOTFOUND; + break; + } + + return ret; +} + +// IUnoTypeWrapper----------------------- +STDMETHODIMP UnoTypeWrapper::put_Name(BSTR val) +{ + Lock(); + HRESULT hr = S_OK; + m_sName = val; + Unlock(); + return hr; +} + +// (UnoTypeWrapper----------------------- +STDMETHODIMP UnoTypeWrapper::get_Name(BSTR *pVal) +{ + Lock(); + HRESULT hr = S_OK; + if( !pVal) + return E_POINTER; + *pVal = m_sName.Copy(); + Unlock(); + return hr; +} + + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/ole/unotypewrapper.hxx b/extensions/source/ole/unotypewrapper.hxx new file mode 100644 index 000000000000..f09fd9bfbbb2 --- /dev/null +++ b/extensions/source/ole/unotypewrapper.hxx @@ -0,0 +1,103 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef UNO_TYPE_WRAPPER_HXX +#define UNO_TYPE_WRAPPER_HXX + +#pragma warning (push,1) +#pragma warning (disable:4548) + +#include <tools/presys.h> +#define STRICT +#define _WIN32_WINNT 0x0403 +#define _WIN32_DCOM +#if OSL_DEBUG_LEVEL > 0 +//#define _ATL_DEBUG_INTERFACES +#endif +#include <atlbase.h> +extern CComModule _Module; +#include <atlcom.h> +#include <tools/postsys.h> + +#pragma warning (pop) +#pragma warning (disable:4505) + // disable "unreferenced local function has been removed" globally + +#include "comifaces.hxx" + +/* creates an UnoTypWrapper and sets the Name property to the value + specified by sTypeName. + Returns true if the object could be created and initialized. + */ +bool createUnoTypeWrapper(BSTR sTypeName, VARIANT * pVariant); +bool createUnoTypeWrapper(const rtl::OUString& sTypeName, VARIANT * pVar); + +class UnoTypeWrapper: + public CComObjectRootEx<CComMultiThreadModel>, + public IUnoTypeWrapper, + public IDispatch +{ +public: + UnoTypeWrapper(); + virtual ~UnoTypeWrapper(); + + BEGIN_COM_MAP(UnoTypeWrapper) + COM_INTERFACE_ENTRY(IDispatch) + COM_INTERFACE_ENTRY(IUnoTypeWrapper) + END_COM_MAP() + + // IDispatch ------------------------------------------- + STDMETHOD( GetTypeInfoCount)(UINT *pctinfo); + + STDMETHOD( GetTypeInfo)( UINT iTInfo, + LCID lcid, + ITypeInfo **ppTInfo); + + STDMETHOD( GetIDsOfNames)( REFIID riid, + LPOLESTR *rgszNames, + UINT cNames, + LCID lcid, + DISPID *rgDispId); + + STDMETHOD( Invoke)( DISPID dispIdMember, + REFIID riid, + LCID lcid, + WORD wFlags, + DISPPARAMS *pDispParams, + VARIANT *pVarResult, + EXCEPINFO *pExcepInfo, + UINT *puArgErr); + // IUnoTypeWrapper -------------------------------------- + STDMETHOD(put_Name)(BSTR val); + STDMETHOD(get_Name)(BSTR* pVal); + + CComBSTR m_sName; +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/ole/windata.cxx b/extensions/source/ole/windata.cxx new file mode 100644 index 000000000000..e4047e3b184c --- /dev/null +++ b/extensions/source/ole/windata.cxx @@ -0,0 +1,42 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_extensions.hxx" +#include "windata.hxx" + + +namespace ole_adapter +{ + + + +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/ole/windata.hxx b/extensions/source/ole/windata.hxx new file mode 100644 index 000000000000..fce3d4af5e9c --- /dev/null +++ b/extensions/source/ole/windata.hxx @@ -0,0 +1,201 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef AUTOMATION_BRIDGE_WINDATA_HXX +#define AUTOMATION_BRIDGE_WINDATA_HXX + +#pragma warning (push,1) +#pragma warning (disable:4668) +#pragma warning (disable:4548) +#include "oleidl.h" + +#include <atlbase.h> +#pragma warning (pop) +#include "osl/diagnose.h" + +namespace ole_adapter +{ +//Wrapper for VARDESC +class VarDesc +{ + VARDESC* operator = (const VarDesc*); + VarDesc(const VarDesc&); +// Construction +public: + CComPtr< ITypeInfo > m_pTypeInfo; + VARDESC* m_pVarDesc; + + VarDesc(ITypeInfo* pTypeInfo) : + m_pVarDesc(NULL), + m_pTypeInfo(pTypeInfo) + { + OSL_ASSERT(pTypeInfo); + } + ~VarDesc() + { + if (m_pVarDesc != NULL) + { + m_pTypeInfo->ReleaseVarDesc(m_pVarDesc); + } + } + + VARDESC* operator->() + { + return m_pVarDesc; + } + + VARDESC** operator&() + { + return &m_pVarDesc; + } + + operator VARDESC* () + { + return m_pVarDesc; + } +}; + +//Wrapper for FUNCDESC structure +class FuncDesc +{ + FUNCDESC* operator = (const FuncDesc &); + FuncDesc(const FuncDesc&); + CComPtr<ITypeInfo> m_pTypeInfo; + FUNCDESC * m_pFuncDesc; + +public: + + FuncDesc(ITypeInfo * pTypeInfo) : + m_pFuncDesc(NULL), + m_pTypeInfo(pTypeInfo) + { + OSL_ASSERT(pTypeInfo); + } + ~FuncDesc() + { + ReleaseFUNCDESC(); + } + + FUNCDESC* operator -> () + { + return m_pFuncDesc; + } + + FUNCDESC** operator & () + { + return & m_pFuncDesc; + } + + operator FUNCDESC* () + { + return m_pFuncDesc; + } + + FUNCDESC* operator = (FUNCDESC* pDesc) + { + ReleaseFUNCDESC(); + m_pFuncDesc = pDesc; + return m_pFuncDesc; + } + FUNCDESC* Detach() + { + FUNCDESC* pDesc = m_pFuncDesc; + m_pFuncDesc = NULL; + return pDesc; + } + + void ReleaseFUNCDESC() + { + if (m_pFuncDesc != NULL) + { + m_pTypeInfo->ReleaseFuncDesc(m_pFuncDesc); + } + m_pFuncDesc = NULL; + } +}; +//Wrapper for EXCEPINFO structure +class ExcepInfo : public EXCEPINFO +{ + EXCEPINFO* operator = (const ExcepInfo& ); + ExcepInfo(const ExcepInfo &); +public: + ExcepInfo() + { + memset(this, 0, sizeof(ExcepInfo)); + } + ~ExcepInfo() + { + if (bstrSource != NULL) + ::SysFreeString(bstrSource); + if (bstrDescription != NULL) + ::SysFreeString(bstrDescription); + if (bstrHelpFile != NULL) + ::SysFreeString(bstrHelpFile); + } +}; + +//Wrapper for TYPEATTR +class TypeAttr +{ + TYPEATTR* operator = (const TypeAttr &); + TypeAttr(const TypeAttr &); +public: + CComPtr< ITypeInfo > m_pTypeInfo; + TYPEATTR* m_pTypeAttr; + + TypeAttr(ITypeInfo* pTypeInfo) : + m_pTypeAttr( NULL ), + m_pTypeInfo( pTypeInfo ) + { + OSL_ASSERT(pTypeInfo); + } + ~TypeAttr() throw() + { + if (m_pTypeAttr != NULL) + { + m_pTypeInfo->ReleaseTypeAttr(m_pTypeAttr); + } + } + + TYPEATTR** operator&() throw() + { + return &m_pTypeAttr; + } + + TYPEATTR* operator->() throw() + { + return m_pTypeAttr; + } +}; + + + +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |