msxml3 [1/4]: Add initial implementation of IXMLElement and IXMLElementCollection [try2]

James Hawkins truiken at gmail.com
Thu May 24 13:12:19 CDT 2007


Hi,

This version adds the necessary checks for libxml2.

Changelog:
* Add initial implementation of IXMLElement and IXMLElementCollection.

 dlls/msxml3/Makefile.in     |    3
 dlls/msxml3/msxml_private.h |    2
 dlls/msxml3/xmlelem.c       |  726 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 730 insertions(+), 1 deletions(-)

-- 
James Hawkins
-------------- next part --------------
diff --git a/dlls/msxml3/Makefile.in b/dlls/msxml3/Makefile.in
index c888e23..870034d 100644
--- a/dlls/msxml3/Makefile.in
+++ b/dlls/msxml3/Makefile.in
@@ -24,7 +24,8 @@ C_SRCS = \
 	regsvr.c \
 	schema.c \
 	text.c \
-	uuid.c
+	uuid.c \
+	xmlelem.c
 
 RC_SRCS = version.rc
 
diff --git a/dlls/msxml3/msxml_private.h b/dlls/msxml3/msxml_private.h
index 39aaa00..74f061a 100644
--- a/dlls/msxml3/msxml_private.h
+++ b/dlls/msxml3/msxml_private.h
@@ -63,5 +63,7 @@ extern IXMLDOMParseError *create_parseEr
                                              LONG line, LONG linepos, LONG filepos );
 extern HRESULT DOMDocument_create( IUnknown *pUnkOuter, LPVOID *ppObj );
 extern HRESULT SchemaCache_create( IUnknown *pUnkOuter, LPVOID *ppObj );
+extern HRESULT XMLElement_create( IUnknown *pUnkOuter, xmlNodePtr node, LPVOID *ppObj );
+extern HRESULT XMLElementCollection_create( IUnknown *pUnkOuter, xmlNodePtr node, LPVOID *ppObj );
 
 #endif /* __MSXML_PRIVATE__ */
