mshtml: Added better error handling to nscolor_to_str.
[wine] / dlls / mshtml / htmlbody.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 <stdio.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
33 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
34
35 typedef struct {
36     HTMLTextContainer textcont;
37
38     const IHTMLBodyElementVtbl *lpHTMLBodyElementVtbl;
39
40     ConnectionPoint cp_propnotif;
41
42     nsIDOMHTMLBodyElement *nsbody;
43 } HTMLBodyElement;
44
45 #define HTMLBODY(x)  (&(x)->lpHTMLBodyElementVtbl)
46
47 static const WCHAR aquaW[] = {'a','q','u','a',0};
48 static const WCHAR blackW[] = {'b','l','a','c','k',0};
49 static const WCHAR blueW[] = {'b','l','u','e',0};
50 static const WCHAR fuchsiaW[] = {'f','u','s','h','s','i','a',0};
51 static const WCHAR grayW[] = {'g','r','a','y',0};
52 static const WCHAR greenW[] = {'g','r','e','e','n',0};
53 static const WCHAR limeW[] = {'l','i','m','e',0};
54 static const WCHAR maroonW[] = {'m','a','r','o','o','n',0};
55 static const WCHAR navyW[] = {'n','a','v','y',0};
56 static const WCHAR oliveW[] = {'o','l','i','v','e',0};
57 static const WCHAR purpleW[] = {'p','u','r','p','l','e',0};
58 static const WCHAR redW[] = {'r','e','d',0};
59 static const WCHAR silverW[] = {'s','i','l','v','e','r',0};
60 static const WCHAR tealW[] = {'t','e','a','l',0};
61 static const WCHAR whiteW[] = {'w','h','i','t','e',0};
62 static const WCHAR yellowW[] = {'y','e','l','l','o','w',0};
63
64 static const struct {
65     LPCWSTR keyword;
66     const WCHAR hexstr[8];
67 } keyword_table[] = {
68     {aquaW,     {'#','0','0','f','f','f','f',0}},
69     {blackW,    {'#','0','0','0','0','0','0',0}},
70     {blueW,     {'#','0','0','0','0','f','f',0}},
71     {fuchsiaW,  {'#','f','f','0','0','f','f',0}},
72     {grayW,     {'#','8','0','8','0','8','0',0}},
73     {greenW,    {'#','0','0','8','0','0','0',0}},
74     {limeW,     {'#','0','0','f','f','0','0',0}},
75     {maroonW,   {'#','8','0','0','0','0','0',0}},
76     {navyW,     {'#','0','0','0','0','8','0',0}},
77     {oliveW,    {'#','8','0','8','0','0','0',0}},
78     {purpleW,   {'#','8','0','0','0','8','0',0}},
79     {redW,      {'#','f','f','0','0','0','0',0}},
80     {silverW,   {'#','c','0','c','0','c','0',0}},
81     {tealW,     {'#','0','0','8','0','8','0',0}},
82     {whiteW,    {'#','f','f','f','f','f','f',0}},
83     {yellowW,   {'#','f','f','f','f','0','0',0}}
84 };
85
86 static HRESULT nscolor_to_str(LPCWSTR color, BSTR *ret)
87 {
88     int i;
89
90     if(!color || *color == '#') {
91         *ret = SysAllocString(color);
92         return *ret ? S_OK : E_OUTOFMEMORY;
93     }
94
95     for(i=0; i < sizeof(keyword_table)/sizeof(keyword_table[0]); i++) {
96         if(!strcmpiW(color, keyword_table[i].keyword)) {
97             *ret = SysAllocString(keyword_table[i].hexstr);
98             return *ret ? S_OK : E_OUTOFMEMORY;
99         }
100     }
101
102     WARN("unknown color %s\n", debugstr_w(color));
103     *ret = SysAllocString(color);
104     return *ret ? S_OK : E_OUTOFMEMORY;
105 }
106
107 static BOOL variant_to_nscolor(const VARIANT *v, nsAString *nsstr)
108 {
109     switch(V_VT(v)) {
110     case VT_BSTR:
111         nsAString_Init(nsstr, V_BSTR(v));
112         return TRUE;
113
114     case VT_I4: {
115         PRUnichar buf[10];
116         static const WCHAR formatW[] = {'#','%','x',0};
117
118         wsprintfW(buf, formatW, V_I4(v));
119         nsAString_Init(nsstr, buf);
120         return TRUE;
121     }
122
123     default:
124         FIXME("invalid vt=%d\n", V_VT(v));
125     }
126
127     return FALSE;
128
129 }
130
131 static void nscolor_to_variant(const nsAString *nsstr, VARIANT *p)
132 {
133     const PRUnichar *color;
134
135     nsAString_GetData(nsstr, &color);
136
137     if(*color == '#') {
138         V_VT(p) = VT_I4;
139         V_I4(p) = strtolW(color+1, NULL, 16);
140     }else {
141         V_VT(p) = VT_BSTR;
142         V_BSTR(p) = SysAllocString(color);
143     }
144 }
145
146 #define HTMLBODY_THIS(iface) DEFINE_THIS(HTMLBodyElement, HTMLBodyElement, iface)
147
148 static HRESULT WINAPI HTMLBodyElement_QueryInterface(IHTMLBodyElement *iface,
149                                                      REFIID riid, void **ppv)
150 {
151     HTMLBodyElement *This = HTMLBODY_THIS(iface);
152
153     return IHTMLDOMNode_QueryInterface(HTMLDOMNODE(&This->textcont.element.node), riid, ppv);
154 }
155
156 static ULONG WINAPI HTMLBodyElement_AddRef(IHTMLBodyElement *iface)
157 {
158     HTMLBodyElement *This = HTMLBODY_THIS(iface);
159
160     return IHTMLDOMNode_AddRef(HTMLDOMNODE(&This->textcont.element.node));
161 }
162
163 static ULONG WINAPI HTMLBodyElement_Release(IHTMLBodyElement *iface)
164 {
165     HTMLBodyElement *This = HTMLBODY_THIS(iface);
166
167     return IHTMLDOMNode_Release(HTMLDOMNODE(&This->textcont.element.node));
168 }
169
170 static HRESULT WINAPI HTMLBodyElement_GetTypeInfoCount(IHTMLBodyElement *iface, UINT *pctinfo)
171 {
172     HTMLBodyElement *This = HTMLBODY_THIS(iface);
173     return IDispatchEx_GetTypeInfoCount(DISPATCHEX(&This->textcont.element.node.dispex), pctinfo);
174 }
175
176 static HRESULT WINAPI HTMLBodyElement_GetTypeInfo(IHTMLBodyElement *iface, UINT iTInfo,
177                                               LCID lcid, ITypeInfo **ppTInfo)
178 {
179     HTMLBodyElement *This = HTMLBODY_THIS(iface);
180     return IDispatchEx_GetTypeInfo(DISPATCHEX(&This->textcont.element.node.dispex), iTInfo, lcid, ppTInfo);
181 }
182
183 static HRESULT WINAPI HTMLBodyElement_GetIDsOfNames(IHTMLBodyElement *iface, REFIID riid,
184                                                 LPOLESTR *rgszNames, UINT cNames,
185                                                 LCID lcid, DISPID *rgDispId)
186 {
187     HTMLBodyElement *This = HTMLBODY_THIS(iface);
188     return IDispatchEx_GetIDsOfNames(DISPATCHEX(&This->textcont.element.node.dispex), riid, rgszNames, cNames, lcid, rgDispId);
189 }
190
191 static HRESULT WINAPI HTMLBodyElement_Invoke(IHTMLBodyElement *iface, DISPID dispIdMember,
192                             REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
193                             VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
194 {
195     HTMLBodyElement *This = HTMLBODY_THIS(iface);
196     return IDispatchEx_Invoke(DISPATCHEX(&This->textcont.element.node.dispex), dispIdMember, riid, lcid,
197             wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
198 }
199
200 static HRESULT WINAPI HTMLBodyElement_put_background(IHTMLBodyElement *iface, BSTR v)
201 {
202     HTMLBodyElement *This = HTMLBODY_THIS(iface);
203     HRESULT hr = S_OK;
204     nsAString nsstr;
205     nsresult nsres;
206
207     TRACE("(%p)->(%s)\n", This, debugstr_w(v));
208
209     nsAString_Init(&nsstr, v);
210
211     nsres = nsIDOMHTMLBodyElement_SetBackground(This->nsbody, &nsstr);
212     if(!NS_SUCCEEDED(nsres))
213     {
214         hr = E_FAIL;
215     }
216
217     nsAString_Finish(&nsstr);
218
219     return hr;
220 }
221
222 static HRESULT WINAPI HTMLBodyElement_get_background(IHTMLBodyElement *iface, BSTR *p)
223 {
224     HTMLBodyElement *This = HTMLBODY_THIS(iface);
225     nsAString background_str;
226     nsresult nsres;
227
228     TRACE("(%p)->(%p)\n", This, p);
229
230     nsAString_Init(&background_str, NULL);
231
232     nsres = nsIDOMHTMLBodyElement_GetBackground(This->nsbody, &background_str);
233     if(NS_SUCCEEDED(nsres)) {
234         const PRUnichar *background;
235         nsAString_GetData(&background_str, &background);
236         *p = *background ? SysAllocString(background) : NULL;
237     }else {
238         ERR("GetBackground failed: %08x\n", nsres);
239         *p = NULL;
240     }
241
242     nsAString_Finish(&background_str);
243
244     TRACE("*p = %s\n", debugstr_w(*p));
245     return S_OK;
246 }
247
248 static HRESULT WINAPI HTMLBodyElement_put_bgProperties(IHTMLBodyElement *iface, BSTR v)
249 {
250     HTMLBodyElement *This = HTMLBODY_THIS(iface);
251     FIXME("(%p)->(%s)\n", This, debugstr_w(v));
252     return E_NOTIMPL;
253 }
254
255 static HRESULT WINAPI HTMLBodyElement_get_bgProperties(IHTMLBodyElement *iface, BSTR *p)
256 {
257     HTMLBodyElement *This = HTMLBODY_THIS(iface);
258     FIXME("(%p)->(%p)\n", This, p);
259     return E_NOTIMPL;
260 }
261
262 static HRESULT WINAPI HTMLBodyElement_put_leftMargin(IHTMLBodyElement *iface, VARIANT v)
263 {
264     HTMLBodyElement *This = HTMLBODY_THIS(iface);
265     FIXME("(%p)->()\n", This);
266     return E_NOTIMPL;
267 }
268
269 static HRESULT WINAPI HTMLBodyElement_get_leftMargin(IHTMLBodyElement *iface, VARIANT *p)
270 {
271     HTMLBodyElement *This = HTMLBODY_THIS(iface);
272     FIXME("(%p)->(%p)\n", This, p);
273     return E_NOTIMPL;
274 }
275
276 static HRESULT WINAPI HTMLBodyElement_put_topMargin(IHTMLBodyElement *iface, VARIANT v)
277 {
278     HTMLBodyElement *This = HTMLBODY_THIS(iface);
279     FIXME("(%p)->()\n", This);
280     return E_NOTIMPL;
281 }
282
283 static HRESULT WINAPI HTMLBodyElement_get_topMargin(IHTMLBodyElement *iface, VARIANT *p)
284 {
285     HTMLBodyElement *This = HTMLBODY_THIS(iface);
286     FIXME("(%p)->(%p)\n", This, p);
287     return E_NOTIMPL;
288 }
289
290 static HRESULT WINAPI HTMLBodyElement_put_rightMargin(IHTMLBodyElement *iface, VARIANT v)
291 {
292     HTMLBodyElement *This = HTMLBODY_THIS(iface);
293     FIXME("(%p)->()\n", This);
294     return E_NOTIMPL;
295 }
296
297 static HRESULT WINAPI HTMLBodyElement_get_rightMargin(IHTMLBodyElement *iface, VARIANT *p)
298 {
299     HTMLBodyElement *This = HTMLBODY_THIS(iface);
300     FIXME("(%p)->(%p)\n", This, p);
301     return E_NOTIMPL;
302 }
303
304 static HRESULT WINAPI HTMLBodyElement_put_bottomMargin(IHTMLBodyElement *iface, VARIANT v)
305 {
306     HTMLBodyElement *This = HTMLBODY_THIS(iface);
307     FIXME("(%p)->()\n", This);
308     return E_NOTIMPL;
309 }
310
311 static HRESULT WINAPI HTMLBodyElement_get_bottomMargin(IHTMLBodyElement *iface, VARIANT *p)
312 {
313     HTMLBodyElement *This = HTMLBODY_THIS(iface);
314     FIXME("(%p)->(%p)\n", This, p);
315     return E_NOTIMPL;
316 }
317
318 static HRESULT WINAPI HTMLBodyElement_put_noWrap(IHTMLBodyElement *iface, VARIANT_BOOL v)
319 {
320     HTMLBodyElement *This = HTMLBODY_THIS(iface);
321     FIXME("(%p)->(%x)\n", This, v);
322     return E_NOTIMPL;
323 }
324
325 static HRESULT WINAPI HTMLBodyElement_get_noWrap(IHTMLBodyElement *iface, VARIANT_BOOL *p)
326 {
327     HTMLBodyElement *This = HTMLBODY_THIS(iface);
328     FIXME("(%p)->(%p)\n", This, p);
329     return E_NOTIMPL;
330 }
331
332 static HRESULT WINAPI HTMLBodyElement_put_bgColor(IHTMLBodyElement *iface, VARIANT v)
333 {
334     HTMLBodyElement *This = HTMLBODY_THIS(iface);
335     nsAString strColor;
336     nsresult nsres;
337
338     TRACE("(%p)->()\n", This);
339
340     if(!variant_to_nscolor(&v, &strColor))
341         return S_OK;
342
343     nsres = nsIDOMHTMLBodyElement_SetBgColor(This->nsbody, &strColor);
344     nsAString_Finish(&strColor);
345     if(NS_FAILED(nsres))
346         ERR("SetBgColor failed: %08x\n", nsres);
347
348     return S_OK;
349 }
350
351 static HRESULT WINAPI HTMLBodyElement_get_bgColor(IHTMLBodyElement *iface, VARIANT *p)
352 {
353     HTMLBodyElement *This = HTMLBODY_THIS(iface);
354     nsAString strColor;
355     nsresult nsres;
356     HRESULT hres;
357
358     TRACE("(%p)->(%p)\n", This, p);
359
360     nsAString_Init(&strColor, NULL);
361     nsres = nsIDOMHTMLBodyElement_GetBgColor(This->nsbody, &strColor);
362     if(NS_SUCCEEDED(nsres)) {
363         const PRUnichar *color;
364
365         nsAString_GetData(&strColor, &color);
366         V_VT(p) = VT_BSTR;
367         hres = nscolor_to_str(color, &V_BSTR(p));
368     }else {
369         ERR("SetBgColor failed: %08x\n", nsres);
370         hres = E_FAIL;
371     }
372
373     nsAString_Finish(&strColor);
374     return hres;
375 }
376
377 static HRESULT WINAPI HTMLBodyElement_put_text(IHTMLBodyElement *iface, VARIANT v)
378 {
379     HTMLBodyElement *This = HTMLBODY_THIS(iface);
380     nsAString text;
381     nsresult nsres;
382
383     TRACE("(%p)->(v%d)\n", This, V_VT(&v));
384
385     if(!variant_to_nscolor(&v, &text))
386         return S_OK;
387
388     nsres = nsIDOMHTMLBodyElement_SetText(This->nsbody, &text);
389     nsAString_Finish(&text);
390
391     return S_OK;
392 }
393
394 static HRESULT WINAPI HTMLBodyElement_get_text(IHTMLBodyElement *iface, VARIANT *p)
395 {
396     HTMLBodyElement *This = HTMLBODY_THIS(iface);
397     nsAString text;
398     nsresult nsres;
399
400     TRACE("(%p)->(%p)\n", This, p);
401
402     nsAString_Init(&text, NULL);
403
404     V_VT(p) = VT_BSTR;
405     V_BSTR(p) = NULL;
406
407     nsres = nsIDOMHTMLBodyElement_GetText(This->nsbody, &text);
408     if(NS_SUCCEEDED(nsres))
409     {
410         const PRUnichar *sText;
411         nsAString_GetData(&text, &sText);
412
413         V_VT(p) = VT_BSTR;
414         V_BSTR(p) = SysAllocString(sText);
415     }
416
417     nsAString_Finish(&text);
418
419     return S_OK;
420 }
421
422 static HRESULT WINAPI HTMLBodyElement_put_link(IHTMLBodyElement *iface, VARIANT v)
423 {
424     HTMLBodyElement *This = HTMLBODY_THIS(iface);
425     nsAString link_str;
426     nsresult nsres;
427
428     TRACE("(%p)->(v%d)\n", This, V_VT(&v));
429
430     if(!variant_to_nscolor(&v, &link_str))
431         return S_OK;
432
433     nsres = nsIDOMHTMLBodyElement_SetLink(This->nsbody, &link_str);
434     nsAString_Finish(&link_str);
435     if(NS_FAILED(nsres))
436         ERR("SetLink failed: %08x\n", nsres);
437
438     return S_OK;
439 }
440
441 static HRESULT WINAPI HTMLBodyElement_get_link(IHTMLBodyElement *iface, VARIANT *p)
442 {
443     HTMLBodyElement *This = HTMLBODY_THIS(iface);
444     nsAString link_str;
445     nsresult nsres;
446
447     TRACE("(%p)->(%p)\n", This, p);
448
449     nsAString_Init(&link_str, NULL);
450     nsres = nsIDOMHTMLBodyElement_GetLink(This->nsbody, &link_str);
451     if(NS_FAILED(nsres))
452         ERR("GetLink failed: %08x\n", nsres);
453
454     nscolor_to_variant(&link_str, p);
455     nsAString_Finish(&link_str);
456
457     return S_OK;
458 }
459
460 static HRESULT WINAPI HTMLBodyElement_put_vLink(IHTMLBodyElement *iface, VARIANT v)
461 {
462     HTMLBodyElement *This = HTMLBODY_THIS(iface);
463     nsAString vlink_str;
464     nsresult nsres;
465
466     TRACE("(%p)->(v%d)\n", This, V_VT(&v));
467
468     if(!variant_to_nscolor(&v, &vlink_str))
469         return S_OK;
470
471     nsres = nsIDOMHTMLBodyElement_SetVLink(This->nsbody, &vlink_str);
472     nsAString_Finish(&vlink_str);
473     if(NS_FAILED(nsres))
474         ERR("SetLink failed: %08x\n", nsres);
475
476     return S_OK;
477 }
478
479 static HRESULT WINAPI HTMLBodyElement_get_vLink(IHTMLBodyElement *iface, VARIANT *p)
480 {
481     HTMLBodyElement *This = HTMLBODY_THIS(iface);
482     nsAString vlink_str;
483     nsresult nsres;
484
485     TRACE("(%p)->(%p)\n", This, p);
486
487     nsAString_Init(&vlink_str, NULL);
488     nsres = nsIDOMHTMLBodyElement_GetVLink(This->nsbody, &vlink_str);
489     if(NS_FAILED(nsres))
490         ERR("GetLink failed: %08x\n", nsres);
491
492     nscolor_to_variant(&vlink_str, p);
493     nsAString_Finish(&vlink_str);
494
495     return S_OK;
496 }
497
498 static HRESULT WINAPI HTMLBodyElement_put_aLink(IHTMLBodyElement *iface, VARIANT v)
499 {
500     HTMLBodyElement *This = HTMLBODY_THIS(iface);
501     nsAString alink_str;
502     nsresult nsres;
503
504     TRACE("(%p)->(v%d)\n", This, V_VT(&v));
505
506     if(!variant_to_nscolor(&v, &alink_str))
507         return S_OK;
508
509     nsres = nsIDOMHTMLBodyElement_SetALink(This->nsbody, &alink_str);
510     nsAString_Finish(&alink_str);
511     if(NS_FAILED(nsres))
512         ERR("SetALink failed: %08x\n", nsres);
513
514     return S_OK;
515 }
516
517 static HRESULT WINAPI HTMLBodyElement_get_aLink(IHTMLBodyElement *iface, VARIANT *p)
518 {
519     HTMLBodyElement *This = HTMLBODY_THIS(iface);
520     nsAString alink_str;
521     nsresult nsres;
522
523     TRACE("(%p)->(%p)\n", This, p);
524
525     nsAString_Init(&alink_str, NULL);
526     nsres = nsIDOMHTMLBodyElement_GetALink(This->nsbody, &alink_str);
527     if(NS_FAILED(nsres))
528         ERR("GetALink failed: %08x\n", nsres);
529
530     nscolor_to_variant(&alink_str, p);
531     nsAString_Finish(&alink_str);
532
533     return S_OK;
534 }
535
536 static HRESULT WINAPI HTMLBodyElement_put_onload(IHTMLBodyElement *iface, VARIANT v)
537 {
538     HTMLBodyElement *This = HTMLBODY_THIS(iface);
539     FIXME("(%p)->()\n", This);
540     return E_NOTIMPL;
541 }
542
543 static HRESULT WINAPI HTMLBodyElement_get_onload(IHTMLBodyElement *iface, VARIANT *p)
544 {
545     HTMLBodyElement *This = HTMLBODY_THIS(iface);
546     FIXME("(%p)->(%p)\n", This, p);
547     return E_NOTIMPL;
548 }
549
550 static HRESULT WINAPI HTMLBodyElement_put_onunload(IHTMLBodyElement *iface, VARIANT v)
551 {
552     HTMLBodyElement *This = HTMLBODY_THIS(iface);
553     FIXME("(%p)->()\n", This);
554     return E_NOTIMPL;
555 }
556
557 static HRESULT WINAPI HTMLBodyElement_get_onunload(IHTMLBodyElement *iface, VARIANT *p)
558 {
559     HTMLBodyElement *This = HTMLBODY_THIS(iface);
560     FIXME("(%p)->(%p)\n", This, p);
561     return E_NOTIMPL;
562 }
563
564 static HRESULT WINAPI HTMLBodyElement_put_scroll(IHTMLBodyElement *iface, BSTR v)
565 {
566     HTMLBodyElement *This = HTMLBODY_THIS(iface);
567     FIXME("(%p)->(%s)\n", This, debugstr_w(v));
568     return E_NOTIMPL;
569 }
570
571 static HRESULT WINAPI HTMLBodyElement_get_scroll(IHTMLBodyElement *iface, BSTR *p)
572 {
573     HTMLBodyElement *This = HTMLBODY_THIS(iface);
574     FIXME("(%p)->(%p)\n", This, p);
575     return E_NOTIMPL;
576 }
577
578 static HRESULT WINAPI HTMLBodyElement_put_onselect(IHTMLBodyElement *iface, VARIANT v)
579 {
580     HTMLBodyElement *This = HTMLBODY_THIS(iface);
581     FIXME("(%p)->()\n", This);
582     return E_NOTIMPL;
583 }
584
585 static HRESULT WINAPI HTMLBodyElement_get_onselect(IHTMLBodyElement *iface, VARIANT *p)
586 {
587     HTMLBodyElement *This = HTMLBODY_THIS(iface);
588     FIXME("(%p)->(%p)\n", This, p);
589     return E_NOTIMPL;
590 }
591
592 static HRESULT WINAPI HTMLBodyElement_put_onbeforeunload(IHTMLBodyElement *iface, VARIANT v)
593 {
594     HTMLBodyElement *This = HTMLBODY_THIS(iface);
595     FIXME("(%p)->()\n", This);
596     return E_NOTIMPL;
597 }
598
599 static HRESULT WINAPI HTMLBodyElement_get_onbeforeunload(IHTMLBodyElement *iface, VARIANT *p)
600 {
601     HTMLBodyElement *This = HTMLBODY_THIS(iface);
602     FIXME("(%p)->(%p)\n", This, p);
603     return E_NOTIMPL;
604 }
605
606 static HRESULT WINAPI HTMLBodyElement_createTextRange(IHTMLBodyElement *iface, IHTMLTxtRange **range)
607 {
608     HTMLBodyElement *This = HTMLBODY_THIS(iface);
609     nsIDOMDocumentRange *nsdocrange;
610     nsIDOMRange *nsrange = NULL;
611     nsresult nsres;
612     HRESULT hres;
613
614     TRACE("(%p)->(%p)\n", This, range);
615
616     if(!This->textcont.element.node.doc->nsdoc) {
617         WARN("No nsdoc\n");
618         return E_UNEXPECTED;
619     }
620
621     nsres = nsIDOMDocument_QueryInterface(This->textcont.element.node.doc->nsdoc, &IID_nsIDOMDocumentRange,
622             (void**)&nsdocrange);
623     if(NS_FAILED(nsres)) {
624         ERR("Could not get nsIDOMDocumentRabge iface: %08x\n", nsres);
625         return E_FAIL;
626     }
627
628     nsres = nsIDOMDocumentRange_CreateRange(nsdocrange, &nsrange);
629     if(NS_SUCCEEDED(nsres)) {
630         nsres = nsIDOMRange_SelectNodeContents(nsrange, This->textcont.element.node.nsnode);
631         if(NS_FAILED(nsres))
632             ERR("SelectNodeContents failed: %08x\n", nsres);
633     }else {
634         ERR("CreateRange failed: %08x\n", nsres);
635     }
636
637     nsIDOMDocumentRange_Release(nsdocrange);
638
639     hres = HTMLTxtRange_Create(This->textcont.element.node.doc->basedoc.doc_node, nsrange, range);
640
641     nsIDOMRange_Release(nsrange);
642     return hres;
643 }
644
645 #undef HTMLBODY_THIS
646
647 static const IHTMLBodyElementVtbl HTMLBodyElementVtbl = {
648     HTMLBodyElement_QueryInterface,
649     HTMLBodyElement_AddRef,
650     HTMLBodyElement_Release,
651     HTMLBodyElement_GetTypeInfoCount,
652     HTMLBodyElement_GetTypeInfo,
653     HTMLBodyElement_GetIDsOfNames,
654     HTMLBodyElement_Invoke,
655     HTMLBodyElement_put_background,
656     HTMLBodyElement_get_background,
657     HTMLBodyElement_put_bgProperties,
658     HTMLBodyElement_get_bgProperties,
659     HTMLBodyElement_put_leftMargin,
660     HTMLBodyElement_get_leftMargin,
661     HTMLBodyElement_put_topMargin,
662     HTMLBodyElement_get_topMargin,
663     HTMLBodyElement_put_rightMargin,
664     HTMLBodyElement_get_rightMargin,
665     HTMLBodyElement_put_bottomMargin,
666     HTMLBodyElement_get_bottomMargin,
667     HTMLBodyElement_put_noWrap,
668     HTMLBodyElement_get_noWrap,
669     HTMLBodyElement_put_bgColor,
670     HTMLBodyElement_get_bgColor,
671     HTMLBodyElement_put_text,
672     HTMLBodyElement_get_text,
673     HTMLBodyElement_put_link,
674     HTMLBodyElement_get_link,
675     HTMLBodyElement_put_vLink,
676     HTMLBodyElement_get_vLink,
677     HTMLBodyElement_put_aLink,
678     HTMLBodyElement_get_aLink,
679     HTMLBodyElement_put_onload,
680     HTMLBodyElement_get_onload,
681     HTMLBodyElement_put_onunload,
682     HTMLBodyElement_get_onunload,
683     HTMLBodyElement_put_scroll,
684     HTMLBodyElement_get_scroll,
685     HTMLBodyElement_put_onselect,
686     HTMLBodyElement_get_onselect,
687     HTMLBodyElement_put_onbeforeunload,
688     HTMLBodyElement_get_onbeforeunload,
689     HTMLBodyElement_createTextRange
690 };
691
692 #define HTMLBODY_NODE_THIS(iface) DEFINE_THIS2(HTMLBodyElement, textcont.element.node, iface)
693
694 static HRESULT HTMLBodyElement_QI(HTMLDOMNode *iface, REFIID riid, void **ppv)
695 {
696     HTMLBodyElement *This = HTMLBODY_NODE_THIS(iface);
697
698     *ppv = NULL;
699
700     if(IsEqualGUID(&IID_IUnknown, riid)) {
701         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
702         *ppv = HTMLBODY(This);
703     }else if(IsEqualGUID(&IID_IDispatch, riid)) {
704         TRACE("(%p)->(IID_IDispatch %p)\n", This, ppv);
705         *ppv = HTMLBODY(This);
706     }else if(IsEqualGUID(&IID_IHTMLBodyElement, riid)) {
707         TRACE("(%p)->(IID_IHTMLBodyElement %p)\n", This, ppv);
708         *ppv = HTMLBODY(This);
709     }else if(IsEqualGUID(&IID_IHTMLTextContainer, riid)) {
710         TRACE("(%p)->(IID_IHTMLTextContainer %p)\n", &This->textcont, ppv);
711         *ppv = HTMLTEXTCONT(&This->textcont);
712     }
713
714     if(*ppv) {
715         IUnknown_AddRef((IUnknown*)*ppv);
716         return S_OK;
717     }
718
719     return HTMLElement_QI(&This->textcont.element.node, riid, ppv);
720 }
721
722 static void HTMLBodyElement_destructor(HTMLDOMNode *iface)
723 {
724     HTMLBodyElement *This = HTMLBODY_NODE_THIS(iface);
725
726     nsIDOMHTMLBodyElement_Release(This->nsbody);
727
728     HTMLElement_destructor(&This->textcont.element.node);
729 }
730
731 static event_target_t **HTMLBodyElement_get_event_target(HTMLDOMNode *iface)
732 {
733     HTMLBodyElement *This = HTMLBODY_NODE_THIS(iface);
734
735     return This->textcont.element.node.doc && This->textcont.element.node.doc->basedoc.window
736         ? &This->textcont.element.node.doc->basedoc.window->event_target
737         : &This->textcont.element.node.event_target;
738 }
739
740 #undef HTMLBODY_NODE_THIS
741
742 static const NodeImplVtbl HTMLBodyElementImplVtbl = {
743     HTMLBodyElement_QI,
744     HTMLBodyElement_destructor,
745     HTMLBodyElement_get_event_target
746 };
747
748 static const tid_t HTMLBodyElement_iface_tids[] = {
749     IHTMLBodyElement_tid,
750     IHTMLBodyElement2_tid,
751     IHTMLDOMNode_tid,
752     IHTMLDOMNode2_tid,
753     IHTMLElement_tid,
754     IHTMLElement2_tid,
755     IHTMLElement3_tid,
756     IHTMLElement4_tid,
757     IHTMLTextContainer_tid,
758     IHTMLUniqueName_tid,
759     0
760 };
761
762 static dispex_static_data_t HTMLBodyElement_dispex = {
763     NULL,
764     DispHTMLBody_tid,
765     NULL,
766     HTMLBodyElement_iface_tids
767 };
768
769 HTMLElement *HTMLBodyElement_Create(HTMLDocumentNode *doc, nsIDOMHTMLElement *nselem)
770 {
771     HTMLBodyElement *ret = heap_alloc_zero(sizeof(HTMLBodyElement));
772     nsresult nsres;
773
774     TRACE("(%p)->(%p)\n", ret, nselem);
775
776     ret->lpHTMLBodyElementVtbl = &HTMLBodyElementVtbl;
777     ret->textcont.element.node.vtbl = &HTMLBodyElementImplVtbl;
778
779     HTMLTextContainer_Init(&ret->textcont, doc, nselem, &HTMLBodyElement_dispex);
780
781     ConnectionPoint_Init(&ret->cp_propnotif, &ret->textcont.element.cp_container, &IID_IPropertyNotifySink, NULL);
782
783     nsres = nsIDOMHTMLElement_QueryInterface(nselem, &IID_nsIDOMHTMLBodyElement,
784                                              (void**)&ret->nsbody);
785     if(NS_FAILED(nsres))
786         ERR("Could not get nsDOMHTMLBodyElement: %08x\n", nsres);
787
788     return &ret->textcont.element;
789 }