>From 0eaee0f8882522634b5a84e4d9de83996b85930f Mon Sep 17 00:00:00 2001
From: Nikolay Sivov <nsivov@codeweavers.com>
Date: Fri, 4 Nov 2011 17:38:15 +0300
Subject: [PATCH 3/4] Add IDispatchEx support for IXMLDOMNamedNodeMap

---
 dlls/msxml3/dispex.c        |   11 ++---
 dlls/msxml3/msxml_private.h |    3 -
 dlls/msxml3/nodemap.c       |   94 ++++++++++++++++++++++++++++++++++++++----
 dlls/msxml3/selection.c     |    8 +++-
 dlls/msxml3/tests/domdoc.c  |   60 +++++++++++++++++++++++++++-
 5 files changed, 154 insertions(+), 22 deletions(-)

diff --git a/dlls/msxml3/dispex.c b/dlls/msxml3/dispex.c
index ae84ab9..64ff583 100644
--- a/dlls/msxml3/dispex.c
+++ b/dlls/msxml3/dispex.c
@@ -326,11 +326,6 @@ static dispex_data_t *get_dispex_data(DispatchEx *This)
     return This->data->data;
 }
 
-static inline BOOL is_custom_dispid(DISPID id)
-{
-    return MSXML_DISPID_CUSTOM_MIN <= id && id <= MSXML_DISPID_CUSTOM_MAX;
-}
-
 static inline BOOL is_dynamic_dispid(DISPID id)
 {
     return DISPID_DYNPROP_0 <= id && id <= DISPID_DYNPROP_MAX;
@@ -523,8 +518,10 @@ static HRESULT WINAPI DispatchEx_InvokeEx(IDispatchEx *iface, DISPID id, LCID lc
 
     TRACE("(%p)->(%x %x %x %p %p %p %p)\n", This, id, lcid, wFlags, pdp, pvarRes, pei, pspCaller);
 
-    if(is_custom_dispid(id) && This->data->vtbl && This->data->vtbl->invoke)
-        return This->data->vtbl->invoke(This->outer, id, lcid, wFlags, pdp, pvarRes, pei);
+    if(This->data->vtbl && This->data->vtbl->invoke) {
+        hres = This->data->vtbl->invoke(This->outer, id, lcid, wFlags, pdp, pvarRes, pei);
+        if (hres != E_NOTIMPL) return hres;
+    }
 
     if(wFlags == DISPATCH_CONSTRUCT) {
         FIXME("DISPATCH_CONSTRUCT not implemented\n");
diff --git a/dlls/msxml3/msxml_private.h b/dlls/msxml3/msxml_private.h
index 698655e..5c2ed4d 100644
--- a/dlls/msxml3/msxml_private.h
+++ b/dlls/msxml3/msxml_private.h
@@ -130,9 +130,6 @@ extern void release_typelib(void) DECLSPEC_HIDDEN;
 typedef struct dispex_data_t dispex_data_t;
 typedef struct dispex_dynamic_data_t dispex_dynamic_data_t;
 
-#define MSXML_DISPID_CUSTOM_MIN 0x60000000
-#define MSXML_DISPID_CUSTOM_MAX 0x6fffffff
-
 typedef struct {
     HRESULT (*get_dispid)(IUnknown*,BSTR,DWORD,DISPID*);
     HRESULT (*invoke)(IUnknown*,DISPID,LCID,WORD,DISPPARAMS*,VARIANT*,EXCEPINFO*);
diff --git a/dlls/msxml3/nodemap.c b/dlls/msxml3/nodemap.c
index 1970840..43bb5c1 100644
--- a/dlls/msxml3/nodemap.c
+++ b/dlls/msxml3/nodemap.c
@@ -34,6 +34,7 @@
 #include "winnls.h"
 #include "ole2.h"
 #include "msxml6.h"
+#include "msxml2did.h"
 
 #include "msxml_private.h"
 
@@ -45,6 +46,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(msxml);
 
 typedef struct _xmlnodemap
 {
+    DispatchEx dispex;
     IXMLDOMNamedNodeMap IXMLDOMNamedNodeMap_iface;
     ISupportErrorInfo ISupportErrorInfo_iface;
     LONG ref;
@@ -76,6 +78,10 @@ static HRESULT WINAPI xmlnodemap_QueryInterface(
     {
         *ppvObject = iface;
     }
+    else if (dispex_query_interface(&This->dispex, riid, ppvObject))
+    {
+        return *ppvObject ? S_OK : E_NOINTERFACE;
+    }
     else if( IsEqualGUID( riid, &IID_ISupportErrorInfo ))
     {
         *ppvObject = &This->ISupportErrorInfo_iface;
@@ -111,6 +117,7 @@ static ULONG WINAPI xmlnodemap_Release(
     if ( ref == 0 )
     {
         xmldoc_release( This->node->doc );
+        release_dispex(&This->dispex);
         heap_free( This );
     }
 
@@ -516,23 +523,92 @@ static const struct ISupportErrorInfoVtbl support_error_vtbl =
     support_error_InterfaceSupportsErrorInfo
 };
 
+static HRESULT xmlnodemap_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 xmlnodemap_invoke(IUnknown *iface, DISPID id, LCID lcid, WORD flags, DISPPARAMS *params,
+        VARIANT *res, EXCEPINFO *ei)
+{
+    xmlnodemap *This = impl_from_IXMLDOMNamedNodeMap( (IXMLDOMNamedNodeMap*)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 E_NOTIMPL;
+
+    switch(flags)
+    {
+        case INVOKE_PROPERTYGET:
+        {
+            IXMLDOMNode *disp = NULL;
+
+            IXMLDOMNamedNodeMap_get_item(&This->IXMLDOMNamedNodeMap_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 xmlnodemap_dispex_vtbl = {
+    xmlnodemap_get_dispid,
+    xmlnodemap_invoke
+};
+
+static const tid_t xmlnodemap_iface_tids[] = {
+    IXMLDOMNamedNodeMap_tid,
+    0
+};
+
+static dispex_static_data_t xmlnodemap_dispex = {
+    &xmlnodemap_dispex_vtbl,
+    IXMLDOMNamedNodeMap_tid,
+    NULL,
+    xmlnodemap_iface_tids
+};
+
 IXMLDOMNamedNodeMap *create_nodemap( const xmlNodePtr node )
 {
-    xmlnodemap *nodemap;
+    xmlnodemap *This;
 
-    nodemap = heap_alloc( sizeof *nodemap );
-    if ( !nodemap )
+    This = heap_alloc( sizeof *This );
+    if ( !This )
         return NULL;
 
-    nodemap->IXMLDOMNamedNodeMap_iface.lpVtbl = &xmlnodemap_vtbl;
-    nodemap->ISupportErrorInfo_iface.lpVtbl = &support_error_vtbl;
-    nodemap->node = node;
-    nodemap->ref = 1;
-    nodemap->iterator = 0;
+    This->IXMLDOMNamedNodeMap_iface.lpVtbl = &xmlnodemap_vtbl;
+    This->ISupportErrorInfo_iface.lpVtbl = &support_error_vtbl;
+    This->node = node;
+    This->ref = 1;
+    This->iterator = 0;
+
+    init_dispex(&This->dispex, (IUnknown*)&This->IXMLDOMNamedNodeMap_iface, &xmlnodemap_dispex);
 
     xmldoc_add_ref(node->doc);
 
-    return &nodemap->IXMLDOMNamedNodeMap_iface;
+    return &This->IXMLDOMNamedNodeMap_iface;
 }
 
 #endif
diff --git a/dlls/msxml3/selection.c b/dlls/msxml3/selection.c
index 31137f3..8500385 100644
--- a/dlls/msxml3/selection.c
+++ b/dlls/msxml3/selection.c
@@ -37,6 +37,7 @@
 #include "winuser.h"
 #include "ole2.h"
 #include "msxml6.h"
+#include "msxml2did.h"
 
 #include "msxml_private.h"
 
@@ -617,7 +618,7 @@ static HRESULT domselection_get_dispid(IUnknown *iface, BSTR name, DWORD flags,
     if(idx >= xmlXPathNodeSetGetLength(This->result->nodesetval))
         return DISP_E_UNKNOWNNAME;
 
-    *dispid = MSXML_DISPID_CUSTOM_MIN + idx;
+    *dispid = DISPID_DOM_COLLECTION_BASE + idx;
     TRACE("ret %x\n", *dispid);
     return S_OK;
 }
@@ -632,13 +633,16 @@ static HRESULT domselection_invoke(IUnknown *iface, DISPID id, LCID lcid, WORD f
     V_VT(res) = VT_DISPATCH;
     V_DISPATCH(res) = NULL;
 
+    if (id < DISPID_DOM_COLLECTION_BASE || id > DISPID_DOM_COLLECTION_MAX)
+        return E_NOTIMPL;
+
     switch(flags)
     {
         case INVOKE_PROPERTYGET:
         {
             IXMLDOMNode *disp = NULL;
 
-            domselection_get_item(&This->IXMLDOMSelection_iface, id - MSXML_DISPID_CUSTOM_MIN, &disp);
+            domselection_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 e1be912..efd8ccc 100644
--- a/dlls/msxml3/tests/domdoc.c
+++ b/dlls/msxml3/tests/domdoc.c
@@ -1731,7 +1731,7 @@ SZ_EMAIL_DTD
 static const char xpath_simple_list[] =
 "<?xml version=\"1.0\"?>"
 "<root>"
-"   <a/>"
+"   <a attr1=\"1\" attr2=\"2\" />"
 "   <b/>"
 "   <c/>"
 "   <d/>"
@@ -10628,9 +10628,15 @@ static void test_dispex(void)
     const DOMNodeType *type = dispex_types_test;
     IXMLDOMNodeList *node_list;
     IXMLDOMParseError *error;
+    IXMLDOMNamedNodeMap *map;
     IXMLDOMDocument *doc;
+    IXMLDOMElement *elem;
+    IDispatchEx *dispex;
+    IXMLDOMNode *node;
+    VARIANT_BOOL b;
     IUnknown *unk;
     HRESULT hr;
+    DISPID did;
 
     doc = create_document(&IID_IXMLDOMDocument);
 
@@ -10672,6 +10678,58 @@ static void test_dispex(void)
     IUnknown_Release(unk);
     IXMLDOMParseError_Release(error);
 
+    /* IXMLDOMNamedNodeMap */
+    hr = IXMLDOMDocument2_loadXML(doc, _bstr_(xpath_simple_list), &b);
+    EXPECT_HR(hr, S_OK);
+
+    hr = IXMLDOMDocument_selectNodes(doc, _bstr_("root/a"), &node_list);
+    EXPECT_HR(hr, S_OK);
+    hr = IXMLDOMNodeList_get_item(node_list, 0, &node);
+    EXPECT_HR(hr, S_OK);
+    IXMLDOMNodeList_Release(node_list);
+
+    hr = IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMElement, (void**)&elem);
+    EXPECT_HR(hr, S_OK);
+    IXMLDOMNode_Release(node);
+    hr = IXMLDOMElement_get_attributes(elem, &map);
+    EXPECT_HR(hr, S_OK);
+    IXMLDOMNamedNodeMap_QueryInterface(map, &IID_IUnknown, (void**)&unk);
+    test_domobj_dispex(unk);
+    IUnknown_Release(unk);
+    /* collection dispex test */
+    hr = IXMLDOMNamedNodeMap_QueryInterface(map, &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);
+    IDispatchEx_Release(dispex);
+
+    hr = IXMLDOMDocument_selectNodes(doc, _bstr_("root/b"), &node_list);
+    EXPECT_HR(hr, S_OK);
+    hr = IXMLDOMNodeList_get_item(node_list, 0, &node);
+    EXPECT_HR(hr, S_OK);
+    IXMLDOMNodeList_Release(node_list);
+    hr = IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMElement, (void**)&elem);
+    EXPECT_HR(hr, S_OK);
+    IXMLDOMNode_Release(node);
+    hr = IXMLDOMElement_get_attributes(elem, &map);
+    EXPECT_HR(hr, S_OK);
+    /* collection dispex test, empty collection */
+    hr = IXMLDOMNamedNodeMap_QueryInterface(map, &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);
+
+    IXMLDOMNamedNodeMap_Release(map);
+    IXMLDOMElement_Release(elem);
+
     IXMLDOMDocument_Release(doc);
     free_bstrs();
 }
-- 
1.5.6.5


