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