summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTor Lillqvist <tml@collabora.com>2018-06-11 19:53:06 +0300
committerTor Lillqvist <tml@collabora.com>2018-06-12 07:33:42 +0200
commitf9e9012e75afe4418f4ebe652fa99a1fa2348a71 (patch)
tree8e8f49aecf0238c88dc694e99145bc4fd859d7e9
parent90e4c55d01637178418c33ffe818263114a53374 (diff)
Support named arguments in InterfaceOleWrapper::Invoke()
Convert a DISPPARAMS with named arguments into one with just positional ones. If there are gaps, use markers for them (VARIANTs with VT_ERROR:DISP_E_PARAMNOTFOUND). Those are then passed on as empty UNO Anys. Change-Id: Iad1197ba2559567a9c0eca4524e76389c2048fec Reviewed-on: https://gerrit.libreoffice.org/55646 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Tor Lillqvist <tml@collabora.com>
-rw-r--r--extensions/source/ole/unoobjw.cxx97
1 files changed, 91 insertions, 6 deletions
diff --git a/extensions/source/ole/unoobjw.cxx b/extensions/source/ole/unoobjw.cxx
index f04254ed0edf..123a4a914412 100644
--- a/extensions/source/ole/unoobjw.cxx
+++ b/extensions/source/ole/unoobjw.cxx
@@ -1225,6 +1225,10 @@ STDMETHODIMP InterfaceOleWrapper::GetIDsOfNames(REFIID /*riid*/,
return ret;
}
+// Note: What the comments here say about JScript possibly holds for Automation clients in general,
+// like VBScript ones, too. Or not. Hard to say. What is the relevance of JScript nowadays anyway,
+// and can LO really be used from JScript code on web pages any longer?
+
// "convertDispparamsArgs" converts VARIANTS to their respecting Any counterparts
// The parameters "id", "wFlags" and "pdispparams" equal those as used in
// IDispatch::Invoke. The function handles special JavaScript
@@ -1331,6 +1335,16 @@ void InterfaceOleWrapper::convertDispparamsArgs(DISPID id,
if (i < countIncomingArgs)
{
+ // A missing (and hopefully optional) arg (in the middle of the argument list) is passed
+ // as an empty Any.
+ if (pdispparams->rgvarg[i].vt == VT_ERROR && pdispparams->rgvarg[i].scode == DISP_E_PARAMNOTFOUND)
+ {
+ Any aEmpty;
+ pParams[ outgoingArgIndex ] = aEmpty;
+ outgoingArgIndex++;
+ continue;
+ }
+
if(convertValueObject( & pdispparams->rgvarg[i], anyParam))
{ //a param is a ValueObject and could be converted
pParams[ outgoingArgIndex ] = anyParam;
@@ -1825,17 +1839,88 @@ STDMETHODIMP InterfaceOleWrapper::Invoke(DISPID dispidMember,
{
if ((flags & DISPATCH_METHOD) != 0)
{
+ std::unique_ptr<DISPPARAMS> pNewDispParams;
+ std::vector<VARIANTARG> vNewArgs;
+
if (pdispparams->cNamedArgs > 0)
- ret = DISP_E_NONAMEDARGS;
- else
{
- Sequence<Any> params;
+ // Convert named arguments to positional ones.
+
+ // An example:
+ //
+ // Function declaration (in pseudo-code):
+ // int foo(int A, int B, optional int C, optional int D, optional int E, optional int F, optional int G)
+ //
+ // Corresponding parameter numbers (DISPIDs):
+ // 0 1 2 3 4 5 6
+ //
+ // Actual call:
+ // foo(10, 20, E:=50, D:=40, F:=60)
+ //
+ // That is, A and B are pased positionally, D, E, and F as named arguments,
+ // and the optional C and G parameters are left out.
+ //
+ // Incoming DISPPARAMS:
+ // cArgs=5, cNamedArgs=3
+ // rgvarg: [60, 40, 50, 20, 10]
+ // rgdispidNamedArgs: [5, 3, 4]
+ //
+ // We calculate nLowestNamedArgDispid = 3 and nHighestNamedArgDispid = 5.
+ //
+ // Result of conversion, no named args:
+ // cArgs=6, cNamedArgs=0
+ // rgvarg: [60, 50, 40, DISP_E_PARAMNOTFOUND, 20, 10]
+
+ // First find the lowest and highest DISPID of the named arguments.
+ DISPID nLowestNamedArgDispid = 1000000;
+ DISPID nHighestNamedArgDispid = -1;
+ for (unsigned int i = 0; i < pdispparams->cNamedArgs; ++i)
+ {
+ if (pdispparams->rgdispidNamedArgs[i] < nLowestNamedArgDispid)
+ nLowestNamedArgDispid = pdispparams->rgdispidNamedArgs[i];
+ if (pdispparams->rgdispidNamedArgs[i] > nHighestNamedArgDispid)
+ nHighestNamedArgDispid = pdispparams->rgdispidNamedArgs[i];
+ }
+
+ // Make sure named arguments don't overlap with positional ones. The lowest
+ // DISPID of the named arguments should be >= the number of positional
+ // arguments.
+ if (nLowestNamedArgDispid < static_cast<DISPID>(pdispparams->cArgs - pdispparams->cNamedArgs))
+ return DISP_E_NONAMEDARGS;
+
+ // Do the actual conversion.
+ pNewDispParams.reset(new DISPPARAMS);
+ vNewArgs.resize(nHighestNamedArgDispid + 1);
+ pNewDispParams->rgvarg = vNewArgs.data();
+ pNewDispParams->rgdispidNamedArgs = nullptr;
+ pNewDispParams->cArgs = nHighestNamedArgDispid + 1;
+ pNewDispParams->cNamedArgs = 0;
+
+ // Initialise all parameter slots as missing
+ for (int i = 0; i < nHighestNamedArgDispid; ++i)
+ {
+ pNewDispParams->rgvarg[i].vt = VT_ERROR;
+ pNewDispParams->rgvarg[i].scode = DISP_E_PARAMNOTFOUND;
+ }
+
+ // Then set the value of those actually present.
+ for (unsigned int i = 0; i < pdispparams->cNamedArgs; ++i)
+ pNewDispParams->rgvarg[nHighestNamedArgDispid - pdispparams->rgdispidNamedArgs[i]] = pdispparams->rgvarg[i];
- convertDispparamsArgs(dispidMember, wFlags, pdispparams , params );
+ const int nFirstUnnamedArg = pdispparams->cNamedArgs + (nLowestNamedArgDispid-(pdispparams->cArgs - pdispparams->cNamedArgs));
- ret= doInvoke(pdispparams, pvarResult,
- pexcepinfo, puArgErr, d.name, params);
+ for (unsigned int i = pdispparams->cNamedArgs; i < pdispparams->cArgs; ++i)
+ pNewDispParams->rgvarg[nFirstUnnamedArg + (i-pdispparams->cNamedArgs)] = pdispparams->rgvarg[i];
+
+ pdispparams = pNewDispParams.get();
}
+
+ Sequence<Any> params;
+
+ convertDispparamsArgs(dispidMember, wFlags, pdispparams , params );
+
+ ret= doInvoke(pdispparams, pvarResult,
+ pexcepinfo, puArgErr, d.name, params);
}
else if ((flags & DISPATCH_PROPERTYGET) != 0)
{