msvcrt: Added basic _popen tests.
[wine] / dlls / mshtml / htmlnode.c
1 /*
2  * Copyright 2006 Jacek Caban for CodeWeavers
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18
19 #include <stdarg.h>
20 #include <assert.h>
21
22 #define COBJMACROS
23
24 #include "windef.h"
25 #include "winbase.h"
26 #include "winuser.h"
27 #include "ole2.h"
28
29 #include "wine/debug.h"
30
31 #include "mshtml_private.h"
32 #include "htmlevent.h"
33
34 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
35
36 static HTMLDOMNode *get_node_obj(IHTMLDOMNode*);
37 static HRESULT create_node(HTMLDocumentNode*,nsIDOMNode*,HTMLDOMNode**);
38
39 typedef struct {
40     DispatchEx dispex;
41     IHTMLDOMChildrenCollection IHTMLDOMChildrenCollection_iface;
42
43     LONG ref;
44
45     /* FIXME: implement weak reference */
46     HTMLDocumentNode *doc;
47
48     nsIDOMNodeList *nslist;
49 } HTMLDOMChildrenCollection;
50
51 static inline HTMLDOMChildrenCollection *impl_from_IHTMLDOMChildrenCollection(IHTMLDOMChildrenCollection *iface)
52 {
53     return CONTAINING_RECORD(iface, HTMLDOMChildrenCollection, IHTMLDOMChildrenCollection_iface);
54 }
55
56 static HRESULT WINAPI HTMLDOMChildrenCollection_QueryInterface(IHTMLDOMChildrenCollection *iface, REFIID riid, void **ppv)
57 {
58     HTMLDOMChildrenCollection *This = impl_from_IHTMLDOMChildrenCollection(iface);
59
60     *ppv = NULL;
61
62     if(IsEqualGUID(&IID_IUnknown, riid)) {
63         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
64         *ppv = &This->IHTMLDOMChildrenCollection_iface;
65     }else if(IsEqualGUID(&IID_IHTMLDOMChildrenCollection, riid)) {
66         TRACE("(%p)->(IID_IHTMLDOMChildrenCollection %p)\n", This, ppv);
67         *ppv = &This->IHTMLDOMChildrenCollection_iface;
68     }else if(dispex_query_interface(&This->dispex, riid, ppv)) {
69         return *ppv ? S_OK : E_NOINTERFACE;
70     }
71
72     if(*ppv) {
73         IUnknown_AddRef((IUnknown*)*ppv);
74         return S_OK;
75     }
76
77     WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
78     return E_NOINTERFACE;
79 }
80
81 static ULONG WINAPI HTMLDOMChildrenCollection_AddRef(IHTMLDOMChildrenCollection *iface)
82 {
83     HTMLDOMChildrenCollection *This = impl_from_IHTMLDOMChildrenCollection(iface);
84     LONG ref = InterlockedIncrement(&This->ref);
85
86     TRACE("(%p) ref=%d\n", This, ref);
87
88     return ref;
89 }
90
91 static ULONG WINAPI HTMLDOMChildrenCollection_Release(IHTMLDOMChildrenCollection *iface)
92 {
93     HTMLDOMChildrenCollection *This = impl_from_IHTMLDOMChildrenCollection(iface);
94     LONG ref = InterlockedDecrement(&This->ref);
95
96     TRACE("(%p) ref=%d\n", This, ref);
97
98     if(!ref) {
99         htmldoc_release(&This->doc->basedoc);
100         nsIDOMNodeList_Release(This->nslist);
101         heap_free(This);
102     }
103
104     return ref;
105 }
106
107 static HRESULT WINAPI HTMLDOMChildrenCollection_GetTypeInfoCount(IHTMLDOMChildrenCollection *iface, UINT *pctinfo)
108 {
109     HTMLDOMChildrenCollection *This = impl_from_IHTMLDOMChildrenCollection(iface);
110     return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo);
111 }
112
113 static HRESULT WINAPI HTMLDOMChildrenCollection_GetTypeInfo(IHTMLDOMChildrenCollection *iface, UINT iTInfo,
114         LCID lcid, ITypeInfo **ppTInfo)
115 {
116     HTMLDOMChildrenCollection *This = impl_from_IHTMLDOMChildrenCollection(iface);
117     return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo);
118 }
119
120 static HRESULT WINAPI HTMLDOMChildrenCollection_GetIDsOfNames(IHTMLDOMChildrenCollection *iface, REFIID riid,
121         LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
122 {
123     HTMLDOMChildrenCollection *This = impl_from_IHTMLDOMChildrenCollection(iface);
124     return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface, riid, rgszNames, cNames,
125             lcid, rgDispId);
126 }
127
128 static HRESULT WINAPI HTMLDOMChildrenCollection_Invoke(IHTMLDOMChildrenCollection *iface, DISPID dispIdMember,
129         REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
130         VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
131 {
132     HTMLDOMChildrenCollection *This = impl_from_IHTMLDOMChildrenCollection(iface);
133     return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface, dispIdMember, riid, lcid,
134             wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
135 }
136
137 static HRESULT WINAPI HTMLDOMChildrenCollection_get_length(IHTMLDOMChildrenCollection *iface, LONG *p)
138 {
139     HTMLDOMChildrenCollection *This = impl_from_IHTMLDOMChildrenCollection(iface);
140     PRUint32 length=0;
141
142     TRACE("(%p)->(%p)\n", This, p);
143
144     nsIDOMNodeList_GetLength(This->nslist, &length);
145     *p = length;
146     return S_OK;
147 }
148
149 static HRESULT WINAPI HTMLDOMChildrenCollection__newEnum(IHTMLDOMChildrenCollection *iface, IUnknown **p)
150 {
151     HTMLDOMChildrenCollection *This = impl_from_IHTMLDOMChildrenCollection(iface);
152     FIXME("(%p)->(%p)\n", This, p);
153     return E_NOTIMPL;
154 }
155
156 static HRESULT WINAPI HTMLDOMChildrenCollection_item(IHTMLDOMChildrenCollection *iface, LONG index, IDispatch **ppItem)
157 {
158     HTMLDOMChildrenCollection *This = impl_from_IHTMLDOMChildrenCollection(iface);
159     nsIDOMNode *nsnode = NULL;
160     HTMLDOMNode *node;
161     PRUint32 length=0;
162     nsresult nsres;
163     HRESULT hres;
164
165     TRACE("(%p)->(%d %p)\n", This, index, ppItem);
166
167     if (ppItem)
168         *ppItem = NULL;
169     else
170         return E_POINTER;
171
172     nsIDOMNodeList_GetLength(This->nslist, &length);
173     if(index < 0 || index >= length)
174         return E_INVALIDARG;
175
176     nsres = nsIDOMNodeList_Item(This->nslist, index, &nsnode);
177     if(NS_FAILED(nsres) || !nsnode) {
178         ERR("Item failed: %08x\n", nsres);
179         return E_FAIL;
180     }
181
182     hres = get_node(This->doc, nsnode, TRUE, &node);
183     if(FAILED(hres))
184         return hres;
185
186     *ppItem = (IDispatch*)&node->IHTMLDOMNode_iface;
187     return S_OK;
188 }
189
190 static const IHTMLDOMChildrenCollectionVtbl HTMLDOMChildrenCollectionVtbl = {
191     HTMLDOMChildrenCollection_QueryInterface,
192     HTMLDOMChildrenCollection_AddRef,
193     HTMLDOMChildrenCollection_Release,
194     HTMLDOMChildrenCollection_GetTypeInfoCount,
195     HTMLDOMChildrenCollection_GetTypeInfo,
196     HTMLDOMChildrenCollection_GetIDsOfNames,
197     HTMLDOMChildrenCollection_Invoke,
198     HTMLDOMChildrenCollection_get_length,
199     HTMLDOMChildrenCollection__newEnum,
200     HTMLDOMChildrenCollection_item
201 };
202
203 static inline HTMLDOMChildrenCollection *impl_from_DispatchEx(DispatchEx *iface)
204 {
205     return CONTAINING_RECORD(iface, HTMLDOMChildrenCollection, dispex);
206 }
207
208 #define DISPID_CHILDCOL_0 MSHTML_DISPID_CUSTOM_MIN
209
210 static HRESULT HTMLDOMChildrenCollection_get_dispid(DispatchEx *dispex, BSTR name, DWORD flags, DISPID *dispid)
211 {
212     HTMLDOMChildrenCollection *This = impl_from_DispatchEx(dispex);
213     WCHAR *ptr;
214     DWORD idx=0;
215     PRUint32 len = 0;
216
217     for(ptr = name; *ptr && isdigitW(*ptr); ptr++)
218         idx = idx*10 + (*ptr-'0');
219     if(*ptr)
220         return DISP_E_UNKNOWNNAME;
221
222     nsIDOMNodeList_GetLength(This->nslist, &len);
223     if(idx >= len)
224         return DISP_E_UNKNOWNNAME;
225
226     *dispid = DISPID_CHILDCOL_0 + idx;
227     TRACE("ret %x\n", *dispid);
228     return S_OK;
229 }
230
231 static HRESULT HTMLDOMChildrenCollection_invoke(DispatchEx *dispex, DISPID id, LCID lcid, WORD flags, DISPPARAMS *params,
232         VARIANT *res, EXCEPINFO *ei, IServiceProvider *caller)
233 {
234     HTMLDOMChildrenCollection *This = impl_from_DispatchEx(dispex);
235
236     TRACE("(%p)->(%x %x %x %p %p %p %p)\n", This, id, lcid, flags, params, res, ei, caller);
237
238     switch(flags) {
239     case DISPATCH_PROPERTYGET: {
240         IDispatch *disp = NULL;
241         HRESULT hres;
242
243         hres = IHTMLDOMChildrenCollection_item(&This->IHTMLDOMChildrenCollection_iface,
244                 id - DISPID_CHILDCOL_0, &disp);
245         if(FAILED(hres))
246             return hres;
247
248         V_VT(res) = VT_DISPATCH;
249         V_DISPATCH(res) = disp;
250         break;
251     }
252
253     default:
254         FIXME("unimplemented flags %x\n", flags);
255         return E_NOTIMPL;
256     }
257
258     return S_OK;
259 }
260
261 static const dispex_static_data_vtbl_t HTMLDOMChildrenCollection_dispex_vtbl = {
262     NULL,
263     HTMLDOMChildrenCollection_get_dispid,
264     HTMLDOMChildrenCollection_invoke,
265     NULL
266 };
267
268 static const tid_t HTMLDOMChildrenCollection_iface_tids[] = {
269     IHTMLDOMChildrenCollection_tid,
270     0
271 };
272
273 static dispex_static_data_t HTMLDOMChildrenCollection_dispex = {
274     &HTMLDOMChildrenCollection_dispex_vtbl,
275     DispDOMChildrenCollection_tid,
276     NULL,
277     HTMLDOMChildrenCollection_iface_tids
278 };
279
280 static IHTMLDOMChildrenCollection *create_child_collection(HTMLDocumentNode *doc, nsIDOMNodeList *nslist)
281 {
282     HTMLDOMChildrenCollection *ret;
283
284     ret = heap_alloc_zero(sizeof(*ret));
285     if(!ret)
286         return NULL;
287
288     ret->IHTMLDOMChildrenCollection_iface.lpVtbl = &HTMLDOMChildrenCollectionVtbl;
289     ret->ref = 1;
290
291     nsIDOMNodeList_AddRef(nslist);
292     ret->nslist = nslist;
293
294     htmldoc_addref(&doc->basedoc);
295     ret->doc = doc;
296
297     init_dispex(&ret->dispex, (IUnknown*)&ret->IHTMLDOMChildrenCollection_iface,
298             &HTMLDOMChildrenCollection_dispex);
299
300     return &ret->IHTMLDOMChildrenCollection_iface;
301 }
302
303 static inline HTMLDOMNode *impl_from_IHTMLDOMNode(IHTMLDOMNode *iface)
304 {
305     return CONTAINING_RECORD(iface, HTMLDOMNode, IHTMLDOMNode_iface);
306 }
307
308 static HRESULT WINAPI HTMLDOMNode_QueryInterface(IHTMLDOMNode *iface,
309                                                  REFIID riid, void **ppv)
310 {
311     HTMLDOMNode *This = impl_from_IHTMLDOMNode(iface);
312
313     return This->vtbl->qi(This, riid, ppv);
314 }
315
316 static ULONG WINAPI HTMLDOMNode_AddRef(IHTMLDOMNode *iface)
317 {
318     HTMLDOMNode *This = impl_from_IHTMLDOMNode(iface);
319     LONG ref = ccref_incr(&This->ccref, (nsISupports*)&This->IHTMLDOMNode_iface);
320
321     TRACE("(%p) ref=%d\n", This, ref);
322
323     return ref;
324 }
325
326 static ULONG WINAPI HTMLDOMNode_Release(IHTMLDOMNode *iface)
327 {
328     HTMLDOMNode *This = impl_from_IHTMLDOMNode(iface);
329     LONG ref = ccref_decr(&This->ccref, (nsISupports*)&This->IHTMLDOMNode_iface);
330
331     TRACE("(%p) ref=%d\n", This, ref);
332
333     if(!ref) {
334         This->vtbl->destructor(This);
335         release_dispex(&This->dispex);
336         heap_free(This);
337     }
338
339     return ref;
340 }
341
342 static HRESULT WINAPI HTMLDOMNode_GetTypeInfoCount(IHTMLDOMNode *iface, UINT *pctinfo)
343 {
344     HTMLDOMNode *This = impl_from_IHTMLDOMNode(iface);
345     return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo);
346 }
347
348 static HRESULT WINAPI HTMLDOMNode_GetTypeInfo(IHTMLDOMNode *iface, UINT iTInfo,
349                                               LCID lcid, ITypeInfo **ppTInfo)
350 {
351     HTMLDOMNode *This = impl_from_IHTMLDOMNode(iface);
352     return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo);
353 }
354
355 static HRESULT WINAPI HTMLDOMNode_GetIDsOfNames(IHTMLDOMNode *iface, REFIID riid,
356                                                 LPOLESTR *rgszNames, UINT cNames,
357                                                 LCID lcid, DISPID *rgDispId)
358 {
359     HTMLDOMNode *This = impl_from_IHTMLDOMNode(iface);
360     return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface, riid, rgszNames, cNames,
361             lcid, rgDispId);
362 }
363
364 static HRESULT WINAPI HTMLDOMNode_Invoke(IHTMLDOMNode *iface, DISPID dispIdMember,
365                             REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
366                             VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
367 {
368     HTMLDOMNode *This = impl_from_IHTMLDOMNode(iface);
369     return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface, dispIdMember, riid, lcid,
370             wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
371 }
372
373 static HRESULT WINAPI HTMLDOMNode_get_nodeType(IHTMLDOMNode *iface, LONG *p)
374 {
375     HTMLDOMNode *This = impl_from_IHTMLDOMNode(iface);
376     PRUint16 type = -1;
377
378     TRACE("(%p)->(%p)\n", This, p);
379
380     nsIDOMNode_GetNodeType(This->nsnode, &type);
381
382     switch(type) {
383     case ELEMENT_NODE:
384         *p = 1;
385         break;
386     case TEXT_NODE:
387         *p = 3;
388         break;
389     case COMMENT_NODE:
390     case DOCUMENT_TYPE_NODE:
391         *p = 8;
392         break;
393     case DOCUMENT_NODE:
394         *p = 9;
395         break;
396     case DOCUMENT_FRAGMENT_NODE:
397         *p = 11;
398         break;
399     default:
400         /*
401          * FIXME:
402          * According to MSDN only ELEMENT_NODE and TEXT_NODE are supported.
403          * It needs more tests.
404          */
405         FIXME("type %u\n", type);
406         *p = 0;
407     }
408
409     return S_OK;
410 }
411
412 static HRESULT WINAPI HTMLDOMNode_get_parentNode(IHTMLDOMNode *iface, IHTMLDOMNode **p)
413 {
414     HTMLDOMNode *This = impl_from_IHTMLDOMNode(iface);
415     HTMLDOMNode *node;
416     nsIDOMNode *nsnode;
417     nsresult nsres;
418     HRESULT hres;
419
420     TRACE("(%p)->(%p)\n", This, p);
421
422     nsres = nsIDOMNode_GetParentNode(This->nsnode, &nsnode);
423     if(NS_FAILED(nsres)) {
424         ERR("GetParentNode failed: %08x\n", nsres);
425         return E_FAIL;
426     }
427
428     if(!nsnode) {
429         *p = NULL;
430         return S_OK;
431     }
432
433     hres = get_node(This->doc, nsnode, TRUE, &node);
434     nsIDOMNode_Release(nsnode);
435     if(FAILED(hres))
436         return hres;
437
438     *p = &node->IHTMLDOMNode_iface;
439     return S_OK;
440 }
441
442 static HRESULT WINAPI HTMLDOMNode_hasChildNodes(IHTMLDOMNode *iface, VARIANT_BOOL *fChildren)
443 {
444     HTMLDOMNode *This = impl_from_IHTMLDOMNode(iface);
445     cpp_bool has_child = FALSE;
446     nsresult nsres;
447
448     TRACE("(%p)->(%p)\n", This, fChildren);
449
450     nsres = nsIDOMNode_HasChildNodes(This->nsnode, &has_child);
451     if(NS_FAILED(nsres))
452         ERR("HasChildNodes failed: %08x\n", nsres);
453
454     *fChildren = has_child ? VARIANT_TRUE : VARIANT_FALSE;
455     return S_OK;
456 }
457
458 static HRESULT WINAPI HTMLDOMNode_get_childNodes(IHTMLDOMNode *iface, IDispatch **p)
459 {
460     HTMLDOMNode *This = impl_from_IHTMLDOMNode(iface);
461     nsIDOMNodeList *nslist;
462     nsresult nsres;
463
464     TRACE("(%p)->(%p)\n", This, p);
465
466     nsres = nsIDOMNode_GetChildNodes(This->nsnode, &nslist);
467     if(NS_FAILED(nsres)) {
468         ERR("GetChildNodes failed: %08x\n", nsres);
469         return E_FAIL;
470     }
471
472     *p = (IDispatch*)create_child_collection(This->doc, nslist);
473     nsIDOMNodeList_Release(nslist);
474
475     return *p ? S_OK : E_OUTOFMEMORY;
476 }
477
478 static HRESULT WINAPI HTMLDOMNode_get_attributes(IHTMLDOMNode *iface, IDispatch **p)
479 {
480     HTMLDOMNode *This = impl_from_IHTMLDOMNode(iface);
481     HTMLAttributeCollection *col;
482     HRESULT hres;
483
484     TRACE("(%p)->(%p)\n", This, p);
485
486     if(This->vtbl->get_attr_col) {
487         hres = This->vtbl->get_attr_col(This, &col);
488         if(FAILED(hres))
489             return hres;
490
491         *p = (IDispatch*)&col->IHTMLAttributeCollection_iface;
492         return S_OK;
493     }
494
495     *p = NULL;
496     return S_OK;
497 }
498
499 static HRESULT WINAPI HTMLDOMNode_insertBefore(IHTMLDOMNode *iface, IHTMLDOMNode *newChild,
500                                                VARIANT refChild, IHTMLDOMNode **node)
501 {
502     HTMLDOMNode *This = impl_from_IHTMLDOMNode(iface);
503     HTMLDOMNode *new_child, *node_obj, *ref_node = NULL;
504     nsIDOMNode *nsnode;
505     nsresult nsres;
506     HRESULT hres = S_OK;
507
508     TRACE("(%p)->(%p %s %p)\n", This, newChild, debugstr_variant(&refChild), node);
509
510     new_child = get_node_obj(newChild);
511     if(!new_child) {
512         ERR("invalid newChild\n");
513         return E_INVALIDARG;
514     }
515
516     switch(V_VT(&refChild)) {
517     case VT_NULL:
518         break;
519     case VT_DISPATCH: {
520         IHTMLDOMNode *ref_iface;
521
522         if(!V_DISPATCH(&refChild))
523             break;
524
525         hres = IDispatch_QueryInterface(V_DISPATCH(&refChild), &IID_IHTMLDOMNode, (void**)&ref_iface);
526         if(FAILED(hres))
527             break;
528
529         ref_node = get_node_obj(ref_iface);
530         IHTMLDOMNode_Release(ref_iface);
531         if(!ref_node) {
532             ERR("unvalid node\n");
533             hres = E_FAIL;
534             break;
535         }
536         break;
537     }
538     default:
539         FIXME("unimplemented refChild %s\n", debugstr_variant(&refChild));
540         hres = E_NOTIMPL;
541     }
542
543     if(SUCCEEDED(hres)) {
544         nsres = nsIDOMNode_InsertBefore(This->nsnode, new_child->nsnode, ref_node ? ref_node->nsnode : NULL, &nsnode);
545         if(NS_FAILED(nsres)) {
546             ERR("InsertBefore failed: %08x\n", nsres);
547             hres = E_FAIL;
548         }
549     }
550     node_release(new_child);
551     if(ref_node)
552         node_release(ref_node);
553     if(FAILED(hres))
554         return hres;
555
556     hres = get_node(This->doc, nsnode, TRUE, &node_obj);
557     nsIDOMNode_Release(nsnode);
558     if(FAILED(hres))
559         return hres;
560
561     *node = &node_obj->IHTMLDOMNode_iface;
562     return S_OK;
563 }
564
565 static HRESULT WINAPI HTMLDOMNode_removeChild(IHTMLDOMNode *iface, IHTMLDOMNode *oldChild,
566                                               IHTMLDOMNode **node)
567 {
568     HTMLDOMNode *This = impl_from_IHTMLDOMNode(iface);
569     HTMLDOMNode *node_obj;
570     nsIDOMNode *nsnode;
571     nsresult nsres;
572     HRESULT hres;
573
574     TRACE("(%p)->(%p %p)\n", This, oldChild, node);
575
576     node_obj = get_node_obj(oldChild);
577     if(!node_obj)
578         return E_FAIL;
579
580     nsres = nsIDOMNode_RemoveChild(This->nsnode, node_obj->nsnode, &nsnode);
581     node_release(node_obj);
582     if(NS_FAILED(nsres)) {
583         ERR("RemoveChild failed: %08x\n", nsres);
584         return E_FAIL;
585     }
586
587     hres = get_node(This->doc, nsnode, TRUE, &node_obj);
588     nsIDOMNode_Release(nsnode);
589     if(FAILED(hres))
590         return hres;
591
592     /* FIXME: Make sure that node != newChild */
593     *node = &node_obj->IHTMLDOMNode_iface;
594     return S_OK;
595 }
596
597 static HRESULT WINAPI HTMLDOMNode_replaceChild(IHTMLDOMNode *iface, IHTMLDOMNode *newChild,
598                                                IHTMLDOMNode *oldChild, IHTMLDOMNode **node)
599 {
600     HTMLDOMNode *This = impl_from_IHTMLDOMNode(iface);
601     HTMLDOMNode *node_new, *node_old, *ret_node;
602     nsIDOMNode *nsnode;
603     nsresult nsres;
604     HRESULT hres;
605
606     TRACE("(%p)->(%p %p %p)\n", This, newChild, oldChild, node);
607
608     node_new = get_node_obj(newChild);
609     if(!node_new)
610         return E_FAIL;
611
612     node_old = get_node_obj(oldChild);
613     if(!node_old) {
614         node_release(node_new);
615         return E_FAIL;
616     }
617
618     nsres = nsIDOMNode_ReplaceChild(This->nsnode, node_new->nsnode, node_old->nsnode, &nsnode);
619     node_release(node_new);
620     node_release(node_old);
621     if(NS_FAILED(nsres))
622         return E_FAIL;
623
624     hres = get_node(This->doc, nsnode, TRUE, &ret_node);
625     nsIDOMNode_Release(nsnode);
626     if(FAILED(hres))
627         return hres;
628
629     *node = &ret_node->IHTMLDOMNode_iface;
630     return S_OK;
631 }
632
633 static HRESULT WINAPI HTMLDOMNode_cloneNode(IHTMLDOMNode *iface, VARIANT_BOOL fDeep,
634                                             IHTMLDOMNode **clonedNode)
635 {
636     HTMLDOMNode *This = impl_from_IHTMLDOMNode(iface);
637     HTMLDOMNode *new_node;
638     nsIDOMNode *nsnode;
639     nsresult nsres;
640     HRESULT hres;
641
642     TRACE("(%p)->(%x %p)\n", This, fDeep, clonedNode);
643
644     nsres = nsIDOMNode_CloneNode(This->nsnode, fDeep != VARIANT_FALSE, 1, &nsnode);
645     if(NS_FAILED(nsres) || !nsnode) {
646         ERR("CloneNode failed: %08x\n", nsres);
647         return E_FAIL;
648     }
649
650     hres = This->vtbl->clone(This, nsnode, &new_node);
651     if(FAILED(hres))
652         return hres;
653
654     *clonedNode = &new_node->IHTMLDOMNode_iface;
655     return S_OK;
656 }
657
658 static HRESULT WINAPI HTMLDOMNode_removeNode(IHTMLDOMNode *iface, VARIANT_BOOL fDeep,
659                                              IHTMLDOMNode **removed)
660 {
661     HTMLDOMNode *This = impl_from_IHTMLDOMNode(iface);
662     FIXME("(%p)->(%x %p)\n", This, fDeep, removed);
663     return E_NOTIMPL;
664 }
665
666 static HRESULT WINAPI HTMLDOMNode_swapNode(IHTMLDOMNode *iface, IHTMLDOMNode *otherNode,
667                                            IHTMLDOMNode **swappedNode)
668 {
669     HTMLDOMNode *This = impl_from_IHTMLDOMNode(iface);
670     FIXME("(%p)->(%p %p)\n", This, otherNode, swappedNode);
671     return E_NOTIMPL;
672 }
673
674 static HRESULT WINAPI HTMLDOMNode_replaceNode(IHTMLDOMNode *iface, IHTMLDOMNode *replacement,
675                                               IHTMLDOMNode **replaced)
676 {
677     HTMLDOMNode *This = impl_from_IHTMLDOMNode(iface);
678     FIXME("(%p)->(%p %p)\n", This, replacement, replaced);
679     return E_NOTIMPL;
680 }
681
682 static HRESULT WINAPI HTMLDOMNode_appendChild(IHTMLDOMNode *iface, IHTMLDOMNode *newChild,
683                                               IHTMLDOMNode **node)
684 {
685     HTMLDOMNode *This = impl_from_IHTMLDOMNode(iface);
686     HTMLDOMNode *node_obj;
687     nsIDOMNode *nsnode;
688     nsresult nsres;
689     HRESULT hres;
690
691     TRACE("(%p)->(%p %p)\n", This, newChild, node);
692
693     node_obj = get_node_obj(newChild);
694     if(!node_obj)
695         return E_FAIL;
696
697     nsres = nsIDOMNode_AppendChild(This->nsnode, node_obj->nsnode, &nsnode);
698     node_release(node_obj);
699     if(NS_FAILED(nsres)) {
700         ERR("AppendChild failed: %08x\n", nsres);
701         return E_FAIL;
702     }
703
704     hres = get_node(This->doc, nsnode, TRUE, &node_obj);
705     nsIDOMNode_Release(nsnode);
706     if(FAILED(hres))
707         return hres;
708
709     /* FIXME: Make sure that node != newChild */
710     *node = &node_obj->IHTMLDOMNode_iface;
711     return S_OK;
712 }
713
714 static HRESULT WINAPI HTMLDOMNode_get_nodeName(IHTMLDOMNode *iface, BSTR *p)
715 {
716     HTMLDOMNode *This = impl_from_IHTMLDOMNode(iface);
717     nsAString name;
718     nsresult nsres;
719
720     TRACE("(%p)->(%p)\n", This, p);
721
722     nsAString_Init(&name, NULL);
723     nsres = nsIDOMNode_GetNodeName(This->nsnode, &name);
724     return return_nsstr(nsres, &name, p);
725 }
726
727 static HRESULT WINAPI HTMLDOMNode_put_nodeValue(IHTMLDOMNode *iface, VARIANT v)
728 {
729     HTMLDOMNode *This = impl_from_IHTMLDOMNode(iface);
730
731     TRACE("(%p)->(%s)\n", This, debugstr_variant(&v));
732
733     switch(V_VT(&v)) {
734     case VT_BSTR: {
735         nsAString val_str;
736
737         nsAString_InitDepend(&val_str, V_BSTR(&v));
738         nsIDOMNode_SetNodeValue(This->nsnode, &val_str);
739         nsAString_Finish(&val_str);
740
741         return S_OK;
742     }
743
744     default:
745         FIXME("unsupported value %s\n", debugstr_variant(&v));
746     }
747
748     return E_NOTIMPL;
749 }
750
751 static HRESULT WINAPI HTMLDOMNode_get_nodeValue(IHTMLDOMNode *iface, VARIANT *p)
752 {
753     HTMLDOMNode *This = impl_from_IHTMLDOMNode(iface);
754     const PRUnichar *val;
755     nsAString val_str;
756
757     TRACE("(%p)->(%p)\n", This, p);
758
759     nsAString_Init(&val_str, NULL);
760     nsIDOMNode_GetNodeValue(This->nsnode, &val_str);
761     nsAString_GetData(&val_str, &val);
762
763     if(*val) {
764         V_VT(p) = VT_BSTR;
765         V_BSTR(p) = SysAllocString(val);
766     }else {
767         V_VT(p) = VT_NULL;
768     }
769
770     nsAString_Finish(&val_str);
771
772     return S_OK;
773 }
774
775 static HRESULT WINAPI HTMLDOMNode_get_firstChild(IHTMLDOMNode *iface, IHTMLDOMNode **p)
776 {
777     HTMLDOMNode *This = impl_from_IHTMLDOMNode(iface);
778     nsIDOMNode *nschild = NULL;
779     HTMLDOMNode *node;
780     HRESULT hres;
781
782     TRACE("(%p)->(%p)\n", This, p);
783
784     nsIDOMNode_GetFirstChild(This->nsnode, &nschild);
785     if(!nschild) {
786         *p = NULL;
787         return S_OK;
788     }
789
790     hres = get_node(This->doc, nschild, TRUE, &node);
791     nsIDOMNode_Release(nschild);
792     if(FAILED(hres))
793         return hres;
794
795     *p = &node->IHTMLDOMNode_iface;
796     return S_OK;
797 }
798
799 static HRESULT WINAPI HTMLDOMNode_get_lastChild(IHTMLDOMNode *iface, IHTMLDOMNode **p)
800 {
801     HTMLDOMNode *This = impl_from_IHTMLDOMNode(iface);
802     nsIDOMNode *nschild = NULL;
803     HTMLDOMNode *node;
804     HRESULT hres;
805
806     TRACE("(%p)->(%p)\n", This, p);
807
808     nsIDOMNode_GetLastChild(This->nsnode, &nschild);
809     if(!nschild) {
810         *p = NULL;
811         return S_OK;
812     }
813
814     hres = get_node(This->doc, nschild, TRUE, &node);
815     nsIDOMNode_Release(nschild);
816     if(FAILED(hres))
817         return hres;
818
819     *p = &node->IHTMLDOMNode_iface;
820     return S_OK;
821 }
822
823 static HRESULT WINAPI HTMLDOMNode_get_previousSibling(IHTMLDOMNode *iface, IHTMLDOMNode **p)
824 {
825     HTMLDOMNode *This = impl_from_IHTMLDOMNode(iface);
826     nsIDOMNode *nschild = NULL;
827     HTMLDOMNode *node;
828     HRESULT hres;
829
830     TRACE("(%p)->(%p)\n", This, p);
831
832     nsIDOMNode_GetPreviousSibling(This->nsnode, &nschild);
833     if(!nschild) {
834         *p = NULL;
835         return S_OK;
836     }
837
838     hres = get_node(This->doc, nschild, TRUE, &node);
839     nsIDOMNode_Release(nschild);
840     if(FAILED(hres))
841         return hres;
842
843     *p = &node->IHTMLDOMNode_iface;
844     return S_OK;
845 }
846
847 static HRESULT WINAPI HTMLDOMNode_get_nextSibling(IHTMLDOMNode *iface, IHTMLDOMNode **p)
848 {
849     HTMLDOMNode *This = impl_from_IHTMLDOMNode(iface);
850     nsIDOMNode *nssibling = NULL;
851     HTMLDOMNode *node;
852     HRESULT hres;
853
854     TRACE("(%p)->(%p)\n", This, p);
855
856     nsIDOMNode_GetNextSibling(This->nsnode, &nssibling);
857     if(!nssibling) {
858         *p = NULL;
859         return S_OK;
860     }
861
862     hres = get_node(This->doc, nssibling, TRUE, &node);
863     nsIDOMNode_Release(nssibling);
864     if(FAILED(hres))
865         return hres;
866
867     *p = &node->IHTMLDOMNode_iface;
868     return S_OK;
869 }
870
871 static const IHTMLDOMNodeVtbl HTMLDOMNodeVtbl = {
872     HTMLDOMNode_QueryInterface,
873     HTMLDOMNode_AddRef,
874     HTMLDOMNode_Release,
875     HTMLDOMNode_GetTypeInfoCount,
876     HTMLDOMNode_GetTypeInfo,
877     HTMLDOMNode_GetIDsOfNames,
878     HTMLDOMNode_Invoke,
879     HTMLDOMNode_get_nodeType,
880     HTMLDOMNode_get_parentNode,
881     HTMLDOMNode_hasChildNodes,
882     HTMLDOMNode_get_childNodes,
883     HTMLDOMNode_get_attributes,
884     HTMLDOMNode_insertBefore,
885     HTMLDOMNode_removeChild,
886     HTMLDOMNode_replaceChild,
887     HTMLDOMNode_cloneNode,
888     HTMLDOMNode_removeNode,
889     HTMLDOMNode_swapNode,
890     HTMLDOMNode_replaceNode,
891     HTMLDOMNode_appendChild,
892     HTMLDOMNode_get_nodeName,
893     HTMLDOMNode_put_nodeValue,
894     HTMLDOMNode_get_nodeValue,
895     HTMLDOMNode_get_firstChild,
896     HTMLDOMNode_get_lastChild,
897     HTMLDOMNode_get_previousSibling,
898     HTMLDOMNode_get_nextSibling
899 };
900
901 static HTMLDOMNode *get_node_obj(IHTMLDOMNode *iface)
902 {
903     HTMLDOMNode *ret;
904
905     if(iface->lpVtbl != &HTMLDOMNodeVtbl)
906         return NULL;
907
908     ret = impl_from_IHTMLDOMNode(iface);
909     node_addref(ret);
910     return ret;
911 }
912
913 static inline HTMLDOMNode *impl_from_IHTMLDOMNode2(IHTMLDOMNode2 *iface)
914 {
915     return CONTAINING_RECORD(iface, HTMLDOMNode, IHTMLDOMNode2_iface);
916 }
917
918 static HRESULT WINAPI HTMLDOMNode2_QueryInterface(IHTMLDOMNode2 *iface,
919         REFIID riid, void **ppv)
920 {
921     HTMLDOMNode *This = impl_from_IHTMLDOMNode2(iface);
922
923     return IHTMLDOMNode_QueryInterface(&This->IHTMLDOMNode_iface, riid, ppv);
924 }
925
926 static ULONG WINAPI HTMLDOMNode2_AddRef(IHTMLDOMNode2 *iface)
927 {
928     HTMLDOMNode *This = impl_from_IHTMLDOMNode2(iface);
929
930     return IHTMLDOMNode_AddRef(&This->IHTMLDOMNode_iface);
931 }
932
933 static ULONG WINAPI HTMLDOMNode2_Release(IHTMLDOMNode2 *iface)
934 {
935     HTMLDOMNode *This = impl_from_IHTMLDOMNode2(iface);
936
937     return IHTMLDOMNode_Release(&This->IHTMLDOMNode_iface);
938 }
939
940 static HRESULT WINAPI HTMLDOMNode2_GetTypeInfoCount(IHTMLDOMNode2 *iface, UINT *pctinfo)
941 {
942     HTMLDOMNode *This = impl_from_IHTMLDOMNode2(iface);
943     return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo);
944 }
945
946 static HRESULT WINAPI HTMLDOMNode2_GetTypeInfo(IHTMLDOMNode2 *iface, UINT iTInfo,
947         LCID lcid, ITypeInfo **ppTInfo)
948 {
949     HTMLDOMNode *This = impl_from_IHTMLDOMNode2(iface);
950     return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo);
951 }
952
953 static HRESULT WINAPI HTMLDOMNode2_GetIDsOfNames(IHTMLDOMNode2 *iface, REFIID riid,
954                                                 LPOLESTR *rgszNames, UINT cNames,
955                                                 LCID lcid, DISPID *rgDispId)
956 {
957     HTMLDOMNode *This = impl_from_IHTMLDOMNode2(iface);
958     return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface, riid, rgszNames, cNames,
959             lcid, rgDispId);
960 }
961
962 static HRESULT WINAPI HTMLDOMNode2_Invoke(IHTMLDOMNode2 *iface, DISPID dispIdMember,
963         REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
964         VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
965 {
966     HTMLDOMNode *This = impl_from_IHTMLDOMNode2(iface);
967     return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface, dispIdMember, riid, lcid,
968             wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
969 }
970
971 static HRESULT WINAPI HTMLDOMNode2_get_ownerDocument(IHTMLDOMNode2 *iface, IDispatch **p)
972 {
973     HTMLDOMNode *This = impl_from_IHTMLDOMNode2(iface);
974
975     TRACE("(%p)->(%p)\n", This, p);
976
977     /* FIXME: Better check for document node */
978     if(This == &This->doc->node) {
979         *p = NULL;
980     }else {
981         *p = (IDispatch*)&This->doc->basedoc.IHTMLDocument2_iface;
982         IDispatch_AddRef(*p);
983     }
984     return S_OK;
985 }
986
987 static const IHTMLDOMNode2Vtbl HTMLDOMNode2Vtbl = {
988     HTMLDOMNode2_QueryInterface,
989     HTMLDOMNode2_AddRef,
990     HTMLDOMNode2_Release,
991     HTMLDOMNode2_GetTypeInfoCount,
992     HTMLDOMNode2_GetTypeInfo,
993     HTMLDOMNode2_GetIDsOfNames,
994     HTMLDOMNode2_Invoke,
995     HTMLDOMNode2_get_ownerDocument
996 };
997
998 static nsXPCOMCycleCollectionParticipant node_ccp;
999
1000 HRESULT HTMLDOMNode_QI(HTMLDOMNode *This, REFIID riid, void **ppv)
1001 {
1002     *ppv = NULL;
1003
1004     if(IsEqualGUID(&IID_IUnknown, riid)) {
1005         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
1006         *ppv = &This->IHTMLDOMNode_iface;
1007     }else if(IsEqualGUID(&IID_IDispatch, riid)) {
1008         TRACE("(%p)->(IID_IDispatch %p)\n", This, ppv);
1009         *ppv = &This->IHTMLDOMNode_iface;
1010     }else if(IsEqualGUID(&IID_IDispatchEx, riid)) {
1011         if(This->dispex.data) {
1012             TRACE("(%p)->(IID_IDispatchEx %p)\n", This, ppv);
1013             *ppv = &This->dispex.IDispatchEx_iface;
1014         }else {
1015             FIXME("(%p)->(IID_IDispatchEx %p)\n", This, ppv);
1016             return E_NOINTERFACE;
1017         }
1018     }else if(IsEqualGUID(&IID_IHTMLDOMNode, riid)) {
1019         TRACE("(%p)->(IID_IHTMLDOMNode %p)\n", This, ppv);
1020         *ppv = &This->IHTMLDOMNode_iface;
1021     }else if(IsEqualGUID(&IID_IHTMLDOMNode2, riid)) {
1022         TRACE("(%p)->(IID_IHTMLDOMNode2 %p)\n", This, ppv);
1023         *ppv = &This->IHTMLDOMNode2_iface;
1024     }else if(IsEqualGUID(&IID_nsXPCOMCycleCollectionParticipant, riid)) {
1025         TRACE("(%p)->(IID_nsXPCOMCycleCollectionParticipant %p)\n", This, ppv);
1026         *ppv = &node_ccp;
1027         return NS_OK;
1028     }else if(IsEqualGUID(&IID_nsCycleCollectionISupports, riid)) {
1029         TRACE("(%p)->(IID_nsCycleCollectionISupports %p)\n", This, ppv);
1030         *ppv = &This->IHTMLDOMNode_iface;
1031         return NS_OK;
1032     }else if(dispex_query_interface(&This->dispex, riid, ppv)) {
1033         return *ppv ? S_OK : E_NOINTERFACE;
1034     }
1035
1036     if(*ppv) {
1037         IUnknown_AddRef((IUnknown*)*ppv);
1038         return S_OK;
1039     }
1040
1041     WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
1042     return E_NOINTERFACE;
1043 }
1044
1045 void HTMLDOMNode_destructor(HTMLDOMNode *This)
1046 {
1047     if(This->nsnode)
1048         nsIDOMNode_Release(This->nsnode);
1049     if(This->doc && &This->doc->node != This)
1050         htmldoc_release(&This->doc->basedoc);
1051     if(This->event_target)
1052         release_event_target(This->event_target);
1053 }
1054
1055 static HRESULT HTMLDOMNode_clone(HTMLDOMNode *This, nsIDOMNode *nsnode, HTMLDOMNode **ret)
1056 {
1057     return create_node(This->doc, nsnode, ret);
1058 }
1059
1060 static const NodeImplVtbl HTMLDOMNodeImplVtbl = {
1061     HTMLDOMNode_QI,
1062     HTMLDOMNode_destructor,
1063     HTMLDOMNode_clone
1064 };
1065
1066 void HTMLDOMNode_Init(HTMLDocumentNode *doc, HTMLDOMNode *node, nsIDOMNode *nsnode)
1067 {
1068     nsresult nsres;
1069
1070     node->IHTMLDOMNode_iface.lpVtbl = &HTMLDOMNodeVtbl;
1071     node->IHTMLDOMNode2_iface.lpVtbl = &HTMLDOMNode2Vtbl;
1072
1073     ccref_init(&node->ccref, 1);
1074
1075     if(&doc->node != node)
1076         htmldoc_addref(&doc->basedoc);
1077     node->doc = doc;
1078
1079     nsIDOMNode_AddRef(nsnode);
1080     node->nsnode = nsnode;
1081
1082     nsres = nsIDOMNode_SetMshtmlNode(nsnode, (nsISupports*)&node->IHTMLDOMNode_iface);
1083     assert(nsres == NS_OK);
1084 }
1085
1086 static HRESULT create_node(HTMLDocumentNode *doc, nsIDOMNode *nsnode, HTMLDOMNode **ret)
1087 {
1088     PRUint16 node_type;
1089     HRESULT hres;
1090
1091     nsIDOMNode_GetNodeType(nsnode, &node_type);
1092
1093     switch(node_type) {
1094     case ELEMENT_NODE: {
1095         HTMLElement *elem;
1096         hres = HTMLElement_Create(doc, nsnode, FALSE, &elem);
1097         if(FAILED(hres))
1098             return hres;
1099         *ret = &elem->node;
1100         break;
1101     }
1102     case TEXT_NODE:
1103         hres = HTMLDOMTextNode_Create(doc, nsnode, ret);
1104         if(FAILED(hres))
1105             return hres;
1106         break;
1107     /* doctype nodes are represented as comment nodes (at least in quirks mode) */
1108     case DOCUMENT_TYPE_NODE:
1109     case COMMENT_NODE: {
1110         HTMLElement *comment;
1111         hres = HTMLCommentElement_Create(doc, nsnode, &comment);
1112         if(FAILED(hres))
1113             return hres;
1114         *ret = &comment->node;
1115         break;
1116     }
1117     case ATTRIBUTE_NODE:
1118         ERR("Called on attribute node\n");
1119         return E_UNEXPECTED;
1120     default: {
1121         HTMLDOMNode *node;
1122
1123         node = heap_alloc_zero(sizeof(HTMLDOMNode));
1124         if(!node)
1125             return E_OUTOFMEMORY;
1126
1127         node->vtbl = &HTMLDOMNodeImplVtbl;
1128         HTMLDOMNode_Init(doc, node, nsnode);
1129         *ret = node;
1130     }
1131     }
1132
1133     TRACE("type %d ret %p\n", node_type, *ret);
1134     return S_OK;
1135 }
1136
1137 static void NSAPI HTMLDOMNode_unmark_if_purple(void *p)
1138 {
1139     HTMLDOMNode *This = impl_from_IHTMLDOMNode(p);
1140     ccref_unmark_if_purple(&This->ccref);
1141 }
1142
1143 static nsresult NSAPI HTMLDOMNode_traverse(void *ccp, void *p, nsCycleCollectionTraversalCallback *cb)
1144 {
1145     HTMLDOMNode *This = impl_from_IHTMLDOMNode(p);
1146
1147     TRACE("%p\n", This);
1148
1149     describe_cc_node(&This->ccref, "HTMLDOMNode", cb);
1150
1151     if(This->nsnode)
1152         note_cc_edge((nsISupports*)This->nsnode, "This->nsnode", cb);
1153     if(This->doc && &This->doc->node != This)
1154         note_cc_edge((nsISupports*)&This->doc->node.IHTMLDOMNode_iface, "This->doc", cb);
1155     dispex_traverse(&This->dispex, cb);
1156
1157     if(This->vtbl->traverse)
1158         This->vtbl->traverse(This, cb);
1159
1160     return NS_OK;
1161 }
1162
1163 static nsresult NSAPI HTMLDOMNode_unlink(void *p)
1164 {
1165     HTMLDOMNode *This = impl_from_IHTMLDOMNode(p);
1166
1167     TRACE("%p\n", This);
1168
1169     if(This->vtbl->unlink)
1170         This->vtbl->unlink(This);
1171
1172     dispex_unlink(&This->dispex);
1173
1174     if(This->nsnode) {
1175         nsIDOMNode *nsnode = This->nsnode;
1176         This->nsnode = NULL;
1177         nsIDOMNode_Release(nsnode);
1178     }
1179
1180     if(This->doc && &This->doc->node != This) {
1181         HTMLDocument *doc = &This->doc->basedoc;
1182         This->doc = NULL;
1183         htmldoc_release(doc);
1184     }else {
1185         This->doc = NULL;
1186     }
1187
1188     return NS_OK;
1189 }
1190
1191 void init_node_cc(void)
1192 {
1193     static const CCObjCallback node_ccp_callback = {
1194         HTMLDOMNode_unmark_if_purple,
1195         HTMLDOMNode_traverse,
1196         HTMLDOMNode_unlink
1197     };
1198
1199     ccp_init(&node_ccp, &node_ccp_callback);
1200 }
1201
1202 HRESULT get_node(HTMLDocumentNode *This, nsIDOMNode *nsnode, BOOL create, HTMLDOMNode **ret)
1203 {
1204     nsISupports *unk = NULL;
1205     nsresult nsres;
1206
1207     nsres = nsIDOMNode_GetMshtmlNode(nsnode, &unk);
1208     assert(nsres == NS_OK);
1209
1210     if(unk) {
1211         *ret = get_node_obj((IHTMLDOMNode*)unk);
1212         return NS_OK;
1213     }
1214
1215     if(!create) {
1216         *ret = NULL;
1217         return S_OK;
1218     }
1219
1220     return create_node(This, nsnode, ret);
1221 }