diff --git a/dlls/msxml3/xmlelem.c b/dlls/msxml3/xmlelem.c
new file mode 100644
index 0000000..4fc8865
--- /dev/null
+++ b/dlls/msxml3/xmlelem.c
@@ -0,0 +1,726 @@
+/*
+ * XML Element implementation
+ *
+ * Copyright 2007 James Hawkins
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#define COBJMACROS
+
+#include "config.h"
+
+#include <stdarg.h>
+#include "windef.h"
+#include "winbase.h"
+#include "winuser.h"
+#include "ole2.h"
+#include "msxml2.h"
+#include "ocidl.h"
+
+#include "wine/debug.h"
+
+#include "msxml_private.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(msxml);
+
+#ifdef HAVE_LIBXML2
+
+/**********************************************************************
+ * IXMLElement
+ */
+typedef struct _xmlelem
+{
+    const IXMLElementVtbl *lpVtbl;
+    LONG ref;
+    xmlNodePtr node;
+} xmlelem;
+
+static inline xmlelem *impl_from_IXMLElement(IXMLElement *iface)
+{
+    return (xmlelem *)((char*)iface - FIELD_OFFSET(xmlelem, lpVtbl));
+}
+
+static HRESULT WINAPI xmlelem_QueryInterface(IXMLElement *iface, REFIID riid, void** ppvObject)
+{
+    xmlelem *This = impl_from_IXMLElement(iface);
+
+    TRACE("%p %s %p\n", This, debugstr_guid(riid), ppvObject);
+
+    if (IsEqualGUID(riid, &IID_IUnknown) ||
+        IsEqualGUID(riid, &IID_IXMLElement))
+    {
+        *ppvObject = iface;
+    }
+    else
+    {
+        FIXME("interface %s not implemented\n", debugstr_guid(riid));
+        return E_NOINTERFACE;
+    }
+
+    IXMLElement_AddRef(iface);
+
+    return S_OK;
+}
+
+static ULONG WINAPI xmlelem_AddRef(IXMLElement *iface)
+{
+    xmlelem *This = impl_from_IXMLElement(iface);
+    TRACE("%p\n", This);
+    return InterlockedIncrement(&This->ref);
+}
+
+static ULONG WINAPI xmlelem_Release(IXMLElement *iface)
+{
+    xmlelem *This = impl_from_IXMLElement(iface);
+    LONG ref;
+
+    TRACE("%p\n", This);
+
+    ref = InterlockedDecrement(&This->ref);
+    if (ref == 0)
+    {
+        HeapFree(GetProcessHeap(), 0, This);
+    }
+
+    return ref;
+}
+
+static HRESULT WINAPI xmlelem_GetTypeInfoCount(IXMLElement *iface, UINT* pctinfo)
+{
+    FIXME("\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI xmlelem_GetTypeInfo(IXMLElement *iface, UINT iTInfo,
+                                          LCID lcid, ITypeInfo** ppTInfo)
+{
+    FIXME("\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI xmlelem_GetIDsOfNames(IXMLElement *iface, REFIID riid,
+                                            LPOLESTR* rgszNames, UINT cNames,
+                                            LCID lcid, DISPID* rgDispId)
+{
+    FIXME("\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI xmlelem_Invoke(IXMLElement *iface, DISPID dispIdMember,
+                                     REFIID riid, LCID lcid, WORD wFlags,
+                                     DISPPARAMS* pDispParams, VARIANT* pVarResult,
+                                     EXCEPINFO* pExcepInfo, UINT* puArgErr)
+{
+    FIXME("\n");
+    return E_NOTIMPL;
+}
+
+static inline BSTR str_dup_upper(BSTR str)
+{
+    INT len = (lstrlenW(str) + 1) * sizeof(WCHAR);
+    BSTR p = SysAllocStringLen(NULL, len);
+    if (p)
+    {
+        memcpy(p, str, len);
+        CharUpperW(p);
+    }
+    return p;
+}
+
+static HRESULT WINAPI xmlelem_get_tagName(IXMLElement *iface, BSTR *p)
+{
+    xmlelem *This = impl_from_IXMLElement(iface);
+    BSTR temp;
+
+    TRACE("(%p, %p)\n", iface, p);
+
+    if (!p)
+        return E_INVALIDARG;
+
+    temp = bstr_from_xmlChar(This->node->name); 
+    *p = str_dup_upper(temp);
+    SysFreeString(temp);
+
+    TRACE("returning %s\n", debugstr_w(*p));
+
+    return S_OK;
+}
+
+static HRESULT WINAPI xmlelem_put_tagName(IXMLElement *iface, BSTR p)
+{
+    FIXME("(%p, %p): stub\n", iface, p);
+
+    if (!p)
+        return E_INVALIDARG;
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI xmlelem_get_parent(IXMLElement *iface, IXMLElement **parent)
+{
+    xmlelem *This = impl_from_IXMLElement(iface);
+
+    TRACE("(%p, %p)\n", iface, parent);
+
+    if (!parent)
+        return E_INVALIDARG;
+
+    *parent = NULL;
+
+    if (!This->node->parent)
+        return S_FALSE;
+
+    return XMLElement_create((IUnknown *)iface, This->node->parent, (LPVOID *)parent);
+}
+
+static HRESULT WINAPI xmlelem_setAttribute(IXMLElement *iface, BSTR strPropertyName,
+                                            VARIANT PropertyValue)
+{
+    xmlelem *This = impl_from_IXMLElement(iface);
+    xmlChar *name, *value;
+    xmlAttrPtr attr;
+
+    TRACE("(%p, %s)\n", iface, debugstr_w(strPropertyName));
+
+    if (!strPropertyName || V_VT(&PropertyValue) != VT_BSTR)
+        return E_INVALIDARG;
+
+    name = xmlChar_from_wchar(strPropertyName);
+    value = xmlChar_from_wchar(V_BSTR(&PropertyValue));
+    attr = xmlSetProp(This->node, name, value);
+
+    HeapFree(GetProcessHeap(), 0, name);
+    HeapFree(GetProcessHeap(), 0, value);
+    return (attr) ? S_OK : S_FALSE;
+}
+
+static HRESULT WINAPI xmlelem_getAttribute(IXMLElement *iface, BSTR strPropertyName,
+                                           VARIANT *PropertyValue)
+{
+    xmlelem *This = impl_from_IXMLElement(iface);
+    xmlChar *val = NULL, *name;
+    xmlAttrPtr ptr;
+
+    TRACE("(%p, %s, %p)\n", iface, debugstr_w(strPropertyName), PropertyValue);
+
+    if (!PropertyValue)
+        return E_INVALIDARG;
+
+    VariantClear(PropertyValue);
+    V_BSTR(PropertyValue) = NULL;
+
+    if (!strPropertyName)
+        return E_INVALIDARG;
+
+    name = xmlChar_from_wchar(strPropertyName);
+    ptr = This->node->properties;
+    while (ptr)
+    {
+        if (!lstrcmpiA((LPSTR)name, (LPSTR)ptr->name))
+        {
+            val = xmlNodeListGetString(ptr->doc, ptr->children, 1);
+            break;
+        }
+
+        ptr = ptr->next;
+    }
+
+    if (val)
+    {
+        V_VT(PropertyValue) = VT_BSTR;
+        V_BSTR(PropertyValue) = bstr_from_xmlChar(val);
+    }
+
+    HeapFree(GetProcessHeap(), 0, name);
+    xmlFree(val);
+    TRACE("returning %s\n", debugstr_w(V_BSTR(PropertyValue)));
+    return (val) ? S_OK : S_FALSE;
+}
+
+static HRESULT WINAPI xmlelem_removeAttribute(IXMLElement *iface, BSTR strPropertyName)
+{
+    xmlelem *This = impl_from_IXMLElement(iface);
+    xmlChar *name;
+    xmlAttrPtr attr;
+    int res;
+    HRESULT hr = S_FALSE;
+
+    TRACE("(%p, %s)\n", iface, debugstr_w(strPropertyName));
+
+    if (!strPropertyName)
+        return E_INVALIDARG;
+
+    name = xmlChar_from_wchar(strPropertyName);
+    attr = xmlHasProp(This->node, name);
+    if (!attr)
+        goto done;
+
+    res = xmlRemoveProp(attr);
+
+    if (res == 0)
+        hr = S_OK;
+
+done:
+    HeapFree(GetProcessHeap(), 0, name);
+    return hr;
+}
+
+static HRESULT WINAPI xmlelem_get_children(IXMLElement *iface, IXMLElementCollection **p)
+{
+    xmlelem *This = impl_from_IXMLElement(iface);
+
+    TRACE("(%p, %p)\n", iface, p);
+
+    if (!p)
+        return E_INVALIDARG;
+
+    return XMLElementCollection_create((IUnknown *)iface, This->node->children, (LPVOID *)p);
+}
+
+static long type_libxml_to_msxml(xmlElementType type)
+{
+    switch (type)
+    {
+        case XML_ELEMENT_NODE:
+            return XMLELEMTYPE_ELEMENT;
+        case XML_TEXT_NODE:
+            return XMLELEMTYPE_TEXT;
+        case XML_COMMENT_NODE:
+            return XMLELEMTYPE_COMMENT;
+        case XML_DOCUMENT_NODE:
+            return XMLELEMTYPE_DOCUMENT;
+        case XML_DTD_NODE:
+            return XMLELEMTYPE_DTD;
+        case XML_PI_NODE:
+            return XMLELEMTYPE_PI;
+        default:
+            break;
+    }
+
+    return XMLELEMTYPE_OTHER;
+}
+
+static HRESULT WINAPI xmlelem_get_type(IXMLElement *iface, long *p)
+{
+    xmlelem *This = impl_from_IXMLElement(iface);
+
+    TRACE("(%p, %p)\n", This, p);
+
+    if (!p)
+        return E_INVALIDARG;
+
+    *p = type_libxml_to_msxml(This->node->type);
+    TRACE("returning %ld\n", *p);
+    return S_OK;
+}
+
+static HRESULT WINAPI xmlelem_get_text(IXMLElement *iface, BSTR *p)
+{
+    xmlelem *This = impl_from_IXMLElement(iface);
+    xmlChar *content;
+
+    TRACE("(%p, %p)\n", iface, p);
+
+    if (!p)
+        return E_INVALIDARG;
+
+    content = xmlNodeGetContent(This->node);
+    *p = bstr_from_xmlChar(content);
+    TRACE("returning %s\n", debugstr_w(*p));
+    return S_OK;
+}
+
+static HRESULT WINAPI xmlelem_put_text(IXMLElement *iface, BSTR p)
+{
+    xmlelem *This = impl_from_IXMLElement(iface);
+    xmlChar *content;
+
+    TRACE("(%p, %s)\n", iface, debugstr_w(p));
+
+    /* FIXME: test which types can be used */
+    if (This->node->type == XML_ELEMENT_NODE)
+        return E_NOTIMPL;
+
+    content = xmlChar_from_wchar(p);
+    xmlNodeSetContent(This->node, content);
+    return S_OK;
+}
+
+static HRESULT WINAPI xmlelem_addChild(IXMLElement *iface, IXMLElement *pChildElem,
+                                        long lIndex, long lreserved)
+{
+    xmlelem *This = impl_from_IXMLElement(iface);
+    xmlelem *childElem = impl_from_IXMLElement(pChildElem);
+    xmlNodePtr child;
+
+    TRACE("(%p, %p, %ld, %ld)\n", iface, pChildElem, lIndex, lreserved);
+
+    if (lIndex == 0)
+        child = xmlAddChild(This->node, childElem->node);
+    else
+        child = xmlAddNextSibling(This->node, childElem->node->last);
+
+    return (child) ? S_OK : S_FALSE;
+}
+
+static HRESULT WINAPI xmlelem_removeChild(IXMLElement *iface, IXMLElement *pChildElem)
+{
+    FIXME("(%p, %p): stub\n", iface, pChildElem);
+    return E_NOTIMPL;
+}
+
+static const struct IXMLElementVtbl xmlelem_vtbl =
+{
+    xmlelem_QueryInterface,
+    xmlelem_AddRef,
+    xmlelem_Release,
+    xmlelem_GetTypeInfoCount,
+    xmlelem_GetTypeInfo,
+    xmlelem_GetIDsOfNames,
+    xmlelem_Invoke,
+    xmlelem_get_tagName,
+    xmlelem_put_tagName,
+    xmlelem_get_parent,
+    xmlelem_setAttribute,
+    xmlelem_getAttribute,
+    xmlelem_removeAttribute,
+    xmlelem_get_children,
+    xmlelem_get_type,
+    xmlelem_get_text,
+    xmlelem_put_text,
+    xmlelem_addChild,
+    xmlelem_removeChild
+};
+
+HRESULT XMLElement_create(IUnknown *pUnkOuter, xmlNodePtr node, LPVOID *ppObj)
+{
+    xmlelem *elem;
+
+    TRACE("(%p,%p)\n", pUnkOuter, ppObj);
+
+    if (!ppObj)
+        return E_INVALIDARG;
+
+    *ppObj = NULL;
+
+    elem = HeapAlloc(GetProcessHeap(), 0, sizeof (*elem));
+    if(!elem)
+        return E_OUTOFMEMORY;
+
+    elem->lpVtbl = &xmlelem_vtbl;
+    elem->ref = 1;
+    elem->node = node;
+
+    *ppObj = &elem->lpVtbl;
+
+    TRACE("returning iface %p\n", *ppObj);
+    return S_OK;
+}
+
+/************************************************************************
+ * IXMLElementCollection
+ */
+typedef struct _xmlelem_collection
+{
+    const IXMLElementCollectionVtbl *lpVtbl;
+    const IEnumVARIANTVtbl          *lpvtblIEnumVARIANT;
+    LONG ref;
+    LONG length;
+    xmlNodePtr node;
+
+    /* IEnumVARIANT members */
+    xmlNodePtr current;
+} xmlelem_collection;
+
+static inline xmlelem_collection *impl_from_IXMLElementCollection(IXMLElementCollection *iface)
+{
+    return (xmlelem_collection *)((char*)iface - FIELD_OFFSET(xmlelem_collection, lpVtbl));
+}
+
+static inline xmlelem_collection *impl_from_IEnumVARIANT(IEnumVARIANT *iface)
+{
+    return (xmlelem_collection *)((char*)iface - FIELD_OFFSET(xmlelem_collection, lpvtblIEnumVARIANT));
+}
+
+static HRESULT WINAPI xmlelem_collection_QueryInterface(IXMLElementCollection *iface, REFIID riid, void** ppvObject)
+{
+    xmlelem_collection *This = impl_from_IXMLElementCollection(iface);
+
+    TRACE("%p %s %p\n", This, debugstr_guid(riid), ppvObject);
+
+    if (IsEqualGUID(riid, &IID_IUnknown) ||
+        IsEqualGUID(riid, &IID_IXMLElementCollection))
+    {
+        *ppvObject = iface;
+    }
+    else if (IsEqualGUID(riid, &IID_IEnumVARIANT))
+    {
+        *ppvObject = (IEnumVARIANT *)&(This->lpvtblIEnumVARIANT);
+    }
+    else
+    {
+        FIXME("interface %s not implemented\n", debugstr_guid(riid));
+        return E_NOINTERFACE;
+    }
+
+    IXMLElementCollection_AddRef(iface);
+
+    return S_OK;
+}
+
+static ULONG WINAPI xmlelem_collection_AddRef(IXMLElementCollection *iface)
+{
+    xmlelem_collection *This = impl_from_IXMLElementCollection(iface);
+    TRACE("%p\n", This);
+    return InterlockedIncrement(&This->ref);
+}
+
+static ULONG WINAPI xmlelem_collection_Release(IXMLElementCollection *iface)
+{
+    xmlelem_collection *This = impl_from_IXMLElementCollection(iface);
+    LONG ref;
+
+    TRACE("%p\n", This);
+
+    ref = InterlockedDecrement(&This->ref);
+    if (ref == 0)
+    {
+        HeapFree(GetProcessHeap(), 0, This);
+    }
+
+    return ref;
+}
+
+static HRESULT WINAPI xmlelem_collection_GetTypeInfoCount(IXMLElementCollection *iface, UINT* pctinfo)
+{
+    FIXME("\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI xmlelem_collection_GetTypeInfo(IXMLElementCollection *iface, UINT iTInfo,
+                                                     LCID lcid, ITypeInfo** ppTInfo)
+{
+    FIXME("\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI xmlelem_collection_GetIDsOfNames(IXMLElementCollection *iface, REFIID riid,
+                                                       LPOLESTR* rgszNames, UINT cNames,
+                                                       LCID lcid, DISPID* rgDispId)
+{
+    FIXME("\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI xmlelem_collection_Invoke(IXMLElementCollection *iface, DISPID dispIdMember,
+                                                REFIID riid, LCID lcid, WORD wFlags,
+                                                DISPPARAMS* pDispParams, VARIANT* pVarResult,
+                                                EXCEPINFO* pExcepInfo, UINT* puArgErr)
+{
+    FIXME("\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI xmlelem_collection_put_length(IXMLElementCollection *iface, long v)
+{
+    TRACE("(%p, %ld)\n", iface, v);
+    return E_FAIL;
+}
+
+static HRESULT WINAPI xmlelem_collection_get_length(IXMLElementCollection *iface, long *p)
+{
+    xmlelem_collection *This = impl_from_IXMLElementCollection(iface);
+
+    TRACE("(%p, %p)\n", iface, p);
+
+    if (!p)
+        return E_INVALIDARG;
+
+    *p = This->length;
+    return S_OK;
+}
+
+static HRESULT WINAPI xmlelem_collection_get__newEnum(IXMLElementCollection *iface, IUnknown **ppUnk)
+{
+    xmlelem_collection *This = impl_from_IXMLElementCollection(iface);
+
+    TRACE("(%p, %p)\n", iface, ppUnk);
+
+    if (!ppUnk)
+        return E_INVALIDARG;
+
+    *ppUnk = (IUnknown *)This;
+    IUnknown_AddRef(*ppUnk);
+    return S_OK;
+}
+
+static HRESULT WINAPI xmlelem_collection_item(IXMLElementCollection *iface, VARIANT var1,
+                                              VARIANT var2, IDispatch **ppDisp)
+{
+    xmlelem_collection *This = impl_from_IXMLElementCollection(iface);
+    xmlNodePtr ptr = This->node;
+    int index, i;
+
+    TRACE("(%p, %p)\n", iface, ppDisp);
+
+    if (!ppDisp)
+        return E_INVALIDARG;
+
+    *ppDisp = NULL;
+
+    index = V_I4(&var1);
+    if (index < 0)
+        return E_INVALIDARG;
+    if (index >= This->length)
+        return E_FAIL;
+
+    for (i = 0; i < index; i++)
+        ptr = ptr->next;
+
+    return XMLElement_create((IUnknown *)iface, ptr, (LPVOID *)ppDisp);
+}
+
+static const struct IXMLElementCollectionVtbl xmlelem_collection_vtbl =
+{
+    xmlelem_collection_QueryInterface,
+    xmlelem_collection_AddRef,
+    xmlelem_collection_Release,
+    xmlelem_collection_GetTypeInfoCount,
+    xmlelem_collection_GetTypeInfo,
+    xmlelem_collection_GetIDsOfNames,
+    xmlelem_collection_Invoke,
+    xmlelem_collection_put_length,
+    xmlelem_collection_get_length,
+    xmlelem_collection_get__newEnum,
+    xmlelem_collection_item
+};
+
+/************************************************************************
+ * xmlelem_collection implementation of IEnumVARIANT.
+ */
+static HRESULT WINAPI xmlelem_collection_IEnumVARIANT_QueryInterface(
+    IEnumVARIANT *iface, REFIID riid, LPVOID *ppvObj)
+{
+    xmlelem_collection *this = impl_from_IEnumVARIANT(iface);
+    return IXMLDocument_QueryInterface((IXMLDocument *)this, riid, ppvObj);
+}
+
+static ULONG WINAPI xmlelem_collection_IEnumVARIANT_AddRef(
+    IEnumVARIANT *iface)
+{
+    xmlelem_collection *this = impl_from_IEnumVARIANT(iface);
+    return IXMLDocument_AddRef((IXMLDocument *)this);
+}
+
+static ULONG WINAPI xmlelem_collection_IEnumVARIANT_Release(
+    IEnumVARIANT *iface)
+{
+    xmlelem_collection *this = impl_from_IEnumVARIANT(iface);
+    return IXMLDocument_Release((IXMLDocument *)this);
+}
+
+static HRESULT WINAPI xmlelem_collection_IEnumVARIANT_Next(
+    IEnumVARIANT *iface, ULONG celt, VARIANT *rgVar, ULONG *pCeltFetched)
+{
+    xmlelem_collection *This = impl_from_IEnumVARIANT(iface);
+    xmlNodePtr ptr = This->current;
+
+    TRACE("(%p, %d, %p, %p)\n", iface, celt, rgVar, pCeltFetched);
+
+    if (!rgVar)
+        return E_INVALIDARG;
+
+    /* FIXME: handle celt */
+    if (pCeltFetched)
+        *pCeltFetched = 1;
+
+    This->current = This->current->next;
+
+    V_VT(rgVar) = VT_DISPATCH;
+    return XMLElement_create((IUnknown *)iface, ptr, (LPVOID *)&V_DISPATCH(rgVar));
+}
+
+static HRESULT WINAPI xmlelem_collection_IEnumVARIANT_Skip(
+    IEnumVARIANT *iface, ULONG celt)
+{
+    FIXME("(%p, %d): stub\n", iface, celt);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI xmlelem_collection_IEnumVARIANT_Reset(
+    IEnumVARIANT *iface)
+{
+    xmlelem_collection *This = impl_from_IEnumVARIANT(iface);
+    This->current = This->node;
+    return S_OK;
+}
+
+static HRESULT WINAPI xmlelem_collection_IEnumVARIANT_Clone(
+    IEnumVARIANT *iface, IEnumVARIANT **ppEnum)
+{
+    FIXME("(%p, %p): stub\n", iface, ppEnum);
+    return E_NOTIMPL;
+}
+
+static const struct IEnumVARIANTVtbl xmlelem_collection_IEnumVARIANTvtbl =
+{
+    xmlelem_collection_IEnumVARIANT_QueryInterface,
+    xmlelem_collection_IEnumVARIANT_AddRef,
+    xmlelem_collection_IEnumVARIANT_Release,
+    xmlelem_collection_IEnumVARIANT_Next,
+    xmlelem_collection_IEnumVARIANT_Skip,
+    xmlelem_collection_IEnumVARIANT_Reset,
+    xmlelem_collection_IEnumVARIANT_Clone
+};
+
+HRESULT XMLElementCollection_create(IUnknown *pUnkOuter, xmlNodePtr node, LPVOID *ppObj)
+{
+    xmlelem_collection *collection;
+    xmlNodePtr ptr;
+
+    TRACE("(%p,%p)\n", pUnkOuter, ppObj);
+
+    *ppObj = NULL;
+
+    if (!node)
+        return S_FALSE;
+
+    collection = HeapAlloc(GetProcessHeap(), 0, sizeof (*collection));
+    if(!collection)
+        return E_OUTOFMEMORY;
+
+    collection->lpVtbl = &xmlelem_collection_vtbl;
+    collection->lpvtblIEnumVARIANT = &xmlelem_collection_IEnumVARIANTvtbl;
+    collection->ref = 1;
+    collection->length = 0;
+    collection->node = node;
+    collection->current = node;
+
+    ptr = node;
+    while (ptr)
+    {
+        collection->length++;
+        ptr = ptr->next;
+    }
+
+    *ppObj = &collection->lpVtbl;
+
+    TRACE("returning iface %p\n", *ppObj);
+    return S_OK;
+}
+
+#endif
+
-- 
1.4.1


More information about the wine-patches mailing list