[Libreoffice-commits] core.git: extensions/source

Tor Lillqvist tml at collabora.com
Tue Jun 12 05:34:03 UTC 2018


 extensions/source/ole/unoobjw.cxx |   97 +++++++++++++++++++++++++++++++++++---
 1 file changed, 91 insertions(+), 6 deletions(-)

New commits:
commit f9e9012e75afe4418f4ebe652fa99a1fa2348a71
Author: Tor Lillqvist <tml at collabora.com>
Date:   Mon Jun 11 19:53:06 2018 +0300

    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 at libreoffice.org>
    Reviewed-by: Tor Lillqvist <tml at collabora.com>

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)
                 {


More information about the Libreoffice-commits mailing list