Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  unoobjw.cxx

  Sprache: C
 

/* -*- 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 "-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 <systools/win32/oleauto.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 = sal::systools::BStr::newBSTR(message);
    }
}

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] = sal::systools::BStr::newBSTR(aMethods[memid + 2]->getName());
    *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 = sal::systools::BStr::newBSTR(msImplementationName);
        }
        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 = sal::systools::BStr::newBSTR(Concat2View("UnknownNameOfMember#" + OUString::number(memid)));
        }
    }
    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 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());
    }
    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.getValueTypeName() + ": " + 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.getValueTypeName().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: " << comphelper::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,&nbsp;&aVarResult, nullptr, &uArgErr);
            SAL_INFO("extensions.olebridge""Sink::Call(" << Method << "): Invoke() returned");

            SAL_WARN_IF(!SUCCEEDED(nResult), "extensions.olebridge""Call to " << Method << " failed: " << comphelper::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: " << comphelper::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;
    defaultbreak;
    }
    return ret;
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Messung V0.5 in Prozent
C=94 H=96 G=94

¤ Dauer der Verarbeitung: 0.104 Sekunden  (vorverarbeitet am  2026-05-08) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge