Version 6.4.0.0.beta1, tag libreoffice-6.4.0.0.beta1
[LibreOffice.git] / extensions / source / ole / unoobjw.cxx
blob436feb3097e9cc562e4c6bec55583408d72dcff8
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 // Documentation pointers for recent work:
22 // https://www.codeproject.com/Articles/9014/Understanding-COM-Event-Handling
23 // https://blogs.msdn.microsoft.com/ericlippert/2005/02/15/why-does-wscript-connectobject-not-always-work/
25 #include "ole2uno.hxx"
27 #include <stdio.h>
28 #include <list>
29 #include <sstream>
30 #include <unordered_map>
31 #include <vector>
33 #if defined _MSC_VER && defined __clang__
34 #pragma clang diagnostic push
35 #pragma clang diagnostic ignored "-Wall"
36 #pragma clang diagnostic ignored "-Wattributes"
37 #pragma clang diagnostic ignored "-Wdelete-incomplete"
38 #pragma clang diagnostic ignored "-Wdynamic-class-memaccess"
39 #pragma clang diagnostic ignored "-Wextra"
40 #pragma clang diagnostic ignored "-Wint-to-pointer-cast"
41 #pragma clang diagnostic ignored "-Winvalid-noreturn"
42 #pragma clang diagnostic ignored "-Wmicrosoft"
43 #pragma clang diagnostic ignored "-Wnon-pod-varargs"
44 #pragma clang diagnostic ignored "-Wnon-virtual-dtor"
45 #pragma clang diagnostic ignored "-Wnonportable-include-path"
46 #pragma clang diagnostic ignored "-Wsequence-point"
47 #pragma clang diagnostic ignored "-Wtypename-missing"
48 #endif
49 #include <atlbase.h>
50 #include <atlcom.h>
51 #if defined _MSC_VER && defined __clang__
52 #pragma clang diagnostic pop
53 #endif
54 #include <comdef.h>
56 #include <osl/diagnose.h>
57 #include <salhelper/simplereferenceobject.hxx>
58 #include <rtl/ref.hxx>
59 #include <rtl/ustring.hxx>
60 #include <tools/diagnose_ex.h>
61 #include <sal/log.hxx>
62 #include <com/sun/star/beans/MethodConcept.hpp>
63 #include <com/sun/star/beans/PropertyConcept.hpp>
64 #include <com/sun/star/frame/Desktop.hpp>
65 #include <com/sun/star/frame/TerminationVetoException.hpp>
66 #include <com/sun/star/frame/XTerminateListener.hpp>
67 #include <com/sun/star/lang/NoSuchMethodException.hpp>
68 #include <com/sun/star/script/CannotConvertException.hpp>
69 #include <com/sun/star/script/FailReason.hpp>
70 #include <com/sun/star/reflection/theCoreReflection.hpp>
71 #include <com/sun/star/reflection/ParamInfo.hpp>
72 #include <com/sun/star/beans/XExactName.hpp>
73 #include <com/sun/star/container/NoSuchElementException.hpp>
74 #include <com/sun/star/container/XEnumeration.hpp>
75 #include <com/sun/star/container/XEnumerationAccess.hpp>
77 #include <com/sun/star/beans/XMaterialHolder.hpp>
78 #include <com/sun/star/script/XInvocation2.hpp>
79 #include <com/sun/star/script/MemberType.hpp>
80 #include <com/sun/star/reflection/XIdlReflection.hpp>
81 #include <ooo/vba/XCollection.hpp>
82 #include <ooo/vba/XConnectable.hpp>
83 #include <ooo/vba/XConnectionPoint.hpp>
84 #include <ooo/vba/XSink.hpp>
85 #include <ooo/vba/msforms/XCheckBox.hpp>
86 #include <osl/interlck.h>
87 #include <com/sun/star/uno/genfunc.h>
88 #include <comphelper/automationinvokedzone.hxx>
89 #include <comphelper/asyncquithandler.hxx>
90 #include <comphelper/processfactory.hxx>
91 #include <comphelper/profilezone.hxx>
92 #include <comphelper/windowsdebugoutput.hxx>
93 #include <comphelper/windowserrorstring.hxx>
94 #include <o3tl/char16_t2wchar_t.hxx>
96 #include "comifaces.hxx"
97 #include "jscriptclasses.hxx"
98 #include "unotypewrapper.hxx"
99 #include "oleobjw.hxx"
100 #include "unoobjw.hxx"
101 #include "servprov.hxx"
103 using namespace std;
104 using namespace osl;
105 using namespace cppu;
106 using namespace com::sun::star::uno;
107 using namespace com::sun::star::beans;
108 using namespace com::sun::star::container;
109 using namespace com::sun::star::script;
110 using namespace com::sun::star::lang;
111 using namespace com::sun::star::bridge::ModelDependent;
112 using namespace com::sun::star::reflection;
114 std::unordered_map<sal_uIntPtr, WeakReference<XInterface> > UnoObjToWrapperMap;
115 static bool writeBackOutParameter(VARIANTARG* pDest, VARIANT* pSource);
116 static bool writeBackOutParameter2( VARIANTARG* pDest, VARIANT* pSource);
117 static HRESULT mapCannotConvertException(const CannotConvertException &e, unsigned int * puArgErr);
119 class TerminationVetoer : public WeakImplHelper<css::frame::XTerminateListener>
121 public:
122 int mnCount;
124 private:
125 TerminationVetoer()
126 : mnCount(0)
130 Reference< css::frame::XDesktop > xDesktop =
131 css::frame::Desktop::create( comphelper::getProcessComponentContext() );
132 xDesktop->addTerminateListener( this );
134 catch ( const Exception& )
136 DBG_UNHANDLED_EXCEPTION("extensions.olebridge");
140 public:
141 static rtl::Reference< TerminationVetoer > get()
143 static TerminationVetoer* pInstance = new TerminationVetoer;
144 static rtl::Reference< TerminationVetoer > aInstance( pInstance );
146 return aInstance;
149 // XTerminateListener
150 void SAL_CALL queryTermination( const EventObject& ) override
152 SAL_INFO("extensions.olebridge", "TerminationVetoer::queryTermination: count=" << mnCount);
153 // Always veto termination while an OLE object is active, except if it is an OLE object that
154 // has asked us to quit.
155 if (!AsyncQuitHandler::instance().IsForceQuit() && mnCount > 0)
157 SAL_INFO("extensions.olebridge", "TerminationVetoer::queryTermination: Throwing!");
158 throw css::frame::TerminationVetoException();
162 void SAL_CALL notifyTermination( const EventObject& ) override
164 // ???
167 // XEventListener
168 void SAL_CALL disposing( const css::lang::EventObject& ) override
170 // ???
174 /* Does not throw any exceptions.
175 Param pInfo can be NULL.
177 static void writeExcepinfo(EXCEPINFO * pInfo, const OUString& message)
179 if (pInfo != nullptr)
181 pInfo->wCode = UNO_2_OLE_EXCEPTIONCODE;
182 pInfo->bstrSource = SysAllocString(L"[automation bridge] ");
183 pInfo->bstrDescription = SysAllocString(o3tl::toW(message.getStr()));
187 InterfaceOleWrapper::InterfaceOleWrapper( Reference<XMultiServiceFactory> const & xFactory,
188 sal_uInt8 unoWrapperClass, sal_uInt8 comWrapperClass):
189 UnoConversionUtilities<InterfaceOleWrapper>( xFactory, unoWrapperClass, comWrapperClass),
190 m_defaultValueType( 0)
192 TerminationVetoer::get()->mnCount++;
193 SAL_INFO("extensions.olebridge", "InterfaceOleWrapper CTOR, count=" << TerminationVetoer::get()->mnCount);
196 InterfaceOleWrapper::~InterfaceOleWrapper()
198 MutexGuard guard(getBridgeMutex());
199 // remove entries in global map
200 auto it = UnoObjToWrapperMap.find( reinterpret_cast<sal_uIntPtr>(m_xOrigin.get()));
201 if(it != UnoObjToWrapperMap.end())
202 UnoObjToWrapperMap.erase(it);
204 TerminationVetoer::get()->mnCount--;
205 SAL_INFO("extensions.olebridge", "InterfaceOleWrapper DTOR, count=" << TerminationVetoer::get()->mnCount);
208 COM_DECLSPEC_NOTHROW STDMETHODIMP InterfaceOleWrapper::QueryInterface(REFIID riid, void ** ppv)
210 comphelper::Automation::AutomationInvokedZone aAutomationActive;
212 SAL_INFO("extensions.olebridge", this << "@InterfaceOleWrapper::QueryInterface(" << riid << ")");
214 HRESULT ret= S_OK;
216 if( !ppv)
217 return E_POINTER;
219 if(IsEqualIID(riid, IID_IUnknown))
221 AddRef();
222 *ppv = static_cast<IUnknown*>(static_cast<IDispatch*>(this));
223 SAL_INFO("extensions.olebridge", " " << *ppv);
225 else if (IsEqualIID(riid, IID_IDispatch))
227 AddRef();
228 *ppv = static_cast<IDispatch*>(this);
229 SAL_INFO("extensions.olebridge", " " << *ppv);
231 else if (IsEqualIID(riid, IID_IProvideClassInfo))
233 Reference<ooo::vba::XConnectable> xConnectable(m_xOrigin, UNO_QUERY);
234 if (!xConnectable.is())
235 return E_NOINTERFACE;
236 AddRef();
237 *ppv = static_cast<IProvideClassInfo*>(this);
238 SAL_INFO("extensions.olebridge", " " << *ppv);
240 else if (IsEqualIID(riid, IID_IConnectionPointContainer))
242 Reference<ooo::vba::XConnectable> xConnectable(m_xOrigin, UNO_QUERY);
243 if (!xConnectable.is())
244 return E_NOINTERFACE;
245 AddRef();
246 *ppv = static_cast<IConnectionPointContainer*>(this);
247 SAL_INFO("extensions.olebridge", " " << *ppv);
249 else if( IsEqualIID( riid, __uuidof( IUnoObjectWrapper)))
251 AddRef();
252 *ppv= static_cast<IUnoObjectWrapper*>(this);
253 SAL_INFO("extensions.olebridge", " " << *ppv);
255 else
256 ret= E_NOINTERFACE;
257 return ret;
260 COM_DECLSPEC_NOTHROW STDMETHODIMP_(ULONG) InterfaceOleWrapper::AddRef()
262 acquire();
263 // does not need to guard because one should not rely on the return value of
264 // AddRef anyway
265 return m_refCount;
268 COM_DECLSPEC_NOTHROW STDMETHODIMP_(ULONG) InterfaceOleWrapper::Release()
270 ULONG n= m_refCount;
271 release();
272 return n - 1;
275 // IUnoObjectWrapper --------------------------------------------------------
276 COM_DECLSPEC_NOTHROW STDMETHODIMP InterfaceOleWrapper::getWrapperXInterface( Reference<XInterface>* pXInt)
278 pXInt->set( static_cast<XWeak*>( this), UNO_QUERY);
279 return pXInt->is() ? S_OK : E_FAIL;
281 COM_DECLSPEC_NOTHROW STDMETHODIMP InterfaceOleWrapper::getOriginalUnoObject( Reference<XInterface>* pXInt)
283 *pXInt= m_xOrigin;
284 return m_xOrigin.is() ? S_OK : E_FAIL;
286 COM_DECLSPEC_NOTHROW STDMETHODIMP InterfaceOleWrapper::getOriginalUnoStruct( Any * pStruct)
288 comphelper::Automation::AutomationInvokedZone aAutomationActive;
290 HRESULT ret= E_FAIL;
291 if( !m_xOrigin.is())
293 Reference<XMaterialHolder> xMatHolder( m_xInvocation, UNO_QUERY);
294 if( xMatHolder.is())
296 Any any = xMatHolder->getMaterial();
297 if( any.getValueTypeClass() == TypeClass_STRUCT)
299 *pStruct= any;
300 ret= S_OK;
304 return ret;
307 COM_DECLSPEC_NOTHROW STDMETHODIMP InterfaceOleWrapper::GetTypeInfoCount( UINT *pctinfo )
309 SAL_INFO("extensions.olebridge", this << "@InterfaceOleWrapper::GetTypeInfoCount");
311 if (!pctinfo)
312 return E_POINTER;
314 *pctinfo = 1;
316 return S_OK;
319 class CXTypeInfo : public ITypeInfo,
320 public CComObjectRoot
322 public:
323 enum class Kind { COCLASS, MAIN, OUTGOING };
325 #if defined __clang__
326 #pragma clang diagnostic push
327 #pragma clang diagnostic ignored "-Wunused-function"
328 #endif
329 BEGIN_COM_MAP(CXTypeInfo)
330 #if defined __clang__
331 #pragma clang diagnostic pop
332 #endif
333 COM_INTERFACE_ENTRY(ITypeInfo)
334 #if defined __clang__
335 #pragma clang diagnostic push
336 #pragma clang diagnostic ignored "-Winconsistent-missing-override"
337 #pragma clang diagnostic ignored "-Wunused-function"
338 #endif
339 END_COM_MAP()
340 #if defined __clang__
341 #pragma clang diagnostic pop
342 #endif
344 DECLARE_NOT_AGGREGATABLE(CXTypeInfo)
346 virtual ~CXTypeInfo() {}
348 void InitForCoclass(Reference<XInterface> xOrigin,
349 const OUString& sImplementationName,
350 const IID& rIID,
351 Reference<XMultiServiceFactory> xMSF);
352 void InitForClassItself(Reference<XInterface> xOrigin,
353 const OUString& sImplementationName,
354 const IID& rIID,
355 Reference<XMultiServiceFactory> xMSF);
356 void InitForOutgoing(Reference<XInterface> xOrigin,
357 const OUString& sInterfaceName,
358 const IID& rIID,
359 Reference<XMultiServiceFactory> xMSF,
360 Type aType);
361 virtual HRESULT STDMETHODCALLTYPE GetTypeAttr(TYPEATTR **ppTypeAttr) override;
362 virtual HRESULT STDMETHODCALLTYPE GetTypeComp(ITypeComp **ppTComp) override;
363 virtual HRESULT STDMETHODCALLTYPE GetFuncDesc(UINT index,
364 FUNCDESC **ppFuncDesc) override;
365 virtual HRESULT STDMETHODCALLTYPE GetVarDesc(UINT index,
366 VARDESC **ppVarDesc) override;
367 virtual HRESULT STDMETHODCALLTYPE GetNames(MEMBERID memid,
368 BSTR *rgBstrNames,
369 UINT cMaxNames,
370 UINT *pcNames) override;
371 virtual HRESULT STDMETHODCALLTYPE GetRefTypeOfImplType(UINT index,
372 HREFTYPE *pRefType) override;
373 virtual HRESULT STDMETHODCALLTYPE GetImplTypeFlags(UINT index,
374 INT *pImplTypeFlags) override;
375 virtual HRESULT STDMETHODCALLTYPE GetIDsOfNames(LPOLESTR *rgszNames,
376 UINT cNames,
377 MEMBERID *pMemId) override;
378 virtual HRESULT STDMETHODCALLTYPE Invoke(PVOID pvInstance,
379 MEMBERID memid,
380 WORD wFlags,
381 DISPPARAMS *pDispParams,
382 VARIANT *pVarResult,
383 EXCEPINFO *pExcepInfo,
384 UINT *puArgErr) override;
385 virtual HRESULT STDMETHODCALLTYPE GetDocumentation(MEMBERID memid,
386 BSTR *pBstrName,
387 BSTR *pBstrDocString,
388 DWORD *pdwHelpContext,
389 BSTR *pBstrHelpFile) override;
390 virtual HRESULT STDMETHODCALLTYPE GetDllEntry(MEMBERID memid,
391 INVOKEKIND invKind,
392 BSTR *pBstrDllName,
393 BSTR *pBstrName,
394 WORD *pwOrdinal) override;
395 virtual HRESULT STDMETHODCALLTYPE GetRefTypeInfo(HREFTYPE hRefType,
396 ITypeInfo **ppTInfo) override;
397 virtual HRESULT STDMETHODCALLTYPE AddressOfMember(MEMBERID memid,
398 INVOKEKIND invKind,
399 PVOID *ppv) override;
400 virtual HRESULT STDMETHODCALLTYPE CreateInstance(IUnknown *pUnkOuter,
401 REFIID riid,
402 PVOID *ppvObj) override;
403 virtual HRESULT STDMETHODCALLTYPE GetMops(MEMBERID memid,
404 BSTR *pBstrMops) override;
405 virtual HRESULT STDMETHODCALLTYPE GetContainingTypeLib(ITypeLib **ppTLib,
406 UINT *pIndex) override;
407 virtual void STDMETHODCALLTYPE ReleaseTypeAttr(TYPEATTR *pTypeAttr) override;
408 virtual void STDMETHODCALLTYPE ReleaseFuncDesc(FUNCDESC *pFuncDesc) override;
409 virtual void STDMETHODCALLTYPE ReleaseVarDesc(VARDESC *pVarDesc) override;
411 private:
412 Kind meKind;
413 Reference<XInterface> mxOrigin;
414 OUString msImplementationName;
415 OUString msInterfaceName;
416 IID maIID;
417 Reference<XMultiServiceFactory> mxMSF;
418 Type maType;
421 class CXTypeLib : public ITypeLib,
422 public CComObjectRoot
424 public:
425 #if defined __clang__
426 #pragma clang diagnostic push
427 #pragma clang diagnostic ignored "-Wunused-function"
428 #endif
429 BEGIN_COM_MAP(CXTypeLib)
430 #if defined __clang__
431 #pragma clang diagnostic pop
432 #endif
433 COM_INTERFACE_ENTRY(ITypeLib)
434 #if defined __clang__
435 #pragma clang diagnostic push
436 #pragma clang diagnostic ignored "-Winconsistent-missing-override"
437 #pragma clang diagnostic ignored "-Wunused-function"
438 #endif
439 END_COM_MAP()
440 #if defined __clang__
441 #pragma clang diagnostic pop
442 #endif
444 DECLARE_NOT_AGGREGATABLE(CXTypeLib)
446 virtual ~CXTypeLib() {}
448 void Init(Reference<XInterface> xOrigin,
449 const OUString& sImplementationName,
450 Reference<XMultiServiceFactory> xMSF)
452 SAL_INFO("extensions.olebridge", this << "@CXTypeLib::Init for " << sImplementationName);
453 mxOrigin = xOrigin;
454 msImplementationName = sImplementationName;
455 mxMSF = xMSF;
458 virtual UINT STDMETHODCALLTYPE GetTypeInfoCount() override
460 SAL_WARN("extensions.olebridge", this << "@CXTypeLib::GetTypeInfoCount");
461 return 1;
464 virtual HRESULT STDMETHODCALLTYPE GetTypeInfo(UINT,
465 ITypeInfo **) override
467 SAL_WARN("extensions.olebridge", this << "@CXTypeLib::GetTypeInfo: E_NOTIMPL");
468 return E_NOTIMPL;
471 virtual HRESULT STDMETHODCALLTYPE GetTypeInfoType(UINT,
472 TYPEKIND *) override
474 SAL_WARN("extensions.olebridge", this << "@CXTypeLib::GetTypeInfoType: E_NOTIMPL");
475 return E_NOTIMPL;
478 virtual HRESULT STDMETHODCALLTYPE GetTypeInfoOfGuid(REFGUID guid,
479 ITypeInfo **ppTInfo) override
481 comphelper::Automation::AutomationInvokedZone aAutomationActive;
483 SAL_INFO("extensions.olebridge", this << "@CXTypeLib::GetTypeInfoOfGuid(" << guid << ")");
484 if (!ppTInfo)
485 return E_POINTER;
487 Reference<ooo::vba::XConnectable> xConnectable(mxOrigin, UNO_QUERY);
488 if (!xConnectable.is())
489 return TYPE_E_ELEMENTNOTFOUND;
491 IID aIID;
492 if (SUCCEEDED(IIDFromString(reinterpret_cast<LPOLESTR>(xConnectable->getIID().pData->buffer), &aIID)))
494 if (IsEqualIID(guid, aIID))
496 HRESULT ret;
498 CComObject<CXTypeInfo>* pTypeInfo;
500 ret = CComObject<CXTypeInfo>::CreateInstance(&pTypeInfo);
501 if (FAILED(ret))
502 return ret;
504 pTypeInfo->AddRef();
506 pTypeInfo->InitForCoclass(mxOrigin, msImplementationName, aIID, mxMSF);
508 *ppTInfo = pTypeInfo;
510 return S_OK;
514 #if 0
515 ooo::vba::TypeAndIID aTypeAndIID = xConnectable->GetConnectionPoint();
517 IID aIID;
518 if (SUCCEEDED(IIDFromString((LPOLESTR)aTypeAndIID.IID.pData->buffer, &aIID)))
520 HRESULT ret;
522 CComObject<CXTypeInfo>* pTypeInfo;
524 ret = CComObject<CXTypeInfo>::CreateInstance(&pTypeInfo);
525 if (FAILED(ret))
526 return ret;
528 pTypeInfo->AddRef();
530 pTypeInfo->InitForOutgoing(mxOrigin, msImplementationName, aIID, mxMSF);
532 *ppTInfo = pTypeInfo;
534 return S_OK;
536 #else
537 SAL_WARN("extensions.olebridge", "Not implemented: GetTypeInfoOfGuid(" << guid << ")");
538 #endif
540 return TYPE_E_ELEMENTNOTFOUND;
544 virtual HRESULT STDMETHODCALLTYPE GetLibAttr(TLIBATTR **) override
546 SAL_WARN("extensions.olebridge", this << "@CXTypeLib::GetLibAttr: E_NOTIMPL");
547 return E_NOTIMPL;
550 virtual HRESULT STDMETHODCALLTYPE GetTypeComp(ITypeComp **) override
552 SAL_WARN("extensions.olebridge", this << "@CXTypeLib::GetTypeComp: E_NOTIMPL");
553 return E_NOTIMPL;
556 virtual HRESULT STDMETHODCALLTYPE GetDocumentation(INT,
557 BSTR *,
558 BSTR *,
559 DWORD *,
560 BSTR *) override
562 SAL_WARN("extensions.olebridge", this << "@CXTypeLib::GetDocumentation: E_NOTIMPL");
563 return E_NOTIMPL;
566 virtual HRESULT STDMETHODCALLTYPE IsName(LPOLESTR,
567 ULONG,
568 BOOL *) override
570 SAL_WARN("extensions.olebridge", this << "@CXTypeLib:IsName: E_NOTIMPL");
571 return E_NOTIMPL;
574 virtual HRESULT STDMETHODCALLTYPE FindName(LPOLESTR,
575 ULONG,
576 ITypeInfo **,
577 MEMBERID *,
578 USHORT *) override
580 SAL_WARN("extensions.olebridge", this << "@CXTypeLib::FindName: E_NOTIMPL");
581 return E_NOTIMPL;
584 virtual void STDMETHODCALLTYPE ReleaseTLibAttr(TLIBATTR *) override
586 SAL_WARN("extensions.olebridge", this << "@CXTypeLib::ReleaseTLibAttr: E_NOTIMPL");
589 private:
590 Reference<XInterface> mxOrigin;
591 OUString msImplementationName;
592 Reference<XMultiServiceFactory> mxMSF;
595 void CXTypeInfo::InitForCoclass(Reference<XInterface> xOrigin,
596 const OUString& sImplementationName,
597 const IID& rIID,
598 Reference<XMultiServiceFactory> xMSF)
600 SAL_INFO("extensions.olebridge", this << "@CXTypeInfo::InitForCoclass(" << sImplementationName << "," << rIID << ")");
601 meKind = Kind::COCLASS;
602 mxOrigin = xOrigin;
603 msImplementationName = sImplementationName;
604 maIID = rIID;
605 mxMSF = xMSF;
608 void CXTypeInfo::InitForClassItself(Reference<XInterface> xOrigin,
609 const OUString& sImplementationName,
610 const IID& rIID,
611 Reference<XMultiServiceFactory> xMSF)
613 SAL_INFO("extensions.olebridge", this << "@CXTypeInfo::InitForClassItself(" << sImplementationName << "," << rIID << ")");
614 meKind = Kind::MAIN;
615 mxOrigin = xOrigin;
616 msImplementationName = sImplementationName;
617 maIID = rIID;
618 mxMSF = xMSF;
621 void CXTypeInfo::InitForOutgoing(Reference<XInterface> xOrigin,
622 const OUString& sInterfaceName,
623 const IID& rIID,
624 Reference<XMultiServiceFactory> xMSF,
625 Type aType)
627 SAL_INFO("extensions.olebridge", this << "@CXTypeInfo::InitForOutgoing(" << sInterfaceName << "," << rIID << ")");
628 meKind = Kind::OUTGOING;
629 mxOrigin = xOrigin;
630 msInterfaceName = sInterfaceName;
631 maIID = rIID;
632 mxMSF = xMSF;
633 maType = aType;
636 HRESULT STDMETHODCALLTYPE CXTypeInfo::GetTypeAttr(TYPEATTR **ppTypeAttr)
638 comphelper::Automation::AutomationInvokedZone aAutomationActive;
640 SAL_INFO("extensions.olebridge", this << "@CXTypeInfo::GetTypeAttr");
642 if (!ppTypeAttr)
643 return E_POINTER;
645 assert(!IsEqualIID(maIID, IID_NULL));
647 TYPEATTR *pTypeAttr = new TYPEATTR;
648 memset(pTypeAttr, 0, sizeof(*pTypeAttr));
650 pTypeAttr->guid = maIID;
652 if (meKind == Kind::COCLASS)
654 pTypeAttr->typekind = TKIND_COCLASS;
655 pTypeAttr->cFuncs = 0;
656 pTypeAttr->cVars = 0;
657 pTypeAttr->cImplTypes = 3;
658 pTypeAttr->cbSizeVft = 0;
659 pTypeAttr->cbAlignment = 8;
660 pTypeAttr->wTypeFlags = TYPEFLAG_FCANCREATE;
662 else if (meKind == Kind::MAIN)
664 pTypeAttr->typekind = TKIND_DISPATCH;
665 pTypeAttr->cFuncs = 10; // FIXME, dummy
666 pTypeAttr->cVars = 0;
667 pTypeAttr->cImplTypes = 1;
668 // FIXME: I think this is always supposed to be as if just for the seven methods in
669 // IDIspatch?
670 pTypeAttr->cbSizeVft = 7 * sizeof(void*);
671 pTypeAttr->cbAlignment = 8;
672 pTypeAttr->wTypeFlags = TYPEFLAG_FHIDDEN|TYPEFLAG_FDISPATCHABLE;
674 else if (meKind == Kind::OUTGOING)
676 pTypeAttr->typekind = TKIND_DISPATCH;
678 Reference<XIdlReflection> xRefl = theCoreReflection::get(comphelper::getComponentContext(mxMSF));
679 assert(xRefl.is());
681 Reference<XIdlClass> xClass = xRefl->forName(maType.getTypeName());
682 assert(xClass.is());
684 auto aMethods = xClass->getMethods();
685 assert(xClass->getTypeClass() == TypeClass_INTERFACE &&
686 aMethods.getLength() > 0);
688 // Drop the three XInterface methods, add the three corresponding IUnknown ones plus the
689 // four IDispatch ones on top of that.
690 pTypeAttr->cFuncs = aMethods.getLength() - 3 + 3 + 4;
691 pTypeAttr->cVars = 0;
692 pTypeAttr->cImplTypes = 1;
693 // FIXME: I think this, too, is always supposed to be as if just for the seven methods in
694 // IDIspatch?
695 pTypeAttr->cbSizeVft = 7 * sizeof(void*);
696 pTypeAttr->cbAlignment = 8;
697 pTypeAttr->wTypeFlags = TYPEFLAG_FHIDDEN|TYPEFLAG_FNONEXTENSIBLE|TYPEFLAG_FDISPATCHABLE;
699 else
700 assert(false);
702 pTypeAttr->lcid = LOCALE_USER_DEFAULT;
703 pTypeAttr->memidConstructor = MEMBERID_NIL;
704 pTypeAttr->memidDestructor = MEMBERID_NIL;
705 // FIXME: Is this correct, just the vtable pointer, right?
706 pTypeAttr->cbSizeInstance = sizeof(void*);
707 pTypeAttr->wMajorVerNum = 0;
708 pTypeAttr->wMinorVerNum = 0;
709 pTypeAttr->idldescType.wIDLFlags = IDLFLAG_NONE;
711 SAL_INFO("extensions.olebridge", this << "@CXTypeInfo::GetTypeAttr: " << pTypeAttr);
713 *ppTypeAttr = pTypeAttr;
715 return S_OK;
718 HRESULT STDMETHODCALLTYPE CXTypeInfo::GetTypeComp(ITypeComp **)
720 SAL_WARN("extensions.olebridge", this << "@CXTypeInfo::GetTypeComp: E_NOTIMPL");
721 return E_NOTIMPL;
724 HRESULT STDMETHODCALLTYPE CXTypeInfo::GetFuncDesc(UINT index,
725 FUNCDESC **ppFuncDesc)
727 comphelper::Automation::AutomationInvokedZone aAutomationActive;
729 if (!ppFuncDesc)
730 return E_POINTER;
732 if (meKind != Kind::OUTGOING)
733 return E_NOTIMPL;
735 if (index <= 6)
737 *ppFuncDesc = new FUNCDESC;
738 (*ppFuncDesc)->memid = 0x60000000 + index;
739 (*ppFuncDesc)->lprgscode = nullptr;
740 (*ppFuncDesc)->lprgelemdescParam = nullptr;
741 (*ppFuncDesc)->funckind = FUNC_DISPATCH;
742 (*ppFuncDesc)->invkind = INVOKE_FUNC;
743 (*ppFuncDesc)->callconv = CC_STDCALL;
744 switch (index)
746 case 0: // QueryInterface
747 (*ppFuncDesc)->cParams = 2;
748 (*ppFuncDesc)->elemdescFunc.tdesc.lptdesc = nullptr;
749 (*ppFuncDesc)->elemdescFunc.tdesc.vt = VT_VOID;
750 break;
751 case 1: // AddRef
752 (*ppFuncDesc)->cParams = 0;
753 (*ppFuncDesc)->elemdescFunc.tdesc.lptdesc = nullptr;
754 (*ppFuncDesc)->elemdescFunc.tdesc.vt = VT_UI4;
755 break;
756 case 2: // Release
757 (*ppFuncDesc)->cParams = 1;
758 (*ppFuncDesc)->elemdescFunc.tdesc.lptdesc = nullptr;
759 (*ppFuncDesc)->elemdescFunc.tdesc.vt = VT_UI4;
760 break;
761 case 3: // GetTypeInfoCount
762 (*ppFuncDesc)->cParams = 1;
763 (*ppFuncDesc)->elemdescFunc.tdesc.lptdesc = nullptr;
764 (*ppFuncDesc)->elemdescFunc.tdesc.vt = VT_VOID;
765 break;
766 case 4: // GetTypeInfo
767 (*ppFuncDesc)->cParams = 3;
768 (*ppFuncDesc)->elemdescFunc.tdesc.lptdesc = nullptr;
769 (*ppFuncDesc)->elemdescFunc.tdesc.vt = VT_VOID;
770 break;
771 case 5: // GetIDsOfNames
772 (*ppFuncDesc)->cParams = 5;
773 (*ppFuncDesc)->elemdescFunc.tdesc.lptdesc = nullptr;
774 (*ppFuncDesc)->elemdescFunc.tdesc.vt = VT_VOID;
775 break;
776 case 6: // Invoke
777 (*ppFuncDesc)->cParams = 8;
778 (*ppFuncDesc)->elemdescFunc.tdesc.lptdesc = nullptr;
779 (*ppFuncDesc)->elemdescFunc.tdesc.vt = VT_VOID;
780 break;
782 (*ppFuncDesc)->cParamsOpt = 0;
783 (*ppFuncDesc)->oVft = index * sizeof(void*);
784 (*ppFuncDesc)->cScodes = 0;
785 (*ppFuncDesc)->wFuncFlags = FUNCFLAG_FRESTRICTED;
787 SAL_INFO("extensions.olebridge", this << "@CXTypeInfo::GetFuncDesc(" << index << "): S_OK: " << *ppFuncDesc);
789 return S_OK;
792 Reference<XIdlReflection> xRefl = theCoreReflection::get(comphelper::getComponentContext(mxMSF));
793 assert(xRefl.is());
795 Reference<XIdlClass> xClass = xRefl->forName(maType.getTypeName());
796 assert(xClass.is());
798 auto aMethods = xClass->getMethods();
799 assert(xClass->getTypeClass() == TypeClass_INTERFACE &&
800 aMethods.getLength() > 0);
802 if (index > static_cast<UINT>(aMethods.getLength() - 3 + 3 + 4))
803 return E_INVALIDARG;
805 *ppFuncDesc = new FUNCDESC;
807 (*ppFuncDesc)->memid = index - 6;
808 (*ppFuncDesc)->lprgscode = nullptr;
809 (*ppFuncDesc)->lprgelemdescParam = nullptr;
810 (*ppFuncDesc)->funckind = FUNC_DISPATCH;
811 (*ppFuncDesc)->invkind = INVOKE_FUNC;
812 (*ppFuncDesc)->callconv = CC_STDCALL;
813 (*ppFuncDesc)->cParams = aMethods[index - 4]->getParameterInfos().getLength();
814 (*ppFuncDesc)->cParamsOpt = 0;
815 (*ppFuncDesc)->oVft = index * sizeof(void*);
816 (*ppFuncDesc)->cScodes = 0;
817 (*ppFuncDesc)->elemdescFunc.tdesc.lptdesc = nullptr; // ???
818 (*ppFuncDesc)->elemdescFunc.tdesc.vt = VT_VOID; // ???
819 (*ppFuncDesc)->wFuncFlags = 0;
821 SAL_INFO("extensions.olebridge", this << "@CXTypeInfo::GetFuncDesc(" << index << "): S_OK: " << *ppFuncDesc);
823 return S_OK;
826 HRESULT STDMETHODCALLTYPE CXTypeInfo::GetVarDesc(UINT,
827 VARDESC **)
829 SAL_WARN("extensions.olebridge", this << "@CXTypeInfo::GetVarDesc: E_NOTIMPL");
830 return E_NOTIMPL;
833 HRESULT STDMETHODCALLTYPE CXTypeInfo::GetNames(MEMBERID memid,
834 BSTR *rgBstrNames,
835 UINT cMaxNames,
836 UINT *pcNames)
838 comphelper::Automation::AutomationInvokedZone aAutomationActive;
840 SAL_INFO("extensions.olebridge", this << "@CXTypeInfo::GetNames(" << memid << ")");
841 assert(meKind != Kind::COCLASS);
843 if (!rgBstrNames)
844 return E_POINTER;
846 if (!pcNames)
847 return E_POINTER;
849 if (memid < 1)
850 return E_INVALIDARG;
852 if (cMaxNames < 1)
853 return E_INVALIDARG;
855 if (meKind == Kind::MAIN)
857 SAL_WARN("extensions.olebridge", "GetNames() for MAIN not implemented");
858 return E_NOTIMPL;
861 Reference<XIdlReflection> xRefl = theCoreReflection::get(comphelper::getComponentContext(mxMSF));
862 assert(xRefl.is());
864 Reference<XIdlClass> xClass = xRefl->forName(maType.getTypeName());
865 assert(xClass.is());
867 auto aMethods = xClass->getMethods();
868 assert(xClass->getTypeClass() == TypeClass_INTERFACE &&
869 aMethods.getLength() > 0);
871 // Subtract the three XInterface methods. Memid for the first following method is 1.
872 if (memid > aMethods.getLength() - 3)
873 return E_INVALIDARG;
875 SAL_INFO("extensions.olebridge", "..." << this << "@CXTypeInfo::GetNames(" << memid << "): " << aMethods[memid + 2]->getName());
876 rgBstrNames[0] = SysAllocString(reinterpret_cast<LPOLESTR>(aMethods[memid + 2]->getName().pData->buffer));
877 *pcNames = 1;
879 return S_OK;
882 HRESULT STDMETHODCALLTYPE CXTypeInfo::GetRefTypeOfImplType(UINT index,
883 HREFTYPE *pRefType)
885 SAL_INFO("extensions.olebridge", this << "@CXTypeInfo::GetRefTypeOfImplType(" << index << ")");
887 if (!pRefType)
888 return E_POINTER;
890 assert(index == 0 || index == 1);
892 *pRefType = 1000+index;
894 return S_OK;
897 HRESULT STDMETHODCALLTYPE CXTypeInfo::GetImplTypeFlags(UINT index,
898 INT *pImplTypeFlags)
900 comphelper::Automation::AutomationInvokedZone aAutomationActive;
902 SAL_INFO("extensions.olebridge", this << "@CXTypeInfo::GetImplTypeFlags(" << index << ")");
904 if (!pImplTypeFlags)
905 return E_POINTER;
907 assert(meKind == Kind::COCLASS);
908 assert(index == 0 || index == 1);
910 if (index == 0)
911 *pImplTypeFlags = IMPLTYPEFLAG_FDEFAULT;
912 else if (index == 1)
913 *pImplTypeFlags = IMPLTYPEFLAG_FDEFAULT|IMPLTYPEFLAG_FSOURCE;
915 return S_OK;
918 HRESULT STDMETHODCALLTYPE CXTypeInfo::GetIDsOfNames(LPOLESTR *,
919 UINT,
920 MEMBERID *)
922 SAL_WARN("extensions.olebridge", this << "@CXTypeInfo::GetIDsOfNames: E_NOTIMPL");
923 return E_NOTIMPL;
926 HRESULT STDMETHODCALLTYPE CXTypeInfo::Invoke(PVOID,
927 MEMBERID,
928 WORD,
929 DISPPARAMS *,
930 VARIANT *,
931 EXCEPINFO *,
932 UINT *)
934 SAL_WARN("extensions.olebridge", this << "@CXTypeInfo::Invoke: E_NOTIMPL");
935 return E_NOTIMPL;
938 HRESULT STDMETHODCALLTYPE CXTypeInfo::GetDocumentation(MEMBERID memid,
939 BSTR *pBstrName,
940 BSTR *pBstrDocString,
941 DWORD *pdwHelpContext,
942 BSTR *pBstrHelpFile)
944 comphelper::Automation::AutomationInvokedZone aAutomationActive;
946 SAL_INFO("extensions.olebridge", this << "@CXTypeInfo::GetDocumentation(" << memid << ")");
948 if (pBstrName)
950 if (memid == MEMBERID_NIL)
952 *pBstrName = SysAllocString(o3tl::toW(msImplementationName.getStr()));
954 else if (memid == DISPID_VALUE)
956 // MEMBERIDs are the same as DISPIDs, apparently?
957 *pBstrName = SysAllocString(L"Value");
959 else
961 // FIXME: Shouldn't we be able to know the names of the members of UNO interfaces?
962 *pBstrName = SysAllocString(o3tl::toW(OUString("UnknownNameOfMember#" + OUString::number(memid)).getStr()));
965 if (pBstrDocString)
966 *pBstrDocString = SysAllocString(L"");
967 if (pdwHelpContext)
968 *pdwHelpContext = 0;
969 if (pBstrHelpFile)
970 *pBstrHelpFile = nullptr;
972 return S_OK;
975 HRESULT STDMETHODCALLTYPE CXTypeInfo::GetDllEntry(MEMBERID,
976 INVOKEKIND,
977 BSTR *,
978 BSTR *,
979 WORD *)
981 SAL_WARN("extensions.olebridge", this << "@CXTypeInfo::GetDllEntry: E_NOTIMPL");
982 return E_NOTIMPL;
985 HRESULT STDMETHODCALLTYPE CXTypeInfo::GetRefTypeInfo(HREFTYPE hRefType,
986 ITypeInfo **ppTInfo)
988 comphelper::Automation::AutomationInvokedZone aAutomationActive;
990 SAL_INFO("extensions.olebridge", this << "@CXTypeInfo::GetRefTypeInfo(" << hRefType << ")");
992 if (!ppTInfo)
993 return E_POINTER;
995 // FIXME: Is it correct to assume that the only interfaces on which GetRefTypeInfo() would be
996 // called are those that implement ooo::vba::XConnectable?
998 Reference<ooo::vba::XConnectable> xConnectable(mxOrigin, UNO_QUERY);
999 if (!xConnectable.is())
1000 return E_NOTIMPL;
1002 ooo::vba::TypeAndIID aTypeAndIID = xConnectable->GetConnectionPoint();
1004 IID aIID;
1005 if (!SUCCEEDED(IIDFromString(reinterpret_cast<LPOLESTR>(aTypeAndIID.IID.pData->buffer), &aIID)))
1006 return E_NOTIMPL;
1008 HRESULT ret;
1010 CComObject<CXTypeInfo>* pTypeInfo;
1012 ret = CComObject<CXTypeInfo>::CreateInstance(&pTypeInfo);
1013 if (FAILED(ret))
1014 return ret;
1016 pTypeInfo->AddRef();
1018 pTypeInfo->InitForOutgoing(mxOrigin, aTypeAndIID.Type.getTypeName(), aIID, mxMSF, aTypeAndIID.Type);
1020 *ppTInfo = pTypeInfo;
1022 return S_OK;
1025 HRESULT STDMETHODCALLTYPE CXTypeInfo::AddressOfMember(MEMBERID,
1026 INVOKEKIND,
1027 PVOID *)
1029 SAL_WARN("extensions.olebridge", this << "@CXTypeInfo::AddressOfMember: E_NOTIMPL");
1030 return E_NOTIMPL;
1033 HRESULT STDMETHODCALLTYPE CXTypeInfo::CreateInstance(IUnknown *,
1034 REFIID,
1035 PVOID *)
1037 SAL_WARN("extensions.olebridge", this << "@CXTypeInfo::CreateInstance: E_NOTIMPL");
1038 return E_NOTIMPL;
1041 HRESULT STDMETHODCALLTYPE CXTypeInfo::GetMops(MEMBERID,
1042 BSTR *)
1044 SAL_WARN("extensions.olebridge", this << "@CXTypeInfo::GetMops: E_NOTIMPL");
1045 return E_NOTIMPL;
1048 // This is not actually called any more by my vbscript test after I added the IProvideClassInfo
1049 // thing... so all the CXTypeLib stuff is dead code at the moment.
1051 HRESULT STDMETHODCALLTYPE CXTypeInfo::GetContainingTypeLib(ITypeLib **ppTLib,
1052 UINT *pIndex)
1054 comphelper::Automation::AutomationInvokedZone aAutomationActive;
1056 SAL_INFO("extensions.olebridge", this << "@CXTypeInfo::GetContainingTypeLib");
1058 if (!ppTLib || !pIndex)
1059 return E_POINTER;
1061 HRESULT ret;
1063 CComObject<CXTypeLib>* pTypeLib;
1065 ret = CComObject<CXTypeLib>::CreateInstance(&pTypeLib);
1066 if (FAILED(ret))
1067 return ret;
1069 pTypeLib->AddRef();
1071 pTypeLib->Init(mxOrigin, msImplementationName, mxMSF);
1073 *ppTLib = pTypeLib;
1075 return S_OK;
1078 void STDMETHODCALLTYPE CXTypeInfo::ReleaseTypeAttr(TYPEATTR *pTypeAttr)
1080 SAL_INFO("extensions.olebridge", this << "@CXTypeInfo::ReleaseTypeAttr(" << pTypeAttr << ")");
1082 delete pTypeAttr;
1085 void STDMETHODCALLTYPE CXTypeInfo::ReleaseFuncDesc(FUNCDESC *pFuncDesc)
1087 SAL_WARN("extensions.olebridge", this << "@CXTypeInfo::ReleaseFuncDesc(" << pFuncDesc << ")");
1089 delete pFuncDesc;
1092 void STDMETHODCALLTYPE CXTypeInfo::ReleaseVarDesc(VARDESC *)
1094 SAL_WARN("extensions.olebridge", this << "@CXTypeInfo::ReleaseVarDesc: E_NOTIMPL");
1097 COM_DECLSPEC_NOTHROW STDMETHODIMP InterfaceOleWrapper::GetTypeInfo(UINT iTInfo, LCID, ITypeInfo ** ppTInfo)
1099 comphelper::Automation::AutomationInvokedZone aAutomationActive;
1101 SAL_INFO("extensions.olebridge", this << "@InterfaceOleWrapper::GetTypeInfo(" << iTInfo << ")");
1103 if (!ppTInfo)
1104 return E_POINTER;
1106 if (iTInfo != 0)
1107 return E_NOTIMPL;
1109 // FIXME: This is surely incorrect. Why is being able to handle GetTypeInfo() here coupled to
1110 // being a source for outgoing events, i.e. implementing XConnectable? What would break if we
1111 // would use XInterfaceWithIID and its getIID instead?
1113 Reference<ooo::vba::XConnectable> xConnectable(m_xOrigin, UNO_QUERY);
1114 if (!xConnectable.is())
1115 return E_NOTIMPL;
1117 OUString sIID = xConnectable->GetIIDForClassItselfNotCoclass();
1118 IID aIID;
1119 if (!SUCCEEDED(IIDFromString(reinterpret_cast<LPOLESTR>(sIID.pData->buffer), &aIID)))
1120 return E_NOTIMPL;
1122 HRESULT ret;
1124 CComObject<CXTypeInfo>* pTypeInfo;
1126 ret = CComObject<CXTypeInfo>::CreateInstance(&pTypeInfo);
1127 if (FAILED(ret))
1128 return ret;
1130 pTypeInfo->AddRef();
1132 pTypeInfo->InitForClassItself(m_xOrigin, m_sImplementationName, aIID, m_smgr);
1134 *ppTInfo = pTypeInfo;
1136 return S_OK;
1139 COM_DECLSPEC_NOTHROW STDMETHODIMP InterfaceOleWrapper::GetIDsOfNames(REFIID /*riid*/,
1140 LPOLESTR * rgszNames,
1141 UINT cNames,
1142 LCID /*lcid*/,
1143 DISPID * rgdispid )
1145 comphelper::Automation::AutomationInvokedZone aAutomationActive;
1147 if( ! rgdispid)
1148 return E_POINTER;
1150 SAL_INFO("extensions.olebridge", this << "@InterfaceOleWrapper::GetIDsOfNames:");
1151 for (unsigned int i = 0; i < cNames; ++i)
1153 // Initialise returned rgdispid values.
1154 rgdispid[i] = DISPID_UNKNOWN;
1156 SAL_INFO("extensions.olebridge", " " << o3tl::toU(rgszNames[i]));
1159 HRESULT ret = DISP_E_UNKNOWNNAME;
1162 MutexGuard guard( getBridgeMutex());
1164 // FIXME: Handle the cNames > 1 case? Note that the rest of the names mean the names of *arguments*.
1166 if( ! _wcsicmp( *rgszNames, JSCRIPT_VALUE_FUNC) ||
1167 ! _wcsicmp( *rgszNames, BRIDGE_VALUE_FUNC))
1169 *rgdispid= DISPID_JSCRIPT_VALUE_FUNC;
1170 return S_OK;
1172 else if( ! _wcsicmp( *rgszNames, GET_STRUCT_FUNC) ||
1173 ! _wcsicmp( *rgszNames, BRIDGE_GET_STRUCT_FUNC))
1175 *rgdispid= DISPID_GET_STRUCT_FUNC;
1176 return S_OK;
1178 else if( ! _wcsicmp( *rgszNames, BRIDGE_CREATE_TYPE_FUNC))
1180 *rgdispid= DISPID_CREATE_TYPE_FUNC;
1181 return S_OK;
1184 if (m_xInvocation.is() && (cNames > 0))
1186 OUString name(o3tl::toU(rgszNames[0]));
1187 NameToIdMap::iterator iter = m_nameToDispIdMap.find(name);
1189 bool bIsMethod = false;
1191 OUString exactName = name;
1193 if (iter == m_nameToDispIdMap.end())
1195 if (m_xExactName.is())
1197 exactName = m_xExactName->getExactName(name);
1198 if (exactName.isEmpty())
1199 exactName = name;
1202 MemberInfo d(0, exactName);
1204 if (m_xInvocation->hasProperty(exactName))
1206 d.flags |= DISPATCH_PROPERTYGET;
1207 d.flags |= DISPATCH_PROPERTYPUT;
1208 d.flags |= DISPATCH_PROPERTYPUTREF;
1211 if (m_xInvocation->hasMethod(exactName))
1213 d.flags |= DISPATCH_METHOD;
1214 bIsMethod = true;
1217 if (d.flags != 0)
1219 m_MemberInfos.push_back(d);
1220 iter = m_nameToDispIdMap.emplace(exactName, static_cast<DISPID>(m_MemberInfos.size())).first;
1222 if (exactName != name)
1224 iter = m_nameToDispIdMap.emplace(name, static_cast<DISPID>(m_MemberInfos.size())).first;
1229 if (iter == m_nameToDispIdMap.end())
1231 ret = DISP_E_UNKNOWNNAME;
1232 SAL_INFO("extensions.olebridge", " " << name << ": UNKNOWN");
1234 else
1236 rgdispid[0] = (*iter).second;
1237 SAL_INFO("extensions.olebridge", " " << name << ": " << rgdispid[0]);
1239 if (bIsMethod && cNames > 1)
1241 Reference<XIdlMethod> xIdlMethod;
1242 Reference<XIntrospectionAccess> xIntrospectionAccess = m_xInvocation->getIntrospection();
1245 if (xIntrospectionAccess.is())
1246 xIdlMethod = xIntrospectionAccess->getMethod(exactName, MethodConcept::ALL);
1248 catch (const NoSuchMethodException&)
1251 if (xIdlMethod.is())
1253 auto aParamInfos = xIdlMethod->getParameterInfos();
1254 for (unsigned int i = 1; i < cNames; ++i)
1256 bool bFound = false;
1257 for (int j = 0; j < aParamInfos.getLength(); ++j)
1259 if (aParamInfos[j].aName.equalsIgnoreAsciiCase(OUString(o3tl::toU(rgszNames[i]))))
1261 rgdispid[i] = j;
1262 bFound = true;
1263 SAL_INFO("extensions.olebridge", " " << OUString(o3tl::toU(rgszNames[i])) << ": " << rgdispid[i]);
1264 break;
1267 if (!bFound)
1268 SAL_INFO("extensions.olebridge", " " << OUString(o3tl::toU(rgszNames[i])) << ": NOT FOUND");
1273 // Return value should be S_OK only if *all* the names were found.
1274 unsigned int i;
1275 for (i = 0; i < cNames; ++i)
1276 if (rgdispid[i] == DISPID_UNKNOWN)
1277 break;
1278 if (i == cNames)
1279 ret = S_OK;
1283 catch(const BridgeRuntimeError&)
1285 OSL_ASSERT(false);
1287 catch(const Exception&)
1289 OSL_ASSERT(false);
1291 catch(...)
1293 OSL_ASSERT(false);
1296 return ret;
1299 // Note: What the comments here say about JScript possibly holds for Automation clients in general,
1300 // like VBScript ones, too. Or not. Hard to say. What is the relevance of JScript nowadays anyway,
1301 // and can LO really be used from JScript code on web pages any longer?
1303 // "convertDispparamsArgs" converts VARIANTS to their respecting Any counterparts
1304 // The parameters "id", "wFlags" and "pdispparams" equal those as used in
1305 // IDispatch::Invoke. The function handles special JavaScript
1306 // cases where a VARIANT of type VT_DISPATCH is ambiguous and could represent
1307 // an object, array ( JavaScript Array object), out parameter and in/out ( JavaScript Array object)
1308 // parameter (JavaScript Array object)
1309 // Because all those VT_DISPATCH objects need a different conversion
1310 // we have to find out what the object is supposed to be. The function does this
1311 // by either using type information or by help of a specialized ValueObject object.
1313 // A. Type Information
1315 // With the help of type information the kind of parameter can be exactly determined
1316 // and an appropriate conversion can be chosen. A problem arises if a method expects
1317 // an Any. Then the type info does not tell what the type of the value, that is kept
1318 // by the any, should be. In this situation the decision whether the param is a
1319 // sequence or an object is made upon the fact if the object has a property "0"
1320 // ( see function "isJScriptArray"). Since this is unsafe it is recommended to use
1321 // the JScript value objects within a JScript script on such an occasion.
1323 // B. JavaScript Value Object ( class JScriptValue )
1325 // A JScriptValue (ValueObject) object is a COM object in that it implements IDispatch and the
1326 // IJScriptValue object interface. Such objects are provided by all UNO wrapper
1327 // objects used within a JScript script. To obtain an instance one has to call
1328 // "_GetValueObject() or Bridge_GetValueObject()" on a UNO wrapper object (class InterfaceOleWrapper).
1329 // A value object is appropriately initialized within the script and passed as
1330 // parameter to a UNO object method or property. The convertDispparamsArgs function
1331 // can easily find out that a param is such an object by querying for the
1332 // IJScriptValue interface. By this interface one the type and kind ( out, in/out)
1333 // can be determined and the right conversion can be applied.
1334 // Using ValueObjects we spare us the effort of acquiring and examining type information
1335 // in order to figure out what the an IDispatch parameter is meant for.
1337 // Normal JScript object parameter can be mixed with JScriptValue object. If an
1338 // VARIANT contains a VT_DISPATCH that is no JScriptValue than the type information
1339 // is used to find out about the required type.
1340 void InterfaceOleWrapper::convertDispparamsArgs(DISPID id,
1341 unsigned short /*wFlags*/, DISPPARAMS* pdispparams, Sequence<Any>& rSeq)
1343 // Parameters come in in reverse order in pdispparams. There might be less parameters than
1344 // expected. In that case, assume they are "optional" (but can't be marked as such in UNO IDL),
1345 // and fill in the rest with empty Anys. There might also be more than expected. In that case,
1346 // assume the oovbaapi UNO IDL hasn't kept up with added optional parameters in MSO, and just
1347 // ignore the extra ones, as long as they are empty.
1349 // An example: incoming parameters: <12, 13, "foo/bar.tem">
1351 // Expected parameters: (string filename, int something, int somethingElse, Any whatever, Any
1352 // whateverElse)
1354 // Here the existing incoming parameters are placed in reverse order in the first three outgoing
1355 // parameters, and the rest of the outgoing parameters are kept as empty Anys.
1357 // Another example: incoming parameters: <EMPTY, TRUE>
1359 // Expected parameters: (bool flag)
1361 // Here the TRUE is passed as the sole outgoing parameter, and the incoming EMPTY is ignored.
1363 // Still an example: incoming parameters: <"foo.doc", TRUE>
1365 // Expected parameters: (bool flag)
1367 // This throws an error as the incoming string parameter presumably should do something important,
1368 // but there is no corresponding outgoing parameter.
1370 HRESULT hr = S_OK;
1371 const int countIncomingArgs = pdispparams->cArgs;
1373 //Get type information for the current call
1374 InvocationInfo info;
1375 if( ! getInvocationInfoForCall( id, info))
1376 throw BridgeRuntimeError(
1377 "[automation bridge]InterfaceOleWrapper::convertDispparamsArgs \n"
1378 "Could not obtain type information for current call.");
1380 // Size rSeq according to the number of expected parameters.
1381 const int expectedArgs = info.aParamTypes.getLength() + (info.eMemberType == MemberType_PROPERTY ? 1 : 0);
1382 rSeq.realloc( expectedArgs );
1383 Any* pParams = rSeq.getArray();
1385 Any anyParam;
1387 int outgoingArgIndex = 0;
1389 // Go through incoming parameters in reverse order, i.e. in the order as declared in IDL
1390 for (int i = std::max(countIncomingArgs, expectedArgs) - 1; i >= 0; i--)
1392 // Ignore too many parameters if they are VT_EMPTY anyway
1393 if ( outgoingArgIndex >= expectedArgs && pdispparams->rgvarg[i].vt == VT_EMPTY )
1394 continue;
1396 // But otherwise too many parameters is an error
1397 if ( outgoingArgIndex >= expectedArgs )
1398 throw BridgeRuntimeError( "[automation bridge] Too many parameters" );
1400 if (info.eMemberType == MemberType_METHOD &&
1401 info.aParamModes[ outgoingArgIndex ] == ParamMode_OUT)
1403 outgoingArgIndex++;
1404 continue;
1407 if (i < countIncomingArgs)
1409 // A missing (and hopefully optional) arg (in the middle of the argument list) is passed
1410 // as an empty Any.
1411 if (pdispparams->rgvarg[i].vt == VT_ERROR && pdispparams->rgvarg[i].scode == DISP_E_PARAMNOTFOUND)
1413 Any aEmpty;
1414 pParams[ outgoingArgIndex ] = aEmpty;
1415 outgoingArgIndex++;
1416 continue;
1419 if(convertValueObject( & pdispparams->rgvarg[i], anyParam))
1420 { //a param is a ValueObject and could be converted
1421 pParams[ outgoingArgIndex ] = anyParam;
1422 outgoingArgIndex++;
1423 continue;
1426 else
1428 // A missing arg. Let's hope it is de facto optional (there is no way in UNO IDL to mark
1429 // a parameter as optional). The corresponding slot in pParams is already a void Any.
1430 // Here we don't increase outgoingArgIndex!
1431 continue;
1434 // If the param is an out, in/out parameter in
1435 // JScript (Array object, with value at index 0) then we
1436 // extract Array[0] and put the value into varParam. At the end of the loop varParam
1437 // is converted if it contains a value otherwise the VARIANT from
1438 // DISPPARAMS is converted.
1439 CComVariant varParam;
1441 // Check for JScript out and in/out paramsobjects (VT_DISPATCH).
1442 // To find them out we use typeinformation of the function being called.
1444 // No idea how this stuff, originally written for JScript, works for other Automation
1445 // clients.
1447 if( pdispparams->rgvarg[i].vt == VT_DISPATCH )
1449 if( info.eMemberType == MemberType_METHOD && info.aParamModes[ outgoingArgIndex ] == ParamMode_INOUT)
1451 // INOUT-param
1452 // Index ( property) "0" contains the actual IN-param. The object is a JScript
1453 // Array object.
1454 // Get the IN-param at index "0"
1455 IDispatch* pdisp= pdispparams->rgvarg[i].pdispVal;
1457 OLECHAR const * sindex= L"0";
1458 DISPID id2;
1459 DISPPARAMS noParams= {nullptr,nullptr,0,0};
1460 if(SUCCEEDED( hr= pdisp->GetIDsOfNames( IID_NULL, const_cast<OLECHAR **>(&sindex), 1, LOCALE_USER_DEFAULT, &id2)))
1461 hr= pdisp->Invoke( id2, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET,
1462 & noParams, & varParam, nullptr, nullptr);
1463 if( FAILED( hr))
1465 throw BridgeRuntimeError(
1466 "[automation bridge] Could not determine "
1467 "if the object has a member \"0\". Error: " +
1468 OUString::number(hr));
1473 if( varParam.vt == VT_EMPTY) // then it was no in/out parameter
1474 varParam= pdispparams->rgvarg[i];
1476 if(info.eMemberType == MemberType_METHOD)
1477 variantToAny( & varParam, anyParam,
1478 info.aParamTypes[ outgoingArgIndex ]);
1479 else if(info.eMemberType == MemberType_PROPERTY)
1480 variantToAny( & varParam, anyParam, info.aType);
1481 else
1482 OSL_ASSERT(false);
1484 if (outgoingArgIndex < expectedArgs)
1485 pParams[ outgoingArgIndex ]= anyParam;
1486 outgoingArgIndex++;
1487 }// end for / iterating over all parameters
1490 bool InterfaceOleWrapper::getInvocationInfoForCall( DISPID id, InvocationInfo& info)
1492 bool bTypesAvailable= false;
1494 if( !m_xInvocation.is() )return false;
1495 Reference<XInvocation2> inv2( m_xInvocation, UNO_QUERY);
1496 if( inv2.is())
1498 // We need the name of the property or method to get its type information.
1499 // The name can be identified through the param "id"
1500 // that is kept as value in the map m_nameToDispIdMap.
1501 // Problem: the Windows JScript engine sometimes changes small letters to capital
1502 // letters as happens in xidlclass_obj.createObject( var) // in JScript.
1503 // IDispatch::GetIdsOfNames is then called with "CreateObject" !!!
1504 // m_nameToDispIdMap can contain several names for one DISPID but only one is
1505 // the exact one. If there's no m_xExactName and therefore no exact name then
1506 // there's only one entry in the map.
1507 OUString sMemberName;
1509 auto ci1 = std::find_if(m_nameToDispIdMap.cbegin(), m_nameToDispIdMap.cend(),
1510 [&id](const NameToIdMap::value_type& nameToDispId) { return nameToDispId.second == id; }); // item is a pair<OUString, DISPID>
1511 if (ci1 != m_nameToDispIdMap.cend())
1512 sMemberName= (*ci1).first;
1513 // Get information for the current call ( property or method).
1514 // There could be similar names which only differ in the cases
1515 // of letters. First we assume that the name which was passed into
1516 // GetIDsOfNames is correct. If we won't get information with that
1517 // name then we have the invocation service use the XExactName interface.
1518 bool validInfo= true;
1519 InvocationInfo invInfo;
1520 try{
1521 invInfo= inv2->getInfoForName( sMemberName, false);
1523 catch(const IllegalArgumentException&)
1525 validInfo= false;
1528 if( ! validInfo)
1530 invInfo= inv2->getInfoForName( sMemberName, true);
1532 if( invInfo.aName.pData)
1534 bTypesAvailable= true;
1535 info= invInfo;
1538 return bTypesAvailable;
1541 // XBridgeSupplier2 ---------------------------------------------------
1542 // only bridges itself ( this instance of InterfaceOleWrapper)from UNO to IDispatch
1543 // If sourceModelType is UNO than any UNO interface implemented by InterfaceOleWrapper
1544 // can bridged to IDispatch ( if destModelType == OLE). The IDispatch is
1545 // implemented by this class.
1546 Any SAL_CALL InterfaceOleWrapper::createBridge(const Any& modelDepObject,
1547 const Sequence<sal_Int8>& /*ProcessId*/,
1548 sal_Int16 sourceModelType,
1549 sal_Int16 destModelType)
1552 Any retAny;
1553 if( sourceModelType == UNO && destModelType == OLE &&
1554 modelDepObject.getValueTypeClass() == TypeClass_INTERFACE )
1556 Reference<XInterface> xInt;
1557 if( modelDepObject >>= xInt )
1559 if( xInt == Reference<XInterface>( static_cast<XWeak*>( this), UNO_QUERY))
1561 VARIANT *pVar= static_cast<VARIANT*>(CoTaskMemAlloc( sizeof( VARIANT)));
1562 if( pVar)
1564 pVar->vt= VT_DISPATCH;
1565 pVar->pdispVal= static_cast<IDispatch*>( this);
1566 AddRef();
1568 retAny<<= reinterpret_cast< sal_uIntPtr >( pVar);
1574 return retAny;
1577 // XInitialization --------------------------------------------------
1578 void SAL_CALL InterfaceOleWrapper::initialize( const Sequence< Any >& aArguments )
1580 switch( aArguments.getLength() )
1582 case 2: // the object wraps a UNO struct
1583 aArguments[0] >>= m_xInvocation;
1584 aArguments[1] >>= m_defaultValueType;
1585 break;
1586 case 3: // the object wraps a UNO interface
1587 aArguments[0] >>= m_xInvocation;
1588 aArguments[1] >>= m_xOrigin;
1589 aArguments[2] >>= m_defaultValueType;
1591 Reference<XServiceInfo> xServiceInfo(m_xOrigin, UNO_QUERY);
1592 if (xServiceInfo.is())
1593 m_sImplementationName = xServiceInfo->getImplementationName();
1595 SAL_INFO("extensions.olebridge", this << "@InterfaceOleWrapper::initialize for "
1596 << (m_sImplementationName.isEmpty()?"an unknown implementation":m_sImplementationName));
1597 break;
1600 m_xExactName.set( m_xInvocation, UNO_QUERY);
1603 Reference< XInterface > InterfaceOleWrapper::createUnoWrapperInstance()
1605 Reference<XWeak> xWeak= static_cast<XWeak*>( new InterfaceOleWrapper(
1606 m_smgr, m_nUnoWrapperClass, m_nComWrapperClass));
1607 return Reference<XInterface>( xWeak, UNO_QUERY);
1610 Reference<XInterface> InterfaceOleWrapper::createComWrapperInstance()
1612 Reference<XWeak> xWeak= static_cast<XWeak*>( new IUnknownWrapper(
1613 m_smgr, m_nUnoWrapperClass, m_nComWrapperClass));
1614 return Reference<XInterface>( xWeak, UNO_QUERY);
1617 // "getType" is used in convertValueObject to map the string denoting the type
1618 // to an actual Type object.
1619 bool getType( const BSTR name, Type & type)
1621 bool ret = false;
1622 typelib_TypeDescription * pDesc= nullptr;
1623 OUString str(o3tl::toU(name));
1624 typelib_typedescription_getByName( &pDesc, str.pData );
1625 if( pDesc)
1627 type = Type( pDesc->pWeakRef );
1628 typelib_typedescription_release( pDesc);
1629 ret = true;
1631 return ret;
1634 static bool writeBackOutParameter2( VARIANTARG* pDest, VARIANT* pSource)
1636 bool ret = false;
1637 HRESULT hr;
1639 // Handle JScriptValue objects and JScript out params ( Array object )
1640 CComVariant varDest( *pDest);
1642 if( SUCCEEDED( varDest.ChangeType(VT_DISPATCH)))
1644 CComPtr<IDispatch> spDispDest(varDest.pdispVal);
1646 // special Handling for a JScriptValue object
1647 CComQIPtr<IJScriptValueObject> spValueDest(spDispDest);
1648 if (spValueDest)
1650 VARIANT_BOOL varBool= VARIANT_FALSE;
1651 if ((SUCCEEDED(hr = spValueDest->IsOutParam(&varBool))
1652 && varBool == VARIANT_TRUE)
1653 || (SUCCEEDED(hr = spValueDest->IsInOutParam(&varBool))
1654 && varBool == VARIANT_TRUE))
1656 if( SUCCEEDED( spValueDest->Set( CComVariant(), *pSource)))
1657 ret= true;
1660 else if (pDest->vt == VT_DISPATCH)// VT_DISPATCH -> JScript out param
1662 // We use IDispatchEx because its GetDispID function causes the creation
1663 // of a property if it does not exist already. This is convenient for
1664 // out parameters in JScript. Then the user must not specify property "0"
1665 // explicitly
1666 CComQIPtr<IDispatchEx> spDispEx( spDispDest);
1667 if( spDispEx)
1669 CComBSTR nullProp(L"0");
1670 DISPID dwDispID;
1671 if( SUCCEEDED( spDispEx->GetDispID( nullProp, fdexNameEnsure, &dwDispID)))
1673 DISPPARAMS dispparams = {nullptr, nullptr, 1, 1};
1674 dispparams.rgvarg = pSource;
1675 DISPID dispidPut = DISPID_PROPERTYPUT;
1676 dispparams.rgdispidNamedArgs = &dispidPut;
1678 if (pSource->vt == VT_UNKNOWN || pSource->vt == VT_DISPATCH ||
1679 (pSource->vt & VT_ARRAY) || (pSource->vt & VT_BYREF))
1680 hr = spDispEx->InvokeEx(dwDispID, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYPUTREF,
1681 &dispparams, nullptr, nullptr, nullptr);
1682 else
1683 hr= spDispEx->InvokeEx(dwDispID, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYPUT,
1684 &dispparams, nullptr, nullptr, nullptr);
1685 if( SUCCEEDED(hr))
1686 ret= true;
1690 else
1691 ret= writeBackOutParameter( pDest, pSource);
1693 else // The param can't be a JScript out-parameter ( an Array object), it could be a VBScript
1694 { // param. The function checks itself for correct VBScript params
1695 ret= writeBackOutParameter( pDest, pSource);
1697 return ret;
1700 // VisualBasic Script passes arguments as VT_VARIANT | VT_BYREF be it in or out parameter.
1701 // Thus we are in charge of freeing an eventual value contained by the inner VARIANT
1702 // Please note: VariantCopy doesn't free a VT_BYREF value
1703 // The out parameters are expected to have always a valid type
1704 static bool writeBackOutParameter(VARIANTARG* pDest, VARIANT* pSource)
1706 HRESULT hr;
1707 bool ret = false;
1708 // Out parameter must be VT_BYREF
1709 if ((V_VT(pDest) & VT_BYREF) != 0 )
1711 VARTYPE oleTypeFlags = V_VT(pSource);
1713 // if caller accept VARIANT as out parameter, any value must be converted
1714 if (V_VT(pDest) == (VT_VARIANT | VT_BYREF))
1716 // When the user provides a VARIANT rather than a concrete type
1717 // we just copy the source to the out, in/out parameter
1718 // VT_DISPATCH, VT_UNKNOWN, VT_ARRAY, VT_BSTR in the VARIANT that
1719 // is contained in pDest are released by VariantCopy
1720 VariantCopy(V_VARIANTREF(pDest), pSource);
1721 ret = true;
1723 else
1725 // variantarg and variant must have same type
1726 if ((V_VT(pDest) & oleTypeFlags) == oleTypeFlags)
1728 if ((oleTypeFlags & VT_ARRAY) != 0)
1730 // In / Out Param
1731 if( *V_ARRAYREF(pDest) != nullptr)
1732 hr= SafeArrayCopyData( V_ARRAY(pSource), *V_ARRAYREF(pDest));
1733 else
1734 // Out Param
1735 hr= SafeArrayCopy(V_ARRAY(pSource), V_ARRAYREF(pDest));
1736 if( SUCCEEDED( hr))
1737 ret = true;
1739 else
1741 // copy base type
1742 switch (V_VT(pSource))
1744 case VT_I2:
1746 *V_I2REF(pDest) = V_I2(pSource);
1747 ret = true;
1748 break;
1750 case VT_I4:
1751 *V_I4REF(pDest) = V_I4(pSource);
1752 ret = true;
1753 break;
1754 case VT_R4:
1755 *V_R4REF(pDest) = V_R4(pSource);
1756 ret = true;
1757 break;
1758 case VT_R8:
1759 *V_R8REF(pDest) = V_R8(pSource);
1760 ret = true;
1761 break;
1762 case VT_CY:
1763 *V_CYREF(pDest) = V_CY(pSource);
1764 ret = true;
1765 break;
1766 case VT_DATE:
1767 *V_DATEREF(pDest) = V_DATE(pSource);
1768 ret = true;
1769 break;
1770 case VT_BSTR:
1771 SysFreeString( *pDest->pbstrVal);
1773 *V_BSTRREF(pDest) = SysAllocString(V_BSTR(pSource));
1774 ret = true;
1775 break;
1776 case VT_DISPATCH:
1777 if (*V_DISPATCHREF(pDest) != nullptr)
1778 (*V_DISPATCHREF(pDest))->Release();
1780 *V_DISPATCHREF(pDest) = V_DISPATCH(pSource);
1782 if (*V_DISPATCHREF(pDest) != nullptr)
1783 (*V_DISPATCHREF(pDest))->AddRef();
1785 ret = true;
1786 break;
1787 case VT_ERROR:
1788 *V_ERRORREF(pDest) = V_ERROR(pSource);
1789 ret = true;
1790 break;
1791 case VT_BOOL:
1792 *V_BOOLREF(pDest) = V_BOOL(pSource);
1793 ret = true;
1794 break;
1795 case VT_UNKNOWN:
1796 if (*V_UNKNOWNREF(pDest) != nullptr)
1797 (*V_UNKNOWNREF(pDest))->Release();
1799 *V_UNKNOWNREF(pDest) = V_UNKNOWN(pSource);
1801 if (*V_UNKNOWNREF(pDest) != nullptr)
1802 (*V_UNKNOWNREF(pDest))->AddRef();
1804 ret = true;
1805 break;
1806 case VT_I1:
1807 *V_I1REF(pDest) = V_I1(pSource);
1808 ret = true;
1809 break;
1810 case VT_UI1:
1811 *V_UI1REF(pDest) = V_UI1(pSource);
1812 ret = true;
1813 break;
1814 case VT_UI2:
1815 *V_UI2REF(pDest) = V_UI2(pSource);
1816 ret = true;
1817 break;
1818 case VT_UI4:
1819 *V_UI4REF(pDest) = V_UI4(pSource);
1820 ret = true;
1821 break;
1822 case VT_INT:
1823 *V_INTREF(pDest) = V_INT(pSource);
1824 ret = true;
1825 break;
1826 case VT_UINT:
1827 *V_UINTREF(pDest) = V_UINT(pSource);
1828 ret = true;
1829 break;
1830 case VT_DECIMAL:
1831 memcpy(pDest->pdecVal, pSource, sizeof(DECIMAL));
1832 ret = true;
1833 break;
1834 default:
1835 break;
1839 else
1841 // Handling of special cases
1842 // Destination and source types are different
1843 if( pDest->vt == (VT_BSTR | VT_BYREF)
1844 && pSource->vt == VT_I2)
1846 // When the user provides a String as out our in/out parameter
1847 // and the type is char (TypeClass_CHAR) then we convert to a BSTR
1848 // instead of VT_I2 as is done otherwise
1849 OLECHAR buff[]= {0,0};
1850 buff[0]= pSource->iVal;
1852 SysFreeString( *pDest->pbstrVal);
1853 *pDest->pbstrVal= SysAllocString( buff);
1854 ret = true;
1859 return ret;
1862 COM_DECLSPEC_NOTHROW STDMETHODIMP InterfaceOleWrapper::Invoke(DISPID dispidMember,
1863 REFIID /*riid*/,
1864 LCID /*lcid*/,
1865 WORD wFlags,
1866 DISPPARAMS * pdispparams,
1867 VARIANT * pvarResult,
1868 EXCEPINFO * pexcepinfo,
1869 UINT * puArgErr )
1871 comphelper::Automation::AutomationInvokedZone aAutomationActive;
1873 OUString sParams;
1874 #if defined SAL_LOG_INFO
1875 sParams += "[";
1876 for (unsigned int i = 0; i < pdispparams->cArgs; ++i)
1878 if (i > 0)
1879 sParams += ",";
1880 std::stringstream aStringStream;
1881 aStringStream << pdispparams->rgvarg[i];
1882 sParams += OUString::createFromAscii(aStringStream.str().c_str());
1884 sParams += "]";
1885 #endif
1886 SAL_INFO("extensions.olebridge", this << "@InterfaceOleWrapper::Invoke(" << dispidMember << "," << sParams << ")");
1888 comphelper::ProfileZone aZone("COM Bridge");
1889 HRESULT ret = S_OK;
1893 bool bHandled= false;
1894 ret= InvokeGeneral( dispidMember, wFlags, pdispparams, pvarResult, pexcepinfo,
1895 puArgErr, bHandled);
1896 if( bHandled)
1897 return ret;
1899 if ((dispidMember > 0) && (static_cast<size_t>(dispidMember) <= m_MemberInfos.size()) && m_xInvocation.is())
1901 MemberInfo d = m_MemberInfos[dispidMember - 1];
1902 DWORD flags = wFlags & d.flags;
1904 if (flags != 0)
1906 if ((flags & DISPATCH_METHOD) != 0)
1908 std::unique_ptr<DISPPARAMS> pNewDispParams;
1909 std::vector<VARIANTARG> vNewArgs;
1911 if (pdispparams->cNamedArgs > 0)
1913 // Convert named arguments to positional ones.
1915 // An example:
1917 // Function declaration (in pseudo-code):
1918 // int foo(int A, int B, optional int C, optional int D, optional int E, optional int F, optional int G)
1920 // Corresponding parameter numbers (DISPIDs):
1921 // 0 1 2 3 4 5 6
1923 // Actual call:
1924 // foo(10, 20, E:=50, D:=40, F:=60)
1926 // That is, A and B are passed positionally, D, E, and F as named arguments,
1927 // and the optional C and G parameters are left out.
1929 // Incoming DISPPARAMS:
1930 // cArgs=5, cNamedArgs=3
1931 // rgvarg: [60, 40, 50, 20, 10]
1932 // rgdispidNamedArgs: [5, 3, 4]
1934 // We calculate nLowestNamedArgDispid = 3 and nHighestNamedArgDispid = 5.
1936 // Result of conversion, no named args:
1937 // cArgs=6, cNamedArgs=0
1938 // rgvarg: [60, 50, 40, DISP_E_PARAMNOTFOUND, 20, 10]
1940 // First find the lowest and highest DISPID of the named arguments.
1941 DISPID nLowestNamedArgDispid = 1000000;
1942 DISPID nHighestNamedArgDispid = -1;
1943 for (unsigned int i = 0; i < pdispparams->cNamedArgs; ++i)
1945 if (pdispparams->rgdispidNamedArgs[i] < nLowestNamedArgDispid)
1946 nLowestNamedArgDispid = pdispparams->rgdispidNamedArgs[i];
1947 if (pdispparams->rgdispidNamedArgs[i] > nHighestNamedArgDispid)
1948 nHighestNamedArgDispid = pdispparams->rgdispidNamedArgs[i];
1951 // Make sure named arguments don't overlap with positional ones. The lowest
1952 // DISPID of the named arguments should be >= the number of positional
1953 // arguments.
1954 if (nLowestNamedArgDispid < static_cast<DISPID>(pdispparams->cArgs - pdispparams->cNamedArgs))
1955 return DISP_E_NONAMEDARGS;
1957 // Do the actual conversion.
1958 pNewDispParams.reset(new DISPPARAMS);
1959 vNewArgs.resize(nHighestNamedArgDispid + 1);
1960 pNewDispParams->rgvarg = vNewArgs.data();
1961 pNewDispParams->rgdispidNamedArgs = nullptr;
1962 pNewDispParams->cArgs = nHighestNamedArgDispid + 1;
1963 pNewDispParams->cNamedArgs = 0;
1965 // Initialise all parameter slots as missing
1966 for (int i = 0; i < nHighestNamedArgDispid; ++i)
1968 pNewDispParams->rgvarg[i].vt = VT_ERROR;
1969 pNewDispParams->rgvarg[i].scode = DISP_E_PARAMNOTFOUND;
1972 // Then set the value of those actually present.
1973 for (unsigned int i = 0; i < pdispparams->cNamedArgs; ++i)
1974 pNewDispParams->rgvarg[nHighestNamedArgDispid - pdispparams->rgdispidNamedArgs[i]] = pdispparams->rgvarg[i];
1976 const int nFirstUnnamedArg = pdispparams->cNamedArgs + (nLowestNamedArgDispid-(pdispparams->cArgs - pdispparams->cNamedArgs));
1978 for (unsigned int i = pdispparams->cNamedArgs; i < pdispparams->cArgs; ++i)
1979 pNewDispParams->rgvarg[nFirstUnnamedArg + (i-pdispparams->cNamedArgs)] = pdispparams->rgvarg[i];
1981 pdispparams = pNewDispParams.get();
1984 Sequence<Any> params;
1986 convertDispparamsArgs(dispidMember, wFlags, pdispparams , params );
1988 ret= doInvoke(pdispparams, pvarResult,
1989 pexcepinfo, puArgErr, d.name, params);
1991 else if ((flags & DISPATCH_PROPERTYGET) != 0)
1993 ret= doGetProperty( pdispparams, pvarResult,
1994 pexcepinfo, d.name);
1996 else if ((flags & DISPATCH_PROPERTYPUT) != 0 || (flags & DISPATCH_PROPERTYPUTREF) != 0)
1998 if (pdispparams->cArgs != 1)
1999 ret = DISP_E_BADPARAMCOUNT;
2000 else
2002 Sequence<Any> params;
2003 convertDispparamsArgs(dispidMember, wFlags, pdispparams, params );
2004 if(params.getLength() > 0)
2005 ret= doSetProperty( pdispparams, pvarResult, pexcepinfo, puArgErr, d.name, params);
2006 else
2007 ret = DISP_E_BADVARTYPE;
2011 else
2012 ret= DISP_E_MEMBERNOTFOUND;
2014 else
2015 ret = DISP_E_MEMBERNOTFOUND;
2017 catch(const BridgeRuntimeError& e)
2019 writeExcepinfo(pexcepinfo, e.message);
2020 ret = DISP_E_EXCEPTION;
2022 catch(const Exception& e)
2024 OUString message= "InterfaceOleWrapper::Invoke : \n" +
2025 e.Message;
2026 writeExcepinfo(pexcepinfo, message);
2027 ret = DISP_E_EXCEPTION;
2029 catch(...)
2031 OUString message= "InterfaceOleWrapper::Invoke : \n"
2032 "Unexpected exception";
2033 writeExcepinfo(pexcepinfo, message);
2034 ret = DISP_E_EXCEPTION;
2037 return ret;
2040 HRESULT InterfaceOleWrapper::doInvoke( DISPPARAMS * pdispparams, VARIANT * pvarResult,
2041 EXCEPINFO * pexcepinfo, unsigned int * puArgErr, OUString& name, Sequence<Any>& params)
2045 HRESULT ret= S_OK;
2048 Sequence<sal_Int16> outIndex;
2049 Sequence<Any> outParams;
2050 Any returnValue;
2052 if (pdispparams->cNamedArgs > 0)
2053 return DISP_E_NONAMEDARGS;
2055 // invoke method and take care of exceptions
2056 returnValue = m_xInvocation->invoke(name,
2057 params,
2058 outIndex,
2059 outParams);
2061 // try to write back out parameter
2062 if (outIndex.getLength() > 0)
2064 const sal_Int16* pOutIndex = outIndex.getConstArray();
2065 const Any* pOutParams = outParams.getConstArray();
2067 for (sal_Int32 i = 0; i < outIndex.getLength(); i++)
2069 CComVariant variant;
2070 // Currently a Sequence is converted to an SafeArray of VARIANTs.
2071 anyToVariant( &variant, pOutParams[i]);
2073 // out parameter need special handling if they are VT_DISPATCH
2074 // and used in JScript
2075 int outindex= pOutIndex[i];
2076 writeBackOutParameter2(&(pdispparams->rgvarg[pdispparams->cArgs - 1 - outindex]),
2077 &variant );
2081 // write back return value
2082 if (pvarResult != nullptr)
2083 anyToVariant(pvarResult, returnValue);
2085 catch(const IllegalArgumentException & e) //XInvocation::invoke
2087 writeExcepinfo(pexcepinfo, e.Message);
2088 ret = DISP_E_TYPEMISMATCH;
2090 catch(const CannotConvertException & e) //XInvocation::invoke
2092 writeExcepinfo(pexcepinfo, e.Message);
2093 ret = mapCannotConvertException( e, puArgErr);
2095 catch(const InvocationTargetException & e) //XInvocation::invoke
2097 const Any& org = e.TargetException;
2098 Exception excTarget;
2099 org >>= excTarget;
2100 OUString message=
2101 org.getValueType().getTypeName() + ": " + excTarget.Message;
2102 writeExcepinfo(pexcepinfo, message);
2103 ret = DISP_E_EXCEPTION;
2105 catch(const NoSuchMethodException & e) //XInvocation::invoke
2107 writeExcepinfo(pexcepinfo, e.Message);
2108 ret = DISP_E_MEMBERNOTFOUND;
2110 catch(const BridgeRuntimeError & e)
2112 writeExcepinfo(pexcepinfo, e.message);
2113 ret = DISP_E_EXCEPTION;
2115 catch(const Exception & e)
2117 OUString message= "InterfaceOleWrapper::doInvoke : \n" +
2118 e.Message;
2119 writeExcepinfo(pexcepinfo, message);
2120 ret = DISP_E_EXCEPTION;
2122 catch( ... )
2124 OUString message= "InterfaceOleWrapper::doInvoke : \n"
2125 "Unexpected exception";
2126 writeExcepinfo(pexcepinfo, message);
2127 ret = DISP_E_EXCEPTION;
2129 return ret;
2132 HRESULT InterfaceOleWrapper::doGetProperty( DISPPARAMS * /*pdispparams*/, VARIANT * pvarResult,
2133 EXCEPINFO * pexcepinfo, OUString& name)
2135 HRESULT ret= S_OK;
2139 Any returnValue = m_xInvocation->getValue( name);
2140 // write back return value
2141 if (pvarResult)
2142 anyToVariant(pvarResult, returnValue);
2144 catch(const UnknownPropertyException& e) //XInvocation::getValue
2146 writeExcepinfo(pexcepinfo, e.Message);
2147 ret = DISP_E_MEMBERNOTFOUND;
2149 catch(const BridgeRuntimeError& e)
2151 writeExcepinfo(pexcepinfo, e.message);
2152 ret = DISP_E_EXCEPTION;
2154 catch(const Exception& e)
2156 OUString message= "InterfaceOleWrapper::doGetProperty : \n" +
2157 e.Message;
2158 writeExcepinfo(pexcepinfo, message);
2160 catch( ... )
2162 OUString message= "InterfaceOleWrapper::doInvoke : \n"
2163 "Unexpected exception";
2164 writeExcepinfo(pexcepinfo, message);
2165 ret = DISP_E_EXCEPTION;
2167 return ret;
2170 HRESULT InterfaceOleWrapper::doSetProperty( DISPPARAMS * /*pdispparams*/, VARIANT * /*pvarResult*/,
2171 EXCEPINFO * pexcepinfo, unsigned int * puArgErr, OUString& name, Sequence<Any> const & params)
2173 HRESULT ret= S_OK;
2177 m_xInvocation->setValue( name, params.getConstArray()[0]);
2179 catch(const UnknownPropertyException &)
2181 ret = DISP_E_MEMBERNOTFOUND;
2183 catch(const CannotConvertException &e)
2185 ret= mapCannotConvertException( e, puArgErr);
2187 catch(const InvocationTargetException &e)
2189 if (pexcepinfo != nullptr)
2191 Any org = e.TargetException;
2193 pexcepinfo->wCode = UNO_2_OLE_EXCEPTIONCODE;
2194 pexcepinfo->bstrSource = SysAllocString(L"any ONE component");
2195 pexcepinfo->bstrDescription = SysAllocString(
2196 o3tl::toW(org.getValueType().getTypeName().getStr()));
2198 ret = DISP_E_EXCEPTION;
2200 catch( ... )
2202 ret= DISP_E_EXCEPTION;
2204 return ret;
2207 class CXEnumVariant : public IEnumVARIANT,
2208 public CComObjectRoot
2210 public:
2211 CXEnumVariant()
2212 : mnIndex(1) // ooo::vba::XCollection index starts at one
2216 virtual ~CXEnumVariant()
2220 #if defined __clang__
2221 #pragma clang diagnostic push
2222 #pragma clang diagnostic ignored "-Wunused-function"
2223 #endif
2224 BEGIN_COM_MAP(CXEnumVariant)
2225 #if defined __clang__
2226 #pragma clang diagnostic pop
2227 #endif
2228 COM_INTERFACE_ENTRY(IEnumVARIANT)
2229 #if defined __clang__
2230 #pragma clang diagnostic push
2231 #pragma clang diagnostic ignored "-Winconsistent-missing-override"
2232 #pragma clang diagnostic ignored "-Wunused-function"
2233 #endif
2234 END_COM_MAP()
2235 #if defined __clang__
2236 #pragma clang diagnostic pop
2237 #endif
2239 DECLARE_NOT_AGGREGATABLE(CXEnumVariant)
2241 // Creates and initializes the enumerator
2242 void Init(InterfaceOleWrapper* pInterfaceOleWrapper,
2243 const Reference<ooo::vba::XCollection > xCollection)
2245 mpInterfaceOleWrapper = pInterfaceOleWrapper;
2246 mxCollection = xCollection;
2249 // IEnumVARIANT
2250 virtual HRESULT STDMETHODCALLTYPE Clone(IEnumVARIANT **) override
2252 SAL_INFO("extensions.olebridge", this << "@CXEnumVariant::Clone: E_NOTIMPL");
2253 return E_NOTIMPL;
2256 virtual HRESULT STDMETHODCALLTYPE Next(ULONG const celt,
2257 VARIANT *rgVar,
2258 ULONG *pCeltFetched) override
2260 comphelper::Automation::AutomationInvokedZone aAutomationActive;
2262 if (pCeltFetched)
2263 *pCeltFetched = 0;
2265 if (celt == 0)
2267 SAL_INFO("extensions.olebridge", this << "@CXEnumVariant::Next(" << celt << "): E_INVALIDARG");
2268 return E_INVALIDARG;
2271 if (rgVar == nullptr || (celt != 1 && pCeltFetched == nullptr))
2273 SAL_INFO("extensions.olebridge", this << "@CXEnumVariant::Next(" << celt << "): E_FAIL");
2274 return E_FAIL;
2277 for (ULONG i = 0; i < celt; i++)
2278 VariantInit(&rgVar[i]);
2280 ULONG nLeft = celt;
2281 ULONG nReturned = 0;
2282 while (nLeft > 0)
2284 if (mnIndex > mxCollection->getCount())
2286 SAL_INFO("extensions.olebridge", this << "@CXEnumVariant::Next(" << celt << "): got " << nReturned << ": S_FALSE");
2287 return S_FALSE;
2289 Any aIndex;
2290 aIndex <<= mnIndex;
2291 Any aElement = mxCollection->Item(aIndex, Any());
2292 mpInterfaceOleWrapper->anyToVariant(rgVar, aElement);
2293 // rgVar->pdispVal->AddRef(); ??
2294 if (pCeltFetched)
2295 (*pCeltFetched)++;
2296 rgVar++;
2297 nReturned++;
2298 mnIndex++;
2299 nLeft--;
2301 SAL_INFO("extensions.olebridge", this << "@CXEnumVariant::Next(" << celt << "): S_OK");
2302 return S_OK;
2305 virtual HRESULT STDMETHODCALLTYPE Reset() override
2307 SAL_INFO("extensions.olebridge", this << "@CXEnumVariant::Reset: S_OK");
2308 mnIndex = 1;
2309 return S_OK;
2312 virtual HRESULT STDMETHODCALLTYPE STDMETHODCALLTYPE Skip(ULONG const celt) override
2314 comphelper::Automation::AutomationInvokedZone aAutomationActive;
2316 ULONG nLeft = celt;
2317 ULONG nSkipped = 0;
2318 while (nLeft > 0)
2320 if (mnIndex > mxCollection->getCount())
2322 SAL_INFO("extensions.olebridge", this << "@CXEnumVariant::Skip(" << celt << "): skipped " << nSkipped << ": S_FALSE");
2323 return S_FALSE;
2325 mnIndex++;
2326 nLeft--;
2328 SAL_INFO("extensions.olebridge", this << "@CXEnumVariant::Skip(" << celt << "): S_OK");
2329 return S_OK;
2332 private:
2333 InterfaceOleWrapper* mpInterfaceOleWrapper;
2334 Reference<ooo::vba::XCollection> mxCollection;
2335 sal_Int32 mnIndex;
2338 class Sink : public cppu::WeakImplHelper<ooo::vba::XSink>
2340 public:
2341 Sink(IUnknown* pUnkSink,
2342 Reference<XMultiServiceFactory> xMSF,
2343 ooo::vba::TypeAndIID aTypeAndIID,
2344 InterfaceOleWrapper* pInterfaceOleWrapper);
2346 // XSink
2347 void SAL_CALL Call( const OUString& Method, Sequence< Any >& Arguments ) override;
2349 private:
2350 IUnknown* mpUnkSink;
2351 Reference<XMultiServiceFactory> mxMSF;
2352 ooo::vba::TypeAndIID maTypeAndIID;
2353 InterfaceOleWrapper* mpInterfaceOleWrapper;
2356 Sink::Sink(IUnknown* pUnkSink,
2357 Reference<XMultiServiceFactory> xMSF,
2358 ooo::vba::TypeAndIID aTypeAndIID,
2359 InterfaceOleWrapper* pInterfaceOleWrapper) :
2360 mpUnkSink(pUnkSink),
2361 mxMSF(xMSF),
2362 maTypeAndIID(aTypeAndIID),
2363 mpInterfaceOleWrapper(pInterfaceOleWrapper)
2365 mpUnkSink->AddRef();
2368 void SAL_CALL
2369 Sink::Call( const OUString& Method, Sequence< Any >& Arguments )
2371 SAL_INFO("extensions.olebridge", "Sink::Call(" << Method << ", " << Arguments.getLength() << " arguments)");
2373 IDispatch* pDispatch;
2374 HRESULT nResult = mpUnkSink->QueryInterface(IID_IDispatch, reinterpret_cast<void **>(&pDispatch));
2375 if (!SUCCEEDED(nResult))
2377 SAL_WARN("extensions.olebridge", "Sink::Call: Not IDispatch: " << WindowsErrorStringFromHRESULT(nResult));
2378 return;
2381 Reference<XIdlReflection> xRefl = theCoreReflection::get(comphelper::getComponentContext(mxMSF));
2382 assert(xRefl.is());
2384 Reference<XIdlClass> xClass = xRefl->forName(maTypeAndIID.Type.getTypeName());
2385 assert(xClass.is());
2387 auto aMethods = xClass->getMethods();
2388 assert(xClass->getTypeClass() == TypeClass_INTERFACE &&
2389 aMethods.getLength() > 0);
2391 int nMemId = 1;
2392 // Skip the three XInterface methods
2393 for (int i = 3; i < aMethods.getLength(); i++)
2395 if (aMethods[i]->getName() == Method)
2397 // FIXME: Handle mismatch in type of actual argument and parameter of the method.
2399 // FIXME: Handle mismatch in number of arguments passed and actual number of parameters
2400 // of the method.
2402 auto aParamInfos = aMethods[i]->getParameterInfos();
2404 assert(Arguments.getLength() == aParamInfos.getLength());
2406 DISPPARAMS aDispParams;
2407 aDispParams.rgdispidNamedArgs = nullptr;
2408 aDispParams.cArgs = Arguments.getLength();
2409 aDispParams.cNamedArgs = 0;
2410 aDispParams.rgvarg = new VARIANT[aDispParams.cArgs];
2411 for (unsigned j = 0; j < aDispParams.cArgs; j++)
2413 VariantInit(aDispParams.rgvarg+j);
2414 // Note: Reverse order of arguments in Arguments and aDispParams.rgvarg!
2415 const unsigned nIncomingArgIndex = aDispParams.cArgs - j - 1;
2416 mpInterfaceOleWrapper->anyToVariant(aDispParams.rgvarg+j, Arguments[nIncomingArgIndex]);
2418 // Handle OUT and INOUT arguments. For instance, the second ('Cancel') parameter to
2419 // DocumentBeforeClose() should be a VT_BYREF|VT_BOOL parameter. Need to handle that
2420 // here.
2422 if (aParamInfos[nIncomingArgIndex].aMode == ParamMode_OUT ||
2423 aParamInfos[nIncomingArgIndex].aMode == ParamMode_INOUT)
2425 switch (aDispParams.rgvarg[j].vt)
2427 case VT_I2:
2428 aDispParams.rgvarg[j].byref = new SHORT(aDispParams.rgvarg[j].iVal);
2429 aDispParams.rgvarg[j].vt |= VT_BYREF;
2430 break;
2431 case VT_I4:
2432 aDispParams.rgvarg[j].byref = new LONG(aDispParams.rgvarg[j].lVal);
2433 aDispParams.rgvarg[j].vt |= VT_BYREF;
2434 break;
2435 case VT_BSTR:
2436 aDispParams.rgvarg[j].byref = new BSTR(aDispParams.rgvarg[j].bstrVal);
2437 aDispParams.rgvarg[j].vt |= VT_BYREF;
2438 break;
2439 case VT_BOOL:
2440 // SAL_ DEBUG("===> VT_BOOL is initially " << (int)aDispParams.rgvarg[j].boolVal);
2441 aDispParams.rgvarg[j].byref = new VARIANT_BOOL(aDispParams.rgvarg[j].boolVal);
2442 // SAL_ DEBUG(" byref=" << aDispParams.rgvarg[j].byref);
2443 aDispParams.rgvarg[j].vt |= VT_BYREF;
2444 break;
2445 default:
2446 assert(false && "Not handled yet");
2447 break;
2452 VARIANT aVarResult;
2453 VariantInit(&aVarResult);
2454 UINT uArgErr;
2456 // In the case of a VBScript client, which uses "late binding", calling Invoke on the
2457 // sink it provides will cause a callback to our CXTypeInfo::GetNames for the given
2458 // member id, and in that we will tell it the name of the corresponding method, and the
2459 // client will know what event handler to invoke based on that name.
2461 // As the outgoing interfaces used (ooo::vba::word::XApplicationOutgoing and others) are
2462 // totally not stable and not published in any way, there can be no client that would
2463 // have done "compile-time binding" and where the sink would actually be an object with
2464 // a vtbl corresponding to the outgoing interface. Late binding clients that work like
2465 // VBScript is all we support.
2466 SAL_INFO("extensions.olebridge", "Sink::Call(" << Method << "): Calling Invoke(" << nMemId << ")");
2468 nResult = pDispatch->Invoke(nMemId, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &aDispParams, &aVarResult, nullptr, &uArgErr);
2469 SAL_INFO("extensions.olebridge", "Sink::Call(" << Method << "): Invoke() returned");
2471 SAL_WARN_IF(!SUCCEEDED(nResult), "extensions.olebridge", "Call to " << Method << " failed: " << WindowsErrorStringFromHRESULT(nResult));
2473 // Undo VT_BYREF magic done above. Copy out parameters back to the Anys in Arguments
2474 for (unsigned j = 0; j < aDispParams.cArgs; j++)
2476 const unsigned nIncomingArgIndex = aDispParams.cArgs - j - 1;
2477 if (aParamInfos[nIncomingArgIndex].aMode == ParamMode_OUT ||
2478 aParamInfos[nIncomingArgIndex].aMode == ParamMode_INOUT)
2480 switch (aDispParams.rgvarg[j].vt)
2482 case VT_BYREF|VT_I2:
2484 SHORT *pI = static_cast<SHORT*>(aDispParams.rgvarg[j].byref);
2485 Arguments[nIncomingArgIndex] <<= static_cast<sal_Int16>(*pI);
2486 delete pI;
2488 break;
2489 case VT_BYREF|VT_I4:
2491 LONG *pL = static_cast<LONG*>(aDispParams.rgvarg[j].byref);
2492 Arguments[nIncomingArgIndex] <<= static_cast<sal_Int32>(*pL);
2493 delete pL;
2495 break;
2496 case VT_BYREF|VT_BSTR:
2498 BSTR *pBstr = static_cast<BSTR*>(aDispParams.rgvarg[j].byref);
2499 Arguments[nIncomingArgIndex] <<= OUString(o3tl::toU(*pBstr));
2500 // Undo SysAllocString() done in anyToVariant()
2501 SysFreeString(*pBstr);
2502 delete pBstr;
2504 break;
2505 case VT_BYREF|VT_BOOL:
2507 VARIANT_BOOL *pBool = static_cast<VARIANT_BOOL*>(aDispParams.rgvarg[j].byref);
2508 // SAL_ DEBUG("===> VT_BOOL: byref is now " << aDispParams.rgvarg[j].byref << ", " << (int)*pBool);
2509 Arguments[nIncomingArgIndex] <<= (*pBool != VARIANT_FALSE);
2510 delete pBool;
2512 break;
2513 default:
2514 assert(false && "Not handled yet");
2515 break;
2518 else
2520 switch (aDispParams.rgvarg[j].vt)
2522 case VT_BSTR:
2523 // Undo SysAllocString() done in anyToVariant()
2524 SysFreeString(aDispParams.rgvarg[j].bstrVal);
2525 break;
2530 delete[] aDispParams.rgvarg;
2531 return;
2533 nMemId++;
2535 SAL_WARN("extensions.olebridge", "Sink::Call: Unknown method '" << Method << "'");
2538 class CXEnumConnections : public IEnumConnections,
2539 public CComObjectRoot
2541 public:
2542 CXEnumConnections()
2546 virtual ~CXEnumConnections()
2550 #if defined __clang__
2551 #pragma clang diagnostic push
2552 #pragma clang diagnostic ignored "-Wunused-function"
2553 #endif
2554 BEGIN_COM_MAP(CXEnumConnections)
2555 #if defined __clang__
2556 #pragma clang diagnostic pop
2557 #endif
2558 COM_INTERFACE_ENTRY(IEnumConnections)
2559 #if defined __clang__
2560 #pragma clang diagnostic push
2561 #pragma clang diagnostic ignored "-Winconsistent-missing-override"
2562 #pragma clang diagnostic ignored "-Wunused-function"
2563 #endif
2564 END_COM_MAP()
2565 #if defined __clang__
2566 #pragma clang diagnostic pop
2567 #endif
2569 DECLARE_NOT_AGGREGATABLE(CXEnumConnections)
2571 void Init(std::vector<IUnknown*>& rUnknowns, std::vector<DWORD>& rCookies)
2573 SAL_INFO("extensions.olebridge", this << "@CXEnumConnections::Init");
2574 SAL_WARN_IF(rUnknowns.size() != rCookies.size(), "extensions.olebridge", "Vectors of different size");
2575 mvUnknowns = rUnknowns;
2576 mvCookies = rCookies;
2577 mnIndex = 0;
2580 virtual HRESULT STDMETHODCALLTYPE Next(ULONG cConnections,
2581 LPCONNECTDATA rgcd,
2582 ULONG *pcFetched) override
2584 comphelper::Automation::AutomationInvokedZone aAutomationActive;
2586 if (!rgcd)
2588 SAL_INFO("extensions.olebridge", this << "@CXEnumConnections::Next(" << cConnections << "): E_POINTER");
2589 return E_POINTER;
2592 if (pcFetched && cConnections != 1)
2594 SAL_INFO("extensions.olebridge", this << "@CXEnumConnections::Next(" << cConnections << "): E_INVALIDARG");
2595 return E_INVALIDARG;
2598 ULONG nFetched = 0;
2599 while (nFetched < cConnections && mnIndex < mvUnknowns.size())
2601 rgcd[nFetched].pUnk = mvUnknowns[mnIndex];
2602 rgcd[nFetched].pUnk->AddRef();
2603 rgcd[nFetched].dwCookie = mvCookies[mnIndex];
2604 ++nFetched;
2605 ++mnIndex;
2607 if (nFetched != cConnections)
2609 SAL_INFO("extensions.olebridge", this << "@CXEnumConnections::Next(" << cConnections << "): S_FALSE");
2610 if (pcFetched)
2611 *pcFetched = nFetched;
2612 return S_FALSE;
2614 SAL_INFO("extensions.olebridge", this << "@CXEnumConnections::Next(" << cConnections << "): S_OK");
2615 if (pcFetched)
2616 *pcFetched = nFetched;
2618 return S_OK;
2621 virtual HRESULT STDMETHODCALLTYPE Skip(ULONG cConnections) override
2623 SAL_INFO("extensions.olebridge", this << "@CXEnumConnections::Skip(" << cConnections << "): E_NOTIMPL");
2625 return E_NOTIMPL;
2628 virtual HRESULT STDMETHODCALLTYPE Reset() override
2630 SAL_INFO("extensions.olebridge", this << "@CXEnumConnections::Reset: E_NOTIMPL");
2632 return E_NOTIMPL;
2635 virtual HRESULT STDMETHODCALLTYPE Clone(IEnumConnections** /* ppEnum */) override
2637 SAL_INFO("extensions.olebridge", this << "@CXEnumConnections::Clone: E_NOTIMPL");
2639 return E_NOTIMPL;
2642 private:
2643 std::vector<IUnknown*> mvUnknowns;
2644 std::vector<DWORD> mvCookies;
2645 ULONG mnIndex;
2648 class CXConnectionPoint : public IConnectionPoint,
2649 public CComObjectRoot
2651 public:
2652 #if defined __clang__
2653 #pragma clang diagnostic push
2654 #pragma clang diagnostic ignored "-Wunused-function"
2655 #endif
2656 BEGIN_COM_MAP(CXConnectionPoint)
2657 #if defined __clang__
2658 #pragma clang diagnostic pop
2659 #endif
2660 COM_INTERFACE_ENTRY(IConnectionPoint)
2661 #if defined __clang__
2662 #pragma clang diagnostic push
2663 #pragma clang diagnostic ignored "-Winconsistent-missing-override"
2664 #pragma clang diagnostic ignored "-Wunused-function"
2665 #endif
2666 END_COM_MAP()
2667 #if defined __clang__
2668 #pragma clang diagnostic pop
2669 #endif
2671 DECLARE_NOT_AGGREGATABLE(CXConnectionPoint)
2673 virtual ~CXConnectionPoint() {}
2675 void Init(InterfaceOleWrapper* pInterfaceOleWrapper,
2676 Reference<ooo::vba::XConnectionPoint>& xCP,
2677 Reference<XMultiServiceFactory>& xMSF,
2678 ooo::vba::TypeAndIID aTypeAndIID)
2680 SAL_INFO("extensions.olebridge", this << "@CXConnectionPoint::Init for " << pInterfaceOleWrapper->getImplementationName());
2682 IUnknown *pUnknown;
2683 if (SUCCEEDED(QueryInterface(IID_IUnknown, reinterpret_cast<void **>(&pUnknown))))
2685 // In case QI for IUnknown returns a different pointer, but nah, it doesn't
2686 SAL_INFO("extensions.olebridge", " (IUnknown@" << pUnknown << ")");
2689 mpInterfaceOleWrapper = pInterfaceOleWrapper;
2690 mxCP = xCP;
2691 mxMSF = xMSF;
2692 maTypeAndIID = aTypeAndIID;
2695 virtual HRESULT STDMETHODCALLTYPE GetConnectionInterface(IID *pIID) override
2697 SAL_WARN("extensions.olebridge", this << "@CXConnectionPoint::GetConnectionInterface(" << *pIID << "): E_NOTIMPL");
2699 // FIXME: Needed?
2701 return E_NOTIMPL;
2704 virtual HRESULT STDMETHODCALLTYPE GetConnectionPointContainer(IConnectionPointContainer **) override
2706 SAL_WARN("extensions.olebridge", this << "@CXConnectionPoint::GetConnectionInterface: E_NOTIMPL");
2708 // FIXME: Needed?
2710 return E_NOTIMPL;
2713 virtual HRESULT STDMETHODCALLTYPE Advise(IUnknown *pUnkSink,
2714 DWORD *pdwCookie) override
2716 comphelper::Automation::AutomationInvokedZone aAutomationActive;
2718 SAL_INFO("extensions.olebridge", this << "@CXConnectionPoint::Advise(" << pUnkSink << ")");
2720 if (!pdwCookie)
2721 return E_POINTER;
2723 Reference<ooo::vba::XSink> xSink(new Sink(pUnkSink, mxMSF, maTypeAndIID, mpInterfaceOleWrapper));
2725 mvISinks.push_back(pUnkSink);
2726 *pdwCookie = mvISinks.size();
2728 mvCookies.push_back(mxCP->Advise(xSink));
2730 mvXSinks.push_back(xSink);
2732 SAL_INFO("extensions.olebridge", " *pdwCookie: " << *pdwCookie);
2734 return S_OK;
2737 virtual HRESULT STDMETHODCALLTYPE Unadvise(DWORD dwCookie) override
2739 comphelper::Automation::AutomationInvokedZone aAutomationActive;
2741 SAL_INFO("extensions.olebridge", this << "@CXConnectionPoint::Unadvise(" << dwCookie << ")");
2743 if (dwCookie == 0 || dwCookie > mvISinks.size())
2744 return E_POINTER;
2746 mvISinks[dwCookie-1] = nullptr;
2748 mxCP->Unadvise(mvCookies[dwCookie-1]);
2750 mvXSinks[dwCookie-1] = Reference<ooo::vba::XSink>();
2752 return S_OK;
2755 virtual HRESULT STDMETHODCALLTYPE EnumConnections(IEnumConnections **ppEnum) override
2757 comphelper::Automation::AutomationInvokedZone aAutomationActive;
2759 HRESULT nResult;
2761 SAL_INFO("extensions.olebridge", this << "@CXConnectionPoint::EnumConnections...");
2763 if (!ppEnum)
2765 SAL_INFO("extensions.olebridge", "..." << this << "@CXConnectionPoint::EnumConnections: E_POINTER");
2766 return E_POINTER;
2769 CComObject<CXEnumConnections>* pEnumConnections;
2771 nResult = CComObject<CXEnumConnections>::CreateInstance(&pEnumConnections);
2772 if (FAILED(nResult))
2774 SAL_INFO("extensions.olebridge", "..." << this << "@CXConnectionPoint::EnumConnections: " << WindowsErrorStringFromHRESULT(nResult));
2775 return nResult;
2778 pEnumConnections->AddRef();
2780 pEnumConnections->Init(mvISinks, mvCookies);
2781 *ppEnum = pEnumConnections;
2783 SAL_INFO("extensions.olebridge", "..." << this << "@CXConnectionPoint::EnumConnections: S_OK");
2785 return S_OK;
2788 InterfaceOleWrapper* mpInterfaceOleWrapper;
2789 std::vector<IUnknown*> mvISinks;
2790 std::vector<Reference<ooo::vba::XSink>> mvXSinks;
2791 std::vector<DWORD> mvCookies;
2792 Reference<XMultiServiceFactory> mxMSF;
2793 Reference<ooo::vba::XConnectionPoint> mxCP;
2794 ooo::vba::TypeAndIID maTypeAndIID;
2797 HRESULT InterfaceOleWrapper::InvokeGeneral( DISPID dispidMember, unsigned short wFlags,
2798 DISPPARAMS * pdispparams, VARIANT * pvarResult, EXCEPINFO * pexcepinfo,
2799 unsigned int * /*puArgErr*/, bool& bHandled)
2801 HRESULT ret= S_OK;
2804 // DISPID_VALUE | The DEFAULT Value is required in JScript when the situation
2805 // is that we put an object into an Array object ( out parameter). We have to return
2806 // IDispatch otherwise the object cannot be accessed from the Script.
2807 if( dispidMember == DISPID_VALUE && (wFlags & DISPATCH_PROPERTYGET) != 0
2808 && m_defaultValueType != VT_EMPTY && pvarResult != nullptr)
2810 // Special case hack: If it is a ScVbaCheckBox, return the boolean value
2811 Reference<ooo::vba::msforms::XCheckBox> xCheckBox(m_xOrigin, UNO_QUERY);
2812 if (xCheckBox.is())
2814 bHandled = true;
2815 Any aValue = xCheckBox->getValue();
2816 anyToVariant(pvarResult, aValue);
2817 return S_OK;
2820 bHandled= true;
2821 if( m_defaultValueType == VT_DISPATCH)
2823 pvarResult->vt= VT_DISPATCH;
2824 pvarResult->pdispVal= static_cast<IDispatch*>( this);
2825 AddRef();
2826 ret= S_OK;
2830 // function: _GetValueObject
2831 else if( dispidMember == DISPID_JSCRIPT_VALUE_FUNC)
2833 bHandled= true;
2834 if( !pvarResult)
2835 return E_POINTER;
2836 CComObject< JScriptValue>* pValue;
2837 if( SUCCEEDED( CComObject<JScriptValue>::CreateInstance( &pValue)))
2839 pValue->AddRef();
2840 pvarResult->vt= VT_DISPATCH;
2841 pvarResult->pdispVal= CComQIPtr<IDispatch>(pValue->GetUnknown());
2842 ret= S_OK;
2844 else
2845 ret= DISP_E_EXCEPTION;
2847 else if( dispidMember == DISPID_GET_STRUCT_FUNC)
2849 bHandled= true;
2850 bool bStruct= false;
2853 Reference<XIdlReflection> xRefl = theCoreReflection::get(comphelper::getComponentContext(m_smgr));
2854 // the first parameter is in DISPPARAMS rgvargs contains the name of the struct.
2855 CComVariant arg;
2856 if( pdispparams->cArgs == 1 && SUCCEEDED( arg.ChangeType( VT_BSTR, &pdispparams->rgvarg[0])) )
2858 Reference<XIdlClass> classStruct= xRefl->forName(o3tl::toU(arg.bstrVal));
2859 if( classStruct.is())
2861 Any anyStruct;
2862 classStruct->createObject( anyStruct);
2863 CComVariant var;
2864 anyToVariant( &var, anyStruct );
2866 if( var.vt == VT_DISPATCH)
2868 VariantCopy( pvarResult, & var);
2869 bStruct= true;
2873 ret= bStruct ? S_OK : DISP_E_EXCEPTION;
2875 else if (dispidMember == DISPID_CREATE_TYPE_FUNC)
2877 bHandled= true;
2878 if( !pvarResult)
2879 return E_POINTER;
2880 // the first parameter is in DISPPARAMS rgvargs contains the name of the struct.
2881 CComVariant arg;
2882 if( pdispparams->cArgs != 1)
2883 return DISP_E_BADPARAMCOUNT;
2884 if (FAILED( arg.ChangeType( VT_BSTR, &pdispparams->rgvarg[0])))
2885 return DISP_E_BADVARTYPE;
2887 //check if the provided name represents a valid type
2888 Type type;
2889 if (!getType(arg.bstrVal, type))
2891 writeExcepinfo(pexcepinfo, OUStringLiteral("[automation bridge] A UNO type with the name ") +
2892 o3tl::toU(arg.bstrVal) + " does not exist!");
2893 return DISP_E_EXCEPTION;
2896 if (!createUnoTypeWrapper(arg.bstrVal, pvarResult))
2898 writeExcepinfo(pexcepinfo, "[automation bridge] InterfaceOleWrapper::InvokeGeneral\n"
2899 "Could not initialize UnoTypeWrapper object!");
2900 return DISP_E_EXCEPTION;
2903 else if (dispidMember == DISPID_NEWENUM)
2905 bHandled = true;
2906 if( !pvarResult)
2907 return E_POINTER;
2909 Reference< ooo::vba::XCollection> xCollection(m_xOrigin, UNO_QUERY);
2910 if (!xCollection.is())
2911 return DISP_E_MEMBERNOTFOUND;
2913 CComObject<CXEnumVariant>* pEnumVar;
2915 ret = CComObject<CXEnumVariant>::CreateInstance(&pEnumVar);
2916 if (FAILED(ret))
2917 return ret;
2919 pEnumVar->AddRef();
2921 pEnumVar->Init(this, xCollection);
2923 pvarResult->vt = VT_UNKNOWN;
2924 pvarResult->punkVal = nullptr;
2926 ret = pEnumVar->QueryInterface(IID_IUnknown, reinterpret_cast<void**>(&pvarResult->punkVal));
2927 if (FAILED(ret))
2929 pEnumVar->Release();
2930 return ret;
2934 catch(const BridgeRuntimeError & e)
2936 writeExcepinfo(pexcepinfo, e.message);
2937 ret = DISP_E_EXCEPTION;
2939 catch(const Exception & e)
2941 OUString message= "InterfaceOleWrapper::InvokeGeneral : \n" +
2942 e.Message;
2943 writeExcepinfo(pexcepinfo, message);
2944 ret = DISP_E_EXCEPTION;
2946 catch( ... )
2948 OUString message= "InterfaceOleWrapper::InvokeGeneral : \n"
2949 "Unexpected exception";
2950 writeExcepinfo(pexcepinfo, message);
2951 ret = DISP_E_EXCEPTION;
2953 return ret;
2956 STDMETHODIMP InterfaceOleWrapper::GetDispID(BSTR /*bstrName*/, DWORD /*grfdex*/, DISPID __RPC_FAR* /*pid*/)
2958 return ResultFromScode(E_NOTIMPL);
2961 STDMETHODIMP InterfaceOleWrapper::InvokeEx(
2962 /* [in] */ DISPID /*id*/,
2963 /* [in] */ LCID /*lcid*/,
2964 /* [in] */ WORD /*wFlags*/,
2965 /* [in] */ DISPPARAMS __RPC_FAR* /*pdp*/,
2966 /* [out] */ VARIANT __RPC_FAR* /*pvarRes*/,
2967 /* [out] */ EXCEPINFO __RPC_FAR* /*pei*/,
2968 /* [unique][in] */ IServiceProvider __RPC_FAR* /*pspCaller*/)
2970 return ResultFromScode(E_NOTIMPL);
2973 STDMETHODIMP InterfaceOleWrapper::DeleteMemberByName(
2974 /* [in] */ BSTR /*bstr*/,
2975 /* [in] */ DWORD /*grfdex*/)
2977 return ResultFromScode(E_NOTIMPL);
2980 STDMETHODIMP InterfaceOleWrapper::DeleteMemberByDispID(DISPID /*id*/)
2982 return ResultFromScode(E_NOTIMPL);
2985 STDMETHODIMP InterfaceOleWrapper::GetMemberProperties(
2986 /* [in] */ DISPID /*id*/,
2987 /* [in] */ DWORD /*grfdexFetch*/,
2988 /* [out] */ DWORD __RPC_FAR* /*pgrfdex*/)
2990 return ResultFromScode(E_NOTIMPL);
2993 STDMETHODIMP InterfaceOleWrapper::GetMemberName(
2994 /* [in] */ DISPID /*id*/,
2995 /* [out] */ BSTR __RPC_FAR* /*pbstrName*/)
2997 return ResultFromScode(E_NOTIMPL);
3000 STDMETHODIMP InterfaceOleWrapper::GetNextDispID(
3001 /* [in] */ DWORD /*grfdex*/,
3002 /* [in] */ DISPID /*id*/,
3003 /* [out] */ DISPID __RPC_FAR* /*pid*/)
3005 return ResultFromScode(E_NOTIMPL);
3008 STDMETHODIMP InterfaceOleWrapper::GetNameSpaceParent(
3009 /* [out] */ IUnknown __RPC_FAR *__RPC_FAR* /*ppunk*/)
3011 return ResultFromScode(E_NOTIMPL);
3014 // IProvideClassInfo
3015 HRESULT STDMETHODCALLTYPE InterfaceOleWrapper::GetClassInfo (
3016 /* [out] */ ITypeInfo **ppTI)
3018 comphelper::Automation::AutomationInvokedZone aAutomationActive;
3020 SAL_INFO("extensions.olebridge", this << "@InterfaceOleWrapper::GetClassInfo");
3022 if (!ppTI)
3023 return E_POINTER;
3025 Reference<ooo::vba::XInterfaceWithIID> xIID(m_xOrigin, UNO_QUERY);
3026 if (!xIID.is())
3027 return E_NOTIMPL;
3029 OUString sIID = xIID->getIID();
3030 IID aIID;
3031 if (!SUCCEEDED(IIDFromString(reinterpret_cast<LPOLESTR>(sIID.pData->buffer), &aIID)))
3032 return E_NOTIMPL;
3034 HRESULT ret;
3036 CComObject<CXTypeInfo>* pTypeInfo;
3038 ret = CComObject<CXTypeInfo>::CreateInstance(&pTypeInfo);
3039 if (FAILED(ret))
3040 return ret;
3042 pTypeInfo->AddRef();
3044 pTypeInfo->InitForCoclass(m_xOrigin, m_sImplementationName, aIID, m_smgr);
3046 *ppTI = pTypeInfo;
3048 return S_OK;
3051 // IConnectionPointContainer
3052 HRESULT STDMETHODCALLTYPE InterfaceOleWrapper::EnumConnectionPoints(
3053 /* [out] */ IEnumConnectionPoints **)
3055 SAL_INFO("extensions.olebridge", this << "@InterfaceOleWrapper::EnumConnectionPoints");
3056 return ResultFromScode(E_NOTIMPL);
3059 HRESULT STDMETHODCALLTYPE InterfaceOleWrapper::FindConnectionPoint(
3060 /* [in] */ REFIID riid,
3061 /* [out] */ IConnectionPoint **ppCP)
3063 comphelper::Automation::AutomationInvokedZone aAutomationActive;
3065 SAL_INFO("extensions.olebridge", this << "@InterfaceOleWrapper::FindConnectionPoint(" << riid << ")");
3067 if (!ppCP)
3068 return E_POINTER;
3070 Reference<ooo::vba::XConnectable> xConnectable(m_xOrigin, UNO_QUERY);
3072 // We checked already
3073 assert(xConnectable.is());
3074 if (!xConnectable.is())
3075 return E_NOTIMPL;
3077 ooo::vba::TypeAndIID aTypeAndIID = xConnectable->GetConnectionPoint();
3079 IID aIID;
3080 if (!SUCCEEDED(IIDFromString(reinterpret_cast<LPOLESTR>(aTypeAndIID.IID.pData->buffer), &aIID)))
3081 return E_INVALIDARG;
3083 if (!IsEqualIID(riid, aIID))
3084 return E_INVALIDARG;
3086 Reference<ooo::vba::XConnectionPoint> xCP = xConnectable->FindConnectionPoint();
3087 if (!xCP.is())
3088 return E_INVALIDARG;
3090 HRESULT ret;
3092 CComObject<CXConnectionPoint>* pConnectionPoint;
3094 ret = CComObject<CXConnectionPoint>::CreateInstance(&pConnectionPoint);
3095 if (FAILED(ret))
3096 return ret;
3098 pConnectionPoint->AddRef();
3100 pConnectionPoint->Init(this, xCP, m_smgr, aTypeAndIID);
3102 *ppCP = pConnectionPoint;
3104 return S_OK;
3107 // UnoObjectWrapperRemoteOpt ---------------------------------------------------
3109 UnoObjectWrapperRemoteOpt::UnoObjectWrapperRemoteOpt( Reference<XMultiServiceFactory> const & aFactory,
3110 sal_uInt8 unoWrapperClass, sal_uInt8 comWrapperClass):
3111 InterfaceOleWrapper( aFactory, unoWrapperClass, comWrapperClass),
3112 m_currentId(1)
3116 UnoObjectWrapperRemoteOpt::~UnoObjectWrapperRemoteOpt()
3120 // UnoConversionUtilities
3121 Reference< XInterface > UnoObjectWrapperRemoteOpt::createUnoWrapperInstance()
3123 Reference<XWeak> xWeak= static_cast<XWeak*>( new UnoObjectWrapperRemoteOpt(
3124 m_smgr, m_nUnoWrapperClass, m_nComWrapperClass));
3125 return Reference<XInterface>( xWeak, UNO_QUERY);
3128 COM_DECLSPEC_NOTHROW STDMETHODIMP UnoObjectWrapperRemoteOpt::GetIDsOfNames ( REFIID /*riid*/, LPOLESTR * rgszNames, UINT cNames,
3129 LCID /*lcid*/, DISPID * rgdispid )
3131 MutexGuard guard( getBridgeMutex());
3133 if( ! rgdispid)
3134 return E_POINTER;
3135 HRESULT ret = E_UNEXPECTED;
3137 // _GetValueObject
3138 if( ! wcscmp( *rgszNames, JSCRIPT_VALUE_FUNC))
3140 *rgdispid= DISPID_JSCRIPT_VALUE_FUNC;
3141 return S_OK;
3143 else if( ! wcscmp( *rgszNames, GET_STRUCT_FUNC))
3145 *rgdispid= DISPID_GET_STRUCT_FUNC;
3146 return S_OK;
3149 if (m_xInvocation.is() && (cNames > 0))
3151 OUString name(o3tl::toU(rgszNames[0]));
3152 // has this name been determined as "bad"
3153 BadNameMap::iterator badIter= m_badNameMap.find( name);
3154 if( badIter == m_badNameMap.end() )
3156 // name has not been bad before( member exists
3157 typedef NameToIdMap::iterator ITnames;
3158 pair< ITnames, bool > pair_id= m_nameToDispIdMap.emplace(name, m_currentId++);
3159 // new ID inserted ?
3160 if( pair_id.second )
3161 {// yes, now create MemberInfo and ad to IdToMemberInfoMap
3162 MemberInfo d(0, name);
3163 m_idToMemberInfoMap.emplace(m_currentId - 1, d);
3166 *rgdispid = pair_id.first->second;
3167 ret = S_OK;
3169 else
3170 ret= DISP_E_UNKNOWNNAME;
3172 return ret;
3175 COM_DECLSPEC_NOTHROW STDMETHODIMP UnoObjectWrapperRemoteOpt::Invoke ( DISPID dispidMember, REFIID /*riid*/, LCID /*lcid*/, WORD wFlags,
3176 DISPPARAMS * pdispparams, VARIANT * pvarResult, EXCEPINFO * pexcepinfo,
3177 UINT * puArgErr )
3179 comphelper::Automation::AutomationInvokedZone aAutomationActive;
3181 HRESULT ret = S_OK;
3184 bool bHandled= false;
3185 ret= InvokeGeneral( dispidMember, wFlags, pdispparams, pvarResult, pexcepinfo,
3186 puArgErr, bHandled);
3187 if( bHandled)
3188 return ret;
3190 if ( dispidMember > 0 && m_xInvocation.is())
3193 IdToMemberInfoMap::iterator it_MemberInfo= m_idToMemberInfoMap.find( dispidMember);
3194 if( it_MemberInfo != m_idToMemberInfoMap.end() )
3196 MemberInfo& info= it_MemberInfo->second;
3198 Sequence<Any> params; // holds converted any s
3199 if( ! info.flags )
3200 { // DISPID called for the first time
3201 if( wFlags == DISPATCH_METHOD )
3203 convertDispparamsArgs(dispidMember, wFlags, pdispparams, params );
3205 if( FAILED( ret= doInvoke( pdispparams, pvarResult,
3206 pexcepinfo, puArgErr, info.name, params))
3207 && ret == DISP_E_MEMBERNOTFOUND)
3209 // try to get the exact name
3210 OUString exactName;
3211 if (m_xExactName.is())
3213 exactName = m_xExactName->getExactName( info.name);
3214 // invoke again
3215 if( !exactName.isEmpty() )
3217 if( SUCCEEDED( ret= doInvoke( pdispparams, pvarResult,
3218 pexcepinfo, puArgErr, exactName, params)))
3219 info.name= exactName;
3223 if( SUCCEEDED( ret ) )
3224 info.flags= DISPATCH_METHOD;
3226 else if( wFlags == DISPATCH_PROPERTYPUT || wFlags == DISPATCH_PROPERTYPUTREF)
3228 convertDispparamsArgs(dispidMember, wFlags, pdispparams, params );
3229 if( FAILED( ret= doSetProperty( pdispparams, pvarResult,
3230 pexcepinfo, puArgErr, info.name, params))
3231 && ret == DISP_E_MEMBERNOTFOUND)
3233 // try to get the exact name
3234 OUString exactName;
3235 if (m_xExactName.is())
3237 exactName = m_xExactName->getExactName( info.name);
3238 // invoke again
3239 if( !exactName.isEmpty() )
3241 if( SUCCEEDED( ret= doSetProperty( pdispparams, pvarResult,
3242 pexcepinfo, puArgErr, exactName, params)))
3243 info.name= exactName;
3247 if( SUCCEEDED( ret ) )
3248 info.flags= DISPATCH_PROPERTYPUT | DISPATCH_PROPERTYGET;
3250 else if( wFlags == DISPATCH_PROPERTYGET)
3252 if( FAILED( ret= doGetProperty( pdispparams, pvarResult,
3253 pexcepinfo, info.name))
3254 && ret == DISP_E_MEMBERNOTFOUND)
3256 // try to get the exact name
3257 OUString exactName;
3258 if (m_xExactName.is())
3260 exactName = m_xExactName->getExactName( info.name);
3261 // invoke again
3262 if( !exactName.isEmpty() )
3264 if( SUCCEEDED( ret= doGetProperty( pdispparams, pvarResult,
3265 pexcepinfo, exactName)))
3266 info.name= exactName;
3270 if( SUCCEEDED( ret ) )
3271 info.flags= DISPATCH_PROPERTYGET | DISPATCH_PROPERTYPUT;
3273 else if( wFlags & DISPATCH_METHOD &&
3274 (wFlags & DISPATCH_PROPERTYPUT || wFlags & DISPATCH_PROPERTYPUTREF))
3277 OUString exactName;
3278 // convert params for DISPATCH_METHOD or DISPATCH_PROPERTYPUT
3279 convertDispparamsArgs(dispidMember, wFlags, pdispparams, params );
3280 // try first as method
3281 if( FAILED( ret= doInvoke( pdispparams, pvarResult,
3282 pexcepinfo, puArgErr, info.name, params))
3283 && ret == DISP_E_MEMBERNOTFOUND)
3285 // try to get the exact name
3286 if (m_xExactName.is())
3288 exactName = m_xExactName->getExactName( info.name);
3289 // invoke again
3290 if( !exactName.isEmpty() )
3292 if( SUCCEEDED( ret= doInvoke( pdispparams, pvarResult,
3293 pexcepinfo, puArgErr, exactName, params)))
3294 info.name= exactName;
3298 if( SUCCEEDED( ret ) )
3299 info.flags= DISPATCH_METHOD;
3301 // try as property
3302 if( FAILED( ret) && pdispparams->cArgs == 1)
3304 if( FAILED( ret= doSetProperty( pdispparams, pvarResult,
3305 pexcepinfo, puArgErr, info.name, params))
3306 && ret == DISP_E_MEMBERNOTFOUND)
3308 // try to get the exact name
3309 if( !exactName.isEmpty() )
3311 if( SUCCEEDED( ret= doSetProperty( pdispparams, pvarResult,
3312 pexcepinfo, puArgErr, exactName, params)))
3313 info.name= exactName;
3316 if( SUCCEEDED( ret ) )
3317 info.flags= DISPATCH_PROPERTYPUT | DISPATCH_PROPERTYGET;
3320 else if( wFlags & DISPATCH_METHOD && wFlags & DISPATCH_PROPERTYGET)
3322 OUString exactName;
3323 convertDispparamsArgs(dispidMember, wFlags, pdispparams, params );
3325 if( FAILED( ret= doInvoke( pdispparams, pvarResult,
3326 pexcepinfo, puArgErr, info.name, params))
3327 && ret == DISP_E_MEMBERNOTFOUND)
3329 // try to get the exact name
3330 if (m_xExactName.is())
3332 exactName = m_xExactName->getExactName( info.name);
3333 // invoke again
3334 if( !exactName.isEmpty() )
3336 if( SUCCEEDED( ret= doInvoke( pdispparams, pvarResult,
3337 pexcepinfo, puArgErr, exactName, params)))
3338 info.name= exactName;
3342 if( SUCCEEDED( ret ) )
3343 info.flags= DISPATCH_METHOD;
3345 // try as property
3346 if( FAILED( ret) && pdispparams->cArgs == 1)
3348 if( FAILED( ret= doGetProperty( pdispparams, pvarResult,
3349 pexcepinfo, info.name))
3350 && ret == DISP_E_MEMBERNOTFOUND)
3352 if( !exactName.isEmpty() )
3354 if( SUCCEEDED( ret= doSetProperty( pdispparams, pvarResult,
3355 pexcepinfo, puArgErr, exactName, params)))
3356 info.name= exactName;
3359 if( SUCCEEDED( ret ) )
3360 info.flags= DISPATCH_PROPERTYGET;
3364 // update information about this member
3365 if( ret == DISP_E_MEMBERNOTFOUND)
3367 // Remember the name as not existing
3368 // and remove the MemberInfo
3369 m_badNameMap[info.name]= false;
3370 m_idToMemberInfoMap.erase( it_MemberInfo);
3372 } // if( ! info.flags )
3373 else // IdToMemberInfoMap contains a MemberInfo
3375 if( wFlags & DISPATCH_METHOD && info.flags == DISPATCH_METHOD)
3377 convertDispparamsArgs(dispidMember, wFlags, pdispparams, params );
3378 ret= doInvoke( pdispparams, pvarResult,
3379 pexcepinfo, puArgErr, info.name, params);
3381 else if( (wFlags & DISPATCH_PROPERTYPUT || wFlags & DISPATCH_PROPERTYPUTREF ) &&
3382 info.flags & DISPATCH_PROPERTYPUT)
3384 convertDispparamsArgs(dispidMember, wFlags, pdispparams, params );
3385 ret= doSetProperty( pdispparams, pvarResult,
3386 pexcepinfo, puArgErr, info.name, params);
3388 else if( (wFlags & DISPATCH_PROPERTYGET) && ( info.flags & DISPATCH_PROPERTYGET))
3390 ret= doGetProperty( pdispparams, pvarResult,
3391 pexcepinfo, info.name);
3393 else
3395 ret= DISP_E_MEMBERNOTFOUND;
3398 }// if( it_MemberInfo != m_idToMemberInfoMap.end() )
3399 else
3400 ret= DISP_E_MEMBERNOTFOUND;
3403 catch(const BridgeRuntimeError& e)
3405 writeExcepinfo(pexcepinfo, e.message);
3406 ret = DISP_E_EXCEPTION;
3408 catch(const Exception& e)
3410 OUString message= "UnoObjectWrapperRemoteOpt::Invoke : \n" +
3411 e.Message;
3412 writeExcepinfo(pexcepinfo, message);
3413 ret = DISP_E_EXCEPTION;
3415 catch(...)
3417 OUString message= "UnoObjectWrapperRemoteOpt::Invoke : \n"
3418 "Unexpected exception";
3419 writeExcepinfo(pexcepinfo, message);
3420 ret = DISP_E_EXCEPTION;
3423 return ret;
3426 HRESULT UnoObjectWrapperRemoteOpt::methodInvoke( DISPID /*dispidMember*/, DISPPARAMS * /*pdispparams*/, VARIANT * /*pvarResult*/,
3427 EXCEPINFO * /*pexcepinfo*/, unsigned int * /*puArgErr*/, Sequence<Any> const &)
3429 return S_OK;
3432 // The returned HRESULT is only appropriate for IDispatch::Invoke
3433 static HRESULT mapCannotConvertException(const CannotConvertException &e, unsigned int * puArgErr)
3435 HRESULT ret;
3436 bool bWriteIndex= true;
3438 switch ( e.Reason)
3440 case FailReason::OUT_OF_RANGE:
3441 ret = DISP_E_OVERFLOW;
3442 break;
3443 case FailReason::IS_NOT_NUMBER:
3444 ret = DISP_E_TYPEMISMATCH;
3445 break;
3446 case FailReason::IS_NOT_ENUM:
3447 ret = DISP_E_TYPEMISMATCH;
3448 break;
3449 case FailReason::IS_NOT_BOOL:
3450 ret = DISP_E_TYPEMISMATCH;
3451 break;
3452 case FailReason::NO_SUCH_INTERFACE:
3453 ret = DISP_E_TYPEMISMATCH;
3454 break;
3455 case FailReason::SOURCE_IS_NO_DERIVED_TYPE:
3456 ret = DISP_E_TYPEMISMATCH;
3457 break;
3458 case FailReason::TYPE_NOT_SUPPORTED:
3459 ret = DISP_E_TYPEMISMATCH;
3460 break;
3461 case FailReason::INVALID:
3462 ret = DISP_E_TYPEMISMATCH;
3463 break;
3464 case FailReason::NO_DEFAULT_AVAILABLE:
3465 ret = DISP_E_BADPARAMCOUNT;
3466 break;
3467 case FailReason::UNKNOWN:
3468 ret = E_UNEXPECTED;
3469 break;
3470 default:
3471 ret = E_UNEXPECTED;
3472 bWriteIndex= false;
3473 break;
3476 if( bWriteIndex && puArgErr != nullptr)
3477 *puArgErr = e.ArgumentIndex;
3478 return ret;
3481 // The function maps the TypeClass of the any to VARTYPE: If
3482 // the Any contains STRUCT or INTERFACE then the return value
3483 // is VT_DISPATCH. The function is used from o2u_createUnoObjectWrapper
3484 // and the result is put into the constructor of the uno - wrapper
3485 // object. If a client asks the object for DISPID_VALUE and this
3486 // function returned VT_DISPATCH then the IDispatch of the same
3487 // object is being returned.
3488 // See InterfaceOleWrapper::Invoke, InterfaceOleWrapper::m_defaultValueType
3489 VARTYPE getVarType( const Any& value)
3491 VARTYPE ret= VT_EMPTY;
3493 switch ( value.getValueTypeClass())
3495 case TypeClass_STRUCT: ret= VT_DISPATCH; break;
3496 case TypeClass_INTERFACE: ret= VT_DISPATCH; break;
3497 default: break;
3499 return ret;
3502 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */