tdf#154285 Check upper bound of arguments in SbRtl_Minute function
[LibreOffice.git] / extensions / source / ole / unoobjw.cxx
blobeada13aa63862a7344a9f3c1880cb27b92fd4a0e
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 "-Wnonportable-include-path"
45 #pragma clang diagnostic ignored "-Wsequence-point"
46 #pragma clang diagnostic ignored "-Wtypename-missing"
47 #endif
48 #include <atlbase.h>
49 #include <atlcom.h>
50 #if defined _MSC_VER && defined __clang__
51 #pragma clang diagnostic pop
52 #endif
53 #include <comdef.h>
55 #include <osl/diagnose.h>
56 #include <salhelper/simplereferenceobject.hxx>
57 #include <rtl/ref.hxx>
58 #include <rtl/ustring.hxx>
59 #include <sal/log.hxx>
60 #include <com/sun/star/beans/MethodConcept.hpp>
61 #include <com/sun/star/beans/PropertyConcept.hpp>
62 #include <com/sun/star/lang/NoSuchMethodException.hpp>
63 #include <com/sun/star/script/CannotConvertException.hpp>
64 #include <com/sun/star/script/FailReason.hpp>
65 #include <com/sun/star/reflection/theCoreReflection.hpp>
66 #include <com/sun/star/reflection/ParamInfo.hpp>
67 #include <com/sun/star/beans/XExactName.hpp>
68 #include <com/sun/star/container/NoSuchElementException.hpp>
69 #include <com/sun/star/container/XEnumeration.hpp>
70 #include <com/sun/star/container/XEnumerationAccess.hpp>
72 #include <com/sun/star/beans/XMaterialHolder.hpp>
73 #include <com/sun/star/script/XInvocation2.hpp>
74 #include <com/sun/star/script/MemberType.hpp>
75 #include <com/sun/star/reflection/XIdlReflection.hpp>
76 #include <ooo/vba/XCollection.hpp>
77 #include <ooo/vba/XConnectable.hpp>
78 #include <ooo/vba/XConnectionPoint.hpp>
79 #include <ooo/vba/XSink.hpp>
80 #include <ooo/vba/msforms/XCheckBox.hpp>
81 #include <osl/interlck.h>
82 #include <com/sun/star/uno/genfunc.h>
83 #include <comphelper/automationinvokedzone.hxx>
84 #include <comphelper/processfactory.hxx>
85 #include <comphelper/profilezone.hxx>
86 #include <comphelper/windowsdebugoutput.hxx>
87 #include <comphelper/windowserrorstring.hxx>
88 #include <o3tl/char16_t2wchar_t.hxx>
89 #include <o3tl/safeint.hxx>
90 #include <systools/win32/oleauto.hxx>
92 #include "comifaces.hxx"
93 #include "jscriptclasses.hxx"
94 #include "unotypewrapper.hxx"
95 #include "oleobjw.hxx"
96 #include "unoobjw.hxx"
97 #include "servprov.hxx"
99 using namespace osl;
100 using namespace cppu;
101 using namespace com::sun::star::uno;
102 using namespace com::sun::star::beans;
103 using namespace com::sun::star::container;
104 using namespace com::sun::star::script;
105 using namespace com::sun::star::lang;
106 using namespace com::sun::star::bridge::ModelDependent;
107 using namespace com::sun::star::reflection;
109 std::unordered_map<sal_uIntPtr, WeakReference<XInterface> > UnoObjToWrapperMap;
110 static bool writeBackOutParameter(VARIANTARG* pDest, VARIANT* pSource);
111 static bool writeBackOutParameter2( VARIANTARG* pDest, VARIANT* pSource);
112 static HRESULT mapCannotConvertException(const CannotConvertException &e, unsigned int * puArgErr);
114 /* Does not throw any exceptions.
115 Param pInfo can be NULL.
117 static void writeExcepinfo(EXCEPINFO * pInfo, const OUString& message)
119 if (pInfo != nullptr)
121 pInfo->wCode = UNO_2_OLE_EXCEPTIONCODE;
122 pInfo->bstrSource = SysAllocString(L"[automation bridge] ");
123 pInfo->bstrDescription = sal::systools::BStr::newBSTR(message);
127 InterfaceOleWrapper::InterfaceOleWrapper( Reference<XMultiServiceFactory> const & xFactory,
128 sal_uInt8 unoWrapperClass, sal_uInt8 comWrapperClass):
129 UnoConversionUtilities<InterfaceOleWrapper>( xFactory, unoWrapperClass, comWrapperClass),
130 m_defaultValueType( 0)
134 InterfaceOleWrapper::~InterfaceOleWrapper()
136 MutexGuard guard(getBridgeMutex());
137 // remove entries in global map
138 auto it = UnoObjToWrapperMap.find( reinterpret_cast<sal_uIntPtr>(m_xOrigin.get()));
139 if(it != UnoObjToWrapperMap.end())
140 UnoObjToWrapperMap.erase(it);
143 COM_DECLSPEC_NOTHROW STDMETHODIMP InterfaceOleWrapper::QueryInterface(REFIID riid, void ** ppv)
145 comphelper::Automation::AutomationInvokedZone aAutomationActive;
147 SAL_INFO("extensions.olebridge", this << "@InterfaceOleWrapper::QueryInterface(" << riid << ")");
149 HRESULT ret= S_OK;
151 if( !ppv)
152 return E_POINTER;
154 if(IsEqualIID(riid, IID_IUnknown))
156 AddRef();
157 *ppv = static_cast<IUnknown*>(static_cast<IDispatch*>(this));
158 SAL_INFO("extensions.olebridge", " " << *ppv);
160 else if (IsEqualIID(riid, IID_IDispatch))
162 AddRef();
163 *ppv = static_cast<IDispatch*>(this);
164 SAL_INFO("extensions.olebridge", " " << *ppv);
166 else if (IsEqualIID(riid, IID_IProvideClassInfo))
168 Reference<ooo::vba::XConnectable> xConnectable(m_xOrigin, UNO_QUERY);
169 if (!xConnectable.is())
170 return E_NOINTERFACE;
171 AddRef();
172 *ppv = static_cast<IProvideClassInfo*>(this);
173 SAL_INFO("extensions.olebridge", " " << *ppv);
175 else if (IsEqualIID(riid, IID_IConnectionPointContainer))
177 Reference<ooo::vba::XConnectable> xConnectable(m_xOrigin, UNO_QUERY);
178 if (!xConnectable.is())
179 return E_NOINTERFACE;
180 AddRef();
181 *ppv = static_cast<IConnectionPointContainer*>(this);
182 SAL_INFO("extensions.olebridge", " " << *ppv);
184 else if( IsEqualIID( riid, __uuidof( IUnoObjectWrapper)))
186 AddRef();
187 *ppv= static_cast<IUnoObjectWrapper*>(this);
188 SAL_INFO("extensions.olebridge", " " << *ppv);
190 else
191 ret= E_NOINTERFACE;
192 return ret;
195 COM_DECLSPEC_NOTHROW STDMETHODIMP_(ULONG) InterfaceOleWrapper::AddRef()
197 acquire();
198 // does not need to guard because one should not rely on the return value of
199 // AddRef anyway
200 return m_refCount;
203 COM_DECLSPEC_NOTHROW STDMETHODIMP_(ULONG) InterfaceOleWrapper::Release()
205 ULONG n= m_refCount;
206 release();
207 return n - 1;
210 // IUnoObjectWrapper --------------------------------------------------------
211 COM_DECLSPEC_NOTHROW STDMETHODIMP InterfaceOleWrapper::getWrapperXInterface( Reference<XInterface>* pXInt)
213 pXInt->set( static_cast<XWeak*>( this), UNO_QUERY);
214 return pXInt->is() ? S_OK : E_FAIL;
216 COM_DECLSPEC_NOTHROW STDMETHODIMP InterfaceOleWrapper::getOriginalUnoObject( Reference<XInterface>* pXInt)
218 *pXInt= m_xOrigin;
219 return m_xOrigin.is() ? S_OK : E_FAIL;
221 COM_DECLSPEC_NOTHROW STDMETHODIMP InterfaceOleWrapper::getOriginalUnoStruct( Any * pStruct)
223 comphelper::Automation::AutomationInvokedZone aAutomationActive;
225 HRESULT ret= E_FAIL;
226 if( !m_xOrigin.is())
228 Reference<XMaterialHolder> xMatHolder( m_xInvocation, UNO_QUERY);
229 if( xMatHolder.is())
231 Any any = xMatHolder->getMaterial();
232 if( any.getValueTypeClass() == TypeClass_STRUCT)
234 *pStruct= any;
235 ret= S_OK;
239 return ret;
242 COM_DECLSPEC_NOTHROW STDMETHODIMP InterfaceOleWrapper::GetTypeInfoCount( UINT *pctinfo )
244 SAL_INFO("extensions.olebridge", this << "@InterfaceOleWrapper::GetTypeInfoCount");
246 if (!pctinfo)
247 return E_POINTER;
249 *pctinfo = 1;
251 return S_OK;
254 namespace {
256 class CXTypeInfo : public ITypeInfo,
257 public CComObjectRoot
259 public:
260 enum class Kind { COCLASS, MAIN, OUTGOING };
262 #if defined __clang__
263 #pragma clang diagnostic push
264 #pragma clang diagnostic ignored "-Wunused-function"
265 #endif
266 BEGIN_COM_MAP(CXTypeInfo)
267 #if defined __clang__
268 #pragma clang diagnostic pop
269 #endif
270 COM_INTERFACE_ENTRY(ITypeInfo)
271 #if defined __clang__
272 #pragma clang diagnostic push
273 #pragma clang diagnostic ignored "-Winconsistent-missing-override"
274 #pragma clang diagnostic ignored "-Wunused-function"
275 #endif
276 END_COM_MAP()
277 #if defined __clang__
278 #pragma clang diagnostic pop
279 #endif
281 DECLARE_NOT_AGGREGATABLE(CXTypeInfo)
283 virtual ~CXTypeInfo() {}
285 void InitForCoclass(Reference<XInterface> xOrigin,
286 const OUString& sImplementationName,
287 const IID& rIID,
288 Reference<XMultiServiceFactory> xMSF);
289 void InitForClassItself(Reference<XInterface> xOrigin,
290 const OUString& sImplementationName,
291 const IID& rIID,
292 Reference<XMultiServiceFactory> xMSF);
293 void InitForOutgoing(Reference<XInterface> xOrigin,
294 const OUString& sInterfaceName,
295 const IID& rIID,
296 Reference<XMultiServiceFactory> xMSF,
297 Type aType);
298 virtual HRESULT STDMETHODCALLTYPE GetTypeAttr(TYPEATTR **ppTypeAttr) override;
299 virtual HRESULT STDMETHODCALLTYPE GetTypeComp(ITypeComp **ppTComp) override;
300 virtual HRESULT STDMETHODCALLTYPE GetFuncDesc(UINT index,
301 FUNCDESC **ppFuncDesc) override;
302 virtual HRESULT STDMETHODCALLTYPE GetVarDesc(UINT index,
303 VARDESC **ppVarDesc) override;
304 virtual HRESULT STDMETHODCALLTYPE GetNames(MEMBERID memid,
305 BSTR *rgBstrNames,
306 UINT cMaxNames,
307 UINT *pcNames) override;
308 virtual HRESULT STDMETHODCALLTYPE GetRefTypeOfImplType(UINT index,
309 HREFTYPE *pRefType) override;
310 virtual HRESULT STDMETHODCALLTYPE GetImplTypeFlags(UINT index,
311 INT *pImplTypeFlags) override;
312 virtual HRESULT STDMETHODCALLTYPE GetIDsOfNames(LPOLESTR *rgszNames,
313 UINT cNames,
314 MEMBERID *pMemId) override;
315 virtual HRESULT STDMETHODCALLTYPE Invoke(PVOID pvInstance,
316 MEMBERID memid,
317 WORD wFlags,
318 DISPPARAMS *pDispParams,
319 VARIANT *pVarResult,
320 EXCEPINFO *pExcepInfo,
321 UINT *puArgErr) override;
322 virtual HRESULT STDMETHODCALLTYPE GetDocumentation(MEMBERID memid,
323 BSTR *pBstrName,
324 BSTR *pBstrDocString,
325 DWORD *pdwHelpContext,
326 BSTR *pBstrHelpFile) override;
327 virtual HRESULT STDMETHODCALLTYPE GetDllEntry(MEMBERID memid,
328 INVOKEKIND invKind,
329 BSTR *pBstrDllName,
330 BSTR *pBstrName,
331 WORD *pwOrdinal) override;
332 virtual HRESULT STDMETHODCALLTYPE GetRefTypeInfo(HREFTYPE hRefType,
333 ITypeInfo **ppTInfo) override;
334 virtual HRESULT STDMETHODCALLTYPE AddressOfMember(MEMBERID memid,
335 INVOKEKIND invKind,
336 PVOID *ppv) override;
337 virtual HRESULT STDMETHODCALLTYPE CreateInstance(IUnknown *pUnkOuter,
338 REFIID riid,
339 PVOID *ppvObj) override;
340 virtual HRESULT STDMETHODCALLTYPE GetMops(MEMBERID memid,
341 BSTR *pBstrMops) override;
342 virtual HRESULT STDMETHODCALLTYPE GetContainingTypeLib(ITypeLib **ppTLib,
343 UINT *pIndex) override;
344 virtual void STDMETHODCALLTYPE ReleaseTypeAttr(TYPEATTR *pTypeAttr) override;
345 virtual void STDMETHODCALLTYPE ReleaseFuncDesc(FUNCDESC *pFuncDesc) override;
346 virtual void STDMETHODCALLTYPE ReleaseVarDesc(VARDESC *pVarDesc) override;
348 private:
349 Kind meKind;
350 Reference<XInterface> mxOrigin;
351 OUString msImplementationName;
352 OUString msInterfaceName;
353 IID maIID;
354 Reference<XMultiServiceFactory> mxMSF;
355 Type maType;
358 class CXTypeLib : public ITypeLib,
359 public CComObjectRoot
361 public:
362 #if defined __clang__
363 #pragma clang diagnostic push
364 #pragma clang diagnostic ignored "-Wunused-function"
365 #endif
366 BEGIN_COM_MAP(CXTypeLib)
367 #if defined __clang__
368 #pragma clang diagnostic pop
369 #endif
370 COM_INTERFACE_ENTRY(ITypeLib)
371 #if defined __clang__
372 #pragma clang diagnostic push
373 #pragma clang diagnostic ignored "-Winconsistent-missing-override"
374 #pragma clang diagnostic ignored "-Wunused-function"
375 #endif
376 END_COM_MAP()
377 #if defined __clang__
378 #pragma clang diagnostic pop
379 #endif
381 DECLARE_NOT_AGGREGATABLE(CXTypeLib)
383 virtual ~CXTypeLib() {}
385 void Init(Reference<XInterface> xOrigin,
386 const OUString& sImplementationName,
387 Reference<XMultiServiceFactory> xMSF)
389 SAL_INFO("extensions.olebridge", this << "@CXTypeLib::Init for " << sImplementationName);
390 mxOrigin = xOrigin;
391 msImplementationName = sImplementationName;
392 mxMSF = xMSF;
395 virtual UINT STDMETHODCALLTYPE GetTypeInfoCount() override
397 SAL_WARN("extensions.olebridge", this << "@CXTypeLib::GetTypeInfoCount");
398 return 1;
401 virtual HRESULT STDMETHODCALLTYPE GetTypeInfo(UINT,
402 ITypeInfo **) override
404 SAL_WARN("extensions.olebridge", this << "@CXTypeLib::GetTypeInfo: E_NOTIMPL");
405 return E_NOTIMPL;
408 virtual HRESULT STDMETHODCALLTYPE GetTypeInfoType(UINT,
409 TYPEKIND *) override
411 SAL_WARN("extensions.olebridge", this << "@CXTypeLib::GetTypeInfoType: E_NOTIMPL");
412 return E_NOTIMPL;
415 virtual HRESULT STDMETHODCALLTYPE GetTypeInfoOfGuid(REFGUID guid,
416 ITypeInfo **ppTInfo) override
418 comphelper::Automation::AutomationInvokedZone aAutomationActive;
420 SAL_INFO("extensions.olebridge", this << "@CXTypeLib::GetTypeInfoOfGuid(" << guid << ")");
421 if (!ppTInfo)
422 return E_POINTER;
424 Reference<ooo::vba::XConnectable> xConnectable(mxOrigin, UNO_QUERY);
425 if (!xConnectable.is())
426 return TYPE_E_ELEMENTNOTFOUND;
428 IID aIID;
429 if (SUCCEEDED(IIDFromString(reinterpret_cast<LPOLESTR>(xConnectable->getIID().pData->buffer), &aIID)))
431 if (IsEqualIID(guid, aIID))
433 HRESULT ret;
435 CComObject<CXTypeInfo>* pTypeInfo;
437 ret = CComObject<CXTypeInfo>::CreateInstance(&pTypeInfo);
438 if (FAILED(ret))
439 return ret;
441 pTypeInfo->AddRef();
443 pTypeInfo->InitForCoclass(mxOrigin, msImplementationName, aIID, mxMSF);
445 *ppTInfo = pTypeInfo;
447 return S_OK;
451 #if 0
452 ooo::vba::TypeAndIID aTypeAndIID = xConnectable->GetConnectionPoint();
454 IID aIID;
455 if (SUCCEEDED(IIDFromString((LPOLESTR)aTypeAndIID.IID.pData->buffer, &aIID)))
457 HRESULT ret;
459 CComObject<CXTypeInfo>* pTypeInfo;
461 ret = CComObject<CXTypeInfo>::CreateInstance(&pTypeInfo);
462 if (FAILED(ret))
463 return ret;
465 pTypeInfo->AddRef();
467 pTypeInfo->InitForOutgoing(mxOrigin, msImplementationName, aIID, mxMSF);
469 *ppTInfo = pTypeInfo;
471 return S_OK;
473 #else
474 SAL_WARN("extensions.olebridge", "Not implemented: GetTypeInfoOfGuid(" << guid << ")");
475 #endif
477 return TYPE_E_ELEMENTNOTFOUND;
481 virtual HRESULT STDMETHODCALLTYPE GetLibAttr(TLIBATTR **) override
483 SAL_WARN("extensions.olebridge", this << "@CXTypeLib::GetLibAttr: E_NOTIMPL");
484 return E_NOTIMPL;
487 virtual HRESULT STDMETHODCALLTYPE GetTypeComp(ITypeComp **) override
489 SAL_WARN("extensions.olebridge", this << "@CXTypeLib::GetTypeComp: E_NOTIMPL");
490 return E_NOTIMPL;
493 virtual HRESULT STDMETHODCALLTYPE GetDocumentation(INT,
494 BSTR *,
495 BSTR *,
496 DWORD *,
497 BSTR *) override
499 SAL_WARN("extensions.olebridge", this << "@CXTypeLib::GetDocumentation: E_NOTIMPL");
500 return E_NOTIMPL;
503 virtual HRESULT STDMETHODCALLTYPE IsName(LPOLESTR,
504 ULONG,
505 BOOL *) override
507 SAL_WARN("extensions.olebridge", this << "@CXTypeLib:IsName: E_NOTIMPL");
508 return E_NOTIMPL;
511 virtual HRESULT STDMETHODCALLTYPE FindName(LPOLESTR,
512 ULONG,
513 ITypeInfo **,
514 MEMBERID *,
515 USHORT *) override
517 SAL_WARN("extensions.olebridge", this << "@CXTypeLib::FindName: E_NOTIMPL");
518 return E_NOTIMPL;
521 virtual void STDMETHODCALLTYPE ReleaseTLibAttr(TLIBATTR *) override
523 SAL_WARN("extensions.olebridge", this << "@CXTypeLib::ReleaseTLibAttr: E_NOTIMPL");
526 private:
527 Reference<XInterface> mxOrigin;
528 OUString msImplementationName;
529 Reference<XMultiServiceFactory> mxMSF;
534 void CXTypeInfo::InitForCoclass(Reference<XInterface> xOrigin,
535 const OUString& sImplementationName,
536 const IID& rIID,
537 Reference<XMultiServiceFactory> xMSF)
539 SAL_INFO("extensions.olebridge", this << "@CXTypeInfo::InitForCoclass(" << sImplementationName << "," << rIID << ")");
540 meKind = Kind::COCLASS;
541 mxOrigin = xOrigin;
542 msImplementationName = sImplementationName;
543 maIID = rIID;
544 mxMSF = xMSF;
547 void CXTypeInfo::InitForClassItself(Reference<XInterface> xOrigin,
548 const OUString& sImplementationName,
549 const IID& rIID,
550 Reference<XMultiServiceFactory> xMSF)
552 SAL_INFO("extensions.olebridge", this << "@CXTypeInfo::InitForClassItself(" << sImplementationName << "," << rIID << ")");
553 meKind = Kind::MAIN;
554 mxOrigin = xOrigin;
555 msImplementationName = sImplementationName;
556 maIID = rIID;
557 mxMSF = xMSF;
560 void CXTypeInfo::InitForOutgoing(Reference<XInterface> xOrigin,
561 const OUString& sInterfaceName,
562 const IID& rIID,
563 Reference<XMultiServiceFactory> xMSF,
564 Type aType)
566 SAL_INFO("extensions.olebridge", this << "@CXTypeInfo::InitForOutgoing(" << sInterfaceName << "," << rIID << ")");
567 meKind = Kind::OUTGOING;
568 mxOrigin = xOrigin;
569 msInterfaceName = sInterfaceName;
570 maIID = rIID;
571 mxMSF = xMSF;
572 maType = aType;
575 HRESULT STDMETHODCALLTYPE CXTypeInfo::GetTypeAttr(TYPEATTR **ppTypeAttr)
577 comphelper::Automation::AutomationInvokedZone aAutomationActive;
579 SAL_INFO("extensions.olebridge", this << "@CXTypeInfo::GetTypeAttr");
581 if (!ppTypeAttr)
582 return E_POINTER;
584 assert(!IsEqualIID(maIID, IID_NULL));
586 TYPEATTR *pTypeAttr = new TYPEATTR;
587 memset(pTypeAttr, 0, sizeof(*pTypeAttr));
589 pTypeAttr->guid = maIID;
591 if (meKind == Kind::COCLASS)
593 pTypeAttr->typekind = TKIND_COCLASS;
594 pTypeAttr->cFuncs = 0;
595 pTypeAttr->cVars = 0;
596 pTypeAttr->cImplTypes = 3;
597 pTypeAttr->cbSizeVft = 0;
598 pTypeAttr->cbAlignment = 8;
599 pTypeAttr->wTypeFlags = TYPEFLAG_FCANCREATE;
601 else if (meKind == Kind::MAIN)
603 pTypeAttr->typekind = TKIND_DISPATCH;
604 pTypeAttr->cFuncs = 10; // FIXME, dummy
605 pTypeAttr->cVars = 0;
606 pTypeAttr->cImplTypes = 1;
607 // FIXME: I think this is always supposed to be as if just for the seven methods in
608 // IDIspatch?
609 pTypeAttr->cbSizeVft = 7 * sizeof(void*);
610 pTypeAttr->cbAlignment = 8;
611 pTypeAttr->wTypeFlags = TYPEFLAG_FHIDDEN|TYPEFLAG_FDISPATCHABLE;
613 else if (meKind == Kind::OUTGOING)
615 pTypeAttr->typekind = TKIND_DISPATCH;
617 Reference<XIdlReflection> xRefl = theCoreReflection::get(comphelper::getComponentContext(mxMSF));
618 assert(xRefl.is());
620 Reference<XIdlClass> xClass = xRefl->forName(maType.getTypeName());
621 assert(xClass.is());
623 auto aMethods = xClass->getMethods();
624 assert(xClass->getTypeClass() == TypeClass_INTERFACE &&
625 aMethods.getLength() > 0);
627 // Drop the three XInterface methods, add the three corresponding IUnknown ones plus the
628 // four IDispatch ones on top of that.
629 pTypeAttr->cFuncs = aMethods.getLength() - 3 + 3 + 4;
630 pTypeAttr->cVars = 0;
631 pTypeAttr->cImplTypes = 1;
632 // FIXME: I think this, too, is always supposed to be as if just for the seven methods in
633 // IDIspatch?
634 pTypeAttr->cbSizeVft = 7 * sizeof(void*);
635 pTypeAttr->cbAlignment = 8;
636 pTypeAttr->wTypeFlags = TYPEFLAG_FHIDDEN|TYPEFLAG_FNONEXTENSIBLE|TYPEFLAG_FDISPATCHABLE;
638 else
639 assert(false);
641 pTypeAttr->lcid = LOCALE_USER_DEFAULT;
642 pTypeAttr->memidConstructor = MEMBERID_NIL;
643 pTypeAttr->memidDestructor = MEMBERID_NIL;
644 // FIXME: Is this correct, just the vtable pointer, right?
645 pTypeAttr->cbSizeInstance = sizeof(void*);
646 pTypeAttr->wMajorVerNum = 0;
647 pTypeAttr->wMinorVerNum = 0;
648 pTypeAttr->idldescType.wIDLFlags = IDLFLAG_NONE;
650 SAL_INFO("extensions.olebridge", this << "@CXTypeInfo::GetTypeAttr: " << pTypeAttr);
652 *ppTypeAttr = pTypeAttr;
654 return S_OK;
657 HRESULT STDMETHODCALLTYPE CXTypeInfo::GetTypeComp(ITypeComp **)
659 SAL_WARN("extensions.olebridge", this << "@CXTypeInfo::GetTypeComp: E_NOTIMPL");
660 return E_NOTIMPL;
663 HRESULT STDMETHODCALLTYPE CXTypeInfo::GetFuncDesc(UINT index,
664 FUNCDESC **ppFuncDesc)
666 comphelper::Automation::AutomationInvokedZone aAutomationActive;
668 if (!ppFuncDesc)
669 return E_POINTER;
671 if (meKind != Kind::OUTGOING)
672 return E_NOTIMPL;
674 if (index <= 6)
676 *ppFuncDesc = new FUNCDESC;
677 (*ppFuncDesc)->memid = 0x60000000 + index;
678 (*ppFuncDesc)->lprgscode = nullptr;
679 (*ppFuncDesc)->lprgelemdescParam = nullptr;
680 (*ppFuncDesc)->funckind = FUNC_DISPATCH;
681 (*ppFuncDesc)->invkind = INVOKE_FUNC;
682 (*ppFuncDesc)->callconv = CC_STDCALL;
683 switch (index)
685 case 0: // QueryInterface
686 (*ppFuncDesc)->cParams = 2;
687 (*ppFuncDesc)->elemdescFunc.tdesc.lptdesc = nullptr;
688 (*ppFuncDesc)->elemdescFunc.tdesc.vt = VT_VOID;
689 break;
690 case 1: // AddRef
691 (*ppFuncDesc)->cParams = 0;
692 (*ppFuncDesc)->elemdescFunc.tdesc.lptdesc = nullptr;
693 (*ppFuncDesc)->elemdescFunc.tdesc.vt = VT_UI4;
694 break;
695 case 2: // Release
696 (*ppFuncDesc)->cParams = 1;
697 (*ppFuncDesc)->elemdescFunc.tdesc.lptdesc = nullptr;
698 (*ppFuncDesc)->elemdescFunc.tdesc.vt = VT_UI4;
699 break;
700 case 3: // GetTypeInfoCount
701 (*ppFuncDesc)->cParams = 1;
702 (*ppFuncDesc)->elemdescFunc.tdesc.lptdesc = nullptr;
703 (*ppFuncDesc)->elemdescFunc.tdesc.vt = VT_VOID;
704 break;
705 case 4: // GetTypeInfo
706 (*ppFuncDesc)->cParams = 3;
707 (*ppFuncDesc)->elemdescFunc.tdesc.lptdesc = nullptr;
708 (*ppFuncDesc)->elemdescFunc.tdesc.vt = VT_VOID;
709 break;
710 case 5: // GetIDsOfNames
711 (*ppFuncDesc)->cParams = 5;
712 (*ppFuncDesc)->elemdescFunc.tdesc.lptdesc = nullptr;
713 (*ppFuncDesc)->elemdescFunc.tdesc.vt = VT_VOID;
714 break;
715 case 6: // Invoke
716 (*ppFuncDesc)->cParams = 8;
717 (*ppFuncDesc)->elemdescFunc.tdesc.lptdesc = nullptr;
718 (*ppFuncDesc)->elemdescFunc.tdesc.vt = VT_VOID;
719 break;
721 (*ppFuncDesc)->cParamsOpt = 0;
722 (*ppFuncDesc)->oVft = index * sizeof(void*);
723 (*ppFuncDesc)->cScodes = 0;
724 (*ppFuncDesc)->wFuncFlags = FUNCFLAG_FRESTRICTED;
726 SAL_INFO("extensions.olebridge", this << "@CXTypeInfo::GetFuncDesc(" << index << "): S_OK: " << *ppFuncDesc);
728 return S_OK;
731 Reference<XIdlReflection> xRefl = theCoreReflection::get(comphelper::getComponentContext(mxMSF));
732 assert(xRefl.is());
734 Reference<XIdlClass> xClass = xRefl->forName(maType.getTypeName());
735 assert(xClass.is());
737 auto aMethods = xClass->getMethods();
738 assert(xClass->getTypeClass() == TypeClass_INTERFACE &&
739 aMethods.getLength() > 0);
741 if (index > o3tl::make_unsigned(aMethods.getLength() - 3 + 3 + 4))
742 return E_INVALIDARG;
744 *ppFuncDesc = new FUNCDESC;
746 (*ppFuncDesc)->memid = index - 6;
747 (*ppFuncDesc)->lprgscode = nullptr;
748 (*ppFuncDesc)->lprgelemdescParam = nullptr;
749 (*ppFuncDesc)->funckind = FUNC_DISPATCH;
750 (*ppFuncDesc)->invkind = INVOKE_FUNC;
751 (*ppFuncDesc)->callconv = CC_STDCALL;
752 (*ppFuncDesc)->cParams = aMethods[index - 4]->getParameterInfos().getLength();
753 (*ppFuncDesc)->cParamsOpt = 0;
754 (*ppFuncDesc)->oVft = index * sizeof(void*);
755 (*ppFuncDesc)->cScodes = 0;
756 (*ppFuncDesc)->elemdescFunc.tdesc.lptdesc = nullptr; // ???
757 (*ppFuncDesc)->elemdescFunc.tdesc.vt = VT_VOID; // ???
758 (*ppFuncDesc)->wFuncFlags = 0;
760 SAL_INFO("extensions.olebridge", this << "@CXTypeInfo::GetFuncDesc(" << index << "): S_OK: " << *ppFuncDesc);
762 return S_OK;
765 HRESULT STDMETHODCALLTYPE CXTypeInfo::GetVarDesc(UINT,
766 VARDESC **)
768 SAL_WARN("extensions.olebridge", this << "@CXTypeInfo::GetVarDesc: E_NOTIMPL");
769 return E_NOTIMPL;
772 HRESULT STDMETHODCALLTYPE CXTypeInfo::GetNames(MEMBERID memid,
773 BSTR *rgBstrNames,
774 UINT cMaxNames,
775 UINT *pcNames)
777 comphelper::Automation::AutomationInvokedZone aAutomationActive;
779 SAL_INFO("extensions.olebridge", this << "@CXTypeInfo::GetNames(" << memid << ")");
780 assert(meKind != Kind::COCLASS);
782 if (!rgBstrNames)
783 return E_POINTER;
785 if (!pcNames)
786 return E_POINTER;
788 if (memid < 1)
789 return E_INVALIDARG;
791 if (cMaxNames < 1)
792 return E_INVALIDARG;
794 if (meKind == Kind::MAIN)
796 SAL_WARN("extensions.olebridge", "GetNames() for MAIN not implemented");
797 return E_NOTIMPL;
800 Reference<XIdlReflection> xRefl = theCoreReflection::get(comphelper::getComponentContext(mxMSF));
801 assert(xRefl.is());
803 Reference<XIdlClass> xClass = xRefl->forName(maType.getTypeName());
804 assert(xClass.is());
806 auto aMethods = xClass->getMethods();
807 assert(xClass->getTypeClass() == TypeClass_INTERFACE &&
808 aMethods.getLength() > 0);
810 // Subtract the three XInterface methods. Memid for the first following method is 1.
811 if (memid > aMethods.getLength() - 3)
812 return E_INVALIDARG;
814 SAL_INFO("extensions.olebridge", "..." << this << "@CXTypeInfo::GetNames(" << memid << "): " << aMethods[memid + 2]->getName());
815 rgBstrNames[0] = sal::systools::BStr::newBSTR(aMethods[memid + 2]->getName());
816 *pcNames = 1;
818 return S_OK;
821 HRESULT STDMETHODCALLTYPE CXTypeInfo::GetRefTypeOfImplType(UINT index,
822 HREFTYPE *pRefType)
824 SAL_INFO("extensions.olebridge", this << "@CXTypeInfo::GetRefTypeOfImplType(" << index << ")");
826 if (!pRefType)
827 return E_POINTER;
829 assert(index == 0 || index == 1);
831 *pRefType = 1000+index;
833 return S_OK;
836 HRESULT STDMETHODCALLTYPE CXTypeInfo::GetImplTypeFlags(UINT index,
837 INT *pImplTypeFlags)
839 comphelper::Automation::AutomationInvokedZone aAutomationActive;
841 SAL_INFO("extensions.olebridge", this << "@CXTypeInfo::GetImplTypeFlags(" << index << ")");
843 if (!pImplTypeFlags)
844 return E_POINTER;
846 assert(meKind == Kind::COCLASS);
847 assert(index == 0 || index == 1);
849 if (index == 0)
850 *pImplTypeFlags = IMPLTYPEFLAG_FDEFAULT;
851 else if (index == 1)
852 *pImplTypeFlags = IMPLTYPEFLAG_FDEFAULT|IMPLTYPEFLAG_FSOURCE;
854 return S_OK;
857 HRESULT STDMETHODCALLTYPE CXTypeInfo::GetIDsOfNames(LPOLESTR *,
858 UINT,
859 MEMBERID *)
861 SAL_WARN("extensions.olebridge", this << "@CXTypeInfo::GetIDsOfNames: E_NOTIMPL");
862 return E_NOTIMPL;
865 HRESULT STDMETHODCALLTYPE CXTypeInfo::Invoke(PVOID,
866 MEMBERID,
867 WORD,
868 DISPPARAMS *,
869 VARIANT *,
870 EXCEPINFO *,
871 UINT *)
873 SAL_WARN("extensions.olebridge", this << "@CXTypeInfo::Invoke: E_NOTIMPL");
874 return E_NOTIMPL;
877 HRESULT STDMETHODCALLTYPE CXTypeInfo::GetDocumentation(MEMBERID memid,
878 BSTR *pBstrName,
879 BSTR *pBstrDocString,
880 DWORD *pdwHelpContext,
881 BSTR *pBstrHelpFile)
883 comphelper::Automation::AutomationInvokedZone aAutomationActive;
885 SAL_INFO("extensions.olebridge", this << "@CXTypeInfo::GetDocumentation(" << memid << ")");
887 if (pBstrName)
889 if (memid == MEMBERID_NIL)
891 *pBstrName = sal::systools::BStr::newBSTR(msImplementationName);
893 else if (memid == DISPID_VALUE)
895 // MEMBERIDs are the same as DISPIDs, apparently?
896 *pBstrName = SysAllocString(L"Value");
898 else
900 // FIXME: Shouldn't we be able to know the names of the members of UNO interfaces?
901 *pBstrName = sal::systools::BStr::newBSTR(Concat2View("UnknownNameOfMember#" + OUString::number(memid)));
904 if (pBstrDocString)
905 *pBstrDocString = SysAllocString(L"");
906 if (pdwHelpContext)
907 *pdwHelpContext = 0;
908 if (pBstrHelpFile)
909 *pBstrHelpFile = nullptr;
911 return S_OK;
914 HRESULT STDMETHODCALLTYPE CXTypeInfo::GetDllEntry(MEMBERID,
915 INVOKEKIND,
916 BSTR *,
917 BSTR *,
918 WORD *)
920 SAL_WARN("extensions.olebridge", this << "@CXTypeInfo::GetDllEntry: E_NOTIMPL");
921 return E_NOTIMPL;
924 HRESULT STDMETHODCALLTYPE CXTypeInfo::GetRefTypeInfo(HREFTYPE hRefType,
925 ITypeInfo **ppTInfo)
927 comphelper::Automation::AutomationInvokedZone aAutomationActive;
929 SAL_INFO("extensions.olebridge", this << "@CXTypeInfo::GetRefTypeInfo(" << hRefType << ")");
931 if (!ppTInfo)
932 return E_POINTER;
934 // FIXME: Is it correct to assume that the only interfaces on which GetRefTypeInfo() would be
935 // called are those that implement ooo::vba::XConnectable?
937 Reference<ooo::vba::XConnectable> xConnectable(mxOrigin, UNO_QUERY);
938 if (!xConnectable.is())
939 return E_NOTIMPL;
941 ooo::vba::TypeAndIID aTypeAndIID = xConnectable->GetConnectionPoint();
943 IID aIID;
944 if (!SUCCEEDED(IIDFromString(reinterpret_cast<LPOLESTR>(aTypeAndIID.IID.pData->buffer), &aIID)))
945 return E_NOTIMPL;
947 HRESULT ret;
949 CComObject<CXTypeInfo>* pTypeInfo;
951 ret = CComObject<CXTypeInfo>::CreateInstance(&pTypeInfo);
952 if (FAILED(ret))
953 return ret;
955 pTypeInfo->AddRef();
957 pTypeInfo->InitForOutgoing(mxOrigin, aTypeAndIID.Type.getTypeName(), aIID, mxMSF, aTypeAndIID.Type);
959 *ppTInfo = pTypeInfo;
961 return S_OK;
964 HRESULT STDMETHODCALLTYPE CXTypeInfo::AddressOfMember(MEMBERID,
965 INVOKEKIND,
966 PVOID *)
968 SAL_WARN("extensions.olebridge", this << "@CXTypeInfo::AddressOfMember: E_NOTIMPL");
969 return E_NOTIMPL;
972 HRESULT STDMETHODCALLTYPE CXTypeInfo::CreateInstance(IUnknown *,
973 REFIID,
974 PVOID *)
976 SAL_WARN("extensions.olebridge", this << "@CXTypeInfo::CreateInstance: E_NOTIMPL");
977 return E_NOTIMPL;
980 HRESULT STDMETHODCALLTYPE CXTypeInfo::GetMops(MEMBERID,
981 BSTR *)
983 SAL_WARN("extensions.olebridge", this << "@CXTypeInfo::GetMops: E_NOTIMPL");
984 return E_NOTIMPL;
987 // This is not actually called any more by my vbscript test after I added the IProvideClassInfo
988 // thing... so all the CXTypeLib stuff is dead code at the moment.
990 HRESULT STDMETHODCALLTYPE CXTypeInfo::GetContainingTypeLib(ITypeLib **ppTLib,
991 UINT *pIndex)
993 comphelper::Automation::AutomationInvokedZone aAutomationActive;
995 SAL_INFO("extensions.olebridge", this << "@CXTypeInfo::GetContainingTypeLib");
997 if (!ppTLib || !pIndex)
998 return E_POINTER;
1000 HRESULT ret;
1002 CComObject<CXTypeLib>* pTypeLib;
1004 ret = CComObject<CXTypeLib>::CreateInstance(&pTypeLib);
1005 if (FAILED(ret))
1006 return ret;
1008 pTypeLib->AddRef();
1010 pTypeLib->Init(mxOrigin, msImplementationName, mxMSF);
1012 *ppTLib = pTypeLib;
1014 return S_OK;
1017 void STDMETHODCALLTYPE CXTypeInfo::ReleaseTypeAttr(TYPEATTR *pTypeAttr)
1019 SAL_INFO("extensions.olebridge", this << "@CXTypeInfo::ReleaseTypeAttr(" << pTypeAttr << ")");
1021 delete pTypeAttr;
1024 void STDMETHODCALLTYPE CXTypeInfo::ReleaseFuncDesc(FUNCDESC *pFuncDesc)
1026 SAL_WARN("extensions.olebridge", this << "@CXTypeInfo::ReleaseFuncDesc(" << pFuncDesc << ")");
1028 delete pFuncDesc;
1031 void STDMETHODCALLTYPE CXTypeInfo::ReleaseVarDesc(VARDESC *)
1033 SAL_WARN("extensions.olebridge", this << "@CXTypeInfo::ReleaseVarDesc: E_NOTIMPL");
1036 COM_DECLSPEC_NOTHROW STDMETHODIMP InterfaceOleWrapper::GetTypeInfo(UINT iTInfo, LCID, ITypeInfo ** ppTInfo)
1038 comphelper::Automation::AutomationInvokedZone aAutomationActive;
1040 SAL_INFO("extensions.olebridge", this << "@InterfaceOleWrapper::GetTypeInfo(" << iTInfo << ")");
1042 if (!ppTInfo)
1043 return E_POINTER;
1045 if (iTInfo != 0)
1046 return E_NOTIMPL;
1048 // FIXME: This is surely incorrect. Why is being able to handle GetTypeInfo() here coupled to
1049 // being a source for outgoing events, i.e. implementing XConnectable? What would break if we
1050 // would use XInterfaceWithIID and its getIID instead?
1052 Reference<ooo::vba::XConnectable> xConnectable(m_xOrigin, UNO_QUERY);
1053 if (!xConnectable.is())
1054 return E_NOTIMPL;
1056 OUString sIID = xConnectable->GetIIDForClassItselfNotCoclass();
1057 IID aIID;
1058 if (!SUCCEEDED(IIDFromString(reinterpret_cast<LPOLESTR>(sIID.pData->buffer), &aIID)))
1059 return E_NOTIMPL;
1061 HRESULT ret;
1063 CComObject<CXTypeInfo>* pTypeInfo;
1065 ret = CComObject<CXTypeInfo>::CreateInstance(&pTypeInfo);
1066 if (FAILED(ret))
1067 return ret;
1069 pTypeInfo->AddRef();
1071 pTypeInfo->InitForClassItself(m_xOrigin, m_sImplementationName, aIID, m_smgr);
1073 *ppTInfo = pTypeInfo;
1075 return S_OK;
1078 COM_DECLSPEC_NOTHROW STDMETHODIMP InterfaceOleWrapper::GetIDsOfNames(REFIID /*riid*/,
1079 LPOLESTR * rgszNames,
1080 UINT cNames,
1081 LCID /*lcid*/,
1082 DISPID * rgdispid )
1084 comphelper::Automation::AutomationInvokedZone aAutomationActive;
1086 if( ! rgdispid)
1087 return E_POINTER;
1089 SAL_INFO("extensions.olebridge", this << "@InterfaceOleWrapper::GetIDsOfNames:");
1090 for (unsigned int i = 0; i < cNames; ++i)
1092 // Initialise returned rgdispid values.
1093 rgdispid[i] = DISPID_UNKNOWN;
1095 SAL_INFO("extensions.olebridge", " " << OUString(o3tl::toU(rgszNames[i])));
1098 HRESULT ret = DISP_E_UNKNOWNNAME;
1101 MutexGuard guard( getBridgeMutex());
1103 // FIXME: Handle the cNames > 1 case? Note that the rest of the names mean the names of *arguments*.
1105 if( ! _wcsicmp( *rgszNames, JSCRIPT_VALUE_FUNC) ||
1106 ! _wcsicmp( *rgszNames, BRIDGE_VALUE_FUNC))
1108 *rgdispid= DISPID_JSCRIPT_VALUE_FUNC;
1109 return S_OK;
1111 else if( ! _wcsicmp( *rgszNames, GET_STRUCT_FUNC) ||
1112 ! _wcsicmp( *rgszNames, BRIDGE_GET_STRUCT_FUNC))
1114 *rgdispid= DISPID_GET_STRUCT_FUNC;
1115 return S_OK;
1117 else if( ! _wcsicmp( *rgszNames, BRIDGE_CREATE_TYPE_FUNC))
1119 *rgdispid= DISPID_CREATE_TYPE_FUNC;
1120 return S_OK;
1123 if (m_xInvocation.is() && (cNames > 0))
1125 OUString name(o3tl::toU(rgszNames[0]));
1126 NameToIdMap::iterator iter = m_nameToDispIdMap.find(name);
1128 bool bIsMethod = false;
1130 OUString exactName = name;
1132 if (iter == m_nameToDispIdMap.end())
1134 if (m_xExactName.is())
1136 exactName = m_xExactName->getExactName(name);
1137 if (exactName.isEmpty())
1138 exactName = name;
1141 MemberInfo d(0, exactName);
1143 if (m_xInvocation->hasProperty(exactName))
1145 d.flags |= DISPATCH_PROPERTYGET;
1146 d.flags |= DISPATCH_PROPERTYPUT;
1147 d.flags |= DISPATCH_PROPERTYPUTREF;
1150 if (m_xInvocation->hasMethod(exactName))
1152 d.flags |= DISPATCH_METHOD;
1153 bIsMethod = true;
1156 if (d.flags != 0)
1158 m_MemberInfos.push_back(d);
1159 iter = m_nameToDispIdMap.emplace(exactName, static_cast<DISPID>(m_MemberInfos.size())).first;
1161 if (exactName != name)
1163 iter = m_nameToDispIdMap.emplace(name, static_cast<DISPID>(m_MemberInfos.size())).first;
1168 if (iter == m_nameToDispIdMap.end())
1170 ret = DISP_E_UNKNOWNNAME;
1171 SAL_INFO("extensions.olebridge", " " << name << ": UNKNOWN");
1173 else
1175 rgdispid[0] = (*iter).second;
1176 SAL_INFO("extensions.olebridge", " " << name << ": " << rgdispid[0]);
1178 if (bIsMethod && cNames > 1)
1180 Reference<XIdlMethod> xIdlMethod;
1181 Reference<XIntrospectionAccess> xIntrospectionAccess = m_xInvocation->getIntrospection();
1184 if (xIntrospectionAccess.is())
1185 xIdlMethod = xIntrospectionAccess->getMethod(exactName, MethodConcept::ALL);
1187 catch (const NoSuchMethodException&)
1190 if (xIdlMethod.is())
1192 auto aParamInfos = xIdlMethod->getParameterInfos();
1193 for (unsigned int i = 1; i < cNames; ++i)
1195 bool bFound = false;
1196 for (int j = 0; j < aParamInfos.getLength(); ++j)
1198 if (aParamInfos[j].aName.equalsIgnoreAsciiCase(o3tl::toU(rgszNames[i])))
1200 rgdispid[i] = j;
1201 bFound = true;
1202 SAL_INFO("extensions.olebridge", " " << OUString(o3tl::toU(rgszNames[i])) << ": " << rgdispid[i]);
1203 break;
1206 if (!bFound)
1207 SAL_INFO("extensions.olebridge", " " << OUString(o3tl::toU(rgszNames[i])) << ": NOT FOUND");
1212 // Return value should be S_OK only if *all* the names were found.
1213 unsigned int i;
1214 for (i = 0; i < cNames; ++i)
1215 if (rgdispid[i] == DISPID_UNKNOWN)
1216 break;
1217 if (i == cNames)
1218 ret = S_OK;
1222 catch(const BridgeRuntimeError&)
1224 OSL_ASSERT(false);
1226 catch(const Exception&)
1228 OSL_ASSERT(false);
1230 catch(...)
1232 OSL_ASSERT(false);
1235 return ret;
1238 // Note: What the comments here say about JScript possibly holds for Automation clients in general,
1239 // like VBScript ones, too. Or not. Hard to say. What is the relevance of JScript nowadays anyway,
1240 // and can LO really be used from JScript code on web pages any longer?
1242 // "convertDispparamsArgs" converts VARIANTS to their respecting Any counterparts
1243 // The parameters "id", "wFlags" and "pdispparams" equal those as used in
1244 // IDispatch::Invoke. The function handles special JavaScript
1245 // cases where a VARIANT of type VT_DISPATCH is ambiguous and could represent
1246 // an object, array ( JavaScript Array object), out parameter and in/out ( JavaScript Array object)
1247 // parameter (JavaScript Array object)
1248 // Because all those VT_DISPATCH objects need a different conversion
1249 // we have to find out what the object is supposed to be. The function does this
1250 // by either using type information or by help of a specialized ValueObject object.
1252 // A. Type Information
1254 // With the help of type information the kind of parameter can be exactly determined
1255 // and an appropriate conversion can be chosen. A problem arises if a method expects
1256 // an Any. Then the type info does not tell what the type of the value, that is kept
1257 // by the any, should be. In this situation the decision whether the param is a
1258 // sequence or an object is made upon the fact if the object has a property "0"
1259 // ( see function "isJScriptArray"). Since this is unsafe it is recommended to use
1260 // the JScript value objects within a JScript script on such an occasion.
1262 // B. JavaScript Value Object ( class JScriptValue )
1264 // A JScriptValue (ValueObject) object is a COM object in that it implements IDispatch and the
1265 // IJScriptValue object interface. Such objects are provided by all UNO wrapper
1266 // objects used within a JScript script. To obtain an instance one has to call
1267 // "_GetValueObject() or Bridge_GetValueObject()" on a UNO wrapper object (class InterfaceOleWrapper).
1268 // A value object is appropriately initialized within the script and passed as
1269 // parameter to a UNO object method or property. The convertDispparamsArgs function
1270 // can easily find out that a param is such an object by querying for the
1271 // IJScriptValue interface. By this interface one the type and kind ( out, in/out)
1272 // can be determined and the right conversion can be applied.
1273 // Using ValueObjects we spare us the effort of acquiring and examining type information
1274 // in order to figure out what the an IDispatch parameter is meant for.
1276 // Normal JScript object parameter can be mixed with JScriptValue object. If an
1277 // VARIANT contains a VT_DISPATCH that is no JScriptValue than the type information
1278 // is used to find out about the required type.
1279 void InterfaceOleWrapper::convertDispparamsArgs(DISPID id,
1280 unsigned short /*wFlags*/, DISPPARAMS* pdispparams, Sequence<Any>& rSeq)
1282 // Parameters come in reverse order in pdispparams. There might be less parameters than
1283 // expected. In that case, assume they are "optional" (but can't be marked as such in UNO IDL),
1284 // and fill in the rest with empty Anys. There might also be more than expected. In that case,
1285 // assume the oovbaapi UNO IDL hasn't kept up with added optional parameters in MSO, and just
1286 // ignore the extra ones, as long as they are empty.
1288 // An example: incoming parameters: <12, 13, "foo/bar.tem">
1290 // Expected parameters: (string filename, int something, int somethingElse, Any whatever, Any
1291 // whateverElse)
1293 // Here the existing incoming parameters are placed in reverse order in the first three outgoing
1294 // parameters, and the rest of the outgoing parameters are kept as empty Anys.
1296 // Another example: incoming parameters: <EMPTY, TRUE>
1298 // Expected parameters: (bool flag)
1300 // Here the TRUE is passed as the sole outgoing parameter, and the incoming EMPTY is ignored.
1302 // Still an example: incoming parameters: <"foo.doc", TRUE>
1304 // Expected parameters: (bool flag)
1306 // This throws an error as the incoming string parameter presumably should do something important,
1307 // but there is no corresponding outgoing parameter.
1309 HRESULT hr = S_OK;
1310 const int countIncomingArgs = pdispparams->cArgs;
1312 //Get type information for the current call
1313 InvocationInfo info;
1314 if( ! getInvocationInfoForCall( id, info))
1315 throw BridgeRuntimeError(
1316 "[automation bridge]InterfaceOleWrapper::convertDispparamsArgs \n"
1317 "Could not obtain type information for current call.");
1319 // Size rSeq according to the number of expected parameters.
1320 const int expectedArgs = info.aParamTypes.getLength() + (info.eMemberType == MemberType_PROPERTY ? 1 : 0);
1321 rSeq.realloc( expectedArgs );
1322 Any* pParams = rSeq.getArray();
1324 Any anyParam;
1326 int outgoingArgIndex = 0;
1328 // Go through incoming parameters in reverse order, i.e. in the order as declared in IDL
1329 for (int i = std::max(countIncomingArgs, expectedArgs) - 1; i >= 0; i--)
1331 // Ignore too many parameters if they are VT_EMPTY anyway
1332 if ( outgoingArgIndex >= expectedArgs && pdispparams->rgvarg[i].vt == VT_EMPTY )
1333 continue;
1335 // But otherwise too many parameters is an error
1336 if ( outgoingArgIndex >= expectedArgs )
1337 throw BridgeRuntimeError( "[automation bridge] Too many parameters" );
1339 if (info.eMemberType == MemberType_METHOD &&
1340 info.aParamModes[ outgoingArgIndex ] == ParamMode_OUT)
1342 outgoingArgIndex++;
1343 continue;
1346 if (i < countIncomingArgs)
1348 // A missing (and hopefully optional) arg (in the middle of the argument list) is passed
1349 // as an empty Any.
1350 if (pdispparams->rgvarg[i].vt == VT_ERROR && pdispparams->rgvarg[i].scode == DISP_E_PARAMNOTFOUND)
1352 Any aEmpty;
1353 pParams[ outgoingArgIndex ] = aEmpty;
1354 outgoingArgIndex++;
1355 continue;
1358 if(convertValueObject( & pdispparams->rgvarg[i], anyParam))
1359 { //a param is a ValueObject and could be converted
1360 pParams[ outgoingArgIndex ] = anyParam;
1361 outgoingArgIndex++;
1362 continue;
1365 else
1367 // A missing arg. Let's hope it is de facto optional (there is no way in UNO IDL to mark
1368 // a parameter as optional). The corresponding slot in pParams is already a void Any.
1369 // Here we don't increase outgoingArgIndex!
1370 continue;
1373 // If the param is an out, in/out parameter in
1374 // JScript (Array object, with value at index 0) then we
1375 // extract Array[0] and put the value into varParam. At the end of the loop varParam
1376 // is converted if it contains a value otherwise the VARIANT from
1377 // DISPPARAMS is converted.
1378 CComVariant varParam;
1380 // Check for JScript out and in/out paramsobjects (VT_DISPATCH).
1381 // To find them out we use typeinformation of the function being called.
1383 // No idea how this stuff, originally written for JScript, works for other Automation
1384 // clients.
1386 if( pdispparams->rgvarg[i].vt == VT_DISPATCH )
1388 if( info.eMemberType == MemberType_METHOD && info.aParamModes[ outgoingArgIndex ] == ParamMode_INOUT)
1390 // INOUT-param
1391 // Index ( property) "0" contains the actual IN-param. The object is a JScript
1392 // Array object.
1393 // Get the IN-param at index "0"
1394 IDispatch* pdisp= pdispparams->rgvarg[i].pdispVal;
1396 OLECHAR const * sindex= L"0";
1397 DISPID id2;
1398 DISPPARAMS noParams= {nullptr,nullptr,0,0};
1399 if(SUCCEEDED( hr= pdisp->GetIDsOfNames( IID_NULL, const_cast<OLECHAR **>(&sindex), 1, LOCALE_USER_DEFAULT, &id2)))
1400 hr= pdisp->Invoke( id2, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET,
1401 & noParams, & varParam, nullptr, nullptr);
1402 if( FAILED( hr))
1404 throw BridgeRuntimeError(
1405 "[automation bridge] Could not determine "
1406 "if the object has a member \"0\". Error: " +
1407 OUString::number(hr));
1412 if( varParam.vt == VT_EMPTY) // then it was no in/out parameter
1413 varParam= pdispparams->rgvarg[i];
1415 if(info.eMemberType == MemberType_METHOD)
1416 variantToAny( & varParam, anyParam,
1417 info.aParamTypes[ outgoingArgIndex ]);
1418 else if(info.eMemberType == MemberType_PROPERTY)
1419 variantToAny( & varParam, anyParam, info.aType);
1420 else
1421 OSL_ASSERT(false);
1423 if (outgoingArgIndex < expectedArgs)
1424 pParams[ outgoingArgIndex ]= anyParam;
1425 outgoingArgIndex++;
1426 }// end for / iterating over all parameters
1429 bool InterfaceOleWrapper::getInvocationInfoForCall( DISPID id, InvocationInfo& info)
1431 bool bTypesAvailable= false;
1433 if( !m_xInvocation.is() )return false;
1434 Reference<XInvocation2> inv2( m_xInvocation, UNO_QUERY);
1435 if( inv2.is())
1437 // We need the name of the property or method to get its type information.
1438 // The name can be identified through the param "id"
1439 // that is kept as value in the map m_nameToDispIdMap.
1440 // Problem: the Windows JScript engine sometimes changes small letters to capital
1441 // letters as happens in xidlclass_obj.createObject( var) // in JScript.
1442 // IDispatch::GetIdsOfNames is then called with "CreateObject" !!!
1443 // m_nameToDispIdMap can contain several names for one DISPID but only one is
1444 // the exact one. If there's no m_xExactName and therefore no exact name then
1445 // there's only one entry in the map.
1446 OUString sMemberName;
1448 auto ci1 = std::find_if(m_nameToDispIdMap.cbegin(), m_nameToDispIdMap.cend(),
1449 [&id](const NameToIdMap::value_type& nameToDispId) { return nameToDispId.second == id; }); // item is a pair<OUString, DISPID>
1450 if (ci1 != m_nameToDispIdMap.cend())
1451 sMemberName= (*ci1).first;
1452 // Get information for the current call ( property or method).
1453 // There could be similar names which only differ in the cases
1454 // of letters. First we assume that the name which was passed into
1455 // GetIDsOfNames is correct. If we won't get information with that
1456 // name then we have the invocation service use the XExactName interface.
1457 bool validInfo= true;
1458 InvocationInfo invInfo;
1459 try{
1460 invInfo= inv2->getInfoForName( sMemberName, false);
1462 catch(const IllegalArgumentException&)
1464 validInfo= false;
1467 if( ! validInfo)
1469 invInfo= inv2->getInfoForName( sMemberName, true);
1471 if( invInfo.aName.pData)
1473 bTypesAvailable= true;
1474 info= invInfo;
1477 return bTypesAvailable;
1480 // XBridgeSupplier2 ---------------------------------------------------
1481 // only bridges itself ( this instance of InterfaceOleWrapper)from UNO to IDispatch
1482 // If sourceModelType is UNO than any UNO interface implemented by InterfaceOleWrapper
1483 // can bridged to IDispatch ( if destModelType == OLE). The IDispatch is
1484 // implemented by this class.
1485 Any SAL_CALL InterfaceOleWrapper::createBridge(const Any& modelDepObject,
1486 const Sequence<sal_Int8>& /*ProcessId*/,
1487 sal_Int16 sourceModelType,
1488 sal_Int16 destModelType)
1491 Any retAny;
1492 if( sourceModelType == UNO && destModelType == OLE &&
1493 modelDepObject.getValueTypeClass() == TypeClass_INTERFACE )
1495 Reference<XInterface> xInt;
1496 if( modelDepObject >>= xInt )
1498 if( xInt == Reference<XInterface>( static_cast<XWeak*>( this), UNO_QUERY))
1500 VARIANT *pVar= static_cast<VARIANT*>(CoTaskMemAlloc( sizeof( VARIANT)));
1501 if( pVar)
1503 pVar->vt= VT_DISPATCH;
1504 pVar->pdispVal= this;
1505 AddRef();
1507 retAny<<= reinterpret_cast< sal_uIntPtr >( pVar);
1513 return retAny;
1516 // XInitialization --------------------------------------------------
1517 void SAL_CALL InterfaceOleWrapper::initialize( const Sequence< Any >& aArguments )
1519 switch( aArguments.getLength() )
1521 case 2: // the object wraps a UNO struct
1522 aArguments[0] >>= m_xInvocation;
1523 aArguments[1] >>= m_defaultValueType;
1524 break;
1525 case 3: // the object wraps a UNO interface
1526 aArguments[0] >>= m_xInvocation;
1527 aArguments[1] >>= m_xOrigin;
1528 aArguments[2] >>= m_defaultValueType;
1530 Reference<XServiceInfo> xServiceInfo(m_xOrigin, UNO_QUERY);
1531 if (xServiceInfo.is())
1532 m_sImplementationName = xServiceInfo->getImplementationName();
1534 SAL_INFO("extensions.olebridge", this << "@InterfaceOleWrapper::initialize for "
1535 << (m_sImplementationName.isEmpty()?"an unknown implementation":m_sImplementationName));
1536 break;
1539 m_xExactName.set( m_xInvocation, UNO_QUERY);
1542 Reference< XInterface > InterfaceOleWrapper::createUnoWrapperInstance()
1544 Reference<XWeak> xWeak= static_cast<XWeak*>( new InterfaceOleWrapper(
1545 m_smgr, m_nUnoWrapperClass, m_nComWrapperClass));
1546 return Reference<XInterface>( xWeak, UNO_QUERY);
1549 Reference<XInterface> InterfaceOleWrapper::createComWrapperInstance()
1551 Reference<XWeak> xWeak= static_cast<XWeak*>( new IUnknownWrapper(
1552 m_smgr, m_nUnoWrapperClass, m_nComWrapperClass));
1553 return Reference<XInterface>( xWeak, UNO_QUERY);
1556 // "getType" is used in convertValueObject to map the string denoting the type
1557 // to an actual Type object.
1558 bool getType( const BSTR name, Type & type)
1560 bool ret = false;
1561 typelib_TypeDescription * pDesc= nullptr;
1562 OUString str(o3tl::toU(name));
1563 typelib_typedescription_getByName( &pDesc, str.pData );
1564 if( pDesc)
1566 type = Type( pDesc->pWeakRef );
1567 typelib_typedescription_release( pDesc);
1568 ret = true;
1570 return ret;
1573 static bool writeBackOutParameter2( VARIANTARG* pDest, VARIANT* pSource)
1575 bool ret = false;
1576 HRESULT hr;
1578 // Handle JScriptValue objects and JScript out params ( Array object )
1579 CComVariant varDest( *pDest);
1581 if( SUCCEEDED( varDest.ChangeType(VT_DISPATCH)))
1583 CComPtr<IDispatch> spDispDest(varDest.pdispVal);
1585 // special Handling for a JScriptValue object
1586 CComQIPtr<IJScriptValueObject> spValueDest(spDispDest);
1587 if (spValueDest)
1589 VARIANT_BOOL varBool= VARIANT_FALSE;
1590 if ((SUCCEEDED(hr = spValueDest->IsOutParam(&varBool))
1591 && varBool == VARIANT_TRUE)
1592 || (SUCCEEDED(hr = spValueDest->IsInOutParam(&varBool))
1593 && varBool == VARIANT_TRUE))
1595 if( SUCCEEDED( spValueDest->Set( CComVariant(), *pSource)))
1596 ret= true;
1599 else if (pDest->vt == VT_DISPATCH)// VT_DISPATCH -> JScript out param
1601 // We use IDispatchEx because its GetDispID function causes the creation
1602 // of a property if it does not exist already. This is convenient for
1603 // out parameters in JScript. Then the user must not specify property "0"
1604 // explicitly
1605 CComQIPtr<IDispatchEx> spDispEx( spDispDest);
1606 if( spDispEx)
1608 CComBSTR nullProp(L"0");
1609 DISPID dwDispID;
1610 if( SUCCEEDED( spDispEx->GetDispID( nullProp, fdexNameEnsure, &dwDispID)))
1612 DISPPARAMS dispparams = {nullptr, nullptr, 1, 1};
1613 dispparams.rgvarg = pSource;
1614 DISPID dispidPut = DISPID_PROPERTYPUT;
1615 dispparams.rgdispidNamedArgs = &dispidPut;
1617 if (pSource->vt == VT_UNKNOWN || pSource->vt == VT_DISPATCH ||
1618 (pSource->vt & VT_ARRAY) || (pSource->vt & VT_BYREF))
1619 hr = spDispEx->InvokeEx(dwDispID, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYPUTREF,
1620 &dispparams, nullptr, nullptr, nullptr);
1621 else
1622 hr= spDispEx->InvokeEx(dwDispID, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYPUT,
1623 &dispparams, nullptr, nullptr, nullptr);
1624 if( SUCCEEDED(hr))
1625 ret= true;
1629 else
1630 ret= writeBackOutParameter( pDest, pSource);
1632 else // The param can't be a JScript out-parameter ( an Array object), it could be a VBScript
1633 { // param. The function checks itself for correct VBScript params
1634 ret= writeBackOutParameter( pDest, pSource);
1636 return ret;
1639 // VisualBasic Script passes arguments as VT_VARIANT | VT_BYREF be it in or out parameter.
1640 // Thus we are in charge of freeing an eventual value contained by the inner VARIANT
1641 // Please note: VariantCopy doesn't free a VT_BYREF value
1642 // The out parameters are expected to have always a valid type
1643 static bool writeBackOutParameter(VARIANTARG* pDest, VARIANT* pSource)
1645 HRESULT hr;
1646 bool ret = false;
1647 // Out parameter must be VT_BYREF
1648 if ((V_VT(pDest) & VT_BYREF) != 0 )
1650 VARTYPE oleTypeFlags = V_VT(pSource);
1652 // if caller accept VARIANT as out parameter, any value must be converted
1653 if (V_VT(pDest) == (VT_VARIANT | VT_BYREF))
1655 // When the user provides a VARIANT rather than a concrete type
1656 // we just copy the source to the out, in/out parameter
1657 // VT_DISPATCH, VT_UNKNOWN, VT_ARRAY, VT_BSTR in the VARIANT that
1658 // is contained in pDest are released by VariantCopy
1659 VariantCopy(V_VARIANTREF(pDest), pSource);
1660 ret = true;
1662 else
1664 // variantarg and variant must have same type
1665 if ((V_VT(pDest) & oleTypeFlags) == oleTypeFlags)
1667 if ((oleTypeFlags & VT_ARRAY) != 0)
1669 // In / Out Param
1670 if( *V_ARRAYREF(pDest) != nullptr)
1671 hr= SafeArrayCopyData( V_ARRAY(pSource), *V_ARRAYREF(pDest));
1672 else
1673 // Out Param
1674 hr= SafeArrayCopy(V_ARRAY(pSource), V_ARRAYREF(pDest));
1675 if( SUCCEEDED( hr))
1676 ret = true;
1678 else
1680 // copy base type
1681 switch (V_VT(pSource))
1683 case VT_I2:
1685 *V_I2REF(pDest) = V_I2(pSource);
1686 ret = true;
1687 break;
1689 case VT_I4:
1690 *V_I4REF(pDest) = V_I4(pSource);
1691 ret = true;
1692 break;
1693 case VT_R4:
1694 *V_R4REF(pDest) = V_R4(pSource);
1695 ret = true;
1696 break;
1697 case VT_R8:
1698 *V_R8REF(pDest) = V_R8(pSource);
1699 ret = true;
1700 break;
1701 case VT_CY:
1702 *V_CYREF(pDest) = V_CY(pSource);
1703 ret = true;
1704 break;
1705 case VT_DATE:
1706 *V_DATEREF(pDest) = V_DATE(pSource);
1707 ret = true;
1708 break;
1709 case VT_BSTR:
1710 SysFreeString( *pDest->pbstrVal);
1712 *V_BSTRREF(pDest) = SysAllocString(V_BSTR(pSource));
1713 ret = true;
1714 break;
1715 case VT_DISPATCH:
1716 if (*V_DISPATCHREF(pDest) != nullptr)
1717 (*V_DISPATCHREF(pDest))->Release();
1719 *V_DISPATCHREF(pDest) = V_DISPATCH(pSource);
1721 if (*V_DISPATCHREF(pDest) != nullptr)
1722 (*V_DISPATCHREF(pDest))->AddRef();
1724 ret = true;
1725 break;
1726 case VT_ERROR:
1727 *V_ERRORREF(pDest) = V_ERROR(pSource);
1728 ret = true;
1729 break;
1730 case VT_BOOL:
1731 *V_BOOLREF(pDest) = V_BOOL(pSource);
1732 ret = true;
1733 break;
1734 case VT_UNKNOWN:
1735 if (*V_UNKNOWNREF(pDest) != nullptr)
1736 (*V_UNKNOWNREF(pDest))->Release();
1738 *V_UNKNOWNREF(pDest) = V_UNKNOWN(pSource);
1740 if (*V_UNKNOWNREF(pDest) != nullptr)
1741 (*V_UNKNOWNREF(pDest))->AddRef();
1743 ret = true;
1744 break;
1745 case VT_I1:
1746 *V_I1REF(pDest) = V_I1(pSource);
1747 ret = true;
1748 break;
1749 case VT_UI1:
1750 *V_UI1REF(pDest) = V_UI1(pSource);
1751 ret = true;
1752 break;
1753 case VT_UI2:
1754 *V_UI2REF(pDest) = V_UI2(pSource);
1755 ret = true;
1756 break;
1757 case VT_UI4:
1758 *V_UI4REF(pDest) = V_UI4(pSource);
1759 ret = true;
1760 break;
1761 case VT_INT:
1762 *V_INTREF(pDest) = V_INT(pSource);
1763 ret = true;
1764 break;
1765 case VT_UINT:
1766 *V_UINTREF(pDest) = V_UINT(pSource);
1767 ret = true;
1768 break;
1769 case VT_DECIMAL:
1770 memcpy(pDest->pdecVal, pSource, sizeof(DECIMAL));
1771 ret = true;
1772 break;
1773 default:
1774 break;
1778 else
1780 // Handling of special cases
1781 // Destination and source types are different
1782 if( pDest->vt == (VT_BSTR | VT_BYREF)
1783 && pSource->vt == VT_I2)
1785 // When the user provides a String as out our in/out parameter
1786 // and the type is char (TypeClass_CHAR) then we convert to a BSTR
1787 // instead of VT_I2 as is done otherwise
1788 OLECHAR buff[]= {0,0};
1789 buff[0]= pSource->iVal;
1791 SysFreeString( *pDest->pbstrVal);
1792 *pDest->pbstrVal= SysAllocString( buff);
1793 ret = true;
1798 return ret;
1801 COM_DECLSPEC_NOTHROW STDMETHODIMP InterfaceOleWrapper::Invoke(DISPID dispidMember,
1802 REFIID /*riid*/,
1803 LCID /*lcid*/,
1804 WORD wFlags,
1805 DISPPARAMS * pdispparams,
1806 VARIANT * pvarResult,
1807 EXCEPINFO * pexcepinfo,
1808 UINT * puArgErr )
1810 comphelper::Automation::AutomationInvokedZone aAutomationActive;
1812 OUString sParams;
1813 #if defined SAL_LOG_INFO
1814 sParams += "[";
1815 for (unsigned int i = 0; i < pdispparams->cArgs; ++i)
1817 if (i > 0)
1818 sParams += ",";
1819 std::stringstream aStringStream;
1820 aStringStream << pdispparams->rgvarg[i];
1821 sParams += OUString::createFromAscii(aStringStream.str());
1823 sParams += "]";
1824 #endif
1825 SAL_INFO("extensions.olebridge", this << "@InterfaceOleWrapper::Invoke(" << dispidMember << "," << sParams << ")");
1827 comphelper::ProfileZone aZone("COM Bridge");
1828 HRESULT ret = S_OK;
1832 bool bHandled= false;
1833 ret= InvokeGeneral( dispidMember, wFlags, pdispparams, pvarResult, pexcepinfo,
1834 puArgErr, bHandled);
1835 if( bHandled)
1836 return ret;
1838 if ((dispidMember > 0) && (o3tl::make_unsigned(dispidMember) <= m_MemberInfos.size()) && m_xInvocation.is())
1840 MemberInfo d = m_MemberInfos[dispidMember - 1];
1841 DWORD flags = wFlags & d.flags;
1843 if (flags != 0)
1845 if ((flags & DISPATCH_METHOD) != 0)
1847 std::unique_ptr<DISPPARAMS> pNewDispParams;
1848 std::vector<VARIANTARG> vNewArgs;
1850 if (pdispparams->cNamedArgs > 0)
1852 // Convert named arguments to positional ones.
1854 // An example:
1856 // Function declaration (in pseudo-code):
1857 // int foo(int A, int B, optional int C, optional int D, optional int E, optional int F, optional int G)
1859 // Corresponding parameter numbers (DISPIDs):
1860 // 0 1 2 3 4 5 6
1862 // Actual call:
1863 // foo(10, 20, E:=50, D:=40, F:=60)
1865 // That is, A and B are passed positionally, D, E, and F as named arguments,
1866 // and the optional C and G parameters are left out.
1868 // Incoming DISPPARAMS:
1869 // cArgs=5, cNamedArgs=3
1870 // rgvarg: [60, 40, 50, 20, 10]
1871 // rgdispidNamedArgs: [5, 3, 4]
1873 // We calculate nLowestNamedArgDispid = 3 and nHighestNamedArgDispid = 5.
1875 // Result of conversion, no named args:
1876 // cArgs=6, cNamedArgs=0
1877 // rgvarg: [60, 50, 40, DISP_E_PARAMNOTFOUND, 20, 10]
1879 // First find the lowest and highest DISPID of the named arguments.
1880 DISPID nLowestNamedArgDispid = 1000000;
1881 DISPID nHighestNamedArgDispid = -1;
1882 for (unsigned int i = 0; i < pdispparams->cNamedArgs; ++i)
1884 if (pdispparams->rgdispidNamedArgs[i] < nLowestNamedArgDispid)
1885 nLowestNamedArgDispid = pdispparams->rgdispidNamedArgs[i];
1886 if (pdispparams->rgdispidNamedArgs[i] > nHighestNamedArgDispid)
1887 nHighestNamedArgDispid = pdispparams->rgdispidNamedArgs[i];
1890 // Make sure named arguments don't overlap with positional ones. The lowest
1891 // DISPID of the named arguments should be >= the number of positional
1892 // arguments.
1893 if (nLowestNamedArgDispid < static_cast<DISPID>(pdispparams->cArgs - pdispparams->cNamedArgs))
1894 return DISP_E_NONAMEDARGS;
1896 // Do the actual conversion.
1897 pNewDispParams.reset(new DISPPARAMS);
1898 vNewArgs.resize(nHighestNamedArgDispid + 1);
1899 pNewDispParams->rgvarg = vNewArgs.data();
1900 pNewDispParams->rgdispidNamedArgs = nullptr;
1901 pNewDispParams->cArgs = nHighestNamedArgDispid + 1;
1902 pNewDispParams->cNamedArgs = 0;
1904 // Initialise all parameter slots as missing
1905 for (int i = 0; i < nHighestNamedArgDispid; ++i)
1907 pNewDispParams->rgvarg[i].vt = VT_ERROR;
1908 pNewDispParams->rgvarg[i].scode = DISP_E_PARAMNOTFOUND;
1911 // Then set the value of those actually present.
1912 for (unsigned int i = 0; i < pdispparams->cNamedArgs; ++i)
1913 pNewDispParams->rgvarg[nHighestNamedArgDispid - pdispparams->rgdispidNamedArgs[i]] = pdispparams->rgvarg[i];
1915 const int nFirstUnnamedArg = pdispparams->cNamedArgs + (nLowestNamedArgDispid-(pdispparams->cArgs - pdispparams->cNamedArgs));
1917 for (unsigned int i = pdispparams->cNamedArgs; i < pdispparams->cArgs; ++i)
1918 pNewDispParams->rgvarg[nFirstUnnamedArg + (i-pdispparams->cNamedArgs)] = pdispparams->rgvarg[i];
1920 pdispparams = pNewDispParams.get();
1923 Sequence<Any> params;
1925 convertDispparamsArgs(dispidMember, wFlags, pdispparams , params );
1927 ret= doInvoke(pdispparams, pvarResult,
1928 pexcepinfo, puArgErr, d.name, params);
1930 else if ((flags & DISPATCH_PROPERTYGET) != 0)
1932 ret= doGetProperty( pdispparams, pvarResult,
1933 pexcepinfo, d.name);
1935 else if ((flags & DISPATCH_PROPERTYPUT) != 0 || (flags & DISPATCH_PROPERTYPUTREF) != 0)
1937 if (pdispparams->cArgs != 1)
1938 ret = DISP_E_BADPARAMCOUNT;
1939 else
1941 Sequence<Any> params;
1942 convertDispparamsArgs(dispidMember, wFlags, pdispparams, params );
1943 if(params.getLength() > 0)
1944 ret= doSetProperty( pdispparams, pvarResult, pexcepinfo, puArgErr, d.name, params);
1945 else
1946 ret = DISP_E_BADVARTYPE;
1950 else
1951 ret= DISP_E_MEMBERNOTFOUND;
1953 else
1954 ret = DISP_E_MEMBERNOTFOUND;
1956 catch(const BridgeRuntimeError& e)
1958 writeExcepinfo(pexcepinfo, e.message);
1959 ret = DISP_E_EXCEPTION;
1961 catch(const Exception& e)
1963 OUString message= "InterfaceOleWrapper::Invoke : \n" +
1964 e.Message;
1965 writeExcepinfo(pexcepinfo, message);
1966 ret = DISP_E_EXCEPTION;
1968 catch(...)
1970 writeExcepinfo(pexcepinfo, "InterfaceOleWrapper::Invoke : \nUnexpected exception");
1971 ret = DISP_E_EXCEPTION;
1974 return ret;
1977 HRESULT InterfaceOleWrapper::doInvoke( DISPPARAMS * pdispparams, VARIANT * pvarResult,
1978 EXCEPINFO * pexcepinfo, unsigned int * puArgErr, OUString& name, Sequence<Any>& params)
1982 HRESULT ret= S_OK;
1985 Sequence<sal_Int16> outIndex;
1986 Sequence<Any> outParams;
1987 Any returnValue;
1989 if (pdispparams->cNamedArgs > 0)
1990 return DISP_E_NONAMEDARGS;
1992 // invoke method and take care of exceptions
1993 returnValue = m_xInvocation->invoke(name,
1994 params,
1995 outIndex,
1996 outParams);
1998 // try to write back out parameter
1999 if (outIndex.getLength() > 0)
2001 const sal_Int16* pOutIndex = outIndex.getConstArray();
2002 const Any* pOutParams = outParams.getConstArray();
2004 for (sal_Int32 i = 0; i < outIndex.getLength(); i++)
2006 CComVariant variant;
2007 // Currently a Sequence is converted to an SafeArray of VARIANTs.
2008 anyToVariant( &variant, pOutParams[i]);
2010 // out parameter need special handling if they are VT_DISPATCH
2011 // and used in JScript
2012 int outindex= pOutIndex[i];
2013 writeBackOutParameter2(&(pdispparams->rgvarg[pdispparams->cArgs - 1 - outindex]),
2014 &variant );
2018 // write back return value
2019 if (pvarResult != nullptr)
2020 anyToVariant(pvarResult, returnValue);
2022 catch(const IllegalArgumentException & e) //XInvocation::invoke
2024 writeExcepinfo(pexcepinfo, e.Message);
2025 ret = DISP_E_TYPEMISMATCH;
2027 catch(const CannotConvertException & e) //XInvocation::invoke
2029 writeExcepinfo(pexcepinfo, e.Message);
2030 ret = mapCannotConvertException( e, puArgErr);
2032 catch(const InvocationTargetException & e) //XInvocation::invoke
2034 const Any& org = e.TargetException;
2035 Exception excTarget;
2036 org >>= excTarget;
2037 OUString message=
2038 org.getValueTypeName() + ": " + excTarget.Message;
2039 writeExcepinfo(pexcepinfo, message);
2040 ret = DISP_E_EXCEPTION;
2042 catch(const NoSuchMethodException & e) //XInvocation::invoke
2044 writeExcepinfo(pexcepinfo, e.Message);
2045 ret = DISP_E_MEMBERNOTFOUND;
2047 catch(const BridgeRuntimeError & e)
2049 writeExcepinfo(pexcepinfo, e.message);
2050 ret = DISP_E_EXCEPTION;
2052 catch(const Exception & e)
2054 OUString message= "InterfaceOleWrapper::doInvoke : \n" +
2055 e.Message;
2056 writeExcepinfo(pexcepinfo, message);
2057 ret = DISP_E_EXCEPTION;
2059 catch( ... )
2061 writeExcepinfo(pexcepinfo, "InterfaceOleWrapper::doInvoke : \nUnexpected exception");
2062 ret = DISP_E_EXCEPTION;
2064 return ret;
2067 HRESULT InterfaceOleWrapper::doGetProperty( DISPPARAMS * /*pdispparams*/, VARIANT * pvarResult,
2068 EXCEPINFO * pexcepinfo, OUString& name)
2070 HRESULT ret= S_OK;
2074 Any returnValue = m_xInvocation->getValue( name);
2075 // write back return value
2076 if (pvarResult)
2077 anyToVariant(pvarResult, returnValue);
2079 catch(const UnknownPropertyException& e) //XInvocation::getValue
2081 writeExcepinfo(pexcepinfo, e.Message);
2082 ret = DISP_E_MEMBERNOTFOUND;
2084 catch(const BridgeRuntimeError& e)
2086 writeExcepinfo(pexcepinfo, e.message);
2087 ret = DISP_E_EXCEPTION;
2089 catch(const Exception& e)
2091 OUString message= "InterfaceOleWrapper::doGetProperty : \n" +
2092 e.Message;
2093 writeExcepinfo(pexcepinfo, message);
2095 catch( ... )
2097 writeExcepinfo(pexcepinfo, "InterfaceOleWrapper::doInvoke : \nUnexpected exception");
2098 ret = DISP_E_EXCEPTION;
2100 return ret;
2103 HRESULT InterfaceOleWrapper::doSetProperty( DISPPARAMS * /*pdispparams*/, VARIANT * /*pvarResult*/,
2104 EXCEPINFO * pexcepinfo, unsigned int * puArgErr, OUString& name, Sequence<Any> const & params)
2106 HRESULT ret= S_OK;
2110 m_xInvocation->setValue( name, params.getConstArray()[0]);
2112 catch(const UnknownPropertyException &)
2114 ret = DISP_E_MEMBERNOTFOUND;
2116 catch(const CannotConvertException &e)
2118 ret= mapCannotConvertException( e, puArgErr);
2120 catch(const InvocationTargetException &e)
2122 if (pexcepinfo != nullptr)
2124 Any org = e.TargetException;
2126 pexcepinfo->wCode = UNO_2_OLE_EXCEPTIONCODE;
2127 pexcepinfo->bstrSource = SysAllocString(L"any ONE component");
2128 pexcepinfo->bstrDescription = SysAllocString(
2129 o3tl::toW(org.getValueTypeName().getStr()));
2131 ret = DISP_E_EXCEPTION;
2133 catch( ... )
2135 ret= DISP_E_EXCEPTION;
2137 return ret;
2140 namespace {
2142 class CXEnumVariant : public IEnumVARIANT,
2143 public CComObjectRoot
2145 public:
2146 CXEnumVariant()
2147 : mnIndex(1) // ooo::vba::XCollection index starts at one
2151 virtual ~CXEnumVariant()
2155 #if defined __clang__
2156 #pragma clang diagnostic push
2157 #pragma clang diagnostic ignored "-Wunused-function"
2158 #endif
2159 BEGIN_COM_MAP(CXEnumVariant)
2160 #if defined __clang__
2161 #pragma clang diagnostic pop
2162 #endif
2163 COM_INTERFACE_ENTRY(IEnumVARIANT)
2164 #if defined __clang__
2165 #pragma clang diagnostic push
2166 #pragma clang diagnostic ignored "-Winconsistent-missing-override"
2167 #pragma clang diagnostic ignored "-Wunused-function"
2168 #endif
2169 END_COM_MAP()
2170 #if defined __clang__
2171 #pragma clang diagnostic pop
2172 #endif
2174 DECLARE_NOT_AGGREGATABLE(CXEnumVariant)
2176 // Creates and initializes the enumerator
2177 void Init(InterfaceOleWrapper* pInterfaceOleWrapper,
2178 const Reference<ooo::vba::XCollection > xCollection)
2180 mpInterfaceOleWrapper = pInterfaceOleWrapper;
2181 mxCollection = xCollection;
2184 // IEnumVARIANT
2185 virtual HRESULT STDMETHODCALLTYPE Clone(IEnumVARIANT **) override
2187 SAL_INFO("extensions.olebridge", this << "@CXEnumVariant::Clone: E_NOTIMPL");
2188 return E_NOTIMPL;
2191 virtual HRESULT STDMETHODCALLTYPE Next(ULONG const celt,
2192 VARIANT *rgVar,
2193 ULONG *pCeltFetched) override
2195 comphelper::Automation::AutomationInvokedZone aAutomationActive;
2197 if (pCeltFetched)
2198 *pCeltFetched = 0;
2200 if (celt == 0)
2202 SAL_INFO("extensions.olebridge", this << "@CXEnumVariant::Next(" << celt << "): E_INVALIDARG");
2203 return E_INVALIDARG;
2206 if (rgVar == nullptr || (celt != 1 && pCeltFetched == nullptr))
2208 SAL_INFO("extensions.olebridge", this << "@CXEnumVariant::Next(" << celt << "): E_FAIL");
2209 return E_FAIL;
2212 for (ULONG i = 0; i < celt; i++)
2213 VariantInit(&rgVar[i]);
2215 ULONG nLeft = celt;
2216 ULONG nReturned = 0;
2217 while (nLeft > 0)
2219 if (mnIndex > mxCollection->getCount())
2221 SAL_INFO("extensions.olebridge", this << "@CXEnumVariant::Next(" << celt << "): got " << nReturned << ": S_FALSE");
2222 return S_FALSE;
2224 Any aIndex;
2225 aIndex <<= mnIndex;
2226 Any aElement = mxCollection->Item(aIndex, Any());
2227 mpInterfaceOleWrapper->anyToVariant(rgVar, aElement);
2228 // rgVar->pdispVal->AddRef(); ??
2229 if (pCeltFetched)
2230 (*pCeltFetched)++;
2231 rgVar++;
2232 nReturned++;
2233 mnIndex++;
2234 nLeft--;
2236 SAL_INFO("extensions.olebridge", this << "@CXEnumVariant::Next(" << celt << "): S_OK");
2237 return S_OK;
2240 virtual HRESULT STDMETHODCALLTYPE Reset() override
2242 SAL_INFO("extensions.olebridge", this << "@CXEnumVariant::Reset: S_OK");
2243 mnIndex = 1;
2244 return S_OK;
2247 virtual HRESULT STDMETHODCALLTYPE STDMETHODCALLTYPE Skip(ULONG const celt) override
2249 comphelper::Automation::AutomationInvokedZone aAutomationActive;
2251 ULONG nLeft = celt;
2252 ULONG nSkipped = 0;
2253 while (nLeft > 0)
2255 if (mnIndex > mxCollection->getCount())
2257 SAL_INFO("extensions.olebridge", this << "@CXEnumVariant::Skip(" << celt << "): skipped " << nSkipped << ": S_FALSE");
2258 return S_FALSE;
2260 mnIndex++;
2261 nLeft--;
2263 SAL_INFO("extensions.olebridge", this << "@CXEnumVariant::Skip(" << celt << "): S_OK");
2264 return S_OK;
2267 private:
2268 InterfaceOleWrapper* mpInterfaceOleWrapper;
2269 Reference<ooo::vba::XCollection> mxCollection;
2270 sal_Int32 mnIndex;
2273 class Sink : public cppu::WeakImplHelper<ooo::vba::XSink>
2275 public:
2276 Sink(IUnknown* pUnkSink,
2277 Reference<XMultiServiceFactory> xMSF,
2278 ooo::vba::TypeAndIID aTypeAndIID,
2279 InterfaceOleWrapper* pInterfaceOleWrapper);
2281 // XSink
2282 void SAL_CALL Call( const OUString& Method, Sequence< Any >& Arguments ) override;
2284 private:
2285 IUnknown* mpUnkSink;
2286 Reference<XMultiServiceFactory> mxMSF;
2287 ooo::vba::TypeAndIID maTypeAndIID;
2288 InterfaceOleWrapper* mpInterfaceOleWrapper;
2293 Sink::Sink(IUnknown* pUnkSink,
2294 Reference<XMultiServiceFactory> xMSF,
2295 ooo::vba::TypeAndIID aTypeAndIID,
2296 InterfaceOleWrapper* pInterfaceOleWrapper) :
2297 mpUnkSink(pUnkSink),
2298 mxMSF(xMSF),
2299 maTypeAndIID(aTypeAndIID),
2300 mpInterfaceOleWrapper(pInterfaceOleWrapper)
2302 mpUnkSink->AddRef();
2305 void SAL_CALL
2306 Sink::Call( const OUString& Method, Sequence< Any >& Arguments )
2308 SAL_INFO("extensions.olebridge", "Sink::Call(" << Method << ", " << Arguments.getLength() << " arguments)");
2310 IDispatch* pDispatch;
2311 HRESULT nResult = mpUnkSink->QueryInterface(IID_IDispatch, reinterpret_cast<void **>(&pDispatch));
2312 if (!SUCCEEDED(nResult))
2314 SAL_WARN("extensions.olebridge", "Sink::Call: Not IDispatch: " << WindowsErrorStringFromHRESULT(nResult));
2315 return;
2318 Reference<XIdlReflection> xRefl = theCoreReflection::get(comphelper::getComponentContext(mxMSF));
2319 assert(xRefl.is());
2321 Reference<XIdlClass> xClass = xRefl->forName(maTypeAndIID.Type.getTypeName());
2322 assert(xClass.is());
2324 auto aMethods = xClass->getMethods();
2325 assert(xClass->getTypeClass() == TypeClass_INTERFACE &&
2326 aMethods.getLength() > 0);
2328 int nMemId = 1;
2329 auto ArgumentsRange = asNonConstRange(Arguments);
2330 // Skip the three XInterface methods
2331 for (int i = 3; i < aMethods.getLength(); i++)
2333 if (aMethods[i]->getName() == Method)
2335 // FIXME: Handle mismatch in type of actual argument and parameter of the method.
2337 // FIXME: Handle mismatch in number of arguments passed and actual number of parameters
2338 // of the method.
2340 auto aParamInfos = aMethods[i]->getParameterInfos();
2342 assert(Arguments.getLength() == aParamInfos.getLength());
2344 DISPPARAMS aDispParams;
2345 aDispParams.rgdispidNamedArgs = nullptr;
2346 aDispParams.cArgs = Arguments.getLength();
2347 aDispParams.cNamedArgs = 0;
2348 aDispParams.rgvarg = new VARIANT[aDispParams.cArgs];
2349 for (unsigned j = 0; j < aDispParams.cArgs; j++)
2351 VariantInit(aDispParams.rgvarg+j);
2352 // Note: Reverse order of arguments in Arguments and aDispParams.rgvarg!
2353 const unsigned nIncomingArgIndex = aDispParams.cArgs - j - 1;
2354 mpInterfaceOleWrapper->anyToVariant(aDispParams.rgvarg+j, Arguments[nIncomingArgIndex]);
2356 // Handle OUT and INOUT arguments. For instance, the second ('Cancel') parameter to
2357 // DocumentBeforeClose() should be a VT_BYREF|VT_BOOL parameter. Need to handle that
2358 // here.
2360 if (aParamInfos[nIncomingArgIndex].aMode == ParamMode_OUT ||
2361 aParamInfos[nIncomingArgIndex].aMode == ParamMode_INOUT)
2363 switch (aDispParams.rgvarg[j].vt)
2365 case VT_I2:
2366 aDispParams.rgvarg[j].byref = new SHORT(aDispParams.rgvarg[j].iVal);
2367 aDispParams.rgvarg[j].vt |= VT_BYREF;
2368 break;
2369 case VT_I4:
2370 aDispParams.rgvarg[j].byref = new LONG(aDispParams.rgvarg[j].lVal);
2371 aDispParams.rgvarg[j].vt |= VT_BYREF;
2372 break;
2373 case VT_BSTR:
2374 aDispParams.rgvarg[j].byref = new BSTR(aDispParams.rgvarg[j].bstrVal);
2375 aDispParams.rgvarg[j].vt |= VT_BYREF;
2376 break;
2377 case VT_BOOL:
2378 aDispParams.rgvarg[j].byref = new VARIANT_BOOL(aDispParams.rgvarg[j].boolVal);
2379 aDispParams.rgvarg[j].vt |= VT_BYREF;
2380 break;
2381 default:
2382 assert(false && "Not handled yet");
2383 break;
2388 VARIANT aVarResult;
2389 VariantInit(&aVarResult);
2390 UINT uArgErr;
2392 // In the case of a VBScript client, which uses "late binding", calling Invoke on the
2393 // sink it provides will cause a callback to our CXTypeInfo::GetNames for the given
2394 // member id, and in that we will tell it the name of the corresponding method, and the
2395 // client will know what event handler to invoke based on that name.
2397 // As the outgoing interfaces used (ooo::vba::word::XApplicationOutgoing and others) are
2398 // totally not stable and not published in any way, there can be no client that would
2399 // have done "compile-time binding" and where the sink would actually be an object with
2400 // a vtbl corresponding to the outgoing interface. Late binding clients that work like
2401 // VBScript is all we support.
2402 SAL_INFO("extensions.olebridge", "Sink::Call(" << Method << "): Calling Invoke(" << nMemId << ")");
2404 nResult = pDispatch->Invoke(nMemId, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &aDispParams, &aVarResult, nullptr, &uArgErr);
2405 SAL_INFO("extensions.olebridge", "Sink::Call(" << Method << "): Invoke() returned");
2407 SAL_WARN_IF(!SUCCEEDED(nResult), "extensions.olebridge", "Call to " << Method << " failed: " << WindowsErrorStringFromHRESULT(nResult));
2409 // Undo VT_BYREF magic done above. Copy out parameters back to the Anys in Arguments
2410 for (unsigned j = 0; j < aDispParams.cArgs; j++)
2412 const unsigned nIncomingArgIndex = aDispParams.cArgs - j - 1;
2413 if (aParamInfos[nIncomingArgIndex].aMode == ParamMode_OUT ||
2414 aParamInfos[nIncomingArgIndex].aMode == ParamMode_INOUT)
2416 switch (aDispParams.rgvarg[j].vt)
2418 case VT_BYREF|VT_I2:
2420 SHORT *pI = static_cast<SHORT*>(aDispParams.rgvarg[j].byref);
2421 ArgumentsRange[nIncomingArgIndex] <<= static_cast<sal_Int16>(*pI);
2422 delete pI;
2424 break;
2425 case VT_BYREF|VT_I4:
2427 LONG *pL = static_cast<LONG*>(aDispParams.rgvarg[j].byref);
2428 ArgumentsRange[nIncomingArgIndex] <<= static_cast<sal_Int32>(*pL);
2429 delete pL;
2431 break;
2432 case VT_BYREF|VT_BSTR:
2434 BSTR *pBstr = static_cast<BSTR*>(aDispParams.rgvarg[j].byref);
2435 ArgumentsRange[nIncomingArgIndex] <<= OUString(o3tl::toU(*pBstr));
2436 // Undo SysAllocString() done in anyToVariant()
2437 SysFreeString(*pBstr);
2438 delete pBstr;
2440 break;
2441 case VT_BYREF|VT_BOOL:
2443 VARIANT_BOOL *pBool = static_cast<VARIANT_BOOL*>(aDispParams.rgvarg[j].byref);
2444 ArgumentsRange[nIncomingArgIndex] <<= (*pBool != VARIANT_FALSE);
2445 delete pBool;
2447 break;
2448 default:
2449 assert(false && "Not handled yet");
2450 break;
2453 else
2455 switch (aDispParams.rgvarg[j].vt)
2457 case VT_BSTR:
2458 // Undo SysAllocString() done in anyToVariant()
2459 SysFreeString(aDispParams.rgvarg[j].bstrVal);
2460 break;
2465 delete[] aDispParams.rgvarg;
2466 return;
2468 nMemId++;
2470 SAL_WARN("extensions.olebridge", "Sink::Call: Unknown method '" << Method << "'");
2473 namespace {
2475 class CXEnumConnections : public IEnumConnections,
2476 public CComObjectRoot
2478 public:
2479 CXEnumConnections()
2483 virtual ~CXEnumConnections()
2487 #if defined __clang__
2488 #pragma clang diagnostic push
2489 #pragma clang diagnostic ignored "-Wunused-function"
2490 #endif
2491 BEGIN_COM_MAP(CXEnumConnections)
2492 #if defined __clang__
2493 #pragma clang diagnostic pop
2494 #endif
2495 COM_INTERFACE_ENTRY(IEnumConnections)
2496 #if defined __clang__
2497 #pragma clang diagnostic push
2498 #pragma clang diagnostic ignored "-Winconsistent-missing-override"
2499 #pragma clang diagnostic ignored "-Wunused-function"
2500 #endif
2501 END_COM_MAP()
2502 #if defined __clang__
2503 #pragma clang diagnostic pop
2504 #endif
2506 DECLARE_NOT_AGGREGATABLE(CXEnumConnections)
2508 void Init(std::vector<IUnknown*>& rUnknowns, std::vector<DWORD>& rCookies)
2510 SAL_INFO("extensions.olebridge", this << "@CXEnumConnections::Init");
2511 SAL_WARN_IF(rUnknowns.size() != rCookies.size(), "extensions.olebridge", "Vectors of different size");
2512 mvUnknowns = rUnknowns;
2513 mvCookies = rCookies;
2514 mnIndex = 0;
2517 virtual HRESULT STDMETHODCALLTYPE Next(ULONG cConnections,
2518 LPCONNECTDATA rgcd,
2519 ULONG *pcFetched) override
2521 comphelper::Automation::AutomationInvokedZone aAutomationActive;
2523 if (!rgcd)
2525 SAL_INFO("extensions.olebridge", this << "@CXEnumConnections::Next(" << cConnections << "): E_POINTER");
2526 return E_POINTER;
2529 if (pcFetched && cConnections != 1)
2531 SAL_INFO("extensions.olebridge", this << "@CXEnumConnections::Next(" << cConnections << "): E_INVALIDARG");
2532 return E_INVALIDARG;
2535 ULONG nFetched = 0;
2536 while (nFetched < cConnections && mnIndex < mvUnknowns.size())
2538 rgcd[nFetched].pUnk = mvUnknowns[mnIndex];
2539 rgcd[nFetched].pUnk->AddRef();
2540 rgcd[nFetched].dwCookie = mvCookies[mnIndex];
2541 ++nFetched;
2542 ++mnIndex;
2544 if (nFetched != cConnections)
2546 SAL_INFO("extensions.olebridge", this << "@CXEnumConnections::Next(" << cConnections << "): S_FALSE");
2547 if (pcFetched)
2548 *pcFetched = nFetched;
2549 return S_FALSE;
2551 SAL_INFO("extensions.olebridge", this << "@CXEnumConnections::Next(" << cConnections << "): S_OK");
2552 if (pcFetched)
2553 *pcFetched = nFetched;
2555 return S_OK;
2558 virtual HRESULT STDMETHODCALLTYPE Skip(ULONG cConnections) override
2560 SAL_INFO("extensions.olebridge", this << "@CXEnumConnections::Skip(" << cConnections << "): E_NOTIMPL");
2562 return E_NOTIMPL;
2565 virtual HRESULT STDMETHODCALLTYPE Reset() override
2567 SAL_INFO("extensions.olebridge", this << "@CXEnumConnections::Reset: E_NOTIMPL");
2569 return E_NOTIMPL;
2572 virtual HRESULT STDMETHODCALLTYPE Clone(IEnumConnections** /* ppEnum */) override
2574 SAL_INFO("extensions.olebridge", this << "@CXEnumConnections::Clone: E_NOTIMPL");
2576 return E_NOTIMPL;
2579 private:
2580 std::vector<IUnknown*> mvUnknowns;
2581 std::vector<DWORD> mvCookies;
2582 ULONG mnIndex;
2585 class CXConnectionPoint : public IConnectionPoint,
2586 public CComObjectRoot
2588 public:
2589 #if defined __clang__
2590 #pragma clang diagnostic push
2591 #pragma clang diagnostic ignored "-Wunused-function"
2592 #endif
2593 BEGIN_COM_MAP(CXConnectionPoint)
2594 #if defined __clang__
2595 #pragma clang diagnostic pop
2596 #endif
2597 COM_INTERFACE_ENTRY(IConnectionPoint)
2598 #if defined __clang__
2599 #pragma clang diagnostic push
2600 #pragma clang diagnostic ignored "-Winconsistent-missing-override"
2601 #pragma clang diagnostic ignored "-Wunused-function"
2602 #endif
2603 END_COM_MAP()
2604 #if defined __clang__
2605 #pragma clang diagnostic pop
2606 #endif
2608 DECLARE_NOT_AGGREGATABLE(CXConnectionPoint)
2610 virtual ~CXConnectionPoint() {}
2612 void Init(InterfaceOleWrapper* pInterfaceOleWrapper,
2613 Reference<ooo::vba::XConnectionPoint>& xCP,
2614 Reference<XMultiServiceFactory>& xMSF,
2615 ooo::vba::TypeAndIID aTypeAndIID)
2617 SAL_INFO("extensions.olebridge", this << "@CXConnectionPoint::Init for " << pInterfaceOleWrapper->getImplementationName());
2619 IUnknown *pUnknown;
2620 if (SUCCEEDED(QueryInterface(IID_IUnknown, reinterpret_cast<void **>(&pUnknown))))
2622 // In case QI for IUnknown returns a different pointer, but nah, it doesn't
2623 SAL_INFO("extensions.olebridge", " (IUnknown@" << pUnknown << ")");
2626 mpInterfaceOleWrapper = pInterfaceOleWrapper;
2627 mxCP = xCP;
2628 mxMSF = xMSF;
2629 maTypeAndIID = aTypeAndIID;
2632 virtual HRESULT STDMETHODCALLTYPE GetConnectionInterface(IID *pIID) override
2634 SAL_WARN("extensions.olebridge", this << "@CXConnectionPoint::GetConnectionInterface(" << *pIID << "): E_NOTIMPL");
2636 // FIXME: Needed?
2638 return E_NOTIMPL;
2641 virtual HRESULT STDMETHODCALLTYPE GetConnectionPointContainer(IConnectionPointContainer **) override
2643 SAL_WARN("extensions.olebridge", this << "@CXConnectionPoint::GetConnectionInterface: E_NOTIMPL");
2645 // FIXME: Needed?
2647 return E_NOTIMPL;
2650 virtual HRESULT STDMETHODCALLTYPE Advise(IUnknown *pUnkSink,
2651 DWORD *pdwCookie) override
2653 comphelper::Automation::AutomationInvokedZone aAutomationActive;
2655 SAL_INFO("extensions.olebridge", this << "@CXConnectionPoint::Advise(" << pUnkSink << ")");
2657 if (!pdwCookie)
2658 return E_POINTER;
2660 Reference<ooo::vba::XSink> xSink(new Sink(pUnkSink, mxMSF, maTypeAndIID, mpInterfaceOleWrapper));
2662 mvISinks.push_back(pUnkSink);
2663 *pdwCookie = mvISinks.size();
2665 mvCookies.push_back(mxCP->Advise(xSink));
2667 mvXSinks.push_back(xSink);
2669 SAL_INFO("extensions.olebridge", " *pdwCookie: " << *pdwCookie);
2671 return S_OK;
2674 virtual HRESULT STDMETHODCALLTYPE Unadvise(DWORD dwCookie) override
2676 comphelper::Automation::AutomationInvokedZone aAutomationActive;
2678 SAL_INFO("extensions.olebridge", this << "@CXConnectionPoint::Unadvise(" << dwCookie << ")");
2680 if (dwCookie == 0 || dwCookie > mvISinks.size())
2681 return E_POINTER;
2683 mvISinks[dwCookie-1] = nullptr;
2685 mxCP->Unadvise(mvCookies[dwCookie-1]);
2687 mvXSinks[dwCookie-1] = Reference<ooo::vba::XSink>();
2689 return S_OK;
2692 virtual HRESULT STDMETHODCALLTYPE EnumConnections(IEnumConnections **ppEnum) override
2694 comphelper::Automation::AutomationInvokedZone aAutomationActive;
2696 HRESULT nResult;
2698 SAL_INFO("extensions.olebridge", this << "@CXConnectionPoint::EnumConnections...");
2700 if (!ppEnum)
2702 SAL_INFO("extensions.olebridge", "..." << this << "@CXConnectionPoint::EnumConnections: E_POINTER");
2703 return E_POINTER;
2706 CComObject<CXEnumConnections>* pEnumConnections;
2708 nResult = CComObject<CXEnumConnections>::CreateInstance(&pEnumConnections);
2709 if (FAILED(nResult))
2711 SAL_INFO("extensions.olebridge", "..." << this << "@CXConnectionPoint::EnumConnections: " << WindowsErrorStringFromHRESULT(nResult));
2712 return nResult;
2715 pEnumConnections->AddRef();
2717 pEnumConnections->Init(mvISinks, mvCookies);
2718 *ppEnum = pEnumConnections;
2720 SAL_INFO("extensions.olebridge", "..." << this << "@CXConnectionPoint::EnumConnections: S_OK");
2722 return S_OK;
2725 InterfaceOleWrapper* mpInterfaceOleWrapper;
2726 std::vector<IUnknown*> mvISinks;
2727 std::vector<Reference<ooo::vba::XSink>> mvXSinks;
2728 std::vector<DWORD> mvCookies;
2729 Reference<XMultiServiceFactory> mxMSF;
2730 Reference<ooo::vba::XConnectionPoint> mxCP;
2731 ooo::vba::TypeAndIID maTypeAndIID;
2736 HRESULT InterfaceOleWrapper::InvokeGeneral( DISPID dispidMember, unsigned short wFlags,
2737 DISPPARAMS * pdispparams, VARIANT * pvarResult, EXCEPINFO * pexcepinfo,
2738 unsigned int * /*puArgErr*/, bool& bHandled)
2740 HRESULT ret= S_OK;
2743 // DISPID_VALUE | The DEFAULT Value is required in JScript when the situation
2744 // is that we put an object into an Array object ( out parameter). We have to return
2745 // IDispatch otherwise the object cannot be accessed from the Script.
2746 if( dispidMember == DISPID_VALUE && (wFlags & DISPATCH_PROPERTYGET) != 0
2747 && m_defaultValueType != VT_EMPTY && pvarResult != nullptr)
2749 // Special case hack: If it is a ScVbaCheckBox, return the boolean value
2750 Reference<ooo::vba::msforms::XCheckBox> xCheckBox(m_xOrigin, UNO_QUERY);
2751 if (xCheckBox.is())
2753 bHandled = true;
2754 Any aValue = xCheckBox->getValue();
2755 anyToVariant(pvarResult, aValue);
2756 return S_OK;
2759 bHandled= true;
2760 if( m_defaultValueType == VT_DISPATCH)
2762 pvarResult->vt= VT_DISPATCH;
2763 pvarResult->pdispVal= this;
2764 AddRef();
2765 ret= S_OK;
2769 // function: _GetValueObject
2770 else if( dispidMember == DISPID_JSCRIPT_VALUE_FUNC)
2772 bHandled= true;
2773 if( !pvarResult)
2774 return E_POINTER;
2775 CComObject< JScriptValue>* pValue;
2776 if( SUCCEEDED( CComObject<JScriptValue>::CreateInstance( &pValue)))
2778 pValue->AddRef();
2779 pvarResult->vt= VT_DISPATCH;
2780 pvarResult->pdispVal= CComQIPtr<IDispatch>(pValue->GetUnknown());
2781 ret= S_OK;
2783 else
2784 ret= DISP_E_EXCEPTION;
2786 else if( dispidMember == DISPID_GET_STRUCT_FUNC)
2788 bHandled= true;
2789 bool bStruct= false;
2792 Reference<XIdlReflection> xRefl = theCoreReflection::get(comphelper::getComponentContext(m_smgr));
2793 // the first parameter is in DISPPARAMS rgvargs contains the name of the struct.
2794 CComVariant arg;
2795 if( pdispparams->cArgs == 1 && SUCCEEDED( arg.ChangeType( VT_BSTR, &pdispparams->rgvarg[0])) )
2797 Reference<XIdlClass> classStruct= xRefl->forName(OUString(o3tl::toU(arg.bstrVal)));
2798 if( classStruct.is())
2800 Any anyStruct;
2801 classStruct->createObject( anyStruct);
2802 CComVariant var;
2803 anyToVariant( &var, anyStruct );
2805 if( var.vt == VT_DISPATCH)
2807 VariantCopy( pvarResult, & var);
2808 bStruct= true;
2812 ret= bStruct ? S_OK : DISP_E_EXCEPTION;
2814 else if (dispidMember == DISPID_CREATE_TYPE_FUNC)
2816 bHandled= true;
2817 if( !pvarResult)
2818 return E_POINTER;
2819 // the first parameter is in DISPPARAMS rgvargs contains the name of the struct.
2820 CComVariant arg;
2821 if( pdispparams->cArgs != 1)
2822 return DISP_E_BADPARAMCOUNT;
2823 if (FAILED( arg.ChangeType( VT_BSTR, &pdispparams->rgvarg[0])))
2824 return DISP_E_BADVARTYPE;
2826 //check if the provided name represents a valid type
2827 Type type;
2828 if (!getType(arg.bstrVal, type))
2830 writeExcepinfo(pexcepinfo, OUString::Concat("[automation bridge] A UNO type with the name ") +
2831 o3tl::toU(arg.bstrVal) + " does not exist!");
2832 return DISP_E_EXCEPTION;
2835 if (!createUnoTypeWrapper(arg.bstrVal, pvarResult))
2837 writeExcepinfo(pexcepinfo, "[automation bridge] InterfaceOleWrapper::InvokeGeneral\n"
2838 "Could not initialize UnoTypeWrapper object!");
2839 return DISP_E_EXCEPTION;
2842 else if (dispidMember == DISPID_NEWENUM)
2844 bHandled = true;
2845 if( !pvarResult)
2846 return E_POINTER;
2848 Reference< ooo::vba::XCollection> xCollection(m_xOrigin, UNO_QUERY);
2849 if (!xCollection.is())
2850 return DISP_E_MEMBERNOTFOUND;
2852 CComObject<CXEnumVariant>* pEnumVar;
2854 ret = CComObject<CXEnumVariant>::CreateInstance(&pEnumVar);
2855 if (FAILED(ret))
2856 return ret;
2858 pEnumVar->AddRef();
2860 pEnumVar->Init(this, xCollection);
2862 pvarResult->vt = VT_UNKNOWN;
2863 pvarResult->punkVal = nullptr;
2865 ret = pEnumVar->QueryInterface(IID_IUnknown, reinterpret_cast<void**>(&pvarResult->punkVal));
2866 if (FAILED(ret))
2868 pEnumVar->Release();
2869 return ret;
2873 catch(const BridgeRuntimeError & e)
2875 writeExcepinfo(pexcepinfo, e.message);
2876 ret = DISP_E_EXCEPTION;
2878 catch(const Exception & e)
2880 OUString message= "InterfaceOleWrapper::InvokeGeneral : \n" +
2881 e.Message;
2882 writeExcepinfo(pexcepinfo, message);
2883 ret = DISP_E_EXCEPTION;
2885 catch( ... )
2887 writeExcepinfo(pexcepinfo, "InterfaceOleWrapper::InvokeGeneral : \nUnexpected exception");
2888 ret = DISP_E_EXCEPTION;
2890 return ret;
2893 STDMETHODIMP InterfaceOleWrapper::GetDispID(BSTR /*bstrName*/, DWORD /*grfdex*/, DISPID __RPC_FAR* /*pid*/)
2895 return ResultFromScode(E_NOTIMPL);
2898 STDMETHODIMP InterfaceOleWrapper::InvokeEx(
2899 /* [in] */ DISPID /*id*/,
2900 /* [in] */ LCID /*lcid*/,
2901 /* [in] */ WORD /*wFlags*/,
2902 /* [in] */ DISPPARAMS __RPC_FAR* /*pdp*/,
2903 /* [out] */ VARIANT __RPC_FAR* /*pvarRes*/,
2904 /* [out] */ EXCEPINFO __RPC_FAR* /*pei*/,
2905 /* [unique][in] */ IServiceProvider __RPC_FAR* /*pspCaller*/)
2907 return ResultFromScode(E_NOTIMPL);
2910 STDMETHODIMP InterfaceOleWrapper::DeleteMemberByName(
2911 /* [in] */ BSTR /*bstr*/,
2912 /* [in] */ DWORD /*grfdex*/)
2914 return ResultFromScode(E_NOTIMPL);
2917 STDMETHODIMP InterfaceOleWrapper::DeleteMemberByDispID(DISPID /*id*/)
2919 return ResultFromScode(E_NOTIMPL);
2922 STDMETHODIMP InterfaceOleWrapper::GetMemberProperties(
2923 /* [in] */ DISPID /*id*/,
2924 /* [in] */ DWORD /*grfdexFetch*/,
2925 /* [out] */ DWORD __RPC_FAR* /*pgrfdex*/)
2927 return ResultFromScode(E_NOTIMPL);
2930 STDMETHODIMP InterfaceOleWrapper::GetMemberName(
2931 /* [in] */ DISPID /*id*/,
2932 /* [out] */ BSTR __RPC_FAR* /*pbstrName*/)
2934 return ResultFromScode(E_NOTIMPL);
2937 STDMETHODIMP InterfaceOleWrapper::GetNextDispID(
2938 /* [in] */ DWORD /*grfdex*/,
2939 /* [in] */ DISPID /*id*/,
2940 /* [out] */ DISPID __RPC_FAR* /*pid*/)
2942 return ResultFromScode(E_NOTIMPL);
2945 STDMETHODIMP InterfaceOleWrapper::GetNameSpaceParent(
2946 /* [out] */ IUnknown __RPC_FAR *__RPC_FAR* /*ppunk*/)
2948 return ResultFromScode(E_NOTIMPL);
2951 // IProvideClassInfo
2952 HRESULT STDMETHODCALLTYPE InterfaceOleWrapper::GetClassInfo (
2953 /* [out] */ ITypeInfo **ppTI)
2955 comphelper::Automation::AutomationInvokedZone aAutomationActive;
2957 SAL_INFO("extensions.olebridge", this << "@InterfaceOleWrapper::GetClassInfo");
2959 if (!ppTI)
2960 return E_POINTER;
2962 Reference<ooo::vba::XInterfaceWithIID> xIID(m_xOrigin, UNO_QUERY);
2963 if (!xIID.is())
2964 return E_NOTIMPL;
2966 OUString sIID = xIID->getIID();
2967 IID aIID;
2968 if (!SUCCEEDED(IIDFromString(reinterpret_cast<LPOLESTR>(sIID.pData->buffer), &aIID)))
2969 return E_NOTIMPL;
2971 HRESULT ret;
2973 CComObject<CXTypeInfo>* pTypeInfo;
2975 ret = CComObject<CXTypeInfo>::CreateInstance(&pTypeInfo);
2976 if (FAILED(ret))
2977 return ret;
2979 pTypeInfo->AddRef();
2981 pTypeInfo->InitForCoclass(m_xOrigin, m_sImplementationName, aIID, m_smgr);
2983 *ppTI = pTypeInfo;
2985 return S_OK;
2988 // IConnectionPointContainer
2989 HRESULT STDMETHODCALLTYPE InterfaceOleWrapper::EnumConnectionPoints(
2990 /* [out] */ IEnumConnectionPoints **)
2992 SAL_INFO("extensions.olebridge", this << "@InterfaceOleWrapper::EnumConnectionPoints");
2993 return ResultFromScode(E_NOTIMPL);
2996 HRESULT STDMETHODCALLTYPE InterfaceOleWrapper::FindConnectionPoint(
2997 /* [in] */ REFIID riid,
2998 /* [out] */ IConnectionPoint **ppCP)
3000 comphelper::Automation::AutomationInvokedZone aAutomationActive;
3002 SAL_INFO("extensions.olebridge", this << "@InterfaceOleWrapper::FindConnectionPoint(" << riid << ")");
3004 if (!ppCP)
3005 return E_POINTER;
3007 Reference<ooo::vba::XConnectable> xConnectable(m_xOrigin, UNO_QUERY);
3009 // We checked already
3010 assert(xConnectable.is());
3011 if (!xConnectable.is())
3012 return E_NOTIMPL;
3014 ooo::vba::TypeAndIID aTypeAndIID = xConnectable->GetConnectionPoint();
3016 IID aIID;
3017 if (!SUCCEEDED(IIDFromString(reinterpret_cast<LPOLESTR>(aTypeAndIID.IID.pData->buffer), &aIID)))
3018 return E_INVALIDARG;
3020 if (!IsEqualIID(riid, aIID))
3021 return E_INVALIDARG;
3023 Reference<ooo::vba::XConnectionPoint> xCP = xConnectable->FindConnectionPoint();
3024 if (!xCP.is())
3025 return E_INVALIDARG;
3027 HRESULT ret;
3029 CComObject<CXConnectionPoint>* pConnectionPoint;
3031 ret = CComObject<CXConnectionPoint>::CreateInstance(&pConnectionPoint);
3032 if (FAILED(ret))
3033 return ret;
3035 pConnectionPoint->AddRef();
3037 pConnectionPoint->Init(this, xCP, m_smgr, aTypeAndIID);
3039 *ppCP = pConnectionPoint;
3041 return S_OK;
3044 // UnoObjectWrapperRemoteOpt ---------------------------------------------------
3046 UnoObjectWrapperRemoteOpt::UnoObjectWrapperRemoteOpt( Reference<XMultiServiceFactory> const & aFactory,
3047 sal_uInt8 unoWrapperClass, sal_uInt8 comWrapperClass):
3048 InterfaceOleWrapper( aFactory, unoWrapperClass, comWrapperClass),
3049 m_currentId(1)
3053 UnoObjectWrapperRemoteOpt::~UnoObjectWrapperRemoteOpt()
3057 // UnoConversionUtilities
3058 Reference< XInterface > UnoObjectWrapperRemoteOpt::createUnoWrapperInstance()
3060 Reference<XWeak> xWeak= static_cast<XWeak*>( new UnoObjectWrapperRemoteOpt(
3061 m_smgr, m_nUnoWrapperClass, m_nComWrapperClass));
3062 return Reference<XInterface>( xWeak, UNO_QUERY);
3065 COM_DECLSPEC_NOTHROW STDMETHODIMP UnoObjectWrapperRemoteOpt::GetIDsOfNames ( REFIID /*riid*/, LPOLESTR * rgszNames, UINT cNames,
3066 LCID /*lcid*/, DISPID * rgdispid )
3068 MutexGuard guard( getBridgeMutex());
3070 if( ! rgdispid)
3071 return E_POINTER;
3072 HRESULT ret = E_UNEXPECTED;
3074 // _GetValueObject
3075 if( ! wcscmp( *rgszNames, JSCRIPT_VALUE_FUNC))
3077 *rgdispid= DISPID_JSCRIPT_VALUE_FUNC;
3078 return S_OK;
3080 else if( ! wcscmp( *rgszNames, GET_STRUCT_FUNC))
3082 *rgdispid= DISPID_GET_STRUCT_FUNC;
3083 return S_OK;
3086 if (m_xInvocation.is() && (cNames > 0))
3088 OUString name(o3tl::toU(rgszNames[0]));
3089 // has this name been determined as "bad"
3090 BadNameMap::iterator badIter= m_badNameMap.find( name);
3091 if( badIter == m_badNameMap.end() )
3093 // name has not been bad before( member exists
3094 typedef NameToIdMap::iterator ITnames;
3095 std::pair< ITnames, bool > pair_id= m_nameToDispIdMap.emplace(name, m_currentId++);
3096 // new ID inserted ?
3097 if( pair_id.second )
3098 {// yes, now create MemberInfo and ad to IdToMemberInfoMap
3099 MemberInfo d(0, name);
3100 m_idToMemberInfoMap.emplace(m_currentId - 1, d);
3103 *rgdispid = pair_id.first->second;
3104 ret = S_OK;
3106 else
3107 ret= DISP_E_UNKNOWNNAME;
3109 return ret;
3112 COM_DECLSPEC_NOTHROW STDMETHODIMP UnoObjectWrapperRemoteOpt::Invoke ( DISPID dispidMember, REFIID /*riid*/, LCID /*lcid*/, WORD wFlags,
3113 DISPPARAMS * pdispparams, VARIANT * pvarResult, EXCEPINFO * pexcepinfo,
3114 UINT * puArgErr )
3116 comphelper::Automation::AutomationInvokedZone aAutomationActive;
3118 HRESULT ret = S_OK;
3121 bool bHandled= false;
3122 ret= InvokeGeneral( dispidMember, wFlags, pdispparams, pvarResult, pexcepinfo,
3123 puArgErr, bHandled);
3124 if( bHandled)
3125 return ret;
3127 if ( dispidMember > 0 && m_xInvocation.is())
3130 IdToMemberInfoMap::iterator it_MemberInfo= m_idToMemberInfoMap.find( dispidMember);
3131 if( it_MemberInfo != m_idToMemberInfoMap.end() )
3133 MemberInfo& info= it_MemberInfo->second;
3135 Sequence<Any> params; // holds converted any s
3136 if( ! info.flags )
3137 { // DISPID called for the first time
3138 if( wFlags == DISPATCH_METHOD )
3140 convertDispparamsArgs(dispidMember, wFlags, pdispparams, params );
3142 if( FAILED( ret= doInvoke( pdispparams, pvarResult,
3143 pexcepinfo, puArgErr, info.name, params))
3144 && ret == DISP_E_MEMBERNOTFOUND)
3146 // try to get the exact name
3147 OUString exactName;
3148 if (m_xExactName.is())
3150 exactName = m_xExactName->getExactName( info.name);
3151 // invoke again
3152 if( !exactName.isEmpty() )
3154 if( SUCCEEDED( ret= doInvoke( pdispparams, pvarResult,
3155 pexcepinfo, puArgErr, exactName, params)))
3156 info.name= exactName;
3160 if( SUCCEEDED( ret ) )
3161 info.flags= DISPATCH_METHOD;
3163 else if( wFlags == DISPATCH_PROPERTYPUT || wFlags == DISPATCH_PROPERTYPUTREF)
3165 convertDispparamsArgs(dispidMember, wFlags, pdispparams, params );
3166 if( FAILED( ret= doSetProperty( pdispparams, pvarResult,
3167 pexcepinfo, puArgErr, info.name, params))
3168 && ret == DISP_E_MEMBERNOTFOUND)
3170 // try to get the exact name
3171 OUString exactName;
3172 if (m_xExactName.is())
3174 exactName = m_xExactName->getExactName( info.name);
3175 // invoke again
3176 if( !exactName.isEmpty() )
3178 if( SUCCEEDED( ret= doSetProperty( pdispparams, pvarResult,
3179 pexcepinfo, puArgErr, exactName, params)))
3180 info.name= exactName;
3184 if( SUCCEEDED( ret ) )
3185 info.flags= DISPATCH_PROPERTYPUT | DISPATCH_PROPERTYGET;
3187 else if( wFlags == DISPATCH_PROPERTYGET)
3189 if( FAILED( ret= doGetProperty( pdispparams, pvarResult,
3190 pexcepinfo, info.name))
3191 && ret == DISP_E_MEMBERNOTFOUND)
3193 // try to get the exact name
3194 OUString exactName;
3195 if (m_xExactName.is())
3197 exactName = m_xExactName->getExactName( info.name);
3198 // invoke again
3199 if( !exactName.isEmpty() )
3201 if( SUCCEEDED( ret= doGetProperty( pdispparams, pvarResult,
3202 pexcepinfo, exactName)))
3203 info.name= exactName;
3207 if( SUCCEEDED( ret ) )
3208 info.flags= DISPATCH_PROPERTYGET | DISPATCH_PROPERTYPUT;
3210 else if( wFlags & DISPATCH_METHOD &&
3211 (wFlags & DISPATCH_PROPERTYPUT || wFlags & DISPATCH_PROPERTYPUTREF))
3214 OUString exactName;
3215 // convert params for DISPATCH_METHOD or DISPATCH_PROPERTYPUT
3216 convertDispparamsArgs(dispidMember, wFlags, pdispparams, params );
3217 // try first as method
3218 if( FAILED( ret= doInvoke( pdispparams, pvarResult,
3219 pexcepinfo, puArgErr, info.name, params))
3220 && ret == DISP_E_MEMBERNOTFOUND)
3222 // try to get the exact name
3223 if (m_xExactName.is())
3225 exactName = m_xExactName->getExactName( info.name);
3226 // invoke again
3227 if( !exactName.isEmpty() )
3229 if( SUCCEEDED( ret= doInvoke( pdispparams, pvarResult,
3230 pexcepinfo, puArgErr, exactName, params)))
3231 info.name= exactName;
3235 if( SUCCEEDED( ret ) )
3236 info.flags= DISPATCH_METHOD;
3238 // try as property
3239 if( FAILED( ret) && pdispparams->cArgs == 1)
3241 if( FAILED( ret= doSetProperty( pdispparams, pvarResult,
3242 pexcepinfo, puArgErr, info.name, params))
3243 && ret == DISP_E_MEMBERNOTFOUND)
3245 // try to get the exact name
3246 if( !exactName.isEmpty() )
3248 if( SUCCEEDED( ret= doSetProperty( pdispparams, pvarResult,
3249 pexcepinfo, puArgErr, exactName, params)))
3250 info.name= exactName;
3253 if( SUCCEEDED( ret ) )
3254 info.flags= DISPATCH_PROPERTYPUT | DISPATCH_PROPERTYGET;
3257 else if( wFlags & DISPATCH_METHOD && wFlags & DISPATCH_PROPERTYGET)
3259 OUString exactName;
3260 convertDispparamsArgs(dispidMember, wFlags, pdispparams, params );
3262 if( FAILED( ret= doInvoke( pdispparams, pvarResult,
3263 pexcepinfo, puArgErr, info.name, params))
3264 && ret == DISP_E_MEMBERNOTFOUND)
3266 // try to get the exact name
3267 if (m_xExactName.is())
3269 exactName = m_xExactName->getExactName( info.name);
3270 // invoke again
3271 if( !exactName.isEmpty() )
3273 if( SUCCEEDED( ret= doInvoke( pdispparams, pvarResult,
3274 pexcepinfo, puArgErr, exactName, params)))
3275 info.name= exactName;
3279 if( SUCCEEDED( ret ) )
3280 info.flags= DISPATCH_METHOD;
3282 // try as property
3283 if( FAILED( ret) && pdispparams->cArgs == 1)
3285 if( FAILED( ret= doGetProperty( pdispparams, pvarResult,
3286 pexcepinfo, info.name))
3287 && ret == DISP_E_MEMBERNOTFOUND)
3289 if( !exactName.isEmpty() )
3291 if( SUCCEEDED( ret= doSetProperty( pdispparams, pvarResult,
3292 pexcepinfo, puArgErr, exactName, params)))
3293 info.name= exactName;
3296 if( SUCCEEDED( ret ) )
3297 info.flags= DISPATCH_PROPERTYGET;
3301 // update information about this member
3302 if( ret == DISP_E_MEMBERNOTFOUND)
3304 // Remember the name as not existing
3305 // and remove the MemberInfo
3306 m_badNameMap[info.name]= false;
3307 m_idToMemberInfoMap.erase( it_MemberInfo);
3309 } // if( ! info.flags )
3310 else // IdToMemberInfoMap contains a MemberInfo
3312 if( wFlags & DISPATCH_METHOD && info.flags == DISPATCH_METHOD)
3314 convertDispparamsArgs(dispidMember, wFlags, pdispparams, params );
3315 ret= doInvoke( pdispparams, pvarResult,
3316 pexcepinfo, puArgErr, info.name, params);
3318 else if( (wFlags & DISPATCH_PROPERTYPUT || wFlags & DISPATCH_PROPERTYPUTREF ) &&
3319 info.flags & DISPATCH_PROPERTYPUT)
3321 convertDispparamsArgs(dispidMember, wFlags, pdispparams, params );
3322 ret= doSetProperty( pdispparams, pvarResult,
3323 pexcepinfo, puArgErr, info.name, params);
3325 else if( (wFlags & DISPATCH_PROPERTYGET) && ( info.flags & DISPATCH_PROPERTYGET))
3327 ret= doGetProperty( pdispparams, pvarResult,
3328 pexcepinfo, info.name);
3330 else
3332 ret= DISP_E_MEMBERNOTFOUND;
3335 }// if( it_MemberInfo != m_idToMemberInfoMap.end() )
3336 else
3337 ret= DISP_E_MEMBERNOTFOUND;
3340 catch(const BridgeRuntimeError& e)
3342 writeExcepinfo(pexcepinfo, e.message);
3343 ret = DISP_E_EXCEPTION;
3345 catch(const Exception& e)
3347 OUString message= "UnoObjectWrapperRemoteOpt::Invoke : \n" +
3348 e.Message;
3349 writeExcepinfo(pexcepinfo, message);
3350 ret = DISP_E_EXCEPTION;
3352 catch(...)
3354 writeExcepinfo(pexcepinfo, "UnoObjectWrapperRemoteOpt::Invoke : \nUnexpected exception");
3355 ret = DISP_E_EXCEPTION;
3358 return ret;
3361 HRESULT UnoObjectWrapperRemoteOpt::methodInvoke( DISPID /*dispidMember*/, DISPPARAMS * /*pdispparams*/, VARIANT * /*pvarResult*/,
3362 EXCEPINFO * /*pexcepinfo*/, unsigned int * /*puArgErr*/, Sequence<Any> const &)
3364 return S_OK;
3367 // The returned HRESULT is only appropriate for IDispatch::Invoke
3368 static HRESULT mapCannotConvertException(const CannotConvertException &e, unsigned int * puArgErr)
3370 HRESULT ret;
3371 bool bWriteIndex= true;
3373 switch ( e.Reason)
3375 case FailReason::OUT_OF_RANGE:
3376 ret = DISP_E_OVERFLOW;
3377 break;
3378 case FailReason::IS_NOT_NUMBER:
3379 ret = DISP_E_TYPEMISMATCH;
3380 break;
3381 case FailReason::IS_NOT_ENUM:
3382 ret = DISP_E_TYPEMISMATCH;
3383 break;
3384 case FailReason::IS_NOT_BOOL:
3385 ret = DISP_E_TYPEMISMATCH;
3386 break;
3387 case FailReason::NO_SUCH_INTERFACE:
3388 ret = DISP_E_TYPEMISMATCH;
3389 break;
3390 case FailReason::SOURCE_IS_NO_DERIVED_TYPE:
3391 ret = DISP_E_TYPEMISMATCH;
3392 break;
3393 case FailReason::TYPE_NOT_SUPPORTED:
3394 ret = DISP_E_TYPEMISMATCH;
3395 break;
3396 case FailReason::INVALID:
3397 ret = DISP_E_TYPEMISMATCH;
3398 break;
3399 case FailReason::NO_DEFAULT_AVAILABLE:
3400 ret = DISP_E_BADPARAMCOUNT;
3401 break;
3402 case FailReason::UNKNOWN:
3403 ret = E_UNEXPECTED;
3404 break;
3405 default:
3406 ret = E_UNEXPECTED;
3407 bWriteIndex= false;
3408 break;
3411 if( bWriteIndex && puArgErr != nullptr)
3412 *puArgErr = e.ArgumentIndex;
3413 return ret;
3416 // The function maps the TypeClass of the any to VARTYPE: If
3417 // the Any contains STRUCT or INTERFACE then the return value
3418 // is VT_DISPATCH. The function is used from o2u_createUnoObjectWrapper
3419 // and the result is put into the constructor of the uno - wrapper
3420 // object. If a client asks the object for DISPID_VALUE and this
3421 // function returned VT_DISPATCH then the IDispatch of the same
3422 // object is being returned.
3423 // See InterfaceOleWrapper::Invoke, InterfaceOleWrapper::m_defaultValueType
3424 VARTYPE getVarType( const Any& value)
3426 VARTYPE ret= VT_EMPTY;
3428 switch ( value.getValueTypeClass())
3430 case TypeClass_STRUCT: ret= VT_DISPATCH; break;
3431 case TypeClass_INTERFACE: ret= VT_DISPATCH; break;
3432 default: break;
3434 return ret;
3437 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */