push 378fe7a60681a28e8b22f62dcfe122d585b92570
[wine/hacks.git] / dlls / msxml3 / xmlelem.c
blob97e342961b9cf790539bdfc7dcd9110e321e4655
1 /*
2 * XML Element implementation
4 * Copyright 2007 James Hawkins
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.
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.
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
21 #define COBJMACROS
23 #include "config.h"
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"
33 #include "wine/debug.h"
35 #include "msxml_private.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
39 #ifdef HAVE_LIBXML2
41 static HRESULT XMLElementCollection_create( IUnknown *pUnkOuter, xmlNodePtr node, LPVOID *ppObj );
43 /**********************************************************************
44 * IXMLElement
46 typedef struct _xmlelem
48 const IXMLElementVtbl *lpVtbl;
49 LONG ref;
50 xmlNodePtr node;
51 } xmlelem;
53 static inline xmlelem *impl_from_IXMLElement(IXMLElement *iface)
55 return (xmlelem *)((char*)iface - FIELD_OFFSET(xmlelem, lpVtbl));
58 static HRESULT WINAPI xmlelem_QueryInterface(IXMLElement *iface, REFIID riid, void** ppvObject)
60 xmlelem *This = impl_from_IXMLElement(iface);
62 TRACE("%p %s %p\n", This, debugstr_guid(riid), ppvObject);
64 if (IsEqualGUID(riid, &IID_IUnknown) ||
65 IsEqualGUID(riid, &IID_IXMLElement))
67 *ppvObject = iface;
69 else
71 FIXME("interface %s not implemented\n", debugstr_guid(riid));
72 return E_NOINTERFACE;
75 IXMLElement_AddRef(iface);
77 return S_OK;
80 static ULONG WINAPI xmlelem_AddRef(IXMLElement *iface)
82 xmlelem *This = impl_from_IXMLElement(iface);
83 TRACE("%p\n", This);
84 return InterlockedIncrement(&This->ref);
87 static ULONG WINAPI xmlelem_Release(IXMLElement *iface)
89 xmlelem *This = impl_from_IXMLElement(iface);
90 LONG ref;
92 TRACE("%p\n", This);
94 ref = InterlockedDecrement(&This->ref);
95 if (ref == 0)
97 HeapFree(GetProcessHeap(), 0, This);
100 return ref;
103 static HRESULT WINAPI xmlelem_GetTypeInfoCount(IXMLElement *iface, UINT* pctinfo)
105 xmlelem *This = impl_from_IXMLElement(iface);
107 TRACE("(%p)->(%p)\n", This, pctinfo);
109 *pctinfo = 1;
111 return S_OK;
114 static HRESULT WINAPI xmlelem_GetTypeInfo(IXMLElement *iface, UINT iTInfo,
115 LCID lcid, ITypeInfo** ppTInfo)
117 xmlelem *This = impl_from_IXMLElement(iface);
118 HRESULT hr;
120 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
122 hr = get_typeinfo(IXMLElement_tid, ppTInfo);
124 return hr;
127 static HRESULT WINAPI xmlelem_GetIDsOfNames(IXMLElement *iface, REFIID riid,
128 LPOLESTR* rgszNames, UINT cNames,
129 LCID lcid, DISPID* rgDispId)
131 xmlelem *This = impl_from_IXMLElement(iface);
132 ITypeInfo *typeinfo;
133 HRESULT hr;
135 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
136 lcid, rgDispId);
138 if(!rgszNames || cNames == 0 || !rgDispId)
139 return E_INVALIDARG;
141 hr = get_typeinfo(IXMLElement_tid, &typeinfo);
142 if(SUCCEEDED(hr))
144 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
145 ITypeInfo_Release(typeinfo);
148 return hr;
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)
156 xmlelem *This = impl_from_IXMLElement(iface);
157 ITypeInfo *typeinfo;
158 HRESULT hr;
160 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
161 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
163 hr = get_typeinfo(IXMLElement_tid, &typeinfo);
164 if(SUCCEEDED(hr))
166 hr = ITypeInfo_Invoke(typeinfo, &(This->lpVtbl), dispIdMember, wFlags, pDispParams,
167 pVarResult, pExcepInfo, puArgErr);
168 ITypeInfo_Release(typeinfo);
171 return hr;
174 static inline BSTR str_dup_upper(BSTR str)
176 INT len = (lstrlenW(str) + 1) * sizeof(WCHAR);
177 BSTR p = SysAllocStringLen(NULL, len);
178 if (p)
180 memcpy(p, str, len);
181 CharUpperW(p);
183 return p;
186 static HRESULT WINAPI xmlelem_get_tagName(IXMLElement *iface, BSTR *p)
188 xmlelem *This = impl_from_IXMLElement(iface);
189 BSTR temp;
191 TRACE("(%p, %p)\n", iface, p);
193 if (!p)
194 return E_INVALIDARG;
196 temp = bstr_from_xmlChar(This->node->name);
197 *p = str_dup_upper(temp);
198 SysFreeString(temp);
200 TRACE("returning %s\n", debugstr_w(*p));
202 return S_OK;
205 static HRESULT WINAPI xmlelem_put_tagName(IXMLElement *iface, BSTR p)
207 FIXME("(%p, %p): stub\n", iface, p);
209 if (!p)
210 return E_INVALIDARG;
212 return E_NOTIMPL;
215 static HRESULT WINAPI xmlelem_get_parent(IXMLElement *iface, IXMLElement **parent)
217 xmlelem *This = impl_from_IXMLElement(iface);
219 TRACE("(%p, %p)\n", iface, parent);
221 if (!parent)
222 return E_INVALIDARG;
224 *parent = NULL;
226 if (!This->node->parent)
227 return S_FALSE;
229 return XMLElement_create((IUnknown *)iface, This->node->parent, (LPVOID *)parent);
232 static HRESULT WINAPI xmlelem_setAttribute(IXMLElement *iface, BSTR strPropertyName,
233 VARIANT PropertyValue)
235 xmlelem *This = impl_from_IXMLElement(iface);
236 xmlChar *name, *value;
237 xmlAttrPtr attr;
239 TRACE("(%p, %s)\n", iface, debugstr_w(strPropertyName));
241 if (!strPropertyName || V_VT(&PropertyValue) != VT_BSTR)
242 return E_INVALIDARG;
244 name = xmlChar_from_wchar(strPropertyName);
245 value = xmlChar_from_wchar(V_BSTR(&PropertyValue));
246 attr = xmlSetProp(This->node, name, value);
248 HeapFree(GetProcessHeap(), 0, name);
249 HeapFree(GetProcessHeap(), 0, value);
250 return (attr) ? S_OK : S_FALSE;
253 static HRESULT WINAPI xmlelem_getAttribute(IXMLElement *iface, BSTR strPropertyName,
254 VARIANT *PropertyValue)
256 xmlelem *This = impl_from_IXMLElement(iface);
257 xmlChar *val = NULL, *name;
258 xmlAttrPtr ptr;
260 TRACE("(%p, %s, %p)\n", iface, debugstr_w(strPropertyName), PropertyValue);
262 if (!PropertyValue)
263 return E_INVALIDARG;
265 VariantInit(PropertyValue);
266 V_BSTR(PropertyValue) = NULL;
268 if (!strPropertyName)
269 return E_INVALIDARG;
271 name = xmlChar_from_wchar(strPropertyName);
272 ptr = This->node->properties;
273 while (ptr)
275 if (!lstrcmpiA((LPSTR)name, (LPCSTR)ptr->name))
277 val = xmlNodeListGetString(ptr->doc, ptr->children, 1);
278 break;
281 ptr = ptr->next;
284 if (val)
286 V_VT(PropertyValue) = VT_BSTR;
287 V_BSTR(PropertyValue) = bstr_from_xmlChar(val);
290 HeapFree(GetProcessHeap(), 0, name);
291 xmlFree(val);
292 TRACE("returning %s\n", debugstr_w(V_BSTR(PropertyValue)));
293 return (val) ? S_OK : S_FALSE;
296 static HRESULT WINAPI xmlelem_removeAttribute(IXMLElement *iface, BSTR strPropertyName)
298 xmlelem *This = impl_from_IXMLElement(iface);
299 xmlChar *name;
300 xmlAttrPtr attr;
301 int res;
302 HRESULT hr = S_FALSE;
304 TRACE("(%p, %s)\n", iface, debugstr_w(strPropertyName));
306 if (!strPropertyName)
307 return E_INVALIDARG;
309 name = xmlChar_from_wchar(strPropertyName);
310 attr = xmlHasProp(This->node, name);
311 if (!attr)
312 goto done;
314 res = xmlRemoveProp(attr);
316 if (res == 0)
317 hr = S_OK;
319 done:
320 HeapFree(GetProcessHeap(), 0, name);
321 return hr;
324 static HRESULT WINAPI xmlelem_get_children(IXMLElement *iface, IXMLElementCollection **p)
326 xmlelem *This = impl_from_IXMLElement(iface);
328 TRACE("(%p, %p)\n", iface, p);
330 if (!p)
331 return E_INVALIDARG;
333 return XMLElementCollection_create((IUnknown *)iface, This->node->children, (LPVOID *)p);
336 static long type_libxml_to_msxml(xmlElementType type)
338 switch (type)
340 case XML_ELEMENT_NODE:
341 return XMLELEMTYPE_ELEMENT;
342 case XML_TEXT_NODE:
343 return XMLELEMTYPE_TEXT;
344 case XML_COMMENT_NODE:
345 return XMLELEMTYPE_COMMENT;
346 case XML_DOCUMENT_NODE:
347 return XMLELEMTYPE_DOCUMENT;
348 case XML_DTD_NODE:
349 return XMLELEMTYPE_DTD;
350 case XML_PI_NODE:
351 return XMLELEMTYPE_PI;
352 default:
353 break;
356 return XMLELEMTYPE_OTHER;
359 static HRESULT WINAPI xmlelem_get_type(IXMLElement *iface, long *p)
361 xmlelem *This = impl_from_IXMLElement(iface);
363 TRACE("(%p, %p)\n", This, p);
365 if (!p)
366 return E_INVALIDARG;
368 *p = type_libxml_to_msxml(This->node->type);
369 TRACE("returning %ld\n", *p);
370 return S_OK;
373 static HRESULT WINAPI xmlelem_get_text(IXMLElement *iface, BSTR *p)
375 xmlelem *This = impl_from_IXMLElement(iface);
376 xmlChar *content;
378 TRACE("(%p, %p)\n", iface, p);
380 if (!p)
381 return E_INVALIDARG;
383 content = xmlNodeGetContent(This->node);
384 *p = bstr_from_xmlChar(content);
385 TRACE("returning %s\n", debugstr_w(*p));
387 xmlFree(content);
388 return S_OK;
391 static HRESULT WINAPI xmlelem_put_text(IXMLElement *iface, BSTR p)
393 xmlelem *This = impl_from_IXMLElement(iface);
394 xmlChar *content;
396 TRACE("(%p, %s)\n", iface, debugstr_w(p));
398 /* FIXME: test which types can be used */
399 if (This->node->type == XML_ELEMENT_NODE)
400 return E_NOTIMPL;
402 content = xmlChar_from_wchar(p);
403 xmlNodeSetContent(This->node, content);
405 HeapFree( GetProcessHeap(), 0, content);
407 return S_OK;
410 static HRESULT WINAPI xmlelem_addChild(IXMLElement *iface, IXMLElement *pChildElem,
411 long lIndex, long lreserved)
413 xmlelem *This = impl_from_IXMLElement(iface);
414 xmlelem *childElem = impl_from_IXMLElement(pChildElem);
415 xmlNodePtr child;
417 TRACE("(%p, %p, %ld, %ld)\n", iface, pChildElem, lIndex, lreserved);
419 if (lIndex == 0)
420 child = xmlAddChild(This->node, childElem->node);
421 else
422 child = xmlAddNextSibling(This->node, childElem->node->last);
424 return (child) ? S_OK : S_FALSE;
427 static HRESULT WINAPI xmlelem_removeChild(IXMLElement *iface, IXMLElement *pChildElem)
429 FIXME("(%p, %p): stub\n", iface, pChildElem);
430 return E_NOTIMPL;
433 static const struct IXMLElementVtbl xmlelem_vtbl =
435 xmlelem_QueryInterface,
436 xmlelem_AddRef,
437 xmlelem_Release,
438 xmlelem_GetTypeInfoCount,
439 xmlelem_GetTypeInfo,
440 xmlelem_GetIDsOfNames,
441 xmlelem_Invoke,
442 xmlelem_get_tagName,
443 xmlelem_put_tagName,
444 xmlelem_get_parent,
445 xmlelem_setAttribute,
446 xmlelem_getAttribute,
447 xmlelem_removeAttribute,
448 xmlelem_get_children,
449 xmlelem_get_type,
450 xmlelem_get_text,
451 xmlelem_put_text,
452 xmlelem_addChild,
453 xmlelem_removeChild
456 HRESULT XMLElement_create(IUnknown *pUnkOuter, xmlNodePtr node, LPVOID *ppObj)
458 xmlelem *elem;
460 TRACE("(%p,%p)\n", pUnkOuter, ppObj);
462 if (!ppObj)
463 return E_INVALIDARG;
465 *ppObj = NULL;
467 elem = HeapAlloc(GetProcessHeap(), 0, sizeof (*elem));
468 if(!elem)
469 return E_OUTOFMEMORY;
471 elem->lpVtbl = &xmlelem_vtbl;
472 elem->ref = 1;
473 elem->node = node;
475 *ppObj = &elem->lpVtbl;
477 TRACE("returning iface %p\n", *ppObj);
478 return S_OK;
481 /************************************************************************
482 * IXMLElementCollection
484 typedef struct _xmlelem_collection
486 const IXMLElementCollectionVtbl *lpVtbl;
487 const IEnumVARIANTVtbl *lpvtblIEnumVARIANT;
488 LONG ref;
489 LONG length;
490 xmlNodePtr node;
492 /* IEnumVARIANT members */
493 xmlNodePtr current;
494 } xmlelem_collection;
496 static inline xmlelem_collection *impl_from_IXMLElementCollection(IXMLElementCollection *iface)
498 return (xmlelem_collection *)((char*)iface - FIELD_OFFSET(xmlelem_collection, lpVtbl));
501 static inline xmlelem_collection *impl_from_IEnumVARIANT(IEnumVARIANT *iface)
503 return (xmlelem_collection *)((char*)iface - FIELD_OFFSET(xmlelem_collection, lpvtblIEnumVARIANT));
506 static HRESULT WINAPI xmlelem_collection_QueryInterface(IXMLElementCollection *iface, REFIID riid, void** ppvObject)
508 xmlelem_collection *This = impl_from_IXMLElementCollection(iface);
510 TRACE("%p %s %p\n", This, debugstr_guid(riid), ppvObject);
512 if (IsEqualGUID(riid, &IID_IUnknown) ||
513 IsEqualGUID(riid, &IID_IXMLElementCollection))
515 *ppvObject = iface;
517 else if (IsEqualGUID(riid, &IID_IEnumVARIANT))
519 *ppvObject = &(This->lpvtblIEnumVARIANT);
521 else
523 FIXME("interface %s not implemented\n", debugstr_guid(riid));
524 return E_NOINTERFACE;
527 IXMLElementCollection_AddRef(iface);
529 return S_OK;
532 static ULONG WINAPI xmlelem_collection_AddRef(IXMLElementCollection *iface)
534 xmlelem_collection *This = impl_from_IXMLElementCollection(iface);
535 TRACE("%p\n", This);
536 return InterlockedIncrement(&This->ref);
539 static ULONG WINAPI xmlelem_collection_Release(IXMLElementCollection *iface)
541 xmlelem_collection *This = impl_from_IXMLElementCollection(iface);
542 LONG ref;
544 TRACE("%p\n", This);
546 ref = InterlockedDecrement(&This->ref);
547 if (ref == 0)
549 HeapFree(GetProcessHeap(), 0, This);
552 return ref;
555 static HRESULT WINAPI xmlelem_collection_GetTypeInfoCount(IXMLElementCollection *iface, UINT* pctinfo)
557 FIXME("\n");
558 return E_NOTIMPL;
561 static HRESULT WINAPI xmlelem_collection_GetTypeInfo(IXMLElementCollection *iface, UINT iTInfo,
562 LCID lcid, ITypeInfo** ppTInfo)
564 FIXME("\n");
565 return E_NOTIMPL;
568 static HRESULT WINAPI xmlelem_collection_GetIDsOfNames(IXMLElementCollection *iface, REFIID riid,
569 LPOLESTR* rgszNames, UINT cNames,
570 LCID lcid, DISPID* rgDispId)
572 FIXME("\n");
573 return E_NOTIMPL;
576 static HRESULT WINAPI xmlelem_collection_Invoke(IXMLElementCollection *iface, DISPID dispIdMember,
577 REFIID riid, LCID lcid, WORD wFlags,
578 DISPPARAMS* pDispParams, VARIANT* pVarResult,
579 EXCEPINFO* pExcepInfo, UINT* puArgErr)
581 FIXME("\n");
582 return E_NOTIMPL;
585 static HRESULT WINAPI xmlelem_collection_put_length(IXMLElementCollection *iface, long v)
587 TRACE("(%p, %ld)\n", iface, v);
588 return E_FAIL;
591 static HRESULT WINAPI xmlelem_collection_get_length(IXMLElementCollection *iface, long *p)
593 xmlelem_collection *This = impl_from_IXMLElementCollection(iface);
595 TRACE("(%p, %p)\n", iface, p);
597 if (!p)
598 return E_INVALIDARG;
600 *p = This->length;
601 return S_OK;
604 static HRESULT WINAPI xmlelem_collection_get__newEnum(IXMLElementCollection *iface, IUnknown **ppUnk)
606 xmlelem_collection *This = impl_from_IXMLElementCollection(iface);
608 TRACE("(%p, %p)\n", iface, ppUnk);
610 if (!ppUnk)
611 return E_INVALIDARG;
613 *ppUnk = (IUnknown *)This;
614 IUnknown_AddRef(*ppUnk);
615 return S_OK;
618 static HRESULT WINAPI xmlelem_collection_item(IXMLElementCollection *iface, VARIANT var1,
619 VARIANT var2, IDispatch **ppDisp)
621 xmlelem_collection *This = impl_from_IXMLElementCollection(iface);
622 xmlNodePtr ptr = This->node;
623 int index, i;
625 TRACE("(%p, %p)\n", iface, ppDisp);
627 if (!ppDisp)
628 return E_INVALIDARG;
630 *ppDisp = NULL;
632 index = V_I4(&var1);
633 if (index < 0)
634 return E_INVALIDARG;
635 if (index >= This->length)
636 return E_FAIL;
638 for (i = 0; i < index; i++)
639 ptr = ptr->next;
641 return XMLElement_create((IUnknown *)iface, ptr, (LPVOID *)ppDisp);
644 static const struct IXMLElementCollectionVtbl xmlelem_collection_vtbl =
646 xmlelem_collection_QueryInterface,
647 xmlelem_collection_AddRef,
648 xmlelem_collection_Release,
649 xmlelem_collection_GetTypeInfoCount,
650 xmlelem_collection_GetTypeInfo,
651 xmlelem_collection_GetIDsOfNames,
652 xmlelem_collection_Invoke,
653 xmlelem_collection_put_length,
654 xmlelem_collection_get_length,
655 xmlelem_collection_get__newEnum,
656 xmlelem_collection_item
659 /************************************************************************
660 * xmlelem_collection implementation of IEnumVARIANT.
662 static HRESULT WINAPI xmlelem_collection_IEnumVARIANT_QueryInterface(
663 IEnumVARIANT *iface, REFIID riid, LPVOID *ppvObj)
665 xmlelem_collection *this = impl_from_IEnumVARIANT(iface);
666 return IXMLDocument_QueryInterface((IXMLDocument *)this, riid, ppvObj);
669 static ULONG WINAPI xmlelem_collection_IEnumVARIANT_AddRef(
670 IEnumVARIANT *iface)
672 xmlelem_collection *this = impl_from_IEnumVARIANT(iface);
673 return IXMLDocument_AddRef((IXMLDocument *)this);
676 static ULONG WINAPI xmlelem_collection_IEnumVARIANT_Release(
677 IEnumVARIANT *iface)
679 xmlelem_collection *this = impl_from_IEnumVARIANT(iface);
680 return IXMLDocument_Release((IXMLDocument *)this);
683 static HRESULT WINAPI xmlelem_collection_IEnumVARIANT_Next(
684 IEnumVARIANT *iface, ULONG celt, VARIANT *rgVar, ULONG *pCeltFetched)
686 xmlelem_collection *This = impl_from_IEnumVARIANT(iface);
687 xmlNodePtr ptr = This->current;
689 TRACE("(%p, %d, %p, %p)\n", iface, celt, rgVar, pCeltFetched);
691 if (!rgVar)
692 return E_INVALIDARG;
694 /* FIXME: handle celt */
695 if (pCeltFetched)
696 *pCeltFetched = 1;
698 This->current = This->current->next;
700 V_VT(rgVar) = VT_DISPATCH;
701 return XMLElement_create((IUnknown *)iface, ptr, (LPVOID *)&V_DISPATCH(rgVar));
704 static HRESULT WINAPI xmlelem_collection_IEnumVARIANT_Skip(
705 IEnumVARIANT *iface, ULONG celt)
707 FIXME("(%p, %d): stub\n", iface, celt);
708 return E_NOTIMPL;
711 static HRESULT WINAPI xmlelem_collection_IEnumVARIANT_Reset(
712 IEnumVARIANT *iface)
714 xmlelem_collection *This = impl_from_IEnumVARIANT(iface);
715 This->current = This->node;
716 return S_OK;
719 static HRESULT WINAPI xmlelem_collection_IEnumVARIANT_Clone(
720 IEnumVARIANT *iface, IEnumVARIANT **ppEnum)
722 FIXME("(%p, %p): stub\n", iface, ppEnum);
723 return E_NOTIMPL;
726 static const struct IEnumVARIANTVtbl xmlelem_collection_IEnumVARIANTvtbl =
728 xmlelem_collection_IEnumVARIANT_QueryInterface,
729 xmlelem_collection_IEnumVARIANT_AddRef,
730 xmlelem_collection_IEnumVARIANT_Release,
731 xmlelem_collection_IEnumVARIANT_Next,
732 xmlelem_collection_IEnumVARIANT_Skip,
733 xmlelem_collection_IEnumVARIANT_Reset,
734 xmlelem_collection_IEnumVARIANT_Clone
737 static HRESULT XMLElementCollection_create(IUnknown *pUnkOuter, xmlNodePtr node, LPVOID *ppObj)
739 xmlelem_collection *collection;
740 xmlNodePtr ptr;
742 TRACE("(%p,%p)\n", pUnkOuter, ppObj);
744 *ppObj = NULL;
746 if (!node)
747 return S_FALSE;
749 collection = HeapAlloc(GetProcessHeap(), 0, sizeof (*collection));
750 if(!collection)
751 return E_OUTOFMEMORY;
753 collection->lpVtbl = &xmlelem_collection_vtbl;
754 collection->lpvtblIEnumVARIANT = &xmlelem_collection_IEnumVARIANTvtbl;
755 collection->ref = 1;
756 collection->length = 0;
757 collection->node = node;
758 collection->current = node;
760 ptr = node;
761 while (ptr)
763 collection->length++;
764 ptr = ptr->next;
767 *ppObj = &collection->lpVtbl;
769 TRACE("returning iface %p\n", *ppObj);
770 return S_OK;
773 #endif