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