atl80: Added AtlComModuleRegisterServer implementation (based on AtlModuleRegisterSer...
[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         *p = 8;
391         break;
392     case DOCUMENT_NODE:
393         *p = 9;
394         break;
395     case DOCUMENT_FRAGMENT_NODE:
396         *p = 11;
397         break;
398     default:
399         /*
400          * FIXME:
401          * According to MSDN only ELEMENT_NODE and TEXT_NODE are supported.
402          * It needs more tests.
403          */
404         FIXME("type %u\n", type);
405         *p = 0;
406     }
407
408     return S_OK;
409 }
410
411 static HRESULT WINAPI HTMLDOMNode_get_parentNode(IHTMLDOMNode *iface, IHTMLDOMNode **p)
412 {
413     HTMLDOMNode *This = impl_from_IHTMLDOMNode(iface);
414     HTMLDOMNode *node;
415     nsIDOMNode *nsnode;
416     nsresult nsres;
417     HRESULT hres;
418
419     TRACE("(%p)->(%p)\n", This, p);
420
421     nsres = nsIDOMNode_GetParentNode(This->nsnode, &nsnode);
422     if(NS_FAILED(nsres)) {
423         ERR("GetParentNode failed: %08x\n", nsres);
424         return E_FAIL;
425     }
426
427     if(!nsnode) {
428         *p = NULL;
429         return S_OK;
430     }
431
432     hres = get_node(This->doc, nsnode, TRUE, &node);
433     nsIDOMNode_Release(nsnode);
434     if(FAILED(hres))
435         return hres;
436
437     *p = &node->IHTMLDOMNode_iface;
438     return S_OK;
439 }
440
441 static HRESULT WINAPI HTMLDOMNode_hasChildNodes(IHTMLDOMNode *iface, VARIANT_BOOL *fChildren)
442 {
443     HTMLDOMNode *This = impl_from_IHTMLDOMNode(iface);
444     cpp_bool has_child = FALSE;
445     nsresult nsres;
446
447     TRACE("(%p)->(%p)\n", This, fChildren);
448
449     nsres = nsIDOMNode_HasChildNodes(This->nsnode, &has_child);
450     if(NS_FAILED(nsres))
451         ERR("HasChildNodes failed: %08x\n", nsres);
452
453     *fChildren = has_child ? VARIANT_TRUE : VARIANT_FALSE;
454     return S_OK;
455 }
456
457 static HRESULT WINAPI HTMLDOMNode_get_childNodes(IHTMLDOMNode *iface, IDispatch **p)
458 {
459     HTMLDOMNode *This = impl_from_IHTMLDOMNode(iface);
460     nsIDOMNodeList *nslist;
461     nsresult nsres;
462
463     TRACE("(%p)->(%p)\n", This, p);
464
465     nsres = nsIDOMNode_GetChildNodes(This->nsnode, &nslist);
466     if(NS_FAILED(nsres)) {
467         ERR("GetChildNodes failed: %08x\n", nsres);
468         return E_FAIL;
469     }
470
471     *p = (IDispatch*)create_child_collection(This->doc, nslist);
472     nsIDOMNodeList_Release(nslist);
473
474     return *p ? S_OK : E_OUTOFMEMORY;
475 }
476
477 static HRESULT WINAPI HTMLDOMNode_get_attributes(IHTMLDOMNode *iface, IDispatch **p)
478 {
479     HTMLDOMNode *This = impl_from_IHTMLDOMNode(iface);
480     HTMLAttributeCollection *col;
481     HRESULT hres;
482
483     TRACE("(%p)->(%p)\n", This, p);
484
485     if(This->vtbl->get_attr_col) {
486         hres = This->vtbl->get_attr_col(This, &col);
487         if(FAILED(hres))
488             return hres;
489
490         *p = (IDispatch*)&col->IHTMLAttributeCollection_iface;
491         return S_OK;
492     }
493
494     *p = NULL;
495     return S_OK;
496 }
497
498 static HRESULT WINAPI HTMLDOMNode_insertBefore(IHTMLDOMNode *iface, IHTMLDOMNode *newChild,
499                                                VARIANT refChild, IHTMLDOMNode **node)
500 {
501     HTMLDOMNode *This = impl_from_IHTMLDOMNode(iface);
502     HTMLDOMNode *new_child, *node_obj, *ref_node = NULL;
503     nsIDOMNode *nsnode;
504     nsresult nsres;
505     HRESULT hres = S_OK;
506
507     TRACE("(%p)->(%p %s %p)\n", This, newChild, debugstr_variant(&refChild), node);
508
509     new_child = get_node_obj(newChild);
510     if(!new_child) {
511         ERR("invalid newChild\n");
512         return E_INVALIDARG;
513     }
514
515     switch(V_VT(&refChild)) {
516     case VT_NULL:
517         break;
518     case VT_DISPATCH: {
519         IHTMLDOMNode *ref_iface;
520
521         if(!V_DISPATCH(&refChild))
522             break;
523
524         hres = IDispatch_QueryInterface(V_DISPATCH(&refChild), &IID_IHTMLDOMNode, (void**)&ref_iface);
525         if(FAILED(hres))
526             break;
527
528         ref_node = get_node_obj(ref_iface);
529         IHTMLDOMNode_Release(ref_iface);
530         if(!ref_node) {
531             ERR("unvalid node\n");
532             hres = E_FAIL;
533             break;
534         }
535         break;
536     }
537     default:
538         FIXME("unimplemented refChild %s\n", debugstr_variant(&refChild));
539         hres = E_NOTIMPL;
540     }
541
542     if(SUCCEEDED(hres)) {
543         nsres = nsIDOMNode_InsertBefore(This->nsnode, new_child->nsnode, ref_node ? ref_node->nsnode : NULL, &nsnode);
544         if(NS_FAILED(nsres)) {
545             ERR("InsertBefore failed: %08x\n", nsres);
546             hres = E_FAIL;
547         }
548     }
549     node_release(new_child);
550     if(ref_node)
551         node_release(ref_node);
552     if(FAILED(hres))
553         return hres;
554
555     hres = get_node(This->doc, nsnode, TRUE, &node_obj);
556     nsIDOMNode_Release(nsnode);
557     if(FAILED(hres))
558         return hres;
559
560     *node = &node_obj->IHTMLDOMNode_iface;
561     return S_OK;
562 }
563
564 static HRESULT WINAPI HTMLDOMNode_removeChild(IHTMLDOMNode *iface, IHTMLDOMNode *oldChild,
565                                               IHTMLDOMNode **node)
566 {
567     HTMLDOMNode *This = impl_from_IHTMLDOMNode(iface);
568     HTMLDOMNode *node_obj;
569     nsIDOMNode *nsnode;
570     nsresult nsres;
571     HRESULT hres;
572
573     TRACE("(%p)->(%p %p)\n", This, oldChild, node);
574
575     node_obj = get_node_obj(oldChild);
576     if(!node_obj)
577         return E_FAIL;
578
579     nsres = nsIDOMNode_RemoveChild(This->nsnode, node_obj->nsnode, &nsnode);
580     node_release(node_obj);
581     if(NS_FAILED(nsres)) {
582         ERR("RemoveChild failed: %08x\n", nsres);
583         return E_FAIL;
584     }
585
586     hres = get_node(This->doc, nsnode, TRUE, &node_obj);
587     nsIDOMNode_Release(nsnode);
588     if(FAILED(hres))
589         return hres;
590
591     /* FIXME: Make sure that node != newChild */
592     *node = &node_obj->IHTMLDOMNode_iface;
593     return S_OK;
594 }
595
596 static HRESULT WINAPI HTMLDOMNode_replaceChild(IHTMLDOMNode *iface, IHTMLDOMNode *newChild,
597                                                IHTMLDOMNode *oldChild, IHTMLDOMNode **node)
598 {
599     HTMLDOMNode *This = impl_from_IHTMLDOMNode(iface);
600     HTMLDOMNode *node_new, *node_old, *ret_node;
601     nsIDOMNode *nsnode;
602     nsresult nsres;
603     HRESULT hres;
604
605     TRACE("(%p)->(%p %p %p)\n", This, newChild, oldChild, node);
606
607     node_new = get_node_obj(newChild);
608     if(!node_new)
609         return E_FAIL;
610
611     node_old = get_node_obj(oldChild);
612     if(!node_old) {
613         node_release(node_new);
614         return E_FAIL;
615     }
616
617     nsres = nsIDOMNode_ReplaceChild(This->nsnode, node_new->nsnode, node_old->nsnode, &nsnode);
618     node_release(node_new);
619     node_release(node_old);
620     if(NS_FAILED(nsres))
621         return E_FAIL;
622
623     hres = get_node(This->doc, nsnode, TRUE, &ret_node);
624     nsIDOMNode_Release(nsnode);
625     if(FAILED(hres))
626         return hres;
627
628     *node = &ret_node->IHTMLDOMNode_iface;
629     return S_OK;
630 }
631
632 static HRESULT WINAPI HTMLDOMNode_cloneNode(IHTMLDOMNode *iface, VARIANT_BOOL fDeep,
633                                             IHTMLDOMNode **clonedNode)
634 {
635     HTMLDOMNode *This = impl_from_IHTMLDOMNode(iface);
636     HTMLDOMNode *new_node;
637     nsIDOMNode *nsnode;
638     nsresult nsres;
639     HRESULT hres;
640
641     TRACE("(%p)->(%x %p)\n", This, fDeep, clonedNode);
642
643     nsres = nsIDOMNode_CloneNode(This->nsnode, fDeep != VARIANT_FALSE, 1, &nsnode);
644     if(NS_FAILED(nsres) || !nsnode) {
645         ERR("CloneNode failed: %08x\n", nsres);
646         return E_FAIL;
647     }
648
649     hres = This->vtbl->clone(This, nsnode, &new_node);
650     if(FAILED(hres))
651         return hres;
652
653     *clonedNode = &new_node->IHTMLDOMNode_iface;
654     return S_OK;
655 }
656
657 static HRESULT WINAPI HTMLDOMNode_removeNode(IHTMLDOMNode *iface, VARIANT_BOOL fDeep,
658                                              IHTMLDOMNode **removed)
659 {
660     HTMLDOMNode *This = impl_from_IHTMLDOMNode(iface);
661     FIXME("(%p)->(%x %p)\n", This, fDeep, removed);
662     return E_NOTIMPL;
663 }
664
665 static HRESULT WINAPI HTMLDOMNode_swapNode(IHTMLDOMNode *iface, IHTMLDOMNode *otherNode,
666                                            IHTMLDOMNode **swappedNode)
667 {
668     HTMLDOMNode *This = impl_from_IHTMLDOMNode(iface);
669     FIXME("(%p)->(%p %p)\n", This, otherNode, swappedNode);
670     return E_NOTIMPL;
671 }
672
673 static HRESULT WINAPI HTMLDOMNode_replaceNode(IHTMLDOMNode *iface, IHTMLDOMNode *replacement,
674                                               IHTMLDOMNode **replaced)
675 {
676     HTMLDOMNode *This = impl_from_IHTMLDOMNode(iface);
677     FIXME("(%p)->(%p %p)\n", This, replacement, replaced);
678     return E_NOTIMPL;
679 }
680
681 static HRESULT WINAPI HTMLDOMNode_appendChild(IHTMLDOMNode *iface, IHTMLDOMNode *newChild,
682                                               IHTMLDOMNode **node)
683 {
684     HTMLDOMNode *This = impl_from_IHTMLDOMNode(iface);
685     HTMLDOMNode *node_obj;
686     nsIDOMNode *nsnode;
687     nsresult nsres;
688     HRESULT hres;
689
690     TRACE("(%p)->(%p %p)\n", This, newChild, node);
691
692     node_obj = get_node_obj(newChild);
693     if(!node_obj)
694         return E_FAIL;
695
696     nsres = nsIDOMNode_AppendChild(This->nsnode, node_obj->nsnode, &nsnode);
697     node_release(node_obj);
698     if(NS_FAILED(nsres)) {
699         ERR("AppendChild failed: %08x\n", nsres);
700         return E_FAIL;
701     }
702
703     hres = get_node(This->doc, nsnode, TRUE, &node_obj);
704     nsIDOMNode_Release(nsnode);
705     if(FAILED(hres))
706         return hres;
707
708     /* FIXME: Make sure that node != newChild */
709     *node = &node_obj->IHTMLDOMNode_iface;
710     return S_OK;
711 }
712
713 static HRESULT WINAPI HTMLDOMNode_get_nodeName(IHTMLDOMNode *iface, BSTR *p)
714 {
715     HTMLDOMNode *This = impl_from_IHTMLDOMNode(iface);
716     nsAString name;
717     nsresult nsres;
718
719     TRACE("(%p)->(%p)\n", This, p);
720
721     nsAString_Init(&name, NULL);
722     nsres = nsIDOMNode_GetNodeName(This->nsnode, &name);
723     return return_nsstr(nsres, &name, p);
724 }
725
726 static HRESULT WINAPI HTMLDOMNode_put_nodeValue(IHTMLDOMNode *iface, VARIANT v)
727 {
728     HTMLDOMNode *This = impl_from_IHTMLDOMNode(iface);
729
730     TRACE("(%p)->(%s)\n", This, debugstr_variant(&v));
731
732     switch(V_VT(&v)) {
733     case VT_BSTR: {
734         nsAString val_str;
735
736         nsAString_InitDepend(&val_str, V_BSTR(&v));
737         nsIDOMNode_SetNodeValue(This->nsnode, &val_str);
738         nsAString_Finish(&val_str);
739
740         return S_OK;
741     }
742
743     default:
744         FIXME("unsupported value %s\n", debugstr_variant(&v));
745     }
746
747     return E_NOTIMPL;
748 }
749
750 static HRESULT WINAPI HTMLDOMNode_get_nodeValue(IHTMLDOMNode *iface, VARIANT *p)
751 {
752     HTMLDOMNode *This = impl_from_IHTMLDOMNode(iface);
753     const PRUnichar *val;
754     nsAString val_str;
755
756     TRACE("(%p)->(%p)\n", This, p);
757
758     nsAString_Init(&val_str, NULL);
759     nsIDOMNode_GetNodeValue(This->nsnode, &val_str);
760     nsAString_GetData(&val_str, &val);
761
762     if(*val) {
763         V_VT(p) = VT_BSTR;
764         V_BSTR(p) = SysAllocString(val);
765     }else {
766         V_VT(p) = VT_NULL;
767     }
768
769     nsAString_Finish(&val_str);
770
771     return S_OK;
772 }
773
774 static HRESULT WINAPI HTMLDOMNode_get_firstChild(IHTMLDOMNode *iface, IHTMLDOMNode **p)
775 {
776     HTMLDOMNode *This = impl_from_IHTMLDOMNode(iface);
777     nsIDOMNode *nschild = NULL;
778     HTMLDOMNode *node;
779     HRESULT hres;
780
781     TRACE("(%p)->(%p)\n", This, p);
782
783     nsIDOMNode_GetFirstChild(This->nsnode, &nschild);
784     if(!nschild) {
785         *p = NULL;
786         return S_OK;
787     }
788
789     hres = get_node(This->doc, nschild, TRUE, &node);
790     nsIDOMNode_Release(nschild);
791     if(FAILED(hres))
792         return hres;
793
794     *p = &node->IHTMLDOMNode_iface;
795     return S_OK;
796 }
797
798 static HRESULT WINAPI HTMLDOMNode_get_lastChild(IHTMLDOMNode *iface, IHTMLDOMNode **p)
799 {
800     HTMLDOMNode *This = impl_from_IHTMLDOMNode(iface);
801     nsIDOMNode *nschild = NULL;
802     HTMLDOMNode *node;
803     HRESULT hres;
804
805     TRACE("(%p)->(%p)\n", This, p);
806
807     nsIDOMNode_GetLastChild(This->nsnode, &nschild);
808     if(!nschild) {
809         *p = NULL;
810         return S_OK;
811     }
812
813     hres = get_node(This->doc, nschild, TRUE, &node);
814     nsIDOMNode_Release(nschild);
815     if(FAILED(hres))
816         return hres;
817
818     *p = &node->IHTMLDOMNode_iface;
819     return S_OK;
820 }
821
822 static HRESULT WINAPI HTMLDOMNode_get_previousSibling(IHTMLDOMNode *iface, IHTMLDOMNode **p)
823 {
824     HTMLDOMNode *This = impl_from_IHTMLDOMNode(iface);
825     nsIDOMNode *nschild = NULL;
826     HTMLDOMNode *node;
827     HRESULT hres;
828
829     TRACE("(%p)->(%p)\n", This, p);
830
831     nsIDOMNode_GetPreviousSibling(This->nsnode, &nschild);
832     if(!nschild) {
833         *p = NULL;
834         return S_OK;
835     }
836
837     hres = get_node(This->doc, nschild, TRUE, &node);
838     nsIDOMNode_Release(nschild);
839     if(FAILED(hres))
840         return hres;
841
842     *p = &node->IHTMLDOMNode_iface;
843     return S_OK;
844 }
845
846 static HRESULT WINAPI HTMLDOMNode_get_nextSibling(IHTMLDOMNode *iface, IHTMLDOMNode **p)
847 {
848     HTMLDOMNode *This = impl_from_IHTMLDOMNode(iface);
849     nsIDOMNode *nssibling = NULL;
850     HTMLDOMNode *node;
851     HRESULT hres;
852
853     TRACE("(%p)->(%p)\n", This, p);
854
855     nsIDOMNode_GetNextSibling(This->nsnode, &nssibling);
856     if(!nssibling) {
857         *p = NULL;
858         return S_OK;
859     }
860
861     hres = get_node(This->doc, nssibling, TRUE, &node);
862     nsIDOMNode_Release(nssibling);
863     if(FAILED(hres))
864         return hres;
865
866     *p = &node->IHTMLDOMNode_iface;
867     return S_OK;
868 }
869
870 static const IHTMLDOMNodeVtbl HTMLDOMNodeVtbl = {
871     HTMLDOMNode_QueryInterface,
872     HTMLDOMNode_AddRef,
873     HTMLDOMNode_Release,
874     HTMLDOMNode_GetTypeInfoCount,
875     HTMLDOMNode_GetTypeInfo,
876     HTMLDOMNode_GetIDsOfNames,
877     HTMLDOMNode_Invoke,
878     HTMLDOMNode_get_nodeType,
879     HTMLDOMNode_get_parentNode,
880     HTMLDOMNode_hasChildNodes,
881     HTMLDOMNode_get_childNodes,
882     HTMLDOMNode_get_attributes,
883     HTMLDOMNode_insertBefore,
884     HTMLDOMNode_removeChild,
885     HTMLDOMNode_replaceChild,
886     HTMLDOMNode_cloneNode,
887     HTMLDOMNode_removeNode,
888     HTMLDOMNode_swapNode,
889     HTMLDOMNode_replaceNode,
890     HTMLDOMNode_appendChild,
891     HTMLDOMNode_get_nodeName,
892     HTMLDOMNode_put_nodeValue,
893     HTMLDOMNode_get_nodeValue,
894     HTMLDOMNode_get_firstChild,
895     HTMLDOMNode_get_lastChild,
896     HTMLDOMNode_get_previousSibling,
897     HTMLDOMNode_get_nextSibling
898 };
899
900 static HTMLDOMNode *get_node_obj(IHTMLDOMNode *iface)
901 {
902     HTMLDOMNode *ret;
903
904     if(iface->lpVtbl != &HTMLDOMNodeVtbl)
905         return NULL;
906
907     ret = impl_from_IHTMLDOMNode(iface);
908     node_addref(ret);
909     return ret;
910 }
911
912 static inline HTMLDOMNode *impl_from_IHTMLDOMNode2(IHTMLDOMNode2 *iface)
913 {
914     return CONTAINING_RECORD(iface, HTMLDOMNode, IHTMLDOMNode2_iface);
915 }
916
917 static HRESULT WINAPI HTMLDOMNode2_QueryInterface(IHTMLDOMNode2 *iface,
918         REFIID riid, void **ppv)
919 {
920     HTMLDOMNode *This = impl_from_IHTMLDOMNode2(iface);
921
922     return IHTMLDOMNode_QueryInterface(&This->IHTMLDOMNode_iface, riid, ppv);
923 }
924
925 static ULONG WINAPI HTMLDOMNode2_AddRef(IHTMLDOMNode2 *iface)
926 {
927     HTMLDOMNode *This = impl_from_IHTMLDOMNode2(iface);
928
929     return IHTMLDOMNode_AddRef(&This->IHTMLDOMNode_iface);
930 }
931
932 static ULONG WINAPI HTMLDOMNode2_Release(IHTMLDOMNode2 *iface)
933 {
934     HTMLDOMNode *This = impl_from_IHTMLDOMNode2(iface);
935
936     return IHTMLDOMNode_Release(&This->IHTMLDOMNode_iface);
937 }
938
939 static HRESULT WINAPI HTMLDOMNode2_GetTypeInfoCount(IHTMLDOMNode2 *iface, UINT *pctinfo)
940 {
941     HTMLDOMNode *This = impl_from_IHTMLDOMNode2(iface);
942     return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo);
943 }
944
945 static HRESULT WINAPI HTMLDOMNode2_GetTypeInfo(IHTMLDOMNode2 *iface, UINT iTInfo,
946         LCID lcid, ITypeInfo **ppTInfo)
947 {
948     HTMLDOMNode *This = impl_from_IHTMLDOMNode2(iface);
949     return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo);
950 }
951
952 static HRESULT WINAPI HTMLDOMNode2_GetIDsOfNames(IHTMLDOMNode2 *iface, REFIID riid,
953                                                 LPOLESTR *rgszNames, UINT cNames,
954                                                 LCID lcid, DISPID *rgDispId)
955 {
956     HTMLDOMNode *This = impl_from_IHTMLDOMNode2(iface);
957     return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface, riid, rgszNames, cNames,
958             lcid, rgDispId);
959 }
960
961 static HRESULT WINAPI HTMLDOMNode2_Invoke(IHTMLDOMNode2 *iface, DISPID dispIdMember,
962         REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
963         VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
964 {
965     HTMLDOMNode *This = impl_from_IHTMLDOMNode2(iface);
966     return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface, dispIdMember, riid, lcid,
967             wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
968 }
969
970 static HRESULT WINAPI HTMLDOMNode2_get_ownerDocument(IHTMLDOMNode2 *iface, IDispatch **p)
971 {
972     HTMLDOMNode *This = impl_from_IHTMLDOMNode2(iface);
973
974     TRACE("(%p)->(%p)\n", This, p);
975
976     /* FIXME: Better check for document node */
977     if(This == &This->doc->node) {
978         *p = NULL;
979     }else {
980         *p = (IDispatch*)&This->doc->basedoc.IHTMLDocument2_iface;
981         IDispatch_AddRef(*p);
982     }
983     return S_OK;
984 }
985
986 static const IHTMLDOMNode2Vtbl HTMLDOMNode2Vtbl = {
987     HTMLDOMNode2_QueryInterface,
988     HTMLDOMNode2_AddRef,
989     HTMLDOMNode2_Release,
990     HTMLDOMNode2_GetTypeInfoCount,
991     HTMLDOMNode2_GetTypeInfo,
992     HTMLDOMNode2_GetIDsOfNames,
993     HTMLDOMNode2_Invoke,
994     HTMLDOMNode2_get_ownerDocument
995 };
996
997 static nsXPCOMCycleCollectionParticipant node_ccp;
998
999 HRESULT HTMLDOMNode_QI(HTMLDOMNode *This, REFIID riid, void **ppv)
1000 {
1001     *ppv = NULL;
1002
1003     if(IsEqualGUID(&IID_IUnknown, riid)) {
1004         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
1005         *ppv = &This->IHTMLDOMNode_iface;
1006     }else if(IsEqualGUID(&IID_IDispatch, riid)) {
1007         TRACE("(%p)->(IID_IDispatch %p)\n", This, ppv);
1008         *ppv = &This->IHTMLDOMNode_iface;
1009     }else if(IsEqualGUID(&IID_IDispatchEx, riid)) {
1010         if(This->dispex.data) {
1011             TRACE("(%p)->(IID_IDispatchEx %p)\n", This, ppv);
1012             *ppv = &This->dispex.IDispatchEx_iface;
1013         }else {
1014             FIXME("(%p)->(IID_IDispatchEx %p)\n", This, ppv);
1015             return E_NOINTERFACE;
1016         }
1017     }else if(IsEqualGUID(&IID_IHTMLDOMNode, riid)) {
1018         TRACE("(%p)->(IID_IHTMLDOMNode %p)\n", This, ppv);
1019         *ppv = &This->IHTMLDOMNode_iface;
1020     }else if(IsEqualGUID(&IID_IHTMLDOMNode2, riid)) {
1021         TRACE("(%p)->(IID_IHTMLDOMNode2 %p)\n", This, ppv);
1022         *ppv = &This->IHTMLDOMNode2_iface;
1023     }else if(IsEqualGUID(&IID_nsXPCOMCycleCollectionParticipant, riid)) {
1024         TRACE("(%p)->(IID_nsXPCOMCycleCollectionParticipant %p)\n", This, ppv);
1025         *ppv = &node_ccp;
1026         return NS_OK;
1027     }else if(IsEqualGUID(&IID_nsCycleCollectionISupports, riid)) {
1028         TRACE("(%p)->(IID_nsCycleCollectionISupports %p)\n", This, ppv);
1029         *ppv = &This->IHTMLDOMNode_iface;
1030         return NS_OK;
1031     }else if(dispex_query_interface(&This->dispex, riid, ppv)) {
1032         return *ppv ? S_OK : E_NOINTERFACE;
1033     }
1034
1035     if(*ppv) {
1036         IUnknown_AddRef((IUnknown*)*ppv);
1037         return S_OK;
1038     }
1039
1040     WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
1041     return E_NOINTERFACE;
1042 }
1043
1044 void HTMLDOMNode_destructor(HTMLDOMNode *This)
1045 {
1046     if(This->nsnode)
1047         nsIDOMNode_Release(This->nsnode);
1048     if(This->doc && &This->doc->node != This)
1049         htmldoc_release(&This->doc->basedoc);
1050     if(This->event_target)
1051         release_event_target(This->event_target);
1052 }
1053
1054 static HRESULT HTMLDOMNode_clone(HTMLDOMNode *This, nsIDOMNode *nsnode, HTMLDOMNode **ret)
1055 {
1056     return create_node(This->doc, nsnode, ret);
1057 }
1058
1059 static const NodeImplVtbl HTMLDOMNodeImplVtbl = {
1060     HTMLDOMNode_QI,
1061     HTMLDOMNode_destructor,
1062     HTMLDOMNode_clone
1063 };
1064
1065 void HTMLDOMNode_Init(HTMLDocumentNode *doc, HTMLDOMNode *node, nsIDOMNode *nsnode)
1066 {
1067     nsresult nsres;
1068
1069     node->IHTMLDOMNode_iface.lpVtbl = &HTMLDOMNodeVtbl;
1070     node->IHTMLDOMNode2_iface.lpVtbl = &HTMLDOMNode2Vtbl;
1071
1072     ccref_init(&node->ccref, 1);
1073
1074     if(&doc->node != node)
1075         htmldoc_addref(&doc->basedoc);
1076     node->doc = doc;
1077
1078     nsIDOMNode_AddRef(nsnode);
1079     node->nsnode = nsnode;
1080
1081     nsres = nsIDOMNode_SetMshtmlNode(nsnode, (nsISupports*)&node->IHTMLDOMNode_iface);
1082     assert(nsres == NS_OK);
1083 }
1084
1085 static HRESULT create_node(HTMLDocumentNode *doc, nsIDOMNode *nsnode, HTMLDOMNode **ret)
1086 {
1087     PRUint16 node_type;
1088     HRESULT hres;
1089
1090     nsIDOMNode_GetNodeType(nsnode, &node_type);
1091
1092     switch(node_type) {
1093     case ELEMENT_NODE: {
1094         HTMLElement *elem;
1095         hres = HTMLElement_Create(doc, nsnode, FALSE, &elem);
1096         if(FAILED(hres))
1097             return hres;
1098         *ret = &elem->node;
1099         break;
1100     }
1101     case TEXT_NODE:
1102         hres = HTMLDOMTextNode_Create(doc, nsnode, ret);
1103         if(FAILED(hres))
1104             return hres;
1105         break;
1106     case COMMENT_NODE: {
1107         HTMLElement *comment;
1108         hres = HTMLCommentElement_Create(doc, nsnode, &comment);
1109         if(FAILED(hres))
1110             return hres;
1111         *ret = &comment->node;
1112         break;
1113     }
1114     case ATTRIBUTE_NODE:
1115         ERR("Called on attribute node\n");
1116         return E_UNEXPECTED;
1117     default: {
1118         HTMLDOMNode *node;
1119
1120         node = heap_alloc_zero(sizeof(HTMLDOMNode));
1121         if(!node)
1122             return E_OUTOFMEMORY;
1123
1124         node->vtbl = &HTMLDOMNodeImplVtbl;
1125         HTMLDOMNode_Init(doc, node, nsnode);
1126         *ret = node;
1127     }
1128     }
1129
1130     TRACE("type %d ret %p\n", node_type, *ret);
1131     return S_OK;
1132 }
1133
1134 static void NSAPI HTMLDOMNode_unmark_if_purple(void *p)
1135 {
1136     HTMLDOMNode *This = impl_from_IHTMLDOMNode(p);
1137     ccref_unmark_if_purple(&This->ccref);
1138 }
1139
1140 static nsresult NSAPI HTMLDOMNode_traverse(void *ccp, void *p, nsCycleCollectionTraversalCallback *cb)
1141 {
1142     HTMLDOMNode *This = impl_from_IHTMLDOMNode(p);
1143
1144     TRACE("%p\n", This);
1145
1146     describe_cc_node(&This->ccref, sizeof(*This), "HTMLDOMNode", cb);
1147
1148     if(This->nsnode)
1149         note_cc_edge((nsISupports*)This->nsnode, "This->nsnode", cb);
1150     if(This->doc && &This->doc->node != This)
1151         note_cc_edge((nsISupports*)&This->doc->node.IHTMLDOMNode_iface, "This->doc", cb);
1152     dispex_traverse(&This->dispex, cb);
1153
1154     if(This->vtbl->traverse)
1155         This->vtbl->traverse(This, cb);
1156
1157     return NS_OK;
1158 }
1159
1160 static nsresult NSAPI HTMLDOMNode_unlink(void *p)
1161 {
1162     HTMLDOMNode *This = impl_from_IHTMLDOMNode(p);
1163
1164     TRACE("%p\n", This);
1165
1166     if(This->vtbl->unlink)
1167         This->vtbl->unlink(This);
1168
1169     dispex_unlink(&This->dispex);
1170
1171     if(This->nsnode) {
1172         nsIDOMNode *nsnode = This->nsnode;
1173         This->nsnode = NULL;
1174         nsIDOMNode_Release(nsnode);
1175     }
1176
1177     if(This->doc && &This->doc->node != This) {
1178         HTMLDocument *doc = &This->doc->basedoc;
1179         This->doc = NULL;
1180         htmldoc_release(doc);
1181     }else {
1182         This->doc = NULL;
1183     }
1184
1185     return NS_OK;
1186 }
1187
1188 void init_node_cc(void)
1189 {
1190     static const CCObjCallback node_ccp_callback = {
1191         HTMLDOMNode_unmark_if_purple,
1192         HTMLDOMNode_traverse,
1193         HTMLDOMNode_unlink
1194     };
1195
1196     ccp_init(&node_ccp, &node_ccp_callback);
1197 }
1198
1199 HRESULT get_node(HTMLDocumentNode *This, nsIDOMNode *nsnode, BOOL create, HTMLDOMNode **ret)
1200 {
1201     nsISupports *unk = NULL;
1202     nsresult nsres;
1203
1204     nsres = nsIDOMNode_GetMshtmlNode(nsnode, &unk);
1205     assert(nsres == NS_OK);
1206
1207     if(unk) {
1208         *ret = get_node_obj((IHTMLDOMNode*)unk);
1209         return NS_OK;
1210     }
1211
1212     if(!create) {
1213         *ret = NULL;
1214         return S_OK;
1215     }
1216
1217     return create_node(This, nsnode, ret);
1218 }