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