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