summaryrefslogtreecommitdiffstats
path: root/extensions/source/ole
diff options
context:
space:
mode:
Diffstat (limited to 'extensions/source/ole')
-rw-r--r--extensions/source/ole/comifaces.hxx62
-rw-r--r--extensions/source/ole/jscriptclasses.cxx312
-rw-r--r--extensions/source/ole/jscriptclasses.hxx147
-rw-r--r--extensions/source/ole/ole2uno.cxx47
-rw-r--r--extensions/source/ole/ole2uno.hxx70
-rw-r--r--extensions/source/ole/oleautobridge.component37
-rw-r--r--extensions/source/ole/oledll.cxx70
-rw-r--r--extensions/source/ole/oleobjw.cxx2513
-rw-r--r--extensions/source/ole/oleobjw.hxx244
-rw-r--r--extensions/source/ole/olethread.cxx66
-rw-r--r--extensions/source/ole/servprov.cxx548
-rw-r--r--extensions/source/ole/servprov.hxx184
-rw-r--r--extensions/source/ole/servreg.cxx94
-rw-r--r--extensions/source/ole/unoconversionutilities.hxx2363
-rw-r--r--extensions/source/ole/unoobjw.cxx3437
-rw-r--r--extensions/source/ole/unoobjw.hxx268
-rw-r--r--extensions/source/ole/unotypewrapper.cxx160
-rw-r--r--extensions/source/ole/unotypewrapper.hxx81
-rw-r--r--extensions/source/ole/wincrap.hxx64
-rw-r--r--extensions/source/ole/windata.hxx196
20 files changed, 10963 insertions, 0 deletions
diff --git a/extensions/source/ole/comifaces.hxx b/extensions/source/ole/comifaces.hxx
new file mode 100644
index 000000000..51e955dd6
--- /dev/null
+++ b/extensions/source/ole/comifaces.hxx
@@ -0,0 +1,62 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <com/sun/star/uno/XInterface.hpp>
+
+using namespace com::sun::star::uno;
+
+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;
+
+protected:
+ ~IJScriptValueObject() {}
+};
+
+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;
+
+protected:
+ ~IUnoObjectWrapper() {}
+};
+
+MIDL_INTERFACE("8BB66591-A544-4de9-822C-57AB57BCED1C")
+IUnoTypeWrapper: public IUnknown
+{
+ STDMETHOD(put_Name)(BSTR val) = 0;
+ STDMETHOD(get_Name)(BSTR* pVal) = 0;
+
+protected:
+ ~IUnoTypeWrapper() {}
+};
+
+
+/* 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 000000000..8fc371c4c
--- /dev/null
+++ b/extensions/source/ole/jscriptclasses.cxx
@@ -0,0 +1,312 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "jscriptclasses.hxx"
+
+
+// JScriptValue
+
+JScriptValue::JScriptValue(): m_bOutParam(false), m_bInOutParam(false)
+{
+}
+
+JScriptValue::~JScriptValue()
+{
+}
+
+
+// JScriptValue, IDispatch --------------------------------------------
+COM_DECLSPEC_NOTHROW STDMETHODIMP JScriptValue::GetTypeInfoCount(UINT* /*pctinfo*/)
+{
+ return E_NOTIMPL;
+}
+
+// JScriptValue, IDispatch --------------------------------------------
+COM_DECLSPEC_NOTHROW STDMETHODIMP JScriptValue::GetTypeInfo( UINT /*iTInfo*/,
+ LCID /*lcid*/,
+ ITypeInfo** /*ppTInfo*/)
+{
+ return E_NOTIMPL;
+}
+
+// JScriptValue, IDispatch --------------------------------------------
+COM_DECLSPEC_NOTHROW 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 --------------------------------------------
+COM_DECLSPEC_NOTHROW 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-----------------------
+COM_DECLSPEC_NOTHROW STDMETHODIMP JScriptValue::Set( VARIANT type, VARIANT value)
+{
+ Lock();
+ m_varValue.Clear();
+ HRESULT 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-----------------------
+COM_DECLSPEC_NOTHROW STDMETHODIMP JScriptValue::Get( VARIANT *val)
+{
+ Lock();
+ if( !val)
+ return E_POINTER;
+ HRESULT hr= VariantCopy( val, &m_varValue);
+ Unlock();
+ return hr;
+}
+
+COM_DECLSPEC_NOTHROW STDMETHODIMP JScriptValue::InitOutParam()
+{
+ Lock();
+ m_varValue.Clear();
+ m_bOutParam= true;
+ m_bInOutParam= false;
+ Unlock();
+ return S_OK;
+}
+
+COM_DECLSPEC_NOTHROW STDMETHODIMP JScriptValue::InitInOutParam( VARIANT type, VARIANT value)
+{
+ Lock();
+ m_bInOutParam= true;
+ m_bOutParam= false;
+ Unlock();
+ return Set( type, value);
+}
+
+COM_DECLSPEC_NOTHROW STDMETHODIMP JScriptValue::IsOutParam( VARIANT_BOOL * flag)
+{
+ Lock();
+ if( !flag)
+ return E_POINTER;
+ *flag= m_bOutParam ? VARIANT_TRUE : VARIANT_FALSE;
+ Unlock();
+ return S_OK;
+}
+
+COM_DECLSPEC_NOTHROW STDMETHODIMP JScriptValue::IsInOutParam( VARIANT_BOOL * flag)
+{
+ Lock();
+ if( !flag)
+ return E_POINTER;
+ *flag= m_bInOutParam ? VARIANT_TRUE : VARIANT_FALSE;
+ Unlock();
+ return S_OK;
+}
+
+COM_DECLSPEC_NOTHROW 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 --------------------------------------------
+COM_DECLSPEC_NOTHROW STDMETHODIMP JScriptOutParam::GetTypeInfoCount(UINT* /*pctinfo*/)
+{
+ return E_NOTIMPL;
+}
+
+// JScriptOutParam, IDispatch --------------------------------------------
+COM_DECLSPEC_NOTHROW STDMETHODIMP JScriptOutParam::GetTypeInfo( UINT /*iTInfo*/,
+ LCID /*lcid*/,
+ ITypeInfo** /*ppTInfo*/)
+{
+ return E_NOTIMPL;
+}
+
+// JScriptOutParam, IDispatch --------------------------------------------
+COM_DECLSPEC_NOTHROW 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 --------------------------------------------
+COM_DECLSPEC_NOTHROW 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 000000000..cef993ed0
--- /dev/null
+++ b/extensions/source/ole/jscriptclasses.hxx
@@ -0,0 +1,147 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "wincrap.hxx"
+
+#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 retrieved 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)
+#if defined __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Winconsistent-missing-override"
+#endif
+ END_COM_MAP()
+#if defined __clang__
+#pragma clang diagnostic pop
+#endif
+
+ // IDispatch -------------------------------------------
+ STDMETHOD( GetTypeInfoCount)(UINT *pctinfo) override;
+
+ STDMETHOD( GetTypeInfo)( UINT iTInfo,
+ LCID lcid,
+ ITypeInfo **ppTInfo) override;
+
+ STDMETHOD( GetIDsOfNames)( REFIID riid,
+ LPOLESTR *rgszNames,
+ UINT cNames,
+ LCID lcid,
+ DISPID *rgDispId) override;
+
+ STDMETHOD( Invoke)( DISPID dispIdMember,
+ REFIID riid,
+ LCID lcid,
+ WORD wFlags,
+ DISPPARAMS *pDispParams,
+ VARIANT *pVarResult,
+ EXCEPINFO *pExcepInfo,
+ UINT *puArgErr) override;
+ // IJScriptOutParam --------------------------------------
+
+ STDMETHOD( Set)( VARIANT type, VARIANT value) override;
+ STDMETHOD( Get)( VARIANT *val) override;
+ STDMETHOD( InitOutParam)() override;
+ STDMETHOD( InitInOutParam)( VARIANT type, VARIANT value) override;
+ STDMETHOD( IsOutParam)( VARIANT_BOOL * flag) override;
+ STDMETHOD( IsInOutParam)( VARIANT_BOOL * flag) override;
+ STDMETHOD( GetValue)( BSTR* type, VARIANT *value) override;
+
+
+ CComVariant m_varValue;
+ CComBSTR m_bstrType;
+ bool m_bOutParam: 1;
+ bool 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)
+#if defined __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Winconsistent-missing-override"
+#endif
+ END_COM_MAP()
+#if defined __clang__
+#pragma clang diagnostic pop
+#endif
+
+ // IDispatch -------------------------------------------
+ STDMETHOD( GetTypeInfoCount)(UINT *pctinfo) override;
+
+ STDMETHOD( GetTypeInfo)( UINT iTInfo,
+ LCID lcid,
+ ITypeInfo **ppTInfo) override;
+
+ STDMETHOD( GetIDsOfNames)( REFIID riid,
+ LPOLESTR *rgszNames,
+ UINT cNames,
+ LCID lcid,
+ DISPID *rgDispId) override;
+
+ STDMETHOD( Invoke)( DISPID dispIdMember,
+ REFIID riid,
+ LCID lcid,
+ WORD wFlags,
+ DISPPARAMS *pDispParams,
+ VARIANT *pVarResult,
+ EXCEPINFO *pExcepInfo,
+ UINT *puArgErr) override;
+
+
+private:
+ CComVariant m_varValue;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/ole/ole2uno.cxx b/extensions/source/ole/ole2uno.cxx
new file mode 100644
index 000000000..f9eef5125
--- /dev/null
+++ b/extensions/source/ole/ole2uno.cxx
@@ -0,0 +1,47 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <osl/getglobalmutex.hxx>
+#include <rtl/instance.hxx>
+#include "ole2uno.hxx"
+
+using namespace osl;
+
+namespace {
+
+struct MutexInit
+{
+ Mutex * operator () ()
+ {
+ static Mutex aInstance;
+ return &aInstance;
+ }
+};
+
+}
+
+Mutex * getBridgeMutex()
+{
+ return rtl_Instance< Mutex, MutexInit, ::osl::MutexGuard,
+ ::osl::GetGlobalMutex >::create(
+ MutexInit(), ::osl::GetGlobalMutex());
+}
+
+/* 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 000000000..5fcf2fd96
--- /dev/null
+++ b/extensions/source/ole/ole2uno.hxx
@@ -0,0 +1,70 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "wincrap.hxx"
+
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/lang/XSingleServiceFactory.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/typeprovider.hxx>
+#include <cppuhelper/factory.hxx>
+#include <sal/types.h>
+#include <typelib/typeclass.h>
+#include <osl/diagnose.h>
+#include <osl/mutex.hxx>
+#include <rtl/process.h>
+#include <rtl/uuid.h>
+
+#define UNO_2_OLE_EXCEPTIONCODE 1001
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::registry;
+using namespace com::sun::star::reflection;
+using namespace com::sun::star::beans;
+using namespace osl;
+
+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();
+
+class BridgeRuntimeError
+{
+public:
+ explicit BridgeRuntimeError(const OUString& sMessage)
+ : message(sMessage)
+ {
+ }
+ OUString message;
+};
+
+Mutex* getBridgeMutex();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/ole/oleautobridge.component b/extensions/source/ole/oleautobridge.component
new file mode 100644
index 000000000..09f7621c2
--- /dev/null
+++ b/extensions/source/ole/oleautobridge.component
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ -->
+
+<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@"
+ prefix="oleautobridge" xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="com.sun.star.comp.ole.OleClient">
+ <service name="com.sun.star.bridge.OleObjectFactory"/>
+ <service name="com.sun.star.bridge.oleautomation.Factory"/>
+ </implementation>
+ <implementation name="com.sun.star.comp.ole.OleConverter2">
+ <service name="com.sun.star.bridge.OleBridgeSupplier2"/>
+ <service name="com.sun.star.bridge.oleautomation.BridgeSupplier"/>
+ </implementation>
+ <implementation name="com.sun.star.comp.ole.OleConverterVar1">
+ <service name="com.sun.star.bridge.OleBridgeSupplierVar1"/>
+ </implementation>
+ <implementation name="com.sun.star.comp.ole.OleServer">
+ <service name="com.sun.star.bridge.OleApplicationRegistration"/>
+ <service name="com.sun.star.bridge.oleautomation.ApplicationRegistration"/>
+ </implementation>
+</component>
diff --git a/extensions/source/ole/oledll.cxx b/extensions/source/ole/oledll.cxx
new file mode 100644
index 000000000..1275f4dc6
--- /dev/null
+++ b/extensions/source/ole/oledll.cxx
@@ -0,0 +1,70 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#define STRICT
+#define _WIN32_DCOM
+
+#if defined __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wall"
+#pragma clang diagnostic ignored "-Wattributes"
+#pragma clang diagnostic ignored "-Wdelete-incomplete"
+#pragma clang diagnostic ignored "-Wextra"
+#pragma clang diagnostic ignored "-Wint-to-pointer-cast"
+#pragma clang diagnostic ignored "-Winvalid-noreturn"
+#pragma clang diagnostic ignored "-Wmicrosoft"
+#pragma clang diagnostic ignored "-Wnon-pod-varargs"
+#pragma clang diagnostic ignored "-Wnon-virtual-dtor"
+#endif
+
+#include <atlbase.h>
+static CComModule _Module;
+#include <atlcom.h>
+
+#if defined __clang__
+#pragma clang diagnostic pop
+#endif
+
+BEGIN_OBJECT_MAP(ObjectMap)
+#if defined __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wmissing-field-initializers"
+#endif
+END_OBJECT_MAP()
+#if defined __clang__
+#pragma clang diagnostic pop
+#endif
+
+// DLL Entry Point
+
+extern "C" BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/)
+{
+ if (dwReason == DLL_PROCESS_ATTACH)
+ {
+ _Module.Init(ObjectMap, hInstance);
+ 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 000000000..85f410c54
--- /dev/null
+++ b/extensions/source/ole/oleobjw.cxx
@@ -0,0 +1,2513 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "ole2uno.hxx"
+#include <sal/log.hxx>
+#include <o3tl/char16_t2wchar_t.hxx>
+
+#include <osl/diagnose.h>
+#include <osl/doublecheckedlocking.h>
+#include <osl/thread.h>
+
+#include <memory>
+#include <string_view>
+#include <com/sun/star/script/CannotConvertException.hpp>
+#include <com/sun/star/script/FailReason.hpp>
+#include <com/sun/star/beans/XMaterialHolder.hpp>
+#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
+#include <com/sun/star/script/XInvocation.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 <cppuhelper/exc_hlp.hxx>
+
+#include <typelib/typedescription.hxx>
+#include <rtl/uuid.h>
+#include <rtl/ustring.hxx>
+
+#include "jscriptclasses.hxx"
+
+#include "oleobjw.hxx"
+#include "unoobjw.hxx"
+#include <stdio.h>
+using namespace osl;
+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;
+using namespace ::com::sun::star;
+
+
+#define JSCRIPT_ID_PROPERTY L"_environment"
+#define JSCRIPT_ID L"jscript"
+
+// 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.
+std::unordered_map<sal_uIntPtr, sal_uIntPtr> 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 AdapterToWrapperMap 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.
+std::unordered_map<sal_uIntPtr,sal_uIntPtr> WrapperToAdapterMap;
+
+std::unordered_map<sal_uIntPtr, WeakReference<XInterface> > ComPtrToWrapperMap;
+
+IUnknownWrapper::IUnknownWrapper( Reference<XMultiServiceFactory> const & xFactory,
+ sal_uInt8 unoWrapperClass, sal_uInt8 comWrapperClass):
+ UnoConversionUtilities<IUnknownWrapper>( xFactory, unoWrapperClass, comWrapperClass),
+ m_pxIdlClass( nullptr), m_eJScript( JScriptUndefined),
+ m_bComTlbIndexInit(false), m_bHasDfltMethod(false), m_bHasDfltProperty(false)
+{
+}
+
+
+IUnknownWrapper::~IUnknownWrapper()
+{
+ o2u_attachCurrentThread();
+ MutexGuard guard(getBridgeMutex());
+ XInterface * xIntRoot = static_cast<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
+ auto it= WrapperToAdapterMap.find( reinterpret_cast<sal_uIntPtr>(xIntRoot));
+ if( it != WrapperToAdapterMap.end())
+ {
+ sal_uIntPtr adapter= it->second;
+
+ AdapterToWrapperMap.erase( adapter);
+ WrapperToAdapterMap.erase( it);
+ }
+
+ auto it_c= ComPtrToWrapperMap.find( reinterpret_cast<sal_uIntPtr>(m_spUnknown.p));
+ if(it_c != ComPtrToWrapperMap.end())
+ ComPtrToWrapperMap.erase(it_c);
+}
+
+Any IUnknownWrapper::queryInterface(const Type& t)
+{
+ if (t == cppu::UnoType<XDefaultMethod>::get() && !m_bHasDfltMethod )
+ return Any();
+ if (t == cppu::UnoType<XDefaultProperty>::get() && !m_bHasDfltProperty )
+ return Any();
+ if ( ( t == cppu::UnoType<XInvocation>::get() || t == cppu::UnoType<XAutomationInvocation>::get() ) && !m_spDispatch)
+ return Any();
+ // XDirectInvocation seems to be an oracle replacement for XAutomationInvocation, however it is flawed especially wrt. assumptions about whether to invoke a
+ // Put or Get property, the implementation code has no business guessing that, it's up to the caller to decide that. Worse XDirectInvocation duplicates lots of code.
+ // XAutomationInvocation provides separate calls for put& get
+ // properties. Note: Currently the basic runtime doesn't call put properties directly, it should... after all the basic runtime should know whether it is calling a put or get property.
+ // For the moment for ease of merging we will let the XDirectInvoke and XAuthomationInvocation interfaces stay side by side (and for the moment at least I would prefer the basic
+ // runtime to call XAutomationInvocation instead of XDirectInvoke
+ return WeakImplHelper<XBridgeSupplier2,
+ XInitialization, XAutomationObject, XDefaultProperty, XDefaultMethod, XDirectInvocation, XAutomationInvocation >::queryInterface(t);
+}
+
+Reference<XIntrospectionAccess> SAL_CALL IUnknownWrapper::getIntrospection()
+{
+ Reference<XIntrospectionAccess> ret;
+
+ return ret;
+}
+
+Any SAL_CALL IUnknownWrapper::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("[automation bridge]Property \"" + aPropertyName +
+ "\" is not supported");
+ throw UnknownPropertyException(msg);
+ }
+ aResult = invokeWithDispIdComTlb( aDescGet, aPropertyName, aParams, aOutParamIndex, aOutParam );
+ }
+ catch ( const Exception& e )
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw css::lang::WrappedTargetRuntimeException("[automation bridge] unexpected exception in "
+ "IUnknownWrapper::invokeGetProperty ! Message : \n " +
+ e.Message,
+ nullptr, anyEx );
+ }
+ return aResult;
+}
+
+Any SAL_CALL IUnknownWrapper::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("[automation bridge]Property \"" + aPropertyName +
+ "\" is not supported");
+ throw UnknownPropertyException(msg);
+ }
+ aResult = invokeWithDispIdComTlb( aDescPut, aPropertyName, aParams, aOutParamIndex, aOutParam );
+ }
+ catch ( const Exception& e )
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw css::lang::WrappedTargetRuntimeException("[automation bridge] unexpected exception in "
+ "IUnknownWrapper::invokePutProperty ! Message : \n" +
+ e.Message,
+ nullptr, anyEx );
+ }
+ return aResult;
+}
+
+
+Any SAL_CALL IUnknownWrapper::invoke( const OUString& aFunctionName,
+ const Sequence< Any >& aParams, Sequence< sal_Int16 >& aOutParamIndex,
+ Sequence< Any >& aOutParam )
+{
+ if ( ! m_spDispatch )
+ {
+ throw RuntimeException(
+ "[automation bridge] The object does not have an IDispatch interface");
+ }
+
+ 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 (const IllegalArgumentException &)
+ {
+ throw;
+ }
+ catch (const CannotConvertException &)
+ {
+ throw;
+ }
+ catch (const BridgeRuntimeError & e)
+ {
+ throw RuntimeException(e.message);
+ }
+ catch (const Exception & e)
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw css::lang::WrappedTargetRuntimeException("[automation bridge] unexpected exception in "
+ "IUnknownWrapper::invoke ! Message : \n" +
+ e.Message,
+ nullptr, anyEx );
+
+ }
+ catch(...)
+ {
+ throw RuntimeException("[automation bridge] unexpected exception in "
+ "IUnknownWrapper::Invoke !");
+ }
+ return ret;
+}
+
+void SAL_CALL IUnknownWrapper::setValue( const OUString& aPropertyName,
+ const Any& aValue )
+{
+ if ( ! m_spDispatch )
+ {
+ throw RuntimeException(
+ "[automation bridge] The object does not have an IDispatch interface");
+ }
+ 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("[automation bridge]Property \"" + aPropertyName +
+ "\" is not supported");
+ throw UnknownPropertyException(msg);
+ }
+
+ if ( (! aDescPut && aDescGet)
+ || (aVarDesc && aVarDesc->wVarFlags == VARFLAG_FREADONLY) )
+ {
+ //read-only
+ SAL_WARN( "extensions.olebridge", "[automation bridge] Property " << aPropertyName << " is read-only");
+ // 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("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("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("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("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 (const CannotConvertException &)
+ {
+ throw;
+ }
+ catch (const UnknownPropertyException &)
+ {
+ throw;
+ }
+ catch (const BridgeRuntimeError& e)
+ {
+ throw RuntimeException(e.message);
+ }
+ catch (const Exception & e)
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw css::lang::WrappedTargetRuntimeException("[automation bridge] unexpected exception in "
+ "IUnknownWrapper::setValue ! Message : \n" +
+ e.Message,
+ nullptr, anyEx );
+
+ }
+ catch (...)
+ {
+ throw RuntimeException(
+ "[automation bridge] unexpected exception in "
+ "IUnknownWrapper::setValue !");
+ }
+}
+
+Any SAL_CALL IUnknownWrapper::getValue( const OUString& aPropertyName )
+{
+ if ( ! m_spDispatch )
+ {
+ throw RuntimeException(
+ "[automation bridge] The object does not have an IDispatch interface");
+ }
+ 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 a 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 == "$GetTypeName" )
+ {
+ if ( pInfo && m_sTypeName.getLength() == 0 )
+ {
+ m_sTypeName = "IDispatch";
+ CComBSTR sName;
+
+ if ( SUCCEEDED( pInfo->GetDocumentation( -1, &sName, nullptr, nullptr, nullptr ) ) )
+ {
+ OUString sTmp( o3tl::toU(LPCOLESTR(sName)));
+ if ( sTmp.startsWith("_") )
+ sTmp = sTmp.copy(1);
+ // do we own the memory for pTypeLib, msdn doc 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, nullptr, nullptr, nullptr ) ) )
+ {
+ OUString sLibName( o3tl::toU(LPCOLESTR(sName)));
+ m_sTypeName = sLibName + "." + 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("[automation bridge]Property \"" + aPropertyName +
+ "\" is not supported");
+ throw UnknownPropertyException(msg);
+ }
+ // write-only should not be possible
+ OSL_ASSERT( aDescGet || ! aDescPut);
+
+ HRESULT hr;
+ DISPPARAMS dispparams = {nullptr, nullptr, 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:
+ case DISP_E_BADVARTYPE:
+ case DISP_E_EXCEPTION:
+ throw RuntimeException(OUString(o3tl::toU(excepinfo.bstrDescription)));
+ break;
+ case DISP_E_MEMBERNOTFOUND:
+ throw UnknownPropertyException(OUString(o3tl::toU(excepinfo.bstrDescription)));
+ break;
+ default:
+ throw RuntimeException(OUString(o3tl::toU(excepinfo.bstrDescription)));
+ break;
+ }
+ }
+ catch ( const UnknownPropertyException& )
+ {
+ throw;
+ }
+ catch (const BridgeRuntimeError& e)
+ {
+ throw RuntimeException(e.message);
+ }
+ catch (const Exception & e)
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw css::lang::WrappedTargetRuntimeException("[automation bridge] unexpected exception in "
+ "IUnknownWrapper::getValue ! Message : \n" +
+ e.Message,
+ nullptr, anyEx );
+ }
+ catch (...)
+ {
+ throw RuntimeException(
+ "[automation bridge] unexpected exception in "
+ "IUnknownWrapper::getValue !");
+ }
+ return ret;
+}
+
+sal_Bool SAL_CALL IUnknownWrapper::hasMethod( const OUString& aName )
+{
+ if ( ! m_spDispatch )
+ {
+ throw RuntimeException(
+ "[automation bridge] The object does not have an IDispatch interface");
+ }
+ bool ret = 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 = true;
+ }
+ else
+ ret = true;
+ }
+ catch (const BridgeRuntimeError& e)
+ {
+ throw RuntimeException(e.message);
+ }
+ catch (const Exception & e)
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw css::lang::WrappedTargetRuntimeException("[automation bridge] unexpected exception in "
+ "IUnknownWrapper::hasMethod ! Message : \n" +
+ e.Message,
+ nullptr, anyEx );
+ }
+ catch (...)
+ {
+ throw RuntimeException("[automation bridge] unexpected exception in "
+ "IUnknownWrapper::hasMethod !");
+ }
+ return ret;
+}
+
+sal_Bool SAL_CALL IUnknownWrapper::hasProperty( const OUString& aName )
+{
+ if ( ! m_spDispatch )
+ {
+ throw RuntimeException("[automation bridge] The object does not have an "
+ "IDispatch interface");
+ }
+ bool ret = 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 func kind
+ // basic has been modified to handle properties ( 'get' ) props at
+ // least with parameters
+ // 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 = true;
+ }
+ }
+ catch (const BridgeRuntimeError& e)
+ {
+ throw RuntimeException(e.message);
+ }
+ catch (const Exception & e)
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw css::lang::WrappedTargetRuntimeException("[automation bridge] unexpected exception in "
+ "IUnknownWrapper::hasProperty ! Message : \n" +
+ e.Message,
+ nullptr, anyEx );
+
+ }
+ catch (...)
+ {
+ throw RuntimeException("[automation bridge] unexpected exception in "
+ "IUnknownWrapper::hasProperty !");
+ }
+ return ret;
+}
+
+Any SAL_CALL IUnknownWrapper::createBridge( const Any& modelDepObject,
+ const Sequence< sal_Int8 >& /*aProcessId*/, sal_Int16 sourceModelType,
+ sal_Int16 destModelType )
+{
+ Any ret;
+ o2u_attachCurrentThread();
+
+ if (
+ (sourceModelType == UNO) &&
+ (destModelType == OLE) &&
+ (modelDepObject.getValueTypeClass() == TypeClass_INTERFACE)
+ )
+ {
+ Reference<XInterface> xInt( *static_cast<XInterface* const *>(modelDepObject.getValue()));
+ Reference<XInterface> xSelf( static_cast<OWeakObject*>(this));
+
+ if (xInt == xSelf)
+ {
+ VARIANT* pVariant = static_cast<VARIANT*>(CoTaskMemAlloc(sizeof(VARIANT)));
+
+ VariantInit(pVariant);
+ if (m_bOriginalDispatch)
+ {
+ 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(static_cast<void*>(&pVariant), cppu::UnoType<sal_uIntPtr>::get());
+ }
+ }
+
+ return ret;
+}
+/** @internal
+ @exception IllegalArgumentException
+ @exception CannotConvertException
+ @exception InvocationTargetException
+ @RuntimeException
+*/
+Any IUnknownWrapper::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= nullptr;
+ 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.
+ bool bJScriptObject= isJScriptObject();
+ std::unique_ptr<CComVariant[]> sarParams;
+ std::unique_ptr<CComVariant[]> sarParamsRef;
+ CComVariant *pVarParams= nullptr;
+ CComVariant *pVarParamsRef= nullptr;
+ bool bConvRet= true;
+
+ if( methodDesc.is())
+ {
+ pMethod = reinterpret_cast<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 && ! pMethod->pParams[i].bOut)
+ {
+ anyToVariant( &pVarParams[parameterCount - i -1], Params.getConstArray()[i]);
+ }
+ // Out parameter + in/out parameter
+ else if( pMethod->pParams[i].bOut )
+ {
+ CComVariant var;
+ if(pMethod->pParams[i].bIn)
+ {
+ anyToVariant( & var,Params[i]);
+ pVarParamsRef[outParamIndex] = var;
+ }
+
+ switch( pMethod->pParams[i].pTypeRef->eTypeClass)
+ {
+ case typelib_TypeClass_INTERFACE:
+ case typelib_TypeClass_STRUCT:
+ if( ! pMethod->pParams[i].bIn)
+ {
+ pVarParamsRef[ outParamIndex].vt= VT_DISPATCH;
+ pVarParamsRef[ outParamIndex].pdispVal= nullptr;
+ }
+ pVarParams[parameterCount - i -1].vt = VT_DISPATCH | VT_BYREF;
+ pVarParams[parameterCount - i -1].ppdispVal= &pVarParamsRef[outParamIndex].pdispVal;
+ break;
+ case typelib_TypeClass_ENUM:
+ case typelib_TypeClass_LONG:
+ case typelib_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 typelib_TypeClass_SEQUENCE:
+ if( ! pMethod->pParams[i].bIn)
+ {
+ pVarParamsRef[ outParamIndex].vt = VT_ARRAY| VT_VARIANT;
+ pVarParamsRef[ outParamIndex].parray= nullptr;
+ }
+ pVarParams[parameterCount - i -1].vt = VT_ARRAY| VT_BYREF | VT_VARIANT;
+ pVarParams[parameterCount - i -1].pparray= &pVarParamsRef[outParamIndex].parray;
+ break;
+ case typelib_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 typelib_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 typelib_TypeClass_STRING:
+ if( ! pMethod->pParams[i].bIn)
+ {
+ pVarParamsRef[ outParamIndex].vt = VT_BSTR;
+ pVarParamsRef[ outParamIndex].bstrVal= nullptr;
+ }
+ pVarParams[parameterCount - i -1].vt = VT_BSTR| VT_BYREF;
+ pVarParams[parameterCount - i -1].pbstrVal=
+ & pVarParamsRef[outParamIndex].bstrVal;
+ break;
+
+ case typelib_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 typelib_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 typelib_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 typelib_TypeClass_CHAR:
+ case typelib_TypeClass_SHORT:
+ case typelib_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 a JScriptObject
+ {
+ int i = 0;
+ try
+ {
+ for( ; i< parameterCount; i++)
+ {
+ // In parameter
+ if( pMethod->pParams[i].bIn && ! pMethod->pParams[i].bOut)
+ {
+ anyToVariant( &pVarParams[parameterCount - i -1], Params.getConstArray()[i]);
+ }
+ // Out parameter + in/out parameter
+ else if( pMethod->pParams[i].bOut )
+ {
+ CComObject<JScriptOutParam>* pParamObject;
+ if( !SUCCEEDED( CComObject<JScriptOutParam>::CreateInstance( &pParamObject)))
+ {
+ throw BridgeRuntimeError(
+ "[automation bridge]IUnknownWrapper::"
+ "invokeWithDispIdUnoTlb\n"
+ "Could not create out parameter at index: " +
+ OUString::number(static_cast<sal_Int32>(i)));
+ }
+
+ CComPtr<IUnknown> pUnk(pParamObject->GetUnknown());
+ CComQIPtr<IDispatch> pDisp( pUnk);
+
+ pVarParams[ parameterCount - i -1].vt= VT_DISPATCH;
+ pVarParams[ parameterCount - i -1].pdispVal= pDisp;
+ pVarParams[ parameterCount - i -1].pdispVal->AddRef();
+ // if the param is in/out then put the parameter on index 0
+ if( pMethod->pParams[i].bIn ) // in / out
+ {
+ CComVariant varParam;
+ anyToVariant( &varParam, Params.getConstArray()[i]);
+ CComDispatchDriver dispDriver( pDisp);
+ if(FAILED( dispDriver.PutPropertyByName( L"0", &varParam)))
+ throw BridgeRuntimeError(
+ "[automation bridge]IUnknownWrapper::"
+ "invokeWithDispIdUnoTlb\n"
+ "Could not set property \"0\" for the in/out "
+ "param!");
+
+ }
+ }
+ }
+ }
+ 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(false);
+ }
+
+
+ CComVariant varResult;
+ ExcepInfo excepinfo;
+ unsigned int uArgErr;
+ DISPPARAMS dispparams= { pVarParams, nullptr, static_cast<UINT>(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);
+ auto pOutParamIndex = OutParamIndex.getArray();
+ OutParam.realloc( outParameterCount);
+ auto pOutParam = OutParam.getArray();
+ sal_Int32 outIndex=0;
+ int i = 0;
+ try
+ {
+ for( ; i < parameterCount; i++)
+ {
+ if( pMethod->pParams[i].bOut )
+ {
+ pOutParamIndex[outIndex]= static_cast<sal_Int16>(i);
+ Any outAny;
+ if( !bJScriptObject)
+ {
+ variantToAny( &pVarParamsRef[outIndex], outAny,
+ Type(pMethod->pParams[i].pTypeRef), false);
+ pOutParam[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), false);
+ pOutParam[outParameterCount - 1 - outIndex++]= outAny;
+ }
+ else
+ bConvRet= false;
+ }
+ else
+ bConvRet= false;
+ }
+ else
+ bConvRet= 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), false);
+ else
+ variantToAny(&varResult, ret, false);
+ }
+ catch (IllegalArgumentException & e)
+ {
+ e.Message =
+ "[automation bridge]IUnknownWrapper::invokeWithDispIdUnoTlb\n"
+ "Could not convert return value! \n Message: \n" + e.Message;
+ throw;
+ }
+ catch (CannotConvertException & e)
+ {
+ e.Message =
+ "[automation bridge]IUnknownWrapper::invokeWithDispIdUnoTlb\n"
+ "Could not convert return value! \n Message: \n" + e.Message;
+ throw;
+ }
+ }
+ }
+
+ if( !bConvRet) // conversion of return or out parameter failed
+ throw CannotConvertException("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("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("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("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("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::initialize( const Sequence< Any >& aArguments )
+{
+ // 1.parameter is IUnknown
+ // 2.parameter is a boolean which indicates if the COM pointer was an IUnknown or IDispatch
+ // 3.parameter is a Sequence<Type>
+ o2u_attachCurrentThread();
+ OSL_ASSERT(aArguments.getLength() == 3);
+
+ m_spUnknown= *static_cast<IUnknown* const *>(aArguments[0].getValue());
+ m_spUnknown.QueryInterface( & m_spDispatch.p);
+
+ aArguments[1] >>= m_bOriginalDispatch;
+ aArguments[2] >>= m_seqTypes;
+
+ ITypeInfo* pType = nullptr;
+ 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( const BridgeRuntimeError& )
+ {}
+ catch( const Exception& )
+ {}
+
+ if ( pType )
+ {
+ try
+ {
+ // Get Default member
+ CComBSTR defaultMemberName;
+ if ( SUCCEEDED( pType->GetDocumentation(0, &defaultMemberName, nullptr, nullptr, nullptr ) ) )
+ {
+ OUString usName(o3tl::toU(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( "[automation bridge]IUnknownWrapper::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 ( const BridgeRuntimeError & e )
+ {
+ throw RuntimeException( e.message );
+ }
+ catch( const Exception& e )
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw css::lang::WrappedTargetRuntimeException(
+ "[automation bridge] unexpected exception in IUnknownWrapper::initialize() error message: \n" + e.Message,
+ nullptr, anyEx );
+ }
+ }
+}
+
+
+// XDirectInvocation
+uno::Any SAL_CALL IUnknownWrapper::directInvoke( const OUString& aName, const uno::Sequence< uno::Any >& aParams )
+{
+ Any aResult;
+
+ if ( !m_spDispatch )
+ {
+ throw RuntimeException(
+ "[automation bridge] The object does not have an IDispatch interface");
+ }
+
+ o2u_attachCurrentThread();
+ DISPID dispid;
+ if ( !getDispid( aName, &dispid ) )
+ throw IllegalArgumentException(
+ "[automation bridge] The object does not have a function or property "
+ + aName, Reference<XInterface>(), 0);
+
+ CComVariant varResult;
+ ExcepInfo excepinfo;
+ unsigned int uArgErr = 0;
+ INVOKEKIND pInvkinds[2];
+ pInvkinds[0] = INVOKE_FUNC;
+ pInvkinds[1] = aParams.getLength() ? INVOKE_PROPERTYPUT : INVOKE_PROPERTYGET;
+ HRESULT hInvRes = E_FAIL;
+
+ // try Invoke first, if it does not work, try put/get property
+ for ( sal_Int32 nStep = 0; FAILED( hInvRes ) && nStep < 2; nStep++ )
+ {
+ DISPPARAMS dispparams = {nullptr, nullptr, 0, 0};
+
+ std::unique_ptr<DISPID[]> arDispidNamedArgs;
+ std::unique_ptr<CComVariant[]> ptrArgs;
+ std::unique_ptr<CComVariant[]> ptrRefArgs; // referenced arguments
+ CComVariant * arArgs = nullptr;
+ CComVariant * arRefArgs = nullptr;
+
+ dispparams.cArgs = aParams.getLength();
+
+ // Determine the number of named arguments
+ for ( uno::Any const & any : aParams )
+ if ( any.getValueType() == cppu::UnoType<NamedArgument>::get() )
+ dispparams.cNamedArgs ++;
+
+ // fill the named arguments
+ if ( dispparams.cNamedArgs > 0
+ && ( dispparams.cNamedArgs != 1 || pInvkinds[nStep] != INVOKE_PROPERTYPUT ) )
+ {
+ int nSizeAr = dispparams.cNamedArgs + 1;
+ if ( pInvkinds[nStep] == INVOKE_PROPERTYPUT )
+ nSizeAr = dispparams.cNamedArgs;
+
+ std::unique_ptr<OLECHAR*[]> saNames(new OLECHAR*[nSizeAr]);
+ OLECHAR ** pNames = saNames.get();
+ pNames[0] = const_cast<OLECHAR*>(o3tl::toW(aName.getStr()));
+
+ int cNamedArg = 0;
+ for ( size_t nInd = 0; nInd < dispparams.cArgs; nInd++ )
+ {
+ if (auto v = o3tl::tryAccess<NamedArgument>(aParams[nInd]))
+ {
+ const NamedArgument& arg = *v;
+
+ //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
+ pNames[nSizeAr - 1 - cNamedArg++] = const_cast<OLECHAR*>(o3tl::toW(arg.Name.getStr()));
+ }
+ }
+
+ arDispidNamedArgs.reset( new DISPID[nSizeAr] );
+ HRESULT hr = getTypeInfo()->GetIDsOfNames( pNames, nSizeAr, arDispidNamedArgs.get() );
+ if ( hr == E_NOTIMPL )
+ hr = m_spDispatch->GetIDsOfNames(IID_NULL, pNames, nSizeAr, LOCALE_USER_DEFAULT, arDispidNamedArgs.get() );
+
+ if ( SUCCEEDED( hr ) )
+ {
+ if ( pInvkinds[nStep] == DISPATCH_PROPERTYPUT )
+ {
+ DISPID* arIDs = arDispidNamedArgs.get();
+ arIDs[0] = DISPID_PROPERTYPUT;
+ dispparams.rgdispidNamedArgs = arIDs;
+ }
+ else
+ {
+ DISPID* arIDs = arDispidNamedArgs.get();
+ dispparams.rgdispidNamedArgs = & arIDs[1];
+ }
+ }
+ else if (hr == DISP_E_UNKNOWNNAME)
+ {
+ throw IllegalArgumentException(
+ "[automation bridge]One of the named arguments is wrong!",
+ Reference<XInterface>(), 0);
+ }
+ else
+ {
+ throw InvocationTargetException(
+ "[automation bridge] ITypeInfo::GetIDsOfNames returned error "
+ + OUString::number(static_cast<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();
+
+ sal_Int32 nInd = 0;
+ try
+ {
+ sal_Int32 revIndex = 0;
+ for ( nInd = 0; nInd < sal_Int32(dispparams.cArgs); nInd++)
+ {
+ revIndex = dispparams.cArgs - nInd - 1;
+ arRefArgs[revIndex].byref = nullptr;
+ Any anyArg;
+ if ( nInd < aParams.getLength() )
+ anyArg = aParams.getConstArray()[nInd];
+
+ // Property Put arguments
+ if ( anyArg.getValueType() == cppu::UnoType<PropertyPutArgument>::get() )
+ {
+ PropertyPutArgument arg;
+ anyArg >>= arg;
+ anyArg = arg.Value;
+ }
+ // named argument
+ if (anyArg.getValueType() == cppu::UnoType<NamedArgument>::get())
+ {
+ NamedArgument aNamedArgument;
+ anyArg >>= aNamedArgument;
+ anyArg = aNamedArgument.Value;
+ }
+
+ if ( nInd < aParams.getLength() && anyArg.getValueTypeClass() != TypeClass_VOID )
+ {
+ anyToVariant( &arArgs[revIndex], anyArg, VT_VARIANT );
+ }
+ else
+ {
+ arArgs[revIndex].vt = VT_ERROR;
+ arArgs[revIndex].scode = DISP_E_PARAMNOTFOUND;
+ }
+ }
+ }
+ catch (IllegalArgumentException & e)
+ {
+ e.ArgumentPosition = ::sal::static_int_cast< sal_Int16, sal_Int32 >( nInd );
+ throw;
+ }
+ catch (CannotConvertException & e)
+ {
+ e.ArgumentIndex = nInd;
+ throw;
+ }
+
+ dispparams.rgvarg = arArgs;
+ // invoking OLE method
+ hInvRes = m_spDispatch->Invoke( dispid,
+ IID_NULL,
+ LOCALE_USER_DEFAULT,
+ ::sal::static_int_cast< WORD, INVOKEKIND >( pInvkinds[nStep] ),
+ &dispparams,
+ &varResult,
+ &excepinfo,
+ &uArgErr);
+ }
+
+ // converting return value and out parameter back to UNO
+ if ( SUCCEEDED( hInvRes ) )
+ variantToAny( &varResult, aResult, false );
+ else
+ {
+ // map error codes to exceptions
+ OUString message;
+ switch ( hInvRes )
+ {
+ case S_OK:
+ break;
+ case DISP_E_BADPARAMCOUNT:
+ throw IllegalArgumentException("[automation bridge] Wrong "
+ "number of arguments. Object returned DISP_E_BADPARAMCOUNT.",
+ nullptr, 0);
+ break;
+ case DISP_E_BADVARTYPE:
+ throw RuntimeException("[automation bridge] One or more "
+ "arguments have the wrong type. Object returned "
+ "DISP_E_BADVARTYPE.", nullptr);
+ break;
+ case DISP_E_EXCEPTION:
+ message = OUString::Concat("[automation bridge]: ")
+ + std::u16string_view(o3tl::toU(excepinfo.bstrDescription),
+ ::SysStringLen(excepinfo.bstrDescription));
+ throw InvocationTargetException(message, Reference<XInterface>(), Any());
+ break;
+ case DISP_E_MEMBERNOTFOUND:
+ message = "[automation bridge]: A function with the name \""
+ + aName + "\" is not supported. Object returned "
+ "DISP_E_MEMBERNOTFOUND.";
+ throw IllegalArgumentException(message, nullptr, 0);
+ break;
+ case DISP_E_NONAMEDARGS:
+ throw IllegalArgumentException("[automation bridge] Object "
+ "returned DISP_E_NONAMEDARGS",nullptr, ::sal::static_int_cast< sal_Int16, unsigned int >( uArgErr ));
+ break;
+ case DISP_E_OVERFLOW:
+ throw CannotConvertException("[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("[automation bridge]Call failed."
+ "Object returned DISP_E_PARAMNOTFOUND.",
+ nullptr, ::sal::static_int_cast< sal_Int16, unsigned int >( uArgErr ));
+ break;
+ case DISP_E_TYPEMISMATCH:
+ throw CannotConvertException("[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("[automation bridge] Call failed. "
+ "Object returned DISP_E_UNKNOWNINTERFACE.",nullptr);
+ break;
+ case DISP_E_UNKNOWNLCID:
+ throw RuntimeException("[automation bridge] Call failed. "
+ "Object returned DISP_E_UNKNOWNLCID.",nullptr);
+ break;
+ case DISP_E_PARAMNOTOPTIONAL:
+ throw CannotConvertException("[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 aResult;
+}
+
+sal_Bool SAL_CALL IUnknownWrapper::hasMember( const OUString& aName )
+{
+ if ( ! m_spDispatch )
+ {
+ throw RuntimeException(
+ "[automation bridge] The object does not have an IDispatch interface");
+ }
+
+ o2u_attachCurrentThread();
+ DISPID dispid;
+ return getDispid( aName, &dispid );
+}
+
+
+// UnoConversionUtilities --------------------------------------------------------------------------------
+Reference< XInterface > IUnknownWrapper::createUnoWrapperInstance()
+{
+ if( m_nUnoWrapperClass == INTERFACE_OLE_WRAPPER_IMPL)
+ {
+ Reference<XWeak> xWeak= static_cast<XWeak*>( new InterfaceOleWrapper(
+ 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::createComWrapperInstance()
+{
+ Reference<XWeak> xWeak= static_cast<XWeak*>( new IUnknownWrapper(
+ m_smgr, m_nUnoWrapperClass, m_nComWrapperClass));
+ return Reference<XInterface>( xWeak, UNO_QUERY);
+}
+
+
+void IUnknownWrapper::getMethodInfo(std::u16string_view sName, TypeDescription& methodInfo)
+{
+ TypeDescription desc= getInterfaceMemberDescOfCurrentCall(sName);
+ if( desc.is())
+ {
+ typelib_TypeDescription* pMember= desc.get();
+ if( pMember->eTypeClass == typelib_TypeClass_INTERFACE_METHOD )
+ methodInfo= pMember;
+ }
+}
+
+void IUnknownWrapper::getAttributeInfo(std::u16string_view sName, TypeDescription& attributeInfo)
+{
+ TypeDescription desc= getInterfaceMemberDescOfCurrentCall(sName);
+ if( desc.is())
+ {
+ typelib_TypeDescription* pMember= desc.get();
+ if( pMember->eTypeClass == typelib_TypeClass_INTERFACE_ATTRIBUTE )
+ {
+ attributeInfo= reinterpret_cast<typelib_InterfaceAttributeTypeDescription*>(pMember)->pAttributeTypeRef;
+ }
+ }
+}
+TypeDescription IUnknownWrapper::getInterfaceMemberDescOfCurrentCall(std::u16string_view sName)
+{
+ TypeDescription ret;
+
+ for( auto const & rType : std::as_const(m_seqTypes) )
+ {
+ TypeDescription _curDesc( rType );
+ _curDesc.makeComplete();
+ typelib_InterfaceTypeDescription * pInterface= reinterpret_cast<typelib_InterfaceTypeDescription*>(_curDesc.get());
+ if( pInterface)
+ {
+ typelib_InterfaceMemberTypeDescription* pMember= nullptr;
+ //find the member description of the current call
+ for( int j=0; j < pInterface->nAllMembers; j++)
+ {
+ typelib_TypeDescriptionReference* pTypeRefMember = pInterface->ppAllMembers[j];
+ typelib_TypeDescription* pDescMember= nullptr;
+ TYPELIB_DANGER_GET( &pDescMember, pTypeRefMember);
+
+ typelib_InterfaceMemberTypeDescription* pInterfaceMember=
+ reinterpret_cast<typelib_InterfaceMemberTypeDescription*>(pDescMember);
+ if( OUString( pInterfaceMember->pMemberName) == sName)
+ {
+ pMember= pInterfaceMember;
+ break;
+ }
+ TYPELIB_DANGER_RELEASE( pDescMember);
+ }
+
+ if( pMember)
+ {
+ ret= &pMember->aBase;
+ TYPELIB_DANGER_RELEASE( &pMember->aBase);
+ }
+ }
+ if( ret.is())
+ break;
+ }
+ return ret;
+}
+
+bool IUnknownWrapper::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;
+}
+
+
+/** @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::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::invokeWithDispIdComTlb(FuncDesc& aFuncDesc,
+ const OUString& sFuncName,
+ const Sequence< Any >& Params,
+ Sequence< sal_Int16 >& OutParamIndex,
+ Sequence< Any >& OutParam)
+{
+ Any ret;
+ HRESULT result;
+
+ DISPPARAMS dispparams = {nullptr, nullptr, 0, 0};
+ CComVariant varResult;
+ ExcepInfo excepinfo;
+ unsigned int uArgErr;
+ sal_Int32 i = 0;
+ sal_Int32 nUnoArgs = Params.getLength();
+ DISPID idPropertyPut = DISPID_PROPERTYPUT;
+ std::unique_ptr<DISPID[]> arDispidNamedArgs;
+ std::unique_ptr<CComVariant[]> ptrArgs;
+ std::unique_ptr<CComVariant[]> ptrRefArgs; // referenced arguments
+ CComVariant * arArgs = nullptr;
+ CComVariant * arRefArgs = nullptr;
+ sal_Int32 revIndex = 0;
+
+ //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() == cppu::UnoType<NamedArgument>::get())
+ 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 an 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 named 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 too many arguments supplied
+ if (::sal::static_int_cast< sal_uInt32, int >( nUnoArgs ) > dispparams.cArgs)
+ {
+ throw IllegalArgumentException(
+ "[automation bridge] There are too many arguments for this method",
+ Reference<XInterface>(), static_cast<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_PROPERTYPUTREF)))
+ {
+ //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
+ }
+
+ std::unique_ptr<OLECHAR*[]> saNames(new OLECHAR*[nSizeAr]);
+ OLECHAR ** arNames = saNames.get();
+ arNames[0] = const_cast<OLECHAR*>(o3tl::toW(sFuncName.getStr()));
+
+ int cNamedArg = 0;
+ for (size_t iParams = 0; iParams < dispparams.cArgs; iParams ++)
+ {
+ const Any & curArg = Params[iParams];
+ if (auto v = o3tl::tryAccess<NamedArgument>(curArg))
+ {
+ const NamedArgument& arg = *v;
+ //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*>(o3tl::toW(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(
+ "[automation bridge]One of the named arguments is wrong!",
+ Reference<XInterface>(), 0);
+ }
+ else
+ {
+ throw InvocationTargetException(
+ "[automation bridge] ITypeInfo::GetIDsOfNames returned error "
+ + OUString::number(static_cast<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 < static_cast<sal_Int32>(dispparams.cArgs); i++)
+ {
+ revIndex= dispparams.cArgs - i -1;
+ arRefArgs[revIndex].byref=nullptr;
+ Any anyArg;
+ if ( i < nUnoArgs)
+ anyArg= Params.getConstArray()[i];
+
+ unsigned short paramFlags = PARAMFLAG_FOPT | PARAMFLAG_FIN;
+ VARTYPE varType = VT_VARIANT;
+ if (aFuncDesc->cParamsOpt != -1 || aFuncDesc->cParams != (i + 1))
+ {
+ 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
+ // it's a UNO programming error.
+ if (i >= nUnoArgs && !(paramFlags & PARAMFLAG_FOPT))
+ {
+ throw IllegalArgumentException(
+ ("ole automation bridge: The called function expects an argument at position: "
+ + OUString::number(i) + " (index starting at 0)."),
+ Reference<XInterface>(), static_cast<sal_Int16>(i));
+ }
+
+ // Property Put arguments
+ if (anyArg.getValueType() == cppu::UnoType<PropertyPutArgument>::get())
+ {
+ PropertyPutArgument arg;
+ anyArg >>= arg;
+ anyArg = arg.Value;
+ }
+ // named argument
+ if (anyArg.getValueType() == cppu::UnoType<NamedArgument>::get())
+ {
+ 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 default either as direct arg : VT_XXX or
+ VariantCopy( & arArgs[revIndex],
+ & aFuncDesc->lprgelemdescParam[i].paramdesc.
+ pparamdescex->varDefaultValue);
+ }
+ else if (paramFlags & PARAMFLAG_FOPT)
+ {
+ arArgs[revIndex].vt = VT_ERROR;
+ arArgs[revIndex].scode = DISP_E_PARAMNOTFOUND;
+ }
+ else
+ {
+ arArgs[revIndex].vt = VT_EMPTY;
+ arArgs[revIndex].lVal = 0;
+ }
+ }
+ }
+ }
+ 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
+ result = m_spDispatch->Invoke(aFuncDesc->memid,
+ IID_NULL,
+ LOCALE_USER_DEFAULT,
+ ::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 j = 0; j < aFuncDesc->cParams; j++)
+ {
+ if (aFuncDesc->lprgelemdescParam[j].paramdesc.wParamFlags &
+ PARAMFLAG_FOUT)
+ outParamsCount++;
+ }
+
+ OutParamIndex.realloc(outParamsCount);
+ OutParam.realloc(outParamsCount);
+ // Convert out params
+ if (outParamsCount)
+ {
+ auto pOutParamIndex = OutParamIndex.getArray();
+ auto pOutParam = OutParam.getArray();
+ int outParamIndex=0;
+ for (int paramIndex = 0; paramIndex < nUnoArgs; paramIndex ++)
+ {
+ //Determine the index within the method signature
+ int realParamIndex = paramIndex;
+ int revParamIndex = dispparams.cArgs - paramIndex - 1;
+ if (Params[paramIndex].getValueType()
+ == cppu::UnoType<NamedArgument>::get())
+ {
+ //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, false );
+ }
+ catch (IllegalArgumentException & e)
+ {
+ e.ArgumentPosition = static_cast<sal_Int16>(paramIndex);
+ throw;
+ }
+ catch (CannotConvertException & e)
+ {
+ e.ArgumentIndex = paramIndex;
+ throw;
+ }
+ pOutParam[outParamIndex] = outAny;
+ pOutParamIndex[outParamIndex] = ::sal::static_int_cast< sal_Int16, int >( paramIndex );
+ outParamIndex++;
+ }
+ OutParam.realloc(outParamIndex);
+ OutParamIndex.realloc(outParamIndex);
+ }
+ // Return value
+ variantToAny(&varResult, ret, false);
+ }
+
+ // map error codes to exceptions
+ OUString message;
+ switch (result)
+ {
+ case S_OK:
+ break;
+ case DISP_E_BADPARAMCOUNT:
+ throw IllegalArgumentException("[automation bridge] Wrong "
+ "number of arguments. Object returned DISP_E_BADPARAMCOUNT.",
+ nullptr, 0);
+ break;
+ case DISP_E_BADVARTYPE:
+ throw RuntimeException("[automation bridge] One or more "
+ "arguments have the wrong type. Object returned "
+ "DISP_E_BADVARTYPE.", nullptr);
+ break;
+ case DISP_E_EXCEPTION:
+ message = OUString::Concat("[automation bridge]: ")
+ + std::u16string_view(o3tl::toU(excepinfo.bstrDescription),
+ ::SysStringLen(excepinfo.bstrDescription));
+
+ throw InvocationTargetException(message, Reference<XInterface>(), Any());
+ break;
+ case DISP_E_MEMBERNOTFOUND:
+ message = "[automation bridge]: A function with the name \""
+ + sFuncName + "\" is not supported. Object returned "
+ "DISP_E_MEMBERNOTFOUND.";
+ throw IllegalArgumentException(message, nullptr, 0);
+ break;
+ case DISP_E_NONAMEDARGS:
+ throw IllegalArgumentException("[automation bridge] Object "
+ "returned DISP_E_NONAMEDARGS",nullptr, ::sal::static_int_cast< sal_Int16, unsigned int >( uArgErr ));
+ break;
+ case DISP_E_OVERFLOW:
+ throw CannotConvertException("[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("[automation bridge]Call failed."
+ "Object returned DISP_E_PARAMNOTFOUND.",
+ nullptr, ::sal::static_int_cast< sal_Int16, unsigned int >( uArgErr ));
+ break;
+ case DISP_E_TYPEMISMATCH:
+ throw CannotConvertException("[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("[automation bridge] Call failed. "
+ "Object returned DISP_E_UNKNOWNINTERFACE.",nullptr);
+ break;
+ case DISP_E_UNKNOWNLCID:
+ throw RuntimeException("[automation bridge] Call failed. "
+ "Object returned DISP_E_UNKNOWNLCID.",nullptr);
+ break;
+ case DISP_E_PARAMNOTOPTIONAL:
+ throw CannotConvertException("[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::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() == cppu::UnoType<PropertyPutArgument>::get())
+ {
+ // DISPATCH_PROPERTYPUT
+ FuncDesc aDescGet(pInfo);
+ FuncDesc aDescPut(pInfo);
+ VarDesc aVarDesc(pInfo);
+ getPropDesc(sFuncName, & aDescGet, & aDescPut, & aVarDesc);
+ if ( ! aDescPut)
+ {
+ throw IllegalArgumentException(
+ "[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 * pTypeInfo = getTypeInfo();
+ FuncDesc aDescPut(pTypeInfo);
+ VarDesc aVarDesc(pTypeInfo);
+ getPropDesc(sFuncName, & aFuncDesc, & aDescPut, & aVarDesc);
+ if ( ! aFuncDesc )
+ {
+ throw IllegalArgumentException(
+ "[automation bridge] The object does not have a function"
+ " or readable property \""
+ + sFuncName + "\"", Reference<XInterface>(), 0);
+ }
+ }
+ *pFuncDesc = aFuncDesc.Detach();
+ }
+}
+bool IUnknownWrapper::getDispid(const OUString& sFuncName, DISPID * id)
+{
+ OSL_ASSERT(m_spDispatch);
+ LPOLESTR lpsz = const_cast<LPOLESTR> (o3tl::toW(sFuncName.getStr()));
+ HRESULT hr = m_spDispatch->GetIDsOfNames(IID_NULL, &lpsz, 1, LOCALE_USER_DEFAULT, id);
+ return hr == S_OK;
+}
+void IUnknownWrapper::getFuncDesc(const OUString & sFuncName, FUNCDESC ** pFuncDesc)
+
+{
+ OSL_ASSERT( * pFuncDesc == nullptr);
+ buildComTlbIndex();
+ typedef TLBFuncIndexMap::const_iterator cit;
+ //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 insensitive 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(o3tl::toU(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
+ std::pair<cit, cit> pItems = m_mapComFunc.equal_range( sRealName );
+ for ( ;pItems.first != pItems.second; ++pItems.first )
+ m_mapComFunc.insert( TLBFuncIndexMap::value_type ( std::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
+ std::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 = nullptr;
+ if (!SUCCEEDED(pType->GetFuncDesc(itIndex->second, & pDesc)))
+ {
+ throw BridgeRuntimeError("[automation bridge] Could not get "
+ "FUNCDESC for " + sFuncName);
+ }
+ if (pDesc->invkind == INVOKE_FUNC)
+ {
+ (*pFuncDesc) = pDesc;
+ }
+ else
+ {
+ pType->ReleaseFuncDesc(pDesc);
+ }
+ }
+ //else no entry found for sFuncName, pFuncDesc will not be filled in
+}
+
+void IUnknownWrapper::getPropDesc(const OUString & sFuncName, FUNCDESC ** pFuncDescGet,
+ FUNCDESC** pFuncDescPut, VARDESC** pVarDesc)
+{
+ OSL_ASSERT( * pFuncDescGet == nullptr && * pFuncDescPut == nullptr);
+ buildComTlbIndex();
+ typedef TLBFuncIndexMap::const_iterator cit;
+ std::pair<cit, cit> p = m_mapComFunc.equal_range(sFuncName);
+ if (p.first == m_mapComFunc.end())
+ {
+ //try case insensitive 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(o3tl::toU(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 = nullptr;
+ 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 = nullptr;
+ if (SUCCEEDED(pType->GetVarDesc(p.first->second, & pVD)))
+ (*pVarDesc) = pVD;
+ }
+ //else no entry for sFuncName, pFuncDesc will not be filled in
+}
+
+VARTYPE IUnknownWrapper::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("[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( "[automation bridge] Unhandled user defined type." );
+ }
+ }
+ }
+ return _type;
+}
+
+VARTYPE IUnknownWrapper::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::buildComTlbIndex()
+{
+ if ( ! m_bComTlbIndexInit)
+ {
+ MutexGuard guard(getBridgeMutex());
+ {
+ if ( ! m_bComTlbIndexInit)
+ {
+ OUString sError;
+ ITypeInfo* pType= getTypeInfo();
+ TypeAttr typeAttr(pType);
+ if( SUCCEEDED( pType->GetTypeAttr( &typeAttr)))
+ {
+ for( WORD 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(o3tl::toU(LPCOLESTR(memberName)));
+ m_mapComFunc.emplace(usName, i);
+ }
+ else
+ {
+ sError = "[automation bridge] IUnknownWrapper::buildComTlbIndex, "
+ "ITypeInfo::GetNames failed.";
+ }
+ }
+ else
+ sError = "[automation bridge] IUnknownWrapper::buildComTlbIndex, "
+ "ITypeInfo::GetFuncDesc failed.";
+ }
+
+ //If we create an Object in JScript and a property then it
+ //has VARDESC instead of FUNCDESC
+ for (WORD 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(o3tl::toU(LPCOLESTR(memberName)));
+ m_mapComFunc.emplace(usName, i);
+ }
+ }
+ else
+ {
+ sError = "[automation bridge] IUnknownWrapper::buildComTlbIndex, "
+ "ITypeInfo::GetNames failed.";
+ }
+ }
+ else
+ sError = "[automation bridge] IUnknownWrapper::buildComTlbIndex, "
+ "ITypeInfo::GetVarDesc failed.";
+
+ }
+ }
+ else
+ sError = "[automation bridge] IUnknownWrapper::buildComTlbIndex, "
+ "ITypeInfo::GetTypeAttr failed.";
+
+ if (sError.getLength())
+ {
+ throw BridgeRuntimeError(sError);
+ }
+
+ m_bComTlbIndexInit = true;
+ }
+ }
+ }
+}
+
+ITypeInfo* IUnknownWrapper::getTypeInfo()
+{
+ if( !m_spDispatch)
+ {
+ throw BridgeRuntimeError("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)))
+ {
+ throw BridgeRuntimeError("[automation bridge]The dispatch object does not "
+ "support ITypeInfo!");
+ }
+
+ 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)))
+ {
+ throw BridgeRuntimeError(
+ "[automation bridge] Could not obtain type information "
+ "for dispatch interface." );
+ }
+ CComPtr<ITypeInfo> spTypeDisp;
+ if (SUCCEEDED(spType->GetRefTypeInfo(refDispatch, & spTypeDisp)))
+ m_spTypeInfo= spTypeDisp;
+ }
+ else if (typeAttr->typekind == TKIND_DISPATCH)
+ {
+ m_spTypeInfo= spType;
+ }
+ else
+ {
+ throw BridgeRuntimeError(
+ "[automation bridge] Automation object does not "
+ "provide type information.");
+ }
+ }
+ }
+ }
+ return m_spTypeInfo;
+}
+
+/* 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 000000000..d1a1d0ed8
--- /dev/null
+++ b/extensions/source/ole/oleobjw.hxx
@@ -0,0 +1,244 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "ole2uno.hxx"
+#include "wincrap.hxx"
+
+#include <string_view>
+#include <unordered_map>
+#include <vector>
+
+#include <cppuhelper/implbase.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 <com/sun/star/script/XDirectInvocation.hpp>
+
+#include <typelib/typedescription.hxx>
+#include "unoconversionutilities.hxx"
+#include "windata.hxx"
+using namespace cppu;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::bridge;
+using namespace com::sun::star::bridge::oleautomation;
+
+typedef std::unordered_map<OUString, std::pair<DISPID, unsigned short>> DispIdMap;
+
+typedef std::unordered_multimap<OUString, unsigned int> 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 a 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 : public WeakImplHelper< XBridgeSupplier2, XInitialization, XAutomationObject, XDefaultProperty, XDefaultMethod, XDirectInvocation, XAutomationInvocation >,
+
+ public UnoConversionUtilities<IUnknownWrapper>
+
+{
+public:
+ IUnknownWrapper(Reference<XMultiServiceFactory> const &xFactory,
+ sal_uInt8 unoWrapperClass, sal_uInt8 comWrapperClass);
+
+ ~IUnknownWrapper() override;
+
+ //XInterface
+ Any SAL_CALL queryInterface(const Type& t) override;
+
+ // XInvokation
+ virtual Reference< XIntrospectionAccess > SAL_CALL getIntrospection( ) override;
+ virtual Any SAL_CALL invoke( const OUString& aFunctionName,
+ const Sequence< Any >& aParams,
+ Sequence< sal_Int16 >& aOutParamIndex,
+ Sequence< Any >& aOutParam ) override;
+ virtual void SAL_CALL setValue( const OUString& aPropertyName,
+ const Any& aValue ) override;
+ virtual Any SAL_CALL getValue( const OUString& aPropertyName ) override;
+ virtual sal_Bool SAL_CALL hasMethod( const OUString& aName ) override;
+ virtual sal_Bool SAL_CALL hasProperty( const OUString& aName ) override;
+
+ // 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 ) override;
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const Sequence< Any >& aArguments ) override;
+
+ // XDefaultProperty
+ virtual OUString SAL_CALL getDefaultPropertyName( ) override { return m_sDefaultMember; }
+
+ // XDefaultMethod
+ virtual OUString SAL_CALL getDefaultMethodName( ) override { return m_sDefaultMember; }
+
+ virtual css::uno::Any SAL_CALL invokeGetProperty( const OUString& aFunctionName, const css::uno::Sequence< css::uno::Any >& aParams, css::uno::Sequence< ::sal_Int16 >& aOutParamIndex, css::uno::Sequence< css::uno::Any >& aOutParam ) override;
+ virtual css::uno::Any SAL_CALL invokePutProperty( const OUString& aFunctionName, const css::uno::Sequence< css::uno::Any >& aParams, css::uno::Sequence< ::sal_Int16 >& aOutParamIndex, css::uno::Sequence< css::uno::Any >& aOutParam ) override;
+
+ // XDirectInvocation
+ virtual css::uno::Any SAL_CALL directInvoke( const OUString& aName, const css::uno::Sequence< css::uno::Any >& aParams ) override;
+ virtual sal_Bool SAL_CALL hasMember( const OUString& aName ) override;
+
+
+ Any invokeWithDispIdComTlb(FuncDesc& aFuncDesc,
+ const OUString& sFuncName,
+ const Sequence< Any >& Params,
+ Sequence< sal_Int16 >& OutParamIndex,
+ Sequence< Any >& OutParam);
+
+
+protected:
+
+ 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);
+
+ // UnoConversionUtilities -------------------------------------------------------------------------------
+ virtual Reference<XInterface> createUnoWrapperInstance() override;
+ virtual Reference<XInterface> createComWrapperInstance() override;
+
+ /**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(std::u16string_view sName, TypeDescription& methodDescription);
+ // After return attributInfo contains typelib_InterfaceAttributeTypeDescription::pAttributeTypeRef
+ void getAttributeInfo(std::u16string_view sName, TypeDescription& attributeInfo);
+ // used by get MethodInfo
+ TypeDescription getInterfaceMemberDescOfCurrentCall(std::u16string_view sName);
+ /** Returns always 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 whether the wrapped IDispatch is a JScript Object. This is
+ // done by
+ // asking for the property "_environment". If it has the value "JScript"
+ // (case insensitive) then the IDispatch is considered a JScript object.
+ 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
+ // a UNO interface. The value is set during a call to XInitialization::initialize.
+ Sequence<Type> m_seqTypes;
+ CComPtr<IUnknown> m_spUnknown;
+ CComPtr<IDispatch> m_spDispatch;
+ 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 during XInitialization::initialize. It indicates that the COM interface
+ was transported as VT_DISPATCH in a VARIANT rather than a VT_UNKNOWN
+ */
+ 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 synchronizing the computation of the content for m_mapComFunc
+ bool m_bComTlbIndexInit;
+ // Keeps the ITypeInfo obtained from IDispatch::GetTypeInfo
+ CComPtr< ITypeInfo > m_spTypeInfo;
+ OUString m_sDefaultMember;
+ bool m_bHasDfltMethod;
+ bool m_bHasDfltProperty;
+};
+
+/* 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 000000000..1580c0b7d
--- /dev/null
+++ b/extensions/source/ole/olethread.cxx
@@ -0,0 +1,66 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "ole2uno.hxx"
+
+#include <comphelper/windowserrorstring.hxx>
+#include <osl/thread.hxx>
+#include <sal/log.hxx>
+
+void o2u_attachCurrentThread()
+{
+ static osl::ThreadData oleThreadData;
+
+ if (!bool(reinterpret_cast<sal_IntPtr>(oleThreadData.getData())))
+ {
+ HRESULT hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
+ if (!SUCCEEDED(hr))
+ { // FIXME: is it a problem that this ends up in STA currently?
+ assert(RPC_E_CHANGED_MODE == hr);
+ // Let's find out explicitly what apartment mode we are in.
+ SAL_WARN("extensions.olebridge", "CoInitializeEx failed"
+ << (hr == RPC_E_CHANGED_MODE ? " (expectedly)" : "")
+ << ": " << WindowsErrorStringFromHRESULT(hr));
+ APTTYPE nAptType;
+ APTTYPEQUALIFIER nAptTypeQualifier;
+ if (SUCCEEDED(CoGetApartmentType(&nAptType, &nAptTypeQualifier)))
+ {
+ SAL_WARN("extensions.olebridge",
+ " Thread is in a "
+ << (nAptType == APTTYPE_STA ? OUString("single-threaded") :
+ (nAptType == APTTYPE_MTA ? OUString("multi-threaded") :
+ (nAptType == APTTYPE_NA ? OUString("neutral") :
+ (nAptType == APTTYPE_MAINSTA ? OUString("main single-threaded") :
+ ("unknown (") + OUString::number(nAptType) + ")"))))
+ << " apartment"
+ << (nAptTypeQualifier == APTTYPEQUALIFIER_NONE ? OUString() :
+ (nAptTypeQualifier == APTTYPEQUALIFIER_IMPLICIT_MTA ? OUString(" (implicit)") :
+ (nAptTypeQualifier == APTTYPEQUALIFIER_NA_ON_MTA ? OUString(" (on MTA)") :
+ (nAptTypeQualifier == APTTYPEQUALIFIER_NA_ON_STA ? OUString(" (on STA)") :
+ (nAptTypeQualifier == APTTYPEQUALIFIER_NA_ON_IMPLICIT_MTA ? OUString(" (on implicit MTA)") :
+ (nAptTypeQualifier == APTTYPEQUALIFIER_NA_ON_MAINSTA ? OUString(" (on main STA)") :
+ (" (with unknown qualifier (" + OUString::number(nAptTypeQualifier) + "))")))))))
+ << ".");
+ }
+ }
+ oleThreadData.setData(reinterpret_cast<void*>(true));
+ }
+}
+
+/* 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 000000000..ea69be1d9
--- /dev/null
+++ b/extensions/source/ole/servprov.cxx
@@ -0,0 +1,548 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <vector>
+
+#include "ole2uno.hxx"
+#include "unoconversionutilities.hxx"
+#include "servprov.hxx"
+#include "unoobjw.hxx"
+#include "oleobjw.hxx"
+
+#include <com/sun/star/script/CannotConvertException.hpp>
+#include <comphelper/automationinvokedzone.hxx>
+#include <comphelper/windowsdebugoutput.hxx>
+#include <comphelper/windowserrorstring.hxx>
+#include <cppuhelper/queryinterface.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <o3tl/any.hxx>
+#include <o3tl/char16_t2wchar_t.hxx>
+#include <ooo/vba/XHelperInterface.hpp>
+#include <sal/log.hxx>
+
+using namespace cppu;
+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;
+
+#include <initguid.h>
+
+// 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);
+
+// FIXME: This GUID is just the above OID_ServiceManager with the
+// initial part bumped by one. Is that good enough?
+// {82154421-0FBF-11d4-8313-005004526AB4}
+DEFINE_GUID(OID_LibreOfficeWriterApplication, 0x82154421, 0xfbf, 0x11d4, 0x83, 0x13, 0x0, 0x50, 0x4, 0x52, 0x6a, 0xb4);
+
+// For Calc
+// {82154425-0FBF-11d4-8313-005004526AB4}
+DEFINE_GUID(OID_LibreOfficeCalcApplication, 0x82154425, 0xfbf, 0x11d4, 0x83, 0x13, 0x0, 0x50, 0x4, 0x52, 0x6a, 0xb4);
+
+OneInstanceOleWrapper::OneInstanceOleWrapper( const Reference<XMultiServiceFactory>& smgr,
+ std::function<const Reference<XInterface>()> xInstFunction )
+ : m_refCount(0)
+ , m_xInstFunction(xInstFunction)
+ , m_factoryHandle(0)
+ , m_smgr(smgr)
+{
+ Reference<XInterface> xInt = m_smgr->createInstance("com.sun.star.bridge.oleautomation.BridgeSupplier");
+
+ if (xInt.is())
+ {
+ Any a= xInt->queryInterface( cppu::UnoType<XBridgeSupplier2>::get() );
+ a >>= m_bridgeSupplier;
+ }
+}
+
+OneInstanceOleWrapper::~OneInstanceOleWrapper()
+{
+}
+
+bool OneInstanceOleWrapper::registerClass(GUID const * pGuid)
+{
+ HRESULT hresult;
+
+ o2u_attachCurrentThread();
+
+ hresult = CoRegisterClassObject(
+ *pGuid,
+ this,
+ CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER,
+ REGCLS_MULTIPLEUSE,
+ &m_factoryHandle);
+
+ SAL_INFO("extensions.olebridge", "CoRegisterClassObject(" << *pGuid << "): " << WindowsErrorStringFromHRESULT(hresult));
+
+ return (hresult == NOERROR);
+}
+
+bool OneInstanceOleWrapper::deregisterClass()
+{
+ return CoRevokeClassObject(m_factoryHandle) == NOERROR;
+}
+
+COM_DECLSPEC_NOTHROW STDMETHODIMP OneInstanceOleWrapper::QueryInterface(REFIID riid, void ** ppv)
+{
+ if(IsEqualIID(riid, IID_IUnknown))
+ {
+ AddRef();
+ *ppv = static_cast<IUnknown*>(static_cast<IClassFactory*>(this));
+ return NOERROR;
+ }
+ else if (IsEqualIID(riid, IID_IClassFactory))
+ {
+ AddRef();
+ *ppv = static_cast<IClassFactory*>(this);
+ return NOERROR;
+ }
+
+ *ppv = nullptr;
+ return ResultFromScode(E_NOINTERFACE);
+}
+
+COM_DECLSPEC_NOTHROW STDMETHODIMP_(ULONG) OneInstanceOleWrapper::AddRef()
+{
+ return osl_atomic_increment( &m_refCount);
+}
+
+COM_DECLSPEC_NOTHROW STDMETHODIMP_(ULONG) OneInstanceOleWrapper::Release()
+{
+ MutexGuard oGuard( Mutex::getGlobalMutex());
+ ULONG refCount = --m_refCount;
+ if ( m_refCount == 0)
+ {
+ delete this;
+ }
+
+ return refCount;
+}
+
+COM_DECLSPEC_NOTHROW STDMETHODIMP OneInstanceOleWrapper::CreateInstance(IUnknown*,
+ REFIID riid, void** ppv)
+{
+ comphelper::Automation::AutomationInvokedZone aAutomationActive;
+
+ SAL_INFO("extensions.olebridge", "OneInstanceOleWrapper::CreateInstance(" << riid << ")");
+
+ HRESULT ret = ResultFromScode(E_UNEXPECTED);
+
+ const Reference<XInterface>& xInst = m_xInstFunction();
+ if (xInst.is())
+ {
+ Any usrAny(&xInst, cppu::UnoType<decltype(xInst)>::get());
+ sal_uInt8 arId[16];
+ rtl_getGlobalProcessId( arId);
+ Any oleAny = m_bridgeSupplier->createBridge(usrAny,
+ Sequence<sal_Int8>( reinterpret_cast<sal_Int8*>(arId), 16),
+ UNO,
+ OLE);
+
+
+ if (auto v = o3tl::tryAccess<sal_uIntPtr>(oleAny))
+ {
+ VARIANT* pVariant = reinterpret_cast<VARIANT*>(*v);
+
+ if ((pVariant->vt == VT_UNKNOWN) || (pVariant->vt == VT_DISPATCH))
+ {
+ SAL_INFO("extensions.olebridge", "OneInstanceOleWrapper::Createbridge: punkVal=" << pVariant->punkVal);
+ ret = pVariant->punkVal->QueryInterface(riid, ppv);
+ }
+
+ VariantClear(pVariant);
+ CoTaskMemFree(pVariant);
+ }
+ }
+
+ return ret;
+}
+
+COM_DECLSPEC_NOTHROW STDMETHODIMP OneInstanceOleWrapper::LockServer(BOOL /*fLock*/)
+{
+ return NOERROR;
+}
+
+OleConverter::OleConverter( const Reference<XMultiServiceFactory> &smgr):
+ UnoConversionUtilities<OleConverter>( smgr)
+
+{
+}
+
+// The XMultiServiceFactory is later set by XInitialization
+OleConverter::OleConverter( const Reference<XMultiServiceFactory>& smgr, sal_uInt8 unoWrapperClass, sal_uInt8 comWrapperClass ):
+ UnoConversionUtilities<OleConverter>( smgr, unoWrapperClass, comWrapperClass )
+
+{
+}
+
+OleConverter::~OleConverter()
+{
+}
+
+// XBridgeSupplier --------------------------------------------------------------
+Any SAL_CALL OleConverter::createBridge(const Any& modelDepObject,
+ const Sequence< sal_Int8 >& ProcessId,
+ sal_Int16 sourceModelType,
+ sal_Int16 destModelType)
+{
+ Any ret;
+ sal_uInt8 arId[16];
+ rtl_getGlobalProcessId( arId );
+
+ Sequence< sal_Int8 > seqProcessId( reinterpret_cast<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 = static_cast<VARIANT*>(CoTaskMemAlloc(sizeof(VARIANT)));
+ VariantInit( pVariant);
+ try
+ {
+ anyToVariant( pVariant, modelDepObject);
+ }
+ catch(...)
+ {
+ CoTaskMemFree(pVariant);
+ throw IllegalArgumentException();
+ }
+ ret.setValue(static_cast<void*>(&pVariant), cppu::UnoType<sal_uIntPtr>::get());
+ }
+ else
+ throw IllegalArgumentException();
+ }
+ else if (sourceModelType == OLE)
+ {
+ auto v = o3tl::tryAccess<sal_uIntPtr>(modelDepObject);
+ if (!v)
+ {
+ throw IllegalArgumentException();
+ }
+ else if (destModelType == OLE)
+ {
+ // same model -> copy value only
+ VARIANT* pVariant = static_cast<VARIANT*>(CoTaskMemAlloc(sizeof(VARIANT)));
+
+ if (NOERROR != VariantCopy(pVariant, reinterpret_cast<VARIANT*>(*v)))
+ {
+ CoTaskMemFree(pVariant);
+ throw(IllegalArgumentException());
+ }
+ else
+ {
+ ret.setValue(static_cast<void*>(&pVariant), cppu::UnoType<sal_uIntPtr>::get());
+ }
+ }
+ else if (destModelType == UNO)
+ {
+ // convert variant into UNO any
+ VARIANT* pVariant = reinterpret_cast<VARIANT*>(*v);
+ try
+ {
+ variantToAny(pVariant, ret);
+ }
+ catch (const CannotConvertException & e)
+ {
+ throw IllegalArgumentException(
+ e.Message, nullptr, -1);
+ }
+ }
+ else
+ throw IllegalArgumentException();
+
+ }
+ else
+ throw IllegalArgumentException();
+ }
+
+ return ret;
+}
+
+OUString OleConverter::getImplementationName()
+{
+ return m_nUnoWrapperClass == INTERFACE_OLE_WRAPPER_IMPL
+ ? OUString("com.sun.star.comp.ole.OleConverter2")
+ : OUString("com.sun.star.comp.ole.OleConverterVar1");
+}
+
+sal_Bool OleConverter::supportsService(OUString const & ServiceName)
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+css::uno::Sequence<OUString> OleConverter::getSupportedServiceNames()
+{
+ if (m_nUnoWrapperClass == INTERFACE_OLE_WRAPPER_IMPL)
+ {
+ return css::uno::Sequence<OUString>{
+ "com.sun.star.bridge.OleBridgeSupplier2",
+ "com.sun.star.bridge.oleautomation.BridgeSupplier"};
+ }
+ return css::uno::Sequence<OUString>{
+ "com.sun.star.bridge.OleBridgeSupplierVar1"};
+}
+
+// XInitialize ------------------------------------------------------------------------------
+// the first argument is an XMultiServiceFactory if at all
+void SAL_CALL OleConverter::initialize( const Sequence< Any >& aArguments )
+{
+ 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::createUnoWrapperInstance()
+{
+ if( m_nUnoWrapperClass == INTERFACE_OLE_WRAPPER_IMPL)
+ {
+ Reference<XWeak> xWeak= static_cast<XWeak*>( new InterfaceOleWrapper(
+ 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::createComWrapperInstance()
+{
+ Reference<XWeak> xWeak= static_cast<XWeak*>( new IUnknownWrapper(
+ m_smgr, m_nUnoWrapperClass, m_nComWrapperClass));
+ return Reference<XInterface>( xWeak, UNO_QUERY);
+}
+
+OleClient::OleClient( const Reference<XMultiServiceFactory>& smgr):
+ UnoConversionUtilities<OleClient>( smgr)
+{
+ Reference<XInterface> xInt;// = m_smgr->createInstance(L"com.sun.star.bridge.OleBridgeSupplier2");
+
+ if (xInt.is())
+ {
+ Any a= xInt->queryInterface(cppu::UnoType<XBridgeSupplier2>::get() );
+ a >>= m_bridgeSupplier;
+ }
+}
+
+OleClient::~OleClient()
+{
+}
+
+Sequence< OUString > SAL_CALL OleClient::getAvailableServiceNames()
+{
+ Sequence< OUString > ret;
+
+ return ret;
+}
+
+OUString OleClient::getImplementationName()
+{
+ return "com.sun.star.comp.ole.OleClient";
+}
+
+sal_Bool OleClient::supportsService(OUString const & ServiceName)
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+css::uno::Sequence<OUString> OleClient::getSupportedServiceNames()
+{
+ return css::uno::Sequence<OUString>{
+ "com.sun.star.bridge.OleObjectFactory",
+ "com.sun.star.bridge.oleautomation.Factory"};
+}
+
+Reference<XInterface> SAL_CALL OleClient::createInstance(const OUString& ServiceSpecifier)
+{
+ Reference<XInterface> ret;
+ HRESULT result;
+ IUnknown* pUnknown = nullptr;
+ CLSID classId;
+
+ o2u_attachCurrentThread();
+
+ result = CLSIDFromProgID(
+ o3tl::toW(ServiceSpecifier.getStr()), //Pointer to the ProgID
+ &classId); //Pointer to the CLSID
+
+
+ if (result == NOERROR)
+ {
+ result = CoCreateInstance(
+ classId, //Class identifier (CLSID) of the object
+ nullptr, //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
+ reinterpret_cast<void**>(&pUnknown)); //Address of output variable that receives
+ // the interface pointer requested in riid
+ }
+
+ if (pUnknown != nullptr)
+ {
+ 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::createInstanceWithArguments(const OUString& ServiceSpecifier, const Sequence< Any >& /*Arguments*/)
+{
+ return createInstance( ServiceSpecifier);
+}
+
+// UnoConversionUtilities -----------------------------------------------------------------------------
+Reference< XInterface > OleClient::createUnoWrapperInstance()
+{
+ if( m_nUnoWrapperClass == INTERFACE_OLE_WRAPPER_IMPL)
+ {
+ Reference<XWeak> xWeak= static_cast<XWeak*>( new InterfaceOleWrapper(
+ 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::createComWrapperInstance( )
+{
+ Reference<XWeak> xWeak= static_cast<XWeak*>( new IUnknownWrapper(
+ m_smgr, m_nUnoWrapperClass, m_nComWrapperClass));
+ return Reference<XInterface>( xWeak, UNO_QUERY);
+}
+
+OleServer::OleServer( const Reference<XMultiServiceFactory>& smgr):
+ m_smgr( smgr)
+{
+ Reference<XInterface> xInt = m_smgr->createInstance("com.sun.star.bridge.oleautomation.BridgeSupplier");
+
+ if (xInt.is())
+ {
+ Any a= xInt->queryInterface( cppu::UnoType<XBridgeSupplier2>::get() );
+ a >>= m_bridgeSupplier;
+ }
+
+ (void) provideInstance( [&]
+ {
+ return m_smgr;
+ },
+ &OID_ServiceManager );
+
+ (void) provideInstance( [&]
+ {
+ // We want just one SwVbaGlobals for all Automation clients
+ static const Reference<XInterface> xWordGlobals = m_smgr->createInstance("ooo.vba.word.Globals");
+ const Reference<ooo::vba::XHelperInterface> xHelperInterface(xWordGlobals, UNO_QUERY);
+ Any aApplication = xHelperInterface->Application();
+ Reference<XInterface> xApplication;
+ aApplication >>= xApplication;
+ return xApplication;
+ },
+ &OID_LibreOfficeWriterApplication );
+
+ (void) provideInstance( [&]
+ {
+ // Ditto for sc
+ static const Reference<XInterface> xCalcGlobals = m_smgr->createInstance("ooo.vba.excel.Globals");
+ const Reference<ooo::vba::XHelperInterface> xHelperInterface(xCalcGlobals, UNO_QUERY);
+ Any aApplication = xHelperInterface->Application();
+ Reference<XInterface> xApplication;
+ aApplication >>= xApplication;
+ return xApplication;
+ },
+ &OID_LibreOfficeCalcApplication );
+}
+
+OleServer::~OleServer()
+{
+ for (auto const& elem : m_wrapperList)
+ {
+ elem->deregisterClass();
+ elem->Release();
+ }
+ m_wrapperList.clear();
+}
+
+OUString OleServer::getImplementationName()
+{
+ return "com.sun.star.comp.ole.OleServer";
+}
+
+sal_Bool OleServer::supportsService(OUString const & ServiceName)
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+css::uno::Sequence<OUString> OleServer::getSupportedServiceNames()
+{
+ return css::uno::Sequence<OUString>{
+ "com.sun.star.bridge.OleApplicationRegistration",
+ "com.sun.star.bridge.oleautomation.ApplicationRegistration"};
+}
+
+bool OleServer::provideInstance(std::function<const Reference<XInterface>()> xInstFunction, GUID const * guid)
+{
+ OneInstanceOleWrapper* pWrapper = new OneInstanceOleWrapper( m_smgr, xInstFunction );
+
+ pWrapper->AddRef();
+ m_wrapperList.push_back(pWrapper);
+
+ return pWrapper->registerClass(guid);
+}
+
+/* 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 000000000..8871f28cf
--- /dev/null
+++ b/extensions/source/ole/servprov.hxx
@@ -0,0 +1,184 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <functional>
+
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <cppuhelper/implbase.hxx>
+
+#include "ole2uno.hxx"
+#include "unoconversionutilities.hxx"
+
+using namespace com::sun::star::bridge;
+using namespace cppu;
+
+/// @throws Exception
+Reference< XInterface> ConverterProvider_CreateInstance2( const Reference<XMultiServiceFactory> & xSMgr);
+/// @throws Exception
+Reference< XInterface> ConverterProvider_CreateInstanceVar1( const Reference<XMultiServiceFactory> & xSMgr);
+/// @throws Exception
+Reference<XInterface> OleClient_CreateInstance( const Reference<XMultiServiceFactory> & xSMgr);
+/// @throws Exception
+Reference<XInterface> OleServer_CreateInstance( const Reference<XMultiServiceFactory> & xSMgr);
+
+/*****************************************************************************
+
+ OneInstanceOleWrapper
+
+ Provides a single UNO object as OLE object.
+
+ 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 : public IClassFactory
+{
+public:
+
+ OneInstanceOleWrapper( const Reference<XMultiServiceFactory>& smgr,
+ std::function<const Reference<XInterface>()> xInstFunction );
+ virtual ~OneInstanceOleWrapper();
+
+ bool registerClass(GUID const * pGuid);
+ bool deregisterClass();
+
+ /* IUnknown methods */
+ STDMETHOD(QueryInterface)(REFIID riid, void ** ppvObj) override;
+ STDMETHOD_(ULONG, AddRef)() override;
+ STDMETHOD_(ULONG, Release)() override;
+
+ /* IClassFactory methods */
+ STDMETHOD(CreateInstance)(IUnknown* punkOuter, REFIID riid, void** ppv) override;
+ STDMETHOD(LockServer)(BOOL fLock) override;
+
+protected:
+ oslInterlockedCount m_refCount;
+ std::function<const Reference<XInterface>()> m_xInstFunction;
+ DWORD m_factoryHandle;
+ Reference<XBridgeSupplier2> m_bridgeSupplier;
+ Reference<XMultiServiceFactory> m_smgr;
+};
+
+// 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 which
+// interface does not need a Machine Id in its createBridge function anymore,
+// If a UNO interface is to be converted then the member m_nUnoWrapperClass determines
+// what wrapper class is to be used. There are currently InterfaceOleWrapper 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).
+class OleConverter : public WeakImplHelper<XBridgeSupplier2, XInitialization, css::lang::XServiceInfo>,
+ public UnoConversionUtilities<OleConverter>
+{
+public:
+ explicit OleConverter( const Reference<XMultiServiceFactory>& smgr);
+ OleConverter( const Reference<XMultiServiceFactory>& smgr, sal_uInt8 unoWrapperClass, sal_uInt8 comWrapperClass );
+ virtual ~OleConverter() override;
+
+ // XBridgeSupplier2 ---------------------------------------------------
+
+ Any SAL_CALL createBridge(const Any& modelDepObject,
+ const Sequence<sal_Int8>& ProcessId,
+ sal_Int16 sourceModelType,
+ sal_Int16 destModelType) override;
+
+ // XInitialization
+ void SAL_CALL initialize( const Sequence< Any >& aArguments ) override;
+
+ OUString SAL_CALL getImplementationName() override;
+
+ sal_Bool SAL_CALL supportsService(OUString const & ServiceName) override;
+
+ css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
+
+ // UnoConversionUtilities
+ Reference< XInterface > createUnoWrapperInstance() override;
+ Reference< XInterface > createComWrapperInstance() override;
+protected:
+
+};
+
+// Implementation of the UNO service com.sun.star.bridge.OleObjectFactory.
+
+class OleClient : public WeakImplHelper<XMultiServiceFactory, css::lang::XServiceInfo>,
+ public UnoConversionUtilities<OleClient>
+{
+public:
+ explicit OleClient( const Reference<XMultiServiceFactory>& smgr);
+ ~OleClient() override;
+
+ // XMultiServiceFactory
+ Reference<XInterface> SAL_CALL createInstance(const OUString& ServiceSpecifier) override;
+ Reference<XInterface> SAL_CALL createInstanceWithArguments(const OUString& ServiceSpecifier, const Sequence< Any >& Arguments) override;
+ Sequence< OUString > SAL_CALL getAvailableServiceNames() override;
+
+ OUString SAL_CALL getImplementationName() override;
+
+ sal_Bool SAL_CALL supportsService(OUString const & ServiceName) override;
+
+ css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
+
+ // UnoConversionUtilities
+ Reference< XInterface > createUnoWrapperInstance() override;
+ Reference< XInterface > createComWrapperInstance() override;
+
+protected:
+ Reference<XBridgeSupplier2> m_bridgeSupplier;
+};
+
+/*****************************************************************************
+
+ OleServer
+
+ 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 instantiating
+ this implementation and deregistered, if this implementation is destroyed.
+
+*****************************************************************************/
+
+class OleServer : public cppu::WeakImplHelper<css::lang::XServiceInfo>
+{
+public:
+ explicit OleServer( const Reference<XMultiServiceFactory> &smgr);
+ ~OleServer() override;
+
+ OUString SAL_CALL getImplementationName() override;
+
+ sal_Bool SAL_CALL supportsService(OUString const & ServiceName) override;
+
+ css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
+
+protected:
+ bool provideInstance(std::function<const Reference<XInterface>()> xInstFunction, GUID const * guid);
+
+ std::list< OneInstanceOleWrapper* > m_wrapperList;
+ Reference< XBridgeSupplier2 > m_bridgeSupplier;
+
+ Reference<XMultiServiceFactory> m_smgr;
+};
+
+/* 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 000000000..66928137b
--- /dev/null
+++ b/extensions/source/ole/servreg.cxx
@@ -0,0 +1,94 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <osl/time.h>
+#include "ole2uno.hxx"
+#include "servprov.hxx"
+#include <rtl/ustring.hxx>
+#include <cppuhelper/factory.hxx>
+
+using namespace cppu;
+
+Reference<XInterface> ConverterProvider_CreateInstance2( const Reference<XMultiServiceFactory> & xSMgr)
+{
+ Reference<XInterface> xService = *new OleConverter( xSMgr);
+ return xService;
+}
+
+Reference<XInterface> ConverterProvider_CreateInstanceVar1( const Reference<XMultiServiceFactory> & xSMgr)
+{
+ Reference<XInterface> xService = *new OleConverter( xSMgr, UNO_OBJECT_WRAPPER_REMOTE_OPT, IUNKNOWN_WRAPPER_IMPL);
+ return xService;
+}
+
+Reference<XInterface> OleClient_CreateInstance( const Reference<XMultiServiceFactory> & xSMgr)
+{
+ Reference<XInterface> xService = *new OleClient( xSMgr);
+ return xService;
+}
+
+Reference<XInterface> OleServer_CreateInstance( const Reference<XMultiServiceFactory> & xSMgr)
+{
+ Reference<XInterface > xService = *new OleServer(xSMgr);
+ return xService;
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT void * oleautobridge_component_getFactory(
+ const char * pImplName, void * pServiceManager, void * /*pRegistryKey*/ )
+{
+ void * pRet = nullptr;
+
+ OUString aImplName( OUString::createFromAscii( pImplName ) );
+ Reference< XSingleServiceFactory > xFactory;
+ Sequence<OUString> seqServiceNames;
+ if (pServiceManager && aImplName == "com.sun.star.comp.ole.OleConverter2")
+ {
+ xFactory= createSingleFactory( static_cast< XMultiServiceFactory*>(pServiceManager),
+ aImplName,
+ ConverterProvider_CreateInstance2, seqServiceNames );
+ }
+ else if (pServiceManager && aImplName == "com.sun.star.comp.ole.OleConverterVar1")
+ {
+ xFactory= createSingleFactory( static_cast<XMultiServiceFactory*>(pServiceManager),
+ aImplName,
+ ConverterProvider_CreateInstanceVar1, seqServiceNames );
+ }
+ else if(pServiceManager && aImplName == "com.sun.star.comp.ole.OleClient")
+ {
+ xFactory= createSingleFactory( static_cast< XMultiServiceFactory*>(pServiceManager),
+ aImplName,
+ OleClient_CreateInstance, seqServiceNames );
+ }
+ else if(pServiceManager && aImplName == "com.sun.star.comp.ole.OleServer")
+ {
+ xFactory= createOneInstanceFactory( static_cast< XMultiServiceFactory*>(pServiceManager),
+ aImplName,
+ OleServer_CreateInstance, seqServiceNames );
+ }
+
+ if (xFactory.is())
+ {
+ xFactory->acquire();
+ pRet = xFactory.get();
+ }
+
+ return pRet;
+}
+
+/* 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 000000000..a73a714ab
--- /dev/null
+++ b/extensions/source/ole/unoconversionutilities.hxx
@@ -0,0 +1,2363 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <memory>
+#include <com/sun/star/script/CannotConvertException.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/ModelDependent.hpp>
+#include <com/sun/star/bridge/XBridgeSupplier2.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 <com/sun/star/lang/XInitialization.hpp>
+#include <typelib/typedescription.hxx>
+#include <o3tl/any.hxx>
+#include <o3tl/char16_t2wchar_t.hxx>
+#include "ole2uno.hxx"
+#include <cppuhelper/weakref.hxx>
+
+#include "unotypewrapper.hxx"
+#include <unordered_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 "com.sun.star.script.Invocation"
+
+
+// classes for wrapping ole objects
+#define IUNKNOWN_WRAPPER_IMPL 1
+
+#define INTERFACE_ADAPTER_FACTORY "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;
+using namespace com::sun::star::bridge::oleautomation;
+
+extern std::unordered_map<sal_uIntPtr, sal_uIntPtr> AdapterToWrapperMap;
+extern std::unordered_map<sal_uIntPtr, sal_uIntPtr> WrapperToAdapterMap;
+
+//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 std::unordered_map<sal_uIntPtr, WeakReference<XInterface> > ComPtrToWrapperMap;
+
+// Maps XInterface pointers to a weak reference of its wrapper class (i.e.
+// InterfaceOleWrapper). 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, a 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 std::unordered_map<sal_uIntPtr, WeakReference<XInterface> > UnoObjToWrapperMap;
+
+// 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.
+
+inline void reduceRange( Any& any)
+{
+ OSL_ASSERT( any.getValueTypeClass() == TypeClass_LONG);
+
+ sal_Int32 value= *o3tl::doAccess<sal_Int32>(any);
+ if( value <= 0x7f && value >= -0x80)
+ {// -128 bis 127
+ sal_Int8 charVal= static_cast<sal_Int8>( value);
+ any.setValue( &charVal, cppu::UnoType<sal_Int8>::get());
+ }
+ else if( value <= 0x7fff && value >= -0x8000)
+ {// -32768 bis 32767
+ sal_Int16 shortVal= static_cast<sal_Int16>( value);
+ any.setValue( &shortVal, cppu::UnoType<sal_Int16>::get());
+ }
+}
+
+// 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:
+ explicit 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_nUnoWrapperClass(unoWrapperClass),
+ m_nComWrapperClass(comWrapperClass), m_smgr(xFactory)
+ {}
+
+ 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, bool bReduceValueRange = 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, bool bReduceValueRange = 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 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
+ static bool incrementMultidimensionalIndex(sal_Int32 dimensions, const sal_Int32 * parDimensionLength,
+ sal_Int32 * parMultidimensionalIndex);
+ // helper function for Sequence conversion
+ static size_t getOleElementSize( VARTYPE type);
+
+ static 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 anyToVariant
+ // function in the createBridge function implementation
+ const sal_uInt8 m_nUnoWrapperClass;
+ const 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< css::bridge::XBridgeSupplier2 > xSupplier( xInt, UNO_QUERY);
+ if( xSupplier.is())
+ {
+ sal_Int8 arId[16];
+ rtl_getGlobalProcessId( reinterpret_cast<sal_uInt8*>(arId));
+ Sequence<sal_Int8> seqId( arId, 16);
+ Any anySource;
+ anySource <<= xInt;
+ Any anyDisp = xSupplier->createBridge(
+ anySource, seqId, css::bridge::ModelDependent::UNO,
+ css::bridge::ModelDependent::OLE);
+
+ // due to global-process-id check this must be in-process pointer
+ if (auto v = o3tl::tryAccess<sal_uIntPtr>(anyDisp))
+ {
+ VARIANT* pvariant= reinterpret_cast<VARIANT*>(*v);
+ HRESULT hr;
+ if (FAILED(hr = VariantCopy(pVar, pvariant)))
+ throw BridgeRuntimeError(
+ "[automation bridge] convertSelfToCom\n"
+ "VariantCopy failed! Error: " +
+ OUString::number(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.set(m_smgrRemote->createInstance( INVOCATION_SERVICE), UNO_QUERY);
+ retVal= m_xInvocationFactoryRemote;
+ }
+ else
+ {
+ if( ! m_xInvocationFactoryLocal.is() )
+ m_xInvocationFactoryLocal.set(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, 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, pArg))) // remove VT_BYREF
+ throw BridgeRuntimeError(
+ "[automation bridge] UnoConversionUtilities<T>::variantToAny \n"
+ "VariantCopyInd failed for reason : " + OUString::number(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 being 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( 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(& 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(& 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. VBScript 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(unoSeq);
+ Any convAny = conv->convertTo(anySeq, ptype);
+ rAny = convAny;
+ }
+ catch (const IllegalArgumentException& e)
+ {
+ throw BridgeRuntimeError(
+ "[automation bridge]com.sun.star.lang.IllegalArgumentException "
+ "in UnoConversionUtilities<T>::variantToAny! Message: " +
+ e.Message);
+ }
+ catch (const CannotConvertException& e)
+ {
+ throw BridgeRuntimeError(
+ "[automation bridge]com.sun.star.script.CannotConvertException "
+ "in UnoConversionUtilities<T>::variantToAny! Message: " +
+ e.Message);
+ }
+ }
+ }
+ }
+ break;
+ case TypeClass_VOID:
+ rAny.setValue(nullptr,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,
+ cppu::UnoType<Sequence<Any>>::get());
+ }
+ 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, cppu::UnoType<sal_uInt64>::get(),
+ bReduceValueRange);
+ }
+ else
+ {
+ //negative value
+ variantToAny( & var, rAny, cppu::UnoType<sal_Int64>::get(),
+ 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(var.vt == VT_NULL)
+ var = CComBSTR("");
+ 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:
+ bCannotConvert = true;
+ break;
+ }
+ }
+ if (bCannotConvert)
+ throw CannotConvertException(
+ "[automation bridge]UnoConversionUtilities<T>::variantToAny \n"
+ "Cannot convert the value of vartype :\"" +
+ OUString::number(static_cast<sal_Int32>(var.vt)) +
+ "\" to the expected UNO type of type class: " +
+ OUString::number(static_cast<sal_Int32>(ptype.getTypeClass())),
+ nullptr, TypeClass_UNKNOWN, FailReason::TYPE_NOT_SUPPORTED,0);
+
+ if (bFail)
+ throw IllegalArgumentException(
+ "[automation bridge]UnoConversionUtilities<T>:variantToAny\n"
+ "The provided VARIANT of type\" " + OUString::number(static_cast<sal_Int32>(var.vt)) +
+ "\" is unappropriate for conversion!", Reference<XInterface>(), -1);
+ }
+ catch (const CannotConvertException &)
+ {
+ throw;
+ }
+ catch (const IllegalArgumentException &)
+ {
+ throw;
+ }
+ catch (const BridgeRuntimeError &)
+ {
+ throw;
+ }
+ catch (const Exception & e)
+ {
+ throw BridgeRuntimeError("[automation bridge] unexpected exception in "
+ "UnoConversionUtilities<T>::variantToAny ! Message : \n" +
+ e.Message);
+ }
+ catch(...)
+ {
+ throw BridgeRuntimeError(
+ "[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(
+ "[automation bridge]UnoConversionUtilities<T>::anyToVariant \n"
+ "Cannot convert the value of type :\"" +
+ rAny.getValueTypeName() +
+ "\" to the expected Automation type of VARTYPE: " +
+ OUString::number(static_cast<sal_Int32>(type)),
+ nullptr, TypeClass_UNKNOWN, FailReason::TYPE_NOT_SUPPORTED,0);
+
+ throw BridgeRuntimeError(
+ "[automation bridge]UnoConversionUtilities<T>::anyToVariant \n"
+ "Conversion of any with " +
+ rAny.getValueType().getTypeName() +
+ " to VARIANT with type: " + OUString::number(static_cast<sal_Int32>(type)) +
+ " failed! Error code: " + OUString::number(hr));
+
+ }
+ if(FAILED(hr = VariantCopy(pVariant, &var)))
+ {
+ throw BridgeRuntimeError(
+ "[automation bridge]UnoConversionUtilities<T>::anyToVariant \n"
+ "VariantCopy failed for reason: " + OUString::number(hr));
+ }
+ }
+ }
+ catch (const IllegalArgumentException &)
+ {
+ throw;
+ }
+ catch (const CannotConvertException &)
+ {
+ throw;
+ }
+ catch (const BridgeRuntimeError&)
+ {
+ throw;
+ }
+ catch(const Exception & e)
+ {
+ throw BridgeRuntimeError(
+ "[automation bridge]UnoConversionUtilities<T>::anyToVariant \n"
+ "Unexpected exception occurred. Message: " + e.Message);
+ }
+ catch(...)
+ {
+ throw BridgeRuntimeError(
+ "[automation bridge]UnoConversionUtilities<T>::anyToVariant \n"
+ "Unexpected exception occurred.");
+ }
+}
+
+template<class T>
+void UnoConversionUtilities<T>::anyToVariant(VARIANT* pVariant, const Any& rAny)
+{
+ try
+ {
+ bool bIllegal = false;
+ 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() == cppu::UnoType<Date>::get() )
+ {
+ Date d;
+ if (rAny >>= d)
+ {
+ pVariant->vt = VT_DATE;
+ pVariant->date = d.Value;
+ }
+ else
+ {
+ bIllegal = true;
+ }
+ }
+ else if(rAny.getValueType() == cppu::UnoType<Decimal>::get())
+ {
+ 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() == cppu::UnoType<Currency>::get())
+ {
+ Currency c;
+ if (rAny >>= c)
+ {
+ pVariant->vt = VT_CY;
+ pVariant->cyVal.int64 = c.Value;
+ }
+ else
+ {
+ bIllegal = true;
+ }
+ }
+ else if(rAny.getValueType() == cppu::UnoType<SCode>::get())
+ {
+ 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(
+ "[automation bridge]UnoConversionUtilities<T>::anyToVariant\n"
+ "VariantClear failed with error:" + OUString::number(hr));
+ }
+ break;
+ }
+ case TypeClass_BOOLEAN:
+ {
+ bool value;
+ if (rAny >>= value)
+ {
+ pVariant->vt = VT_BOOL;
+ pVariant->boolVal = value ? 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 = *o3tl::forceAccess<sal_Unicode>(rAny);
+ pVariant->vt = VT_I2;
+ pVariant->iVal = value;
+ break;
+ }
+ case TypeClass_STRING:
+ {
+ OUString value;
+ if (rAny >>= value)
+ {
+ pVariant->vt = VT_BSTR;
+ pVariant->bstrVal = SysAllocString(o3tl::toW(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 = *static_cast<sal_Int32 const *>(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))
+ throw BridgeRuntimeError(
+ "[automation bridge] UnoConversionUtilities<T>::anyToVariant \n"
+ "Error during conversion of UNO type to Automation object!");
+
+ if (FAILED(VariantCopy(pVariant, &var)))
+ throw BridgeRuntimeError(
+ "[automation bridge] UnoConversionUtilities<T>::anyToVariant \n"
+ "Unexpected error!");
+ break;
+ }
+ default:
+ //TypeClass_SERVICE:
+ //TypeClass_EXCEPTION:
+ //When an 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_MODULE:
+ throw CannotConvertException(
+ "[automation bridge]UnoConversionUtilities<T>::anyToVariant\n"
+ "There is no conversion for this UNO type to an 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(
+ "[automation bridge]UnoConversionUtilities<T>::anyToVariant\n"
+ "The provided any of type\" " + rAny.getValueType().getTypeName() +
+ "\" is unappropriate for conversion!", Reference<XInterface>(), -1);
+
+ }
+ }
+ catch (const CannotConvertException &)
+ {
+ throw;
+ }
+ catch (const IllegalArgumentException &)
+ {
+ throw;
+ }
+ catch(const BridgeRuntimeError&)
+ {
+ throw;
+ }
+ catch(const Exception & e)
+ {
+ throw BridgeRuntimeError(
+ "[automation bridge]UnoConversionUtilities<T>::anyToVariant \n"
+ "Unexpected exception occurred. Message: " + e.Message);
+ }
+ catch(...)
+ {
+ throw BridgeRuntimeError(
+ "[automation bridge]UnoConversionUtilities<T>::anyToVariant \n"
+ "Unexpected exception occurred. " );
+ }
+}
+
+// Creates an SAFEARRAY of the specified element and if necessary
+// creates a SAFEARRAY with 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(
+ "[automation bridge]UnoConversionUtilities<T>::createUnoSequenceWrapper \n"
+ "The any does not contain a sequence!", nullptr, 0);
+ if (elemtype == VT_NULL || elemtype == VT_EMPTY)
+ throw IllegalArgumentException(
+ "[automation bridge]UnoConversionUtilities<T>::createUnoSequenceWrapper \n"
+ "No element type supplied!",nullptr, -1);
+ SAFEARRAY* pArray= nullptr;
+ // 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
+ std::unique_ptr<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= *static_cast<uno_Sequence* const*>(rSeq.getValue());
+ sal_Int32 dimsSeq= dims - 1;
+
+ // arDimSeqIndices 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 are 0 based
+ std::unique_ptr<sal_Int32[]> sarDimsSeqIndices;
+ sal_Int32* arDimsSeqIndices= nullptr;
+ if( dimsSeq > 0)
+ {
+ sarDimsSeqIndices.reset(new sal_Int32[dimsSeq]);
+ arDimsSeqIndices = sarDimsSeqIndices.get();
+ memset( arDimsSeqIndices, 0, sizeof( sal_Int32 ) * dimsSeq);
+ }
+
+ char* psaCurrentData= static_cast<char*>(pSAData);
+
+ do
+ {
+ // Get the Sequence at the current index , see arDimsSeqIndices
+ uno_Sequence * pCurrentSeq= pMultiSeq;
+ sal_Int32 curDim=1; // 1 based
+ bool skipSeq= 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= *reinterpret_cast<uno_Sequence**>(&pCurrentSeq->elements[ offset]);
+ curDim++;
+ }
+ else
+ {
+ // There is no Sequence at this index, so skip this index
+ skipSeq= 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_Int32 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= static_cast<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 a 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( reinterpret_cast<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>
+bool UnoConversionUtilities<T>::incrementMultidimensionalIndex(sal_Int32 dimensions,
+ const sal_Int32 * parDimensionLengths,
+ sal_Int32 * parMultidimensionalIndex)
+{
+ if( dimensions < 1)
+ return false;
+
+ bool ret= true;
+ bool carry= 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= 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= false;
+ ret= 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 - contains 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= (*static_cast<uno_Sequence* const *>(rSeq.getValue()))->nElements;
+ if( dimCount > seqElementCounts[ dim-1])
+ seqElementCounts.getArray()[ dim-1]= dimCount;
+
+ // we need the element type to construct the any that is
+ // passed into getElementCountAndTypeOfSequence again
+ typelib_TypeDescription* pSeqDesc= nullptr;
+ rSeq.getValueTypeDescription( &pSeqDesc);
+ typelib_TypeDescriptionReference* pElementDescRef= reinterpret_cast<typelib_IndirectTypeDescription*>(pSeqDesc)->pType;
+
+ // if the elements are Sequences then do recursion
+ if( dim < seqElementCounts.getLength() )
+ {
+ uno_Sequence* pSeq = *static_cast<uno_Sequence* const*>(rSeq.getValue());
+ uno_Sequence** arSequences= reinterpret_cast<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 = nullptr;
+ sal_uInt32 n = 0;
+
+ if( rSeq.getValueTypeClass() != TypeClass_SEQUENCE )
+ throw IllegalArgumentException(
+ "[automation bridge]UnoConversionUtilities<T>::createUnoSequenceWrapper\n"
+ "The UNO argument is not a sequence", nullptr, -1);
+
+ uno_Sequence * punoSeq= *static_cast<uno_Sequence* const *>(rSeq.getValue());
+
+ typelib_TypeDescriptionReference* pSeqTypeRef= rSeq.getValueTypeRef();
+ typelib_TypeDescription* pSeqType= nullptr;
+ TYPELIB_DANGER_GET( &pSeqType, pSeqTypeRef);
+ typelib_IndirectTypeDescription * pSeqIndDec= reinterpret_cast<typelib_IndirectTypeDescription*>(pSeqType);
+
+
+ typelib_TypeDescriptionReference * pSeqElementTypeRef= pSeqIndDec->pType;
+ TYPELIB_DANGER_RELEASE( pSeqType);
+
+ typelib_TypeDescription* pSeqElementDesc= nullptr;
+ TYPELIB_DANGER_GET( &pSeqElementDesc, pSeqElementTypeRef);
+ 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;
+ char * pSeqData= 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(
+ "[automation bridge]UnoConversionUtilities<T>::createUnoObjectWrapper \n"
+ "Cannot create an Automation interface for a UNO type which is not "
+ "a struct or interface!", nullptr, -1);
+
+ if (rObj.getValueTypeClass() == TypeClass_INTERFACE)
+ {
+ if (! (rObj >>= xInt))
+ throw IllegalArgumentException(
+ "[automation bridge] UnoConversionUtilities<T>::createUnoObjectWrapper\n "
+ "Could not create wrapper object for UNO object!", nullptr, -1);
+ //If XInterface is NULL, which is a valid value, then simply return NULL.
+ if ( ! xInt.is())
+ {
+ pVar->vt = VT_UNKNOWN;
+ pVar->punkVal = nullptr;
+ return;
+ }
+ //make sure we have the main XInterface which is used with a map
+ xInt.set(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 ?
+ auto it_uno = UnoObjToWrapperMap.find( reinterpret_cast<sal_uIntPtr>(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 supply an IDispatch by its own ?
+ else
+ {
+ Reference<XInterface> xIntComWrapper = xInt;
+
+ // Adapter? then get the COM wrapper to which the adapter delegates its calls
+ auto it = AdapterToWrapperMap.find( reinterpret_cast<sal_uIntPtr>(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.
+
+ // create an XInvocation using the invocation service
+ Reference<XInvocation> xInv;
+ Reference<XSingleServiceFactory> xInvFactory= getInvocationFactory(rObj);
+ if (xInvFactory.is())
+ {
+ Sequence<Any> params(2);
+ params.getArray()[0] = rObj;
+ params.getArray()[1] <<= OUString("FromOLE");
+ Reference<XInterface> xInt2 = xInvFactory->createInstanceWithArguments(params);
+ xInv.set(xInt2, UNO_QUERY);
+ }
+
+ if (xInv.is())
+ {
+ Reference<XInterface> xNewWrapper = createUnoWrapperInstance();
+ Reference<css::lang::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[reinterpret_cast<sal_uIntPtr>(xInt.get())]= xNewWrapper;
+ convertSelfToCom(xNewWrapper, pVar);
+ return;
+ }
+ }
+}
+
+template<class T>
+void UnoConversionUtilities<T>::variantToAny( const VARIANT* pVariant, Any& rAny,
+ 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, pVariant))) // remove VT_BYREF
+ throw BridgeRuntimeError(
+ "[automation bridge] UnoConversionUtilities<T>::variantToAny \n"
+ "VariantCopyInd failed for reason : " + OUString::number(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, cppu::UnoType<decltype(unoSeq)>::get());
+ }
+ else
+ {
+ switch (var.vt)
+ {
+ case VT_EMPTY:
+ rAny.setValue(nullptr, Type());
+ break;
+ case VT_NULL:
+ rAny.setValue(nullptr, Type());
+ break;
+ case VT_I2:
+ rAny.setValue( & var.iVal, cppu::UnoType<sal_Int16>::get());
+ break;
+ case VT_I4:
+ rAny.setValue( & var.lVal, cppu::UnoType<sal_Int32>::get());
+ // necessary for use in JavaScript ( see "reduceRange")
+ if( bReduceValueRange)
+ reduceRange(rAny);
+ break;
+ case VT_R4:
+ rAny.setValue( & var.fltVal, cppu::UnoType<float>::get());
+ break;
+ case VT_R8:
+ rAny.setValue(& var.dblVal, cppu::UnoType<double>::get());
+ 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(o3tl::toU(var.bstrVal));
+ rAny.setValue( &b, cppu::UnoType<decltype(b)>::get());
+ break;
+ }
+ case VT_UNKNOWN:
+ case VT_DISPATCH:
+ {
+ //check if it is a UNO type
+ CComQIPtr<IUnoTypeWrapper> spType(static_cast<IUnknown*>(var.byref));
+ if (spType)
+ {
+ CComBSTR sName;
+ if (FAILED(spType->get_Name(&sName)))
+ throw BridgeRuntimeError(
+ "[automation bridge]UnoConversionUtilities<T>::variantToAny \n"
+ "Failed to get the type name from a UnoTypeWrapper!");
+ Type type;
+ if (!getType(sName, type))
+ {
+ throw CannotConvertException(
+ OUString::Concat("[automation bridge]UnoConversionUtilities<T>::variantToAny \n"
+ "A UNO type with the name: ") + o3tl::toU(LPCOLESTR(sName)) +
+ "does not exist!",
+ nullptr, 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:
+ {
+ rAny <<= (var.boolVal == VARIANT_TRUE);
+ break;
+ }
+ case VT_I1:
+ rAny.setValue( & var.cVal, cppu::UnoType<sal_Int8>::get());
+ break;
+ case VT_UI1: // there is no unsigned char in UNO
+ rAny <<= sal_Int8(var.bVal);
+ break;
+ case VT_UI2:
+ rAny.setValue( & var.uiVal, cppu::UnoType<cppu::UnoUnsignedShortType>::get() );
+ break;
+ case VT_UI4:
+ rAny.setValue( & var.ulVal, cppu::UnoType<sal_uInt32>::get());
+ break;
+ case VT_INT:
+ rAny.setValue( & var.intVal, cppu::UnoType<sal_Int32>::get());
+ break;
+ case VT_UINT:
+ rAny.setValue( & var.uintVal, cppu::UnoType<sal_uInt32>::get());
+ break;
+ case VT_VOID:
+ rAny.setValue( nullptr, 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 (const IllegalArgumentException &)
+ {
+ throw;
+ }
+ catch (const CannotConvertException &)
+ {
+ throw;
+ }
+ catch (const BridgeRuntimeError &)
+ {
+ throw;
+ }
+ catch (const Exception & e)
+ {
+ throw BridgeRuntimeError("[automation bridge] unexpected exception in "
+ "UnoConversionUtilities<T>::variantToAny ! Message : \n" +
+ e.Message);
+ }
+ catch(...)
+ {
+ throw BridgeRuntimeError(
+ "[automation bridge] unexpected exception in "
+ "UnoConversionUtilities<T>::variantToAny !");
+ }
+
+}
+// The function converts an IUnknown* into a UNO interface or struct. The
+// IUnknown pointer can constitute different kind of objects:
+// 1. a wrapper of a UNO struct (the wrapper was created by this bridge)
+// 2. a wrapper of a 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. 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 than 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 a 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>
+Any UnoConversionUtilities<T>::createOleObjectWrapper(VARIANT* pVar, const Type& aType)
+{
+ //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(
+ "[automation bridge]UnoConversionUtilities<T>::createOleObjectWrapper \n"
+ "The VARIANT does not contain an object type! ", nullptr, -1);
+
+ MutexGuard guard( getBridgeMutex());
+
+ CComPtr<IUnknown> spUnknown;
+ CComPtr<IDispatch> spDispatch;
+
+ if (pVar->vt == VT_UNKNOWN)
+ {
+ spUnknown = pVar->punkVal;
+ if (spUnknown)
+ spUnknown.QueryInterface( & spDispatch.p);
+ }
+ else if (pVar->vt == VT_DISPATCH && pVar->pdispVal != nullptr)
+ {
+ CComPtr<IDispatch> spDispatch2(pVar->pdispVal);
+ if (spDispatch2)
+ spDispatch2.QueryInterface( & spUnknown.p);
+ }
+
+ static Type VOID_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 = cppu::UnoType<XInterface>::get();
+ break;
+ case VT_DISPATCH:
+ desiredType = cppu::UnoType<XInvocation>::get();
+ break;
+ default:
+ desiredType = aType;
+ }
+ }
+
+ // COM pointer are NULL, no wrapper required
+ if (spUnknown == nullptr)
+ {
+ Reference<XInterface> xInt;
+ if( aType.getTypeClass() == TypeClass_INTERFACE)
+ ret.setValue( &xInt, aType);
+ else if( aType.getTypeClass() == TypeClass_STRUCT)
+ ret.setValue( nullptr, aType);
+ else
+ ret <<= xInt;
+ return ret;
+ }
+
+
+ // Check if "spUnknown" is a UNO wrapper, that is a UNO object that has been
+ // passed to COM. Then it supports IUnoObjectWrapper
+ // and we extract the original UNO object.
+ CComQIPtr<IUnoObjectWrapper> spUno( spUnknown);
+ 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;
+ auto cit_currWrapper= ComPtrToWrapperMap.find( reinterpret_cast<sal_uIntPtr>(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.
+ auto it = WrapperToAdapterMap.find(reinterpret_cast<sal_uIntPtr>(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(
+ "[automation bridge]UnoConversionUtilities<T>::createOleObjectWrapper \n"
+ "The COM object is not suitable for the UNO type: " +
+ desiredType.getTypeName(), nullptr, -1);
+ }
+ else
+ {
+ //There is an adapter available
+ Reference<XInterface> xIntAdapter(reinterpret_cast<XInterface*>(it->second));
+ ret = xIntAdapter->queryInterface( desiredType);
+ if ( ! ret.hasValue())
+ throw IllegalArgumentException(
+ "[automation bridge]UnoConversionUtilities<T>::createOleObjectWrapper \n"
+ "The COM object is not suitable for the UNO type: " +
+ desiredType.getTypeName(), nullptr, -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 != cppu::UnoType<XInvocation>::get())
+ {
+ 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(
+ "[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];
+ params[0] <<= reinterpret_cast<sal_uIntPtr>(spUnknown.p);
+ params[1] <<= (pVar->vt == VT_DISPATCH);
+ params[2] <<= seqTypes;
+
+ xInit->initialize( Sequence<Any>( params, 3));
+ ComPtrToWrapperMap[reinterpret_cast<sal_uInt64>(spUnknown.p)] = xIntNewProxy;
+
+ // 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 == cppu::UnoType<XInvocation>::get()||
+ (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. A 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())
+ {
+ throw BridgeRuntimeError(
+ "[automation bridge]UnoConversionUtilities<T>::createOleObjectWrapper \n"
+ "Could not create a proxy for COM object! Creation of adapter failed.");
+ }
+
+ // 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 std::unordered_map<sal_uInt64,sal_uInt64>::value_type VALUE;
+ AdapterToWrapperMap.insert( VALUE( reinterpret_cast<sal_uInt64>(xIntAdapted.get()), reinterpret_cast<sal_uInt64>(receiver.get())));
+ WrapperToAdapterMap.insert( VALUE( reinterpret_cast<sal_uInt64>(receiver.get()), reinterpret_cast<sal_uInt64>(xIntAdapted.get())));
+
+ 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 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(
+ "[automation bridge] Conversion of ValueObject failed ");
+ }
+ catch (const BridgeRuntimeError &)
+ {
+ throw;
+ }
+ catch (const Exception & e)
+ {
+ throw BridgeRuntimeError("[automation bridge] unexpected exception in "
+ "UnoConversionUtilities<T>::convertValueObject ! Message : \n" +
+ e.Message);
+ }
+ catch(...)
+ {
+ throw BridgeRuntimeError(
+ "[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
+ {
+ if( pvar->vt != VT_DISPATCH)
+ throw BridgeRuntimeError("[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("[automation bridge] UnoConversionUtilities<T>::dispatchExObject2Sequence \n"
+ "Conversion of dispatch object to Sequence failed!");
+
+ DISPID dispid;
+ DISPPARAMS param= {nullptr,nullptr,0,0};
+ CComVariant result;
+
+ OLECHAR const * sLength= L"length";
+
+ // Get the length of the array. Can also be obtained through GetNextDispID. The
+ // method only returns DISPIDs of the array data. Their names are like "0", "1" etc.
+ if( FAILED( hr= pdispEx->GetIDsOfNames(IID_NULL, const_cast<OLECHAR **>(&sLength), 1, LOCALE_USER_DEFAULT, &dispid)))
+ throw BridgeRuntimeError("[automation bridge] UnoConversionUtilities<T>::dispatchExObject2Sequence \n"
+ "Conversion of dispatch object to Sequence failed!");
+ if( FAILED( hr= pdispEx->InvokeEx(dispid, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET,
+ &param, &result, nullptr, nullptr)))
+ throw BridgeRuntimeError("[automation bridge] UnoConversionUtilities<T>::dispatchExObject2Sequence \n"
+ "Conversion of dispatch object to Sequence failed!");
+ if( FAILED( VariantChangeType( &result, &result, 0, VT_I4)))
+ throw BridgeRuntimeError("[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= nullptr;
+ 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=nullptr;
+ 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, nullptr, 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::number( i);
+ OLECHAR* sindex = const_cast<OLECHAR *>(o3tl::toW(ousIndex.getStr()));
+
+ if( FAILED( hr= pdispEx->GetIDsOfNames(IID_NULL, &sindex , 1, LOCALE_USER_DEFAULT, &dispid)))
+ {
+ throw BridgeRuntimeError("[automation bridge] UnoConversionUtilities<T>::dispatchExObject2Sequence \n"
+ "Conversion of dispatch object to Sequence failed!");
+ }
+ if( FAILED( hr= pdispEx->InvokeEx(dispid, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET,
+ &param, &result, nullptr, nullptr)))
+ {
+ throw BridgeRuntimeError("[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= pArray + (i * nelementSize);
+
+ if( result.vt & VT_DISPATCH && typeElement == typelib_TypeClass_SEQUENCE)
+ {
+ variantToAny( &result, any, elemType, false);
+ // copy the converted VARIANT, that is a Sequence to the Sequence
+ uno_Sequence * p_unoSeq= *static_cast<uno_Sequence* const *>(any.getValue());
+ // just copy the pointer of the uno_Sequence
+ // nelementSize should be 4 !!!!
+ memcpy( pDest, &p_unoSeq, nelementSize);
+ osl_atomic_increment( &p_unoSeq->nRefCount);
+ }
+ else // Element type is no Sequence -> do one conversion
+ {
+ variantToAny( &result, any, elemType, 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() == css::uno::TypeClass(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);
+ }
+ catch (const BridgeRuntimeError &)
+ {
+ throw;
+ }
+ catch (const Exception & e)
+ {
+ throw BridgeRuntimeError("[automation bridge] unexpected exception in "
+ "UnoConversionUtilities<T>::convertValueObject ! Message : \n" +
+ e.Message);
+ }
+ catch(...)
+ {
+ throw BridgeRuntimeError(
+ "[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 recursively 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)
+{
+ 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, cppu::UnoType<decltype(element)>::get());
+ }
+ 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:
+ 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], false);
+ else
+ variantToAny(&variant, pUnoArray[index[actDim - 1] - lBound],
+ getElementTypeOfSequence(unotype), 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_TypeDescription* pDescSeq= nullptr;
+ seqType.getDescription(& pDescSeq);
+ retValue = Type(reinterpret_cast<typelib_IndirectTypeDescription *>(pDescSeq)->pType);
+ typelib_typedescription_release(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)
+ {
+ std::unique_ptr<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 a VARIANT has the type VT_DISPATCH it can either be a 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.
+// A JScript has property like "0", "1", "2" etc. which represent the
+// value at the corresponding index of the array
+template<class T>
+bool UnoConversionUtilities<T>::isJScriptArray(const VARIANT* rvar)
+{
+ OSL_ENSURE( rvar->vt == VT_DISPATCH, "param is not a VT_DISPATCH");
+ HRESULT hr;
+ OLECHAR const * sindex= L"0";
+ DISPID id;
+ if ( rvar->vt == VT_DISPATCH && rvar->pdispVal )
+ {
+ hr= rvar->pdispVal->GetIDsOfNames(
+ IID_NULL, const_cast<OLECHAR **>(&sindex), 1, LOCALE_USER_DEFAULT,
+ &id);
+
+ if( SUCCEEDED ( hr) )
+ return true;
+ }
+
+ return 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 expect an array( SafeArray or IDispatch) of Strings.
+ Any anyNames;
+ variantToAny( &var, anyNames, cppu::UnoType<Sequence<Any>>::get());
+ Sequence<Any> seqAny;
+ if( anyNames >>= seqAny)
+ {
+ seqTypes.realloc( seqAny.getLength());
+ auto pseqTypes = seqTypes.getArray();
+ for( sal_Int32 i=0; i < seqAny.getLength(); i++)
+ {
+ OUString typeName;
+ seqAny[i] >>= typeName;
+ pseqTypes[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("com.sun.star.script.Converter");
+ if (xIntConverter.is())
+ m_typeConverter.set(xIntConverter, UNO_QUERY);
+ }
+ }
+ return m_typeConverter;
+}
+
+/* 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 000000000..28286bddb
--- /dev/null
+++ b/extensions/source/ole/unoobjw.cxx
@@ -0,0 +1,3437 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+// Documentation pointers for recent work:
+//
+// https://www.codeproject.com/Articles/9014/Understanding-COM-Event-Handling
+// https://blogs.msdn.microsoft.com/ericlippert/2005/02/15/why-does-wscript-connectobject-not-always-work/
+
+#include "ole2uno.hxx"
+
+#include <stdio.h>
+#include <list>
+#include <sstream>
+#include <unordered_map>
+#include <vector>
+
+#if defined _MSC_VER && defined __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wall"
+#pragma clang diagnostic ignored "-Wattributes"
+#pragma clang diagnostic ignored "-Wdelete-incomplete"
+#pragma clang diagnostic ignored "-Wdynamic-class-memaccess"
+#pragma clang diagnostic ignored "-Wextra"
+#pragma clang diagnostic ignored "-Wint-to-pointer-cast"
+#pragma clang diagnostic ignored "-Winvalid-noreturn"
+#pragma clang diagnostic ignored "-Wmicrosoft"
+#pragma clang diagnostic ignored "-Wnon-pod-varargs"
+#pragma clang diagnostic ignored "-Wnon-virtual-dtor"
+#pragma clang diagnostic ignored "-Wnonportable-include-path"
+#pragma clang diagnostic ignored "-Wsequence-point"
+#pragma clang diagnostic ignored "-Wtypename-missing"
+#endif
+#include <atlbase.h>
+#include <atlcom.h>
+#if defined _MSC_VER && defined __clang__
+#pragma clang diagnostic pop
+#endif
+#include <comdef.h>
+
+#include <osl/diagnose.h>
+#include <salhelper/simplereferenceobject.hxx>
+#include <rtl/ref.hxx>
+#include <rtl/ustring.hxx>
+#include <sal/log.hxx>
+#include <com/sun/star/beans/MethodConcept.hpp>
+#include <com/sun/star/beans/PropertyConcept.hpp>
+#include <com/sun/star/lang/NoSuchMethodException.hpp>
+#include <com/sun/star/script/CannotConvertException.hpp>
+#include <com/sun/star/script/FailReason.hpp>
+#include <com/sun/star/reflection/theCoreReflection.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/container/XEnumeration.hpp>
+#include <com/sun/star/container/XEnumerationAccess.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 <ooo/vba/XCollection.hpp>
+#include <ooo/vba/XConnectable.hpp>
+#include <ooo/vba/XConnectionPoint.hpp>
+#include <ooo/vba/XSink.hpp>
+#include <ooo/vba/msforms/XCheckBox.hpp>
+#include <osl/interlck.h>
+#include <com/sun/star/uno/genfunc.h>
+#include <comphelper/automationinvokedzone.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/profilezone.hxx>
+#include <comphelper/windowsdebugoutput.hxx>
+#include <comphelper/windowserrorstring.hxx>
+#include <o3tl/char16_t2wchar_t.hxx>
+#include <o3tl/safeint.hxx>
+
+#include "comifaces.hxx"
+#include "jscriptclasses.hxx"
+#include "unotypewrapper.hxx"
+#include "oleobjw.hxx"
+#include "unoobjw.hxx"
+#include "servprov.hxx"
+
+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;
+
+std::unordered_map<sal_uIntPtr, WeakReference<XInterface> > UnoObjToWrapperMap;
+static bool writeBackOutParameter(VARIANTARG* pDest, VARIANT* pSource);
+static bool writeBackOutParameter2( VARIANTARG* pDest, VARIANT* pSource);
+static HRESULT mapCannotConvertException(const 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 != nullptr)
+ {
+ pInfo->wCode = UNO_2_OLE_EXCEPTIONCODE;
+ pInfo->bstrSource = SysAllocString(L"[automation bridge] ");
+ pInfo->bstrDescription = SysAllocString(o3tl::toW(message.getStr()));
+ }
+}
+
+InterfaceOleWrapper::InterfaceOleWrapper( Reference<XMultiServiceFactory> const & xFactory,
+ sal_uInt8 unoWrapperClass, sal_uInt8 comWrapperClass):
+ UnoConversionUtilities<InterfaceOleWrapper>( xFactory, unoWrapperClass, comWrapperClass),
+ m_defaultValueType( 0)
+{
+}
+
+InterfaceOleWrapper::~InterfaceOleWrapper()
+{
+ MutexGuard guard(getBridgeMutex());
+ // remove entries in global map
+ auto it = UnoObjToWrapperMap.find( reinterpret_cast<sal_uIntPtr>(m_xOrigin.get()));
+ if(it != UnoObjToWrapperMap.end())
+ UnoObjToWrapperMap.erase(it);
+}
+
+COM_DECLSPEC_NOTHROW STDMETHODIMP InterfaceOleWrapper::QueryInterface(REFIID riid, void ** ppv)
+{
+ comphelper::Automation::AutomationInvokedZone aAutomationActive;
+
+ SAL_INFO("extensions.olebridge", this << "@InterfaceOleWrapper::QueryInterface(" << riid << ")");
+
+ HRESULT ret= S_OK;
+
+ if( !ppv)
+ return E_POINTER;
+
+ if(IsEqualIID(riid, IID_IUnknown))
+ {
+ AddRef();
+ *ppv = static_cast<IUnknown*>(static_cast<IDispatch*>(this));
+ SAL_INFO("extensions.olebridge", " " << *ppv);
+ }
+ else if (IsEqualIID(riid, IID_IDispatch))
+ {
+ AddRef();
+ *ppv = static_cast<IDispatch*>(this);
+ SAL_INFO("extensions.olebridge", " " << *ppv);
+ }
+ else if (IsEqualIID(riid, IID_IProvideClassInfo))
+ {
+ Reference<ooo::vba::XConnectable> xConnectable(m_xOrigin, UNO_QUERY);
+ if (!xConnectable.is())
+ return E_NOINTERFACE;
+ AddRef();
+ *ppv = static_cast<IProvideClassInfo*>(this);
+ SAL_INFO("extensions.olebridge", " " << *ppv);
+ }
+ else if (IsEqualIID(riid, IID_IConnectionPointContainer))
+ {
+ Reference<ooo::vba::XConnectable> xConnectable(m_xOrigin, UNO_QUERY);
+ if (!xConnectable.is())
+ return E_NOINTERFACE;
+ AddRef();
+ *ppv = static_cast<IConnectionPointContainer*>(this);
+ SAL_INFO("extensions.olebridge", " " << *ppv);
+ }
+ else if( IsEqualIID( riid, __uuidof( IUnoObjectWrapper)))
+ {
+ AddRef();
+ *ppv= static_cast<IUnoObjectWrapper*>(this);
+ SAL_INFO("extensions.olebridge", " " << *ppv);
+ }
+ else
+ ret= E_NOINTERFACE;
+ return ret;
+}
+
+COM_DECLSPEC_NOTHROW STDMETHODIMP_(ULONG) InterfaceOleWrapper::AddRef()
+{
+ acquire();
+ // does not need to guard because one should not rely on the return value of
+ // AddRef anyway
+ return m_refCount;
+}
+
+COM_DECLSPEC_NOTHROW STDMETHODIMP_(ULONG) InterfaceOleWrapper::Release()
+{
+ ULONG n= m_refCount;
+ release();
+ return n - 1;
+}
+
+// IUnoObjectWrapper --------------------------------------------------------
+COM_DECLSPEC_NOTHROW STDMETHODIMP InterfaceOleWrapper::getWrapperXInterface( Reference<XInterface>* pXInt)
+{
+ pXInt->set( static_cast<XWeak*>( this), UNO_QUERY);
+ return pXInt->is() ? S_OK : E_FAIL;
+}
+COM_DECLSPEC_NOTHROW STDMETHODIMP InterfaceOleWrapper::getOriginalUnoObject( Reference<XInterface>* pXInt)
+{
+ *pXInt= m_xOrigin;
+ return m_xOrigin.is() ? S_OK : E_FAIL;
+}
+COM_DECLSPEC_NOTHROW STDMETHODIMP InterfaceOleWrapper::getOriginalUnoStruct( Any * pStruct)
+{
+ comphelper::Automation::AutomationInvokedZone aAutomationActive;
+
+ 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;
+}
+
+COM_DECLSPEC_NOTHROW STDMETHODIMP InterfaceOleWrapper::GetTypeInfoCount( UINT *pctinfo )
+{
+ SAL_INFO("extensions.olebridge", this << "@InterfaceOleWrapper::GetTypeInfoCount");
+
+ if (!pctinfo)
+ return E_POINTER;
+
+ *pctinfo = 1;
+
+ return S_OK;
+}
+
+namespace {
+
+class CXTypeInfo : public ITypeInfo,
+ public CComObjectRoot
+{
+public:
+ enum class Kind { COCLASS, MAIN, OUTGOING };
+
+#if defined __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunused-function"
+#endif
+ BEGIN_COM_MAP(CXTypeInfo)
+#if defined __clang__
+#pragma clang diagnostic pop
+#endif
+ COM_INTERFACE_ENTRY(ITypeInfo)
+#if defined __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Winconsistent-missing-override"
+#pragma clang diagnostic ignored "-Wunused-function"
+#endif
+ END_COM_MAP()
+#if defined __clang__
+#pragma clang diagnostic pop
+#endif
+
+ DECLARE_NOT_AGGREGATABLE(CXTypeInfo)
+
+ virtual ~CXTypeInfo() {}
+
+ void InitForCoclass(Reference<XInterface> xOrigin,
+ const OUString& sImplementationName,
+ const IID& rIID,
+ Reference<XMultiServiceFactory> xMSF);
+ void InitForClassItself(Reference<XInterface> xOrigin,
+ const OUString& sImplementationName,
+ const IID& rIID,
+ Reference<XMultiServiceFactory> xMSF);
+ void InitForOutgoing(Reference<XInterface> xOrigin,
+ const OUString& sInterfaceName,
+ const IID& rIID,
+ Reference<XMultiServiceFactory> xMSF,
+ Type aType);
+ virtual HRESULT STDMETHODCALLTYPE GetTypeAttr(TYPEATTR **ppTypeAttr) override;
+ virtual HRESULT STDMETHODCALLTYPE GetTypeComp(ITypeComp **ppTComp) override;
+ virtual HRESULT STDMETHODCALLTYPE GetFuncDesc(UINT index,
+ FUNCDESC **ppFuncDesc) override;
+ virtual HRESULT STDMETHODCALLTYPE GetVarDesc(UINT index,
+ VARDESC **ppVarDesc) override;
+ virtual HRESULT STDMETHODCALLTYPE GetNames(MEMBERID memid,
+ BSTR *rgBstrNames,
+ UINT cMaxNames,
+ UINT *pcNames) override;
+ virtual HRESULT STDMETHODCALLTYPE GetRefTypeOfImplType(UINT index,
+ HREFTYPE *pRefType) override;
+ virtual HRESULT STDMETHODCALLTYPE GetImplTypeFlags(UINT index,
+ INT *pImplTypeFlags) override;
+ virtual HRESULT STDMETHODCALLTYPE GetIDsOfNames(LPOLESTR *rgszNames,
+ UINT cNames,
+ MEMBERID *pMemId) override;
+ virtual HRESULT STDMETHODCALLTYPE Invoke(PVOID pvInstance,
+ MEMBERID memid,
+ WORD wFlags,
+ DISPPARAMS *pDispParams,
+ VARIANT *pVarResult,
+ EXCEPINFO *pExcepInfo,
+ UINT *puArgErr) override;
+ virtual HRESULT STDMETHODCALLTYPE GetDocumentation(MEMBERID memid,
+ BSTR *pBstrName,
+ BSTR *pBstrDocString,
+ DWORD *pdwHelpContext,
+ BSTR *pBstrHelpFile) override;
+ virtual HRESULT STDMETHODCALLTYPE GetDllEntry(MEMBERID memid,
+ INVOKEKIND invKind,
+ BSTR *pBstrDllName,
+ BSTR *pBstrName,
+ WORD *pwOrdinal) override;
+ virtual HRESULT STDMETHODCALLTYPE GetRefTypeInfo(HREFTYPE hRefType,
+ ITypeInfo **ppTInfo) override;
+ virtual HRESULT STDMETHODCALLTYPE AddressOfMember(MEMBERID memid,
+ INVOKEKIND invKind,
+ PVOID *ppv) override;
+ virtual HRESULT STDMETHODCALLTYPE CreateInstance(IUnknown *pUnkOuter,
+ REFIID riid,
+ PVOID *ppvObj) override;
+ virtual HRESULT STDMETHODCALLTYPE GetMops(MEMBERID memid,
+ BSTR *pBstrMops) override;
+ virtual HRESULT STDMETHODCALLTYPE GetContainingTypeLib(ITypeLib **ppTLib,
+ UINT *pIndex) override;
+ virtual void STDMETHODCALLTYPE ReleaseTypeAttr(TYPEATTR *pTypeAttr) override;
+ virtual void STDMETHODCALLTYPE ReleaseFuncDesc(FUNCDESC *pFuncDesc) override;
+ virtual void STDMETHODCALLTYPE ReleaseVarDesc(VARDESC *pVarDesc) override;
+
+private:
+ Kind meKind;
+ Reference<XInterface> mxOrigin;
+ OUString msImplementationName;
+ OUString msInterfaceName;
+ IID maIID;
+ Reference<XMultiServiceFactory> mxMSF;
+ Type maType;
+};
+
+class CXTypeLib : public ITypeLib,
+ public CComObjectRoot
+{
+public:
+#if defined __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunused-function"
+#endif
+ BEGIN_COM_MAP(CXTypeLib)
+#if defined __clang__
+#pragma clang diagnostic pop
+#endif
+ COM_INTERFACE_ENTRY(ITypeLib)
+#if defined __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Winconsistent-missing-override"
+#pragma clang diagnostic ignored "-Wunused-function"
+#endif
+ END_COM_MAP()
+#if defined __clang__
+#pragma clang diagnostic pop
+#endif
+
+ DECLARE_NOT_AGGREGATABLE(CXTypeLib)
+
+ virtual ~CXTypeLib() {}
+
+ void Init(Reference<XInterface> xOrigin,
+ const OUString& sImplementationName,
+ Reference<XMultiServiceFactory> xMSF)
+ {
+ SAL_INFO("extensions.olebridge", this << "@CXTypeLib::Init for " << sImplementationName);
+ mxOrigin = xOrigin;
+ msImplementationName = sImplementationName;
+ mxMSF = xMSF;
+ }
+
+ virtual UINT STDMETHODCALLTYPE GetTypeInfoCount() override
+ {
+ SAL_WARN("extensions.olebridge", this << "@CXTypeLib::GetTypeInfoCount");
+ return 1;
+ }
+
+ virtual HRESULT STDMETHODCALLTYPE GetTypeInfo(UINT,
+ ITypeInfo **) override
+ {
+ SAL_WARN("extensions.olebridge", this << "@CXTypeLib::GetTypeInfo: E_NOTIMPL");
+ return E_NOTIMPL;
+ }
+
+ virtual HRESULT STDMETHODCALLTYPE GetTypeInfoType(UINT,
+ TYPEKIND *) override
+ {
+ SAL_WARN("extensions.olebridge", this << "@CXTypeLib::GetTypeInfoType: E_NOTIMPL");
+ return E_NOTIMPL;
+ }
+
+ virtual HRESULT STDMETHODCALLTYPE GetTypeInfoOfGuid(REFGUID guid,
+ ITypeInfo **ppTInfo) override
+ {
+ comphelper::Automation::AutomationInvokedZone aAutomationActive;
+
+ SAL_INFO("extensions.olebridge", this << "@CXTypeLib::GetTypeInfoOfGuid(" << guid << ")");
+ if (!ppTInfo)
+ return E_POINTER;
+
+ Reference<ooo::vba::XConnectable> xConnectable(mxOrigin, UNO_QUERY);
+ if (!xConnectable.is())
+ return TYPE_E_ELEMENTNOTFOUND;
+
+ IID aIID;
+ if (SUCCEEDED(IIDFromString(reinterpret_cast<LPOLESTR>(xConnectable->getIID().pData->buffer), &aIID)))
+ {
+ if (IsEqualIID(guid, aIID))
+ {
+ HRESULT ret;
+
+ CComObject<CXTypeInfo>* pTypeInfo;
+
+ ret = CComObject<CXTypeInfo>::CreateInstance(&pTypeInfo);
+ if (FAILED(ret))
+ return ret;
+
+ pTypeInfo->AddRef();
+
+ pTypeInfo->InitForCoclass(mxOrigin, msImplementationName, aIID, mxMSF);
+
+ *ppTInfo = pTypeInfo;
+
+ return S_OK;
+ }
+ }
+
+#if 0
+ ooo::vba::TypeAndIID aTypeAndIID = xConnectable->GetConnectionPoint();
+
+ IID aIID;
+ if (SUCCEEDED(IIDFromString((LPOLESTR)aTypeAndIID.IID.pData->buffer, &aIID)))
+ {
+ HRESULT ret;
+
+ CComObject<CXTypeInfo>* pTypeInfo;
+
+ ret = CComObject<CXTypeInfo>::CreateInstance(&pTypeInfo);
+ if (FAILED(ret))
+ return ret;
+
+ pTypeInfo->AddRef();
+
+ pTypeInfo->InitForOutgoing(mxOrigin, msImplementationName, aIID, mxMSF);
+
+ *ppTInfo = pTypeInfo;
+
+ return S_OK;
+ }
+#else
+ SAL_WARN("extensions.olebridge", "Not implemented: GetTypeInfoOfGuid(" << guid << ")");
+#endif
+
+ return TYPE_E_ELEMENTNOTFOUND;
+
+ }
+
+ virtual HRESULT STDMETHODCALLTYPE GetLibAttr(TLIBATTR **) override
+ {
+ SAL_WARN("extensions.olebridge", this << "@CXTypeLib::GetLibAttr: E_NOTIMPL");
+ return E_NOTIMPL;
+ }
+
+ virtual HRESULT STDMETHODCALLTYPE GetTypeComp(ITypeComp **) override
+ {
+ SAL_WARN("extensions.olebridge", this << "@CXTypeLib::GetTypeComp: E_NOTIMPL");
+ return E_NOTIMPL;
+ }
+
+ virtual HRESULT STDMETHODCALLTYPE GetDocumentation(INT,
+ BSTR *,
+ BSTR *,
+ DWORD *,
+ BSTR *) override
+ {
+ SAL_WARN("extensions.olebridge", this << "@CXTypeLib::GetDocumentation: E_NOTIMPL");
+ return E_NOTIMPL;
+ }
+
+ virtual HRESULT STDMETHODCALLTYPE IsName(LPOLESTR,
+ ULONG,
+ BOOL *) override
+ {
+ SAL_WARN("extensions.olebridge", this << "@CXTypeLib:IsName: E_NOTIMPL");
+ return E_NOTIMPL;
+ }
+
+ virtual HRESULT STDMETHODCALLTYPE FindName(LPOLESTR,
+ ULONG,
+ ITypeInfo **,
+ MEMBERID *,
+ USHORT *) override
+ {
+ SAL_WARN("extensions.olebridge", this << "@CXTypeLib::FindName: E_NOTIMPL");
+ return E_NOTIMPL;
+ }
+
+ virtual void STDMETHODCALLTYPE ReleaseTLibAttr(TLIBATTR *) override
+ {
+ SAL_WARN("extensions.olebridge", this << "@CXTypeLib::ReleaseTLibAttr: E_NOTIMPL");
+ }
+
+private:
+ Reference<XInterface> mxOrigin;
+ OUString msImplementationName;
+ Reference<XMultiServiceFactory> mxMSF;
+};
+
+}
+
+void CXTypeInfo::InitForCoclass(Reference<XInterface> xOrigin,
+ const OUString& sImplementationName,
+ const IID& rIID,
+ Reference<XMultiServiceFactory> xMSF)
+{
+ SAL_INFO("extensions.olebridge", this << "@CXTypeInfo::InitForCoclass(" << sImplementationName << "," << rIID << ")");
+ meKind = Kind::COCLASS;
+ mxOrigin = xOrigin;
+ msImplementationName = sImplementationName;
+ maIID = rIID;
+ mxMSF = xMSF;
+}
+
+void CXTypeInfo::InitForClassItself(Reference<XInterface> xOrigin,
+ const OUString& sImplementationName,
+ const IID& rIID,
+ Reference<XMultiServiceFactory> xMSF)
+{
+ SAL_INFO("extensions.olebridge", this << "@CXTypeInfo::InitForClassItself(" << sImplementationName << "," << rIID << ")");
+ meKind = Kind::MAIN;
+ mxOrigin = xOrigin;
+ msImplementationName = sImplementationName;
+ maIID = rIID;
+ mxMSF = xMSF;
+}
+
+void CXTypeInfo::InitForOutgoing(Reference<XInterface> xOrigin,
+ const OUString& sInterfaceName,
+ const IID& rIID,
+ Reference<XMultiServiceFactory> xMSF,
+ Type aType)
+{
+ SAL_INFO("extensions.olebridge", this << "@CXTypeInfo::InitForOutgoing(" << sInterfaceName << "," << rIID << ")");
+ meKind = Kind::OUTGOING;
+ mxOrigin = xOrigin;
+ msInterfaceName = sInterfaceName;
+ maIID = rIID;
+ mxMSF = xMSF;
+ maType = aType;
+}
+
+HRESULT STDMETHODCALLTYPE CXTypeInfo::GetTypeAttr(TYPEATTR **ppTypeAttr)
+{
+ comphelper::Automation::AutomationInvokedZone aAutomationActive;
+
+ SAL_INFO("extensions.olebridge", this << "@CXTypeInfo::GetTypeAttr");
+
+ if (!ppTypeAttr)
+ return E_POINTER;
+
+ assert(!IsEqualIID(maIID, IID_NULL));
+
+ TYPEATTR *pTypeAttr = new TYPEATTR;
+ memset(pTypeAttr, 0, sizeof(*pTypeAttr));
+
+ pTypeAttr->guid = maIID;
+
+ if (meKind == Kind::COCLASS)
+ {
+ pTypeAttr->typekind = TKIND_COCLASS;
+ pTypeAttr->cFuncs = 0;
+ pTypeAttr->cVars = 0;
+ pTypeAttr->cImplTypes = 3;
+ pTypeAttr->cbSizeVft = 0;
+ pTypeAttr->cbAlignment = 8;
+ pTypeAttr->wTypeFlags = TYPEFLAG_FCANCREATE;
+ }
+ else if (meKind == Kind::MAIN)
+ {
+ pTypeAttr->typekind = TKIND_DISPATCH;
+ pTypeAttr->cFuncs = 10; // FIXME, dummy
+ pTypeAttr->cVars = 0;
+ pTypeAttr->cImplTypes = 1;
+ // FIXME: I think this is always supposed to be as if just for the seven methods in
+ // IDIspatch?
+ pTypeAttr->cbSizeVft = 7 * sizeof(void*);
+ pTypeAttr->cbAlignment = 8;
+ pTypeAttr->wTypeFlags = TYPEFLAG_FHIDDEN|TYPEFLAG_FDISPATCHABLE;
+ }
+ else if (meKind == Kind::OUTGOING)
+ {
+ pTypeAttr->typekind = TKIND_DISPATCH;
+
+ Reference<XIdlReflection> xRefl = theCoreReflection::get(comphelper::getComponentContext(mxMSF));
+ assert(xRefl.is());
+
+ Reference<XIdlClass> xClass = xRefl->forName(maType.getTypeName());
+ assert(xClass.is());
+
+ auto aMethods = xClass->getMethods();
+ assert(xClass->getTypeClass() == TypeClass_INTERFACE &&
+ aMethods.getLength() > 0);
+
+ // Drop the three XInterface methods, add the three corresponding IUnknown ones plus the
+ // four IDispatch ones on top of that.
+ pTypeAttr->cFuncs = aMethods.getLength() - 3 + 3 + 4;
+ pTypeAttr->cVars = 0;
+ pTypeAttr->cImplTypes = 1;
+ // FIXME: I think this, too, is always supposed to be as if just for the seven methods in
+ // IDIspatch?
+ pTypeAttr->cbSizeVft = 7 * sizeof(void*);
+ pTypeAttr->cbAlignment = 8;
+ pTypeAttr->wTypeFlags = TYPEFLAG_FHIDDEN|TYPEFLAG_FNONEXTENSIBLE|TYPEFLAG_FDISPATCHABLE;
+ }
+ else
+ assert(false);
+
+ pTypeAttr->lcid = LOCALE_USER_DEFAULT;
+ pTypeAttr->memidConstructor = MEMBERID_NIL;
+ pTypeAttr->memidDestructor = MEMBERID_NIL;
+ // FIXME: Is this correct, just the vtable pointer, right?
+ pTypeAttr->cbSizeInstance = sizeof(void*);
+ pTypeAttr->wMajorVerNum = 0;
+ pTypeAttr->wMinorVerNum = 0;
+ pTypeAttr->idldescType.wIDLFlags = IDLFLAG_NONE;
+
+ SAL_INFO("extensions.olebridge", this << "@CXTypeInfo::GetTypeAttr: " << pTypeAttr);
+
+ *ppTypeAttr = pTypeAttr;
+
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE CXTypeInfo::GetTypeComp(ITypeComp **)
+{
+ SAL_WARN("extensions.olebridge", this << "@CXTypeInfo::GetTypeComp: E_NOTIMPL");
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CXTypeInfo::GetFuncDesc(UINT index,
+ FUNCDESC **ppFuncDesc)
+{
+ comphelper::Automation::AutomationInvokedZone aAutomationActive;
+
+ if (!ppFuncDesc)
+ return E_POINTER;
+
+ if (meKind != Kind::OUTGOING)
+ return E_NOTIMPL;
+
+ if (index <= 6)
+ {
+ *ppFuncDesc = new FUNCDESC;
+ (*ppFuncDesc)->memid = 0x60000000 + index;
+ (*ppFuncDesc)->lprgscode = nullptr;
+ (*ppFuncDesc)->lprgelemdescParam = nullptr;
+ (*ppFuncDesc)->funckind = FUNC_DISPATCH;
+ (*ppFuncDesc)->invkind = INVOKE_FUNC;
+ (*ppFuncDesc)->callconv = CC_STDCALL;
+ switch (index)
+ {
+ case 0: // QueryInterface
+ (*ppFuncDesc)->cParams = 2;
+ (*ppFuncDesc)->elemdescFunc.tdesc.lptdesc = nullptr;
+ (*ppFuncDesc)->elemdescFunc.tdesc.vt = VT_VOID;
+ break;
+ case 1: // AddRef
+ (*ppFuncDesc)->cParams = 0;
+ (*ppFuncDesc)->elemdescFunc.tdesc.lptdesc = nullptr;
+ (*ppFuncDesc)->elemdescFunc.tdesc.vt = VT_UI4;
+ break;
+ case 2: // Release
+ (*ppFuncDesc)->cParams = 1;
+ (*ppFuncDesc)->elemdescFunc.tdesc.lptdesc = nullptr;
+ (*ppFuncDesc)->elemdescFunc.tdesc.vt = VT_UI4;
+ break;
+ case 3: // GetTypeInfoCount
+ (*ppFuncDesc)->cParams = 1;
+ (*ppFuncDesc)->elemdescFunc.tdesc.lptdesc = nullptr;
+ (*ppFuncDesc)->elemdescFunc.tdesc.vt = VT_VOID;
+ break;
+ case 4: // GetTypeInfo
+ (*ppFuncDesc)->cParams = 3;
+ (*ppFuncDesc)->elemdescFunc.tdesc.lptdesc = nullptr;
+ (*ppFuncDesc)->elemdescFunc.tdesc.vt = VT_VOID;
+ break;
+ case 5: // GetIDsOfNames
+ (*ppFuncDesc)->cParams = 5;
+ (*ppFuncDesc)->elemdescFunc.tdesc.lptdesc = nullptr;
+ (*ppFuncDesc)->elemdescFunc.tdesc.vt = VT_VOID;
+ break;
+ case 6: // Invoke
+ (*ppFuncDesc)->cParams = 8;
+ (*ppFuncDesc)->elemdescFunc.tdesc.lptdesc = nullptr;
+ (*ppFuncDesc)->elemdescFunc.tdesc.vt = VT_VOID;
+ break;
+ }
+ (*ppFuncDesc)->cParamsOpt = 0;
+ (*ppFuncDesc)->oVft = index * sizeof(void*);
+ (*ppFuncDesc)->cScodes = 0;
+ (*ppFuncDesc)->wFuncFlags = FUNCFLAG_FRESTRICTED;
+
+ SAL_INFO("extensions.olebridge", this << "@CXTypeInfo::GetFuncDesc(" << index << "): S_OK: " << *ppFuncDesc);
+
+ return S_OK;
+ }
+
+ Reference<XIdlReflection> xRefl = theCoreReflection::get(comphelper::getComponentContext(mxMSF));
+ assert(xRefl.is());
+
+ Reference<XIdlClass> xClass = xRefl->forName(maType.getTypeName());
+ assert(xClass.is());
+
+ auto aMethods = xClass->getMethods();
+ assert(xClass->getTypeClass() == TypeClass_INTERFACE &&
+ aMethods.getLength() > 0);
+
+ if (index > o3tl::make_unsigned(aMethods.getLength() - 3 + 3 + 4))
+ return E_INVALIDARG;
+
+ *ppFuncDesc = new FUNCDESC;
+
+ (*ppFuncDesc)->memid = index - 6;
+ (*ppFuncDesc)->lprgscode = nullptr;
+ (*ppFuncDesc)->lprgelemdescParam = nullptr;
+ (*ppFuncDesc)->funckind = FUNC_DISPATCH;
+ (*ppFuncDesc)->invkind = INVOKE_FUNC;
+ (*ppFuncDesc)->callconv = CC_STDCALL;
+ (*ppFuncDesc)->cParams = aMethods[index - 4]->getParameterInfos().getLength();
+ (*ppFuncDesc)->cParamsOpt = 0;
+ (*ppFuncDesc)->oVft = index * sizeof(void*);
+ (*ppFuncDesc)->cScodes = 0;
+ (*ppFuncDesc)->elemdescFunc.tdesc.lptdesc = nullptr; // ???
+ (*ppFuncDesc)->elemdescFunc.tdesc.vt = VT_VOID; // ???
+ (*ppFuncDesc)->wFuncFlags = 0;
+
+ SAL_INFO("extensions.olebridge", this << "@CXTypeInfo::GetFuncDesc(" << index << "): S_OK: " << *ppFuncDesc);
+
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE CXTypeInfo::GetVarDesc(UINT,
+ VARDESC **)
+{
+ SAL_WARN("extensions.olebridge", this << "@CXTypeInfo::GetVarDesc: E_NOTIMPL");
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CXTypeInfo::GetNames(MEMBERID memid,
+ BSTR *rgBstrNames,
+ UINT cMaxNames,
+ UINT *pcNames)
+{
+ comphelper::Automation::AutomationInvokedZone aAutomationActive;
+
+ SAL_INFO("extensions.olebridge", this << "@CXTypeInfo::GetNames(" << memid << ")");
+ assert(meKind != Kind::COCLASS);
+
+ if (!rgBstrNames)
+ return E_POINTER;
+
+ if (!pcNames)
+ return E_POINTER;
+
+ if (memid < 1)
+ return E_INVALIDARG;
+
+ if (cMaxNames < 1)
+ return E_INVALIDARG;
+
+ if (meKind == Kind::MAIN)
+ {
+ SAL_WARN("extensions.olebridge", "GetNames() for MAIN not implemented");
+ return E_NOTIMPL;
+ }
+
+ Reference<XIdlReflection> xRefl = theCoreReflection::get(comphelper::getComponentContext(mxMSF));
+ assert(xRefl.is());
+
+ Reference<XIdlClass> xClass = xRefl->forName(maType.getTypeName());
+ assert(xClass.is());
+
+ auto aMethods = xClass->getMethods();
+ assert(xClass->getTypeClass() == TypeClass_INTERFACE &&
+ aMethods.getLength() > 0);
+
+ // Subtract the three XInterface methods. Memid for the first following method is 1.
+ if (memid > aMethods.getLength() - 3)
+ return E_INVALIDARG;
+
+ SAL_INFO("extensions.olebridge", "..." << this << "@CXTypeInfo::GetNames(" << memid << "): " << aMethods[memid + 2]->getName());
+ rgBstrNames[0] = SysAllocString(reinterpret_cast<LPOLESTR>(aMethods[memid + 2]->getName().pData->buffer));
+ *pcNames = 1;
+
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE CXTypeInfo::GetRefTypeOfImplType(UINT index,
+ HREFTYPE *pRefType)
+{
+ SAL_INFO("extensions.olebridge", this << "@CXTypeInfo::GetRefTypeOfImplType(" << index << ")");
+
+ if (!pRefType)
+ return E_POINTER;
+
+ assert(index == 0 || index == 1);
+
+ *pRefType = 1000+index;
+
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE CXTypeInfo::GetImplTypeFlags(UINT index,
+ INT *pImplTypeFlags)
+{
+ comphelper::Automation::AutomationInvokedZone aAutomationActive;
+
+ SAL_INFO("extensions.olebridge", this << "@CXTypeInfo::GetImplTypeFlags(" << index << ")");
+
+ if (!pImplTypeFlags)
+ return E_POINTER;
+
+ assert(meKind == Kind::COCLASS);
+ assert(index == 0 || index == 1);
+
+ if (index == 0)
+ *pImplTypeFlags = IMPLTYPEFLAG_FDEFAULT;
+ else if (index == 1)
+ *pImplTypeFlags = IMPLTYPEFLAG_FDEFAULT|IMPLTYPEFLAG_FSOURCE;
+
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE CXTypeInfo::GetIDsOfNames(LPOLESTR *,
+ UINT,
+ MEMBERID *)
+{
+ SAL_WARN("extensions.olebridge", this << "@CXTypeInfo::GetIDsOfNames: E_NOTIMPL");
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CXTypeInfo::Invoke(PVOID,
+ MEMBERID,
+ WORD,
+ DISPPARAMS *,
+ VARIANT *,
+ EXCEPINFO *,
+ UINT *)
+{
+ SAL_WARN("extensions.olebridge", this << "@CXTypeInfo::Invoke: E_NOTIMPL");
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CXTypeInfo::GetDocumentation(MEMBERID memid,
+ BSTR *pBstrName,
+ BSTR *pBstrDocString,
+ DWORD *pdwHelpContext,
+ BSTR *pBstrHelpFile)
+{
+ comphelper::Automation::AutomationInvokedZone aAutomationActive;
+
+ SAL_INFO("extensions.olebridge", this << "@CXTypeInfo::GetDocumentation(" << memid << ")");
+
+ if (pBstrName)
+ {
+ if (memid == MEMBERID_NIL)
+ {
+ *pBstrName = SysAllocString(o3tl::toW(msImplementationName.getStr()));
+ }
+ else if (memid == DISPID_VALUE)
+ {
+ // MEMBERIDs are the same as DISPIDs, apparently?
+ *pBstrName = SysAllocString(L"Value");
+ }
+ else
+ {
+ // FIXME: Shouldn't we be able to know the names of the members of UNO interfaces?
+ *pBstrName = SysAllocString(o3tl::toW(OUString("UnknownNameOfMember#" + OUString::number(memid)).getStr()));
+ }
+ }
+ if (pBstrDocString)
+ *pBstrDocString = SysAllocString(L"");
+ if (pdwHelpContext)
+ *pdwHelpContext = 0;
+ if (pBstrHelpFile)
+ *pBstrHelpFile = nullptr;
+
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE CXTypeInfo::GetDllEntry(MEMBERID,
+ INVOKEKIND,
+ BSTR *,
+ BSTR *,
+ WORD *)
+{
+ SAL_WARN("extensions.olebridge", this << "@CXTypeInfo::GetDllEntry: E_NOTIMPL");
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CXTypeInfo::GetRefTypeInfo(HREFTYPE hRefType,
+ ITypeInfo **ppTInfo)
+{
+ comphelper::Automation::AutomationInvokedZone aAutomationActive;
+
+ SAL_INFO("extensions.olebridge", this << "@CXTypeInfo::GetRefTypeInfo(" << hRefType << ")");
+
+ if (!ppTInfo)
+ return E_POINTER;
+
+ // FIXME: Is it correct to assume that the only interfaces on which GetRefTypeInfo() would be
+ // called are those that implement ooo::vba::XConnectable?
+
+ Reference<ooo::vba::XConnectable> xConnectable(mxOrigin, UNO_QUERY);
+ if (!xConnectable.is())
+ return E_NOTIMPL;
+
+ ooo::vba::TypeAndIID aTypeAndIID = xConnectable->GetConnectionPoint();
+
+ IID aIID;
+ if (!SUCCEEDED(IIDFromString(reinterpret_cast<LPOLESTR>(aTypeAndIID.IID.pData->buffer), &aIID)))
+ return E_NOTIMPL;
+
+ HRESULT ret;
+
+ CComObject<CXTypeInfo>* pTypeInfo;
+
+ ret = CComObject<CXTypeInfo>::CreateInstance(&pTypeInfo);
+ if (FAILED(ret))
+ return ret;
+
+ pTypeInfo->AddRef();
+
+ pTypeInfo->InitForOutgoing(mxOrigin, aTypeAndIID.Type.getTypeName(), aIID, mxMSF, aTypeAndIID.Type);
+
+ *ppTInfo = pTypeInfo;
+
+ return S_OK;
+}
+
+HRESULT STDMETHODCALLTYPE CXTypeInfo::AddressOfMember(MEMBERID,
+ INVOKEKIND,
+ PVOID *)
+{
+ SAL_WARN("extensions.olebridge", this << "@CXTypeInfo::AddressOfMember: E_NOTIMPL");
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CXTypeInfo::CreateInstance(IUnknown *,
+ REFIID,
+ PVOID *)
+{
+ SAL_WARN("extensions.olebridge", this << "@CXTypeInfo::CreateInstance: E_NOTIMPL");
+ return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE CXTypeInfo::GetMops(MEMBERID,
+ BSTR *)
+{
+ SAL_WARN("extensions.olebridge", this << "@CXTypeInfo::GetMops: E_NOTIMPL");
+ return E_NOTIMPL;
+}
+
+// This is not actually called any more by my vbscript test after I added the IProvideClassInfo
+// thing... so all the CXTypeLib stuff is dead code at the moment.
+
+HRESULT STDMETHODCALLTYPE CXTypeInfo::GetContainingTypeLib(ITypeLib **ppTLib,
+ UINT *pIndex)
+{
+ comphelper::Automation::AutomationInvokedZone aAutomationActive;
+
+ SAL_INFO("extensions.olebridge", this << "@CXTypeInfo::GetContainingTypeLib");
+
+ if (!ppTLib || !pIndex)
+ return E_POINTER;
+
+ HRESULT ret;
+
+ CComObject<CXTypeLib>* pTypeLib;
+
+ ret = CComObject<CXTypeLib>::CreateInstance(&pTypeLib);
+ if (FAILED(ret))
+ return ret;
+
+ pTypeLib->AddRef();
+
+ pTypeLib->Init(mxOrigin, msImplementationName, mxMSF);
+
+ *ppTLib = pTypeLib;
+
+ return S_OK;
+}
+
+void STDMETHODCALLTYPE CXTypeInfo::ReleaseTypeAttr(TYPEATTR *pTypeAttr)
+{
+ SAL_INFO("extensions.olebridge", this << "@CXTypeInfo::ReleaseTypeAttr(" << pTypeAttr << ")");
+
+ delete pTypeAttr;
+}
+
+void STDMETHODCALLTYPE CXTypeInfo::ReleaseFuncDesc(FUNCDESC *pFuncDesc)
+{
+ SAL_WARN("extensions.olebridge", this << "@CXTypeInfo::ReleaseFuncDesc(" << pFuncDesc << ")");
+
+ delete pFuncDesc;
+}
+
+void STDMETHODCALLTYPE CXTypeInfo::ReleaseVarDesc(VARDESC *)
+{
+ SAL_WARN("extensions.olebridge", this << "@CXTypeInfo::ReleaseVarDesc: E_NOTIMPL");
+}
+
+COM_DECLSPEC_NOTHROW STDMETHODIMP InterfaceOleWrapper::GetTypeInfo(UINT iTInfo, LCID, ITypeInfo ** ppTInfo)
+{
+ comphelper::Automation::AutomationInvokedZone aAutomationActive;
+
+ SAL_INFO("extensions.olebridge", this << "@InterfaceOleWrapper::GetTypeInfo(" << iTInfo << ")");
+
+ if (!ppTInfo)
+ return E_POINTER;
+
+ if (iTInfo != 0)
+ return E_NOTIMPL;
+
+ // FIXME: This is surely incorrect. Why is being able to handle GetTypeInfo() here coupled to
+ // being a source for outgoing events, i.e. implementing XConnectable? What would break if we
+ // would use XInterfaceWithIID and its getIID instead?
+
+ Reference<ooo::vba::XConnectable> xConnectable(m_xOrigin, UNO_QUERY);
+ if (!xConnectable.is())
+ return E_NOTIMPL;
+
+ OUString sIID = xConnectable->GetIIDForClassItselfNotCoclass();
+ IID aIID;
+ if (!SUCCEEDED(IIDFromString(reinterpret_cast<LPOLESTR>(sIID.pData->buffer), &aIID)))
+ return E_NOTIMPL;
+
+ HRESULT ret;
+
+ CComObject<CXTypeInfo>* pTypeInfo;
+
+ ret = CComObject<CXTypeInfo>::CreateInstance(&pTypeInfo);
+ if (FAILED(ret))
+ return ret;
+
+ pTypeInfo->AddRef();
+
+ pTypeInfo->InitForClassItself(m_xOrigin, m_sImplementationName, aIID, m_smgr);
+
+ *ppTInfo = pTypeInfo;
+
+ return S_OK;
+}
+
+COM_DECLSPEC_NOTHROW STDMETHODIMP InterfaceOleWrapper::GetIDsOfNames(REFIID /*riid*/,
+ LPOLESTR * rgszNames,
+ UINT cNames,
+ LCID /*lcid*/,
+ DISPID * rgdispid )
+{
+ comphelper::Automation::AutomationInvokedZone aAutomationActive;
+
+ if( ! rgdispid)
+ return E_POINTER;
+
+ SAL_INFO("extensions.olebridge", this << "@InterfaceOleWrapper::GetIDsOfNames:");
+ for (unsigned int i = 0; i < cNames; ++i)
+ {
+ // Initialise returned rgdispid values.
+ rgdispid[i] = DISPID_UNKNOWN;
+
+ SAL_INFO("extensions.olebridge", " " << OUString(o3tl::toU(rgszNames[i])));
+ }
+
+ HRESULT ret = DISP_E_UNKNOWNNAME;
+ try
+ {
+ MutexGuard guard( getBridgeMutex());
+
+ // FIXME: Handle the cNames > 1 case? Note that the rest of the names mean the names of *arguments*.
+
+ 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(o3tl::toU(rgszNames[0]));
+ NameToIdMap::iterator iter = m_nameToDispIdMap.find(name);
+
+ bool bIsMethod = false;
+
+ OUString exactName = name;
+
+ if (iter == m_nameToDispIdMap.end())
+ {
+ if (m_xExactName.is())
+ {
+ exactName = m_xExactName->getExactName(name);
+ if (exactName.isEmpty())
+ 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;
+ bIsMethod = true;
+ }
+
+ if (d.flags != 0)
+ {
+ m_MemberInfos.push_back(d);
+ iter = m_nameToDispIdMap.emplace(exactName, static_cast<DISPID>(m_MemberInfos.size())).first;
+
+ if (exactName != name)
+ {
+ iter = m_nameToDispIdMap.emplace(name, static_cast<DISPID>(m_MemberInfos.size())).first;
+ }
+ }
+ }
+
+ if (iter == m_nameToDispIdMap.end())
+ {
+ ret = DISP_E_UNKNOWNNAME;
+ SAL_INFO("extensions.olebridge", " " << name << ": UNKNOWN");
+ }
+ else
+ {
+ rgdispid[0] = (*iter).second;
+ SAL_INFO("extensions.olebridge", " " << name << ": " << rgdispid[0]);
+
+ if (bIsMethod && cNames > 1)
+ {
+ Reference<XIdlMethod> xIdlMethod;
+ Reference<XIntrospectionAccess> xIntrospectionAccess = m_xInvocation->getIntrospection();
+ try
+ {
+ if (xIntrospectionAccess.is())
+ xIdlMethod = xIntrospectionAccess->getMethod(exactName, MethodConcept::ALL);
+ }
+ catch (const NoSuchMethodException&)
+ {
+ }
+ if (xIdlMethod.is())
+ {
+ auto aParamInfos = xIdlMethod->getParameterInfos();
+ for (unsigned int i = 1; i < cNames; ++i)
+ {
+ bool bFound = false;
+ for (int j = 0; j < aParamInfos.getLength(); ++j)
+ {
+ if (aParamInfos[j].aName.equalsIgnoreAsciiCase(o3tl::toU(rgszNames[i])))
+ {
+ rgdispid[i] = j;
+ bFound = true;
+ SAL_INFO("extensions.olebridge", " " << OUString(o3tl::toU(rgszNames[i])) << ": " << rgdispid[i]);
+ break;
+ }
+ }
+ if (!bFound)
+ SAL_INFO("extensions.olebridge", " " << OUString(o3tl::toU(rgszNames[i])) << ": NOT FOUND");
+ }
+ }
+ }
+
+ // Return value should be S_OK only if *all* the names were found.
+ unsigned int i;
+ for (i = 0; i < cNames; ++i)
+ if (rgdispid[i] == DISPID_UNKNOWN)
+ break;
+ if (i == cNames)
+ ret = S_OK;
+ }
+ }
+ }
+ catch(const BridgeRuntimeError&)
+ {
+ OSL_ASSERT(false);
+ }
+ catch(const Exception&)
+ {
+ OSL_ASSERT(false);
+ }
+ catch(...)
+ {
+ OSL_ASSERT(false);
+ }
+
+ return ret;
+}
+
+// Note: What the comments here say about JScript possibly holds for Automation clients in general,
+// like VBScript ones, too. Or not. Hard to say. What is the relevance of JScript nowadays anyway,
+// and can LO really be used from JScript code on web pages any longer?
+
+// "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 chosen. 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 whether 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 a UNO wrapper object (class InterfaceOleWrapper).
+// A value object is appropriately initialized within the script and passed as
+// parameter to a UNO object method or property. The convertDispparamsArgs function
+// can easily find out that a param is such an object by querying 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 acquiring 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 a VT_DISPATCH that is no JScriptValue than the type information
+// is used to find out about the required type.
+void InterfaceOleWrapper::convertDispparamsArgs(DISPID id,
+ unsigned short /*wFlags*/, DISPPARAMS* pdispparams, Sequence<Any>& rSeq)
+{
+ // Parameters come in in reverse order in pdispparams. There might be less parameters than
+ // expected. In that case, assume they are "optional" (but can't be marked as such in UNO IDL),
+ // and fill in the rest with empty Anys. There might also be more than expected. In that case,
+ // assume the oovbaapi UNO IDL hasn't kept up with added optional parameters in MSO, and just
+ // ignore the extra ones, as long as they are empty.
+
+ // An example: incoming parameters: <12, 13, "foo/bar.tem">
+ //
+ // Expected parameters: (string filename, int something, int somethingElse, Any whatever, Any
+ // whateverElse)
+ //
+ // Here the existing incoming parameters are placed in reverse order in the first three outgoing
+ // parameters, and the rest of the outgoing parameters are kept as empty Anys.
+ //
+ // Another example: incoming parameters: <EMPTY, TRUE>
+ //
+ // Expected parameters: (bool flag)
+ //
+ // Here the TRUE is passed as the sole outgoing parameter, and the incoming EMPTY is ignored.
+ //
+ // Still an example: incoming parameters: <"foo.doc", TRUE>
+ //
+ // Expected parameters: (bool flag)
+ //
+ // This throws an error as the incoming string parameter presumably should do something important,
+ // but there is no corresponding outgoing parameter.
+
+ HRESULT hr = S_OK;
+ const int countIncomingArgs = pdispparams->cArgs;
+
+ //Get type information for the current call
+ InvocationInfo info;
+ if( ! getInvocationInfoForCall( id, info))
+ throw BridgeRuntimeError(
+ "[automation bridge]InterfaceOleWrapper::convertDispparamsArgs \n"
+ "Could not obtain type information for current call.");
+
+ // Size rSeq according to the number of expected parameters.
+ const int expectedArgs = info.aParamTypes.getLength() + (info.eMemberType == MemberType_PROPERTY ? 1 : 0);
+ rSeq.realloc( expectedArgs );
+ Any* pParams = rSeq.getArray();
+
+ Any anyParam;
+
+ int outgoingArgIndex = 0;
+
+ // Go through incoming parameters in reverse order, i.e. in the order as declared in IDL
+ for (int i = std::max(countIncomingArgs, expectedArgs) - 1; i >= 0; i--)
+ {
+ // Ignore too many parameters if they are VT_EMPTY anyway
+ if ( outgoingArgIndex >= expectedArgs && pdispparams->rgvarg[i].vt == VT_EMPTY )
+ continue;
+
+ // But otherwise too many parameters is an error
+ if ( outgoingArgIndex >= expectedArgs )
+ throw BridgeRuntimeError( "[automation bridge] Too many parameters" );
+
+ if (info.eMemberType == MemberType_METHOD &&
+ info.aParamModes[ outgoingArgIndex ] == ParamMode_OUT)
+ {
+ outgoingArgIndex++;
+ continue;
+ }
+
+ if (i < countIncomingArgs)
+ {
+ // A missing (and hopefully optional) arg (in the middle of the argument list) is passed
+ // as an empty Any.
+ if (pdispparams->rgvarg[i].vt == VT_ERROR && pdispparams->rgvarg[i].scode == DISP_E_PARAMNOTFOUND)
+ {
+ Any aEmpty;
+ pParams[ outgoingArgIndex ] = aEmpty;
+ outgoingArgIndex++;
+ continue;
+ }
+
+ if(convertValueObject( & pdispparams->rgvarg[i], anyParam))
+ { //a param is a ValueObject and could be converted
+ pParams[ outgoingArgIndex ] = anyParam;
+ outgoingArgIndex++;
+ continue;
+ }
+ }
+ else
+ {
+ // A missing arg. Let's hope it is de facto optional (there is no way in UNO IDL to mark
+ // a parameter as optional). The corresponding slot in pParams is already a void Any.
+ // Here we don't increase outgoingArgIndex!
+ 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.
+
+ // No idea how this stuff, originally written for JScript, works for other Automation
+ // clients.
+
+ if( pdispparams->rgvarg[i].vt == VT_DISPATCH )
+ {
+ if( info.eMemberType == MemberType_METHOD && info.aParamModes[ outgoingArgIndex ] == 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 const * sindex= L"0";
+ DISPID id2;
+ DISPPARAMS noParams= {nullptr,nullptr,0,0};
+ if(SUCCEEDED( hr= pdisp->GetIDsOfNames( IID_NULL, const_cast<OLECHAR **>(&sindex), 1, LOCALE_USER_DEFAULT, &id2)))
+ hr= pdisp->Invoke( id2, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET,
+ & noParams, & varParam, nullptr, nullptr);
+ if( FAILED( hr))
+ {
+ throw BridgeRuntimeError(
+ "[automation bridge] Could not determine "
+ "if the object has a member \"0\". Error: " +
+ OUString::number(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[ outgoingArgIndex ]);
+ else if(info.eMemberType == MemberType_PROPERTY)
+ variantToAny( & varParam, anyParam, info.aType);
+ else
+ OSL_ASSERT(false);
+
+ if (outgoingArgIndex < expectedArgs)
+ pParams[ outgoingArgIndex ]= anyParam;
+ outgoingArgIndex++;
+ }// end for / iterating over all parameters
+}
+
+bool InterfaceOleWrapper::getInvocationInfoForCall( DISPID id, InvocationInfo& info)
+{
+ bool bTypesAvailable= 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.
+ // Problem: 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.
+ OUString sMemberName;
+
+ auto ci1 = std::find_if(m_nameToDispIdMap.cbegin(), m_nameToDispIdMap.cend(),
+ [&id](const NameToIdMap::value_type& nameToDispId) { return nameToDispId.second == id; }); // item is a pair<OUString, DISPID>
+ if (ci1 != m_nameToDispIdMap.cend())
+ sMemberName= (*ci1).first;
+ // 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.
+ bool validInfo= true;
+ InvocationInfo invInfo;
+ try{
+ invInfo= inv2->getInfoForName( sMemberName, false);
+ }
+ catch(const IllegalArgumentException&)
+ {
+ validInfo= false;
+ }
+
+ if( ! validInfo)
+ {
+ invInfo= inv2->getInfoForName( sMemberName, true);
+ }
+ if( invInfo.aName.pData)
+ {
+ bTypesAvailable= true;
+ info= invInfo;
+ }
+ }
+ return bTypesAvailable;
+}
+
+// XBridgeSupplier2 ---------------------------------------------------
+// only bridges itself ( this instance of InterfaceOleWrapper)from UNO to IDispatch
+// If sourceModelType is UNO than any UNO interface implemented by InterfaceOleWrapper
+// can bridged to IDispatch ( if destModelType == OLE). The IDispatch is
+// implemented by this class.
+Any SAL_CALL InterfaceOleWrapper::createBridge(const Any& modelDepObject,
+ const Sequence<sal_Int8>& /*ProcessId*/,
+ sal_Int16 sourceModelType,
+ sal_Int16 destModelType)
+{
+
+ 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= static_cast<VARIANT*>(CoTaskMemAlloc( sizeof( VARIANT)));
+ if( pVar)
+ {
+ pVar->vt= VT_DISPATCH;
+ pVar->pdispVal= this;
+ AddRef();
+
+ retAny<<= reinterpret_cast< sal_uIntPtr >( pVar);
+ }
+ }
+ }
+ }
+
+ return retAny;
+}
+
+// XInitialization --------------------------------------------------
+void SAL_CALL InterfaceOleWrapper::initialize( const Sequence< Any >& aArguments )
+{
+ switch( aArguments.getLength() )
+ {
+ case 2: // the object wraps a UNO struct
+ aArguments[0] >>= m_xInvocation;
+ aArguments[1] >>= m_defaultValueType;
+ break;
+ case 3: // the object wraps a UNO interface
+ aArguments[0] >>= m_xInvocation;
+ aArguments[1] >>= m_xOrigin;
+ aArguments[2] >>= m_defaultValueType;
+
+ Reference<XServiceInfo> xServiceInfo(m_xOrigin, UNO_QUERY);
+ if (xServiceInfo.is())
+ m_sImplementationName = xServiceInfo->getImplementationName();
+
+ SAL_INFO("extensions.olebridge", this << "@InterfaceOleWrapper::initialize for "
+ << (m_sImplementationName.isEmpty()?"an unknown implementation":m_sImplementationName));
+ break;
+ }
+
+ m_xExactName.set( m_xInvocation, UNO_QUERY);
+}
+
+Reference< XInterface > InterfaceOleWrapper::createUnoWrapperInstance()
+{
+ Reference<XWeak> xWeak= static_cast<XWeak*>( new InterfaceOleWrapper(
+ m_smgr, m_nUnoWrapperClass, m_nComWrapperClass));
+ return Reference<XInterface>( xWeak, UNO_QUERY);
+}
+
+Reference<XInterface> InterfaceOleWrapper::createComWrapperInstance()
+{
+ Reference<XWeak> xWeak= static_cast<XWeak*>( new IUnknownWrapper(
+ 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)
+{
+ bool ret = false;
+ typelib_TypeDescription * pDesc= nullptr;
+ OUString str(o3tl::toU(name));
+ typelib_typedescription_getByName( &pDesc, str.pData );
+ if( pDesc)
+ {
+ type = Type( pDesc->pWeakRef );
+ typelib_typedescription_release( pDesc);
+ ret = true;
+ }
+ return ret;
+}
+
+static bool writeBackOutParameter2( VARIANTARG* pDest, VARIANT* pSource)
+{
+ bool ret = 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
+ CComQIPtr<IJScriptValueObject> spValueDest(spDispDest);
+ 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= 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 property "0"
+ // explicitly
+ CComQIPtr<IDispatchEx> spDispEx( spDispDest);
+ if( spDispEx)
+ {
+ CComBSTR nullProp(L"0");
+ DISPID dwDispID;
+ if( SUCCEEDED( spDispEx->GetDispID( nullProp, fdexNameEnsure, &dwDispID)))
+ {
+ DISPPARAMS dispparams = {nullptr, nullptr, 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, nullptr, nullptr, nullptr);
+ else
+ hr= spDispEx->InvokeEx(dwDispID, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYPUT,
+ &dispparams, nullptr, nullptr, nullptr);
+ if( SUCCEEDED(hr))
+ ret= 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 bool writeBackOutParameter(VARIANTARG* pDest, VARIANT* pSource)
+{
+ HRESULT hr;
+ 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 than 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 = 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) != nullptr)
+ hr= SafeArrayCopyData( V_ARRAY(pSource), *V_ARRAYREF(pDest));
+ else
+ // Out Param
+ hr= SafeArrayCopy(V_ARRAY(pSource), V_ARRAYREF(pDest));
+ if( SUCCEEDED( hr))
+ ret = true;
+ }
+ else
+ {
+ // copy base type
+ switch (V_VT(pSource))
+ {
+ case VT_I2:
+ {
+ *V_I2REF(pDest) = V_I2(pSource);
+ ret = true;
+ break;
+ }
+ case VT_I4:
+ *V_I4REF(pDest) = V_I4(pSource);
+ ret = true;
+ break;
+ case VT_R4:
+ *V_R4REF(pDest) = V_R4(pSource);
+ ret = true;
+ break;
+ case VT_R8:
+ *V_R8REF(pDest) = V_R8(pSource);
+ ret = true;
+ break;
+ case VT_CY:
+ *V_CYREF(pDest) = V_CY(pSource);
+ ret = true;
+ break;
+ case VT_DATE:
+ *V_DATEREF(pDest) = V_DATE(pSource);
+ ret = true;
+ break;
+ case VT_BSTR:
+ SysFreeString( *pDest->pbstrVal);
+
+ *V_BSTRREF(pDest) = SysAllocString(V_BSTR(pSource));
+ ret = true;
+ break;
+ case VT_DISPATCH:
+ if (*V_DISPATCHREF(pDest) != nullptr)
+ (*V_DISPATCHREF(pDest))->Release();
+
+ *V_DISPATCHREF(pDest) = V_DISPATCH(pSource);
+
+ if (*V_DISPATCHREF(pDest) != nullptr)
+ (*V_DISPATCHREF(pDest))->AddRef();
+
+ ret = true;
+ break;
+ case VT_ERROR:
+ *V_ERRORREF(pDest) = V_ERROR(pSource);
+ ret = true;
+ break;
+ case VT_BOOL:
+ *V_BOOLREF(pDest) = V_BOOL(pSource);
+ ret = true;
+ break;
+ case VT_UNKNOWN:
+ if (*V_UNKNOWNREF(pDest) != nullptr)
+ (*V_UNKNOWNREF(pDest))->Release();
+
+ *V_UNKNOWNREF(pDest) = V_UNKNOWN(pSource);
+
+ if (*V_UNKNOWNREF(pDest) != nullptr)
+ (*V_UNKNOWNREF(pDest))->AddRef();
+
+ ret = true;
+ break;
+ case VT_I1:
+ *V_I1REF(pDest) = V_I1(pSource);
+ ret = true;
+ break;
+ case VT_UI1:
+ *V_UI1REF(pDest) = V_UI1(pSource);
+ ret = true;
+ break;
+ case VT_UI2:
+ *V_UI2REF(pDest) = V_UI2(pSource);
+ ret = true;
+ break;
+ case VT_UI4:
+ *V_UI4REF(pDest) = V_UI4(pSource);
+ ret = true;
+ break;
+ case VT_INT:
+ *V_INTREF(pDest) = V_INT(pSource);
+ ret = true;
+ break;
+ case VT_UINT:
+ *V_UINTREF(pDest) = V_UINT(pSource);
+ ret = true;
+ break;
+ case VT_DECIMAL:
+ memcpy(pDest->pdecVal, pSource, sizeof(DECIMAL));
+ ret = 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 = true;
+ }
+ }
+ }
+ }
+ return ret;
+}
+
+COM_DECLSPEC_NOTHROW STDMETHODIMP InterfaceOleWrapper::Invoke(DISPID dispidMember,
+ REFIID /*riid*/,
+ LCID /*lcid*/,
+ WORD wFlags,
+ DISPPARAMS * pdispparams,
+ VARIANT * pvarResult,
+ EXCEPINFO * pexcepinfo,
+ UINT * puArgErr )
+{
+ comphelper::Automation::AutomationInvokedZone aAutomationActive;
+
+ OUString sParams;
+#if defined SAL_LOG_INFO
+ sParams += "[";
+ for (unsigned int i = 0; i < pdispparams->cArgs; ++i)
+ {
+ if (i > 0)
+ sParams += ",";
+ std::stringstream aStringStream;
+ aStringStream << pdispparams->rgvarg[i];
+ sParams += OUString::createFromAscii(aStringStream.str().c_str());
+ }
+ sParams += "]";
+#endif
+ SAL_INFO("extensions.olebridge", this << "@InterfaceOleWrapper::Invoke(" << dispidMember << "," << sParams << ")");
+
+ comphelper::ProfileZone aZone("COM Bridge");
+ HRESULT ret = S_OK;
+
+ try
+ {
+ bool bHandled= false;
+ ret= InvokeGeneral( dispidMember, wFlags, pdispparams, pvarResult, pexcepinfo,
+ puArgErr, bHandled);
+ if( bHandled)
+ return ret;
+
+ if ((dispidMember > 0) && (o3tl::make_unsigned(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)
+ {
+ std::unique_ptr<DISPPARAMS> pNewDispParams;
+ std::vector<VARIANTARG> vNewArgs;
+
+ if (pdispparams->cNamedArgs > 0)
+ {
+ // Convert named arguments to positional ones.
+
+ // An example:
+ //
+ // Function declaration (in pseudo-code):
+ // int foo(int A, int B, optional int C, optional int D, optional int E, optional int F, optional int G)
+ //
+ // Corresponding parameter numbers (DISPIDs):
+ // 0 1 2 3 4 5 6
+ //
+ // Actual call:
+ // foo(10, 20, E:=50, D:=40, F:=60)
+ //
+ // That is, A and B are passed positionally, D, E, and F as named arguments,
+ // and the optional C and G parameters are left out.
+ //
+ // Incoming DISPPARAMS:
+ // cArgs=5, cNamedArgs=3
+ // rgvarg: [60, 40, 50, 20, 10]
+ // rgdispidNamedArgs: [5, 3, 4]
+ //
+ // We calculate nLowestNamedArgDispid = 3 and nHighestNamedArgDispid = 5.
+ //
+ // Result of conversion, no named args:
+ // cArgs=6, cNamedArgs=0
+ // rgvarg: [60, 50, 40, DISP_E_PARAMNOTFOUND, 20, 10]
+
+ // First find the lowest and highest DISPID of the named arguments.
+ DISPID nLowestNamedArgDispid = 1000000;
+ DISPID nHighestNamedArgDispid = -1;
+ for (unsigned int i = 0; i < pdispparams->cNamedArgs; ++i)
+ {
+ if (pdispparams->rgdispidNamedArgs[i] < nLowestNamedArgDispid)
+ nLowestNamedArgDispid = pdispparams->rgdispidNamedArgs[i];
+ if (pdispparams->rgdispidNamedArgs[i] > nHighestNamedArgDispid)
+ nHighestNamedArgDispid = pdispparams->rgdispidNamedArgs[i];
+ }
+
+ // Make sure named arguments don't overlap with positional ones. The lowest
+ // DISPID of the named arguments should be >= the number of positional
+ // arguments.
+ if (nLowestNamedArgDispid < static_cast<DISPID>(pdispparams->cArgs - pdispparams->cNamedArgs))
+ return DISP_E_NONAMEDARGS;
+
+ // Do the actual conversion.
+ pNewDispParams.reset(new DISPPARAMS);
+ vNewArgs.resize(nHighestNamedArgDispid + 1);
+ pNewDispParams->rgvarg = vNewArgs.data();
+ pNewDispParams->rgdispidNamedArgs = nullptr;
+ pNewDispParams->cArgs = nHighestNamedArgDispid + 1;
+ pNewDispParams->cNamedArgs = 0;
+
+ // Initialise all parameter slots as missing
+ for (int i = 0; i < nHighestNamedArgDispid; ++i)
+ {
+ pNewDispParams->rgvarg[i].vt = VT_ERROR;
+ pNewDispParams->rgvarg[i].scode = DISP_E_PARAMNOTFOUND;
+ }
+
+ // Then set the value of those actually present.
+ for (unsigned int i = 0; i < pdispparams->cNamedArgs; ++i)
+ pNewDispParams->rgvarg[nHighestNamedArgDispid - pdispparams->rgdispidNamedArgs[i]] = pdispparams->rgvarg[i];
+
+ const int nFirstUnnamedArg = pdispparams->cNamedArgs + (nLowestNamedArgDispid-(pdispparams->cArgs - pdispparams->cNamedArgs));
+
+ for (unsigned int i = pdispparams->cNamedArgs; i < pdispparams->cArgs; ++i)
+ pNewDispParams->rgvarg[nFirstUnnamedArg + (i-pdispparams->cNamedArgs)] = pdispparams->rgvarg[i];
+
+ pdispparams = pNewDispParams.get();
+ }
+
+ 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) != 0 || (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(const BridgeRuntimeError& e)
+ {
+ writeExcepinfo(pexcepinfo, e.message);
+ ret = DISP_E_EXCEPTION;
+ }
+ catch(const Exception& e)
+ {
+ OUString message= "InterfaceOleWrapper::Invoke : \n" +
+ e.Message;
+ writeExcepinfo(pexcepinfo, message);
+ ret = DISP_E_EXCEPTION;
+ }
+ catch(...)
+ {
+ writeExcepinfo(pexcepinfo, "InterfaceOleWrapper::Invoke : \nUnexpected exception");
+ ret = DISP_E_EXCEPTION;
+ }
+
+ return ret;
+}
+
+HRESULT InterfaceOleWrapper::doInvoke( DISPPARAMS * pdispparams, VARIANT * pvarResult,
+ EXCEPINFO * pexcepinfo, unsigned int * puArgErr, OUString& name, Sequence<Any>& params)
+{
+
+
+ HRESULT ret= S_OK;
+ try
+ {
+ Sequence<sal_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 sal_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 != nullptr)
+ anyToVariant(pvarResult, returnValue);
+ }
+ catch(const IllegalArgumentException & e) //XInvocation::invoke
+ {
+ writeExcepinfo(pexcepinfo, e.Message);
+ ret = DISP_E_TYPEMISMATCH;
+ }
+ catch(const CannotConvertException & e) //XInvocation::invoke
+ {
+ writeExcepinfo(pexcepinfo, e.Message);
+ ret = mapCannotConvertException( e, puArgErr);
+ }
+ catch(const InvocationTargetException & e) //XInvocation::invoke
+ {
+ const Any& org = e.TargetException;
+ Exception excTarget;
+ org >>= excTarget;
+ OUString message=
+ org.getValueType().getTypeName() + ": " + excTarget.Message;
+ writeExcepinfo(pexcepinfo, message);
+ ret = DISP_E_EXCEPTION;
+ }
+ catch(const NoSuchMethodException & e) //XInvocation::invoke
+ {
+ writeExcepinfo(pexcepinfo, e.Message);
+ ret = DISP_E_MEMBERNOTFOUND;
+ }
+ catch(const BridgeRuntimeError & e)
+ {
+ writeExcepinfo(pexcepinfo, e.message);
+ ret = DISP_E_EXCEPTION;
+ }
+ catch(const Exception & e)
+ {
+ OUString message= "InterfaceOleWrapper::doInvoke : \n" +
+ e.Message;
+ writeExcepinfo(pexcepinfo, message);
+ ret = DISP_E_EXCEPTION;
+ }
+ catch( ... )
+ {
+ writeExcepinfo(pexcepinfo, "InterfaceOleWrapper::doInvoke : \nUnexpected exception");
+ ret = DISP_E_EXCEPTION;
+ }
+ return ret;
+}
+
+HRESULT InterfaceOleWrapper::doGetProperty( DISPPARAMS * /*pdispparams*/, VARIANT * pvarResult,
+ EXCEPINFO * pexcepinfo, OUString& name)
+{
+ HRESULT ret= S_OK;
+
+ try
+ {
+ Any returnValue = m_xInvocation->getValue( name);
+ // write back return value
+ if (pvarResult)
+ anyToVariant(pvarResult, returnValue);
+ }
+ catch(const UnknownPropertyException& e) //XInvocation::getValue
+ {
+ writeExcepinfo(pexcepinfo, e.Message);
+ ret = DISP_E_MEMBERNOTFOUND;
+ }
+ catch(const BridgeRuntimeError& e)
+ {
+ writeExcepinfo(pexcepinfo, e.message);
+ ret = DISP_E_EXCEPTION;
+ }
+ catch(const Exception& e)
+ {
+ OUString message= "InterfaceOleWrapper::doGetProperty : \n" +
+ e.Message;
+ writeExcepinfo(pexcepinfo, message);
+ }
+ catch( ... )
+ {
+ writeExcepinfo(pexcepinfo, "InterfaceOleWrapper::doInvoke : \nUnexpected exception");
+ ret = DISP_E_EXCEPTION;
+ }
+ return ret;
+}
+
+HRESULT InterfaceOleWrapper::doSetProperty( DISPPARAMS * /*pdispparams*/, VARIANT * /*pvarResult*/,
+ EXCEPINFO * pexcepinfo, unsigned int * puArgErr, OUString& name, Sequence<Any> const & params)
+{
+ HRESULT ret= S_OK;
+
+ try
+ {
+ m_xInvocation->setValue( name, params.getConstArray()[0]);
+ }
+ catch(const UnknownPropertyException &)
+ {
+ ret = DISP_E_MEMBERNOTFOUND;
+ }
+ catch(const CannotConvertException &e)
+ {
+ ret= mapCannotConvertException( e, puArgErr);
+ }
+ catch(const InvocationTargetException &e)
+ {
+ if (pexcepinfo != nullptr)
+ {
+ Any org = e.TargetException;
+
+ pexcepinfo->wCode = UNO_2_OLE_EXCEPTIONCODE;
+ pexcepinfo->bstrSource = SysAllocString(L"any ONE component");
+ pexcepinfo->bstrDescription = SysAllocString(
+ o3tl::toW(org.getValueType().getTypeName().getStr()));
+ }
+ ret = DISP_E_EXCEPTION;
+ }
+ catch( ... )
+ {
+ ret= DISP_E_EXCEPTION;
+ }
+ return ret;
+}
+
+namespace {
+
+class CXEnumVariant : public IEnumVARIANT,
+ public CComObjectRoot
+{
+public:
+ CXEnumVariant()
+ : mnIndex(1) // ooo::vba::XCollection index starts at one
+ {
+ }
+
+ virtual ~CXEnumVariant()
+ {
+ }
+
+#if defined __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunused-function"
+#endif
+ BEGIN_COM_MAP(CXEnumVariant)
+#if defined __clang__
+#pragma clang diagnostic pop
+#endif
+ COM_INTERFACE_ENTRY(IEnumVARIANT)
+#if defined __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Winconsistent-missing-override"
+#pragma clang diagnostic ignored "-Wunused-function"
+#endif
+ END_COM_MAP()
+#if defined __clang__
+#pragma clang diagnostic pop
+#endif
+
+ DECLARE_NOT_AGGREGATABLE(CXEnumVariant)
+
+ // Creates and initializes the enumerator
+ void Init(InterfaceOleWrapper* pInterfaceOleWrapper,
+ const Reference<ooo::vba::XCollection > xCollection)
+ {
+ mpInterfaceOleWrapper = pInterfaceOleWrapper;
+ mxCollection = xCollection;
+ }
+
+ // IEnumVARIANT
+ virtual HRESULT STDMETHODCALLTYPE Clone(IEnumVARIANT **) override
+ {
+ SAL_INFO("extensions.olebridge", this << "@CXEnumVariant::Clone: E_NOTIMPL");
+ return E_NOTIMPL;
+ }
+
+ virtual HRESULT STDMETHODCALLTYPE Next(ULONG const celt,
+ VARIANT *rgVar,
+ ULONG *pCeltFetched) override
+ {
+ comphelper::Automation::AutomationInvokedZone aAutomationActive;
+
+ if (pCeltFetched)
+ *pCeltFetched = 0;
+
+ if (celt == 0)
+ {
+ SAL_INFO("extensions.olebridge", this << "@CXEnumVariant::Next(" << celt << "): E_INVALIDARG");
+ return E_INVALIDARG;
+ }
+
+ if (rgVar == nullptr || (celt != 1 && pCeltFetched == nullptr))
+ {
+ SAL_INFO("extensions.olebridge", this << "@CXEnumVariant::Next(" << celt << "): E_FAIL");
+ return E_FAIL;
+ }
+
+ for (ULONG i = 0; i < celt; i++)
+ VariantInit(&rgVar[i]);
+
+ ULONG nLeft = celt;
+ ULONG nReturned = 0;
+ while (nLeft > 0)
+ {
+ if (mnIndex > mxCollection->getCount())
+ {
+ SAL_INFO("extensions.olebridge", this << "@CXEnumVariant::Next(" << celt << "): got " << nReturned << ": S_FALSE");
+ return S_FALSE;
+ }
+ Any aIndex;
+ aIndex <<= mnIndex;
+ Any aElement = mxCollection->Item(aIndex, Any());
+ mpInterfaceOleWrapper->anyToVariant(rgVar, aElement);
+ // rgVar->pdispVal->AddRef(); ??
+ if (pCeltFetched)
+ (*pCeltFetched)++;
+ rgVar++;
+ nReturned++;
+ mnIndex++;
+ nLeft--;
+ }
+ SAL_INFO("extensions.olebridge", this << "@CXEnumVariant::Next(" << celt << "): S_OK");
+ return S_OK;
+ }
+
+ virtual HRESULT STDMETHODCALLTYPE Reset() override
+ {
+ SAL_INFO("extensions.olebridge", this << "@CXEnumVariant::Reset: S_OK");
+ mnIndex = 1;
+ return S_OK;
+ }
+
+ virtual HRESULT STDMETHODCALLTYPE STDMETHODCALLTYPE Skip(ULONG const celt) override
+ {
+ comphelper::Automation::AutomationInvokedZone aAutomationActive;
+
+ ULONG nLeft = celt;
+ ULONG nSkipped = 0;
+ while (nLeft > 0)
+ {
+ if (mnIndex > mxCollection->getCount())
+ {
+ SAL_INFO("extensions.olebridge", this << "@CXEnumVariant::Skip(" << celt << "): skipped " << nSkipped << ": S_FALSE");
+ return S_FALSE;
+ }
+ mnIndex++;
+ nLeft--;
+ }
+ SAL_INFO("extensions.olebridge", this << "@CXEnumVariant::Skip(" << celt << "): S_OK");
+ return S_OK;
+ }
+
+private:
+ InterfaceOleWrapper* mpInterfaceOleWrapper;
+ Reference<ooo::vba::XCollection> mxCollection;
+ sal_Int32 mnIndex;
+};
+
+class Sink : public cppu::WeakImplHelper<ooo::vba::XSink>
+{
+public:
+ Sink(IUnknown* pUnkSink,
+ Reference<XMultiServiceFactory> xMSF,
+ ooo::vba::TypeAndIID aTypeAndIID,
+ InterfaceOleWrapper* pInterfaceOleWrapper);
+
+ // XSink
+ void SAL_CALL Call( const OUString& Method, Sequence< Any >& Arguments ) override;
+
+private:
+ IUnknown* mpUnkSink;
+ Reference<XMultiServiceFactory> mxMSF;
+ ooo::vba::TypeAndIID maTypeAndIID;
+ InterfaceOleWrapper* mpInterfaceOleWrapper;
+};
+
+}
+
+Sink::Sink(IUnknown* pUnkSink,
+ Reference<XMultiServiceFactory> xMSF,
+ ooo::vba::TypeAndIID aTypeAndIID,
+ InterfaceOleWrapper* pInterfaceOleWrapper) :
+ mpUnkSink(pUnkSink),
+ mxMSF(xMSF),
+ maTypeAndIID(aTypeAndIID),
+ mpInterfaceOleWrapper(pInterfaceOleWrapper)
+{
+ mpUnkSink->AddRef();
+}
+
+void SAL_CALL
+Sink::Call( const OUString& Method, Sequence< Any >& Arguments )
+{
+ SAL_INFO("extensions.olebridge", "Sink::Call(" << Method << ", " << Arguments.getLength() << " arguments)");
+
+ IDispatch* pDispatch;
+ HRESULT nResult = mpUnkSink->QueryInterface(IID_IDispatch, reinterpret_cast<void **>(&pDispatch));
+ if (!SUCCEEDED(nResult))
+ {
+ SAL_WARN("extensions.olebridge", "Sink::Call: Not IDispatch: " << WindowsErrorStringFromHRESULT(nResult));
+ return;
+ }
+
+ Reference<XIdlReflection> xRefl = theCoreReflection::get(comphelper::getComponentContext(mxMSF));
+ assert(xRefl.is());
+
+ Reference<XIdlClass> xClass = xRefl->forName(maTypeAndIID.Type.getTypeName());
+ assert(xClass.is());
+
+ auto aMethods = xClass->getMethods();
+ assert(xClass->getTypeClass() == TypeClass_INTERFACE &&
+ aMethods.getLength() > 0);
+
+ int nMemId = 1;
+ auto ArgumentsRange = asNonConstRange(Arguments);
+ // Skip the three XInterface methods
+ for (int i = 3; i < aMethods.getLength(); i++)
+ {
+ if (aMethods[i]->getName() == Method)
+ {
+ // FIXME: Handle mismatch in type of actual argument and parameter of the method.
+
+ // FIXME: Handle mismatch in number of arguments passed and actual number of parameters
+ // of the method.
+
+ auto aParamInfos = aMethods[i]->getParameterInfos();
+
+ assert(Arguments.getLength() == aParamInfos.getLength());
+
+ DISPPARAMS aDispParams;
+ aDispParams.rgdispidNamedArgs = nullptr;
+ aDispParams.cArgs = Arguments.getLength();
+ aDispParams.cNamedArgs = 0;
+ aDispParams.rgvarg = new VARIANT[aDispParams.cArgs];
+ for (unsigned j = 0; j < aDispParams.cArgs; j++)
+ {
+ VariantInit(aDispParams.rgvarg+j);
+ // Note: Reverse order of arguments in Arguments and aDispParams.rgvarg!
+ const unsigned nIncomingArgIndex = aDispParams.cArgs - j - 1;
+ mpInterfaceOleWrapper->anyToVariant(aDispParams.rgvarg+j, Arguments[nIncomingArgIndex]);
+
+ // Handle OUT and INOUT arguments. For instance, the second ('Cancel') parameter to
+ // DocumentBeforeClose() should be a VT_BYREF|VT_BOOL parameter. Need to handle that
+ // here.
+
+ if (aParamInfos[nIncomingArgIndex].aMode == ParamMode_OUT ||
+ aParamInfos[nIncomingArgIndex].aMode == ParamMode_INOUT)
+ {
+ switch (aDispParams.rgvarg[j].vt)
+ {
+ case VT_I2:
+ aDispParams.rgvarg[j].byref = new SHORT(aDispParams.rgvarg[j].iVal);
+ aDispParams.rgvarg[j].vt |= VT_BYREF;
+ break;
+ case VT_I4:
+ aDispParams.rgvarg[j].byref = new LONG(aDispParams.rgvarg[j].lVal);
+ aDispParams.rgvarg[j].vt |= VT_BYREF;
+ break;
+ case VT_BSTR:
+ aDispParams.rgvarg[j].byref = new BSTR(aDispParams.rgvarg[j].bstrVal);
+ aDispParams.rgvarg[j].vt |= VT_BYREF;
+ break;
+ case VT_BOOL:
+ aDispParams.rgvarg[j].byref = new VARIANT_BOOL(aDispParams.rgvarg[j].boolVal);
+ aDispParams.rgvarg[j].vt |= VT_BYREF;
+ break;
+ default:
+ assert(false && "Not handled yet");
+ break;
+ }
+ }
+ }
+
+ VARIANT aVarResult;
+ VariantInit(&aVarResult);
+ UINT uArgErr;
+
+ // In the case of a VBScript client, which uses "late binding", calling Invoke on the
+ // sink it provides will cause a callback to our CXTypeInfo::GetNames for the given
+ // member id, and in that we will tell it the name of the corresponding method, and the
+ // client will know what event handler to invoke based on that name.
+ //
+ // As the outgoing interfaces used (ooo::vba::word::XApplicationOutgoing and others) are
+ // totally not stable and not published in any way, there can be no client that would
+ // have done "compile-time binding" and where the sink would actually be an object with
+ // a vtbl corresponding to the outgoing interface. Late binding clients that work like
+ // VBScript is all we support.
+ SAL_INFO("extensions.olebridge", "Sink::Call(" << Method << "): Calling Invoke(" << nMemId << ")");
+
+ nResult = pDispatch->Invoke(nMemId, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &aDispParams, &aVarResult, nullptr, &uArgErr);
+ SAL_INFO("extensions.olebridge", "Sink::Call(" << Method << "): Invoke() returned");
+
+ SAL_WARN_IF(!SUCCEEDED(nResult), "extensions.olebridge", "Call to " << Method << " failed: " << WindowsErrorStringFromHRESULT(nResult));
+
+ // Undo VT_BYREF magic done above. Copy out parameters back to the Anys in Arguments
+ for (unsigned j = 0; j < aDispParams.cArgs; j++)
+ {
+ const unsigned nIncomingArgIndex = aDispParams.cArgs - j - 1;
+ if (aParamInfos[nIncomingArgIndex].aMode == ParamMode_OUT ||
+ aParamInfos[nIncomingArgIndex].aMode == ParamMode_INOUT)
+ {
+ switch (aDispParams.rgvarg[j].vt)
+ {
+ case VT_BYREF|VT_I2:
+ {
+ SHORT *pI = static_cast<SHORT*>(aDispParams.rgvarg[j].byref);
+ ArgumentsRange[nIncomingArgIndex] <<= static_cast<sal_Int16>(*pI);
+ delete pI;
+ }
+ break;
+ case VT_BYREF|VT_I4:
+ {
+ LONG *pL = static_cast<LONG*>(aDispParams.rgvarg[j].byref);
+ ArgumentsRange[nIncomingArgIndex] <<= static_cast<sal_Int32>(*pL);
+ delete pL;
+ }
+ break;
+ case VT_BYREF|VT_BSTR:
+ {
+ BSTR *pBstr = static_cast<BSTR*>(aDispParams.rgvarg[j].byref);
+ ArgumentsRange[nIncomingArgIndex] <<= OUString(o3tl::toU(*pBstr));
+ // Undo SysAllocString() done in anyToVariant()
+ SysFreeString(*pBstr);
+ delete pBstr;
+ }
+ break;
+ case VT_BYREF|VT_BOOL:
+ {
+ VARIANT_BOOL *pBool = static_cast<VARIANT_BOOL*>(aDispParams.rgvarg[j].byref);
+ ArgumentsRange[nIncomingArgIndex] <<= (*pBool != VARIANT_FALSE);
+ delete pBool;
+ }
+ break;
+ default:
+ assert(false && "Not handled yet");
+ break;
+ }
+ }
+ else
+ {
+ switch (aDispParams.rgvarg[j].vt)
+ {
+ case VT_BSTR:
+ // Undo SysAllocString() done in anyToVariant()
+ SysFreeString(aDispParams.rgvarg[j].bstrVal);
+ break;
+ }
+ }
+ }
+
+ delete[] aDispParams.rgvarg;
+ return;
+ }
+ nMemId++;
+ }
+ SAL_WARN("extensions.olebridge", "Sink::Call: Unknown method '" << Method << "'");
+}
+
+namespace {
+
+class CXEnumConnections : public IEnumConnections,
+ public CComObjectRoot
+{
+public:
+ CXEnumConnections()
+ {
+ }
+
+ virtual ~CXEnumConnections()
+ {
+ }
+
+#if defined __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunused-function"
+#endif
+ BEGIN_COM_MAP(CXEnumConnections)
+#if defined __clang__
+#pragma clang diagnostic pop
+#endif
+ COM_INTERFACE_ENTRY(IEnumConnections)
+#if defined __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Winconsistent-missing-override"
+#pragma clang diagnostic ignored "-Wunused-function"
+#endif
+ END_COM_MAP()
+#if defined __clang__
+#pragma clang diagnostic pop
+#endif
+
+ DECLARE_NOT_AGGREGATABLE(CXEnumConnections)
+
+ void Init(std::vector<IUnknown*>& rUnknowns, std::vector<DWORD>& rCookies)
+ {
+ SAL_INFO("extensions.olebridge", this << "@CXEnumConnections::Init");
+ SAL_WARN_IF(rUnknowns.size() != rCookies.size(), "extensions.olebridge", "Vectors of different size");
+ mvUnknowns = rUnknowns;
+ mvCookies = rCookies;
+ mnIndex = 0;
+ }
+
+ virtual HRESULT STDMETHODCALLTYPE Next(ULONG cConnections,
+ LPCONNECTDATA rgcd,
+ ULONG *pcFetched) override
+ {
+ comphelper::Automation::AutomationInvokedZone aAutomationActive;
+
+ if (!rgcd)
+ {
+ SAL_INFO("extensions.olebridge", this << "@CXEnumConnections::Next(" << cConnections << "): E_POINTER");
+ return E_POINTER;
+ }
+
+ if (pcFetched && cConnections != 1)
+ {
+ SAL_INFO("extensions.olebridge", this << "@CXEnumConnections::Next(" << cConnections << "): E_INVALIDARG");
+ return E_INVALIDARG;
+ }
+
+ ULONG nFetched = 0;
+ while (nFetched < cConnections && mnIndex < mvUnknowns.size())
+ {
+ rgcd[nFetched].pUnk = mvUnknowns[mnIndex];
+ rgcd[nFetched].pUnk->AddRef();
+ rgcd[nFetched].dwCookie = mvCookies[mnIndex];
+ ++nFetched;
+ ++mnIndex;
+ }
+ if (nFetched != cConnections)
+ {
+ SAL_INFO("extensions.olebridge", this << "@CXEnumConnections::Next(" << cConnections << "): S_FALSE");
+ if (pcFetched)
+ *pcFetched = nFetched;
+ return S_FALSE;
+ }
+ SAL_INFO("extensions.olebridge", this << "@CXEnumConnections::Next(" << cConnections << "): S_OK");
+ if (pcFetched)
+ *pcFetched = nFetched;
+
+ return S_OK;
+ }
+
+ virtual HRESULT STDMETHODCALLTYPE Skip(ULONG cConnections) override
+ {
+ SAL_INFO("extensions.olebridge", this << "@CXEnumConnections::Skip(" << cConnections << "): E_NOTIMPL");
+
+ return E_NOTIMPL;
+ }
+
+ virtual HRESULT STDMETHODCALLTYPE Reset() override
+ {
+ SAL_INFO("extensions.olebridge", this << "@CXEnumConnections::Reset: E_NOTIMPL");
+
+ return E_NOTIMPL;
+ }
+
+ virtual HRESULT STDMETHODCALLTYPE Clone(IEnumConnections** /* ppEnum */) override
+ {
+ SAL_INFO("extensions.olebridge", this << "@CXEnumConnections::Clone: E_NOTIMPL");
+
+ return E_NOTIMPL;
+ }
+
+private:
+ std::vector<IUnknown*> mvUnknowns;
+ std::vector<DWORD> mvCookies;
+ ULONG mnIndex;
+};
+
+class CXConnectionPoint : public IConnectionPoint,
+ public CComObjectRoot
+{
+public:
+#if defined __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunused-function"
+#endif
+ BEGIN_COM_MAP(CXConnectionPoint)
+#if defined __clang__
+#pragma clang diagnostic pop
+#endif
+ COM_INTERFACE_ENTRY(IConnectionPoint)
+#if defined __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Winconsistent-missing-override"
+#pragma clang diagnostic ignored "-Wunused-function"
+#endif
+ END_COM_MAP()
+#if defined __clang__
+#pragma clang diagnostic pop
+#endif
+
+ DECLARE_NOT_AGGREGATABLE(CXConnectionPoint)
+
+ virtual ~CXConnectionPoint() {}
+
+ void Init(InterfaceOleWrapper* pInterfaceOleWrapper,
+ Reference<ooo::vba::XConnectionPoint>& xCP,
+ Reference<XMultiServiceFactory>& xMSF,
+ ooo::vba::TypeAndIID aTypeAndIID)
+ {
+ SAL_INFO("extensions.olebridge", this << "@CXConnectionPoint::Init for " << pInterfaceOleWrapper->getImplementationName());
+
+ IUnknown *pUnknown;
+ if (SUCCEEDED(QueryInterface(IID_IUnknown, reinterpret_cast<void **>(&pUnknown))))
+ {
+ // In case QI for IUnknown returns a different pointer, but nah, it doesn't
+ SAL_INFO("extensions.olebridge", " (IUnknown@" << pUnknown << ")");
+ }
+
+ mpInterfaceOleWrapper = pInterfaceOleWrapper;
+ mxCP = xCP;
+ mxMSF = xMSF;
+ maTypeAndIID = aTypeAndIID;
+ }
+
+ virtual HRESULT STDMETHODCALLTYPE GetConnectionInterface(IID *pIID) override
+ {
+ SAL_WARN("extensions.olebridge", this << "@CXConnectionPoint::GetConnectionInterface(" << *pIID << "): E_NOTIMPL");
+
+ // FIXME: Needed?
+
+ return E_NOTIMPL;
+ }
+
+ virtual HRESULT STDMETHODCALLTYPE GetConnectionPointContainer(IConnectionPointContainer **) override
+ {
+ SAL_WARN("extensions.olebridge", this << "@CXConnectionPoint::GetConnectionInterface: E_NOTIMPL");
+
+ // FIXME: Needed?
+
+ return E_NOTIMPL;
+ }
+
+ virtual HRESULT STDMETHODCALLTYPE Advise(IUnknown *pUnkSink,
+ DWORD *pdwCookie) override
+ {
+ comphelper::Automation::AutomationInvokedZone aAutomationActive;
+
+ SAL_INFO("extensions.olebridge", this << "@CXConnectionPoint::Advise(" << pUnkSink << ")");
+
+ if (!pdwCookie)
+ return E_POINTER;
+
+ Reference<ooo::vba::XSink> xSink(new Sink(pUnkSink, mxMSF, maTypeAndIID, mpInterfaceOleWrapper));
+
+ mvISinks.push_back(pUnkSink);
+ *pdwCookie = mvISinks.size();
+
+ mvCookies.push_back(mxCP->Advise(xSink));
+
+ mvXSinks.push_back(xSink);
+
+ SAL_INFO("extensions.olebridge", " *pdwCookie: " << *pdwCookie);
+
+ return S_OK;
+ }
+
+ virtual HRESULT STDMETHODCALLTYPE Unadvise(DWORD dwCookie) override
+ {
+ comphelper::Automation::AutomationInvokedZone aAutomationActive;
+
+ SAL_INFO("extensions.olebridge", this << "@CXConnectionPoint::Unadvise(" << dwCookie << ")");
+
+ if (dwCookie == 0 || dwCookie > mvISinks.size())
+ return E_POINTER;
+
+ mvISinks[dwCookie-1] = nullptr;
+
+ mxCP->Unadvise(mvCookies[dwCookie-1]);
+
+ mvXSinks[dwCookie-1] = Reference<ooo::vba::XSink>();
+
+ return S_OK;
+ }
+
+ virtual HRESULT STDMETHODCALLTYPE EnumConnections(IEnumConnections **ppEnum) override
+ {
+ comphelper::Automation::AutomationInvokedZone aAutomationActive;
+
+ HRESULT nResult;
+
+ SAL_INFO("extensions.olebridge", this << "@CXConnectionPoint::EnumConnections...");
+
+ if (!ppEnum)
+ {
+ SAL_INFO("extensions.olebridge", "..." << this << "@CXConnectionPoint::EnumConnections: E_POINTER");
+ return E_POINTER;
+ }
+
+ CComObject<CXEnumConnections>* pEnumConnections;
+
+ nResult = CComObject<CXEnumConnections>::CreateInstance(&pEnumConnections);
+ if (FAILED(nResult))
+ {
+ SAL_INFO("extensions.olebridge", "..." << this << "@CXConnectionPoint::EnumConnections: " << WindowsErrorStringFromHRESULT(nResult));
+ return nResult;
+ }
+
+ pEnumConnections->AddRef();
+
+ pEnumConnections->Init(mvISinks, mvCookies);
+ *ppEnum = pEnumConnections;
+
+ SAL_INFO("extensions.olebridge", "..." << this << "@CXConnectionPoint::EnumConnections: S_OK");
+
+ return S_OK;
+ }
+
+ InterfaceOleWrapper* mpInterfaceOleWrapper;
+ std::vector<IUnknown*> mvISinks;
+ std::vector<Reference<ooo::vba::XSink>> mvXSinks;
+ std::vector<DWORD> mvCookies;
+ Reference<XMultiServiceFactory> mxMSF;
+ Reference<ooo::vba::XConnectionPoint> mxCP;
+ ooo::vba::TypeAndIID maTypeAndIID;
+};
+
+}
+
+HRESULT InterfaceOleWrapper::InvokeGeneral( DISPID dispidMember, unsigned short wFlags,
+ DISPPARAMS * pdispparams, VARIANT * pvarResult, EXCEPINFO * pexcepinfo,
+ unsigned int * /*puArgErr*/, 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) != 0
+ && m_defaultValueType != VT_EMPTY && pvarResult != nullptr)
+ {
+ // Special case hack: If it is a ScVbaCheckBox, return the boolean value
+ Reference<ooo::vba::msforms::XCheckBox> xCheckBox(m_xOrigin, UNO_QUERY);
+ if (xCheckBox.is())
+ {
+ bHandled = true;
+ Any aValue = xCheckBox->getValue();
+ anyToVariant(pvarResult, aValue);
+ return S_OK;
+ }
+
+ bHandled= true;
+ if( m_defaultValueType == VT_DISPATCH)
+ {
+ pvarResult->vt= VT_DISPATCH;
+ pvarResult->pdispVal= this;
+ AddRef();
+ ret= S_OK;
+ }
+ }
+
+ // function: _GetValueObject
+ else if( dispidMember == DISPID_JSCRIPT_VALUE_FUNC)
+ {
+ bHandled= true;
+ if( !pvarResult)
+ return E_POINTER;
+ CComObject< JScriptValue>* pValue;
+ if( SUCCEEDED( CComObject<JScriptValue>::CreateInstance( &pValue)))
+ {
+ pValue->AddRef();
+ pvarResult->vt= VT_DISPATCH;
+ pvarResult->pdispVal= CComQIPtr<IDispatch>(pValue->GetUnknown());
+ ret= S_OK;
+ }
+ else
+ ret= DISP_E_EXCEPTION;
+ }
+ else if( dispidMember == DISPID_GET_STRUCT_FUNC)
+ {
+ bHandled= true;
+ bool bStruct= false;
+
+
+ Reference<XIdlReflection> xRefl = theCoreReflection::get(comphelper::getComponentContext(m_smgr));
+ // 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(OUString(o3tl::toU(arg.bstrVal)));
+ if( classStruct.is())
+ {
+ Any anyStruct;
+ classStruct->createObject( anyStruct);
+ CComVariant var;
+ anyToVariant( &var, anyStruct );
+
+ if( var.vt == VT_DISPATCH)
+ {
+ VariantCopy( pvarResult, & var);
+ bStruct= true;
+ }
+ }
+ }
+ ret= bStruct ? S_OK : DISP_E_EXCEPTION;
+ }
+ else if (dispidMember == DISPID_CREATE_TYPE_FUNC)
+ {
+ bHandled= true;
+ if( !pvarResult)
+ return 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))
+ {
+ writeExcepinfo(pexcepinfo, OUString::Concat("[automation bridge] A UNO type with the name ") +
+ o3tl::toU(arg.bstrVal) + " does not exist!");
+ return DISP_E_EXCEPTION;
+ }
+
+ if (!createUnoTypeWrapper(arg.bstrVal, pvarResult))
+ {
+ writeExcepinfo(pexcepinfo, "[automation bridge] InterfaceOleWrapper::InvokeGeneral\n"
+ "Could not initialize UnoTypeWrapper object!");
+ return DISP_E_EXCEPTION;
+ }
+ }
+ else if (dispidMember == DISPID_NEWENUM)
+ {
+ bHandled = true;
+ if( !pvarResult)
+ return E_POINTER;
+
+ Reference< ooo::vba::XCollection> xCollection(m_xOrigin, UNO_QUERY);
+ if (!xCollection.is())
+ return DISP_E_MEMBERNOTFOUND;
+
+ CComObject<CXEnumVariant>* pEnumVar;
+
+ ret = CComObject<CXEnumVariant>::CreateInstance(&pEnumVar);
+ if (FAILED(ret))
+ return ret;
+
+ pEnumVar->AddRef();
+
+ pEnumVar->Init(this, xCollection);
+
+ pvarResult->vt = VT_UNKNOWN;
+ pvarResult->punkVal = nullptr;
+
+ ret = pEnumVar->QueryInterface(IID_IUnknown, reinterpret_cast<void**>(&pvarResult->punkVal));
+ if (FAILED(ret))
+ {
+ pEnumVar->Release();
+ return ret;
+ }
+ }
+ }
+ catch(const BridgeRuntimeError & e)
+ {
+ writeExcepinfo(pexcepinfo, e.message);
+ ret = DISP_E_EXCEPTION;
+ }
+ catch(const Exception & e)
+ {
+ OUString message= "InterfaceOleWrapper::InvokeGeneral : \n" +
+ e.Message;
+ writeExcepinfo(pexcepinfo, message);
+ ret = DISP_E_EXCEPTION;
+ }
+ catch( ... )
+ {
+ writeExcepinfo(pexcepinfo, "InterfaceOleWrapper::InvokeGeneral : \nUnexpected exception");
+ ret = DISP_E_EXCEPTION;
+ }
+ return ret;
+}
+
+STDMETHODIMP InterfaceOleWrapper::GetDispID(BSTR /*bstrName*/, DWORD /*grfdex*/, DISPID __RPC_FAR* /*pid*/)
+{
+ return ResultFromScode(E_NOTIMPL);
+}
+
+STDMETHODIMP InterfaceOleWrapper::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*/)
+{
+ return ResultFromScode(E_NOTIMPL);
+}
+
+STDMETHODIMP InterfaceOleWrapper::DeleteMemberByName(
+ /* [in] */ BSTR /*bstr*/,
+ /* [in] */ DWORD /*grfdex*/)
+{
+ return ResultFromScode(E_NOTIMPL);
+}
+
+STDMETHODIMP InterfaceOleWrapper::DeleteMemberByDispID(DISPID /*id*/)
+{
+ return ResultFromScode(E_NOTIMPL);
+}
+
+STDMETHODIMP InterfaceOleWrapper::GetMemberProperties(
+ /* [in] */ DISPID /*id*/,
+ /* [in] */ DWORD /*grfdexFetch*/,
+ /* [out] */ DWORD __RPC_FAR* /*pgrfdex*/)
+{
+ return ResultFromScode(E_NOTIMPL);
+}
+
+STDMETHODIMP InterfaceOleWrapper::GetMemberName(
+ /* [in] */ DISPID /*id*/,
+ /* [out] */ BSTR __RPC_FAR* /*pbstrName*/)
+{
+ return ResultFromScode(E_NOTIMPL);
+}
+
+STDMETHODIMP InterfaceOleWrapper::GetNextDispID(
+ /* [in] */ DWORD /*grfdex*/,
+ /* [in] */ DISPID /*id*/,
+ /* [out] */ DISPID __RPC_FAR* /*pid*/)
+{
+ return ResultFromScode(E_NOTIMPL);
+}
+
+STDMETHODIMP InterfaceOleWrapper::GetNameSpaceParent(
+ /* [out] */ IUnknown __RPC_FAR *__RPC_FAR* /*ppunk*/)
+{
+ return ResultFromScode(E_NOTIMPL);
+}
+
+// IProvideClassInfo
+HRESULT STDMETHODCALLTYPE InterfaceOleWrapper::GetClassInfo (
+ /* [out] */ ITypeInfo **ppTI)
+{
+ comphelper::Automation::AutomationInvokedZone aAutomationActive;
+
+ SAL_INFO("extensions.olebridge", this << "@InterfaceOleWrapper::GetClassInfo");
+
+ if (!ppTI)
+ return E_POINTER;
+
+ Reference<ooo::vba::XInterfaceWithIID> xIID(m_xOrigin, UNO_QUERY);
+ if (!xIID.is())
+ return E_NOTIMPL;
+
+ OUString sIID = xIID->getIID();
+ IID aIID;
+ if (!SUCCEEDED(IIDFromString(reinterpret_cast<LPOLESTR>(sIID.pData->buffer), &aIID)))
+ return E_NOTIMPL;
+
+ HRESULT ret;
+
+ CComObject<CXTypeInfo>* pTypeInfo;
+
+ ret = CComObject<CXTypeInfo>::CreateInstance(&pTypeInfo);
+ if (FAILED(ret))
+ return ret;
+
+ pTypeInfo->AddRef();
+
+ pTypeInfo->InitForCoclass(m_xOrigin, m_sImplementationName, aIID, m_smgr);
+
+ *ppTI = pTypeInfo;
+
+ return S_OK;
+}
+
+// IConnectionPointContainer
+HRESULT STDMETHODCALLTYPE InterfaceOleWrapper::EnumConnectionPoints(
+ /* [out] */ IEnumConnectionPoints **)
+{
+ SAL_INFO("extensions.olebridge", this << "@InterfaceOleWrapper::EnumConnectionPoints");
+ return ResultFromScode(E_NOTIMPL);
+}
+
+HRESULT STDMETHODCALLTYPE InterfaceOleWrapper::FindConnectionPoint(
+ /* [in] */ REFIID riid,
+ /* [out] */ IConnectionPoint **ppCP)
+{
+ comphelper::Automation::AutomationInvokedZone aAutomationActive;
+
+ SAL_INFO("extensions.olebridge", this << "@InterfaceOleWrapper::FindConnectionPoint(" << riid << ")");
+
+ if (!ppCP)
+ return E_POINTER;
+
+ Reference<ooo::vba::XConnectable> xConnectable(m_xOrigin, UNO_QUERY);
+
+ // We checked already
+ assert(xConnectable.is());
+ if (!xConnectable.is())
+ return E_NOTIMPL;
+
+ ooo::vba::TypeAndIID aTypeAndIID = xConnectable->GetConnectionPoint();
+
+ IID aIID;
+ if (!SUCCEEDED(IIDFromString(reinterpret_cast<LPOLESTR>(aTypeAndIID.IID.pData->buffer), &aIID)))
+ return E_INVALIDARG;
+
+ if (!IsEqualIID(riid, aIID))
+ return E_INVALIDARG;
+
+ Reference<ooo::vba::XConnectionPoint> xCP = xConnectable->FindConnectionPoint();
+ if (!xCP.is())
+ return E_INVALIDARG;
+
+ HRESULT ret;
+
+ CComObject<CXConnectionPoint>* pConnectionPoint;
+
+ ret = CComObject<CXConnectionPoint>::CreateInstance(&pConnectionPoint);
+ if (FAILED(ret))
+ return ret;
+
+ pConnectionPoint->AddRef();
+
+ pConnectionPoint->Init(this, xCP, m_smgr, aTypeAndIID);
+
+ *ppCP = pConnectionPoint;
+
+ return S_OK;
+}
+
+// UnoObjectWrapperRemoteOpt ---------------------------------------------------
+
+UnoObjectWrapperRemoteOpt::UnoObjectWrapperRemoteOpt( Reference<XMultiServiceFactory> const & aFactory,
+ sal_uInt8 unoWrapperClass, sal_uInt8 comWrapperClass):
+InterfaceOleWrapper( 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);
+}
+
+COM_DECLSPEC_NOTHROW STDMETHODIMP UnoObjectWrapperRemoteOpt::GetIDsOfNames ( REFIID /*riid*/, LPOLESTR * rgszNames, UINT 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(o3tl::toU(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;
+ std::pair< ITnames, bool > pair_id= m_nameToDispIdMap.emplace(name, m_currentId++);
+ // new ID inserted ?
+ if( pair_id.second )
+ {// yes, now create MemberInfo and ad to IdToMemberInfoMap
+ MemberInfo d(0, name);
+ m_idToMemberInfoMap.emplace(m_currentId - 1, d);
+ }
+
+ *rgdispid = pair_id.first->second;
+ ret = S_OK;
+ }
+ else
+ ret= DISP_E_UNKNOWNNAME;
+ }
+ return ret;
+}
+
+COM_DECLSPEC_NOTHROW STDMETHODIMP UnoObjectWrapperRemoteOpt::Invoke ( DISPID dispidMember, REFIID /*riid*/, LCID /*lcid*/, WORD wFlags,
+ DISPPARAMS * pdispparams, VARIANT * pvarResult, EXCEPINFO * pexcepinfo,
+ UINT * puArgErr )
+{
+ comphelper::Automation::AutomationInvokedZone aAutomationActive;
+
+ HRESULT ret = S_OK;
+ try
+ {
+ bool bHandled= 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.isEmpty() )
+ {
+ if( SUCCEEDED( ret= doInvoke( pdispparams, pvarResult,
+ pexcepinfo, puArgErr, exactName, params)))
+ info.name= exactName;
+ }
+ }
+ }
+ if( SUCCEEDED( ret ) )
+ info.flags= 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.isEmpty() )
+ {
+ 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.isEmpty() )
+ {
+ 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.isEmpty() )
+ {
+ 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.isEmpty() )
+ {
+ 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.isEmpty() )
+ {
+ 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.isEmpty() )
+ {
+ if( SUCCEEDED( ret= doSetProperty( pdispparams, pvarResult,
+ pexcepinfo, puArgErr, exactName, params)))
+ info.name= exactName;
+ }
+ }
+ if( SUCCEEDED( ret ) )
+ info.flags= DISPATCH_PROPERTYGET;
+ }
+ }
+
+ // update information about this member
+ if( ret == DISP_E_MEMBERNOTFOUND)
+ {
+ // Remember the name as not existing
+ // and remove the MemberInfo
+ m_badNameMap[info.name]= 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(const BridgeRuntimeError& e)
+ {
+ writeExcepinfo(pexcepinfo, e.message);
+ ret = DISP_E_EXCEPTION;
+ }
+ catch(const Exception& e)
+ {
+ OUString message= "UnoObjectWrapperRemoteOpt::Invoke : \n" +
+ e.Message;
+ writeExcepinfo(pexcepinfo, message);
+ ret = DISP_E_EXCEPTION;
+ }
+ catch(...)
+ {
+ writeExcepinfo(pexcepinfo, "UnoObjectWrapperRemoteOpt::Invoke : \nUnexpected exception");
+ ret = DISP_E_EXCEPTION;
+ }
+
+ return ret;
+}
+
+HRESULT UnoObjectWrapperRemoteOpt::methodInvoke( DISPID /*dispidMember*/, DISPPARAMS * /*pdispparams*/, VARIANT * /*pvarResult*/,
+ EXCEPINFO * /*pexcepinfo*/, unsigned int * /*puArgErr*/, Sequence<Any> const &)
+{
+ return S_OK;
+}
+
+// The returned HRESULT is only appropriate for IDispatch::Invoke
+static HRESULT mapCannotConvertException(const CannotConvertException &e, unsigned int * puArgErr)
+{
+ HRESULT ret;
+ bool bWriteIndex= 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= false;
+ break;
+ }
+
+ if( bWriteIndex && puArgErr != nullptr)
+ *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
+// function returned VT_DISPATCH then the IDispatch of the same
+// object is being returned.
+// See InterfaceOleWrapper::Invoke, InterfaceOleWrapper::m_defaultValueType
+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;
+}
+
+/* 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 000000000..845724d81
--- /dev/null
+++ b/extensions/source/ole/unoobjw.hxx
@@ -0,0 +1,268 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#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 <cppuhelper/implbase.hxx>
+
+#include "comifaces.hxx"
+#include "ole2uno.hxx"
+#include "unoconversionutilities.hxx"
+
+#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 cppu;
+using namespace com::sun::star::bridge;
+using namespace com::sun::star::script;
+
+struct MemberInfo
+{
+ MemberInfo() : flags(0), name() {}
+ MemberInfo(WORD f, const OUString& n) : flags(f), name(n) {}
+
+ WORD flags;
+ OUString name;
+};
+
+typedef std::unordered_map
+<
+ OUString,
+ DISPID
+> NameToIdMap;
+
+typedef std::unordered_map
+<
+ OUString,
+ bool
+> BadNameMap;
+
+typedef std::unordered_map
+<
+ DISPID,
+ MemberInfo
+> IdToMemberInfoMap;
+
+// An InterfaceOleWrapper object can wrap either a UNO struct or a UNO
+// interface as a COM IDispatchEx and IUnoObjectWrapper.
+
+class InterfaceOleWrapper : public WeakImplHelper<XBridgeSupplier2, XInitialization>,
+ public IDispatchEx,
+ public IProvideClassInfo,
+ public IConnectionPointContainer,
+ public UnoConversionUtilities<InterfaceOleWrapper>,
+ public IUnoObjectWrapper
+{
+public:
+ InterfaceOleWrapper(Reference<XMultiServiceFactory> const & xFactory, sal_uInt8 unoWrapperClass, sal_uInt8 comWrapperClass);
+ ~InterfaceOleWrapper() override;
+
+ // IUnknown
+ STDMETHOD(QueryInterface)(REFIID riid, void ** ppvObj) override;
+ STDMETHOD_(ULONG, AddRef)() override;
+ STDMETHOD_(ULONG, Release)() override;
+
+ // IDispatch
+ STDMETHOD( GetTypeInfoCount )( UINT * pctinfo ) override;
+ STDMETHOD( GetTypeInfo )( UINT itinfo, LCID lcid, ITypeInfo ** pptinfo ) override;
+ STDMETHOD( GetIDsOfNames )( REFIID riid, LPOLESTR * rgszNames, UINT cNames,
+ LCID lcid, DISPID * rgdispid ) override;
+ STDMETHOD( Invoke )( DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags,
+ DISPPARAMS * pdispparams, VARIANT * pvarResult, EXCEPINFO * pexcepinfo,
+ UINT * puArgErr ) override;
+
+ // IDispatchEx
+ virtual HRESULT STDMETHODCALLTYPE GetDispID(
+ /* [in] */ BSTR bstrName,
+ /* [in] */ DWORD grfdex,
+ /* [out] */ DISPID __RPC_FAR *pid) override;
+
+ 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) override;
+
+ virtual HRESULT STDMETHODCALLTYPE DeleteMemberByName(
+ /* [in] */ BSTR bstr,
+ /* [in] */ DWORD grfdex) override;
+
+ virtual HRESULT STDMETHODCALLTYPE DeleteMemberByDispID(
+ /* [in] */ DISPID id) override;
+
+ virtual HRESULT STDMETHODCALLTYPE GetMemberProperties(
+ /* [in] */ DISPID id,
+ /* [in] */ DWORD grfdexFetch,
+ /* [out] */ DWORD __RPC_FAR *pgrfdex) override;
+
+ virtual HRESULT STDMETHODCALLTYPE GetMemberName(
+ /* [in] */ DISPID id,
+ /* [out] */ BSTR __RPC_FAR *pbstrName) override;
+
+ virtual HRESULT STDMETHODCALLTYPE GetNextDispID(
+ /* [in] */ DWORD grfdex,
+ /* [in] */ DISPID id,
+ /* [out] */ DISPID __RPC_FAR *pid) override;
+
+ virtual HRESULT STDMETHODCALLTYPE GetNameSpaceParent(
+ /* [out] */ IUnknown __RPC_FAR *__RPC_FAR *ppunk) override;
+
+ // IProvideClassInfo
+ virtual HRESULT STDMETHODCALLTYPE GetClassInfo(
+ /* [out] */ ITypeInfo **ppTI) override;
+
+ // IConnectionPointContainer
+ virtual HRESULT STDMETHODCALLTYPE EnumConnectionPoints(
+ /* [out] */ IEnumConnectionPoints **ppEnum) override;
+ virtual HRESULT STDMETHODCALLTYPE FindConnectionPoint(
+ /* [in] */ REFIID riid,
+ /* [out] */ IConnectionPoint **ppCP) override;
+
+ // XBridgeSupplier2
+ virtual Any SAL_CALL createBridge(const Any& modelDepObject,
+ const Sequence<sal_Int8>& ProcessId,
+ sal_Int16 sourceModelType,
+ sal_Int16 destModelType) override;
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const Sequence< Any >& aArguments ) override;
+
+ // IUnoObjectWrapper
+ STDMETHOD( getWrapperXInterface)( Reference<XInterface>* pXInt) override;
+ STDMETHOD( getOriginalUnoObject)( Reference<XInterface>* pXInt) override;
+ STDMETHOD( getOriginalUnoStruct)( Any * pStruct) override;
+
+ // UnoConversionUtility
+ virtual Reference< XInterface > createUnoWrapperInstance() override;
+ virtual Reference< XInterface > createComWrapperInstance() override;
+
+ const OUString& getImplementationName() const
+ {
+ return m_sImplementationName;
+ }
+
+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> const & params);
+
+ virtual HRESULT InvokeGeneral( DISPID dispidMember, unsigned short wFlags,
+ DISPPARAMS * pdispparams, VARIANT * pvarResult, EXCEPINFO * pexcepinfo,
+ unsigned int * puArgErr, bool& bHandled);
+
+ void convertDispparamsArgs( DISPID id, unsigned short wFlags, DISPPARAMS* pdispparams,
+ Sequence<Any>& rSeq);
+
+ bool getInvocationInfoForCall(DISPID id, InvocationInfo& info);
+
+ Reference<XInvocation> m_xInvocation;
+ Reference<XExactName> m_xExactName;
+ Reference<XInterface> m_xOrigin;
+ NameToIdMap m_nameToDispIdMap;
+ std::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 a 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::Invoke
+ VARTYPE m_defaultValueType;
+
+ // The name of the implementation. Can be empty if unknown.
+ OUString m_sImplementationName;
+};
+
+/*****************************************************************************
+
+ 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 an IdToMemberInfoMap stl map.
+
+*****************************************************************************/
+class UnoObjectWrapperRemoteOpt: public InterfaceOleWrapper
+{
+public:
+ UnoObjectWrapperRemoteOpt( Reference<XMultiServiceFactory> const & aFactory, sal_uInt8 unoWrapperClass, sal_uInt8 comWrapperClass);
+ ~UnoObjectWrapperRemoteOpt() override;
+
+ STDMETHOD( GetIDsOfNames )( REFIID riid, LPOLESTR * rgszNames, UINT cNames,
+ LCID lcid, DISPID * rgdispid ) override;
+ STDMETHOD( Invoke )( DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags,
+ DISPPARAMS * pdispparams, VARIANT * pvarResult, EXCEPINFO * pexcepinfo,
+ UINT * puArgErr ) override;
+
+ // 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() override;
+
+protected:
+
+ static HRESULT methodInvoke( DISPID dispidMember, DISPPARAMS * pdispparams, VARIANT * pvarResult,
+ EXCEPINFO * pexcepinfo, unsigned int * puArgErr, Sequence<Any> const & 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;
+
+
+};
+
+/* 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 000000000..2824e8ef7
--- /dev/null
+++ b/extensions/source/ole/unotypewrapper.cxx
@@ -0,0 +1,160 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "unotypewrapper.hxx"
+#include <rtl/ustring.hxx>
+#include <osl/diagnose.h>
+#include <o3tl/char16_t2wchar_t.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;
+ pVar->pdispVal= CComQIPtr<IDispatch>(pObj->GetUnknown());
+ //now set the value, e.i. the name of the type
+ CComQIPtr<IUnoTypeWrapper> spType(pVar->pdispVal);
+ OSL_ASSERT(spType);
+ if (SUCCEEDED(spType->put_Name(sTypeName)))
+ {
+ ret = true;
+ }
+ }
+ return ret;
+}
+
+
+bool createUnoTypeWrapper(const OUString& sTypeName, VARIANT * pVar)
+{
+ CComBSTR bstr(o3tl::toW(sTypeName.getStr()));
+ return createUnoTypeWrapper(bstr, pVar);
+}
+
+UnoTypeWrapper::UnoTypeWrapper()
+{
+}
+
+UnoTypeWrapper::~UnoTypeWrapper()
+{
+}
+
+
+// UnoTypeWrapper, IDispatch --------------------------------------------
+COM_DECLSPEC_NOTHROW STDMETHODIMP UnoTypeWrapper::GetTypeInfoCount(UINT* /*pctinfo*/)
+{
+ return E_NOTIMPL;
+}
+
+// UnoTypeWrapper, IDispatch --------------------------------------------
+COM_DECLSPEC_NOTHROW STDMETHODIMP UnoTypeWrapper::GetTypeInfo( UINT /*iTInfo*/,
+ LCID /*lcid*/,
+ ITypeInfo** /*ppTInfo*/)
+{
+ return E_NOTIMPL;
+}
+
+// UnoTypeWrapper, IDispatch --------------------------------------------
+COM_DECLSPEC_NOTHROW 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 --------------------------------------------
+COM_DECLSPEC_NOTHROW STDMETHODIMP UnoTypeWrapper::Invoke( DISPID dispIdMember,
+ REFIID /*riid*/,
+ LCID /*lcid*/,
+ WORD wFlags,
+ DISPPARAMS *pDispParams,
+ VARIANT *pVarResult,
+ EXCEPINFO* /*pExcepInfo*/,
+ UINT* /*puArgErr*/)
+{
+ if (pDispParams == nullptr)
+ 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 == nullptr)
+ {
+ ret = E_POINTER;
+ break;
+ }
+ get_Name( & pVarResult->bstrVal);
+ pVarResult->vt = VT_BSTR;
+ }
+ break;
+ default:
+ ret= DISP_E_MEMBERNOTFOUND;
+ break;
+ }
+
+ return ret;
+}
+
+// IUnoTypeWrapper-----------------------
+COM_DECLSPEC_NOTHROW STDMETHODIMP UnoTypeWrapper::put_Name(BSTR val)
+{
+ Lock();
+ m_sName = val;
+ Unlock();
+ return S_OK;
+}
+
+// (UnoTypeWrapper-----------------------
+COM_DECLSPEC_NOTHROW STDMETHODIMP UnoTypeWrapper::get_Name(BSTR *pVal)
+{
+ Lock();
+ if( !pVal)
+ return E_POINTER;
+ *pVal = m_sName.Copy();
+ Unlock();
+ return S_OK;
+}
+
+
+/* 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 000000000..a7515448c
--- /dev/null
+++ b/extensions/source/ole/unotypewrapper.hxx
@@ -0,0 +1,81 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "wincrap.hxx"
+
+#include "comifaces.hxx"
+
+/* creates a 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 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)
+#if defined __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Winconsistent-missing-override"
+#endif
+ END_COM_MAP()
+#if defined __clang__
+#pragma clang diagnostic pop
+#endif
+
+ // IDispatch -------------------------------------------
+ STDMETHOD( GetTypeInfoCount)(UINT *pctinfo) override;
+
+ STDMETHOD( GetTypeInfo)( UINT iTInfo,
+ LCID lcid,
+ ITypeInfo **ppTInfo) override;
+
+ STDMETHOD( GetIDsOfNames)( REFIID riid,
+ LPOLESTR *rgszNames,
+ UINT cNames,
+ LCID lcid,
+ DISPID *rgDispId) override;
+
+ STDMETHOD( Invoke)( DISPID dispIdMember,
+ REFIID riid,
+ LCID lcid,
+ WORD wFlags,
+ DISPPARAMS *pDispParams,
+ VARIANT *pVarResult,
+ EXCEPINFO *pExcepInfo,
+ UINT *puArgErr) override;
+ // IUnoTypeWrapper --------------------------------------
+ STDMETHOD(put_Name)(BSTR val) override;
+ STDMETHOD(get_Name)(BSTR* pVal) override;
+
+ CComBSTR m_sName;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/extensions/source/ole/wincrap.hxx b/extensions/source/ole/wincrap.hxx
new file mode 100644
index 000000000..4da57d53c
--- /dev/null
+++ b/extensions/source/ole/wincrap.hxx
@@ -0,0 +1,64 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+/* wrap all includes that need to be wrapped by prewin.h/postwin.h here */
+
+#define STRICT
+
+#define _WIN32_DCOM
+#if OSL_DEBUG_LEVEL > 0
+//#define _ATL_DEBUG_INTERFACES
+#endif
+
+#include <dispex.h>
+
+#include <prewin.h>
+#include <list>
+
+#if defined __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wall"
+#pragma clang diagnostic ignored "-Wattributes"
+#pragma clang diagnostic ignored "-Wdelete-incomplete"
+#pragma clang diagnostic ignored "-Wextra"
+#pragma clang diagnostic ignored "-Wint-to-pointer-cast"
+#pragma clang diagnostic ignored "-Winvalid-noreturn"
+#pragma clang diagnostic ignored "-Wmicrosoft"
+#pragma clang diagnostic ignored "-Wnon-pod-varargs"
+#pragma clang diagnostic ignored "-Wnon-virtual-dtor"
+#endif
+
+// from oleobjw.hxx
+#include <atlbase.h>
+// from jscriptclasses.hxx
+extern CComModule _Module;
+#include <atlcom.h>
+
+#if defined __clang__
+#pragma clang diagnostic pop
+#endif
+
+// from unoobjw.cxx
+#include <olectl.h>
+
+#include <postwin.h>
+
+/* 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 000000000..edf3c1d45
--- /dev/null
+++ b/extensions/source/ole/windata.hxx
@@ -0,0 +1,196 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <oleidl.h>
+
+#if defined __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wall"
+#pragma clang diagnostic ignored "-Wextra"
+#pragma clang diagnostic ignored "-Wignored-attributes"
+#pragma clang diagnostic ignored "-Wint-to-pointer-cast"
+#pragma clang diagnostic ignored "-Winvalid-noreturn"
+#pragma clang diagnostic ignored "-Wmicrosoft"
+#pragma clang diagnostic ignored "-Wnon-pod-varargs"
+#pragma clang diagnostic ignored "-Wnon-virtual-dtor"
+#endif
+
+#include <atlbase.h>
+
+#if defined __clang__
+#pragma clang diagnostic pop
+#endif
+
+#include <osl/diagnose.h>
+
+//Wrapper for VARDESC
+class VarDesc
+{
+ VARDESC* operator = (const VarDesc*);
+ VarDesc(const VarDesc&);
+// Construction
+public:
+ CComPtr< ITypeInfo > m_pTypeInfo;
+ VARDESC* m_pVarDesc;
+
+ explicit VarDesc(ITypeInfo* pTypeInfo) :
+ m_pTypeInfo(pTypeInfo),
+ m_pVarDesc(nullptr)
+ {
+ OSL_ASSERT(pTypeInfo);
+ }
+ ~VarDesc()
+ {
+ if (m_pVarDesc != nullptr)
+ {
+ 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:
+
+ explicit FuncDesc(ITypeInfo * pTypeInfo) :
+ m_pTypeInfo(pTypeInfo),
+ m_pFuncDesc(nullptr)
+ {
+ 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 = nullptr;
+ return pDesc;
+ }
+
+ void ReleaseFUNCDESC()
+ {
+ if (m_pFuncDesc != nullptr)
+ {
+ m_pTypeInfo->ReleaseFuncDesc(m_pFuncDesc);
+ }
+ m_pFuncDesc = nullptr;
+ }
+};
+//Wrapper for EXCEPINFO structure
+class ExcepInfo : public EXCEPINFO
+{
+ EXCEPINFO* operator = (const ExcepInfo& );
+ ExcepInfo(const ExcepInfo &);
+public:
+ ExcepInfo()
+ : EXCEPINFO{}
+ {
+ }
+ ~ExcepInfo()
+ {
+ if (bstrSource != nullptr)
+ ::SysFreeString(bstrSource);
+ if (bstrDescription != nullptr)
+ ::SysFreeString(bstrDescription);
+ if (bstrHelpFile != nullptr)
+ ::SysFreeString(bstrHelpFile);
+ }
+};
+
+//Wrapper for TYPEATTR
+class TypeAttr
+{
+ TYPEATTR* operator = (const TypeAttr &);
+ TypeAttr(const TypeAttr &);
+public:
+ CComPtr< ITypeInfo > m_pTypeInfo;
+ TYPEATTR* m_pTypeAttr;
+
+ explicit TypeAttr(ITypeInfo* pTypeInfo) :
+ m_pTypeInfo( pTypeInfo ),
+ m_pTypeAttr( nullptr )
+ {
+ OSL_ASSERT(pTypeInfo);
+ }
+ ~TypeAttr() noexcept
+ {
+ if (m_pTypeAttr != nullptr)
+ {
+ m_pTypeInfo->ReleaseTypeAttr(m_pTypeAttr);
+ }
+ }
+
+ TYPEATTR** operator&() noexcept
+ {
+ return &m_pTypeAttr;
+ }
+
+ TYPEATTR* operator->() noexcept
+ {
+ return m_pTypeAttr;
+ }
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */