gdiplus: Add test for GdipGetImageThumbnail.
[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     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 strPropertyName,
242                                            VARIANT *PropertyValue)
243 {
244     xmlelem *This = impl_from_IXMLElement(iface);
245     xmlChar *val = NULL, *name;
246     xmlAttrPtr ptr;
247
248     TRACE("(%p, %s, %p)\n", iface, debugstr_w(strPropertyName), PropertyValue);
249
250     if (!PropertyValue)
251         return E_INVALIDARG;
252
253     VariantInit(PropertyValue);
254     V_BSTR(PropertyValue) = NULL;
255
256     if (!strPropertyName)
257         return E_INVALIDARG;
258
259     name = xmlChar_from_wchar(strPropertyName);
260     ptr = This->node->properties;
261     while (ptr)
262     {
263         if (!lstrcmpiA((LPSTR)name, (LPCSTR)ptr->name))
264         {
265             val = xmlNodeListGetString(ptr->doc, ptr->children, 1);
266             break;
267         }
268
269         ptr = ptr->next;
270     }
271
272     if (val)
273     {
274         V_VT(PropertyValue) = VT_BSTR;
275         V_BSTR(PropertyValue) = bstr_from_xmlChar(val);
276     }
277
278     heap_free(name);
279     xmlFree(val);
280     TRACE("returning %s\n", debugstr_w(V_BSTR(PropertyValue)));
281     return (val) ? S_OK : S_FALSE;
282 }
283
284 static HRESULT WINAPI xmlelem_removeAttribute(IXMLElement *iface, BSTR strPropertyName)
285 {
286     xmlelem *This = impl_from_IXMLElement(iface);
287     xmlChar *name;
288     xmlAttrPtr attr;
289     int res;
290     HRESULT hr = S_FALSE;
291
292     TRACE("(%p, %s)\n", iface, debugstr_w(strPropertyName));
293
294     if (!strPropertyName)
295         return E_INVALIDARG;
296
297     name = xmlChar_from_wchar(strPropertyName);
298     attr = xmlHasProp(This->node, name);
299     if (!attr)
300         goto done;
301
302     res = xmlRemoveProp(attr);
303
304     if (res == 0)
305         hr = S_OK;
306
307 done:
308     heap_free(name);
309     return hr;
310 }
311
312 static HRESULT WINAPI xmlelem_get_children(IXMLElement *iface, IXMLElementCollection **p)
313 {
314     xmlelem *This = impl_from_IXMLElement(iface);
315
316     TRACE("(%p, %p)\n", iface, p);
317
318     if (!p)
319         return E_INVALIDARG;
320
321     return XMLElementCollection_create((IUnknown *)iface, This->node, (LPVOID *)p);
322 }
323
324 static LONG type_libxml_to_msxml(xmlElementType type)
325 {
326     switch (type)
327     {
328         case XML_ELEMENT_NODE:
329             return XMLELEMTYPE_ELEMENT;
330         case XML_TEXT_NODE:
331             return XMLELEMTYPE_TEXT;
332         case XML_COMMENT_NODE:
333             return XMLELEMTYPE_COMMENT;
334         case XML_DOCUMENT_NODE:
335             return XMLELEMTYPE_DOCUMENT;
336         case XML_DTD_NODE:
337             return XMLELEMTYPE_DTD;
338         case XML_PI_NODE:
339             return XMLELEMTYPE_PI;
340         default:
341             break;
342     }
343
344     return XMLELEMTYPE_OTHER;
345 }
346
347 static HRESULT WINAPI xmlelem_get_type(IXMLElement *iface, LONG *p)
348 {
349     xmlelem *This = impl_from_IXMLElement(iface);
350
351     TRACE("(%p, %p)\n", This, p);
352
353     if (!p)
354         return E_INVALIDARG;
355
356     *p = type_libxml_to_msxml(This->node->type);
357     TRACE("returning %d\n", *p);
358     return S_OK;
359 }
360
361 static HRESULT WINAPI xmlelem_get_text(IXMLElement *iface, BSTR *p)
362 {
363     xmlelem *This = impl_from_IXMLElement(iface);
364     xmlChar *content;
365
366     TRACE("(%p, %p)\n", iface, p);
367
368     if (!p)
369         return E_INVALIDARG;
370
371     content = xmlNodeGetContent(This->node);
372     *p = bstr_from_xmlChar(content);
373     TRACE("returning %s\n", debugstr_w(*p));
374
375     xmlFree(content);
376     return S_OK;
377 }
378
379 static HRESULT WINAPI xmlelem_put_text(IXMLElement *iface, BSTR p)
380 {
381     xmlelem *This = impl_from_IXMLElement(iface);
382     xmlChar *content;
383
384     TRACE("(%p, %s)\n", iface, debugstr_w(p));
385
386     /* FIXME: test which types can be used */
387     if (This->node->type == XML_ELEMENT_NODE)
388         return E_NOTIMPL;
389
390     content = xmlChar_from_wchar(p);
391     xmlNodeSetContent(This->node, content);
392
393     heap_free(content);
394
395     return S_OK;
396 }
397
398 static HRESULT WINAPI xmlelem_addChild(IXMLElement *iface, IXMLElement *pChildElem,
399                                        LONG lIndex, LONG lreserved)
400 {
401     xmlelem *This = impl_from_IXMLElement(iface);
402     xmlelem *childElem = impl_from_IXMLElement(pChildElem);
403     xmlNodePtr child;
404
405     TRACE("(%p, %p, %d, %d)\n", iface, pChildElem, lIndex, lreserved);
406
407     if (lIndex == 0)
408         child = xmlAddChild(This->node, childElem->node);
409     else
410         child = xmlAddNextSibling(This->node, childElem->node->last);
411
412     /* parent is responsible for child data */
413     if (child) childElem->own = FALSE;
414
415     return (child) ? S_OK : S_FALSE;
416 }
417
418 static HRESULT WINAPI xmlelem_removeChild(IXMLElement *iface, IXMLElement *pChildElem)
419 {
420     xmlelem *This = impl_from_IXMLElement(iface);
421     xmlelem *childElem = impl_from_IXMLElement(pChildElem);
422
423     TRACE("(%p, %p)\n", This, childElem);
424
425     if (!pChildElem)
426         return E_INVALIDARG;
427
428     /* only supported for This is childElem parent case */
429     if (This->node != childElem->node->parent)
430         return E_INVALIDARG;
431
432     xmlUnlinkNode(childElem->node);
433     /* standalone element now */
434     childElem->own = TRUE;
435
436     return S_OK;
437 }
438
439 static const struct IXMLElementVtbl xmlelem_vtbl =
440 {
441     xmlelem_QueryInterface,
442     xmlelem_AddRef,
443     xmlelem_Release,
444     xmlelem_GetTypeInfoCount,
445     xmlelem_GetTypeInfo,
446     xmlelem_GetIDsOfNames,
447     xmlelem_Invoke,
448     xmlelem_get_tagName,
449     xmlelem_put_tagName,
450     xmlelem_get_parent,
451     xmlelem_setAttribute,
452     xmlelem_getAttribute,
453     xmlelem_removeAttribute,
454     xmlelem_get_children,
455     xmlelem_get_type,
456     xmlelem_get_text,
457     xmlelem_put_text,
458     xmlelem_addChild,
459     xmlelem_removeChild
460 };
461
462 HRESULT XMLElement_create(IUnknown *pUnkOuter, xmlNodePtr node, LPVOID *ppObj, BOOL own)
463 {
464     xmlelem *elem;
465
466     TRACE("(%p,%p)\n", pUnkOuter, ppObj);
467
468     if (!ppObj)
469         return E_INVALIDARG;
470
471     *ppObj = NULL;
472
473     elem = heap_alloc(sizeof (*elem));
474     if(!elem)
475         return E_OUTOFMEMORY;
476
477     elem->lpVtbl = &xmlelem_vtbl;
478     elem->ref = 1;
479     elem->node = node;
480     elem->own  = own;
481
482     *ppObj = &elem->lpVtbl;
483
484     TRACE("returning iface %p\n", *ppObj);
485     return S_OK;
486 }
487
488 /************************************************************************
489  * IXMLElementCollection
490  */
491 typedef struct _xmlelem_collection
492 {
493     const IXMLElementCollectionVtbl *lpVtbl;
494     const IEnumVARIANTVtbl          *lpvtblIEnumVARIANT;
495     LONG ref;
496     LONG length;
497     xmlNodePtr node;
498
499     /* IEnumVARIANT members */
500     xmlNodePtr current;
501 } xmlelem_collection;
502
503 static inline LONG xmlelem_collection_updatelength(xmlelem_collection *collection)
504 {
505     xmlNodePtr ptr = collection->node->children;
506
507     collection->length = 0;
508     while (ptr)
509     {
510         collection->length++;
511         ptr = ptr->next;
512     }
513     return collection->length;
514 }
515
516 static inline xmlelem_collection *impl_from_IXMLElementCollection(IXMLElementCollection *iface)
517 {
518     return (xmlelem_collection *)((char*)iface - FIELD_OFFSET(xmlelem_collection, lpVtbl));
519 }
520
521 static inline xmlelem_collection *impl_from_IEnumVARIANT(IEnumVARIANT *iface)
522 {
523     return (xmlelem_collection *)((char*)iface - FIELD_OFFSET(xmlelem_collection, lpvtblIEnumVARIANT));
524 }
525
526 static HRESULT WINAPI xmlelem_collection_QueryInterface(IXMLElementCollection *iface, REFIID riid, void** ppvObject)
527 {
528     xmlelem_collection *This = impl_from_IXMLElementCollection(iface);
529
530     TRACE("%p %s %p\n", This, debugstr_guid(riid), ppvObject);
531
532     if (IsEqualGUID(riid, &IID_IUnknown) ||
533         IsEqualGUID(riid, &IID_IXMLElementCollection))
534     {
535         *ppvObject = iface;
536     }
537     else if (IsEqualGUID(riid, &IID_IEnumVARIANT))
538     {
539         *ppvObject = &(This->lpvtblIEnumVARIANT);
540     }
541     else
542     {
543         FIXME("interface %s not implemented\n", debugstr_guid(riid));
544         return E_NOINTERFACE;
545     }
546
547     IXMLElementCollection_AddRef(iface);
548
549     return S_OK;
550 }
551
552 static ULONG WINAPI xmlelem_collection_AddRef(IXMLElementCollection *iface)
553 {
554     xmlelem_collection *This = impl_from_IXMLElementCollection(iface);
555     TRACE("%p\n", This);
556     return InterlockedIncrement(&This->ref);
557 }
558
559 static ULONG WINAPI xmlelem_collection_Release(IXMLElementCollection *iface)
560 {
561     xmlelem_collection *This = impl_from_IXMLElementCollection(iface);
562     LONG ref;
563
564     TRACE("%p\n", This);
565
566     ref = InterlockedDecrement(&This->ref);
567     if (ref == 0)
568     {
569         heap_free(This);
570     }
571
572     return ref;
573 }
574
575 static HRESULT WINAPI xmlelem_collection_GetTypeInfoCount(IXMLElementCollection *iface, UINT* pctinfo)
576 {
577     FIXME("\n");
578     return E_NOTIMPL;
579 }
580
581 static HRESULT WINAPI xmlelem_collection_GetTypeInfo(IXMLElementCollection *iface, UINT iTInfo,
582                                                      LCID lcid, ITypeInfo** ppTInfo)
583 {
584     FIXME("\n");
585     return E_NOTIMPL;
586 }
587
588 static HRESULT WINAPI xmlelem_collection_GetIDsOfNames(IXMLElementCollection *iface, REFIID riid,
589                                                        LPOLESTR* rgszNames, UINT cNames,
590                                                        LCID lcid, DISPID* rgDispId)
591 {
592     FIXME("\n");
593     return E_NOTIMPL;
594 }
595
596 static HRESULT WINAPI xmlelem_collection_Invoke(IXMLElementCollection *iface, DISPID dispIdMember,
597                                                 REFIID riid, LCID lcid, WORD wFlags,
598                                                 DISPPARAMS* pDispParams, VARIANT* pVarResult,
599                                                 EXCEPINFO* pExcepInfo, UINT* puArgErr)
600 {
601     FIXME("\n");
602     return E_NOTIMPL;
603 }
604
605 static HRESULT WINAPI xmlelem_collection_put_length(IXMLElementCollection *iface, LONG v)
606 {
607     TRACE("(%p, %d)\n", iface, v);
608     return E_FAIL;
609 }
610
611 static HRESULT WINAPI xmlelem_collection_get_length(IXMLElementCollection *iface, LONG *p)
612 {
613     xmlelem_collection *This = impl_from_IXMLElementCollection(iface);
614
615     TRACE("(%p, %p)\n", iface, p);
616
617     if (!p)
618         return E_INVALIDARG;
619
620     *p = xmlelem_collection_updatelength(This);
621     return S_OK;
622 }
623
624 static HRESULT WINAPI xmlelem_collection_get__newEnum(IXMLElementCollection *iface, IUnknown **ppUnk)
625 {
626     xmlelem_collection *This = impl_from_IXMLElementCollection(iface);
627
628     TRACE("(%p, %p)\n", iface, ppUnk);
629
630     if (!ppUnk)
631         return E_INVALIDARG;
632
633     *ppUnk = (IUnknown *)This;
634     IUnknown_AddRef(*ppUnk);
635     return S_OK;
636 }
637
638 static HRESULT WINAPI xmlelem_collection_item(IXMLElementCollection *iface, VARIANT var1,
639                                               VARIANT var2, IDispatch **ppDisp)
640 {
641     xmlelem_collection *This = impl_from_IXMLElementCollection(iface);
642     xmlNodePtr ptr = This->node->children;
643     int index, i;
644
645     TRACE("(%p, %p)\n", iface, ppDisp);
646
647     if (!ppDisp)
648         return E_INVALIDARG;
649
650     *ppDisp = NULL;
651
652     index = V_I4(&var1);
653     if (index < 0)
654         return E_INVALIDARG;
655
656     xmlelem_collection_updatelength(This);
657     if (index >= This->length)
658         return E_FAIL;
659
660     for (i = 0; i < index; i++)
661         ptr = ptr->next;
662
663     return XMLElement_create((IUnknown *)iface, ptr, (LPVOID *)ppDisp, FALSE);
664 }
665
666 static const struct IXMLElementCollectionVtbl xmlelem_collection_vtbl =
667 {
668     xmlelem_collection_QueryInterface,
669     xmlelem_collection_AddRef,
670     xmlelem_collection_Release,
671     xmlelem_collection_GetTypeInfoCount,
672     xmlelem_collection_GetTypeInfo,
673     xmlelem_collection_GetIDsOfNames,
674     xmlelem_collection_Invoke,
675     xmlelem_collection_put_length,
676     xmlelem_collection_get_length,
677     xmlelem_collection_get__newEnum,
678     xmlelem_collection_item
679 };
680
681 /************************************************************************
682  * xmlelem_collection implementation of IEnumVARIANT.
683  */
684 static HRESULT WINAPI xmlelem_collection_IEnumVARIANT_QueryInterface(
685     IEnumVARIANT *iface, REFIID riid, LPVOID *ppvObj)
686 {
687     xmlelem_collection *this = impl_from_IEnumVARIANT(iface);
688     return IXMLDocument_QueryInterface((IXMLDocument *)this, riid, ppvObj);
689 }
690
691 static ULONG WINAPI xmlelem_collection_IEnumVARIANT_AddRef(
692     IEnumVARIANT *iface)
693 {
694     xmlelem_collection *this = impl_from_IEnumVARIANT(iface);
695     return IXMLDocument_AddRef((IXMLDocument *)this);
696 }
697
698 static ULONG WINAPI xmlelem_collection_IEnumVARIANT_Release(
699     IEnumVARIANT *iface)
700 {
701     xmlelem_collection *this = impl_from_IEnumVARIANT(iface);
702     return IXMLDocument_Release((IXMLDocument *)this);
703 }
704
705 static HRESULT WINAPI xmlelem_collection_IEnumVARIANT_Next(
706     IEnumVARIANT *iface, ULONG celt, VARIANT *rgVar, ULONG *pCeltFetched)
707 {
708     xmlelem_collection *This = impl_from_IEnumVARIANT(iface);
709     xmlNodePtr ptr = This->current;
710
711     TRACE("(%p, %d, %p, %p)\n", iface, celt, rgVar, pCeltFetched);
712
713     if (!rgVar)
714         return E_INVALIDARG;
715
716     /* FIXME: handle celt */
717     if (pCeltFetched)
718         *pCeltFetched = 1;
719
720     This->current = This->current->next;
721
722     V_VT(rgVar) = VT_DISPATCH;
723     return XMLElement_create((IUnknown *)iface, ptr, (LPVOID *)&V_DISPATCH(rgVar), FALSE);
724 }
725
726 static HRESULT WINAPI xmlelem_collection_IEnumVARIANT_Skip(
727     IEnumVARIANT *iface, ULONG celt)
728 {
729     FIXME("(%p, %d): stub\n", iface, celt);
730     return E_NOTIMPL;
731 }
732
733 static HRESULT WINAPI xmlelem_collection_IEnumVARIANT_Reset(
734     IEnumVARIANT *iface)
735 {
736     xmlelem_collection *This = impl_from_IEnumVARIANT(iface);
737     This->current = This->node->children;
738     return S_OK;
739 }
740
741 static HRESULT WINAPI xmlelem_collection_IEnumVARIANT_Clone(
742     IEnumVARIANT *iface, IEnumVARIANT **ppEnum)
743 {
744     FIXME("(%p, %p): stub\n", iface, ppEnum);
745     return E_NOTIMPL;
746 }
747
748 static const struct IEnumVARIANTVtbl xmlelem_collection_IEnumVARIANTvtbl =
749 {
750     xmlelem_collection_IEnumVARIANT_QueryInterface,
751     xmlelem_collection_IEnumVARIANT_AddRef,
752     xmlelem_collection_IEnumVARIANT_Release,
753     xmlelem_collection_IEnumVARIANT_Next,
754     xmlelem_collection_IEnumVARIANT_Skip,
755     xmlelem_collection_IEnumVARIANT_Reset,
756     xmlelem_collection_IEnumVARIANT_Clone
757 };
758
759 static HRESULT XMLElementCollection_create(IUnknown *pUnkOuter, xmlNodePtr node, LPVOID *ppObj)
760 {
761     xmlelem_collection *collection;
762
763     TRACE("(%p,%p)\n", pUnkOuter, ppObj);
764
765     *ppObj = NULL;
766
767     if (!node->children)
768         return S_FALSE;
769
770     collection = heap_alloc(sizeof (*collection));
771     if(!collection)
772         return E_OUTOFMEMORY;
773
774     collection->lpVtbl = &xmlelem_collection_vtbl;
775     collection->lpvtblIEnumVARIANT = &xmlelem_collection_IEnumVARIANTvtbl;
776     collection->ref = 1;
777     collection->length = 0;
778     collection->node = node;
779     collection->current = node->children;
780     xmlelem_collection_updatelength(collection);
781
782     *ppObj = &collection->lpVtbl;
783
784     TRACE("returning iface %p\n", *ppObj);
785     return S_OK;
786 }
787
788 #endif