appwiz.cpl: Fix compilation on systems that don't support nameless unions.
[wine.git] / dlls / msxml3 / xmlelem.c
blob8166e6ac5bb170ddb515136b1d33b4cf46182f88
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 /**********************************************************************
42 * IXMLElement
44 typedef struct _xmlelem
46 const IXMLElementVtbl *lpVtbl;
47 LONG ref;
48 xmlNodePtr node;
49 } xmlelem;
51 static inline xmlelem *impl_from_IXMLElement(IXMLElement *iface)
53 return (xmlelem *)((char*)iface - FIELD_OFFSET(xmlelem, lpVtbl));
56 static HRESULT WINAPI xmlelem_QueryInterface(IXMLElement *iface, REFIID riid, void** ppvObject)
58 xmlelem *This = impl_from_IXMLElement(iface);
60 TRACE("%p %s %p\n", This, debugstr_guid(riid), ppvObject);
62 if (IsEqualGUID(riid, &IID_IUnknown) ||
63 IsEqualGUID(riid, &IID_IXMLElement))
65 *ppvObject = iface;
67 else
69 FIXME("interface %s not implemented\n", debugstr_guid(riid));
70 return E_NOINTERFACE;
73 IXMLElement_AddRef(iface);
75 return S_OK;
78 static ULONG WINAPI xmlelem_AddRef(IXMLElement *iface)
80 xmlelem *This = impl_from_IXMLElement(iface);
81 TRACE("%p\n", This);
82 return InterlockedIncrement(&This->ref);
85 static ULONG WINAPI xmlelem_Release(IXMLElement *iface)
87 xmlelem *This = impl_from_IXMLElement(iface);
88 LONG ref;
90 TRACE("%p\n", This);
92 ref = InterlockedDecrement(&This->ref);
93 if (ref == 0)
95 HeapFree(GetProcessHeap(), 0, This);
98 return ref;
101 static HRESULT WINAPI xmlelem_GetTypeInfoCount(IXMLElement *iface, UINT* pctinfo)
103 xmlelem *This = impl_from_IXMLElement(iface);
105 TRACE("(%p)->(%p)\n", This, pctinfo);
107 *pctinfo = 1;
109 return S_OK;
112 static HRESULT WINAPI xmlelem_GetTypeInfo(IXMLElement *iface, UINT iTInfo,
113 LCID lcid, ITypeInfo** ppTInfo)
115 xmlelem *This = impl_from_IXMLElement(iface);
116 HRESULT hr;
118 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
120 hr = get_typeinfo(IXMLElement_tid, ppTInfo);
122 return hr;
125 static HRESULT WINAPI xmlelem_GetIDsOfNames(IXMLElement *iface, REFIID riid,
126 LPOLESTR* rgszNames, UINT cNames,
127 LCID lcid, DISPID* rgDispId)
129 xmlelem *This = impl_from_IXMLElement(iface);
130 ITypeInfo *typeinfo;
131 HRESULT hr;
133 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
134 lcid, rgDispId);
136 if(!rgszNames || cNames == 0 || !rgDispId)
137 return E_INVALIDARG;
139 hr = get_typeinfo(IXMLElement_tid, &typeinfo);
140 if(SUCCEEDED(hr))
142 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
143 ITypeInfo_Release(typeinfo);
146 return hr;
149 static HRESULT WINAPI xmlelem_Invoke(IXMLElement *iface, DISPID dispIdMember,
150 REFIID riid, LCID lcid, WORD wFlags,
151 DISPPARAMS* pDispParams, VARIANT* pVarResult,
152 EXCEPINFO* pExcepInfo, UINT* puArgErr)
154 xmlelem *This = impl_from_IXMLElement(iface);
155 ITypeInfo *typeinfo;
156 HRESULT hr;
158 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
159 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
161 hr = get_typeinfo(IXMLElement_tid, &typeinfo);
162 if(SUCCEEDED(hr))
164 hr = ITypeInfo_Invoke(typeinfo, &(This->lpVtbl), dispIdMember, wFlags, pDispParams,
165 pVarResult, pExcepInfo, puArgErr);
166 ITypeInfo_Release(typeinfo);
169 return hr;
172 static inline BSTR str_dup_upper(BSTR str)
174 INT len = (lstrlenW(str) + 1) * sizeof(WCHAR);
175 BSTR p = SysAllocStringLen(NULL, len);
176 if (p)
178 memcpy(p, str, len);
179 CharUpperW(p);
181 return p;
184 static HRESULT WINAPI xmlelem_get_tagName(IXMLElement *iface, BSTR *p)
186 xmlelem *This = impl_from_IXMLElement(iface);
187 BSTR temp;
189 TRACE("(%p, %p)\n", iface, p);
191 if (!p)
192 return E_INVALIDARG;
194 temp = bstr_from_xmlChar(This->node->name);
195 *p = str_dup_upper(temp);
196 SysFreeString(temp);
198 TRACE("returning %s\n", debugstr_w(*p));
200 return S_OK;
203 static HRESULT WINAPI xmlelem_put_tagName(IXMLElement *iface, BSTR p)
205 FIXME("(%p, %p): stub\n", iface, p);
207 if (!p)
208 return E_INVALIDARG;
210 return E_NOTIMPL;
213 static HRESULT WINAPI xmlelem_get_parent(IXMLElement *iface, IXMLElement **parent)
215 xmlelem *This = impl_from_IXMLElement(iface);
217 TRACE("(%p, %p)\n", iface, parent);
219 if (!parent)
220 return E_INVALIDARG;
222 *parent = NULL;
224 if (!This->node->parent)
225 return S_FALSE;
227 return XMLElement_create((IUnknown *)iface, This->node->parent, (LPVOID *)parent);
230 static HRESULT WINAPI xmlelem_setAttribute(IXMLElement *iface, BSTR strPropertyName,
231 VARIANT PropertyValue)
233 xmlelem *This = impl_from_IXMLElement(iface);
234 xmlChar *name, *value;
235 xmlAttrPtr attr;
237 TRACE("(%p, %s)\n", iface, debugstr_w(strPropertyName));
239 if (!strPropertyName || V_VT(&PropertyValue) != VT_BSTR)
240 return E_INVALIDARG;
242 name = xmlChar_from_wchar(strPropertyName);
243 value = xmlChar_from_wchar(V_BSTR(&PropertyValue));
244 attr = xmlSetProp(This->node, name, value);
246 HeapFree(GetProcessHeap(), 0, name);
247 HeapFree(GetProcessHeap(), 0, value);
248 return (attr) ? S_OK : S_FALSE;
251 static HRESULT WINAPI xmlelem_getAttribute(IXMLElement *iface, BSTR strPropertyName,
252 VARIANT *PropertyValue)
254 xmlelem *This = impl_from_IXMLElement(iface);
255 xmlChar *val = NULL, *name;
256 xmlAttrPtr ptr;
258 TRACE("(%p, %s, %p)\n", iface, debugstr_w(strPropertyName), PropertyValue);
260 if (!PropertyValue)
261 return E_INVALIDARG;
263 VariantInit(PropertyValue);
264 V_BSTR(PropertyValue) = NULL;
266 if (!strPropertyName)
267 return E_INVALIDARG;
269 name = xmlChar_from_wchar(strPropertyName);
270 ptr = This->node->properties;
271 while (ptr)
273 if (!lstrcmpiA((LPSTR)name, (LPCSTR)ptr->name))
275 val = xmlNodeListGetString(ptr->doc, ptr->children, 1);
276 break;
279 ptr = ptr->next;
282 if (val)
284 V_VT(PropertyValue) = VT_BSTR;
285 V_BSTR(PropertyValue) = bstr_from_xmlChar(val);
288 HeapFree(GetProcessHeap(), 0, name);
289 xmlFree(val);
290 TRACE("returning %s\n", debugstr_w(V_BSTR(PropertyValue)));
291 return (val) ? S_OK : S_FALSE;
294 static HRESULT WINAPI xmlelem_removeAttribute(IXMLElement *iface, BSTR strPropertyName)
296 xmlelem *This = impl_from_IXMLElement(iface);
297 xmlChar *name;
298 xmlAttrPtr attr;
299 int res;
300 HRESULT hr = S_FALSE;
302 TRACE("(%p, %s)\n", iface, debugstr_w(strPropertyName));
304 if (!strPropertyName)
305 return E_INVALIDARG;
307 name = xmlChar_from_wchar(strPropertyName);
308 attr = xmlHasProp(This->node, name);
309 if (!attr)
310 goto done;
312 res = xmlRemoveProp(attr);
314 if (res == 0)
315 hr = S_OK;
317 done:
318 HeapFree(GetProcessHeap(), 0, name);
319 return hr;
322 static HRESULT WINAPI xmlelem_get_children(IXMLElement *iface, IXMLElementCollection **p)
324 xmlelem *This = impl_from_IXMLElement(iface);
326 TRACE("(%p, %p)\n", iface, p);
328 if (!p)
329 return E_INVALIDARG;
331 return XMLElementCollection_create((IUnknown *)iface, This->node->children, (LPVOID *)p);
334 static long type_libxml_to_msxml(xmlElementType type)
336 switch (type)
338 case XML_ELEMENT_NODE:
339 return XMLELEMTYPE_ELEMENT;
340 case XML_TEXT_NODE:
341 return XMLELEMTYPE_TEXT;
342 case XML_COMMENT_NODE:
343 return XMLELEMTYPE_COMMENT;
344 case XML_DOCUMENT_NODE:
345 return XMLELEMTYPE_DOCUMENT;
346 case XML_DTD_NODE:
347 return XMLELEMTYPE_DTD;
348 case XML_PI_NODE:
349 return XMLELEMTYPE_PI;
350 default:
351 break;
354 return XMLELEMTYPE_OTHER;
357 static HRESULT WINAPI xmlelem_get_type(IXMLElement *iface, long *p)
359 xmlelem *This = impl_from_IXMLElement(iface);
361 TRACE("(%p, %p)\n", This, p);
363 if (!p)
364 return E_INVALIDARG;
366 *p = type_libxml_to_msxml(This->node->type);
367 TRACE("returning %ld\n", *p);
368 return S_OK;
371 static HRESULT WINAPI xmlelem_get_text(IXMLElement *iface, BSTR *p)
373 xmlelem *This = impl_from_IXMLElement(iface);
374 xmlChar *content;
376 TRACE("(%p, %p)\n", iface, p);
378 if (!p)
379 return E_INVALIDARG;
381 content = xmlNodeGetContent(This->node);
382 *p = bstr_from_xmlChar(content);
383 TRACE("returning %s\n", debugstr_w(*p));
385 xmlFree(content);
386 return S_OK;
389 static HRESULT WINAPI xmlelem_put_text(IXMLElement *iface, BSTR p)
391 xmlelem *This = impl_from_IXMLElement(iface);
392 xmlChar *content;
394 TRACE("(%p, %s)\n", iface, debugstr_w(p));
396 /* FIXME: test which types can be used */
397 if (This->node->type == XML_ELEMENT_NODE)
398 return E_NOTIMPL;
400 content = xmlChar_from_wchar(p);
401 xmlNodeSetContent(This->node, content);
403 HeapFree( GetProcessHeap(), 0, content);
405 return S_OK;
408 static HRESULT WINAPI xmlelem_addChild(IXMLElement *iface, IXMLElement *pChildElem,
409 long lIndex, long lreserved)
411 xmlelem *This = impl_from_IXMLElement(iface);
412 xmlelem *childElem = impl_from_IXMLElement(pChildElem);
413 xmlNodePtr child;
415 TRACE("(%p, %p, %ld, %ld)\n", iface, pChildElem, lIndex, lreserved);
417 if (lIndex == 0)
418 child = xmlAddChild(This->node, childElem->node);
419 else
420 child = xmlAddNextSibling(This->node, childElem->node->last);
422 return (child) ? S_OK : S_FALSE;
425 static HRESULT WINAPI xmlelem_removeChild(IXMLElement *iface, IXMLElement *pChildElem)
427 FIXME("(%p, %p): stub\n", iface, pChildElem);
428 return E_NOTIMPL;
431 static const struct IXMLElementVtbl xmlelem_vtbl =
433 xmlelem_QueryInterface,
434 xmlelem_AddRef,
435 xmlelem_Release,
436 xmlelem_GetTypeInfoCount,
437 xmlelem_GetTypeInfo,
438 xmlelem_GetIDsOfNames,
439 xmlelem_Invoke,
440 xmlelem_get_tagName,
441 xmlelem_put_tagName,
442 xmlelem_get_parent,
443 xmlelem_setAttribute,
444 xmlelem_getAttribute,
445 xmlelem_removeAttribute,
446 xmlelem_get_children,
447 xmlelem_get_type,
448 xmlelem_get_text,
449 xmlelem_put_text,
450 xmlelem_addChild,
451 xmlelem_removeChild
454 HRESULT XMLElement_create(IUnknown *pUnkOuter, xmlNodePtr node, LPVOID *ppObj)
456 xmlelem *elem;
458 TRACE("(%p,%p)\n", pUnkOuter, ppObj);
460 if (!ppObj)
461 return E_INVALIDARG;
463 *ppObj = NULL;
465 elem = HeapAlloc(GetProcessHeap(), 0, sizeof (*elem));
466 if(!elem)
467 return E_OUTOFMEMORY;
469 elem->lpVtbl = &xmlelem_vtbl;
470 elem->ref = 1;
471 elem->node = node;
473 *ppObj = &elem->lpVtbl;
475 TRACE("returning iface %p\n", *ppObj);
476 return S_OK;
479 /************************************************************************
480 * IXMLElementCollection
482 typedef struct _xmlelem_collection
484 const IXMLElementCollectionVtbl *lpVtbl;
485 const IEnumVARIANTVtbl *lpvtblIEnumVARIANT;
486 LONG ref;
487 LONG length;
488 xmlNodePtr node;
490 /* IEnumVARIANT members */
491 xmlNodePtr current;
492 } xmlelem_collection;
494 static inline xmlelem_collection *impl_from_IXMLElementCollection(IXMLElementCollection *iface)
496 return (xmlelem_collection *)((char*)iface - FIELD_OFFSET(xmlelem_collection, lpVtbl));
499 static inline xmlelem_collection *impl_from_IEnumVARIANT(IEnumVARIANT *iface)
501 return (xmlelem_collection *)((char*)iface - FIELD_OFFSET(xmlelem_collection, lpvtblIEnumVARIANT));
504 static HRESULT WINAPI xmlelem_collection_QueryInterface(IXMLElementCollection *iface, REFIID riid, void** ppvObject)
506 xmlelem_collection *This = impl_from_IXMLElementCollection(iface);
508 TRACE("%p %s %p\n", This, debugstr_guid(riid), ppvObject);
510 if (IsEqualGUID(riid, &IID_IUnknown) ||
511 IsEqualGUID(riid, &IID_IXMLElementCollection))
513 *ppvObject = iface;
515 else if (IsEqualGUID(riid, &IID_IEnumVARIANT))
517 *ppvObject = (IEnumVARIANT *)&(This->lpvtblIEnumVARIANT);
519 else
521 FIXME("interface %s not implemented\n", debugstr_guid(riid));
522 return E_NOINTERFACE;
525 IXMLElementCollection_AddRef(iface);
527 return S_OK;
530 static ULONG WINAPI xmlelem_collection_AddRef(IXMLElementCollection *iface)
532 xmlelem_collection *This = impl_from_IXMLElementCollection(iface);
533 TRACE("%p\n", This);
534 return InterlockedIncrement(&This->ref);
537 static ULONG WINAPI xmlelem_collection_Release(IXMLElementCollection *iface)
539 xmlelem_collection *This = impl_from_IXMLElementCollection(iface);
540 LONG ref;
542 TRACE("%p\n", This);
544 ref = InterlockedDecrement(&This->ref);
545 if (ref == 0)
547 HeapFree(GetProcessHeap(), 0, This);
550 return ref;
553 static HRESULT WINAPI xmlelem_collection_GetTypeInfoCount(IXMLElementCollection *iface, UINT* pctinfo)
555 FIXME("\n");
556 return E_NOTIMPL;
559 static HRESULT WINAPI xmlelem_collection_GetTypeInfo(IXMLElementCollection *iface, UINT iTInfo,
560 LCID lcid, ITypeInfo** ppTInfo)
562 FIXME("\n");
563 return E_NOTIMPL;
566 static HRESULT WINAPI xmlelem_collection_GetIDsOfNames(IXMLElementCollection *iface, REFIID riid,
567 LPOLESTR* rgszNames, UINT cNames,
568 LCID lcid, DISPID* rgDispId)
570 FIXME("\n");
571 return E_NOTIMPL;
574 static HRESULT WINAPI xmlelem_collection_Invoke(IXMLElementCollection *iface, DISPID dispIdMember,
575 REFIID riid, LCID lcid, WORD wFlags,
576 DISPPARAMS* pDispParams, VARIANT* pVarResult,
577 EXCEPINFO* pExcepInfo, UINT* puArgErr)
579 FIXME("\n");
580 return E_NOTIMPL;
583 static HRESULT WINAPI xmlelem_collection_put_length(IXMLElementCollection *iface, long v)
585 TRACE("(%p, %ld)\n", iface, v);
586 return E_FAIL;
589 static HRESULT WINAPI xmlelem_collection_get_length(IXMLElementCollection *iface, long *p)
591 xmlelem_collection *This = impl_from_IXMLElementCollection(iface);
593 TRACE("(%p, %p)\n", iface, p);
595 if (!p)
596 return E_INVALIDARG;
598 *p = This->length;
599 return S_OK;
602 static HRESULT WINAPI xmlelem_collection_get__newEnum(IXMLElementCollection *iface, IUnknown **ppUnk)
604 xmlelem_collection *This = impl_from_IXMLElementCollection(iface);
606 TRACE("(%p, %p)\n", iface, ppUnk);
608 if (!ppUnk)
609 return E_INVALIDARG;
611 *ppUnk = (IUnknown *)This;
612 IUnknown_AddRef(*ppUnk);
613 return S_OK;
616 static HRESULT WINAPI xmlelem_collection_item(IXMLElementCollection *iface, VARIANT var1,
617 VARIANT var2, IDispatch **ppDisp)
619 xmlelem_collection *This = impl_from_IXMLElementCollection(iface);
620 xmlNodePtr ptr = This->node;
621 int index, i;
623 TRACE("(%p, %p)\n", iface, ppDisp);
625 if (!ppDisp)
626 return E_INVALIDARG;
628 *ppDisp = NULL;
630 index = V_I4(&var1);
631 if (index < 0)
632 return E_INVALIDARG;
633 if (index >= This->length)
634 return E_FAIL;
636 for (i = 0; i < index; i++)
637 ptr = ptr->next;
639 return XMLElement_create((IUnknown *)iface, ptr, (LPVOID *)ppDisp);
642 static const struct IXMLElementCollectionVtbl xmlelem_collection_vtbl =
644 xmlelem_collection_QueryInterface,
645 xmlelem_collection_AddRef,
646 xmlelem_collection_Release,
647 xmlelem_collection_GetTypeInfoCount,
648 xmlelem_collection_GetTypeInfo,
649 xmlelem_collection_GetIDsOfNames,
650 xmlelem_collection_Invoke,
651 xmlelem_collection_put_length,
652 xmlelem_collection_get_length,
653 xmlelem_collection_get__newEnum,
654 xmlelem_collection_item
657 /************************************************************************
658 * xmlelem_collection implementation of IEnumVARIANT.
660 static HRESULT WINAPI xmlelem_collection_IEnumVARIANT_QueryInterface(
661 IEnumVARIANT *iface, REFIID riid, LPVOID *ppvObj)
663 xmlelem_collection *this = impl_from_IEnumVARIANT(iface);
664 return IXMLDocument_QueryInterface((IXMLDocument *)this, riid, ppvObj);
667 static ULONG WINAPI xmlelem_collection_IEnumVARIANT_AddRef(
668 IEnumVARIANT *iface)
670 xmlelem_collection *this = impl_from_IEnumVARIANT(iface);
671 return IXMLDocument_AddRef((IXMLDocument *)this);
674 static ULONG WINAPI xmlelem_collection_IEnumVARIANT_Release(
675 IEnumVARIANT *iface)
677 xmlelem_collection *this = impl_from_IEnumVARIANT(iface);
678 return IXMLDocument_Release((IXMLDocument *)this);
681 static HRESULT WINAPI xmlelem_collection_IEnumVARIANT_Next(
682 IEnumVARIANT *iface, ULONG celt, VARIANT *rgVar, ULONG *pCeltFetched)
684 xmlelem_collection *This = impl_from_IEnumVARIANT(iface);
685 xmlNodePtr ptr = This->current;
687 TRACE("(%p, %d, %p, %p)\n", iface, celt, rgVar, pCeltFetched);
689 if (!rgVar)
690 return E_INVALIDARG;
692 /* FIXME: handle celt */
693 if (pCeltFetched)
694 *pCeltFetched = 1;
696 This->current = This->current->next;
698 V_VT(rgVar) = VT_DISPATCH;
699 return XMLElement_create((IUnknown *)iface, ptr, (LPVOID *)&V_DISPATCH(rgVar));
702 static HRESULT WINAPI xmlelem_collection_IEnumVARIANT_Skip(
703 IEnumVARIANT *iface, ULONG celt)
705 FIXME("(%p, %d): stub\n", iface, celt);
706 return E_NOTIMPL;
709 static HRESULT WINAPI xmlelem_collection_IEnumVARIANT_Reset(
710 IEnumVARIANT *iface)
712 xmlelem_collection *This = impl_from_IEnumVARIANT(iface);
713 This->current = This->node;
714 return S_OK;
717 static HRESULT WINAPI xmlelem_collection_IEnumVARIANT_Clone(
718 IEnumVARIANT *iface, IEnumVARIANT **ppEnum)
720 FIXME("(%p, %p): stub\n", iface, ppEnum);
721 return E_NOTIMPL;
724 static const struct IEnumVARIANTVtbl xmlelem_collection_IEnumVARIANTvtbl =
726 xmlelem_collection_IEnumVARIANT_QueryInterface,
727 xmlelem_collection_IEnumVARIANT_AddRef,
728 xmlelem_collection_IEnumVARIANT_Release,
729 xmlelem_collection_IEnumVARIANT_Next,
730 xmlelem_collection_IEnumVARIANT_Skip,
731 xmlelem_collection_IEnumVARIANT_Reset,
732 xmlelem_collection_IEnumVARIANT_Clone
735 HRESULT XMLElementCollection_create(IUnknown *pUnkOuter, xmlNodePtr node, LPVOID *ppObj)
737 xmlelem_collection *collection;
738 xmlNodePtr ptr;
740 TRACE("(%p,%p)\n", pUnkOuter, ppObj);
742 *ppObj = NULL;
744 if (!node)
745 return S_FALSE;
747 collection = HeapAlloc(GetProcessHeap(), 0, sizeof (*collection));
748 if(!collection)
749 return E_OUTOFMEMORY;
751 collection->lpVtbl = &xmlelem_collection_vtbl;
752 collection->lpvtblIEnumVARIANT = &xmlelem_collection_IEnumVARIANTvtbl;
753 collection->ref = 1;
754 collection->length = 0;
755 collection->node = node;
756 collection->current = node;
758 ptr = node;
759 while (ptr)
761 collection->length++;
762 ptr = ptr->next;
765 *ppObj = &collection->lpVtbl;
767 TRACE("returning iface %p\n", *ppObj);
768 return S_OK;
771 #endif