Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / extensions / source / ole / unoobjw.cxx
blob936e049b147adcca3f39a376ac23f18f75953fa3
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>
91 #include "comifaces.hxx"
92 #include "jscriptclasses.hxx"
93 #include "unotypewrapper.hxx"
94 #include "oleobjw.hxx"
95 #include "unoobjw.hxx"
96 #include "servprov.hxx"
98 using namespace osl;
99 using namespace cppu;
100 using namespace com::sun::star::uno;
101 using namespace com::sun::star::beans;
102 using namespace com::sun::star::container;
103 using namespace com::sun::star::script;
104 using namespace com::sun::star::lang;
105 using namespace com::sun::star::bridge::ModelDependent;
106 using namespace com::sun::star::reflection;
108 std::unordered_map<sal_uIntPtr, WeakReference<XInterface> > UnoObjToWrapperMap;
109 static bool writeBackOutParameter(VARIANTARG* pDest, VARIANT* pSource);
110 static bool writeBackOutParameter2( VARIANTARG* pDest, VARIANT* pSource);
111 static HRESULT mapCannotConvertException(const CannotConvertException &e, unsigned int * puArgErr);
113 /* Does not throw any exceptions.
114 Param pInfo can be NULL.
116 static void writeExcepinfo(EXCEPINFO * pInfo, const OUString& message)
118 if (pInfo != nullptr)
120 pInfo->wCode = UNO_2_OLE_EXCEPTIONCODE;
121 pInfo->bstrSource = SysAllocString(L"[automation bridge] ");
122 pInfo->bstrDescription = SysAllocString(o3tl::toW(message.getStr()));
126 InterfaceOleWrapper::InterfaceOleWrapper( Reference<XMultiServiceFactory> const & xFactory,
127 sal_uInt8 unoWrapperClass, sal_uInt8 comWrapperClass):
128 UnoConversionUtilities<InterfaceOleWrapper>( xFactory, unoWrapperClass, comWrapperClass),
129 m_defaultValueType( 0)
133 InterfaceOleWrapper::~InterfaceOleWrapper()
135 MutexGuard guard(getBridgeMutex());
136 // remove entries in global map
137 auto it = UnoObjToWrapperMap.find( reinterpret_cast<sal_uIntPtr>(m_xOrigin.get()));
138 if(it != UnoObjToWrapperMap.end())
139 UnoObjToWrapperMap.erase(it);
142 COM_DECLSPEC_NOTHROW STDMETHODIMP InterfaceOleWrapper::QueryInterface(REFIID riid, void ** ppv)
144 comphelper::Automation::AutomationInvokedZone aAutomationActive;
146 SAL_INFO("extensions.olebridge", this << "@InterfaceOleWrapper::QueryInterface(" << riid << ")");
148 HRESULT ret= S_OK;
150 if( !ppv)
151 return E_POINTER;
153 if(IsEqualIID(riid, IID_IUnknown))
155 AddRef();
156 *ppv = static_cast<IUnknown*>(static_cast<IDispatch*>(this));
157 SAL_INFO("extensions.olebridge", " " << *ppv);
159 else if (IsEqualIID(riid, IID_IDispatch))
161 AddRef();
162 *ppv = static_cast<IDispatch*>(this);
163 SAL_INFO("extensions.olebridge", " " << *ppv);
165 else if (IsEqualIID(riid, IID_IProvideClassInfo))
167 Reference<ooo::vba::XConnectable> xConnectable(m_xOrigin, UNO_QUERY);
168 if (!xConnectable.is())
169 return E_NOINTERFACE;
170 AddRef();
171 *ppv = static_cast<IProvideClassInfo*>(this);
172 SAL_INFO("extensions.olebridge", " " << *ppv);
174 else if (IsEqualIID(riid, IID_IConnectionPointContainer))
176 Reference<ooo::vba::XConnectable> xConnectable(m_xOrigin, UNO_QUERY);
177 if (!xConnectable.is())
178 return E_NOINTERFACE;
179 AddRef();
180 *ppv = static_cast<IConnectionPointContainer*>(this);
181 SAL_INFO("extensions.olebridge", " " << *ppv);
183 else if( IsEqualIID( riid, __uuidof( IUnoObjectWrapper)))
185 AddRef();
186 *ppv= static_cast<IUnoObjectWrapper*>(this);
187 SAL_INFO("extensions.olebridge", " " << *ppv);
189 else
190 ret= E_NOINTERFACE;
191 return ret;
194 COM_DECLSPEC_NOTHROW STDMETHODIMP_(ULONG) InterfaceOleWrapper::AddRef()
196 acquire();
197 // does not need to guard because one should not rely on the return value of
198 // AddRef anyway
199 return m_refCount;
202 COM_DECLSPEC_NOTHROW STDMETHODIMP_(ULONG) InterfaceOleWrapper::Release()
204 ULONG n= m_refCount;
205 release();
206 return n - 1;
209 // IUnoObjectWrapper --------------------------------------------------------
210 COM_DECLSPEC_NOTHROW STDMETHODIMP InterfaceOleWrapper::getWrapperXInterface( Reference<XInterface>* pXInt)
212 pXInt->set( static_cast<XWeak*>( this), UNO_QUERY);
213 return pXInt->is() ? S_OK : E_FAIL;
215 COM_DECLSPEC_NOTHROW STDMETHODIMP InterfaceOleWrapper::getOriginalUnoObject( Reference<XInterface>* pXInt)
217 *pXInt= m_xOrigin;
218 return m_xOrigin.is() ? S_OK : E_FAIL;
220 COM_DECLSPEC_NOTHROW STDMETHODIMP InterfaceOleWrapper::getOriginalUnoStruct( Any * pStruct)
222 comphelper::Automation::AutomationInvokedZone aAutomationActive;
224 HRESULT ret= E_FAIL;
225 if( !m_xOrigin.is())
227 Reference<XMaterialHolder> xMatHolder( m_xInvocation, UNO_QUERY);
228 if( xMatHolder.is())
230 Any any = xMatHolder->getMaterial();
231 if( any.getValueTypeClass() == TypeClass_STRUCT)
233 *pStruct= any;
234 ret= S_OK;
238 return ret;
241 COM_DECLSPEC_NOTHROW STDMETHODIMP InterfaceOleWrapper::GetTypeInfoCount( UINT *pctinfo )
243 SAL_INFO("extensions.olebridge", this << "@InterfaceOleWrapper::GetTypeInfoCount");
245 if (!pctinfo)
246 return E_POINTER;
248 *pctinfo = 1;
250 return S_OK;
253 namespace {
255 class CXTypeInfo : public ITypeInfo,
256 public CComObjectRoot
258 public:
259 enum class Kind { COCLASS, MAIN, OUTGOING };
261 #if defined __clang__
262 #pragma clang diagnostic push
263 #pragma clang diagnostic ignored "-Wunused-function"
264 #endif
265 BEGIN_COM_MAP(CXTypeInfo)
266 #if defined __clang__
267 #pragma clang diagnostic pop
268 #endif
269 COM_INTERFACE_ENTRY(ITypeInfo)
270 #if defined __clang__
271 #pragma clang diagnostic push
272 #pragma clang diagnostic ignored "-Winconsistent-missing-override"
273 #pragma clang diagnostic ignored "-Wunused-function"
274 #endif
275 END_COM_MAP()
276 #if defined __clang__
277 #pragma clang diagnostic pop
278 #endif
280 DECLARE_NOT_AGGREGATABLE(CXTypeInfo)
282 virtual ~CXTypeInfo() {}
284 void InitForCoclass(Reference<XInterface> xOrigin,
285 const OUString& sImplementationName,
286 const IID& rIID,
287 Reference<XMultiServiceFactory> xMSF);
288 void InitForClassItself(Reference<XInterface> xOrigin,
289 const OUString& sImplementationName,
290 const IID& rIID,
291 Reference<XMultiServiceFactory> xMSF);
292 void InitForOutgoing(Reference<XInterface> xOrigin,
293 const OUString& sInterfaceName,
294 const IID& rIID,
295 Reference<XMultiServiceFactory> xMSF,
296 Type aType);
297 virtual HRESULT STDMETHODCALLTYPE GetTypeAttr(TYPEATTR **ppTypeAttr) override;
298 virtual HRESULT STDMETHODCALLTYPE GetTypeComp(ITypeComp **ppTComp) override;
299 virtual HRESULT STDMETHODCALLTYPE GetFuncDesc(UINT index,
300 FUNCDESC **ppFuncDesc) override;
301 virtual HRESULT STDMETHODCALLTYPE GetVarDesc(UINT index,
302 VARDESC **ppVarDesc) override;
303 virtual HRESULT STDMETHODCALLTYPE GetNames(MEMBERID memid,
304 BSTR *rgBstrNames,
305 UINT cMaxNames,
306 UINT *pcNames) override;
307 virtual HRESULT STDMETHODCALLTYPE GetRefTypeOfImplType(UINT index,
308 HREFTYPE *pRefType) override;
309 virtual HRESULT STDMETHODCALLTYPE GetImplTypeFlags(UINT index,
310 INT *pImplTypeFlags) override;
311 virtual HRESULT STDMETHODCALLTYPE GetIDsOfNames(LPOLESTR *rgszNames,
312 UINT cNames,
313 MEMBERID *pMemId) override;
314 virtual HRESULT STDMETHODCALLTYPE Invoke(PVOID pvInstance,
315 MEMBERID memid,
316 WORD wFlags,
317 DISPPARAMS *pDispParams,
318 VARIANT *pVarResult,
319 EXCEPINFO *pExcepInfo,
320 UINT *puArgErr) override;
321 virtual HRESULT STDMETHODCALLTYPE GetDocumentation(MEMBERID memid,
322 BSTR *pBstrName,
323 BSTR *pBstrDocString,
324 DWORD *pdwHelpContext,
325 BSTR *pBstrHelpFile) override;
326 virtual HRESULT STDMETHODCALLTYPE GetDllEntry(MEMBERID memid,
327 INVOKEKIND invKind,
328 BSTR *pBstrDllName,
329 BSTR *pBstrName,
330 WORD *pwOrdinal) override;
331 virtual HRESULT STDMETHODCALLTYPE GetRefTypeInfo(HREFTYPE hRefType,
332 ITypeInfo **ppTInfo) override;
333 virtual HRESULT STDMETHODCALLTYPE AddressOfMember(MEMBERID memid,
334 INVOKEKIND invKind,
335 PVOID *ppv) override;
336 virtual HRESULT STDMETHODCALLTYPE CreateInstance(IUnknown *pUnkOuter,
337 REFIID riid,
338 PVOID *ppvObj) override;
339 virtual HRESULT STDMETHODCALLTYPE GetMops(MEMBERID memid,
340 BSTR *pBstrMops) override;
341 virtual HRESULT STDMETHODCALLTYPE GetContainingTypeLib(ITypeLib **ppTLib,
342 UINT *pIndex) override;
343 virtual void STDMETHODCALLTYPE ReleaseTypeAttr(TYPEATTR *pTypeAttr) override;
344 virtual void STDMETHODCALLTYPE ReleaseFuncDesc(FUNCDESC *pFuncDesc) override;
345 virtual void STDMETHODCALLTYPE ReleaseVarDesc(VARDESC *pVarDesc) override;
347 private:
348 Kind meKind;
349 Reference<XInterface> mxOrigin;
350 OUString msImplementationName;
351 OUString msInterfaceName;
352 IID maIID;
353 Reference<XMultiServiceFactory> mxMSF;
354 Type maType;
357 class CXTypeLib : public ITypeLib,
358 public CComObjectRoot
360 public:
361 #if defined __clang__
362 #pragma clang diagnostic push
363 #pragma clang diagnostic ignored "-Wunused-function"
364 #endif
365 BEGIN_COM_MAP(CXTypeLib)
366 #if defined __clang__
367 #pragma clang diagnostic pop
368 #endif
369 COM_INTERFACE_ENTRY(ITypeLib)
370 #if defined __clang__
371 #pragma clang diagnostic push
372 #pragma clang diagnostic ignored "-Winconsistent-missing-override"
373 #pragma clang diagnostic ignored "-Wunused-function"
374 #endif
375 END_COM_MAP()
376 #if defined __clang__
377 #pragma clang diagnostic pop
378 #endif
380 DECLARE_NOT_AGGREGATABLE(CXTypeLib)
382 virtual ~CXTypeLib() {}
384 void Init(Reference<XInterface> xOrigin,
385 const OUString& sImplementationName,
386 Reference<XMultiServiceFactory> xMSF)
388 SAL_INFO("extensions.olebridge", this << "@CXTypeLib::Init for " << sImplementationName);
389 mxOrigin = xOrigin;
390 msImplementationName = sImplementationName;
391 mxMSF = xMSF;
394 virtual UINT STDMETHODCALLTYPE GetTypeInfoCount() override
396 SAL_WARN("extensions.olebridge", this << "@CXTypeLib::GetTypeInfoCount");
397 return 1;
400 virtual HRESULT STDMETHODCALLTYPE GetTypeInfo(UINT,
401 ITypeInfo **) override
403 SAL_WARN("extensions.olebridge", this << "@CXTypeLib::GetTypeInfo: E_NOTIMPL");
404 return E_NOTIMPL;
407 virtual HRESULT STDMETHODCALLTYPE GetTypeInfoType(UINT,
408 TYPEKIND *) override
410 SAL_WARN("extensions.olebridge", this << "@CXTypeLib::GetTypeInfoType: E_NOTIMPL");
411 return E_NOTIMPL;
414 virtual HRESULT STDMETHODCALLTYPE GetTypeInfoOfGuid(REFGUID guid,
415 ITypeInfo **ppTInfo) override
417 comphelper::Automation::AutomationInvokedZone aAutomationActive;
419 SAL_INFO("extensions.olebridge", this << "@CXTypeLib::GetTypeInfoOfGuid(" << guid << ")");
420 if (!ppTInfo)
421 return E_POINTER;
423 Reference<ooo::vba::XConnectable> xConnectable(mxOrigin, UNO_QUERY);
424 if (!xConnectable.is())
425 return TYPE_E_ELEMENTNOTFOUND;
427 IID aIID;
428 if (SUCCEEDED(IIDFromString(reinterpret_cast<LPOLESTR>(xConnectable->getIID().pData->buffer), &aIID)))
430 if (IsEqualIID(guid, aIID))
432 HRESULT ret;
434 CComObject<CXTypeInfo>* pTypeInfo;
436 ret = CComObject<CXTypeInfo>::CreateInstance(&pTypeInfo);
437 if (FAILED(ret))
438 return ret;
440 pTypeInfo->AddRef();
442 pTypeInfo->InitForCoclass(mxOrigin, msImplementationName, aIID, mxMSF);
444 *ppTInfo = pTypeInfo;
446 return S_OK;
450 #if 0
451 ooo::vba::TypeAndIID aTypeAndIID = xConnectable->GetConnectionPoint();
453 IID aIID;
454 if (SUCCEEDED(IIDFromString((LPOLESTR)aTypeAndIID.IID.pData->buffer, &aIID)))
456 HRESULT ret;
458 CComObject<CXTypeInfo>* pTypeInfo;
460 ret = CComObject<CXTypeInfo>::CreateInstance(&pTypeInfo);
461 if (FAILED(ret))
462 return ret;
464 pTypeInfo->AddRef();
466 pTypeInfo->InitForOutgoing(mxOrigin, msImplementationName, aIID, mxMSF);
468 *ppTInfo = pTypeInfo;
470 return S_OK;
472 #else
473 SAL_WARN("extensions.olebridge", "Not implemented: GetTypeInfoOfGuid(" << guid << ")");
474 #endif
476 return TYPE_E_ELEMENTNOTFOUND;
480 virtual HRESULT STDMETHODCALLTYPE GetLibAttr(TLIBATTR **) override
482 SAL_WARN("extensions.olebridge", this << "@CXTypeLib::GetLibAttr: E_NOTIMPL");
483 return E_NOTIMPL;
486 virtual HRESULT STDMETHODCALLTYPE GetTypeComp(ITypeComp **) override
488 SAL_WARN("extensions.olebridge", this << "@CXTypeLib::GetTypeComp: E_NOTIMPL");
489 return E_NOTIMPL;
492 virtual HRESULT STDMETHODCALLTYPE GetDocumentation(INT,
493 BSTR *,
494 BSTR *,
495 DWORD *,
496 BSTR *) override
498 SAL_WARN("extensions.olebridge", this << "@CXTypeLib::GetDocumentation: E_NOTIMPL");
499 return E_NOTIMPL;
502 virtual HRESULT STDMETHODCALLTYPE IsName(LPOLESTR,
503 ULONG,
504 BOOL *) override
506 SAL_WARN("extensions.olebridge", this << "@CXTypeLib:IsName: E_NOTIMPL");
507 return E_NOTIMPL;
510 virtual HRESULT STDMETHODCALLTYPE FindName(LPOLESTR,
511 ULONG,
512 ITypeInfo **,
513 MEMBERID *,
514 USHORT *) override
516 SAL_WARN("extensions.olebridge", this << "@CXTypeLib::FindName: E_NOTIMPL");
517 return E_NOTIMPL;
520 virtual void STDMETHODCALLTYPE ReleaseTLibAttr(TLIBATTR *) override
522 SAL_WARN("extensions.olebridge", this << "@CXTypeLib::ReleaseTLibAttr: E_NOTIMPL");
525 private:
526 Reference<XInterface> mxOrigin;
527 OUString msImplementationName;
528 Reference<XMultiServiceFactory> mxMSF;
533 void CXTypeInfo::InitForCoclass(Reference<XInterface> xOrigin,
534 const OUString& sImplementationName,
535 const IID& rIID,
536 Reference<XMultiServiceFactory> xMSF)
538 SAL_INFO("extensions.olebridge", this << "@CXTypeInfo::InitForCoclass(" << sImplementationName << "," << rIID << ")");
539 meKind = Kind::COCLASS;
540 mxOrigin = xOrigin;
541 msImplementationName = sImplementationName;
542 maIID = rIID;
543 mxMSF = xMSF;
546 void CXTypeInfo::InitForClassItself(Reference<XInterface> xOrigin,
547 const OUString& sImplementationName,
548 const IID& rIID,
549 Reference<XMultiServiceFactory> xMSF)
551 SAL_INFO("extensions.olebridge", this << "@CXTypeInfo::InitForClassItself(" << sImplementationName << "," << rIID << ")");
552 meKind = Kind::MAIN;
553 mxOrigin = xOrigin;
554 msImplementationName = sImplementationName;
555 maIID = rIID;
556 mxMSF = xMSF;
559 void CXTypeInfo::InitForOutgoing(Reference<XInterface> xOrigin,
560 const OUString& sInterfaceName,
561 const IID& rIID,
562 Reference<XMultiServiceFactory> xMSF,
563 Type aType)
565 SAL_INFO("extensions.olebridge", this << "@CXTypeInfo::InitForOutgoing(" << sInterfaceName << "," << rIID << ")");
566 meKind = Kind::OUTGOING;
567 mxOrigin = xOrigin;
568 msInterfaceName = sInterfaceName;
569 maIID = rIID;
570 mxMSF = xMSF;
571 maType = aType;
574 HRESULT STDMETHODCALLTYPE CXTypeInfo::GetTypeAttr(TYPEATTR **ppTypeAttr)
576 comphelper::Automation::AutomationInvokedZone aAutomationActive;
578 SAL_INFO("extensions.olebridge", this << "@CXTypeInfo::GetTypeAttr");
580 if (!ppTypeAttr)
581 return E_POINTER;
583 assert(!IsEqualIID(maIID, IID_NULL));
585 TYPEATTR *pTypeAttr = new TYPEATTR;
586 memset(pTypeAttr, 0, sizeof(*pTypeAttr));
588 pTypeAttr->guid = maIID;
590 if (meKind == Kind::COCLASS)
592 pTypeAttr->typekind = TKIND_COCLASS;
593 pTypeAttr->cFuncs = 0;
594 pTypeAttr->cVars = 0;
595 pTypeAttr->cImplTypes = 3;
596 pTypeAttr->cbSizeVft = 0;
597 pTypeAttr->cbAlignment = 8;
598 pTypeAttr->wTypeFlags = TYPEFLAG_FCANCREATE;
600 else if (meKind == Kind::MAIN)
602 pTypeAttr->typekind = TKIND_DISPATCH;
603 pTypeAttr->cFuncs = 10; // FIXME, dummy
604 pTypeAttr->cVars = 0;
605 pTypeAttr->cImplTypes = 1;
606 // FIXME: I think this is always supposed to be as if just for the seven methods in
607 // IDIspatch?
608 pTypeAttr->cbSizeVft = 7 * sizeof(void*);
609 pTypeAttr->cbAlignment = 8;
610 pTypeAttr->wTypeFlags = TYPEFLAG_FHIDDEN|TYPEFLAG_FDISPATCHABLE;
612 else if (meKind == Kind::OUTGOING)
614 pTypeAttr->typekind = TKIND_DISPATCH;
616 Reference<XIdlReflection> xRefl = theCoreReflection::get(comphelper::getComponentContext(mxMSF));
617 assert(xRefl.is());
619 Reference<XIdlClass> xClass = xRefl->forName(maType.getTypeName());
620 assert(xClass.is());
622 auto aMethods = xClass->getMethods();
623 assert(xClass->getTypeClass() == TypeClass_INTERFACE &&
624 aMethods.getLength() > 0);
626 // Drop the three XInterface methods, add the three corresponding IUnknown ones plus the
627 // four IDispatch ones on top of that.
628 pTypeAttr->cFuncs = aMethods.getLength() - 3 + 3 + 4;
629 pTypeAttr->cVars = 0;
630 pTypeAttr->cImplTypes = 1;
631 // FIXME: I think this, too, is always supposed to be as if just for the seven methods in
632 // IDIspatch?
633 pTypeAttr->cbSizeVft = 7 * sizeof(void*);
634 pTypeAttr->cbAlignment = 8;
635 pTypeAttr->wTypeFlags = TYPEFLAG_FHIDDEN|TYPEFLAG_FNONEXTENSIBLE|TYPEFLAG_FDISPATCHABLE;
637 else
638 assert(false);
640 pTypeAttr->lcid = LOCALE_USER_DEFAULT;
641 pTypeAttr->memidConstructor = MEMBERID_NIL;
642 pTypeAttr->memidDestructor = MEMBERID_NIL;
643 // FIXME: Is this correct, just the vtable pointer, right?
644 pTypeAttr->cbSizeInstance = sizeof(void*);
645 pTypeAttr->wMajorVerNum = 0;
646 pTypeAttr->wMinorVerNum = 0;
647 pTypeAttr->idldescType.wIDLFlags = IDLFLAG_NONE;
649 SAL_INFO("extensions.olebridge", this << "@CXTypeInfo::GetTypeAttr: " << pTypeAttr);
651 *ppTypeAttr = pTypeAttr;
653 return S_OK;
656 HRESULT STDMETHODCALLTYPE CXTypeInfo::GetTypeComp(ITypeComp **)
658 SAL_WARN("extensions.olebridge", this << "@CXTypeInfo::GetTypeComp: E_NOTIMPL");
659 return E_NOTIMPL;
662 HRESULT STDMETHODCALLTYPE CXTypeInfo::GetFuncDesc(UINT index,
663 FUNCDESC **ppFuncDesc)
665 comphelper::Automation::AutomationInvokedZone aAutomationActive;
667 if (!ppFuncDesc)
668 return E_POINTER;
670 if (meKind != Kind::OUTGOING)
671 return E_NOTIMPL;
673 if (index <= 6)
675 *ppFuncDesc = new FUNCDESC;
676 (*ppFuncDesc)->memid = 0x60000000 + index;
677 (*ppFuncDesc)->lprgscode = nullptr;
678 (*ppFuncDesc)->lprgelemdescParam = nullptr;
679 (*ppFuncDesc)->funckind = FUNC_DISPATCH;
680 (*ppFuncDesc)->invkind = INVOKE_FUNC;
681 (*ppFuncDesc)->callconv = CC_STDCALL;
682 switch (index)
684 case 0: // QueryInterface
685 (*ppFuncDesc)->cParams = 2;
686 (*ppFuncDesc)->elemdescFunc.tdesc.lptdesc = nullptr;
687 (*ppFuncDesc)->elemdescFunc.tdesc.vt = VT_VOID;
688 break;
689 case 1: // AddRef
690 (*ppFuncDesc)->cParams = 0;
691 (*ppFuncDesc)->elemdescFunc.tdesc.lptdesc = nullptr;
692 (*ppFuncDesc)->elemdescFunc.tdesc.vt = VT_UI4;
693 break;
694 case 2: // Release
695 (*ppFuncDesc)->cParams = 1;
696 (*ppFuncDesc)->elemdescFunc.tdesc.lptdesc = nullptr;
697 (*ppFuncDesc)->elemdescFunc.tdesc.vt = VT_UI4;
698 break;
699 case 3: // GetTypeInfoCount
700 (*ppFuncDesc)->cParams = 1;
701 (*ppFuncDesc)->elemdescFunc.tdesc.lptdesc = nullptr;
702 (*ppFuncDesc)->elemdescFunc.tdesc.vt = VT_VOID;
703 break;
704 case 4: // GetTypeInfo
705 (*ppFuncDesc)->cParams = 3;
706 (*ppFuncDesc)->elemdescFunc.tdesc.lptdesc = nullptr;
707 (*ppFuncDesc)->elemdescFunc.tdesc.vt = VT_VOID;
708 break;
709 case 5: // GetIDsOfNames
710 (*ppFuncDesc)->cParams = 5;
711 (*ppFuncDesc)->elemdescFunc.tdesc.lptdesc = nullptr;
712 (*ppFuncDesc)->elemdescFunc.tdesc.vt = VT_VOID;
713 break;
714 case 6: // Invoke
715 (*ppFuncDesc)->cParams = 8;
716 (*ppFuncDesc)->elemdescFunc.tdesc.lptdesc = nullptr;
717 (*ppFuncDesc)->elemdescFunc.tdesc.vt = VT_VOID;
718 break;
720 (*ppFuncDesc)->cParamsOpt = 0;
721 (*ppFuncDesc)->oVft = index * sizeof(void*);
722 (*ppFuncDesc)->cScodes = 0;
723 (*ppFuncDesc)->wFuncFlags = FUNCFLAG_FRESTRICTED;
725 SAL_INFO("extensions.olebridge", this << "@CXTypeInfo::GetFuncDesc(" << index << "): S_OK: " << *ppFuncDesc);
727 return S_OK;
730 Reference<XIdlReflection> xRefl = theCoreReflection::get(comphelper::getComponentContext(mxMSF));
731 assert(xRefl.is());
733 Reference<XIdlClass> xClass = xRefl->forName(maType.getTypeName());
734 assert(xClass.is());
736 auto aMethods = xClass->getMethods();
737 assert(xClass->getTypeClass() == TypeClass_INTERFACE &&
738 aMethods.getLength() > 0);
740 if (index > o3tl::make_unsigned(aMethods.getLength() - 3 + 3 + 4))
741 return E_INVALIDARG;
743 *ppFuncDesc = new FUNCDESC;
745 (*ppFuncDesc)->memid = index - 6;
746 (*ppFuncDesc)->lprgscode = nullptr;
747 (*ppFuncDesc)->lprgelemdescParam = nullptr;
748 (*ppFuncDesc)->funckind = FUNC_DISPATCH;
749 (*ppFuncDesc)->invkind = INVOKE_FUNC;
750 (*ppFuncDesc)->callconv = CC_STDCALL;
751 (*ppFuncDesc)->cParams = aMethods[index - 4]->getParameterInfos().getLength();
752 (*ppFuncDesc)->cParamsOpt = 0;
753 (*ppFuncDesc)->oVft = index * sizeof(void*);
754 (*ppFuncDesc)->cScodes = 0;
755 (*ppFuncDesc)->elemdescFunc.tdesc.lptdesc = nullptr; // ???
756 (*ppFuncDesc)->elemdescFunc.tdesc.vt = VT_VOID; // ???
757 (*ppFuncDesc)->wFuncFlags = 0;
759 SAL_INFO("extensions.olebridge", this << "@CXTypeInfo::GetFuncDesc(" << index << "): S_OK: " << *ppFuncDesc);
761 return S_OK;
764 HRESULT STDMETHODCALLTYPE CXTypeInfo::GetVarDesc(UINT,
765 VARDESC **)
767 SAL_WARN("extensions.olebridge", this << "@CXTypeInfo::GetVarDesc: E_NOTIMPL");
768 return E_NOTIMPL;
771 HRESULT STDMETHODCALLTYPE CXTypeInfo::GetNames(MEMBERID memid,
772 BSTR *rgBstrNames,
773 UINT cMaxNames,
774 UINT *pcNames)
776 comphelper::Automation::AutomationInvokedZone aAutomationActive;
778 SAL_INFO("extensions.olebridge", this << "@CXTypeInfo::GetNames(" << memid << ")");
779 assert(meKind != Kind::COCLASS);
781 if (!rgBstrNames)
782 return E_POINTER;
784 if (!pcNames)
785 return E_POINTER;
787 if (memid < 1)
788 return E_INVALIDARG;
790 if (cMaxNames < 1)
791 return E_INVALIDARG;
793 if (meKind == Kind::MAIN)
795 SAL_WARN("extensions.olebridge", "GetNames() for MAIN not implemented");
796 return E_NOTIMPL;
799 Reference<XIdlReflection> xRefl = theCoreReflection::get(comphelper::getComponentContext(mxMSF));
800 assert(xRefl.is());
802 Reference<XIdlClass> xClass = xRefl->forName(maType.getTypeName());
803 assert(xClass.is());
805 auto aMethods = xClass->getMethods();
806 assert(xClass->getTypeClass() == TypeClass_INTERFACE &&
807 aMethods.getLength() > 0);
809 // Subtract the three XInterface methods. Memid for the first following method is 1.
810 if (memid > aMethods.getLength() - 3)
811 return E_INVALIDARG;
813 SAL_INFO("extensions.olebridge", "..." << this << "@CXTypeInfo::GetNames(" << memid << "): " << aMethods[memid + 2]->getName());
814 rgBstrNames[0] = SysAllocString(reinterpret_cast<LPOLESTR>(aMethods[memid + 2]->getName().pData->buffer));
815 *pcNames = 1;
817 return S_OK;
820 HRESULT STDMETHODCALLTYPE CXTypeInfo::GetRefTypeOfImplType(UINT index,
821 HREFTYPE *pRefType)
823 SAL_INFO("extensions.olebridge", this << "@CXTypeInfo::GetRefTypeOfImplType(" << index << ")");
825 if (!pRefType)
826 return E_POINTER;
828 assert(index == 0 || index == 1);
830 *pRefType = 1000+index;
832 return S_OK;
835 HRESULT STDMETHODCALLTYPE CXTypeInfo::GetImplTypeFlags(UINT index,
836 INT *pImplTypeFlags)
838 comphelper::Automation::AutomationInvokedZone aAutomationActive;
840 SAL_INFO("extensions.olebridge", this << "@CXTypeInfo::GetImplTypeFlags(" << index << ")");
842 if (!pImplTypeFlags)
843 return E_POINTER;
845 assert(meKind == Kind::COCLASS);
846 assert(index == 0 || index == 1);
848 if (index == 0)
849 *pImplTypeFlags = IMPLTYPEFLAG_FDEFAULT;
850 else if (index == 1)
851 *pImplTypeFlags = IMPLTYPEFLAG_FDEFAULT|IMPLTYPEFLAG_FSOURCE;
853 return S_OK;
856 HRESULT STDMETHODCALLTYPE CXTypeInfo::GetIDsOfNames(LPOLESTR *,
857 UINT,
858 MEMBERID *)
860 SAL_WARN("extensions.olebridge", this << "@CXTypeInfo::GetIDsOfNames: E_NOTIMPL");
861 return E_NOTIMPL;
864 HRESULT STDMETHODCALLTYPE CXTypeInfo::Invoke(PVOID,
865 MEMBERID,
866 WORD,
867 DISPPARAMS *,
868 VARIANT *,
869 EXCEPINFO *,
870 UINT *)
872 SAL_WARN("extensions.olebridge", this << "@CXTypeInfo::Invoke: E_NOTIMPL");
873 return E_NOTIMPL;
876 HRESULT STDMETHODCALLTYPE CXTypeInfo::GetDocumentation(MEMBERID memid,
877 BSTR *pBstrName,
878 BSTR *pBstrDocString,
879 DWORD *pdwHelpContext,
880 BSTR *pBstrHelpFile)
882 comphelper::Automation::AutomationInvokedZone aAutomationActive;
884 SAL_INFO("extensions.olebridge", this << "@CXTypeInfo::GetDocumentation(" << memid << ")");
886 if (pBstrName)
888 if (memid == MEMBERID_NIL)
890 *pBstrName = SysAllocString(o3tl::toW(msImplementationName.getStr()));
892 else if (memid == DISPID_VALUE)
894 // MEMBERIDs are the same as DISPIDs, apparently?
895 *pBstrName = SysAllocString(L"Value");
897 else
899 // FIXME: Shouldn't we be able to know the names of the members of UNO interfaces?
900 *pBstrName = SysAllocString(o3tl::toW(OUString("UnknownNameOfMember#" + OUString::number(memid)).getStr()));
903 if (pBstrDocString)
904 *pBstrDocString = SysAllocString(L"");
905 if (pdwHelpContext)
906 *pdwHelpContext = 0;
907 if (pBstrHelpFile)
908 *pBstrHelpFile = nullptr;
910 return S_OK;
913 HRESULT STDMETHODCALLTYPE CXTypeInfo::GetDllEntry(MEMBERID,
914 INVOKEKIND,
915 BSTR *,
916 BSTR *,
917 WORD *)
919 SAL_WARN("extensions.olebridge", this << "@CXTypeInfo::GetDllEntry: E_NOTIMPL");
920 return E_NOTIMPL;
923 HRESULT STDMETHODCALLTYPE CXTypeInfo::GetRefTypeInfo(HREFTYPE hRefType,
924 ITypeInfo **ppTInfo)
926 comphelper::Automation::AutomationInvokedZone aAutomationActive;
928 SAL_INFO("extensions.olebridge", this << "@CXTypeInfo::GetRefTypeInfo(" << hRefType << ")");
930 if (!ppTInfo)
931 return E_POINTER;
933 // FIXME: Is it correct to assume that the only interfaces on which GetRefTypeInfo() would be
934 // called are those that implement ooo::vba::XConnectable?
936 Reference<ooo::vba::XConnectable> xConnectable(mxOrigin, UNO_QUERY);
937 if (!xConnectable.is())
938 return E_NOTIMPL;
940 ooo::vba::TypeAndIID aTypeAndIID = xConnectable->GetConnectionPoint();
942 IID aIID;
943 if (!SUCCEEDED(IIDFromString(reinterpret_cast<LPOLESTR>(aTypeAndIID.IID.pData->buffer), &aIID)))
944 return E_NOTIMPL;
946 HRESULT ret;
948 CComObject<CXTypeInfo>* pTypeInfo;
950 ret = CComObject<CXTypeInfo>::CreateInstance(&pTypeInfo);
951 if (FAILED(ret))
952 return ret;
954 pTypeInfo->AddRef();
956 pTypeInfo->InitForOutgoing(mxOrigin, aTypeAndIID.Type.getTypeName(), aIID, mxMSF, aTypeAndIID.Type);
958 *ppTInfo = pTypeInfo;
960 return S_OK;
963 HRESULT STDMETHODCALLTYPE CXTypeInfo::AddressOfMember(MEMBERID,
964 INVOKEKIND,
965 PVOID *)
967 SAL_WARN("extensions.olebridge", this << "@CXTypeInfo::AddressOfMember: E_NOTIMPL");
968 return E_NOTIMPL;
971 HRESULT STDMETHODCALLTYPE CXTypeInfo::CreateInstance(IUnknown *,
972 REFIID,
973 PVOID *)
975 SAL_WARN("extensions.olebridge", this << "@CXTypeInfo::CreateInstance: E_NOTIMPL");
976 return E_NOTIMPL;
979 HRESULT STDMETHODCALLTYPE CXTypeInfo::GetMops(MEMBERID,
980 BSTR *)
982 SAL_WARN("extensions.olebridge", this << "@CXTypeInfo::GetMops: E_NOTIMPL");
983 return E_NOTIMPL;
986 // This is not actually called any more by my vbscript test after I added the IProvideClassInfo
987 // thing... so all the CXTypeLib stuff is dead code at the moment.
989 HRESULT STDMETHODCALLTYPE CXTypeInfo::GetContainingTypeLib(ITypeLib **ppTLib,
990 UINT *pIndex)
992 comphelper::Automation::AutomationInvokedZone aAutomationActive;
994 SAL_INFO("extensions.olebridge", this << "@CXTypeInfo::GetContainingTypeLib");
996 if (!ppTLib || !pIndex)
997 return E_POINTER;
999 HRESULT ret;
1001 CComObject<CXTypeLib>* pTypeLib;
1003 ret = CComObject<CXTypeLib>::CreateInstance(&pTypeLib);
1004 if (FAILED(ret))
1005 return ret;
1007 pTypeLib->AddRef();
1009 pTypeLib->Init(mxOrigin, msImplementationName, mxMSF);
1011 *ppTLib = pTypeLib;
1013 return S_OK;
1016 void STDMETHODCALLTYPE CXTypeInfo::ReleaseTypeAttr(TYPEATTR *pTypeAttr)
1018 SAL_INFO("extensions.olebridge", this << "@CXTypeInfo::ReleaseTypeAttr(" << pTypeAttr << ")");
1020 delete pTypeAttr;
1023 void STDMETHODCALLTYPE CXTypeInfo::ReleaseFuncDesc(FUNCDESC *pFuncDesc)
1025 SAL_WARN("extensions.olebridge", this << "@CXTypeInfo::ReleaseFuncDesc(" << pFuncDesc << ")");
1027 delete pFuncDesc;
1030 void STDMETHODCALLTYPE CXTypeInfo::ReleaseVarDesc(VARDESC *)
1032 SAL_WARN("extensions.olebridge", this << "@CXTypeInfo::ReleaseVarDesc: E_NOTIMPL");
1035 COM_DECLSPEC_NOTHROW STDMETHODIMP InterfaceOleWrapper::GetTypeInfo(UINT iTInfo, LCID, ITypeInfo ** ppTInfo)
1037 comphelper::Automation::AutomationInvokedZone aAutomationActive;
1039 SAL_INFO("extensions.olebridge", this << "@InterfaceOleWrapper::GetTypeInfo(" << iTInfo << ")");
1041 if (!ppTInfo)
1042 return E_POINTER;
1044 if (iTInfo != 0)
1045 return E_NOTIMPL;
1047 // FIXME: This is surely incorrect. Why is being able to handle GetTypeInfo() here coupled to
1048 // being a source for outgoing events, i.e. implementing XConnectable? What would break if we
1049 // would use XInterfaceWithIID and its getIID instead?
1051 Reference<ooo::vba::XConnectable> xConnectable(m_xOrigin, UNO_QUERY);
1052 if (!xConnectable.is())
1053 return E_NOTIMPL;
1055 OUString sIID = xConnectable->GetIIDForClassItselfNotCoclass();
1056 IID aIID;
1057 if (!SUCCEEDED(IIDFromString(reinterpret_cast<LPOLESTR>(sIID.pData->buffer), &aIID)))
1058 return E_NOTIMPL;
1060 HRESULT ret;
1062 CComObject<CXTypeInfo>* pTypeInfo;
1064 ret = CComObject<CXTypeInfo>::CreateInstance(&pTypeInfo);
1065 if (FAILED(ret))
1066 return ret;
1068 pTypeInfo->AddRef();
1070 pTypeInfo->InitForClassItself(m_xOrigin, m_sImplementationName, aIID, m_smgr);
1072 *ppTInfo = pTypeInfo;
1074 return S_OK;
1077 COM_DECLSPEC_NOTHROW STDMETHODIMP InterfaceOleWrapper::GetIDsOfNames(REFIID /*riid*/,
1078 LPOLESTR * rgszNames,
1079 UINT cNames,
1080 LCID /*lcid*/,
1081 DISPID * rgdispid )
1083 comphelper::Automation::AutomationInvokedZone aAutomationActive;
1085 if( ! rgdispid)
1086 return E_POINTER;
1088 SAL_INFO("extensions.olebridge", this << "@InterfaceOleWrapper::GetIDsOfNames:");
1089 for (unsigned int i = 0; i < cNames; ++i)
1091 // Initialise returned rgdispid values.
1092 rgdispid[i] = DISPID_UNKNOWN;
1094 SAL_INFO("extensions.olebridge", " " << OUString(o3tl::toU(rgszNames[i])));
1097 HRESULT ret = DISP_E_UNKNOWNNAME;
1100 MutexGuard guard( getBridgeMutex());
1102 // FIXME: Handle the cNames > 1 case? Note that the rest of the names mean the names of *arguments*.
1104 if( ! _wcsicmp( *rgszNames, JSCRIPT_VALUE_FUNC) ||
1105 ! _wcsicmp( *rgszNames, BRIDGE_VALUE_FUNC))
1107 *rgdispid= DISPID_JSCRIPT_VALUE_FUNC;
1108 return S_OK;
1110 else if( ! _wcsicmp( *rgszNames, GET_STRUCT_FUNC) ||
1111 ! _wcsicmp( *rgszNames, BRIDGE_GET_STRUCT_FUNC))
1113 *rgdispid= DISPID_GET_STRUCT_FUNC;
1114 return S_OK;
1116 else if( ! _wcsicmp( *rgszNames, BRIDGE_CREATE_TYPE_FUNC))
1118 *rgdispid= DISPID_CREATE_TYPE_FUNC;
1119 return S_OK;
1122 if (m_xInvocation.is() && (cNames > 0))
1124 OUString name(o3tl::toU(rgszNames[0]));
1125 NameToIdMap::iterator iter = m_nameToDispIdMap.find(name);
1127 bool bIsMethod = false;
1129 OUString exactName = name;
1131 if (iter == m_nameToDispIdMap.end())
1133 if (m_xExactName.is())
1135 exactName = m_xExactName->getExactName(name);
1136 if (exactName.isEmpty())
1137 exactName = name;
1140 MemberInfo d(0, exactName);
1142 if (m_xInvocation->hasProperty(exactName))
1144 d.flags |= DISPATCH_PROPERTYGET;
1145 d.flags |= DISPATCH_PROPERTYPUT;
1146 d.flags |= DISPATCH_PROPERTYPUTREF;
1149 if (m_xInvocation->hasMethod(exactName))
1151 d.flags |= DISPATCH_METHOD;
1152 bIsMethod = true;
1155 if (d.flags != 0)
1157 m_MemberInfos.push_back(d);
1158 iter = m_nameToDispIdMap.emplace(exactName, static_cast<DISPID>(m_MemberInfos.size())).first;
1160 if (exactName != name)
1162 iter = m_nameToDispIdMap.emplace(name, static_cast<DISPID>(m_MemberInfos.size())).first;
1167 if (iter == m_nameToDispIdMap.end())
1169 ret = DISP_E_UNKNOWNNAME;
1170 SAL_INFO("extensions.olebridge", " " << name << ": UNKNOWN");
1172 else
1174 rgdispid[0] = (*iter).second;
1175 SAL_INFO("extensions.olebridge", " " << name << ": " << rgdispid[0]);
1177 if (bIsMethod && cNames > 1)
1179 Reference<XIdlMethod> xIdlMethod;
1180 Reference<XIntrospectionAccess> xIntrospectionAccess = m_xInvocation->getIntrospection();
1183 if (xIntrospectionAccess.is())
1184 xIdlMethod = xIntrospectionAccess->getMethod(exactName, MethodConcept::ALL);
1186 catch (const NoSuchMethodException&)
1189 if (xIdlMethod.is())
1191 auto aParamInfos = xIdlMethod->getParameterInfos();
1192 for (unsigned int i = 1; i < cNames; ++i)
1194 bool bFound = false;
1195 for (int j = 0; j < aParamInfos.getLength(); ++j)
1197 if (aParamInfos[j].aName.equalsIgnoreAsciiCase(o3tl::toU(rgszNames[i])))
1199 rgdispid[i] = j;
1200 bFound = true;
1201 SAL_INFO("extensions.olebridge", " " << OUString(o3tl::toU(rgszNames[i])) << ": " << rgdispid[i]);
1202 break;
1205 if (!bFound)
1206 SAL_INFO("extensions.olebridge", " " << OUString(o3tl::toU(rgszNames[i])) << ": NOT FOUND");
1211 // Return value should be S_OK only if *all* the names were found.
1212 unsigned int i;
1213 for (i = 0; i < cNames; ++i)
1214 if (rgdispid[i] == DISPID_UNKNOWN)
1215 break;
1216 if (i == cNames)
1217 ret = S_OK;
1221 catch(const BridgeRuntimeError&)
1223 OSL_ASSERT(false);
1225 catch(const Exception&)
1227 OSL_ASSERT(false);
1229 catch(...)
1231 OSL_ASSERT(false);
1234 return ret;
1237 // Note: What the comments here say about JScript possibly holds for Automation clients in general,
1238 // like VBScript ones, too. Or not. Hard to say. What is the relevance of JScript nowadays anyway,
1239 // and can LO really be used from JScript code on web pages any longer?
1241 // "convertDispparamsArgs" converts VARIANTS to their respecting Any counterparts
1242 // The parameters "id", "wFlags" and "pdispparams" equal those as used in
1243 // IDispatch::Invoke. The function handles special JavaScript
1244 // cases where a VARIANT of type VT_DISPATCH is ambiguous and could represent
1245 // an object, array ( JavaScript Array object), out parameter and in/out ( JavaScript Array object)
1246 // parameter (JavaScript Array object)
1247 // Because all those VT_DISPATCH objects need a different conversion
1248 // we have to find out what the object is supposed to be. The function does this
1249 // by either using type information or by help of a specialized ValueObject object.
1251 // A. Type Information
1253 // With the help of type information the kind of parameter can be exactly determined
1254 // and an appropriate conversion can be chosen. A problem arises if a method expects
1255 // an Any. Then the type info does not tell what the type of the value, that is kept
1256 // by the any, should be. In this situation the decision whether the param is a
1257 // sequence or an object is made upon the fact if the object has a property "0"
1258 // ( see function "isJScriptArray"). Since this is unsafe it is recommended to use
1259 // the JScript value objects within a JScript script on such an occasion.
1261 // B. JavaScript Value Object ( class JScriptValue )
1263 // A JScriptValue (ValueObject) object is a COM object in that it implements IDispatch and the
1264 // IJScriptValue object interface. Such objects are provided by all UNO wrapper
1265 // objects used within a JScript script. To obtain an instance one has to call
1266 // "_GetValueObject() or Bridge_GetValueObject()" on a UNO wrapper object (class InterfaceOleWrapper).
1267 // A value object is appropriately initialized within the script and passed as
1268 // parameter to a UNO object method or property. The convertDispparamsArgs function
1269 // can easily find out that a param is such an object by querying for the
1270 // IJScriptValue interface. By this interface one the type and kind ( out, in/out)
1271 // can be determined and the right conversion can be applied.
1272 // Using ValueObjects we spare us the effort of acquiring and examining type information
1273 // in order to figure out what the an IDispatch parameter is meant for.
1275 // Normal JScript object parameter can be mixed with JScriptValue object. If an
1276 // VARIANT contains a VT_DISPATCH that is no JScriptValue than the type information
1277 // is used to find out about the required type.
1278 void InterfaceOleWrapper::convertDispparamsArgs(DISPID id,
1279 unsigned short /*wFlags*/, DISPPARAMS* pdispparams, Sequence<Any>& rSeq)
1281 // Parameters come in in reverse order in pdispparams. There might be less parameters than
1282 // expected. In that case, assume they are "optional" (but can't be marked as such in UNO IDL),
1283 // and fill in the rest with empty Anys. There might also be more than expected. In that case,
1284 // assume the oovbaapi UNO IDL hasn't kept up with added optional parameters in MSO, and just
1285 // ignore the extra ones, as long as they are empty.
1287 // An example: incoming parameters: <12, 13, "foo/bar.tem">
1289 // Expected parameters: (string filename, int something, int somethingElse, Any whatever, Any
1290 // whateverElse)
1292 // Here the existing incoming parameters are placed in reverse order in the first three outgoing
1293 // parameters, and the rest of the outgoing parameters are kept as empty Anys.
1295 // Another example: incoming parameters: <EMPTY, TRUE>
1297 // Expected parameters: (bool flag)
1299 // Here the TRUE is passed as the sole outgoing parameter, and the incoming EMPTY is ignored.
1301 // Still an example: incoming parameters: <"foo.doc", TRUE>
1303 // Expected parameters: (bool flag)
1305 // This throws an error as the incoming string parameter presumably should do something important,
1306 // but there is no corresponding outgoing parameter.
1308 HRESULT hr = S_OK;
1309 const int countIncomingArgs = pdispparams->cArgs;
1311 //Get type information for the current call
1312 InvocationInfo info;
1313 if( ! getInvocationInfoForCall( id, info))
1314 throw BridgeRuntimeError(
1315 "[automation bridge]InterfaceOleWrapper::convertDispparamsArgs \n"
1316 "Could not obtain type information for current call.");
1318 // Size rSeq according to the number of expected parameters.
1319 const int expectedArgs = info.aParamTypes.getLength() + (info.eMemberType == MemberType_PROPERTY ? 1 : 0);
1320 rSeq.realloc( expectedArgs );
1321 Any* pParams = rSeq.getArray();
1323 Any anyParam;
1325 int outgoingArgIndex = 0;
1327 // Go through incoming parameters in reverse order, i.e. in the order as declared in IDL
1328 for (int i = std::max(countIncomingArgs, expectedArgs) - 1; i >= 0; i--)
1330 // Ignore too many parameters if they are VT_EMPTY anyway
1331 if ( outgoingArgIndex >= expectedArgs && pdispparams->rgvarg[i].vt == VT_EMPTY )
1332 continue;
1334 // But otherwise too many parameters is an error
1335 if ( outgoingArgIndex >= expectedArgs )
1336 throw BridgeRuntimeError( "[automation bridge] Too many parameters" );
1338 if (info.eMemberType == MemberType_METHOD &&
1339 info.aParamModes[ outgoingArgIndex ] == ParamMode_OUT)
1341 outgoingArgIndex++;
1342 continue;
1345 if (i < countIncomingArgs)
1347 // A missing (and hopefully optional) arg (in the middle of the argument list) is passed
1348 // as an empty Any.
1349 if (pdispparams->rgvarg[i].vt == VT_ERROR && pdispparams->rgvarg[i].scode == DISP_E_PARAMNOTFOUND)
1351 Any aEmpty;
1352 pParams[ outgoingArgIndex ] = aEmpty;
1353 outgoingArgIndex++;
1354 continue;
1357 if(convertValueObject( & pdispparams->rgvarg[i], anyParam))
1358 { //a param is a ValueObject and could be converted
1359 pParams[ outgoingArgIndex ] = anyParam;
1360 outgoingArgIndex++;
1361 continue;
1364 else
1366 // A missing arg. Let's hope it is de facto optional (there is no way in UNO IDL to mark
1367 // a parameter as optional). The corresponding slot in pParams is already a void Any.
1368 // Here we don't increase outgoingArgIndex!
1369 continue;
1372 // If the param is an out, in/out parameter in
1373 // JScript (Array object, with value at index 0) then we
1374 // extract Array[0] and put the value into varParam. At the end of the loop varParam
1375 // is converted if it contains a value otherwise the VARIANT from
1376 // DISPPARAMS is converted.
1377 CComVariant varParam;
1379 // Check for JScript out and in/out paramsobjects (VT_DISPATCH).
1380 // To find them out we use typeinformation of the function being called.
1382 // No idea how this stuff, originally written for JScript, works for other Automation
1383 // clients.
1385 if( pdispparams->rgvarg[i].vt == VT_DISPATCH )
1387 if( info.eMemberType == MemberType_METHOD && info.aParamModes[ outgoingArgIndex ] == ParamMode_INOUT)
1389 // INOUT-param
1390 // Index ( property) "0" contains the actual IN-param. The object is a JScript
1391 // Array object.
1392 // Get the IN-param at index "0"
1393 IDispatch* pdisp= pdispparams->rgvarg[i].pdispVal;
1395 OLECHAR const * sindex= L"0";
1396 DISPID id2;
1397 DISPPARAMS noParams= {nullptr,nullptr,0,0};
1398 if(SUCCEEDED( hr= pdisp->GetIDsOfNames( IID_NULL, const_cast<OLECHAR **>(&sindex), 1, LOCALE_USER_DEFAULT, &id2)))
1399 hr= pdisp->Invoke( id2, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET,
1400 & noParams, & varParam, nullptr, nullptr);
1401 if( FAILED( hr))
1403 throw BridgeRuntimeError(
1404 "[automation bridge] Could not determine "
1405 "if the object has a member \"0\". Error: " +
1406 OUString::number(hr));
1411 if( varParam.vt == VT_EMPTY) // then it was no in/out parameter
1412 varParam= pdispparams->rgvarg[i];
1414 if(info.eMemberType == MemberType_METHOD)
1415 variantToAny( & varParam, anyParam,
1416 info.aParamTypes[ outgoingArgIndex ]);
1417 else if(info.eMemberType == MemberType_PROPERTY)
1418 variantToAny( & varParam, anyParam, info.aType);
1419 else
1420 OSL_ASSERT(false);
1422 if (outgoingArgIndex < expectedArgs)
1423 pParams[ outgoingArgIndex ]= anyParam;
1424 outgoingArgIndex++;
1425 }// end for / iterating over all parameters
1428 bool InterfaceOleWrapper::getInvocationInfoForCall( DISPID id, InvocationInfo& info)
1430 bool bTypesAvailable= false;
1432 if( !m_xInvocation.is() )return false;
1433 Reference<XInvocation2> inv2( m_xInvocation, UNO_QUERY);
1434 if( inv2.is())
1436 // We need the name of the property or method to get its type information.
1437 // The name can be identified through the param "id"
1438 // that is kept as value in the map m_nameToDispIdMap.
1439 // Problem: the Windows JScript engine sometimes changes small letters to capital
1440 // letters as happens in xidlclass_obj.createObject( var) // in JScript.
1441 // IDispatch::GetIdsOfNames is then called with "CreateObject" !!!
1442 // m_nameToDispIdMap can contain several names for one DISPID but only one is
1443 // the exact one. If there's no m_xExactName and therefore no exact name then
1444 // there's only one entry in the map.
1445 OUString sMemberName;
1447 auto ci1 = std::find_if(m_nameToDispIdMap.cbegin(), m_nameToDispIdMap.cend(),
1448 [&id](const NameToIdMap::value_type& nameToDispId) { return nameToDispId.second == id; }); // item is a pair<OUString, DISPID>
1449 if (ci1 != m_nameToDispIdMap.cend())
1450 sMemberName= (*ci1).first;
1451 // Get information for the current call ( property or method).
1452 // There could be similar names which only differ in the cases
1453 // of letters. First we assume that the name which was passed into
1454 // GetIDsOfNames is correct. If we won't get information with that
1455 // name then we have the invocation service use the XExactName interface.
1456 bool validInfo= true;
1457 InvocationInfo invInfo;
1458 try{
1459 invInfo= inv2->getInfoForName( sMemberName, false);
1461 catch(const IllegalArgumentException&)
1463 validInfo= false;
1466 if( ! validInfo)
1468 invInfo= inv2->getInfoForName( sMemberName, true);
1470 if( invInfo.aName.pData)
1472 bTypesAvailable= true;
1473 info= invInfo;
1476 return bTypesAvailable;
1479 // XBridgeSupplier2 ---------------------------------------------------
1480 // only bridges itself ( this instance of InterfaceOleWrapper)from UNO to IDispatch
1481 // If sourceModelType is UNO than any UNO interface implemented by InterfaceOleWrapper
1482 // can bridged to IDispatch ( if destModelType == OLE). The IDispatch is
1483 // implemented by this class.
1484 Any SAL_CALL InterfaceOleWrapper::createBridge(const Any& modelDepObject,
1485 const Sequence<sal_Int8>& /*ProcessId*/,
1486 sal_Int16 sourceModelType,
1487 sal_Int16 destModelType)
1490 Any retAny;
1491 if( sourceModelType == UNO && destModelType == OLE &&
1492 modelDepObject.getValueTypeClass() == TypeClass_INTERFACE )
1494 Reference<XInterface> xInt;
1495 if( modelDepObject >>= xInt )
1497 if( xInt == Reference<XInterface>( static_cast<XWeak*>( this), UNO_QUERY))
1499 VARIANT *pVar= static_cast<VARIANT*>(CoTaskMemAlloc( sizeof( VARIANT)));
1500 if( pVar)
1502 pVar->vt= VT_DISPATCH;
1503 pVar->pdispVal= this;
1504 AddRef();
1506 retAny<<= reinterpret_cast< sal_uIntPtr >( pVar);
1512 return retAny;
1515 // XInitialization --------------------------------------------------
1516 void SAL_CALL InterfaceOleWrapper::initialize( const Sequence< Any >& aArguments )
1518 switch( aArguments.getLength() )
1520 case 2: // the object wraps a UNO struct
1521 aArguments[0] >>= m_xInvocation;
1522 aArguments[1] >>= m_defaultValueType;
1523 break;
1524 case 3: // the object wraps a UNO interface
1525 aArguments[0] >>= m_xInvocation;
1526 aArguments[1] >>= m_xOrigin;
1527 aArguments[2] >>= m_defaultValueType;
1529 Reference<XServiceInfo> xServiceInfo(m_xOrigin, UNO_QUERY);
1530 if (xServiceInfo.is())
1531 m_sImplementationName = xServiceInfo->getImplementationName();
1533 SAL_INFO("extensions.olebridge", this << "@InterfaceOleWrapper::initialize for "
1534 << (m_sImplementationName.isEmpty()?"an unknown implementation":m_sImplementationName));
1535 break;
1538 m_xExactName.set( m_xInvocation, UNO_QUERY);
1541 Reference< XInterface > InterfaceOleWrapper::createUnoWrapperInstance()
1543 Reference<XWeak> xWeak= static_cast<XWeak*>( new InterfaceOleWrapper(
1544 m_smgr, m_nUnoWrapperClass, m_nComWrapperClass));
1545 return Reference<XInterface>( xWeak, UNO_QUERY);
1548 Reference<XInterface> InterfaceOleWrapper::createComWrapperInstance()
1550 Reference<XWeak> xWeak= static_cast<XWeak*>( new IUnknownWrapper(
1551 m_smgr, m_nUnoWrapperClass, m_nComWrapperClass));
1552 return Reference<XInterface>( xWeak, UNO_QUERY);
1555 // "getType" is used in convertValueObject to map the string denoting the type
1556 // to an actual Type object.
1557 bool getType( const BSTR name, Type & type)
1559 bool ret = false;
1560 typelib_TypeDescription * pDesc= nullptr;
1561 OUString str(o3tl::toU(name));
1562 typelib_typedescription_getByName( &pDesc, str.pData );
1563 if( pDesc)
1565 type = Type( pDesc->pWeakRef );
1566 typelib_typedescription_release( pDesc);
1567 ret = true;
1569 return ret;
1572 static bool writeBackOutParameter2( VARIANTARG* pDest, VARIANT* pSource)
1574 bool ret = false;
1575 HRESULT hr;
1577 // Handle JScriptValue objects and JScript out params ( Array object )
1578 CComVariant varDest( *pDest);
1580 if( SUCCEEDED( varDest.ChangeType(VT_DISPATCH)))
1582 CComPtr<IDispatch> spDispDest(varDest.pdispVal);
1584 // special Handling for a JScriptValue object
1585 CComQIPtr<IJScriptValueObject> spValueDest(spDispDest);
1586 if (spValueDest)
1588 VARIANT_BOOL varBool= VARIANT_FALSE;
1589 if ((SUCCEEDED(hr = spValueDest->IsOutParam(&varBool))
1590 && varBool == VARIANT_TRUE)
1591 || (SUCCEEDED(hr = spValueDest->IsInOutParam(&varBool))
1592 && varBool == VARIANT_TRUE))
1594 if( SUCCEEDED( spValueDest->Set( CComVariant(), *pSource)))
1595 ret= true;
1598 else if (pDest->vt == VT_DISPATCH)// VT_DISPATCH -> JScript out param
1600 // We use IDispatchEx because its GetDispID function causes the creation
1601 // of a property if it does not exist already. This is convenient for
1602 // out parameters in JScript. Then the user must not specify property "0"
1603 // explicitly
1604 CComQIPtr<IDispatchEx> spDispEx( spDispDest);
1605 if( spDispEx)
1607 CComBSTR nullProp(L"0");
1608 DISPID dwDispID;
1609 if( SUCCEEDED( spDispEx->GetDispID( nullProp, fdexNameEnsure, &dwDispID)))
1611 DISPPARAMS dispparams = {nullptr, nullptr, 1, 1};
1612 dispparams.rgvarg = pSource;
1613 DISPID dispidPut = DISPID_PROPERTYPUT;
1614 dispparams.rgdispidNamedArgs = &dispidPut;
1616 if (pSource->vt == VT_UNKNOWN || pSource->vt == VT_DISPATCH ||
1617 (pSource->vt & VT_ARRAY) || (pSource->vt & VT_BYREF))
1618 hr = spDispEx->InvokeEx(dwDispID, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYPUTREF,
1619 &dispparams, nullptr, nullptr, nullptr);
1620 else
1621 hr= spDispEx->InvokeEx(dwDispID, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYPUT,
1622 &dispparams, nullptr, nullptr, nullptr);
1623 if( SUCCEEDED(hr))
1624 ret= true;
1628 else
1629 ret= writeBackOutParameter( pDest, pSource);
1631 else // The param can't be a JScript out-parameter ( an Array object), it could be a VBScript
1632 { // param. The function checks itself for correct VBScript params
1633 ret= writeBackOutParameter( pDest, pSource);
1635 return ret;
1638 // VisualBasic Script passes arguments as VT_VARIANT | VT_BYREF be it in or out parameter.
1639 // Thus we are in charge of freeing an eventual value contained by the inner VARIANT
1640 // Please note: VariantCopy doesn't free a VT_BYREF value
1641 // The out parameters are expected to have always a valid type
1642 static bool writeBackOutParameter(VARIANTARG* pDest, VARIANT* pSource)
1644 HRESULT hr;
1645 bool ret = false;
1646 // Out parameter must be VT_BYREF
1647 if ((V_VT(pDest) & VT_BYREF) != 0 )
1649 VARTYPE oleTypeFlags = V_VT(pSource);
1651 // if caller accept VARIANT as out parameter, any value must be converted
1652 if (V_VT(pDest) == (VT_VARIANT | VT_BYREF))
1654 // When the user provides a VARIANT rather than a concrete type
1655 // we just copy the source to the out, in/out parameter
1656 // VT_DISPATCH, VT_UNKNOWN, VT_ARRAY, VT_BSTR in the VARIANT that
1657 // is contained in pDest are released by VariantCopy
1658 VariantCopy(V_VARIANTREF(pDest), pSource);
1659 ret = true;
1661 else
1663 // variantarg and variant must have same type
1664 if ((V_VT(pDest) & oleTypeFlags) == oleTypeFlags)
1666 if ((oleTypeFlags & VT_ARRAY) != 0)
1668 // In / Out Param
1669 if( *V_ARRAYREF(pDest) != nullptr)
1670 hr= SafeArrayCopyData( V_ARRAY(pSource), *V_ARRAYREF(pDest));
1671 else
1672 // Out Param
1673 hr= SafeArrayCopy(V_ARRAY(pSource), V_ARRAYREF(pDest));
1674 if( SUCCEEDED( hr))
1675 ret = true;
1677 else
1679 // copy base type
1680 switch (V_VT(pSource))
1682 case VT_I2:
1684 *V_I2REF(pDest) = V_I2(pSource);
1685 ret = true;
1686 break;
1688 case VT_I4:
1689 *V_I4REF(pDest) = V_I4(pSource);
1690 ret = true;
1691 break;
1692 case VT_R4:
1693 *V_R4REF(pDest) = V_R4(pSource);
1694 ret = true;
1695 break;
1696 case VT_R8:
1697 *V_R8REF(pDest) = V_R8(pSource);
1698 ret = true;
1699 break;
1700 case VT_CY:
1701 *V_CYREF(pDest) = V_CY(pSource);
1702 ret = true;
1703 break;
1704 case VT_DATE:
1705 *V_DATEREF(pDest) = V_DATE(pSource);
1706 ret = true;
1707 break;
1708 case VT_BSTR:
1709 SysFreeString( *pDest->pbstrVal);
1711 *V_BSTRREF(pDest) = SysAllocString(V_BSTR(pSource));
1712 ret = true;
1713 break;
1714 case VT_DISPATCH:
1715 if (*V_DISPATCHREF(pDest) != nullptr)
1716 (*V_DISPATCHREF(pDest))->Release();
1718 *V_DISPATCHREF(pDest) = V_DISPATCH(pSource);
1720 if (*V_DISPATCHREF(pDest) != nullptr)
1721 (*V_DISPATCHREF(pDest))->AddRef();
1723 ret = true;
1724 break;
1725 case VT_ERROR:
1726 *V_ERRORREF(pDest) = V_ERROR(pSource);
1727 ret = true;
1728 break;
1729 case VT_BOOL:
1730 *V_BOOLREF(pDest) = V_BOOL(pSource);
1731 ret = true;
1732 break;
1733 case VT_UNKNOWN:
1734 if (*V_UNKNOWNREF(pDest) != nullptr)
1735 (*V_UNKNOWNREF(pDest))->Release();
1737 *V_UNKNOWNREF(pDest) = V_UNKNOWN(pSource);
1739 if (*V_UNKNOWNREF(pDest) != nullptr)
1740 (*V_UNKNOWNREF(pDest))->AddRef();
1742 ret = true;
1743 break;
1744 case VT_I1:
1745 *V_I1REF(pDest) = V_I1(pSource);
1746 ret = true;
1747 break;
1748 case VT_UI1:
1749 *V_UI1REF(pDest) = V_UI1(pSource);
1750 ret = true;
1751 break;
1752 case VT_UI2:
1753 *V_UI2REF(pDest) = V_UI2(pSource);
1754 ret = true;
1755 break;
1756 case VT_UI4:
1757 *V_UI4REF(pDest) = V_UI4(pSource);
1758 ret = true;
1759 break;
1760 case VT_INT:
1761 *V_INTREF(pDest) = V_INT(pSource);
1762 ret = true;
1763 break;
1764 case VT_UINT:
1765 *V_UINTREF(pDest) = V_UINT(pSource);
1766 ret = true;
1767 break;
1768 case VT_DECIMAL:
1769 memcpy(pDest->pdecVal, pSource, sizeof(DECIMAL));
1770 ret = true;
1771 break;
1772 default:
1773 break;
1777 else
1779 // Handling of special cases
1780 // Destination and source types are different
1781 if( pDest->vt == (VT_BSTR | VT_BYREF)
1782 && pSource->vt == VT_I2)
1784 // When the user provides a String as out our in/out parameter
1785 // and the type is char (TypeClass_CHAR) then we convert to a BSTR
1786 // instead of VT_I2 as is done otherwise
1787 OLECHAR buff[]= {0,0};
1788 buff[0]= pSource->iVal;
1790 SysFreeString( *pDest->pbstrVal);
1791 *pDest->pbstrVal= SysAllocString( buff);
1792 ret = true;
1797 return ret;
1800 COM_DECLSPEC_NOTHROW STDMETHODIMP InterfaceOleWrapper::Invoke(DISPID dispidMember,
1801 REFIID /*riid*/,
1802 LCID /*lcid*/,
1803 WORD wFlags,
1804 DISPPARAMS * pdispparams,
1805 VARIANT * pvarResult,
1806 EXCEPINFO * pexcepinfo,
1807 UINT * puArgErr )
1809 comphelper::Automation::AutomationInvokedZone aAutomationActive;
1811 OUString sParams;
1812 #if defined SAL_LOG_INFO
1813 sParams += "[";
1814 for (unsigned int i = 0; i < pdispparams->cArgs; ++i)
1816 if (i > 0)
1817 sParams += ",";
1818 std::stringstream aStringStream;
1819 aStringStream << pdispparams->rgvarg[i];
1820 sParams += OUString::createFromAscii(aStringStream.str().c_str());
1822 sParams += "]";
1823 #endif
1824 SAL_INFO("extensions.olebridge", this << "@InterfaceOleWrapper::Invoke(" << dispidMember << "," << sParams << ")");
1826 comphelper::ProfileZone aZone("COM Bridge");
1827 HRESULT ret = S_OK;
1831 bool bHandled= false;
1832 ret= InvokeGeneral( dispidMember, wFlags, pdispparams, pvarResult, pexcepinfo,
1833 puArgErr, bHandled);
1834 if( bHandled)
1835 return ret;
1837 if ((dispidMember > 0) && (o3tl::make_unsigned(dispidMember) <= m_MemberInfos.size()) && m_xInvocation.is())
1839 MemberInfo d = m_MemberInfos[dispidMember - 1];
1840 DWORD flags = wFlags & d.flags;
1842 if (flags != 0)
1844 if ((flags & DISPATCH_METHOD) != 0)
1846 std::unique_ptr<DISPPARAMS> pNewDispParams;
1847 std::vector<VARIANTARG> vNewArgs;
1849 if (pdispparams->cNamedArgs > 0)
1851 // Convert named arguments to positional ones.
1853 // An example:
1855 // Function declaration (in pseudo-code):
1856 // int foo(int A, int B, optional int C, optional int D, optional int E, optional int F, optional int G)
1858 // Corresponding parameter numbers (DISPIDs):
1859 // 0 1 2 3 4 5 6
1861 // Actual call:
1862 // foo(10, 20, E:=50, D:=40, F:=60)
1864 // That is, A and B are passed positionally, D, E, and F as named arguments,
1865 // and the optional C and G parameters are left out.
1867 // Incoming DISPPARAMS:
1868 // cArgs=5, cNamedArgs=3
1869 // rgvarg: [60, 40, 50, 20, 10]
1870 // rgdispidNamedArgs: [5, 3, 4]
1872 // We calculate nLowestNamedArgDispid = 3 and nHighestNamedArgDispid = 5.
1874 // Result of conversion, no named args:
1875 // cArgs=6, cNamedArgs=0
1876 // rgvarg: [60, 50, 40, DISP_E_PARAMNOTFOUND, 20, 10]
1878 // First find the lowest and highest DISPID of the named arguments.
1879 DISPID nLowestNamedArgDispid = 1000000;
1880 DISPID nHighestNamedArgDispid = -1;
1881 for (unsigned int i = 0; i < pdispparams->cNamedArgs; ++i)
1883 if (pdispparams->rgdispidNamedArgs[i] < nLowestNamedArgDispid)
1884 nLowestNamedArgDispid = pdispparams->rgdispidNamedArgs[i];
1885 if (pdispparams->rgdispidNamedArgs[i] > nHighestNamedArgDispid)
1886 nHighestNamedArgDispid = pdispparams->rgdispidNamedArgs[i];
1889 // Make sure named arguments don't overlap with positional ones. The lowest
1890 // DISPID of the named arguments should be >= the number of positional
1891 // arguments.
1892 if (nLowestNamedArgDispid < static_cast<DISPID>(pdispparams->cArgs - pdispparams->cNamedArgs))
1893 return DISP_E_NONAMEDARGS;
1895 // Do the actual conversion.
1896 pNewDispParams.reset(new DISPPARAMS);
1897 vNewArgs.resize(nHighestNamedArgDispid + 1);
1898 pNewDispParams->rgvarg = vNewArgs.data();
1899 pNewDispParams->rgdispidNamedArgs = nullptr;
1900 pNewDispParams->cArgs = nHighestNamedArgDispid + 1;
1901 pNewDispParams->cNamedArgs = 0;
1903 // Initialise all parameter slots as missing
1904 for (int i = 0; i < nHighestNamedArgDispid; ++i)
1906 pNewDispParams->rgvarg[i].vt = VT_ERROR;
1907 pNewDispParams->rgvarg[i].scode = DISP_E_PARAMNOTFOUND;
1910 // Then set the value of those actually present.
1911 for (unsigned int i = 0; i < pdispparams->cNamedArgs; ++i)
1912 pNewDispParams->rgvarg[nHighestNamedArgDispid - pdispparams->rgdispidNamedArgs[i]] = pdispparams->rgvarg[i];
1914 const int nFirstUnnamedArg = pdispparams->cNamedArgs + (nLowestNamedArgDispid-(pdispparams->cArgs - pdispparams->cNamedArgs));
1916 for (unsigned int i = pdispparams->cNamedArgs; i < pdispparams->cArgs; ++i)
1917 pNewDispParams->rgvarg[nFirstUnnamedArg + (i-pdispparams->cNamedArgs)] = pdispparams->rgvarg[i];
1919 pdispparams = pNewDispParams.get();
1922 Sequence<Any> params;
1924 convertDispparamsArgs(dispidMember, wFlags, pdispparams , params );
1926 ret= doInvoke(pdispparams, pvarResult,
1927 pexcepinfo, puArgErr, d.name, params);
1929 else if ((flags & DISPATCH_PROPERTYGET) != 0)
1931 ret= doGetProperty( pdispparams, pvarResult,
1932 pexcepinfo, d.name);
1934 else if ((flags & DISPATCH_PROPERTYPUT) != 0 || (flags & DISPATCH_PROPERTYPUTREF) != 0)
1936 if (pdispparams->cArgs != 1)
1937 ret = DISP_E_BADPARAMCOUNT;
1938 else
1940 Sequence<Any> params;
1941 convertDispparamsArgs(dispidMember, wFlags, pdispparams, params );
1942 if(params.getLength() > 0)
1943 ret= doSetProperty( pdispparams, pvarResult, pexcepinfo, puArgErr, d.name, params);
1944 else
1945 ret = DISP_E_BADVARTYPE;
1949 else
1950 ret= DISP_E_MEMBERNOTFOUND;
1952 else
1953 ret = DISP_E_MEMBERNOTFOUND;
1955 catch(const BridgeRuntimeError& e)
1957 writeExcepinfo(pexcepinfo, e.message);
1958 ret = DISP_E_EXCEPTION;
1960 catch(const Exception& e)
1962 OUString message= "InterfaceOleWrapper::Invoke : \n" +
1963 e.Message;
1964 writeExcepinfo(pexcepinfo, message);
1965 ret = DISP_E_EXCEPTION;
1967 catch(...)
1969 writeExcepinfo(pexcepinfo, "InterfaceOleWrapper::Invoke : \nUnexpected exception");
1970 ret = DISP_E_EXCEPTION;
1973 return ret;
1976 HRESULT InterfaceOleWrapper::doInvoke( DISPPARAMS * pdispparams, VARIANT * pvarResult,
1977 EXCEPINFO * pexcepinfo, unsigned int * puArgErr, OUString& name, Sequence<Any>& params)
1981 HRESULT ret= S_OK;
1984 Sequence<sal_Int16> outIndex;
1985 Sequence<Any> outParams;
1986 Any returnValue;
1988 if (pdispparams->cNamedArgs > 0)
1989 return DISP_E_NONAMEDARGS;
1991 // invoke method and take care of exceptions
1992 returnValue = m_xInvocation->invoke(name,
1993 params,
1994 outIndex,
1995 outParams);
1997 // try to write back out parameter
1998 if (outIndex.getLength() > 0)
2000 const sal_Int16* pOutIndex = outIndex.getConstArray();
2001 const Any* pOutParams = outParams.getConstArray();
2003 for (sal_Int32 i = 0; i < outIndex.getLength(); i++)
2005 CComVariant variant;
2006 // Currently a Sequence is converted to an SafeArray of VARIANTs.
2007 anyToVariant( &variant, pOutParams[i]);
2009 // out parameter need special handling if they are VT_DISPATCH
2010 // and used in JScript
2011 int outindex= pOutIndex[i];
2012 writeBackOutParameter2(&(pdispparams->rgvarg[pdispparams->cArgs - 1 - outindex]),
2013 &variant );
2017 // write back return value
2018 if (pvarResult != nullptr)
2019 anyToVariant(pvarResult, returnValue);
2021 catch(const IllegalArgumentException & e) //XInvocation::invoke
2023 writeExcepinfo(pexcepinfo, e.Message);
2024 ret = DISP_E_TYPEMISMATCH;
2026 catch(const CannotConvertException & e) //XInvocation::invoke
2028 writeExcepinfo(pexcepinfo, e.Message);
2029 ret = mapCannotConvertException( e, puArgErr);
2031 catch(const InvocationTargetException & e) //XInvocation::invoke
2033 const Any& org = e.TargetException;
2034 Exception excTarget;
2035 org >>= excTarget;
2036 OUString message=
2037 org.getValueType().getTypeName() + ": " + excTarget.Message;
2038 writeExcepinfo(pexcepinfo, message);
2039 ret = DISP_E_EXCEPTION;
2041 catch(const NoSuchMethodException & e) //XInvocation::invoke
2043 writeExcepinfo(pexcepinfo, e.Message);
2044 ret = DISP_E_MEMBERNOTFOUND;
2046 catch(const BridgeRuntimeError & e)
2048 writeExcepinfo(pexcepinfo, e.message);
2049 ret = DISP_E_EXCEPTION;
2051 catch(const Exception & e)
2053 OUString message= "InterfaceOleWrapper::doInvoke : \n" +
2054 e.Message;
2055 writeExcepinfo(pexcepinfo, message);
2056 ret = DISP_E_EXCEPTION;
2058 catch( ... )
2060 writeExcepinfo(pexcepinfo, "InterfaceOleWrapper::doInvoke : \nUnexpected exception");
2061 ret = DISP_E_EXCEPTION;
2063 return ret;
2066 HRESULT InterfaceOleWrapper::doGetProperty( DISPPARAMS * /*pdispparams*/, VARIANT * pvarResult,
2067 EXCEPINFO * pexcepinfo, OUString& name)
2069 HRESULT ret= S_OK;
2073 Any returnValue = m_xInvocation->getValue( name);
2074 // write back return value
2075 if (pvarResult)
2076 anyToVariant(pvarResult, returnValue);
2078 catch(const UnknownPropertyException& e) //XInvocation::getValue
2080 writeExcepinfo(pexcepinfo, e.Message);
2081 ret = DISP_E_MEMBERNOTFOUND;
2083 catch(const BridgeRuntimeError& e)
2085 writeExcepinfo(pexcepinfo, e.message);
2086 ret = DISP_E_EXCEPTION;
2088 catch(const Exception& e)
2090 OUString message= "InterfaceOleWrapper::doGetProperty : \n" +
2091 e.Message;
2092 writeExcepinfo(pexcepinfo, message);
2094 catch( ... )
2096 writeExcepinfo(pexcepinfo, "InterfaceOleWrapper::doInvoke : \nUnexpected exception");
2097 ret = DISP_E_EXCEPTION;
2099 return ret;
2102 HRESULT InterfaceOleWrapper::doSetProperty( DISPPARAMS * /*pdispparams*/, VARIANT * /*pvarResult*/,
2103 EXCEPINFO * pexcepinfo, unsigned int * puArgErr, OUString& name, Sequence<Any> const & params)
2105 HRESULT ret= S_OK;
2109 m_xInvocation->setValue( name, params.getConstArray()[0]);
2111 catch(const UnknownPropertyException &)
2113 ret = DISP_E_MEMBERNOTFOUND;
2115 catch(const CannotConvertException &e)
2117 ret= mapCannotConvertException( e, puArgErr);
2119 catch(const InvocationTargetException &e)
2121 if (pexcepinfo != nullptr)
2123 Any org = e.TargetException;
2125 pexcepinfo->wCode = UNO_2_OLE_EXCEPTIONCODE;
2126 pexcepinfo->bstrSource = SysAllocString(L"any ONE component");
2127 pexcepinfo->bstrDescription = SysAllocString(
2128 o3tl::toW(org.getValueType().getTypeName().getStr()));
2130 ret = DISP_E_EXCEPTION;
2132 catch( ... )
2134 ret= DISP_E_EXCEPTION;
2136 return ret;
2139 namespace {
2141 class CXEnumVariant : public IEnumVARIANT,
2142 public CComObjectRoot
2144 public:
2145 CXEnumVariant()
2146 : mnIndex(1) // ooo::vba::XCollection index starts at one
2150 virtual ~CXEnumVariant()
2154 #if defined __clang__
2155 #pragma clang diagnostic push
2156 #pragma clang diagnostic ignored "-Wunused-function"
2157 #endif
2158 BEGIN_COM_MAP(CXEnumVariant)
2159 #if defined __clang__
2160 #pragma clang diagnostic pop
2161 #endif
2162 COM_INTERFACE_ENTRY(IEnumVARIANT)
2163 #if defined __clang__
2164 #pragma clang diagnostic push
2165 #pragma clang diagnostic ignored "-Winconsistent-missing-override"
2166 #pragma clang diagnostic ignored "-Wunused-function"
2167 #endif
2168 END_COM_MAP()
2169 #if defined __clang__
2170 #pragma clang diagnostic pop
2171 #endif
2173 DECLARE_NOT_AGGREGATABLE(CXEnumVariant)
2175 // Creates and initializes the enumerator
2176 void Init(InterfaceOleWrapper* pInterfaceOleWrapper,
2177 const Reference<ooo::vba::XCollection > xCollection)
2179 mpInterfaceOleWrapper = pInterfaceOleWrapper;
2180 mxCollection = xCollection;
2183 // IEnumVARIANT
2184 virtual HRESULT STDMETHODCALLTYPE Clone(IEnumVARIANT **) override
2186 SAL_INFO("extensions.olebridge", this << "@CXEnumVariant::Clone: E_NOTIMPL");
2187 return E_NOTIMPL;
2190 virtual HRESULT STDMETHODCALLTYPE Next(ULONG const celt,
2191 VARIANT *rgVar,
2192 ULONG *pCeltFetched) override
2194 comphelper::Automation::AutomationInvokedZone aAutomationActive;
2196 if (pCeltFetched)
2197 *pCeltFetched = 0;
2199 if (celt == 0)
2201 SAL_INFO("extensions.olebridge", this << "@CXEnumVariant::Next(" << celt << "): E_INVALIDARG");
2202 return E_INVALIDARG;
2205 if (rgVar == nullptr || (celt != 1 && pCeltFetched == nullptr))
2207 SAL_INFO("extensions.olebridge", this << "@CXEnumVariant::Next(" << celt << "): E_FAIL");
2208 return E_FAIL;
2211 for (ULONG i = 0; i < celt; i++)
2212 VariantInit(&rgVar[i]);
2214 ULONG nLeft = celt;
2215 ULONG nReturned = 0;
2216 while (nLeft > 0)
2218 if (mnIndex > mxCollection->getCount())
2220 SAL_INFO("extensions.olebridge", this << "@CXEnumVariant::Next(" << celt << "): got " << nReturned << ": S_FALSE");
2221 return S_FALSE;
2223 Any aIndex;
2224 aIndex <<= mnIndex;
2225 Any aElement = mxCollection->Item(aIndex, Any());
2226 mpInterfaceOleWrapper->anyToVariant(rgVar, aElement);
2227 // rgVar->pdispVal->AddRef(); ??
2228 if (pCeltFetched)
2229 (*pCeltFetched)++;
2230 rgVar++;
2231 nReturned++;
2232 mnIndex++;
2233 nLeft--;
2235 SAL_INFO("extensions.olebridge", this << "@CXEnumVariant::Next(" << celt << "): S_OK");
2236 return S_OK;
2239 virtual HRESULT STDMETHODCALLTYPE Reset() override
2241 SAL_INFO("extensions.olebridge", this << "@CXEnumVariant::Reset: S_OK");
2242 mnIndex = 1;
2243 return S_OK;
2246 virtual HRESULT STDMETHODCALLTYPE STDMETHODCALLTYPE Skip(ULONG const celt) override
2248 comphelper::Automation::AutomationInvokedZone aAutomationActive;
2250 ULONG nLeft = celt;
2251 ULONG nSkipped = 0;
2252 while (nLeft > 0)
2254 if (mnIndex > mxCollection->getCount())
2256 SAL_INFO("extensions.olebridge", this << "@CXEnumVariant::Skip(" << celt << "): skipped " << nSkipped << ": S_FALSE");
2257 return S_FALSE;
2259 mnIndex++;
2260 nLeft--;
2262 SAL_INFO("extensions.olebridge", this << "@CXEnumVariant::Skip(" << celt << "): S_OK");
2263 return S_OK;
2266 private:
2267 InterfaceOleWrapper* mpInterfaceOleWrapper;
2268 Reference<ooo::vba::XCollection> mxCollection;
2269 sal_Int32 mnIndex;
2272 class Sink : public cppu::WeakImplHelper<ooo::vba::XSink>
2274 public:
2275 Sink(IUnknown* pUnkSink,
2276 Reference<XMultiServiceFactory> xMSF,
2277 ooo::vba::TypeAndIID aTypeAndIID,
2278 InterfaceOleWrapper* pInterfaceOleWrapper);
2280 // XSink
2281 void SAL_CALL Call( const OUString& Method, Sequence< Any >& Arguments ) override;
2283 private:
2284 IUnknown* mpUnkSink;
2285 Reference<XMultiServiceFactory> mxMSF;
2286 ooo::vba::TypeAndIID maTypeAndIID;
2287 InterfaceOleWrapper* mpInterfaceOleWrapper;
2292 Sink::Sink(IUnknown* pUnkSink,
2293 Reference<XMultiServiceFactory> xMSF,
2294 ooo::vba::TypeAndIID aTypeAndIID,
2295 InterfaceOleWrapper* pInterfaceOleWrapper) :
2296 mpUnkSink(pUnkSink),
2297 mxMSF(xMSF),
2298 maTypeAndIID(aTypeAndIID),
2299 mpInterfaceOleWrapper(pInterfaceOleWrapper)
2301 mpUnkSink->AddRef();
2304 void SAL_CALL
2305 Sink::Call( const OUString& Method, Sequence< Any >& Arguments )
2307 SAL_INFO("extensions.olebridge", "Sink::Call(" << Method << ", " << Arguments.getLength() << " arguments)");
2309 IDispatch* pDispatch;
2310 HRESULT nResult = mpUnkSink->QueryInterface(IID_IDispatch, reinterpret_cast<void **>(&pDispatch));
2311 if (!SUCCEEDED(nResult))
2313 SAL_WARN("extensions.olebridge", "Sink::Call: Not IDispatch: " << WindowsErrorStringFromHRESULT(nResult));
2314 return;
2317 Reference<XIdlReflection> xRefl = theCoreReflection::get(comphelper::getComponentContext(mxMSF));
2318 assert(xRefl.is());
2320 Reference<XIdlClass> xClass = xRefl->forName(maTypeAndIID.Type.getTypeName());
2321 assert(xClass.is());
2323 auto aMethods = xClass->getMethods();
2324 assert(xClass->getTypeClass() == TypeClass_INTERFACE &&
2325 aMethods.getLength() > 0);
2327 int nMemId = 1;
2328 auto ArgumentsRange = asNonConstRange(Arguments);
2329 // Skip the three XInterface methods
2330 for (int i = 3; i < aMethods.getLength(); i++)
2332 if (aMethods[i]->getName() == Method)
2334 // FIXME: Handle mismatch in type of actual argument and parameter of the method.
2336 // FIXME: Handle mismatch in number of arguments passed and actual number of parameters
2337 // of the method.
2339 auto aParamInfos = aMethods[i]->getParameterInfos();
2341 assert(Arguments.getLength() == aParamInfos.getLength());
2343 DISPPARAMS aDispParams;
2344 aDispParams.rgdispidNamedArgs = nullptr;
2345 aDispParams.cArgs = Arguments.getLength();
2346 aDispParams.cNamedArgs = 0;
2347 aDispParams.rgvarg = new VARIANT[aDispParams.cArgs];
2348 for (unsigned j = 0; j < aDispParams.cArgs; j++)
2350 VariantInit(aDispParams.rgvarg+j);
2351 // Note: Reverse order of arguments in Arguments and aDispParams.rgvarg!
2352 const unsigned nIncomingArgIndex = aDispParams.cArgs - j - 1;
2353 mpInterfaceOleWrapper->anyToVariant(aDispParams.rgvarg+j, Arguments[nIncomingArgIndex]);
2355 // Handle OUT and INOUT arguments. For instance, the second ('Cancel') parameter to
2356 // DocumentBeforeClose() should be a VT_BYREF|VT_BOOL parameter. Need to handle that
2357 // here.
2359 if (aParamInfos[nIncomingArgIndex].aMode == ParamMode_OUT ||
2360 aParamInfos[nIncomingArgIndex].aMode == ParamMode_INOUT)
2362 switch (aDispParams.rgvarg[j].vt)
2364 case VT_I2:
2365 aDispParams.rgvarg[j].byref = new SHORT(aDispParams.rgvarg[j].iVal);
2366 aDispParams.rgvarg[j].vt |= VT_BYREF;
2367 break;
2368 case VT_I4:
2369 aDispParams.rgvarg[j].byref = new LONG(aDispParams.rgvarg[j].lVal);
2370 aDispParams.rgvarg[j].vt |= VT_BYREF;
2371 break;
2372 case VT_BSTR:
2373 aDispParams.rgvarg[j].byref = new BSTR(aDispParams.rgvarg[j].bstrVal);
2374 aDispParams.rgvarg[j].vt |= VT_BYREF;
2375 break;
2376 case VT_BOOL:
2377 aDispParams.rgvarg[j].byref = new VARIANT_BOOL(aDispParams.rgvarg[j].boolVal);
2378 aDispParams.rgvarg[j].vt |= VT_BYREF;
2379 break;
2380 default:
2381 assert(false && "Not handled yet");
2382 break;
2387 VARIANT aVarResult;
2388 VariantInit(&aVarResult);
2389 UINT uArgErr;
2391 // In the case of a VBScript client, which uses "late binding", calling Invoke on the
2392 // sink it provides will cause a callback to our CXTypeInfo::GetNames for the given
2393 // member id, and in that we will tell it the name of the corresponding method, and the
2394 // client will know what event handler to invoke based on that name.
2396 // As the outgoing interfaces used (ooo::vba::word::XApplicationOutgoing and others) are
2397 // totally not stable and not published in any way, there can be no client that would
2398 // have done "compile-time binding" and where the sink would actually be an object with
2399 // a vtbl corresponding to the outgoing interface. Late binding clients that work like
2400 // VBScript is all we support.
2401 SAL_INFO("extensions.olebridge", "Sink::Call(" << Method << "): Calling Invoke(" << nMemId << ")");
2403 nResult = pDispatch->Invoke(nMemId, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &aDispParams, &aVarResult, nullptr, &uArgErr);
2404 SAL_INFO("extensions.olebridge", "Sink::Call(" << Method << "): Invoke() returned");
2406 SAL_WARN_IF(!SUCCEEDED(nResult), "extensions.olebridge", "Call to " << Method << " failed: " << WindowsErrorStringFromHRESULT(nResult));
2408 // Undo VT_BYREF magic done above. Copy out parameters back to the Anys in Arguments
2409 for (unsigned j = 0; j < aDispParams.cArgs; j++)
2411 const unsigned nIncomingArgIndex = aDispParams.cArgs - j - 1;
2412 if (aParamInfos[nIncomingArgIndex].aMode == ParamMode_OUT ||
2413 aParamInfos[nIncomingArgIndex].aMode == ParamMode_INOUT)
2415 switch (aDispParams.rgvarg[j].vt)
2417 case VT_BYREF|VT_I2:
2419 SHORT *pI = static_cast<SHORT*>(aDispParams.rgvarg[j].byref);
2420 ArgumentsRange[nIncomingArgIndex] <<= static_cast<sal_Int16>(*pI);
2421 delete pI;
2423 break;
2424 case VT_BYREF|VT_I4:
2426 LONG *pL = static_cast<LONG*>(aDispParams.rgvarg[j].byref);
2427 ArgumentsRange[nIncomingArgIndex] <<= static_cast<sal_Int32>(*pL);
2428 delete pL;
2430 break;
2431 case VT_BYREF|VT_BSTR:
2433 BSTR *pBstr = static_cast<BSTR*>(aDispParams.rgvarg[j].byref);
2434 ArgumentsRange[nIncomingArgIndex] <<= OUString(o3tl::toU(*pBstr));
2435 // Undo SysAllocString() done in anyToVariant()
2436 SysFreeString(*pBstr);
2437 delete pBstr;
2439 break;
2440 case VT_BYREF|VT_BOOL:
2442 VARIANT_BOOL *pBool = static_cast<VARIANT_BOOL*>(aDispParams.rgvarg[j].byref);
2443 ArgumentsRange[nIncomingArgIndex] <<= (*pBool != VARIANT_FALSE);
2444 delete pBool;
2446 break;
2447 default:
2448 assert(false && "Not handled yet");
2449 break;
2452 else
2454 switch (aDispParams.rgvarg[j].vt)
2456 case VT_BSTR:
2457 // Undo SysAllocString() done in anyToVariant()
2458 SysFreeString(aDispParams.rgvarg[j].bstrVal);
2459 break;
2464 delete[] aDispParams.rgvarg;
2465 return;
2467 nMemId++;
2469 SAL_WARN("extensions.olebridge", "Sink::Call: Unknown method '" << Method << "'");
2472 namespace {
2474 class CXEnumConnections : public IEnumConnections,
2475 public CComObjectRoot
2477 public:
2478 CXEnumConnections()
2482 virtual ~CXEnumConnections()
2486 #if defined __clang__
2487 #pragma clang diagnostic push
2488 #pragma clang diagnostic ignored "-Wunused-function"
2489 #endif
2490 BEGIN_COM_MAP(CXEnumConnections)
2491 #if defined __clang__
2492 #pragma clang diagnostic pop
2493 #endif
2494 COM_INTERFACE_ENTRY(IEnumConnections)
2495 #if defined __clang__
2496 #pragma clang diagnostic push
2497 #pragma clang diagnostic ignored "-Winconsistent-missing-override"
2498 #pragma clang diagnostic ignored "-Wunused-function"
2499 #endif
2500 END_COM_MAP()
2501 #if defined __clang__
2502 #pragma clang diagnostic pop
2503 #endif
2505 DECLARE_NOT_AGGREGATABLE(CXEnumConnections)
2507 void Init(std::vector<IUnknown*>& rUnknowns, std::vector<DWORD>& rCookies)
2509 SAL_INFO("extensions.olebridge", this << "@CXEnumConnections::Init");
2510 SAL_WARN_IF(rUnknowns.size() != rCookies.size(), "extensions.olebridge", "Vectors of different size");
2511 mvUnknowns = rUnknowns;
2512 mvCookies = rCookies;
2513 mnIndex = 0;
2516 virtual HRESULT STDMETHODCALLTYPE Next(ULONG cConnections,
2517 LPCONNECTDATA rgcd,
2518 ULONG *pcFetched) override
2520 comphelper::Automation::AutomationInvokedZone aAutomationActive;
2522 if (!rgcd)
2524 SAL_INFO("extensions.olebridge", this << "@CXEnumConnections::Next(" << cConnections << "): E_POINTER");
2525 return E_POINTER;
2528 if (pcFetched && cConnections != 1)
2530 SAL_INFO("extensions.olebridge", this << "@CXEnumConnections::Next(" << cConnections << "): E_INVALIDARG");
2531 return E_INVALIDARG;
2534 ULONG nFetched = 0;
2535 while (nFetched < cConnections && mnIndex < mvUnknowns.size())
2537 rgcd[nFetched].pUnk = mvUnknowns[mnIndex];
2538 rgcd[nFetched].pUnk->AddRef();
2539 rgcd[nFetched].dwCookie = mvCookies[mnIndex];
2540 ++nFetched;
2541 ++mnIndex;
2543 if (nFetched != cConnections)
2545 SAL_INFO("extensions.olebridge", this << "@CXEnumConnections::Next(" << cConnections << "): S_FALSE");
2546 if (pcFetched)
2547 *pcFetched = nFetched;
2548 return S_FALSE;
2550 SAL_INFO("extensions.olebridge", this << "@CXEnumConnections::Next(" << cConnections << "): S_OK");
2551 if (pcFetched)
2552 *pcFetched = nFetched;
2554 return S_OK;
2557 virtual HRESULT STDMETHODCALLTYPE Skip(ULONG cConnections) override
2559 SAL_INFO("extensions.olebridge", this << "@CXEnumConnections::Skip(" << cConnections << "): E_NOTIMPL");
2561 return E_NOTIMPL;
2564 virtual HRESULT STDMETHODCALLTYPE Reset() override
2566 SAL_INFO("extensions.olebridge", this << "@CXEnumConnections::Reset: E_NOTIMPL");
2568 return E_NOTIMPL;
2571 virtual HRESULT STDMETHODCALLTYPE Clone(IEnumConnections** /* ppEnum */) override
2573 SAL_INFO("extensions.olebridge", this << "@CXEnumConnections::Clone: E_NOTIMPL");
2575 return E_NOTIMPL;
2578 private:
2579 std::vector<IUnknown*> mvUnknowns;
2580 std::vector<DWORD> mvCookies;
2581 ULONG mnIndex;
2584 class CXConnectionPoint : public IConnectionPoint,
2585 public CComObjectRoot
2587 public:
2588 #if defined __clang__
2589 #pragma clang diagnostic push
2590 #pragma clang diagnostic ignored "-Wunused-function"
2591 #endif
2592 BEGIN_COM_MAP(CXConnectionPoint)
2593 #if defined __clang__
2594 #pragma clang diagnostic pop
2595 #endif
2596 COM_INTERFACE_ENTRY(IConnectionPoint)
2597 #if defined __clang__
2598 #pragma clang diagnostic push
2599 #pragma clang diagnostic ignored "-Winconsistent-missing-override"
2600 #pragma clang diagnostic ignored "-Wunused-function"
2601 #endif
2602 END_COM_MAP()
2603 #if defined __clang__
2604 #pragma clang diagnostic pop
2605 #endif
2607 DECLARE_NOT_AGGREGATABLE(CXConnectionPoint)
2609 virtual ~CXConnectionPoint() {}
2611 void Init(InterfaceOleWrapper* pInterfaceOleWrapper,
2612 Reference<ooo::vba::XConnectionPoint>& xCP,
2613 Reference<XMultiServiceFactory>& xMSF,
2614 ooo::vba::TypeAndIID aTypeAndIID)
2616 SAL_INFO("extensions.olebridge", this << "@CXConnectionPoint::Init for " << pInterfaceOleWrapper->getImplementationName());
2618 IUnknown *pUnknown;
2619 if (SUCCEEDED(QueryInterface(IID_IUnknown, reinterpret_cast<void **>(&pUnknown))))
2621 // In case QI for IUnknown returns a different pointer, but nah, it doesn't
2622 SAL_INFO("extensions.olebridge", " (IUnknown@" << pUnknown << ")");
2625 mpInterfaceOleWrapper = pInterfaceOleWrapper;
2626 mxCP = xCP;
2627 mxMSF = xMSF;
2628 maTypeAndIID = aTypeAndIID;
2631 virtual HRESULT STDMETHODCALLTYPE GetConnectionInterface(IID *pIID) override
2633 SAL_WARN("extensions.olebridge", this << "@CXConnectionPoint::GetConnectionInterface(" << *pIID << "): E_NOTIMPL");
2635 // FIXME: Needed?
2637 return E_NOTIMPL;
2640 virtual HRESULT STDMETHODCALLTYPE GetConnectionPointContainer(IConnectionPointContainer **) override
2642 SAL_WARN("extensions.olebridge", this << "@CXConnectionPoint::GetConnectionInterface: E_NOTIMPL");
2644 // FIXME: Needed?
2646 return E_NOTIMPL;
2649 virtual HRESULT STDMETHODCALLTYPE Advise(IUnknown *pUnkSink,
2650 DWORD *pdwCookie) override
2652 comphelper::Automation::AutomationInvokedZone aAutomationActive;
2654 SAL_INFO("extensions.olebridge", this << "@CXConnectionPoint::Advise(" << pUnkSink << ")");
2656 if (!pdwCookie)
2657 return E_POINTER;
2659 Reference<ooo::vba::XSink> xSink(new Sink(pUnkSink, mxMSF, maTypeAndIID, mpInterfaceOleWrapper));
2661 mvISinks.push_back(pUnkSink);
2662 *pdwCookie = mvISinks.size();
2664 mvCookies.push_back(mxCP->Advise(xSink));
2666 mvXSinks.push_back(xSink);
2668 SAL_INFO("extensions.olebridge", " *pdwCookie: " << *pdwCookie);
2670 return S_OK;
2673 virtual HRESULT STDMETHODCALLTYPE Unadvise(DWORD dwCookie) override
2675 comphelper::Automation::AutomationInvokedZone aAutomationActive;
2677 SAL_INFO("extensions.olebridge", this << "@CXConnectionPoint::Unadvise(" << dwCookie << ")");
2679 if (dwCookie == 0 || dwCookie > mvISinks.size())
2680 return E_POINTER;
2682 mvISinks[dwCookie-1] = nullptr;
2684 mxCP->Unadvise(mvCookies[dwCookie-1]);
2686 mvXSinks[dwCookie-1] = Reference<ooo::vba::XSink>();
2688 return S_OK;
2691 virtual HRESULT STDMETHODCALLTYPE EnumConnections(IEnumConnections **ppEnum) override
2693 comphelper::Automation::AutomationInvokedZone aAutomationActive;
2695 HRESULT nResult;
2697 SAL_INFO("extensions.olebridge", this << "@CXConnectionPoint::EnumConnections...");
2699 if (!ppEnum)
2701 SAL_INFO("extensions.olebridge", "..." << this << "@CXConnectionPoint::EnumConnections: E_POINTER");
2702 return E_POINTER;
2705 CComObject<CXEnumConnections>* pEnumConnections;
2707 nResult = CComObject<CXEnumConnections>::CreateInstance(&pEnumConnections);
2708 if (FAILED(nResult))
2710 SAL_INFO("extensions.olebridge", "..." << this << "@CXConnectionPoint::EnumConnections: " << WindowsErrorStringFromHRESULT(nResult));
2711 return nResult;
2714 pEnumConnections->AddRef();
2716 pEnumConnections->Init(mvISinks, mvCookies);
2717 *ppEnum = pEnumConnections;
2719 SAL_INFO("extensions.olebridge", "..." << this << "@CXConnectionPoint::EnumConnections: S_OK");
2721 return S_OK;
2724 InterfaceOleWrapper* mpInterfaceOleWrapper;
2725 std::vector<IUnknown*> mvISinks;
2726 std::vector<Reference<ooo::vba::XSink>> mvXSinks;
2727 std::vector<DWORD> mvCookies;
2728 Reference<XMultiServiceFactory> mxMSF;
2729 Reference<ooo::vba::XConnectionPoint> mxCP;
2730 ooo::vba::TypeAndIID maTypeAndIID;
2735 HRESULT InterfaceOleWrapper::InvokeGeneral( DISPID dispidMember, unsigned short wFlags,
2736 DISPPARAMS * pdispparams, VARIANT * pvarResult, EXCEPINFO * pexcepinfo,
2737 unsigned int * /*puArgErr*/, bool& bHandled)
2739 HRESULT ret= S_OK;
2742 // DISPID_VALUE | The DEFAULT Value is required in JScript when the situation
2743 // is that we put an object into an Array object ( out parameter). We have to return
2744 // IDispatch otherwise the object cannot be accessed from the Script.
2745 if( dispidMember == DISPID_VALUE && (wFlags & DISPATCH_PROPERTYGET) != 0
2746 && m_defaultValueType != VT_EMPTY && pvarResult != nullptr)
2748 // Special case hack: If it is a ScVbaCheckBox, return the boolean value
2749 Reference<ooo::vba::msforms::XCheckBox> xCheckBox(m_xOrigin, UNO_QUERY);
2750 if (xCheckBox.is())
2752 bHandled = true;
2753 Any aValue = xCheckBox->getValue();
2754 anyToVariant(pvarResult, aValue);
2755 return S_OK;
2758 bHandled= true;
2759 if( m_defaultValueType == VT_DISPATCH)
2761 pvarResult->vt= VT_DISPATCH;
2762 pvarResult->pdispVal= this;
2763 AddRef();
2764 ret= S_OK;
2768 // function: _GetValueObject
2769 else if( dispidMember == DISPID_JSCRIPT_VALUE_FUNC)
2771 bHandled= true;
2772 if( !pvarResult)
2773 return E_POINTER;
2774 CComObject< JScriptValue>* pValue;
2775 if( SUCCEEDED( CComObject<JScriptValue>::CreateInstance( &pValue)))
2777 pValue->AddRef();
2778 pvarResult->vt= VT_DISPATCH;
2779 pvarResult->pdispVal= CComQIPtr<IDispatch>(pValue->GetUnknown());
2780 ret= S_OK;
2782 else
2783 ret= DISP_E_EXCEPTION;
2785 else if( dispidMember == DISPID_GET_STRUCT_FUNC)
2787 bHandled= true;
2788 bool bStruct= false;
2791 Reference<XIdlReflection> xRefl = theCoreReflection::get(comphelper::getComponentContext(m_smgr));
2792 // the first parameter is in DISPPARAMS rgvargs contains the name of the struct.
2793 CComVariant arg;
2794 if( pdispparams->cArgs == 1 && SUCCEEDED( arg.ChangeType( VT_BSTR, &pdispparams->rgvarg[0])) )
2796 Reference<XIdlClass> classStruct= xRefl->forName(OUString(o3tl::toU(arg.bstrVal)));
2797 if( classStruct.is())
2799 Any anyStruct;
2800 classStruct->createObject( anyStruct);
2801 CComVariant var;
2802 anyToVariant( &var, anyStruct );
2804 if( var.vt == VT_DISPATCH)
2806 VariantCopy( pvarResult, & var);
2807 bStruct= true;
2811 ret= bStruct ? S_OK : DISP_E_EXCEPTION;
2813 else if (dispidMember == DISPID_CREATE_TYPE_FUNC)
2815 bHandled= true;
2816 if( !pvarResult)
2817 return E_POINTER;
2818 // the first parameter is in DISPPARAMS rgvargs contains the name of the struct.
2819 CComVariant arg;
2820 if( pdispparams->cArgs != 1)
2821 return DISP_E_BADPARAMCOUNT;
2822 if (FAILED( arg.ChangeType( VT_BSTR, &pdispparams->rgvarg[0])))
2823 return DISP_E_BADVARTYPE;
2825 //check if the provided name represents a valid type
2826 Type type;
2827 if (!getType(arg.bstrVal, type))
2829 writeExcepinfo(pexcepinfo, OUString::Concat("[automation bridge] A UNO type with the name ") +
2830 o3tl::toU(arg.bstrVal) + " does not exist!");
2831 return DISP_E_EXCEPTION;
2834 if (!createUnoTypeWrapper(arg.bstrVal, pvarResult))
2836 writeExcepinfo(pexcepinfo, "[automation bridge] InterfaceOleWrapper::InvokeGeneral\n"
2837 "Could not initialize UnoTypeWrapper object!");
2838 return DISP_E_EXCEPTION;
2841 else if (dispidMember == DISPID_NEWENUM)
2843 bHandled = true;
2844 if( !pvarResult)
2845 return E_POINTER;
2847 Reference< ooo::vba::XCollection> xCollection(m_xOrigin, UNO_QUERY);
2848 if (!xCollection.is())
2849 return DISP_E_MEMBERNOTFOUND;
2851 CComObject<CXEnumVariant>* pEnumVar;
2853 ret = CComObject<CXEnumVariant>::CreateInstance(&pEnumVar);
2854 if (FAILED(ret))
2855 return ret;
2857 pEnumVar->AddRef();
2859 pEnumVar->Init(this, xCollection);
2861 pvarResult->vt = VT_UNKNOWN;
2862 pvarResult->punkVal = nullptr;
2864 ret = pEnumVar->QueryInterface(IID_IUnknown, reinterpret_cast<void**>(&pvarResult->punkVal));
2865 if (FAILED(ret))
2867 pEnumVar->Release();
2868 return ret;
2872 catch(const BridgeRuntimeError & e)
2874 writeExcepinfo(pexcepinfo, e.message);
2875 ret = DISP_E_EXCEPTION;
2877 catch(const Exception & e)
2879 OUString message= "InterfaceOleWrapper::InvokeGeneral : \n" +
2880 e.Message;
2881 writeExcepinfo(pexcepinfo, message);
2882 ret = DISP_E_EXCEPTION;
2884 catch( ... )
2886 writeExcepinfo(pexcepinfo, "InterfaceOleWrapper::InvokeGeneral : \nUnexpected exception");
2887 ret = DISP_E_EXCEPTION;
2889 return ret;
2892 STDMETHODIMP InterfaceOleWrapper::GetDispID(BSTR /*bstrName*/, DWORD /*grfdex*/, DISPID __RPC_FAR* /*pid*/)
2894 return ResultFromScode(E_NOTIMPL);
2897 STDMETHODIMP InterfaceOleWrapper::InvokeEx(
2898 /* [in] */ DISPID /*id*/,
2899 /* [in] */ LCID /*lcid*/,
2900 /* [in] */ WORD /*wFlags*/,
2901 /* [in] */ DISPPARAMS __RPC_FAR* /*pdp*/,
2902 /* [out] */ VARIANT __RPC_FAR* /*pvarRes*/,
2903 /* [out] */ EXCEPINFO __RPC_FAR* /*pei*/,
2904 /* [unique][in] */ IServiceProvider __RPC_FAR* /*pspCaller*/)
2906 return ResultFromScode(E_NOTIMPL);
2909 STDMETHODIMP InterfaceOleWrapper::DeleteMemberByName(
2910 /* [in] */ BSTR /*bstr*/,
2911 /* [in] */ DWORD /*grfdex*/)
2913 return ResultFromScode(E_NOTIMPL);
2916 STDMETHODIMP InterfaceOleWrapper::DeleteMemberByDispID(DISPID /*id*/)
2918 return ResultFromScode(E_NOTIMPL);
2921 STDMETHODIMP InterfaceOleWrapper::GetMemberProperties(
2922 /* [in] */ DISPID /*id*/,
2923 /* [in] */ DWORD /*grfdexFetch*/,
2924 /* [out] */ DWORD __RPC_FAR* /*pgrfdex*/)
2926 return ResultFromScode(E_NOTIMPL);
2929 STDMETHODIMP InterfaceOleWrapper::GetMemberName(
2930 /* [in] */ DISPID /*id*/,
2931 /* [out] */ BSTR __RPC_FAR* /*pbstrName*/)
2933 return ResultFromScode(E_NOTIMPL);
2936 STDMETHODIMP InterfaceOleWrapper::GetNextDispID(
2937 /* [in] */ DWORD /*grfdex*/,
2938 /* [in] */ DISPID /*id*/,
2939 /* [out] */ DISPID __RPC_FAR* /*pid*/)
2941 return ResultFromScode(E_NOTIMPL);
2944 STDMETHODIMP InterfaceOleWrapper::GetNameSpaceParent(
2945 /* [out] */ IUnknown __RPC_FAR *__RPC_FAR* /*ppunk*/)
2947 return ResultFromScode(E_NOTIMPL);
2950 // IProvideClassInfo
2951 HRESULT STDMETHODCALLTYPE InterfaceOleWrapper::GetClassInfo (
2952 /* [out] */ ITypeInfo **ppTI)
2954 comphelper::Automation::AutomationInvokedZone aAutomationActive;
2956 SAL_INFO("extensions.olebridge", this << "@InterfaceOleWrapper::GetClassInfo");
2958 if (!ppTI)
2959 return E_POINTER;
2961 Reference<ooo::vba::XInterfaceWithIID> xIID(m_xOrigin, UNO_QUERY);
2962 if (!xIID.is())
2963 return E_NOTIMPL;
2965 OUString sIID = xIID->getIID();
2966 IID aIID;
2967 if (!SUCCEEDED(IIDFromString(reinterpret_cast<LPOLESTR>(sIID.pData->buffer), &aIID)))
2968 return E_NOTIMPL;
2970 HRESULT ret;
2972 CComObject<CXTypeInfo>* pTypeInfo;
2974 ret = CComObject<CXTypeInfo>::CreateInstance(&pTypeInfo);
2975 if (FAILED(ret))
2976 return ret;
2978 pTypeInfo->AddRef();
2980 pTypeInfo->InitForCoclass(m_xOrigin, m_sImplementationName, aIID, m_smgr);
2982 *ppTI = pTypeInfo;
2984 return S_OK;
2987 // IConnectionPointContainer
2988 HRESULT STDMETHODCALLTYPE InterfaceOleWrapper::EnumConnectionPoints(
2989 /* [out] */ IEnumConnectionPoints **)
2991 SAL_INFO("extensions.olebridge", this << "@InterfaceOleWrapper::EnumConnectionPoints");
2992 return ResultFromScode(E_NOTIMPL);
2995 HRESULT STDMETHODCALLTYPE InterfaceOleWrapper::FindConnectionPoint(
2996 /* [in] */ REFIID riid,
2997 /* [out] */ IConnectionPoint **ppCP)
2999 comphelper::Automation::AutomationInvokedZone aAutomationActive;
3001 SAL_INFO("extensions.olebridge", this << "@InterfaceOleWrapper::FindConnectionPoint(" << riid << ")");
3003 if (!ppCP)
3004 return E_POINTER;
3006 Reference<ooo::vba::XConnectable> xConnectable(m_xOrigin, UNO_QUERY);
3008 // We checked already
3009 assert(xConnectable.is());
3010 if (!xConnectable.is())
3011 return E_NOTIMPL;
3013 ooo::vba::TypeAndIID aTypeAndIID = xConnectable->GetConnectionPoint();
3015 IID aIID;
3016 if (!SUCCEEDED(IIDFromString(reinterpret_cast<LPOLESTR>(aTypeAndIID.IID.pData->buffer), &aIID)))
3017 return E_INVALIDARG;
3019 if (!IsEqualIID(riid, aIID))
3020 return E_INVALIDARG;
3022 Reference<ooo::vba::XConnectionPoint> xCP = xConnectable->FindConnectionPoint();
3023 if (!xCP.is())
3024 return E_INVALIDARG;
3026 HRESULT ret;
3028 CComObject<CXConnectionPoint>* pConnectionPoint;
3030 ret = CComObject<CXConnectionPoint>::CreateInstance(&pConnectionPoint);
3031 if (FAILED(ret))
3032 return ret;
3034 pConnectionPoint->AddRef();
3036 pConnectionPoint->Init(this, xCP, m_smgr, aTypeAndIID);
3038 *ppCP = pConnectionPoint;
3040 return S_OK;
3043 // UnoObjectWrapperRemoteOpt ---------------------------------------------------
3045 UnoObjectWrapperRemoteOpt::UnoObjectWrapperRemoteOpt( Reference<XMultiServiceFactory> const & aFactory,
3046 sal_uInt8 unoWrapperClass, sal_uInt8 comWrapperClass):
3047 InterfaceOleWrapper( aFactory, unoWrapperClass, comWrapperClass),
3048 m_currentId(1)
3052 UnoObjectWrapperRemoteOpt::~UnoObjectWrapperRemoteOpt()
3056 // UnoConversionUtilities
3057 Reference< XInterface > UnoObjectWrapperRemoteOpt::createUnoWrapperInstance()
3059 Reference<XWeak> xWeak= static_cast<XWeak*>( new UnoObjectWrapperRemoteOpt(
3060 m_smgr, m_nUnoWrapperClass, m_nComWrapperClass));
3061 return Reference<XInterface>( xWeak, UNO_QUERY);
3064 COM_DECLSPEC_NOTHROW STDMETHODIMP UnoObjectWrapperRemoteOpt::GetIDsOfNames ( REFIID /*riid*/, LPOLESTR * rgszNames, UINT cNames,
3065 LCID /*lcid*/, DISPID * rgdispid )
3067 MutexGuard guard( getBridgeMutex());
3069 if( ! rgdispid)
3070 return E_POINTER;
3071 HRESULT ret = E_UNEXPECTED;
3073 // _GetValueObject
3074 if( ! wcscmp( *rgszNames, JSCRIPT_VALUE_FUNC))
3076 *rgdispid= DISPID_JSCRIPT_VALUE_FUNC;
3077 return S_OK;
3079 else if( ! wcscmp( *rgszNames, GET_STRUCT_FUNC))
3081 *rgdispid= DISPID_GET_STRUCT_FUNC;
3082 return S_OK;
3085 if (m_xInvocation.is() && (cNames > 0))
3087 OUString name(o3tl::toU(rgszNames[0]));
3088 // has this name been determined as "bad"
3089 BadNameMap::iterator badIter= m_badNameMap.find( name);
3090 if( badIter == m_badNameMap.end() )
3092 // name has not been bad before( member exists
3093 typedef NameToIdMap::iterator ITnames;
3094 std::pair< ITnames, bool > pair_id= m_nameToDispIdMap.emplace(name, m_currentId++);
3095 // new ID inserted ?
3096 if( pair_id.second )
3097 {// yes, now create MemberInfo and ad to IdToMemberInfoMap
3098 MemberInfo d(0, name);
3099 m_idToMemberInfoMap.emplace(m_currentId - 1, d);
3102 *rgdispid = pair_id.first->second;
3103 ret = S_OK;
3105 else
3106 ret= DISP_E_UNKNOWNNAME;
3108 return ret;
3111 COM_DECLSPEC_NOTHROW STDMETHODIMP UnoObjectWrapperRemoteOpt::Invoke ( DISPID dispidMember, REFIID /*riid*/, LCID /*lcid*/, WORD wFlags,
3112 DISPPARAMS * pdispparams, VARIANT * pvarResult, EXCEPINFO * pexcepinfo,
3113 UINT * puArgErr )
3115 comphelper::Automation::AutomationInvokedZone aAutomationActive;
3117 HRESULT ret = S_OK;
3120 bool bHandled= false;
3121 ret= InvokeGeneral( dispidMember, wFlags, pdispparams, pvarResult, pexcepinfo,
3122 puArgErr, bHandled);
3123 if( bHandled)
3124 return ret;
3126 if ( dispidMember > 0 && m_xInvocation.is())
3129 IdToMemberInfoMap::iterator it_MemberInfo= m_idToMemberInfoMap.find( dispidMember);
3130 if( it_MemberInfo != m_idToMemberInfoMap.end() )
3132 MemberInfo& info= it_MemberInfo->second;
3134 Sequence<Any> params; // holds converted any s
3135 if( ! info.flags )
3136 { // DISPID called for the first time
3137 if( wFlags == DISPATCH_METHOD )
3139 convertDispparamsArgs(dispidMember, wFlags, pdispparams, params );
3141 if( FAILED( ret= doInvoke( pdispparams, pvarResult,
3142 pexcepinfo, puArgErr, info.name, params))
3143 && ret == DISP_E_MEMBERNOTFOUND)
3145 // try to get the exact name
3146 OUString exactName;
3147 if (m_xExactName.is())
3149 exactName = m_xExactName->getExactName( info.name);
3150 // invoke again
3151 if( !exactName.isEmpty() )
3153 if( SUCCEEDED( ret= doInvoke( pdispparams, pvarResult,
3154 pexcepinfo, puArgErr, exactName, params)))
3155 info.name= exactName;
3159 if( SUCCEEDED( ret ) )
3160 info.flags= DISPATCH_METHOD;
3162 else if( wFlags == DISPATCH_PROPERTYPUT || wFlags == DISPATCH_PROPERTYPUTREF)
3164 convertDispparamsArgs(dispidMember, wFlags, pdispparams, params );
3165 if( FAILED( ret= doSetProperty( pdispparams, pvarResult,
3166 pexcepinfo, puArgErr, info.name, params))
3167 && ret == DISP_E_MEMBERNOTFOUND)
3169 // try to get the exact name
3170 OUString exactName;
3171 if (m_xExactName.is())
3173 exactName = m_xExactName->getExactName( info.name);
3174 // invoke again
3175 if( !exactName.isEmpty() )
3177 if( SUCCEEDED( ret= doSetProperty( pdispparams, pvarResult,
3178 pexcepinfo, puArgErr, exactName, params)))
3179 info.name= exactName;
3183 if( SUCCEEDED( ret ) )
3184 info.flags= DISPATCH_PROPERTYPUT | DISPATCH_PROPERTYGET;
3186 else if( wFlags == DISPATCH_PROPERTYGET)
3188 if( FAILED( ret= doGetProperty( pdispparams, pvarResult,
3189 pexcepinfo, info.name))
3190 && ret == DISP_E_MEMBERNOTFOUND)
3192 // try to get the exact name
3193 OUString exactName;
3194 if (m_xExactName.is())
3196 exactName = m_xExactName->getExactName( info.name);
3197 // invoke again
3198 if( !exactName.isEmpty() )
3200 if( SUCCEEDED( ret= doGetProperty( pdispparams, pvarResult,
3201 pexcepinfo, exactName)))
3202 info.name= exactName;
3206 if( SUCCEEDED( ret ) )
3207 info.flags= DISPATCH_PROPERTYGET | DISPATCH_PROPERTYPUT;
3209 else if( wFlags & DISPATCH_METHOD &&
3210 (wFlags & DISPATCH_PROPERTYPUT || wFlags & DISPATCH_PROPERTYPUTREF))
3213 OUString exactName;
3214 // convert params for DISPATCH_METHOD or DISPATCH_PROPERTYPUT
3215 convertDispparamsArgs(dispidMember, wFlags, pdispparams, params );
3216 // try first as method
3217 if( FAILED( ret= doInvoke( pdispparams, pvarResult,
3218 pexcepinfo, puArgErr, info.name, params))
3219 && ret == DISP_E_MEMBERNOTFOUND)
3221 // try to get the exact name
3222 if (m_xExactName.is())
3224 exactName = m_xExactName->getExactName( info.name);
3225 // invoke again
3226 if( !exactName.isEmpty() )
3228 if( SUCCEEDED( ret= doInvoke( pdispparams, pvarResult,
3229 pexcepinfo, puArgErr, exactName, params)))
3230 info.name= exactName;
3234 if( SUCCEEDED( ret ) )
3235 info.flags= DISPATCH_METHOD;
3237 // try as property
3238 if( FAILED( ret) && pdispparams->cArgs == 1)
3240 if( FAILED( ret= doSetProperty( pdispparams, pvarResult,
3241 pexcepinfo, puArgErr, info.name, params))
3242 && ret == DISP_E_MEMBERNOTFOUND)
3244 // try to get the exact name
3245 if( !exactName.isEmpty() )
3247 if( SUCCEEDED( ret= doSetProperty( pdispparams, pvarResult,
3248 pexcepinfo, puArgErr, exactName, params)))
3249 info.name= exactName;
3252 if( SUCCEEDED( ret ) )
3253 info.flags= DISPATCH_PROPERTYPUT | DISPATCH_PROPERTYGET;
3256 else if( wFlags & DISPATCH_METHOD && wFlags & DISPATCH_PROPERTYGET)
3258 OUString exactName;
3259 convertDispparamsArgs(dispidMember, wFlags, pdispparams, params );
3261 if( FAILED( ret= doInvoke( pdispparams, pvarResult,
3262 pexcepinfo, puArgErr, info.name, params))
3263 && ret == DISP_E_MEMBERNOTFOUND)
3265 // try to get the exact name
3266 if (m_xExactName.is())
3268 exactName = m_xExactName->getExactName( info.name);
3269 // invoke again
3270 if( !exactName.isEmpty() )
3272 if( SUCCEEDED( ret= doInvoke( pdispparams, pvarResult,
3273 pexcepinfo, puArgErr, exactName, params)))
3274 info.name= exactName;
3278 if( SUCCEEDED( ret ) )
3279 info.flags= DISPATCH_METHOD;
3281 // try as property
3282 if( FAILED( ret) && pdispparams->cArgs == 1)
3284 if( FAILED( ret= doGetProperty( pdispparams, pvarResult,
3285 pexcepinfo, info.name))
3286 && ret == DISP_E_MEMBERNOTFOUND)
3288 if( !exactName.isEmpty() )
3290 if( SUCCEEDED( ret= doSetProperty( pdispparams, pvarResult,
3291 pexcepinfo, puArgErr, exactName, params)))
3292 info.name= exactName;
3295 if( SUCCEEDED( ret ) )
3296 info.flags= DISPATCH_PROPERTYGET;
3300 // update information about this member
3301 if( ret == DISP_E_MEMBERNOTFOUND)
3303 // Remember the name as not existing
3304 // and remove the MemberInfo
3305 m_badNameMap[info.name]= false;
3306 m_idToMemberInfoMap.erase( it_MemberInfo);
3308 } // if( ! info.flags )
3309 else // IdToMemberInfoMap contains a MemberInfo
3311 if( wFlags & DISPATCH_METHOD && info.flags == DISPATCH_METHOD)
3313 convertDispparamsArgs(dispidMember, wFlags, pdispparams, params );
3314 ret= doInvoke( pdispparams, pvarResult,
3315 pexcepinfo, puArgErr, info.name, params);
3317 else if( (wFlags & DISPATCH_PROPERTYPUT || wFlags & DISPATCH_PROPERTYPUTREF ) &&
3318 info.flags & DISPATCH_PROPERTYPUT)
3320 convertDispparamsArgs(dispidMember, wFlags, pdispparams, params );
3321 ret= doSetProperty( pdispparams, pvarResult,
3322 pexcepinfo, puArgErr, info.name, params);
3324 else if( (wFlags & DISPATCH_PROPERTYGET) && ( info.flags & DISPATCH_PROPERTYGET))
3326 ret= doGetProperty( pdispparams, pvarResult,
3327 pexcepinfo, info.name);
3329 else
3331 ret= DISP_E_MEMBERNOTFOUND;
3334 }// if( it_MemberInfo != m_idToMemberInfoMap.end() )
3335 else
3336 ret= DISP_E_MEMBERNOTFOUND;
3339 catch(const BridgeRuntimeError& e)
3341 writeExcepinfo(pexcepinfo, e.message);
3342 ret = DISP_E_EXCEPTION;
3344 catch(const Exception& e)
3346 OUString message= "UnoObjectWrapperRemoteOpt::Invoke : \n" +
3347 e.Message;
3348 writeExcepinfo(pexcepinfo, message);
3349 ret = DISP_E_EXCEPTION;
3351 catch(...)
3353 writeExcepinfo(pexcepinfo, "UnoObjectWrapperRemoteOpt::Invoke : \nUnexpected exception");
3354 ret = DISP_E_EXCEPTION;
3357 return ret;
3360 HRESULT UnoObjectWrapperRemoteOpt::methodInvoke( DISPID /*dispidMember*/, DISPPARAMS * /*pdispparams*/, VARIANT * /*pvarResult*/,
3361 EXCEPINFO * /*pexcepinfo*/, unsigned int * /*puArgErr*/, Sequence<Any> const &)
3363 return S_OK;
3366 // The returned HRESULT is only appropriate for IDispatch::Invoke
3367 static HRESULT mapCannotConvertException(const CannotConvertException &e, unsigned int * puArgErr)
3369 HRESULT ret;
3370 bool bWriteIndex= true;
3372 switch ( e.Reason)
3374 case FailReason::OUT_OF_RANGE:
3375 ret = DISP_E_OVERFLOW;
3376 break;
3377 case FailReason::IS_NOT_NUMBER:
3378 ret = DISP_E_TYPEMISMATCH;
3379 break;
3380 case FailReason::IS_NOT_ENUM:
3381 ret = DISP_E_TYPEMISMATCH;
3382 break;
3383 case FailReason::IS_NOT_BOOL:
3384 ret = DISP_E_TYPEMISMATCH;
3385 break;
3386 case FailReason::NO_SUCH_INTERFACE:
3387 ret = DISP_E_TYPEMISMATCH;
3388 break;
3389 case FailReason::SOURCE_IS_NO_DERIVED_TYPE:
3390 ret = DISP_E_TYPEMISMATCH;
3391 break;
3392 case FailReason::TYPE_NOT_SUPPORTED:
3393 ret = DISP_E_TYPEMISMATCH;
3394 break;
3395 case FailReason::INVALID:
3396 ret = DISP_E_TYPEMISMATCH;
3397 break;
3398 case FailReason::NO_DEFAULT_AVAILABLE:
3399 ret = DISP_E_BADPARAMCOUNT;
3400 break;
3401 case FailReason::UNKNOWN:
3402 ret = E_UNEXPECTED;
3403 break;
3404 default:
3405 ret = E_UNEXPECTED;
3406 bWriteIndex= false;
3407 break;
3410 if( bWriteIndex && puArgErr != nullptr)
3411 *puArgErr = e.ArgumentIndex;
3412 return ret;
3415 // The function maps the TypeClass of the any to VARTYPE: If
3416 // the Any contains STRUCT or INTERFACE then the return value
3417 // is VT_DISPATCH. The function is used from o2u_createUnoObjectWrapper
3418 // and the result is put into the constructor of the uno - wrapper
3419 // object. If a client asks the object for DISPID_VALUE and this
3420 // function returned VT_DISPATCH then the IDispatch of the same
3421 // object is being returned.
3422 // See InterfaceOleWrapper::Invoke, InterfaceOleWrapper::m_defaultValueType
3423 VARTYPE getVarType( const Any& value)
3425 VARTYPE ret= VT_EMPTY;
3427 switch ( value.getValueTypeClass())
3429 case TypeClass_STRUCT: ret= VT_DISPATCH; break;
3430 case TypeClass_INTERFACE: ret= VT_DISPATCH; break;
3431 default: break;
3433 return ret;
3436 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */