>From 29248ece76effbdc2ea3f1640e0c404607874e24 Mon Sep 17 00:00:00 2001
From: Nikolay Sivov <nsivov@codeweavers.com>
Date: Sat, 19 Nov 2011 20:55:30 +0300
Subject: [PATCH 4/4] Support IDispatchEx for IXMLDOMNodeList too

---
 dlls/msxml3/nodelist.c     |  148 +++++++++++++++++++++++++++-----------------
 dlls/msxml3/selection.c    |    2 +-
 dlls/msxml3/tests/domdoc.c |   21 ++++++
 3 files changed, 114 insertions(+), 57 deletions(-)

diff --git a/dlls/msxml3/nodelist.c b/dlls/msxml3/nodelist.c
index 6a25463..5710d48 100644
--- a/dlls/msxml3/nodelist.c
+++ b/dlls/msxml3/nodelist.c
@@ -33,6 +33,7 @@
 #include "winuser.h"
 #include "ole2.h"
 #include "msxml6.h"
+#include "msxml2did.h"
 
 #include "msxml_private.h"
 
@@ -53,6 +54,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(msxml);
 
 typedef struct _xmlnodelist
 {
+    DispatchEx dispex;
     IXMLDOMNodeList IXMLDOMNodeList_iface;
     LONG ref;
     xmlNodePtr parent;
@@ -69,7 +71,9 @@ static HRESULT WINAPI xmlnodelist_QueryInterface(
     REFIID riid,
     void** ppvObject )
 {
-    TRACE("(%p)->(%s %p)\n", iface, debugstr_guid(riid), ppvObject);
+    xmlnodelist *This = impl_from_IXMLDOMNodeList( iface );
+
+    TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
 
     if ( IsEqualGUID( riid, &IID_IUnknown ) ||
          IsEqualGUID( riid, &IID_IDispatch ) ||
@@ -77,6 +81,10 @@ static HRESULT WINAPI xmlnodelist_QueryInterface(
     {
         *ppvObject = iface;
     }
+    else if (dispex_query_interface(&This->dispex, riid, ppvObject))
+    {
+        return *ppvObject ? S_OK : E_NOINTERFACE;
+    }
     else
     {
         TRACE("interface %s not implemented\n", debugstr_guid(riid));
@@ -119,12 +127,7 @@ static HRESULT WINAPI xmlnodelist_GetTypeInfoCount(
     UINT* pctinfo )
 {
     xmlnodelist *This = impl_from_IXMLDOMNodeList( iface );
-
-    TRACE("(%p)->(%p)\n", This, pctinfo);
-
-    *pctinfo = 1;
-
-    return S_OK;
+    return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo);
 }
 
 static HRESULT WINAPI xmlnodelist_GetTypeInfo(
@@ -134,13 +137,8 @@ static HRESULT WINAPI xmlnodelist_GetTypeInfo(
     ITypeInfo** ppTInfo )
 {
     xmlnodelist *This = impl_from_IXMLDOMNodeList( iface );
-    HRESULT hr;
-
-    TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
-
-    hr = get_typeinfo(IXMLDOMNodeList_tid, ppTInfo);
-
-    return hr;
+    return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface,
+        iTInfo, lcid, ppTInfo);
 }
 
 static HRESULT WINAPI xmlnodelist_GetIDsOfNames(
@@ -152,23 +150,8 @@ static HRESULT WINAPI xmlnodelist_GetIDsOfNames(
     DISPID* rgDispId )
 {
     xmlnodelist *This = impl_from_IXMLDOMNodeList( iface );
-    ITypeInfo *typeinfo;
-    HRESULT hr;
-
-    TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
-          lcid, rgDispId);
-
-    if(!rgszNames || cNames == 0 || !rgDispId)
-        return E_INVALIDARG;
-
-    hr = get_typeinfo(IXMLDOMNodeList_tid, &typeinfo);
-    if(SUCCEEDED(hr))
-    {
-        hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
-        ITypeInfo_Release(typeinfo);
-    }
-
-    return hr;
+    return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface,
+        riid, rgszNames, cNames, lcid, rgDispId);
 }
 
 static HRESULT WINAPI xmlnodelist_Invoke(
@@ -183,21 +166,8 @@ static HRESULT WINAPI xmlnodelist_Invoke(
     UINT* puArgErr )
 {
     xmlnodelist *This = impl_from_IXMLDOMNodeList( iface );
-    ITypeInfo *typeinfo;
-    HRESULT hr;
-
-    TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
-          lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
-
-    hr = get_typeinfo(IXMLDOMNodeList_tid, &typeinfo);
-    if(SUCCEEDED(hr))
-    {
-        hr = ITypeInfo_Invoke(typeinfo, &This->IXMLDOMNodeList_iface, dispIdMember, wFlags,
-                pDispParams, pVarResult, pExcepInfo, puArgErr);
-        ITypeInfo_Release(typeinfo);
-    }
-
-    return hr;
+    return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface,
+        dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
 }
 
 static HRESULT WINAPI xmlnodelist_get_item(
@@ -298,7 +268,6 @@ static HRESULT WINAPI xmlnodelist__newEnum(
     return E_NOTIMPL;
 }
 
-
 static const struct IXMLDOMNodeListVtbl xmlnodelist_vtbl =
 {
     xmlnodelist_QueryInterface,
@@ -315,22 +284,89 @@ static const struct IXMLDOMNodeListVtbl xmlnodelist_vtbl =
     xmlnodelist__newEnum,
 };
 
+static HRESULT xmlnodelist_get_dispid(IUnknown *iface, BSTR name, DWORD flags, DISPID *dispid)
+{
+    WCHAR *ptr;
+    int idx = 0;
+
+    for(ptr = name; *ptr && isdigitW(*ptr); ptr++)
+        idx = idx*10 + (*ptr-'0');
+    if(*ptr)
+        return DISP_E_UNKNOWNNAME;
+
+    *dispid = DISPID_DOM_COLLECTION_BASE + idx;
+    TRACE("ret %x\n", *dispid);
+    return S_OK;
+}
+
+static HRESULT xmlnodelist_invoke(IUnknown *iface, DISPID id, LCID lcid, WORD flags, DISPPARAMS *params,
+        VARIANT *res, EXCEPINFO *ei)
+{
+    xmlnodelist *This = impl_from_IXMLDOMNodeList( (IXMLDOMNodeList*)iface );
+
+    TRACE("(%p)->(%x %x %x %p %p %p)\n", This, id, lcid, flags, params, res, ei);
+
+    V_VT(res) = VT_DISPATCH;
+    V_DISPATCH(res) = NULL;
+
+    if (id < DISPID_DOM_COLLECTION_BASE || id > DISPID_DOM_COLLECTION_MAX)
+        return DISP_E_UNKNOWNNAME;
+
+    switch(flags)
+    {
+        case INVOKE_PROPERTYGET:
+        {
+            IXMLDOMNode *disp = NULL;
+
+            IXMLDOMNodeList_get_item(&This->IXMLDOMNodeList_iface, id - DISPID_DOM_COLLECTION_BASE, &disp);
+            V_DISPATCH(res) = (IDispatch*)disp;
+            break;
+        }
+        default:
+        {
+            FIXME("unimplemented flags %x\n", flags);
+            break;
+        }
+    }
+
+    TRACE("ret %p\n", V_DISPATCH(res));
+
+    return S_OK;
+}
+
+static const dispex_static_data_vtbl_t xmlnodelist_dispex_vtbl = {
+    xmlnodelist_get_dispid,
+    xmlnodelist_invoke
+};
+
+static const tid_t xmlnodelist_iface_tids[] = {
+    IXMLDOMNodeList_tid,
+    0
+};
+static dispex_static_data_t xmlnodelist_dispex = {
+    &xmlnodelist_dispex_vtbl,
+    IXMLDOMNodeList_tid,
+    NULL,
+    xmlnodelist_iface_tids
+};
+
 IXMLDOMNodeList* create_children_nodelist( xmlNodePtr node )
 {
-    xmlnodelist *nodelist;
+    xmlnodelist *This;
 
-    nodelist = heap_alloc( sizeof *nodelist );
-    if ( !nodelist )
+    This = heap_alloc( sizeof *This );
+    if ( !This )
         return NULL;
 
-    nodelist->IXMLDOMNodeList_iface.lpVtbl = &xmlnodelist_vtbl;
-    nodelist->ref = 1;
-    nodelist->parent = node;
-    nodelist->current = node->children;
-
+    This->IXMLDOMNodeList_iface.lpVtbl = &xmlnodelist_vtbl;
+    This->ref = 1;
+    This->parent = node;
+    This->current = node->children;
     xmldoc_add_ref( node->doc );
 
-    return &nodelist->IXMLDOMNodeList_iface;
+    init_dispex(&This->dispex, (IUnknown*)&This->IXMLDOMNodeList_iface, &xmlnodelist_dispex);
+
+    return &This->IXMLDOMNodeList_iface;
 }
 
 #endif
diff --git a/dlls/msxml3/selection.c b/dlls/msxml3/selection.c
index aba8e7d..8871817 100644
--- a/dlls/msxml3/selection.c
+++ b/dlls/msxml3/selection.c
@@ -600,7 +600,7 @@ static HRESULT domselection_invoke(IUnknown *iface, DISPID id, LCID lcid, WORD f
         {
             IXMLDOMNode *disp = NULL;
 
-            domselection_get_item(&This->IXMLDOMSelection_iface, id - DISPID_DOM_COLLECTION_BASE, &disp);
+            IXMLDOMSelection_get_item(&This->IXMLDOMSelection_iface, id - DISPID_DOM_COLLECTION_BASE, &disp);
             V_DISPATCH(res) = (IDispatch*)disp;
             break;
         }
diff --git a/dlls/msxml3/tests/domdoc.c b/dlls/msxml3/tests/domdoc.c
index abd0b37..e72e1f3 100644
--- a/dlls/msxml3/tests/domdoc.c
+++ b/dlls/msxml3/tests/domdoc.c
@@ -10531,6 +10531,27 @@ static void test_dispex(void)
     IUnknown_Release(unk);
     IXMLDOMNodeList_Release(node_list);
 
+    /* IXMLDOMNodeList for children list */
+    hr = IXMLDOMDocument_get_childNodes(doc, &node_list);
+    EXPECT_HR(hr, S_OK);
+    IXMLDOMNodeList_QueryInterface(node_list, &IID_IUnknown, (void**)&unk);
+    test_domobj_dispex(unk);
+    IUnknown_Release(unk);
+
+    /* collection dispex test, empty collection */
+    hr = IXMLDOMNodeList_QueryInterface(node_list, &IID_IDispatchEx, (void**)&dispex);
+    EXPECT_HR(hr, S_OK);
+    did = 0;
+    hr = IDispatchEx_GetDispID(dispex, _bstr_("0"), 0, &did);
+    EXPECT_HR(hr, S_OK);
+    ok(did == DISPID_DOM_COLLECTION_BASE, "got 0x%08x\n", did);
+    hr = IDispatchEx_GetDispID(dispex, _bstr_("1"), 0, &did);
+    EXPECT_HR(hr, S_OK);
+    ok(did == DISPID_DOM_COLLECTION_BASE+1, "got 0x%08x\n", did);
+    IDispatchEx_Release(dispex);
+
+    IXMLDOMNodeList_Release(node_list);
+
     /* IXMLDOMParseError */
     hr = IXMLDOMDocument_get_parseError(doc, &error);
     EXPECT_HR(hr, S_OK);
-- 
1.5.6.5


