>From 7fdb2feef2d7549f4bd9376869315109b712e476 Mon Sep 17 00:00:00 2001
From: Nikolay Sivov <nsivov@codeweavers.com>
Date: Sun, 23 Oct 2011 22:54:20 +0400
Subject: [PATCH 3/3] Add stub IEnumVARIANT support for IXMLDOMSelection

---
 dlls/msxml3/selection.c    |  149 +++++++++++++++++++++++++++++++++++++++++++-
 dlls/msxml3/tests/domdoc.c |   83 ++++++++++++++++++++++++-
 2 files changed, 228 insertions(+), 4 deletions(-)

diff --git a/dlls/msxml3/selection.c b/dlls/msxml3/selection.c
index e0f30c3..c90c8c2 100644
--- a/dlls/msxml3/selection.c
+++ b/dlls/msxml3/selection.c
@@ -58,6 +58,15 @@ WINE_DEFAULT_DEBUG_CHANNEL(msxml);
 int registerNamespaces(xmlXPathContextPtr ctxt);
 xmlChar* XSLPattern_to_XPath(xmlXPathContextPtr ctxt, xmlChar const* xslpat_str);
 
+typedef struct _enumvariant
+{
+    IEnumVARIANT IEnumVARIANT_iface;
+    LONG ref;
+
+    IXMLDOMSelection *selection;
+    BOOL own;
+} enumvariant;
+
 typedef struct _domselection
 {
     DispatchEx dispex;
@@ -66,6 +75,7 @@ typedef struct _domselection
     xmlNodePtr node;
     xmlXPathObjectPtr result;
     int resultPos;
+    IEnumVARIANT *enumvariant;
 } domselection;
 
 static inline domselection *impl_from_IXMLDOMSelection( IXMLDOMSelection *iface )
@@ -73,6 +83,13 @@ static inline domselection *impl_from_IXMLDOMSelection( IXMLDOMSelection *iface
     return CONTAINING_RECORD(iface, domselection, IXMLDOMSelection_iface);
 }
 
