msxml3: Fix duplicated declarations after document ::get_xml().
[wine] / dlls / msxml3 / xmlelem.c
1 /*
2  * XML Element implementation
3  *
4  * Copyright 2007 James Hawkins
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #define COBJMACROS
22
23 #include "config.h"
24
25 #include <stdarg.h>
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winuser.h"
29 #include "ole2.h"
30 #include "msxml6.h"
31 #include "ocidl.h"
32
33 #include "wine/debug.h"
34
35 #include "msxml_private.h"
36
37 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
38
39 #ifdef HAVE_LIBXML2
40
41 static HRESULT XMLElementCollection_create( IUnknown *pUnkOuter, xmlNodePtr node, LPVOID *ppObj );
42
43 /**********************************************************************
44  * IXMLElement
45  */
46 typedef struct _xmlelem
47 {
48     const IXMLElementVtbl *lpVtbl;
49     LONG ref;
50     xmlNodePtr node;
51     BOOL own;
52 } xmlelem;
53
54 static inline xmlelem *impl_from_IXMLElement(IXMLElement *iface)
55 {
56     return (xmlelem *)((char*)iface - FIELD_OFFSET(xmlelem, lpVtbl));
57 }
58
59 static HRESULT WINAPI xmlelem_QueryInterface(IXMLElement *iface, REFIID riid, void** ppvObject)
60 {
61     xmlelem *This = impl_from_IXMLElement(iface);
62
63     TRACE("%p %s %p\n", This, debugstr_guid(riid), ppvObject);
64
65     if (IsEqualGUID(riid, &IID_IUnknown) ||
66         IsEqualGUID(riid, &IID_IXMLElement))
67     {
68         *ppvObject = iface;
69     }
70     else
71     {
72         FIXME("interface %s not implemented\n", debugstr_guid(riid));
73         return E_NOINTERFACE;
74     }
75
76     IXMLElement_AddRef(iface);
77
78     return S_OK;
79 }
80
81 static ULONG WINAPI xmlelem_AddRef(IXMLElement *iface)
82 {
83     xmlelem *This = impl_from_IXMLElement(iface);
84     TRACE("%p\n", This);
85     return InterlockedIncrement(&This->ref);
86 }
87
88 static ULONG WINAPI xmlelem_Release(IXMLElement *iface)
89 {
90     xmlelem *This = impl_from_IXMLElement(iface);
91     LONG ref;
92
93     TRACE("%p\n", This);
94
95     ref = InterlockedDecrement(&This->ref);
96     if (ref == 0)
97     {
98         if (This->own) xmlFreeNode(This->node);
99         heap_free(This);
100     }
101
102     return ref;
103 }
104
105 static HRESULT WINAPI xmlelem_GetTypeInfoCount(IXMLElement *iface, UINT* pctinfo)
106 {
107     xmlelem *This = impl_from_IXMLElement(iface);
108
109     TRACE("(%p)->(%p)\n", This, pctinfo);
110
111     *pctinfo = 1;
112
113     return S_OK;
114 }
115
116 static HRESULT WINAPI xmlelem_GetTypeInfo(IXMLElement *iface, UINT iTInfo,
117                                           LCID lcid, ITypeInfo** ppTInfo)
118 {
119     xmlelem *This = impl_from_IXMLElement(iface);
120     HRESULT hr;
121
122     TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
123
124     hr = get_typeinfo(IXMLElement_tid, ppTInfo);
125
126     return hr;
127 }
128
129 static HRESULT WINAPI xmlelem_GetIDsOfNames(IXMLElement *iface, REFIID riid,
130                                             LPOLESTR* rgszNames, UINT cNames,
131                                             LCID lcid, DISPID* rgDispId)
132 {
133     xmlelem *This = impl_from_IXMLElement(iface);
134     ITypeInfo *typeinfo;
135     HRESULT hr;
136
137     TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
138           lcid, rgDispId);
139
140     if(!rgszNames || cNames == 0 || !rgDispId)
141         return E_INVALIDARG;
142
143     hr = get_typeinfo(IXMLElement_tid, &typeinfo);
144     if(SUCCEEDED(hr))
145     {
146         hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
147         ITypeInfo_Release(typeinfo);
148     }
149
150     return hr;
151 }
152
153 static HRESULT WINAPI xmlelem_Invoke(IXMLElement *iface, DISPID dispIdMember,
154                                      REFIID riid, LCID lcid, WORD wFlags,
155                                      DISPPARAMS* pDispParams, VARIANT* pVarResult,
156                                      EXCEPINFO* pExcepInfo, UINT* puArgErr)
157 {
158     xmlelem *This = impl_from_IXMLElement(iface);
159     ITypeInfo *typeinfo;
160     HRESULT hr;
161
162     TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
163           lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
164
165     hr = get_typeinfo(IXMLElement_tid, &typeinfo);
166     if(SUCCEEDED(hr))
167     {
168         hr = ITypeInfo_Invoke(typeinfo, &(This->lpVtbl), dispIdMember, wFlags, pDispParams,
169                 pVarResult, pExcepInfo, puArgErr);
170         ITypeInfo_Release(typeinfo);
171     }
172
173     return hr;
174 }
175
176 static HRESULT WINAPI xmlelem_get_tagName(IXMLElement *iface, BSTR *p)
177 {
178     xmlelem *This = impl_from_IXMLElement(iface);
179
180     TRACE("(%p, %p)\n", iface, p);
181
182     if (!p)
183         return E_INVALIDARG;
184
185     *p = bstr_from_xmlChar(This->node->name);
186     CharUpperBuffW(*p, SysStringLen(*p));
187
188     TRACE("returning %s\n", debugstr_w(*p));
189
190     return S_OK;
191 }
192
193 static HRESULT WINAPI xmlelem_put_tagName(IXMLElement *iface, BSTR p)
194 {
195     FIXME("(%p, %p): stub\n", iface, p);
196
197     if (!p)
198         return E_INVALIDARG;
199
200     return E_NOTIMPL;
201 }
202
203 static HRESULT WINAPI xmlelem_get_parent(IXMLElement *iface, IXMLElement **parent)
204 {
205     xmlelem *This = impl_from_IXMLElement(iface);
206
207     TRACE("(%p, %p)\n", iface, parent);
208
209     if (!parent)
210         return E_INVALIDARG;
211
212     *parent = NULL;
213
214     if (!This->node->parent)
215         return S_FALSE;
216
217     return XMLElement_create((IUnknown *)iface, This->node->parent, (LPVOID *)parent, FALSE);
218 }
219
220 static HRESULT WINAPI xmlelem_setAttribute(IXMLElement *iface, BSTR strPropertyName,
221                                             VARIANT PropertyValue)
222 {
223     xmlelem *This = impl_from_IXMLElement(iface);
224     xmlChar *name, *value;
225     xmlAttrPtr attr;
226
227     TRACE("(%p, %s)\n", iface, debugstr_w(strPropertyName));
228
229     if (!strPropertyName || V_VT(&PropertyValue) != VT_BSTR)
230         return E_INVALIDARG;
231
232     name = xmlChar_from_wchar(strPropertyName);
233     value = xmlChar_from_wchar(V_BSTR(&PropertyValue));
234     attr = xmlSetProp(This->node, name, value);
235
236     heap_free(name);
237     heap_free(value);
238     return (attr) ? S_OK : S_FALSE;
239 }
240
241 static HRESULT WINAPI xmlelem_getAttribute(IXMLElement *iface, BSTR name,
242     VARIANT *value)
243 {
244     static const WCHAR xmllangW[] = { 'x','m','l',':','l','a','n','g',0 };
245     xmlelem *This = impl_from_IXMLElement(iface);
246     xmlChar *val = NULL;
247
248     TRACE("(%p, %s, %p)\n", iface, debugstr_w(name), value);
249
250     if (!value)
251         return E_INVALIDARG;
252
253     VariantInit(value);
254     V_BSTR(value) = NULL;
255
256     if (!name)
257         return E_INVALIDARG;
258
259     /* case for xml:lang attribute */
260     if (!lstrcmpiW(name, xmllangW))
261     {
262         xmlNsPtr ns;
263         ns = xmlSearchNs(This->node->doc, This->node, (xmlChar*)"xml");
264         val = xmlGetNsProp(This->node, (xmlChar*)"lang", ns->href);
265     }
266     else
267     {
268         xmlAttrPtr attr;
269         xmlChar *xml_name;
270
271         xml_name = xmlChar_from_wchar(name);
272         attr = This->node->properties;
273         while (attr)
274         {
275             BSTR attr_name;
276
277             attr_name = bstr_from_xmlChar(attr->name);
278             if (!lstrcmpiW(name, attr_name))
279             {
280                 val = xmlNodeListGetString(attr->doc, attr->children, 1);
281                 SysFreeString(attr_name);
282                 break;
283             }
284
285             attr = attr->next;
286             SysFreeString(attr_name);
287         }
288
289         heap_free(xml_name);
290     }
291
292     if (val)
293     {
294         V_VT(value) = VT_BSTR;
295         V_BSTR(value) = bstr_from_xmlChar(val);
296     }
297
298     xmlFree(val);
299     TRACE("returning %s\n", debugstr_w(V_BSTR(value)));
300     return (val) ? S_OK : S_FALSE;
301 }
302
303 static HRESULT WINAPI xmlelem_removeAttribute(IXMLElement *iface, BSTR strPropertyName)
304 {
305     xmlelem *This = impl_from_IXMLElement(iface);
306     xmlChar *name;
307     xmlAttrPtr attr;
308     int res;
309     HRESULT hr = S_FALSE;
310
311     TRACE("(%p, %s)\n", iface, debugstr_w(strPropertyName));
312
313     if (!strPropertyName)
314         return E_INVALIDARG;
315
316     name = xmlChar_from_wchar(strPropertyName);
317     attr = xmlHasProp(This->node, name);
318     if (!attr)
319         goto done;
320
321     res = xmlRemoveProp(attr);
322
323     if (res == 0)
324         hr = S_OK;
325
326 done:
327     heap_free(name);
328     return hr;
329 }
330
331 static HRESULT WINAPI xmlelem_get_children(IXMLElement *iface, IXMLElementCollection **p)
332 {
333     xmlelem *This = impl_from_IXMLElement(iface);
334
335     TRACE("(%p, %p)\n", iface, p);
336
337     if (!p)
338         return E_INVALIDARG;
339
340     return XMLElementCollection_create((IUnknown *)iface, This->node, (LPVOID *)p);
341 }
342
343 static LONG type_libxml_to_msxml(xmlElementType type)
344 {
345     switch (type)
346     {
347         case XML_ELEMENT_NODE:
348             return XMLELEMTYPE_ELEMENT;
349         case XML_TEXT_NODE:
350             return XMLELEMTYPE_TEXT;
351         case XML_COMMENT_NODE:
352             return XMLELEMTYPE_COMMENT;
353         case XML_DOCUMENT_NODE:
354             return XMLELEMTYPE_DOCUMENT;
355         case XML_DTD_NODE:
356             return XMLELEMTYPE_DTD;
357         case XML_PI_NODE:
358             return XMLELEMTYPE_PI;
359         default:
360             break;
361     }
362
363     return XMLELEMTYPE_OTHER;
364 }
365
366 static HRESULT WINAPI xmlelem_get_type(IXMLElement *iface, LONG *p)
367 {
368     xmlelem *This = impl_from_IXMLElement(iface);
369
370     TRACE("(%p, %p)\n", This, p);
371
372     if (!p)
373         return E_INVALIDARG;
374
375     *p = type_libxml_to_msxml(This->node->type);
376     TRACE("returning %d\n", *p);
377     return S_OK;
378 }
379
380 static HRESULT WINAPI xmlelem_get_text(IXMLElement *iface, BSTR *p)
381 {
382     xmlelem *This = impl_from_IXMLElement(iface);
383     xmlChar *content;
384
385     TRACE("(%p, %p)\n", iface, p);
386
387     if (!p)
388         return E_INVALIDARG;
389
390     content = xmlNodeGetContent(This->node);
391     *p = bstr_from_xmlChar(content);
392     TRACE("returning %s\n", debugstr_w(*p));
393
394     xmlFree(content);
395     return S_OK;
396 }
397
398 static HRESULT WINAPI xmlelem_put_text(IXMLElement *iface, BSTR p)
399 {
400     xmlelem *This = impl_from_IXMLElement(iface);
401     xmlChar *content;
402
403     TRACE("(%p, %s)\n", iface, debugstr_w(p));
404
405     /* FIXME: test which types can be used */
406     if (This->node->type == XML_ELEMENT_NODE)
407         return E_NOTIMPL;
408
409     content = xmlChar_from_wchar(p);
410     xmlNodeSetContent(This->node, content);
411
412     heap_free(content);
413
414     return S_OK;
415 }
416
417 static HRESULT WINAPI xmlelem_addChild(IXMLElement *iface, IXMLElement *pChildElem,
418                                        LONG lIndex, LONG lreserved)
419 {
420     xmlelem *This = impl_from_IXMLElement(iface);
421     xmlelem *childElem = impl_from_IXMLElement(pChildElem);
422     xmlNodePtr child;
423
424     TRACE("(%p, %p, %d, %d)\n", iface, pChildElem, lIndex, lreserved);
425
426     if (lIndex == 0)
427         child = xmlAddChild(This->node, childElem->node);
428     else
429         child = xmlAddNextSibling(This->node, childElem->node->last);
430
431     /* parent is responsible for child data */
432     if (child) childElem->own = FALSE;
433
434     return (child) ? S_OK : S_FALSE;
435 }
436
437 static HRESULT WINAPI xmlelem_removeChild(IXMLElement *iface, IXMLElement *pChildElem)
438 {
439     xmlelem *This = impl_from_IXMLElement(iface);
440     xmlelem *childElem = impl_from_IXMLElement(pChildElem);
441
442     TRACE("(%p, %p)\n", This, childElem);
443
444     if (!pChildElem)
445         return E_INVALIDARG;
446
447     /* only supported for This is childElem parent case */
448     if (This->node != childElem->node->parent)
449         return E_INVALIDARG;
450
451     xmlUnlinkNode(childElem->node);
452     /* standalone element now */
453     childElem->own = TRUE;
454
455     return S_OK;
456 }
457
458 static const struct IXMLElementVtbl xmlelem_vtbl =
459 {
460     xmlelem_QueryInterface,
461     xmlelem_AddRef,
462     xmlelem_Release,
463     xmlelem_GetTypeInfoCount,
464     xmlelem_GetTypeInfo,
465     xmlelem_GetIDsOfNames,
466     xmlelem_Invoke,
467     xmlelem_get_tagName,
468     xmlelem_put_tagName,
469     xmlelem_get_parent,
470     xmlelem_setAttribute,
471     xmlelem_getAttribute,
472     xmlelem_removeAttribute,
473     xmlelem_get_children,
474     xmlelem_get_type,
475     xmlelem_get_text,
476     xmlelem_put_text,
477     xmlelem_addChild,
478     xmlelem_removeChild
479 };
480
481 HRESULT XMLElement_create(IUnknown *pUnkOuter, xmlNodePtr node, LPVOID *ppObj, BOOL own)
482 {
483     xmlelem *elem;
484
485     TRACE("(%p,%p)\n", pUnkOuter, ppObj);
486
487     if (!ppObj)
488         return E_INVALIDARG;
489
490     *ppObj = NULL;
491
492     elem = heap_alloc(sizeof (*elem));
493     if(!elem)
494         return E_OUTOFMEMORY;
495
496     elem->lpVtbl = &xmlelem_vtbl;
497     elem->ref = 1;
498     elem->node = node;
499     elem->own  = own;
500
501     *ppObj = &elem->lpVtbl;
502
503     TRACE("returning iface %p\n", *ppObj);
504     return S_OK;
505 }
506
507 /************************************************************************
508  * IXMLElementCollection
509  */
510 typedef struct _xmlelem_collection
511 {
512     const IXMLElementCollectionVtbl *lpVtbl;
513     const IEnumVARIANTVtbl          *lpvtblIEnumVARIANT;
514     LONG ref;
515     LONG length;
516     xmlNodePtr node;
517
518     /* IEnumVARIANT members */
519     xmlNodePtr current;
520 } xmlelem_collection;
521
522 static inline LONG xmlelem_collection_updatelength(xmlelem_collection *collection)
523 {
524     xmlNodePtr ptr = collection->node->children;
525
526     collection->length = 0;
527     while (ptr)
528     {
529         collection->length++;
530         ptr = ptr->next;
531     }
532     return collection->length;
533 }
534
535 static inline xmlelem_collection *impl_from_IXMLElementCollection(IXMLElementCollection *iface)
536 {
537     return (xmlelem_collection *)((char*)iface - FIELD_OFFSET(xmlelem_collection, lpVtbl));
538 }
539
540 static inline xmlelem_collection *impl_from_IEnumVARIANT(IEnumVARIANT *iface)
541 {
542     return (xmlelem_collection *)((char*)iface - FIELD_OFFSET(xmlelem_collection, lpvtblIEnumVARIANT));
543 }
544
545 static HRESULT WINAPI xmlelem_collection_QueryInterface(IXMLElementCollection *iface, REFIID riid, void** ppvObject)
546 {
547     xmlelem_collection *This = impl_from_IXMLElementCollection(iface);
548
549     TRACE("%p %s %p\n", This, debugstr_guid(riid), ppvObject);
550
551     if (IsEqualGUID(riid, &IID_IUnknown) ||
552         IsEqualGUID(riid, &IID_IXMLElementCollection))
553     {
554         *ppvObject = iface;
555     }
556     else if (IsEqualGUID(riid, &IID_IEnumVARIANT))
557     {
558         *ppvObject = &(This->lpvtblIEnumVARIANT);
559     }
560     else
561     {
562         FIXME("interface %s not implemented\n", debugstr_guid(riid));
563         return E_NOINTERFACE;
564     }
565
566     IXMLElementCollection_AddRef(iface);
567
568     return S_OK;
569 }
570
571 static ULONG WINAPI xmlelem_collection_AddRef(IXMLElementCollection *iface)
572 {
573     xmlelem_collection *This = impl_from_IXMLElementCollection(iface);
574     TRACE("%p\n", This);
575     return InterlockedIncrement(&This->ref);
576 }
577
578 static ULONG WINAPI xmlelem_collection_Release(IXMLElementCollection *iface)
579 {
580     xmlelem_collection *This = impl_from_IXMLElementCollection(iface);
581     LONG ref;
582
583     TRACE("%p\n", This);
584
585     ref = InterlockedDecrement(&This->ref);
586     if (ref == 0)
587     {
588         heap_free(This);
589     }
590
591     return ref;
592 }
593
594 static HRESULT WINAPI xmlelem_collection_GetTypeInfoCount(IXMLElementCollection *iface, UINT* pctinfo)
595 {
596     FIXME("\n");
597     return E_NOTIMPL;
598 }
599
600 static HRESULT WINAPI xmlelem_collection_GetTypeInfo(IXMLElementCollection *iface, UINT iTInfo,
601                                                      LCID lcid, ITypeInfo** ppTInfo)
602 {
603     FIXME("\n");
604     return E_NOTIMPL;
605 }
606
607 static HRESULT WINAPI xmlelem_collection_GetIDsOfNames(IXMLElementCollection *iface, REFIID riid,
608                                                        LPOLESTR* rgszNames, UINT cNames,
609                                                        LCID lcid, DISPID* rgDispId)
610 {
611     FIXME("\n");
612     return E_NOTIMPL;
613 }
614
615 static HRESULT WINAPI xmlelem_collection_Invoke(IXMLElementCollection *iface, DISPID dispIdMember,
616                                                 REFIID riid, LCID lcid, WORD wFlags,
617                                                 DISPPARAMS* pDispParams, VARIANT* pVarResult,
618                                                 EXCEPINFO* pExcepInfo, UINT* puArgErr)
619 {
620     FIXME("\n");
621     return E_NOTIMPL;
622 }
623
624 static HRESULT WINAPI xmlelem_collection_put_length(IXMLElementCollection *iface, LONG v)
625 {
626     TRACE("(%p, %d)\n", iface, v);
627     return E_FAIL;
628 }
629
630 static HRESULT WINAPI xmlelem_collection_get_length(IXMLElementCollection *iface, LONG *p)
631 {
632     xmlelem_collection *This = impl_from_IXMLElementCollection(iface);
633
634     TRACE("(%p, %p)\n", iface, p);
635
636     if (!p)
637         return E_INVALIDARG;
638
639     *p = xmlelem_collection_updatelength(This);
640     return S_OK;
641 }
642
643 static HRESULT WINAPI xmlelem_collection_get__newEnum(IXMLElementCollection *iface, IUnknown **ppUnk)
644 {
645     xmlelem_collection *This = impl_from_IXMLElementCollection(iface);
646
647     TRACE("(%p, %p)\n", iface, ppUnk);
648
649     if (!ppUnk)
650         return E_INVALIDARG;
651
652     *ppUnk = (IUnknown *)This;
653     IUnknown_AddRef(*ppUnk);
654     return S_OK;
655 }
656
657 static HRESULT WINAPI xmlelem_collection_item(IXMLElementCollection *iface, VARIANT var1,
658                                               VARIANT var2, IDispatch **ppDisp)
659 {
660     xmlelem_collection *This = impl_from_IXMLElementCollection(iface);
661     xmlNodePtr ptr = This->node->children;
662     int index, i;
663
664     TRACE("(%p, %p)\n", iface, ppDisp);
665
666     if (!ppDisp)
667         return E_INVALIDARG;
668
669     *ppDisp = NULL;
670
671     index = V_I4(&var1);
672     if (index < 0)
673         return E_INVALIDARG;
674
675     xmlelem_collection_updatelength(This);
676     if (index >= This->length)
677         return E_FAIL;
678
679     for (i = 0; i < index; i++)
680         ptr = ptr->next;
681
682     return XMLElement_create((IUnknown *)iface, ptr, (LPVOID *)ppDisp, FALSE);
683 }
684
685 static const struct IXMLElementCollectionVtbl xmlelem_collection_vtbl =
686 {
687     xmlelem_collection_QueryInterface,
688     xmlelem_collection_AddRef,
689     xmlelem_collection_Release,
690     xmlelem_collection_GetTypeInfoCount,
691     xmlelem_collection_GetTypeInfo,
692     xmlelem_collection_GetIDsOfNames,
693     xmlelem_collection_Invoke,
694     xmlelem_collection_put_length,
695     xmlelem_collection_get_length,
696     xmlelem_collection_get__newEnum,
697     xmlelem_collection_item
698 };
699
700 /************************************************************************
701  * xmlelem_collection implementation of IEnumVARIANT.
702  */
703 static HRESULT WINAPI xmlelem_collection_IEnumVARIANT_QueryInterface(
704     IEnumVARIANT *iface, REFIID riid, LPVOID *ppvObj)
705 {
706     xmlelem_collection *this = impl_from_IEnumVARIANT(iface);
707     return IXMLDocument_QueryInterface((IXMLDocument *)this, riid, ppvObj);
708 }
709
710 static ULONG WINAPI xmlelem_collection_IEnumVARIANT_AddRef(
711     IEnumVARIANT *iface)
712 {
713     xmlelem_collection *this = impl_from_IEnumVARIANT(iface);
714     return IXMLDocument_AddRef((IXMLDocument *)this);
715 }
716
717 static ULONG WINAPI xmlelem_collection_IEnumVARIANT_Release(
718     IEnumVARIANT *iface)
719 {
720     xmlelem_collection *this = impl_from_IEnumVARIANT(iface);
721     return IXMLDocument_Release((IXMLDocument *)this);
722 }
723
724 static HRESULT WINAPI xmlelem_collection_IEnumVARIANT_Next(
725     IEnumVARIANT *iface, ULONG celt, VARIANT *rgVar, ULONG *fetched)
726 {
727     xmlelem_collection *This = impl_from_IEnumVARIANT(iface);
728     xmlNodePtr ptr = This->current;
729
730     TRACE("(%p, %d, %p, %p)\n", iface, celt, rgVar, fetched);
731
732     if (!rgVar)
733         return E_INVALIDARG;
734
735     /* FIXME: handle celt */
736     if (fetched)
737         *fetched = 1;
738
739     if (This->current)
740         This->current = This->current->next;
741     else
742     {
743         V_VT(rgVar) = VT_EMPTY;
744         if (fetched) *fetched = 0;
745         return S_FALSE;
746     }
747
748     V_VT(rgVar) = VT_DISPATCH;
749     return XMLElement_create((IUnknown *)iface, ptr, (LPVOID *)&V_DISPATCH(rgVar), FALSE);
750 }
751
752 static HRESULT WINAPI xmlelem_collection_IEnumVARIANT_Skip(
753     IEnumVARIANT *iface, ULONG celt)
754 {
755     FIXME("(%p, %d): stub\n", iface, celt);
756     return E_NOTIMPL;
757 }
758
759 static HRESULT WINAPI xmlelem_collection_IEnumVARIANT_Reset(
760     IEnumVARIANT *iface)
761 {
762     xmlelem_collection *This = impl_from_IEnumVARIANT(iface);
763     This->current = This->node->children;
764     return S_OK;
765 }
766
767 static HRESULT WINAPI xmlelem_collection_IEnumVARIANT_Clone(
768     IEnumVARIANT *iface, IEnumVARIANT **ppEnum)
769 {
770     FIXME("(%p, %p): stub\n", iface, ppEnum);
771     return E_NOTIMPL;
772 }
773
774 static const struct IEnumVARIANTVtbl xmlelem_collection_IEnumVARIANTvtbl =
775 {
776     xmlelem_collection_IEnumVARIANT_QueryInterface,
777     xmlelem_collection_IEnumVARIANT_AddRef,
778     xmlelem_collection_IEnumVARIANT_Release,
779     xmlelem_collection_IEnumVARIANT_Next,
780     xmlelem_collection_IEnumVARIANT_Skip,
781     xmlelem_collection_IEnumVARIANT_Reset,
782     xmlelem_collection_IEnumVARIANT_Clone
783 };
784
785 static HRESULT XMLElementCollection_create(IUnknown *pUnkOuter, xmlNodePtr node, LPVOID *ppObj)
786 {
787     xmlelem_collection *collection;
788
789     TRACE("(%p,%p)\n", pUnkOuter, ppObj);
790
791     *ppObj = NULL;
792
793     if (!node->children)
794         return S_FALSE;
795
796     collection = heap_alloc(sizeof (*collection));
797     if(!collection)
798         return E_OUTOFMEMORY;
799
800     collection->lpVtbl = &xmlelem_collection_vtbl;
801     collection->lpvtblIEnumVARIANT = &xmlelem_collection_IEnumVARIANTvtbl;
802     collection->ref = 1;
803     collection->length = 0;
804     collection->node = node;
805     collection->current = node->children;
806     xmlelem_collection_updatelength(collection);
807
808     *ppObj = &collection->lpVtbl;
809
810     TRACE("returning iface %p\n", *ppObj);
811     return S_OK;
812 }
813
814 #endif