diff options
Diffstat (limited to 'extensions/source/ole/unoobjw.cxx')
-rw-r--r-- | extensions/source/ole/unoobjw.cxx | 1131 |
1 files changed, 975 insertions, 156 deletions
diff --git a/extensions/source/ole/unoobjw.cxx b/extensions/source/ole/unoobjw.cxx index 8e499b8b2dd2..b7aa0fa48cd3 100644 --- a/extensions/source/ole/unoobjw.cxx +++ b/extensions/source/ole/unoobjw.cxx @@ -1,4 +1,4 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ /* * This file is part of the LibreOffice project. * @@ -17,6 +17,11 @@ * 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/ + // See https://blogs.msdn.microsoft.com/vcblog/2017/12/08/c17-feature-removals-and-deprecations/ #define _SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING 1 @@ -50,12 +55,16 @@ #include <com/sun/star/script/XInvocation2.hpp> #include <com/sun/star/script/MemberType.hpp> #include <com/sun/star/reflection/XIdlReflection.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/processfactory.hxx> #include <comphelper/profilezone.hxx> #include <comphelper/windowsdebugoutput.hxx> +#include <comphelper/windowserrorstring.hxx> #include <o3tl/char16_t2wchar_t.hxx> #include "comifaces.hxx" @@ -81,6 +90,73 @@ static bool writeBackOutParameter(VARIANTARG* pDest, VARIANT* pSource); static bool writeBackOutParameter2( VARIANTARG* pDest, VARIANT* pSource); static HRESULT mapCannotConvertException(const CannotConvertException &e, unsigned int * puArgErr); +static std::string DumpTypeInfo(ITypeInfo *pTypeInfo, int indentLevel) +{ + std::ostringstream os; + os << std::string(indentLevel, ' ') << "ITypeInfo@" << std::hex << (void*) pTypeInfo; + + BSTR sName; + if (SUCCEEDED(pTypeInfo->GetDocumentation(MEMBERID_NIL, &sName, NULL, NULL, NULL))) + { + os << ":" << std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t>().to_bytes(sName); + } + + return os.str(); +} + +static std::string DumpDispatch(IDispatch *pDispatch, int indentLevel) +{ + std::ostringstream os; + os << std::string(indentLevel, ' ') << "IDispatch@" << (void*) pDispatch; +#if 0 // Doesn't work anyway, see comment "Sadly" below + // We "know" that we call this on the IUnknown passed to IConnectionPoint::Advise(), so check + // the event names we "know" are used in my Events.vbs test script. I.e. this is debug code very + // specific to the author's arbitrary transient development environment. + LPOLESTR vNames[] = { + L"DocumentOpen", + L"DocumentChange", + L"DocumentBeforeClose", + L"Foobar" + L"Quit", + L"WindowActivate" + }; + for (int i = 0; i < SAL_N_ELEMENTS(vNames); i++) + { + DISPID nDispId; + HRESULT hr; + // Sadly it turns out that the IUnknown passed to IConnectionPoint::Advise does have an + // IDispatch, but its GetIDsOfNames() returns E_NOTIMPL?! How is the COM object supposed to + // be able to invoke events in the outgoing interface when it can't look them up by name? + // Need to google harder for informative articles from the early 2000s. + hr = pDispatch->GetIDsOfNames(IID_NULL, vNames+i, 1, LOCALE_USER_DEFAULT, &nDispId); + if (SUCCEEDED(hr)) + { + os << "\n" << std::string(indentLevel+2, ' ') + << std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t>().to_bytes(vNames[i]) + << ": " << nDispId; + } + else if (hr == DISP_E_UNKNOWNNAME) + { + os << "\n" << std::string(indentLevel+2, ' ') + << std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t>().to_bytes(vNames[i]) + << ": unknown"; + } + } +#endif + + UINT nTypeInfoCount = 0; + if (SUCCEEDED(pDispatch->GetTypeInfoCount(&nTypeInfoCount)) && nTypeInfoCount == 1) + { + ITypeInfo *pTypeInfo = NULL; + if (SUCCEEDED(pDispatch->GetTypeInfo(0, LOCALE_USER_DEFAULT, &pTypeInfo)) && pTypeInfo != NULL) + { + os << "\n" << DumpTypeInfo(pTypeInfo, indentLevel); + } + } + + return os.str(); +} + /* Does not throw any exceptions. Param pInfo can be NULL. */ @@ -123,16 +199,35 @@ STDMETHODIMP InterfaceOleWrapper::QueryInterface(REFIID riid, LPVOID FAR * ppv) { 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) && + m_sImplementationName == "SwVbaApplication") + { + 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; @@ -200,229 +295,678 @@ class CXTypeInfo : public ITypeInfo, public CComObjectRoot { public: + enum class Kind { COCLASS, MAIN, OUTGOING }; + BEGIN_COM_MAP(CXTypeInfo) COM_INTERFACE_ENTRY(ITypeInfo) END_COM_MAP() DECLARE_NOT_AGGREGATABLE(CXTypeInfo) - void Init(InterfaceOleWrapper* pInterfaceOleWrapper) + 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); + 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: + BEGIN_COM_MAP(CXTypeLib) + COM_INTERFACE_ENTRY(ITypeLib) + END_COM_MAP() + + DECLARE_NOT_AGGREGATABLE(CXTypeLib) + + void Init(Reference<XInterface> xOrigin, + const OUString& sImplementationName, + Reference<XMultiServiceFactory> xMSF) { - SAL_INFO("extensions.olebridge", "CXTypeInfo::Init() this=" << this << " for " << pInterfaceOleWrapper->getImplementationName()); - mpInterfaceOleWrapper = pInterfaceOleWrapper; + SAL_INFO("extensions.olebridge", "CXTypeLib::Init() this=" << this << " for " << sImplementationName); + mxOrigin = xOrigin; + msImplementationName = sImplementationName; + mxMSF = xMSF; } - virtual HRESULT STDMETHODCALLTYPE GetTypeAttr(TYPEATTR **ppTypeAttr) override + virtual UINT STDMETHODCALLTYPE GetTypeInfoCount() override { - (void) ppTypeAttr; - SAL_WARN("extensions.olebridge", "CXTypeInfo::GetTypeAttr: NOTIMPL"); - return E_NOTIMPL; + SAL_WARN("extensions.olebridge", "CXTypeLib@" << this << "::GetTypeInfoCount()"); + return 1; } - virtual HRESULT STDMETHODCALLTYPE GetTypeComp(ITypeComp **ppTComp) override + virtual HRESULT STDMETHODCALLTYPE GetTypeInfo(UINT index, + ITypeInfo **ppTInfo) override { - (void) ppTComp; - SAL_WARN("extensions.olebridge", "CXTypeInfo::GetTypeComp: NOTIMPL"); + (void) index; + (void) ppTInfo; + SAL_WARN("extensions.olebridge", "CXTypeLib@" << this << "::GetTypeInfo: NOTIMPL"); return E_NOTIMPL; } - virtual HRESULT STDMETHODCALLTYPE GetFuncDesc(UINT index, - FUNCDESC **ppFuncDesc) override + virtual HRESULT STDMETHODCALLTYPE GetTypeInfoType(UINT index, + TYPEKIND *pTKind) override { (void) index; - (void) ppFuncDesc; - SAL_WARN("extensions.olebridge", "CXTypeInfo::GetFuncDesc: NOTIMPL"); + (void) pTKind; + SAL_WARN("extensions.olebridge", "CXTypeLib@" << this << "::GetTypeInfoType: NOTIMPL"); return E_NOTIMPL; } - virtual HRESULT STDMETHODCALLTYPE GetVarDesc(UINT index, - VARDESC **ppVarDesc) override + virtual HRESULT STDMETHODCALLTYPE GetTypeInfoOfGuid(REFGUID guid, + ITypeInfo **ppTInfo) override { - (void) index; - (void) ppVarDesc; - SAL_WARN("extensions.olebridge", "CXTypeInfo::GetVarDesc: NOTIMPL"); + SAL_INFO("extensions.olebridge", "CXTypeLib@" << this << "::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((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 **ppTLibAttr) override + { + (void) ppTLibAttr; + SAL_WARN("extensions.olebridge", "CXTypeLib@" << this << "::GetLibAttr: NOTIMPL"); return E_NOTIMPL; } - virtual HRESULT STDMETHODCALLTYPE GetNames(MEMBERID memid, - BSTR *rgBstrNames, - UINT cMaxNames, - UINT *pcNames) override + virtual HRESULT STDMETHODCALLTYPE GetTypeComp(ITypeComp **ppTComp) override { - (void) memid; - (void) rgBstrNames; - (void) cMaxNames; - (void) pcNames; - SAL_WARN("extensions.olebridge", "CXTypeInfo::GetNames: NOTIMPL"); + (void) ppTComp; + SAL_WARN("extensions.olebridge", "CXTypeLib@" << this << "::GetTypeComp: NOTIMPL"); return E_NOTIMPL; } - virtual HRESULT STDMETHODCALLTYPE GetRefTypeOfImplType(UINT index, - HREFTYPE *pRefType) override + virtual HRESULT STDMETHODCALLTYPE GetDocumentation(INT index, + BSTR *pBstrName, + BSTR *pBstrDocString, + DWORD *pdwHelpContext, + BSTR *pBstrHelpFile) override { (void) index; - (void) pRefType; - SAL_WARN("extensions.olebridge", "CXTypeInfo::GetRefTypeOfImplType: NOTIMPL"); + (void) pBstrName; + (void) pBstrDocString; + (void) pdwHelpContext; + (void) pBstrHelpFile; + SAL_WARN("extensions.olebridge", "CXTypeLib@" << this << "::GetDocumentation: NOTIMPL"); return E_NOTIMPL; } - virtual HRESULT STDMETHODCALLTYPE GetImplTypeFlags(UINT index, - INT *pImplTypeFlags) override + virtual HRESULT STDMETHODCALLTYPE IsName(LPOLESTR szNameBuf, + ULONG lHashVal, + BOOL *pfName) override { - (void) index; - (void) pImplTypeFlags; - SAL_WARN("extensions.olebridge", "CXTypeInfo::GetImplTypeFlags: NOTIMPL"); + (void) szNameBuf; + (void) lHashVal; + (void) pfName; + SAL_WARN("extensions.olebridge", "CXTypeLib@" << this << "::IsName: NOTIMPL"); return E_NOTIMPL; } - virtual HRESULT STDMETHODCALLTYPE GetIDsOfNames(LPOLESTR *rgszNames, - UINT cNames, - MEMBERID *pMemId) override + virtual HRESULT STDMETHODCALLTYPE FindName(LPOLESTR szNameBuf, + ULONG lHashVal, + ITypeInfo **ppTInfo, + MEMBERID *rgMemId, + USHORT *pcFound) override { - (void) rgszNames; - (void) cNames; - (void) pMemId; - SAL_WARN("extensions.olebridge", "CXTypeInfo::GetIDsOfNames: NOTIMPL"); + (void) szNameBuf; + (void) lHashVal; + (void) ppTInfo; + (void) rgMemId; + (void) pcFound; + SAL_WARN("extensions.olebridge", "CXTypeLib@" << this << "::FindName: NOTIMPL"); return E_NOTIMPL; } - virtual HRESULT STDMETHODCALLTYPE Invoke(PVOID pvInstance, + virtual void STDMETHODCALLTYPE ReleaseTLibAttr(TLIBATTR *pTLibAttr) override + { + (void) pTLibAttr; + SAL_WARN("extensions.olebridge", "CXTypeLib@" << this << "::ReleaseTLibAttr: 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", "CXTypeInfo::InitForCoclass() this=" << this << " for " << rIID << " (" << sImplementationName << ")"); + meKind = Kind::COCLASS; + mxOrigin = xOrigin; + msImplementationName = sImplementationName; + maIID = rIID; + mxMSF = xMSF; +} + +void CXTypeInfo::InitForClassItself(Reference<XInterface> xOrigin, + const OUString& sImplementationName, + const IID& rIID) +{ + SAL_INFO("extensions.olebridge", "CXTypeInfo::InitForClassItself() this=" << this << " for " << rIID << " (" << sImplementationName << ")"); + meKind = Kind::MAIN; + mxOrigin = xOrigin; + msImplementationName = sImplementationName; + maIID = rIID; +} + +void CXTypeInfo::InitForOutgoing(Reference<XInterface> xOrigin, + const OUString& sInterfaceName, + const IID& rIID, + Reference<XMultiServiceFactory> xMSF, + Type aType) +{ + SAL_INFO("extensions.olebridge", "CXTypeInfo::InitForOutgoing() this=" << this << " for " << rIID << " (" << sInterfaceName << ")"); + meKind = Kind::OUTGOING; + mxOrigin = xOrigin; + msInterfaceName = sInterfaceName; + maIID = rIID; + mxMSF = xMSF; + maType = aType; +} + +HRESULT STDMETHODCALLTYPE CXTypeInfo::GetTypeAttr(TYPEATTR **ppTypeAttr) +{ + SAL_INFO("extensions.olebridge", "CXTypeInfo@" << this << "::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", "CXTypeInfo@" << this << "::GetTypeAttr(): " << pTypeAttr); + + *ppTypeAttr = pTypeAttr; + + return S_OK; +} + +HRESULT STDMETHODCALLTYPE CXTypeInfo::GetTypeComp(ITypeComp **ppTComp) +{ + (void) ppTComp; + SAL_WARN("extensions.olebridge", "CXTypeInfo@" << this << "::GetTypeComp: NOTIMPL"); + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE CXTypeInfo::GetFuncDesc(UINT index, + FUNCDESC **ppFuncDesc) +{ + (void) index; + (void) ppFuncDesc; + SAL_WARN("extensions.olebridge", "CXTypeInfo@" << this << "::GetFuncDesc: NOTIMPL"); + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE CXTypeInfo::GetVarDesc(UINT index, + VARDESC **ppVarDesc) +{ + (void) index; + (void) ppVarDesc; + SAL_WARN("extensions.olebridge", "CXTypeInfo@" << this << "::GetVarDesc: NOTIMPL"); + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE CXTypeInfo::GetNames(MEMBERID memid, + BSTR *rgBstrNames, + UINT cMaxNames, + UINT *pcNames) +{ + SAL_WARN("extensions.olebridge", "CXTypeInfo@" << this << "::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; + + rgBstrNames[0] = SysAllocString((LPOLESTR) aMethods[memid + 2]->getName().pData->buffer); + *pcNames = 1; + + return S_OK; +} + +HRESULT STDMETHODCALLTYPE CXTypeInfo::GetRefTypeOfImplType(UINT index, + HREFTYPE *pRefType) +{ + SAL_INFO("extensions.olebridge", "CXTypeInfo@" << this << "::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) +{ + SAL_INFO("extensions.olebridge", "CXTypeInfo@" << this << "::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 *rgszNames, + UINT cNames, + MEMBERID *pMemId) +{ + (void) rgszNames; + (void) cNames; + (void) pMemId; + SAL_WARN("extensions.olebridge", "CXTypeInfo@" << this << "::GetIDsOfNames: NOTIMPL"); + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE CXTypeInfo::Invoke(PVOID pvInstance, MEMBERID memid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, - UINT *puArgErr) override - { - (void) pvInstance; - (void) memid; - (void) wFlags; - (void) pDispParams; - (void) pVarResult; - (void) pExcepInfo; - (void) puArgErr; - SAL_WARN("extensions.olebridge", "CXTypeInfo::Invoke: NOTIMPL"); - return E_NOTIMPL; - } + UINT *puArgErr) +{ + (void) pvInstance; + (void) memid; + (void) wFlags; + (void) pDispParams; + (void) pVarResult; + (void) pExcepInfo; + (void) puArgErr; + SAL_WARN("extensions.olebridge", "CXTypeInfo@" << this << "::Invoke: NOTIMPL"); + return E_NOTIMPL; +} - virtual HRESULT STDMETHODCALLTYPE GetDocumentation(MEMBERID memid, +HRESULT STDMETHODCALLTYPE CXTypeInfo::GetDocumentation(MEMBERID memid, BSTR *pBstrName, BSTR *pBstrDocString, DWORD *pdwHelpContext, - BSTR *pBstrHelpFile) override + BSTR *pBstrHelpFile) +{ + SAL_INFO("extensions.olebridge", "CXTypeInfo@" << this << "::GetDocumentation(" << memid << ")"); + if (pBstrName) { - SAL_INFO("extensions.olebridge", "CXTypeInfo::GetDocumentation(" << memid << ")"); - if (pBstrName) + if (memid == MEMBERID_NIL) { - if (memid == MEMBERID_NIL) - { - *pBstrName = SysAllocString(o3tl::toW(mpInterfaceOleWrapper->getImplementationName().getStr())); - } - else if (memid == DISPID_VALUE) - { - // MEMBERIDs are the same as DISPIDs, apparently? - *pBstrName = SysAllocString(L"Value"); - } - else - { - *pBstrName = SysAllocString(L"Unknown"); - } + *pBstrName = SysAllocString(o3tl::toW(msImplementationName.getStr())); + } + else if (memid == DISPID_VALUE) + { + // MEMBERIDs are the same as DISPIDs, apparently? + *pBstrName = SysAllocString(L"Value"); + } + else + { + *pBstrName = SysAllocString(L"Unknown"); } - if (pBstrDocString) - *pBstrDocString = SysAllocString(L"");; - if (pdwHelpContext) - *pdwHelpContext = 0; - if (pBstrHelpFile) - *pBstrHelpFile = NULL; - - return S_OK; } + if (pBstrDocString) + *pBstrDocString = SysAllocString(L"");; + if (pdwHelpContext) + *pdwHelpContext = 0; + if (pBstrHelpFile) + *pBstrHelpFile = NULL; - virtual HRESULT STDMETHODCALLTYPE GetDllEntry(MEMBERID memid, + return S_OK; +} + +HRESULT STDMETHODCALLTYPE CXTypeInfo::GetDllEntry(MEMBERID memid, INVOKEKIND invKind, BSTR *pBstrDllName, BSTR *pBstrName, - WORD *pwOrdinal) override - { - (void) memid; - (void) invKind; - (void) pBstrDllName; - (void) pBstrName; - (void) pwOrdinal; - SAL_WARN("extensions.olebridge", "CXTypeInfo::GetDllEntry: NOTIMPL"); + WORD *pwOrdinal) +{ + (void) memid; + (void) invKind; + (void) pBstrDllName; + (void) pBstrName; + (void) pwOrdinal; + SAL_WARN("extensions.olebridge", "CXTypeInfo@" << this << "::GetDllEntry: NOTIMPL"); + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE CXTypeInfo::GetRefTypeInfo(HREFTYPE hRefType, + ITypeInfo **ppTInfo) +{ + SAL_INFO("extensions.olebridge", "CXTypeInfo@" << this << "::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; - } - virtual HRESULT STDMETHODCALLTYPE GetRefTypeInfo(HREFTYPE hRefType, - ITypeInfo **ppTInfo) override - { - (void) hRefType; - (void) ppTInfo; - SAL_WARN("extensions.olebridge", "CXTypeInfo::GetRefTypeInfo: NOTIMPL"); + ooo::vba::TypeAndIID aTypeAndIID = xConnectable->GetConnectionPoint(); + + IID aIID; + if (!SUCCEEDED(IIDFromString((LPOLESTR)aTypeAndIID.IID.pData->buffer, &aIID))) return E_NOTIMPL; - } - virtual HRESULT STDMETHODCALLTYPE AddressOfMember(MEMBERID memid, + 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 memid, INVOKEKIND invKind, - PVOID *ppv) override - { - (void) memid; - (void) invKind; - (void) ppv; - SAL_WARN("extensions.olebridge", "CXTypeInfo::AddressOfMember: NOTIMPL"); - return E_NOTIMPL; - } + PVOID *ppv) +{ + (void) memid; + (void) invKind; + (void) ppv; + SAL_WARN("extensions.olebridge", "CXTypeInfo@" << this << "::AddressOfMember: NOTIMPL"); + return E_NOTIMPL; +} - virtual HRESULT STDMETHODCALLTYPE CreateInstance(IUnknown *pUnkOuter, +HRESULT STDMETHODCALLTYPE CXTypeInfo::CreateInstance(IUnknown *pUnkOuter, REFIID riid, - PVOID *ppvObj) override - { - (void) pUnkOuter; - (void) riid; - (void) ppvObj; - SAL_WARN("extensions.olebridge", "CXTypeInfo::CreateInstance: NOTIMPL"); - return E_NOTIMPL; - } + PVOID *ppvObj) +{ + (void) pUnkOuter; + (void) riid; + (void) ppvObj; + SAL_WARN("extensions.olebridge", "CXTypeInfo@" << this << "::CreateInstance: NOTIMPL"); + return E_NOTIMPL; +} - virtual HRESULT STDMETHODCALLTYPE GetMops(MEMBERID memid, - BSTR *pBstrMops) override - { - (void) memid; - (void) pBstrMops; - SAL_WARN("extensions.olebridge", "CXTypeInfo::GetMops: NOTIMPL"); - return E_NOTIMPL; - } +HRESULT STDMETHODCALLTYPE CXTypeInfo::GetMops(MEMBERID memid, + BSTR *pBstrMops) +{ + (void) memid; + (void) pBstrMops; + SAL_WARN("extensions.olebridge", "CXTypeInfo@" << this << "::GetMops: NOTIMPL"); + return E_NOTIMPL; +} - virtual HRESULT STDMETHODCALLTYPE GetContainingTypeLib(ITypeLib **ppTLib, - UINT *pIndex) override - { - (void) ppTLib; - (void) pIndex; - SAL_WARN("extensions.olebridge", "CXTypeInfo::GetContainingTypeLib: 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. - virtual void STDMETHODCALLTYPE ReleaseTypeAttr(TYPEATTR *pTypeAttr) override - { - (void) pTypeAttr; - SAL_WARN("extensions.olebridge", "CXTypeInfo::ReleaseTypeAttr: NOTIMPL"); - } +HRESULT STDMETHODCALLTYPE CXTypeInfo::GetContainingTypeLib(ITypeLib **ppTLib, + UINT *pIndex) +{ + SAL_INFO("extensions.olebridge", "CXTypeInfo@" << this << "::GetContainingTypeLib"); - virtual void STDMETHODCALLTYPE ReleaseFuncDesc(FUNCDESC *pFuncDesc) override - { - (void) pFuncDesc; - SAL_WARN("extensions.olebridge", "CXTypeInfo::ReleaseFuncDesc: NOTIMPL"); - } + if (!ppTLib || !pIndex) + return E_POINTER; - virtual void STDMETHODCALLTYPE ReleaseVarDesc(VARDESC *pVarDesc) override - { - (void) pVarDesc; - SAL_WARN("extensions.olebridge", "CXTypeInfo::ReleaseVarDesc: NOTIMPL"); - } + HRESULT ret; -private: - InterfaceOleWrapper* mpInterfaceOleWrapper; -}; + 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", "CXTypeInfo@" << this << "::ReleaseTypeAttr(" << pTypeAttr << ")"); + + delete pTypeAttr; +} + +void STDMETHODCALLTYPE CXTypeInfo::ReleaseFuncDesc(FUNCDESC *pFuncDesc) +{ + (void) pFuncDesc; + SAL_WARN("extensions.olebridge", "CXTypeInfo@" << this << "::ReleaseFuncDesc: NOTIMPL"); +} + +void STDMETHODCALLTYPE CXTypeInfo::ReleaseVarDesc(VARDESC *pVarDesc) +{ + (void) pVarDesc; + SAL_WARN("extensions.olebridge", "CXTypeInfo@" << this << "::ReleaseVarDesc: NOTIMPL"); +} STDMETHODIMP InterfaceOleWrapper::GetTypeInfo(unsigned int iTInfo, LCID, ITypeInfo ** ppTInfo) { @@ -434,7 +978,16 @@ STDMETHODIMP InterfaceOleWrapper::GetTypeInfo(unsigned int iTInfo, LCID, ITypeIn if (iTInfo != 0) return E_NOTIMPL; - HRESULT ret = S_OK; + Reference<ooo::vba::XConnectable> xConnectable(m_xOrigin, UNO_QUERY); + if (!xConnectable.is()) + return E_NOTIMPL; + + OUString sIID = xConnectable->GetIIDForClassItselfNotCoclass(); + IID aIID; + if (!SUCCEEDED(IIDFromString((LPOLESTR)sIID.pData->buffer, &aIID))) + return E_NOTIMPL; + + HRESULT ret; CComObject<CXTypeInfo>* pTypeInfo; @@ -444,7 +997,7 @@ STDMETHODIMP InterfaceOleWrapper::GetTypeInfo(unsigned int iTInfo, LCID, ITypeIn pTypeInfo->AddRef(); - pTypeInfo->Init(this); + pTypeInfo->InitForClassItself(m_xOrigin, m_sImplementationName, aIID); *ppTInfo = pTypeInfo; @@ -468,7 +1021,7 @@ STDMETHODIMP InterfaceOleWrapper::GetIDsOfNames(REFIID /*riid*/, if( ! rgdispid) return E_POINTER; - // FIXME: Handle the cNames > 1 case + // 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)) @@ -1414,6 +1967,182 @@ private: Reference<XEnumeration> mxEnumeration; }; +class Sink : public cppu::WeakImplHelper<ooo::vba::XSink> +{ +public: + Sink(IUnknown* pUnkSink, + Reference<XMultiServiceFactory> xMSF, + ooo::vba::TypeAndIID aTypeAndIID); + + // XSink + void SAL_CALL Call( const OUString& Method, const Sequence< Any >& Arguments ) override; + +private: + IUnknown* mpUnkSink; + Reference<XMultiServiceFactory> mxMSF; + ooo::vba::TypeAndIID maTypeAndIID; +}; + +Sink::Sink(IUnknown* pUnkSink, + Reference<XMultiServiceFactory> xMSF, + ooo::vba::TypeAndIID aTypeAndIID) : + mpUnkSink(pUnkSink), + mxMSF(xMSF), + maTypeAndIID(aTypeAndIID) +{ + mpUnkSink->AddRef(); +} + +void SAL_CALL +Sink::Call( const OUString& Method, const Sequence< Any >& Arguments ) +{ + SAL_INFO("extensions.olebridge", "Sink::Call(" << Method << ", " << Arguments.getLength() << " arguments)"); + + IDispatch* pDispatch; + HRESULT nResult = mpUnkSink->QueryInterface(IID_IDispatch, (void **) &pDispatch); + if (!SUCCEEDED(nResult)) + { + SAL_WARN("extensions.olebridge", "Sink::Call: Not IDispatch: " << WindowsErrorStringFromHRESULT(nResult)); + return; + } + + Reference<XIdlReflection> xRefl = theCoreReflection::get(comphelper::getComponentContext(mxMSF)); + assert(xRefl.is()); + + Reference<XIdlClass> xClass = xRefl->forName(maTypeAndIID.Type.getTypeName()); + assert(xClass.is()); + + auto aMethods = xClass->getMethods(); + assert(xClass->getTypeClass() == TypeClass_INTERFACE && + aMethods.getLength() > 0); + + int nMemId = 1; + // Skip the three XInterface methods + for (int i = 3; i < aMethods.getLength(); i++) + { + if (aMethods[i]->getName() == Method) + { + DISPPARAMS aDispParams; + aDispParams.rgvarg = NULL; + aDispParams.rgdispidNamedArgs = NULL; + aDispParams.cArgs = 0; + aDispParams.cNamedArgs = 0; + VARIANT aVarResult; + VariantInit(&aVarResult); + UINT uArgErr; + nResult = pDispatch->Invoke(nMemId, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &aDispParams, &aVarResult, NULL, &uArgErr); + SAL_WARN_IF(!SUCCEEDED(nResult), "extensions.olebridge", "Call to " << Method << " failed: " << WindowsErrorStringFromHRESULT(nResult)); + return; + } + nMemId++; + } + SAL_WARN("extensions.olebridge", "Sink::Call: Uknown method '" << Method << "'"); +} + +class CXConnectionPoint : public IConnectionPoint, + public CComObjectRoot +{ +public: + BEGIN_COM_MAP(CXConnectionPoint) + COM_INTERFACE_ENTRY(IConnectionPoint) + END_COM_MAP() + + DECLARE_NOT_AGGREGATABLE(CXConnectionPoint) + + void Init(InterfaceOleWrapper* pInterfaceOleWrapper, + Reference<ooo::vba::XConnectionPoint>& xCP, + Reference<XMultiServiceFactory>& xMSF, + ooo::vba::TypeAndIID aTypeAndIID) + { + SAL_INFO("extensions.olebridge", "CXConnectionPoint::Init() this=" << this << " for " << pInterfaceOleWrapper->getImplementationName()); + + IUnknown *pUnknown; + if (SUCCEEDED(QueryInterface(IID_IUnknown, (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", "CXConnectionPoint@" << this << "::GetConnectionInterface(" << *pIID << "): NOTIMPL"); + + // FIXME: Needed? + + return E_NOTIMPL; + } + + virtual HRESULT STDMETHODCALLTYPE GetConnectionPointContainer(IConnectionPointContainer **ppCPC) override + { + (void) ppCPC; + SAL_WARN("extensions.olebridge", "CXConnectionPoint@" << this << "::GetConnectionInterface: NOTIMPL"); + + // FIXME: Needed? + + return E_NOTIMPL; + } + + virtual HRESULT STDMETHODCALLTYPE Advise(IUnknown *pUnkSink, + DWORD *pdwCookie) override + { + SAL_INFO("extensions.olebridge", "CXConnectionPoint@" << this << "::Advise(" << pUnkSink << ")"); + + if (!pdwCookie) + return E_POINTER; + + Reference<ooo::vba::XSink> xSink(new Sink(pUnkSink, mxMSF, maTypeAndIID)); + + 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 + { + SAL_INFO("extensions.olebridge", "CXConnectionPoint@" << this << "::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 + { + (void) ppEnum; + SAL_WARN("extensions.olebridge", "CXConnectionPoint@" << this << "::EnumConnections: NOTIMPL"); + return E_NOTIMPL; + } + +private: + InterfaceOleWrapper* mpInterfaceOleWrapper; + std::vector<IUnknown*> mvISinks; + std::vector<Reference<ooo::vba::XSink>> mvXSinks; + std::vector<sal_uInt32> 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) @@ -1545,7 +2274,7 @@ HRESULT InterfaceOleWrapper::InvokeGeneral( DISPID dispidMember, unsigned short pvarResult->vt = VT_UNKNOWN; pvarResult->punkVal = NULL; - ret = pEnumVar->QueryInterface(IID_IUnknown, (void**)&pvarResult->punkVal); + ret = pEnumVar->QueryInterface(IID_IUnknown, (void**) &pvarResult->punkVal); if (FAILED(ret)) { pEnumVar->Release(); @@ -1633,6 +2362,96 @@ STDMETHODIMP InterfaceOleWrapper::GetNameSpaceParent( return ResultFromScode(E_NOTIMPL); } +// IProvideClassInfo +HRESULT STDMETHODCALLTYPE InterfaceOleWrapper::GetClassInfo ( + /* [out] */ ITypeInfo **ppTI) +{ + SAL_INFO("extensions.olebridge", "InterfaceOleWrapper@" << this << "::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((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 **ppEnum) +{ + (void) ppEnum; + SAL_INFO("extensions.olebridge", "InterfaceOleWrapper@" << this << "::EnumConnectionPoints"); + return ResultFromScode(E_NOTIMPL); +} + +HRESULT STDMETHODCALLTYPE InterfaceOleWrapper::FindConnectionPoint( + /* [in] */ REFIID riid, + /* [out] */ IConnectionPoint **ppCP) +{ + SAL_INFO("extensions.olebridge", "InterfaceOleWrapper@" << this << "::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((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, |