+static inline enumvariant *impl_from_IEnumVARIANT( IEnumVARIANT *iface )
+{
+    return CONTAINING_RECORD(iface, enumvariant, IEnumVARIANT_iface);
+}
+
+static HRESULT create_enumvariant(IXMLDOMSelection*, BOOL, IUnknown**);
+
 static HRESULT WINAPI domselection_QueryInterface(
     IXMLDOMSelection *iface,
     REFIID riid,
@@ -91,7 +108,17 @@ static HRESULT WINAPI domselection_QueryInterface(
     {
         *ppvObject = &This->IXMLDOMSelection_iface;
     }
-    else if(dispex_query_interface(&This->dispex, riid, ppvObject))
+    else if (IsEqualGUID( riid, &IID_IEnumVARIANT ))
+    {
+        if (!This->enumvariant)
+        {
+            HRESULT hr = create_enumvariant(iface, FALSE, (IUnknown**)&This->enumvariant);
+            if (FAILED(hr)) return hr;
+        }
+
+        return IEnumVARIANT_QueryInterface(This->enumvariant, &IID_IEnumVARIANT, ppvObject);
+    }
+    else if (dispex_query_interface(&This->dispex, riid, ppvObject))
     {
         return *ppvObject ? S_OK : E_NOINTERFACE;
     }
@@ -127,6 +154,7 @@ static ULONG WINAPI domselection_Release(
     {
         xmlXPathFreeObject(This->result);
         xmldoc_release(This->node->doc);
+        if (This->enumvariant) IEnumVARIANT_Release(This->enumvariant);
         heap_free(This);
     }
 
@@ -293,8 +321,10 @@ static HRESULT WINAPI domselection_get__newEnum(
         IUnknown** ppUnk)
 {
     domselection *This = impl_from_IXMLDOMSelection( iface );
-    FIXME("(%p)->(%p)\n", This, ppUnk);
-    return E_NOTIMPL;
+
+    TRACE("(%p)->(%p)\n", This, ppUnk);
+
+    return create_enumvariant(iface, TRUE, ppUnk);
 }
 
 static HRESULT WINAPI domselection_get_expr(
@@ -425,6 +455,118 @@ static const struct IXMLDOMSelectionVtbl domselection_vtbl =
     domselection_setProperty
 };
 
+/* IEnumVARIANT support */
+static HRESULT WINAPI enumvariant_QueryInterface(
+    IEnumVARIANT *iface,
+    REFIID riid,
+    void** ppvObject )
+{
+    enumvariant *This = impl_from_IEnumVARIANT( iface );
+
+    TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
+
+    *ppvObject = NULL;
+
+    if ( IsEqualGUID( riid, &IID_IUnknown ) ||
+         IsEqualGUID( riid, &IID_IEnumVARIANT ))
+    {
+        *ppvObject = &This->IEnumVARIANT_iface;
+    }
+    else
+        return IXMLDOMSelection_QueryInterface(This->selection, riid, ppvObject);
+
+    IEnumVARIANT_AddRef( iface );
+
+    return S_OK;
+}
+
+static ULONG WINAPI enumvariant_AddRef(IEnumVARIANT *iface )
+{
+    enumvariant *This = impl_from_IEnumVARIANT( iface );
+    ULONG ref = InterlockedIncrement( &This->ref );
+    TRACE("(%p)->(%d)\n", This, ref);
+    return ref;
+}
+
+static ULONG WINAPI enumvariant_Release(IEnumVARIANT *iface )
+{
+    enumvariant *This = impl_from_IEnumVARIANT( iface );
+    ULONG ref = InterlockedDecrement(&This->ref);
+
+    TRACE("(%p)->(%d)\n", This, ref);
+    if ( ref == 0 )
+    {
+        if (This->own) IXMLDOMSelection_Release(This->selection);
+        heap_free(This);
+    }
+
+    return ref;
+}
+
+static HRESULT WINAPI enumvariant_Next(
+    IEnumVARIANT *iface,
+    ULONG celt,
+    VARIANT *rgvar,
+    ULONG *pceltFetched)
+{
+    enumvariant *This = impl_from_IEnumVARIANT( iface );
+    FIXME("(%p)->(%u %p %p): stub\n", This, celt, rgvar, pceltFetched);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI enumvariant_Skip(
+    IEnumVARIANT *iface,
+    ULONG celt)
+{
+    enumvariant *This = impl_from_IEnumVARIANT( iface );
+    FIXME("(%p)->(%u): stub\n", This, celt);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI enumvariant_Reset(IEnumVARIANT *iface)
+{
+    enumvariant *This = impl_from_IEnumVARIANT( iface );
+    FIXME("(%p): stub\n", This);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI enumvariant_Clone(
+    IEnumVARIANT *iface, IEnumVARIANT **ppenum)
+{
+    enumvariant *This = impl_from_IEnumVARIANT( iface );
+    FIXME("(%p)->(%p): stub\n", This, ppenum);
+    return E_NOTIMPL;
+}
+
+static const struct IEnumVARIANTVtbl EnumVARIANTVtbl =
+{
+    enumvariant_QueryInterface,
+    enumvariant_AddRef,
+    enumvariant_Release,
+    enumvariant_Next,
+    enumvariant_Skip,
+    enumvariant_Reset,
+    enumvariant_Clone
+};
+
+static HRESULT create_enumvariant(IXMLDOMSelection *selection, BOOL own, IUnknown **penum)
+{
+    enumvariant *This;
+
+    This = heap_alloc(sizeof(enumvariant));
+    if (!This) return E_OUTOFMEMORY;
+
+    This->IEnumVARIANT_iface.lpVtbl = &EnumVARIANTVtbl;
+    This->ref = 0;
+    This->selection = selection;
+    This->own = own;
+
+    if (This->own)
+        IXMLDOMSelection_AddRef(selection);
+
+    return IEnumVARIANT_QueryInterface(&This->IEnumVARIANT_iface, &IID_IUnknown, (void**)penum);
+}
+
 static HRESULT domselection_get_dispid(IUnknown *iface, BSTR name, DWORD flags, DISPID *dispid)
 {
     domselection *This = impl_from_IXMLDOMSelection( (IXMLDOMSelection*)iface );
@@ -622,6 +764,7 @@ HRESULT create_selection(xmlNodePtr node, xmlChar* query, IXMLDOMNodeList **out)
     This->ref = 1;
     This->resultPos = 0;
     This->node = node;
+    This->enumvariant = NULL;
     xmldoc_add_ref(This->node->doc);
 
     ctxt->error = query_serror;
diff --git a/dlls/msxml3/tests/domdoc.c b/dlls/msxml3/tests/domdoc.c
index c12aa5c..0acfa25 100644
--- a/dlls/msxml3/tests/domdoc.c
+++ b/dlls/msxml3/tests/domdoc.c
@@ -9964,7 +9964,9 @@ static void test_get_attributes(void)
 
 static void test_selection(void)
 {
-    IXMLDOMSelection *selection;
+    IXMLDOMSelection *selection, *selection2;
+    IEnumVARIANT *enum1, *enum2, *enum3;
+    IDispatch *disp;
     IXMLDOMNodeList *list;
     IXMLDOMDocument *doc;
     VARIANT_BOOL b;
@@ -9982,6 +9984,85 @@ static void test_selection(void)
     EXPECT_HR(hr, S_OK);
     IXMLDOMSelection_Release(selection);
 
+    /* IEnumVARIANT tests */
+    enum1 = NULL;
+    hr = IXMLDOMSelection_QueryInterface(selection, &IID_IEnumVARIANT, (void**)&enum1);
+    EXPECT_HR(hr, S_OK);
+    ok(enum1 != NULL, "got %p\n", enum1);
+    EXPECT_REF(enum1, 2);
+
+    enum3 = NULL;
+    hr = IXMLDOMSelection_QueryInterface(selection, &IID_IEnumVARIANT, (void**)&enum3);
+    EXPECT_HR(hr, S_OK);
+    ok(enum3 != NULL, "got %p\n", enum3);
+    ok(enum1 == enum3, "got %p and %p\n", enum1, enum3);
+    EXPECT_REF(enum1, 3);
+    IEnumVARIANT_Release(enum3);
+
+    EXPECT_REF(selection, 1);
+    EXPECT_REF(enum1, 2);
+
+    enum2 = NULL;
+    hr = IXMLDOMSelection_get__newEnum(selection, (IUnknown**)&enum2);
+    EXPECT_HR(hr, S_OK);
+    ok(enum2 != NULL, "got %p\n", enum2);
+
+    EXPECT_REF(selection, 2);
+    EXPECT_REF(enum1, 2);
+    EXPECT_REF(enum2, 1);
+
+    ok(enum1 != enum2, "got %p, %p\n", enum1, enum2);
+
+    selection2 = NULL;
+    hr = IEnumVARIANT_QueryInterface(enum1, &IID_IXMLDOMSelection, (void**)&selection2);
+    EXPECT_HR(hr, S_OK);
+    ok(selection2 == selection, "got %p and %p\n", selection, selection2);
+    EXPECT_REF(selection, 3);
+    EXPECT_REF(enum1, 2);
+
+    IXMLDOMSelection_Release(selection2);
+
+    hr = IEnumVARIANT_QueryInterface(enum1, &IID_IDispatch, (void**)&disp);
+    EXPECT_HR(hr, S_OK);
+    EXPECT_REF(selection, 3);
+    IDispatch_Release(disp);
+
+    hr = IEnumVARIANT_QueryInterface(enum1, &IID_IEnumVARIANT, (void**)&enum3);
+    EXPECT_HR(hr, S_OK);
+    ok(enum3 == enum1, "got %p and %p\n", enum3, enum1);
+    EXPECT_REF(selection, 2);
+    EXPECT_REF(enum1, 3);
+
+    IEnumVARIANT_Release(enum1);
+    IEnumVARIANT_Release(enum2);
+
+    enum1 = NULL;
+    hr = IXMLDOMSelection_get__newEnum(selection, (IUnknown**)&enum1);
+    EXPECT_HR(hr, S_OK);
+    ok(enum1 != NULL, "got %p\n", enum1);
+    EXPECT_REF(enum1, 1);
+    EXPECT_REF(selection, 2);
+
+    enum2 = NULL;
+    hr = IXMLDOMSelection_get__newEnum(selection, (IUnknown**)&enum2);
+    EXPECT_HR(hr, S_OK);
+    ok(enum2 != NULL, "got %p\n", enum2);
+    EXPECT_REF(enum2, 1);
+    EXPECT_REF(selection, 3);
+
+    ok(enum1 != enum2, "got %p, %p\n", enum1, enum2);
+
+    IEnumVARIANT_AddRef(enum1);
+    EXPECT_REF(selection, 3);
+    EXPECT_REF(enum1, 2);
+    EXPECT_REF(enum2, 1);
+    IEnumVARIANT_Release(enum1);
+
+    IEnumVARIANT_Release(enum1);
+    IEnumVARIANT_Release(enum2);
+
+    EXPECT_REF(selection, 1);
+
     IXMLDOMNodeList_Release(list);
 
     hr = IXMLDOMDocument_get_childNodes(doc, &list);
-- 
1.5.6.5


