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