ddraw: Fix stupid bug when setting surface client memory.
[wine] / dlls / mshtml / olecmd.c
1 /*
2  * Copyright 2005-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 "config.h"
20
21 #include <stdarg.h>
22 #include <stdio.h>
23
24 #define COBJMACROS
25
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winuser.h"
29 #include "winnls.h"
30 #include "ole2.h"
31 #include "shlguid.h"
32 #include "mshtmdid.h"
33 #include "idispids.h"
34 #include "mshtmcid.h"
35
36 #include "wine/debug.h"
37 #include "wine/unicode.h"
38
39 #include "mshtml_private.h"
40 #include "resource.h"
41
42 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
43
44 #define NSCMD_BOLD "cmd_bold"
45 #define NSCMD_ITALIC "cmd_italic"
46 #define NSCMD_UNDERLINE "cmd_underline"
47 #define NSCMD_FONTCOLOR "cmd_fontColor"
48 #define NSCMD_ALIGN "cmd_align"
49 #define NSCMD_FONTFACE "cmd_fontFace"
50 #define NSCMD_INDENT "cmd_indent"
51 #define NSCMD_OUTDENT "cmd_outdent"
52 #define NSCMD_INSERTHR "cmd_insertHR"
53 #define NSCMD_UL "cmd_ul"
54 #define NSCMD_OL "cmd_ol"
55
56 #define NSSTATE_ATTRIBUTE "state_attribute"
57 #define NSSTATE_ALL "state_all"
58
59 #define NSALIGN_CENTER "center"
60 #define NSALIGN_LEFT   "left"
61 #define NSALIGN_RIGHT  "right"
62
63 /**********************************************************
64  * IOleCommandTarget implementation
65  */
66
67 #define CMDTARGET_THIS(iface) DEFINE_THIS(HTMLDocument, OleCommandTarget, iface)
68
69 static HRESULT exec_open(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
70 {
71     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
72     return E_NOTIMPL;
73 }
74
75 static HRESULT exec_new(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
76 {
77     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
78     return E_NOTIMPL;
79 }
80
81 static HRESULT exec_save(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
82 {
83     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
84     return E_NOTIMPL;
85 }
86
87 static HRESULT exec_save_as(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
88 {
89     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
90     return E_NOTIMPL;
91 }
92
93 static HRESULT exec_save_copy_as(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
94 {
95     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
96     return E_NOTIMPL;
97 }
98
99 static nsresult set_head_text(nsIPrintSettings *settings, LPCWSTR template, BOOL head, int pos)
100 {
101     if(head) {
102         switch(pos) {
103         case 0:
104             return nsIPrintSettings_SetHeaderStrLeft(settings, template);
105         case 1:
106             return nsIPrintSettings_SetHeaderStrRight(settings, template);
107         case 2:
108             return nsIPrintSettings_SetHeaderStrCenter(settings, template);
109         }
110     }else {
111         switch(pos) {
112         case 0:
113             return nsIPrintSettings_SetFooterStrLeft(settings, template);
114         case 1:
115             return nsIPrintSettings_SetFooterStrRight(settings, template);
116         case 2:
117             return nsIPrintSettings_SetFooterStrCenter(settings, template);
118         }
119     }
120
121     return NS_OK;
122 }
123
124 static void set_print_template(nsIPrintSettings *settings, LPCWSTR template, BOOL head)
125 {
126     PRUnichar nstemplate[200]; /* FIXME: Use dynamic allocation */
127     PRUnichar *p = nstemplate;
128     LPCWSTR ptr=template;
129     int pos=0;
130
131     while(*ptr) {
132         if(*ptr != '&') {
133             *p++ = *ptr++;
134             continue;
135         }
136
137         switch(*++ptr) {
138         case '&':
139             *p++ = '&';
140             *p++ = '&';
141             ptr++;
142             break;
143         case 'b': /* change align */
144             ptr++;
145             *p = 0;
146             set_head_text(settings, nstemplate, head, pos);
147             p = nstemplate;
148             pos++;
149             break;
150         case 'd': { /* short date */
151             SYSTEMTIME systime;
152             GetLocalTime(&systime);
153             GetDateFormatW(LOCALE_SYSTEM_DEFAULT, 0, &systime, NULL, p,
154                     sizeof(nstemplate)-(p-nstemplate)*sizeof(WCHAR));
155             p += strlenW(p);
156             ptr++;
157             break;
158         }
159         case 'p': /* page number */
160             *p++ = '&';
161             *p++ = 'P';
162             ptr++;
163             break;
164         case 'P': /* page count */
165             *p++ = '?'; /* FIXME */
166             ptr++;
167             break;
168         case 'u':
169             *p++ = '&';
170             *p++ = 'U';
171             ptr++;
172             break;
173         case 'w':
174             /* FIXME: set window title */
175             ptr++;
176             break;
177         default:
178             *p++ = '&';
179             *p++ = *ptr++;
180         }
181     }
182
183     *p = 0;
184     set_head_text(settings, nstemplate, head, pos);
185
186     while(++pos < 3)
187         set_head_text(settings, p, head, pos);
188 }
189
190 static void set_default_templates(nsIPrintSettings *settings)
191 {
192     WCHAR buf[64];
193
194     static const PRUnichar empty[] = {0};
195
196     nsIPrintSettings_SetHeaderStrLeft(settings, empty);
197     nsIPrintSettings_SetHeaderStrRight(settings, empty);
198     nsIPrintSettings_SetHeaderStrCenter(settings, empty);
199     nsIPrintSettings_SetFooterStrLeft(settings, empty);
200     nsIPrintSettings_SetFooterStrRight(settings, empty);
201     nsIPrintSettings_SetFooterStrCenter(settings, empty);
202
203     if(LoadStringW(get_shdoclc(), IDS_PRINT_HEADER_TEMPLATE, buf,
204                    sizeof(buf)/sizeof(WCHAR)))
205         set_print_template(settings, buf, TRUE);
206
207
208     if(LoadStringW(get_shdoclc(), IDS_PRINT_FOOTER_TEMPLATE, buf,
209                    sizeof(buf)/sizeof(WCHAR)))
210         set_print_template(settings, buf, FALSE);
211
212 }
213
214 static HRESULT exec_print(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
215 {
216     nsIInterfaceRequestor *iface_req;
217     nsIWebBrowserPrint *nsprint;
218     nsIPrintSettings *settings;
219     nsresult nsres;
220
221     TRACE("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
222
223     if(pvaOut)
224         FIXME("unsupported pvaOut\n");
225
226     if(!This->nscontainer)
227         return S_OK;
228
229     nsres = nsIWebBrowser_QueryInterface(This->nscontainer->webbrowser,
230             &IID_nsIInterfaceRequestor, (void**)&iface_req);
231     if(NS_FAILED(nsres)) {
232         ERR("Could not get nsIInterfaceRequestor: %08x\n", nsres);
233         return S_OK;
234     }
235
236     nsres = nsIInterfaceRequestor_GetInterface(iface_req, &IID_nsIWebBrowserPrint,
237             (void**)&nsprint);
238     nsIInterfaceRequestor_Release(iface_req);
239     if(NS_FAILED(nsres)) {
240         ERR("Could not get nsIWebBrowserPrint: %08x\n", nsres);
241         return S_OK;
242     }
243
244     nsres = nsIWebBrowserPrint_GetGlobalPrintSettings(nsprint, &settings);
245     if(NS_FAILED(nsres))
246         ERR("GetCurrentPrintSettings failed: %08x\n", nsres);
247
248     set_default_templates(settings);
249
250     if(pvaIn) {
251         switch(V_VT(pvaIn)) {
252         case VT_BYREF|VT_ARRAY: {
253             VARIANT *opts;
254             DWORD opts_cnt;
255
256             if(V_ARRAY(pvaIn)->cDims != 1)
257                 WARN("cDims = %d\n", V_ARRAY(pvaIn)->cDims);
258
259             SafeArrayAccessData(V_ARRAY(pvaIn), (void**)&opts);
260             opts_cnt = V_ARRAY(pvaIn)->rgsabound[0].cElements;
261
262             if(opts_cnt >= 1) {
263                 switch(V_VT(opts)) {
264                 case VT_BSTR:
265                     TRACE("setting footer %s\n", debugstr_w(V_BSTR(opts)));
266                     set_print_template(settings, V_BSTR(opts), TRUE);
267                     break;
268                 case VT_NULL:
269                     break;
270                 default:
271                     WARN("V_VT(opts) = %d\n", V_VT(opts));
272                 }
273             }
274
275             if(opts_cnt >= 2) {
276                 switch(V_VT(opts+1)) {
277                 case VT_BSTR:
278                     TRACE("setting footer %s\n", debugstr_w(V_BSTR(opts+1)));
279                     set_print_template(settings, V_BSTR(opts+1), FALSE);
280                     break;
281                 case VT_NULL:
282                     break;
283                 default:
284                     WARN("V_VT(opts) = %d\n", V_VT(opts+1));
285                 }
286             }
287
288             if(opts_cnt >= 3)
289                 FIXME("Unsupported opts_cnt %d\n", opts_cnt);
290
291             SafeArrayUnaccessData(V_ARRAY(pvaIn));
292             break;
293         }
294         default:
295             FIXME("unsupported vt %x\n", V_VT(pvaIn));
296         }
297     }
298
299     nsres = nsIWebBrowserPrint_Print(nsprint, settings, NULL);
300     if(NS_FAILED(nsres))
301         ERR("Print failed: %08x\n", nsres);
302
303     nsIWebBrowserPrint_Release(nsprint);
304
305     return S_OK;
306 }
307
308 static HRESULT exec_print_preview(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
309 {
310     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
311     return E_NOTIMPL;
312 }
313
314 static HRESULT exec_page_setup(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
315 {
316     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
317     return E_NOTIMPL;
318 }
319
320 static HRESULT exec_spell(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
321 {
322     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
323     return E_NOTIMPL;
324 }
325
326 static HRESULT exec_properties(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
327 {
328     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
329     return E_NOTIMPL;
330 }
331
332 static HRESULT exec_cut(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
333 {
334     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
335     return E_NOTIMPL;
336 }
337
338 static HRESULT exec_copy(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
339 {
340     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
341     return E_NOTIMPL;
342 }
343
344 static HRESULT exec_paste(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
345 {
346     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
347     return E_NOTIMPL;
348 }
349
350 static HRESULT exec_paste_special(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
351 {
352     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
353     return E_NOTIMPL;
354 }
355
356 static HRESULT exec_undo(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
357 {
358     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
359     return E_NOTIMPL;
360 }
361
362 static HRESULT exec_rendo(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
363 {
364     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
365     return E_NOTIMPL;
366 }
367
368 static HRESULT exec_select_all(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
369 {
370     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
371     return E_NOTIMPL;
372 }
373
374 static HRESULT exec_clear_selection(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
375 {
376     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
377     return E_NOTIMPL;
378 }
379
380 static HRESULT exec_zoom(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
381 {
382     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
383     return E_NOTIMPL;
384 }
385
386 static HRESULT exec_get_zoom_range(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
387 {
388     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
389     return E_NOTIMPL;
390 }
391
392 static HRESULT exec_refresh(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
393 {
394     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
395     return E_NOTIMPL;
396 }
397
398 static HRESULT exec_stop(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
399 {
400     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
401     return E_NOTIMPL;
402 }
403
404 static HRESULT exec_stop_download(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
405 {
406     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
407     return E_NOTIMPL;
408 }
409
410 static HRESULT exec_delete(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
411 {
412     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
413     return E_NOTIMPL;
414 }
415
416 static HRESULT exec_enable_interaction(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
417 {
418     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
419     return E_NOTIMPL;
420 }
421
422 static HRESULT exec_on_unload(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
423 {
424     TRACE("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
425
426     /* Tests show that we have nothing more to do here */
427
428     if(pvaOut) {
429         V_VT(pvaOut) = VT_BOOL;
430         V_BOOL(pvaOut) = VARIANT_TRUE;
431     }
432
433     return S_OK;
434 }
435
436 static HRESULT exec_show_page_setup(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
437 {
438     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
439     return E_NOTIMPL;
440 }
441
442 static HRESULT exec_show_print(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
443 {
444     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
445     return E_NOTIMPL;
446 }
447
448 static HRESULT exec_close(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
449 {
450     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
451     return E_NOTIMPL;
452 }
453
454 static HRESULT exec_set_print_template(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
455 {
456     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
457     return E_NOTIMPL;
458 }
459
460 static HRESULT exec_get_print_template(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
461 {
462     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
463     return E_NOTIMPL;
464 }
465
466 static void do_ns_command(NSContainer *This, const char *cmd, nsICommandParams *nsparam)
467 {
468     nsICommandManager *cmdmgr;
469     nsIInterfaceRequestor *iface_req;
470     nsresult nsres;
471
472     TRACE("(%p)\n", This);
473
474     nsres = nsIWebBrowser_QueryInterface(This->webbrowser,
475             &IID_nsIInterfaceRequestor, (void**)&iface_req);
476     if(NS_FAILED(nsres)) {
477         ERR("Could not get nsIInterfaceRequestor: %08x\n", nsres);
478         return;
479     }
480
481     nsres = nsIInterfaceRequestor_GetInterface(iface_req, &IID_nsICommandManager,
482                                                (void**)&cmdmgr);
483     nsIInterfaceRequestor_Release(iface_req);
484     if(NS_FAILED(nsres)) {
485         ERR("Could not get nsICommandManager: %08x\n", nsres);
486         return;
487     }
488
489     nsres = nsICommandManager_DoCommand(cmdmgr, cmd, nsparam, NULL);
490     if(NS_FAILED(nsres))
491         ERR("DoCommand(%s) failed: %08x\n", debugstr_a(cmd), nsres);
492
493     nsICommandManager_Release(cmdmgr);
494 }
495
496 static nsresult get_ns_command_state(NSContainer *This, const char *cmd, nsICommandParams *nsparam)
497 {
498     nsICommandManager *cmdmgr;
499     nsIInterfaceRequestor *iface_req;
500     nsresult nsres;
501
502     nsres = nsIWebBrowser_QueryInterface(This->webbrowser,
503             &IID_nsIInterfaceRequestor, (void**)&iface_req);
504     if(NS_FAILED(nsres)) {
505         ERR("Could not get nsIInterfaceRequestor: %08x\n", nsres);
506         return nsres;
507     }
508
509     nsres = nsIInterfaceRequestor_GetInterface(iface_req, &IID_nsICommandManager,
510                                                (void**)&cmdmgr);
511     nsIInterfaceRequestor_Release(iface_req);
512     if(NS_FAILED(nsres)) {
513         ERR("Could not get nsICommandManager: %08x\n", nsres);
514         return nsres;
515     }
516
517     nsres = nsICommandManager_GetCommandState(cmdmgr, cmd, NULL, nsparam);
518     if(NS_FAILED(nsres))
519         ERR("GetCommandState(%s) failed: %08x\n", debugstr_a(cmd), nsres);
520
521     nsICommandManager_Release(cmdmgr);
522     return nsres;
523 }
524
525 static DWORD query_edit_status(HTMLDocument *This, const char *nscmd)
526 {
527     nsICommandParams *nsparam;
528     PRBool b = FALSE;
529
530     if(This->usermode != EDITMODE || This->readystate < READYSTATE_INTERACTIVE)
531         return OLECMDF_SUPPORTED;
532
533     if(This->nscontainer && nscmd) {
534         nsparam = create_nscommand_params();
535         get_ns_command_state(This->nscontainer, nscmd, nsparam);
536
537         nsICommandParams_GetBooleanValue(nsparam, NSSTATE_ALL, &b);
538
539         nsICommandParams_Release(nsparam);
540     }
541
542     return OLECMDF_SUPPORTED | OLECMDF_ENABLED | (b ? OLECMDF_LATCHED : 0);
543 }
544
545 static DWORD query_align_status(HTMLDocument *This, const char *align_str)
546 {
547     nsICommandParams *nsparam;
548     char *align = NULL;
549
550     if(This->usermode != EDITMODE || This->readystate < READYSTATE_INTERACTIVE)
551         return OLECMDF_SUPPORTED;
552
553     if(This->nscontainer) {
554         nsparam = create_nscommand_params();
555         get_ns_command_state(This->nscontainer, NSCMD_ALIGN, nsparam);
556
557         nsICommandParams_GetCStringValue(nsparam, NSSTATE_ATTRIBUTE, &align);
558
559         nsICommandParams_Release(nsparam);
560     }
561
562     return OLECMDF_SUPPORTED | OLECMDF_ENABLED | (align && !strcmp(align_str, align) ? OLECMDF_LATCHED : 0);
563 }
564
565 static void set_ns_align(HTMLDocument *This, const char *align_str)
566 {
567     nsICommandParams *nsparam;
568
569     if(!This->nscontainer)
570         return;
571
572     nsparam = create_nscommand_params();
573     nsICommandParams_SetCStringValue(nsparam, NSSTATE_ATTRIBUTE, align_str);
574
575     do_ns_command(This->nscontainer, NSCMD_ALIGN, nsparam);
576
577     nsICommandParams_Release(nsparam);
578 }
579
580 static HRESULT exec_fontname(HTMLDocument *This, VARIANT *in, VARIANT *out)
581 {
582     TRACE("(%p)->(%p %p)\n", This, in, out);
583
584     if(!This->nscontainer)
585         return E_FAIL;
586
587     if(in) {
588         nsICommandParams *nsparam = create_nscommand_params();
589         char *stra;
590         DWORD len;
591
592         if(V_VT(in) != VT_BSTR) {
593             FIXME("Unsupported vt=%d\n", V_VT(out));
594             return E_INVALIDARG;
595         }
596
597         len = WideCharToMultiByte(CP_ACP, 0, V_BSTR(in), -1, NULL, 0, NULL, NULL);
598         stra = mshtml_alloc(len);
599         WideCharToMultiByte(CP_ACP, 0, V_BSTR(in), -1, stra, -1, NULL, NULL);
600         nsICommandParams_SetCStringValue(nsparam, NSSTATE_ATTRIBUTE, stra);
601         mshtml_free(stra);
602
603         do_ns_command(This->nscontainer, NSCMD_FONTFACE, nsparam);
604
605         nsICommandParams_Release(nsparam);
606     }
607
608     if(out) {
609         nsICommandParams *nsparam;
610         LPWSTR strw;
611         char *stra;
612         DWORD len;
613         nsresult nsres;
614
615         if(V_VT(out) != VT_BSTR) {
616             FIXME("Unsupported vt=%d\n", V_VT(out));
617             return E_INVALIDARG;
618         }
619
620         nsparam = create_nscommand_params();
621
622         nsres = get_ns_command_state(This->nscontainer, NSCMD_FONTFACE, nsparam);
623         if(NS_FAILED(nsres))
624             return S_OK;
625
626         nsICommandParams_GetCStringValue(nsparam, NSSTATE_ATTRIBUTE, &stra);
627         nsICommandParams_Release(nsparam);
628
629         len = MultiByteToWideChar(CP_ACP, 0, stra, -1, NULL, 0);
630         strw = mshtml_alloc(len*sizeof(WCHAR));
631         MultiByteToWideChar(CP_ACP, 0, stra, -1, strw, -1);
632         nsfree(stra);
633
634         V_BSTR(out) = SysAllocString(strw);
635         mshtml_free(strw);
636     }
637
638     return S_OK;
639 }
640
641 static HRESULT exec_forecolor(HTMLDocument *This, VARIANT *in, VARIANT *out)
642 {
643     TRACE("(%p)->(%p %p)\n", This, in, out);
644
645     if(in) {
646         if(V_VT(in) == VT_I4) {
647             nsICommandParams *nsparam = create_nscommand_params();
648             char color_str[10];
649
650             sprintf(color_str, "#%02x%02x%02x",
651                     V_I4(in)&0xff, (V_I4(in)>>8)&0xff, (V_I4(in)>>16)&0xff);
652
653             nsICommandParams_SetCStringValue(nsparam, NSSTATE_ATTRIBUTE, color_str);
654             do_ns_command(This->nscontainer, NSCMD_FONTCOLOR, nsparam);
655
656             nsICommandParams_Release(nsparam);
657         }else {
658             FIXME("unsupported in vt=%d\n", V_VT(in));
659         }
660     }
661
662     if(out) {
663         FIXME("unsupported out\n");
664         return E_NOTIMPL;
665     }
666
667     return S_OK;
668 }
669
670 static HRESULT exec_fontsize(HTMLDocument *This, VARIANT *in, VARIANT *out)
671 {
672     TRACE("(%p)->(%p %p)\n", This, in, out);
673
674     if(out) {
675         WCHAR val[10] = {0};
676
677         switch(V_VT(out)) {
678         case VT_I4:
679             get_font_size(This, val);
680             V_I4(out) = strtolW(val, NULL, 10);
681             break;
682         case VT_BSTR:
683             get_font_size(This, val);
684             V_BSTR(out) = SysAllocString(val);
685             break;
686         default:
687             FIXME("unsupported vt %d\n", V_VT(out));
688         }
689     }
690
691     if(in) {
692         switch(V_VT(in)) {
693         case VT_I4: {
694             WCHAR size[10];
695             static const WCHAR format[] = {'%','d',0};
696             wsprintfW(size, format, V_I4(in));
697             set_font_size(This, size);
698             break;
699         }
700         case VT_BSTR:
701             set_font_size(This, V_BSTR(in));
702             break;
703         default:
704             FIXME("unsupported vt %d\n", V_VT(in));
705         }
706     }
707
708     return S_OK;
709 }
710
711 static HRESULT exec_bold(HTMLDocument *This)
712 {
713     TRACE("(%p)\n", This);
714
715     if(This->nscontainer)
716         do_ns_command(This->nscontainer, NSCMD_BOLD, NULL);
717
718     return S_OK;
719 }
720
721 static HRESULT exec_italic(HTMLDocument *This)
722 {
723     TRACE("(%p)\n", This);
724
725     if(This->nscontainer)
726         do_ns_command(This->nscontainer, NSCMD_ITALIC, NULL);
727
728     return S_OK;
729 }
730
731 static HRESULT exec_justifycenter(HTMLDocument *This)
732 {
733     TRACE("(%p)\n", This);
734     set_ns_align(This, NSALIGN_CENTER);
735     return S_OK;
736 }
737
738 static HRESULT exec_justifyleft(HTMLDocument *This)
739 {
740     TRACE("(%p)\n", This);
741     set_ns_align(This, NSALIGN_LEFT);
742     return S_OK;
743 }
744
745 static HRESULT exec_justifyright(HTMLDocument *This)
746 {
747     TRACE("(%p)\n", This);
748     set_ns_align(This, NSALIGN_RIGHT);
749     return S_OK;
750 }
751
752 static HRESULT exec_underline(HTMLDocument *This)
753 {
754     TRACE("(%p)\n", This);
755
756     if(This->nscontainer)
757         do_ns_command(This->nscontainer, NSCMD_UNDERLINE, NULL);
758
759     return S_OK;
760 }
761
762 static HRESULT exec_browsemode(HTMLDocument *This)
763 {
764     WARN("(%p)\n", This);
765
766     This->usermode = BROWSEMODE;
767
768     return S_OK;
769 }
770
771 static void setup_ns_editing(NSContainer *This)
772 {
773     nsIInterfaceRequestor *iface_req;
774     nsIEditingSession *editing_session = NULL;
775     nsIURIContentListener *listener = NULL;
776     nsIDOMWindow *dom_window = NULL;
777     nsresult nsres;
778
779     nsres = nsIWebBrowser_QueryInterface(This->webbrowser,
780             &IID_nsIInterfaceRequestor, (void**)&iface_req);
781     if(NS_FAILED(nsres)) {
782         ERR("Could not get nsIInterfaceRequestor: %08x\n", nsres);
783         return;
784     }
785
786     nsres = nsIInterfaceRequestor_GetInterface(iface_req, &IID_nsIEditingSession,
787                                                (void**)&editing_session);
788     nsIInterfaceRequestor_Release(iface_req);
789     if(NS_FAILED(nsres)) {
790         ERR("Could not get nsIEditingSession: %08x\n", nsres);
791         return;
792     }
793
794     nsres = nsIWebBrowser_GetContentDOMWindow(This->webbrowser, &dom_window);
795     if(NS_FAILED(nsres)) {
796         ERR("Could not get content DOM window: %08x\n", nsres);
797         nsIEditingSession_Release(editing_session);
798         return;
799     }
800
801     nsres = nsIEditingSession_MakeWindowEditable(editing_session, dom_window, NULL, FALSE);
802     nsIEditingSession_Release(editing_session);
803     nsIDOMWindow_Release(dom_window);
804     if(NS_FAILED(nsres)) {
805         ERR("MakeWindowEditable failed: %08x\n", nsres);
806         return;
807     }
808
809     /* MakeWindowEditable changes WebBrowser's parent URI content listener.
810      * It seams to be a bug in Gecko. To workaround it we set our content
811      * listener again and Gecko's one as its parent.
812      */
813     nsIWebBrowser_GetParentURIContentListener(This->webbrowser, &listener);
814     nsIURIContentListener_SetParentContentListener(NSURICL(This), listener);
815     nsIURIContentListener_Release(listener);
816     nsIWebBrowser_SetParentURIContentListener(This->webbrowser, NSURICL(This));
817 }
818
819 static HRESULT exec_editmode(HTMLDocument *This)
820 {
821     IMoniker *mon;
822     HRESULT hres;
823
824     static const WCHAR wszAboutBlank[] = {'a','b','o','u','t',':','b','l','a','n','k',0};
825
826     TRACE("(%p)\n", This);
827
828     This->usermode = EDITMODE;
829
830     if(This->frame)
831         IOleInPlaceFrame_SetStatusText(This->frame, NULL);
832
833     if(This->hostui) {
834         DOCHOSTUIINFO hostinfo;
835
836         memset(&hostinfo, 0, sizeof(DOCHOSTUIINFO));
837         hostinfo.cbSize = sizeof(DOCHOSTUIINFO);
838         hres = IDocHostUIHandler_GetHostInfo(This->hostui, &hostinfo);
839         if(SUCCEEDED(hres))
840             /* FIXME: use hostinfo */
841             TRACE("hostinfo = {%u %08x %08x %s %s}\n",
842                     hostinfo.cbSize, hostinfo.dwFlags, hostinfo.dwDoubleClick,
843                     debugstr_w(hostinfo.pchHostCss), debugstr_w(hostinfo.pchHostNS));
844     }
845
846     if(This->nscontainer)
847         setup_ns_editing(This->nscontainer);
848
849     hres = CreateURLMoniker(NULL, wszAboutBlank, &mon);
850     if(FAILED(hres)) {
851         FIXME("CreateURLMoniker failed: %08x\n", hres);
852         return hres;
853     }
854
855     return IPersistMoniker_Load(PERSISTMON(This), TRUE, mon, NULL, 0);
856 }
857
858 static HRESULT exec_baselinefont3(HTMLDocument *This)
859 {
860     FIXME("(%p)\n", This);
861     return S_OK;
862 }
863
864 static HRESULT exec_horizontalline(HTMLDocument *This)
865 {
866     TRACE("(%p)\n", This);
867
868     if(This->nscontainer)
869         do_ns_command(This->nscontainer, NSCMD_INSERTHR, NULL);
870
871     return S_OK;
872 }
873
874 static HRESULT exec_orderlist(HTMLDocument *This)
875 {
876     TRACE("(%p)\n", This);
877
878     if(This->nscontainer)
879         do_ns_command(This->nscontainer, NSCMD_OL, NULL);
880
881     return S_OK;
882 }
883
884 static HRESULT exec_unorderlist(HTMLDocument *This)
885 {
886     TRACE("(%p)\n", This);
887
888     if(This->nscontainer)
889         do_ns_command(This->nscontainer, NSCMD_UL, NULL);
890
891     return S_OK;
892 }
893
894 static HRESULT exec_indent(HTMLDocument *This)
895 {
896     TRACE("(%p)\n", This);
897
898     if(This->nscontainer)
899         do_ns_command(This->nscontainer, NSCMD_INDENT, NULL);
900
901     return S_OK;
902 }
903
904 static HRESULT exec_outdent(HTMLDocument *This)
905 {
906     TRACE("(%p)\n", This);
907
908     if(This->nscontainer)
909         do_ns_command(This->nscontainer, NSCMD_OUTDENT, NULL);
910
911     return S_OK;
912 }
913
914 static HRESULT exec_htmleditmode(HTMLDocument *This)
915 {
916     FIXME("(%p)\n", This);
917     return S_OK;
918 }
919
920 static HRESULT exec_composesettings(HTMLDocument *This, VARIANT *in)
921 {
922     if(!in || V_VT(in) != VT_BSTR) {
923         WARN("invalid arg\n");
924         return E_INVALIDARG;
925     }
926
927     FIXME("%s\n", debugstr_w(V_BSTR(in)));
928
929     return S_OK;
930 }
931
932 static const struct {
933     OLECMDF cmdf;
934     HRESULT (*func)(HTMLDocument*,DWORD,VARIANT*,VARIANT*);
935 } exec_table[OLECMDID_GETPRINTTEMPLATE+1] = {
936     {0},
937     { OLECMDF_SUPPORTED,                  exec_open                 }, /* OLECMDID_OPEN */
938     { OLECMDF_SUPPORTED,                  exec_new                  }, /* OLECMDID_NEW */
939     { OLECMDF_SUPPORTED,                  exec_save                 }, /* OLECMDID_SAVE */
940     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_save_as              }, /* OLECMDID_SAVEAS */
941     { OLECMDF_SUPPORTED,                  exec_save_copy_as         }, /* OLECMDID_SAVECOPYAS */
942     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_print                }, /* OLECMDID_PRINT */
943     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_print_preview        }, /* OLECMDID_PRINTPREVIEW */
944     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_page_setup           }, /* OLECMDID_PAGESETUP */
945     { OLECMDF_SUPPORTED,                  exec_spell                }, /* OLECMDID_SPELL */
946     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_properties           }, /* OLECMDID_PROPERTIES */
947     { OLECMDF_SUPPORTED,                  exec_cut                  }, /* OLECMDID_CUT */
948     { OLECMDF_SUPPORTED,                  exec_copy                 }, /* OLECMDID_COPY */
949     { OLECMDF_SUPPORTED,                  exec_paste                }, /* OLECMDID_PASTE */
950     { OLECMDF_SUPPORTED,                  exec_paste_special        }, /* OLECMDID_PASTESPECIAL */
951     { OLECMDF_SUPPORTED,                  exec_undo                 }, /* OLECMDID_UNDO */
952     { OLECMDF_SUPPORTED,                  exec_rendo                }, /* OLECMDID_REDO */
953     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_select_all           }, /* OLECMDID_SELECTALL */
954     { OLECMDF_SUPPORTED,                  exec_clear_selection      }, /* OLECMDID_CLEARSELECTION */
955     { OLECMDF_SUPPORTED,                  exec_zoom                 }, /* OLECMDID_ZOOM */
956     { OLECMDF_SUPPORTED,                  exec_get_zoom_range       }, /* OLECMDID_GETZOOMRANGE */
957     {0},
958     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_refresh              }, /* OLECMDID_REFRESH */
959     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_stop                 }, /* OLECMDID_STOP */
960     {0},{0},{0},{0},{0},{0},
961     { OLECMDF_SUPPORTED,                  exec_stop_download        }, /* OLECMDID_STOPDOWNLOAD */
962     {0},{0},
963     { OLECMDF_SUPPORTED,                  exec_delete               }, /* OLECMDID_DELETE */
964     {0},{0},
965     { OLECMDF_SUPPORTED,                  exec_enable_interaction   }, /* OLECMDID_ENABLE_INTERACTION */
966     { OLECMDF_SUPPORTED,                  exec_on_unload            }, /* OLECMDID_ONUNLOAD */
967     {0},{0},{0},{0},{0},
968     { OLECMDF_SUPPORTED,                  exec_show_page_setup      }, /* OLECMDID_SHOWPAGESETUP */
969     { OLECMDF_SUPPORTED,                  exec_show_print           }, /* OLECMDID_SHOWPRINT */
970     {0},{0},
971     { OLECMDF_SUPPORTED,                  exec_close                }, /* OLECMDID_CLOSE */
972     {0},{0},{0},
973     { OLECMDF_SUPPORTED,                  exec_set_print_template   }, /* OLECMDID_SETPRINTTEMPLATE */
974     { OLECMDF_SUPPORTED,                  exec_get_print_template   }  /* OLECMDID_GETPRINTTEMPLATE */
975 };
976
977 static HRESULT WINAPI OleCommandTarget_QueryInterface(IOleCommandTarget *iface, REFIID riid, void **ppv)
978 {
979     HTMLDocument *This = CMDTARGET_THIS(iface);
980     return IHTMLDocument2_QueryInterface(HTMLDOC(This), riid, ppv);
981 }
982
983 static ULONG WINAPI OleCommandTarget_AddRef(IOleCommandTarget *iface)
984 {
985     HTMLDocument *This = CMDTARGET_THIS(iface);
986     return IHTMLDocument2_AddRef(HTMLDOC(This));
987 }
988
989 static ULONG WINAPI OleCommandTarget_Release(IOleCommandTarget *iface)
990 {
991     HTMLDocument *This = CMDTARGET_THIS(iface);
992     return IHTMLDocument_Release(HTMLDOC(This));
993 }
994
995 static HRESULT WINAPI OleCommandTarget_QueryStatus(IOleCommandTarget *iface, const GUID *pguidCmdGroup,
996         ULONG cCmds, OLECMD prgCmds[], OLECMDTEXT *pCmdText)
997 {
998     HTMLDocument *This = CMDTARGET_THIS(iface);
999     HRESULT hres = S_OK, hr;
1000
1001     TRACE("(%p)->(%s %d %p %p)\n", This, debugstr_guid(pguidCmdGroup), cCmds, prgCmds, pCmdText);
1002
1003     if(!pguidCmdGroup) {
1004         ULONG i;
1005
1006         for(i=0; i<cCmds; i++) {
1007             if(prgCmds[i].cmdID<OLECMDID_OPEN || prgCmds[i].cmdID>OLECMDID_GETPRINTTEMPLATE) {
1008                 WARN("Unsupported cmdID = %d\n", prgCmds[i].cmdID);
1009                 prgCmds[i].cmdf = 0;
1010                 hres = OLECMDERR_E_NOTSUPPORTED;
1011             }else {
1012                 if(prgCmds[i].cmdID == OLECMDID_OPEN || prgCmds[i].cmdID == OLECMDID_NEW) {
1013                     IOleCommandTarget *cmdtrg = NULL;
1014                     OLECMD olecmd;
1015
1016                     prgCmds[i].cmdf = OLECMDF_SUPPORTED;
1017                     if(This->client) {
1018                         hr = IOleClientSite_QueryInterface(This->client, &IID_IOleCommandTarget,
1019                                 (void**)&cmdtrg);
1020                         if(SUCCEEDED(hr)) {
1021                             olecmd.cmdID = prgCmds[i].cmdID;
1022                             olecmd.cmdf = 0;
1023
1024                             hr = IOleCommandTarget_QueryStatus(cmdtrg, NULL, 1, &olecmd, NULL);
1025                             if(SUCCEEDED(hr) && olecmd.cmdf)
1026                                 prgCmds[i].cmdf = olecmd.cmdf;
1027                         }
1028                     }else {
1029                         ERR("This->client == NULL, native would crash\n");
1030                     }
1031                 }else {
1032                     prgCmds[i].cmdf = exec_table[prgCmds[i].cmdID].cmdf;
1033                     TRACE("cmdID = %d  returning %x\n", prgCmds[i].cmdID, prgCmds[i].cmdf);
1034                 }
1035                 hres = S_OK;
1036             }
1037         }
1038
1039         if(pCmdText)
1040             FIXME("Set pCmdText\n");
1041     }else if(IsEqualGUID(&CGID_MSHTML, pguidCmdGroup)) {
1042         ULONG i;
1043
1044         for(i=0; i<cCmds; i++) {
1045             switch(prgCmds[i].cmdID) {
1046             case IDM_COPY:
1047                 FIXME("CGID_MSHTML: IDM_COPY\n");
1048                 prgCmds[i].cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
1049                 break;
1050             case IDM_CUT:
1051                 FIXME("CGID_MSHTML: IDM_CUT\n");
1052                 prgCmds[i].cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
1053                 break;
1054             case IDM_FONTNAME:
1055                 TRACE("CGID_MSHTML: IDM_FONTNAME\n");
1056                 prgCmds[i].cmdf = query_edit_status(This, NULL);
1057                 break;
1058             case IDM_FONTSIZE:
1059                 TRACE("CGID_MSHTML: IDM_FONTSIZE\n");
1060                 prgCmds[i].cmdf = query_edit_status(This, NULL);
1061                 break;
1062             case IDM_PRINT:
1063                 FIXME("CGID_MSHTML: IDM_PRINT\n");
1064                 prgCmds[i].cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
1065                 break;
1066             case IDM_PASTE:
1067                 FIXME("CGID_MSHTML: IDM_PASTE\n");
1068                 prgCmds[i].cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
1069                 break;
1070             case IDM_BOLD:
1071                 TRACE("CGID_MSHTML: IDM_BOLD\n");
1072                 prgCmds[i].cmdf = query_edit_status(This, NSCMD_BOLD);
1073                 break;
1074             case IDM_FORECOLOR:
1075                 TRACE("CGID_MSHTML: IDM_FORECOLOR\n");
1076                 prgCmds[i].cmdf = query_edit_status(This, NULL);
1077                 break;
1078             case IDM_ITALIC:
1079                 TRACE("CGID_MSHTML: IDM_ITALIC\n");
1080                 prgCmds[i].cmdf = query_edit_status(This, NSCMD_ITALIC);
1081                 break;
1082             case IDM_JUSTIFYCENTER:
1083                 TRACE("CGID_MSHTML: IDM_JUSTIFYCENTER\n");
1084                 prgCmds[i].cmdf = query_align_status(This, NSALIGN_CENTER);
1085                 break;
1086             case IDM_JUSTIFYLEFT:
1087                 TRACE("CGID_MSHTML: IDM_JUSTIFYLEFT\n");
1088                 prgCmds[i].cmdf = query_align_status(This, NSALIGN_LEFT);
1089                 break;
1090             case IDM_JUSTIFYRIGHT:
1091                 TRACE("CGID_MSHTML: IDM_JUSTIFYRIGHT\n");
1092                 prgCmds[i].cmdf = query_align_status(This, NSALIGN_RIGHT);
1093                 break;
1094             case IDM_UNDERLINE:
1095                 TRACE("CGID_MSHTML: IDM_UNDERLINE\n");
1096                 prgCmds[i].cmdf = query_edit_status(This, NSCMD_UNDERLINE);
1097                 break;
1098             case IDM_HORIZONTALLINE:
1099                 TRACE("CGID_MSHTML: IDM_HORIZONTALLINE\n");
1100                 prgCmds[i].cmdf = query_edit_status(This, NULL);
1101                 break;
1102             case IDM_ORDERLIST:
1103                 TRACE("CGID_MSHTML: IDM_ORDERLIST\n");
1104                 prgCmds[i].cmdf = query_edit_status(This, NSCMD_OL);
1105                 break;
1106             case IDM_UNORDERLIST:
1107                 TRACE("CGID_MSHTML: IDM_HORIZONTALLINE\n");
1108                 prgCmds[i].cmdf = query_edit_status(This, NSCMD_UL);
1109                 break;
1110             case IDM_INDENT:
1111                 TRACE("CGID_MSHTML: IDM_INDENT\n");
1112                 prgCmds[i].cmdf = query_edit_status(This, NULL);
1113                 break;
1114             case IDM_OUTDENT:
1115                 TRACE("CGID_MSHTML: IDM_OUTDENT\n");
1116                 prgCmds[i].cmdf = query_edit_status(This, NULL);
1117                 break;
1118             case IDM_BLOCKDIRLTR:
1119                 FIXME("CGID_MSHTML: IDM_BLOCKDIRLTR\n");
1120                 prgCmds[i].cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
1121                 break;
1122             case IDM_BLOCKDIRRTL:
1123                 FIXME("CGID_MSHTML: IDM_BLOCKDIRRTL\n");
1124                 prgCmds[i].cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
1125                 break;
1126             default:
1127                 FIXME("CGID_MSHTML: unsupported cmdID %d\n", prgCmds[i].cmdID);
1128                 prgCmds[i].cmdf = 0;
1129             }
1130         }
1131
1132         hres = prgCmds[i-1].cmdf ? S_OK : OLECMDERR_E_NOTSUPPORTED;
1133
1134         if(pCmdText)
1135             FIXME("Set pCmdText\n");
1136     }else {
1137         FIXME("Unsupported pguidCmdGroup %s\n", debugstr_guid(pguidCmdGroup));
1138         hres = OLECMDERR_E_UNKNOWNGROUP;
1139     }
1140
1141     return hres;
1142 }
1143
1144 static HRESULT WINAPI OleCommandTarget_Exec(IOleCommandTarget *iface, const GUID *pguidCmdGroup,
1145         DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
1146 {
1147     HTMLDocument *This = CMDTARGET_THIS(iface);
1148
1149     if(!pguidCmdGroup) {
1150         if(nCmdID<OLECMDID_OPEN || nCmdID>OLECMDID_GETPRINTTEMPLATE || !exec_table[nCmdID].func) {
1151             WARN("Unsupported cmdID = %d\n", nCmdID);
1152             return OLECMDERR_E_NOTSUPPORTED;
1153         }
1154
1155         return exec_table[nCmdID].func(This, nCmdexecopt, pvaIn, pvaOut);
1156     }else if(IsEqualGUID(&CGID_Explorer, pguidCmdGroup)) {
1157         FIXME("unsupported nCmdID %d of CGID_Explorer group\n", nCmdID);
1158         TRACE("%p %p\n", pvaIn, pvaOut);
1159         return OLECMDERR_E_NOTSUPPORTED;
1160     }else if(IsEqualGUID(&CGID_ShellDocView, pguidCmdGroup)) {
1161         FIXME("unsupported nCmdID %d of CGID_ShellDocView group\n", nCmdID);
1162         return OLECMDERR_E_NOTSUPPORTED;
1163     }else if(IsEqualGUID(&CGID_MSHTML, pguidCmdGroup)) {
1164         switch(nCmdID) {
1165         case IDM_FONTNAME:
1166             return exec_fontname(This, pvaIn, pvaOut);
1167         case IDM_FONTSIZE:
1168             return exec_fontsize(This, pvaIn, pvaOut);
1169         case IDM_PRINT:
1170             return exec_print(This, nCmdexecopt, pvaIn, pvaOut);
1171         case IDM_BOLD:
1172             if(pvaIn || pvaOut)
1173                 FIXME("unsupported arguments\n");
1174             return exec_bold(This);
1175         case IDM_FORECOLOR:
1176             return exec_forecolor(This, pvaIn, pvaOut);
1177         case IDM_ITALIC:
1178             if(pvaIn || pvaOut)
1179                 FIXME("unsupported arguments\n");
1180             return exec_italic(This);
1181         case IDM_JUSTIFYCENTER:
1182             if(pvaIn || pvaOut)
1183                 FIXME("unsupported arguments\n");
1184             return exec_justifycenter(This);
1185         case IDM_JUSTIFYLEFT:
1186             if(pvaIn || pvaOut)
1187                 FIXME("unsupported arguments\n");
1188             return exec_justifyleft(This);
1189         case IDM_JUSTIFYRIGHT:
1190             if(pvaIn || pvaOut)
1191                 FIXME("unsupported arguments\n");
1192             return exec_justifyright(This);
1193         case IDM_UNDERLINE:
1194             if(pvaIn || pvaOut)
1195                 FIXME("unsupported arguments\n");
1196             return exec_underline(This);
1197         case IDM_BROWSEMODE:
1198             if(pvaIn || pvaOut)
1199                 FIXME("unsupported arguments\n");
1200             return exec_browsemode(This);
1201         case IDM_EDITMODE:
1202             if(pvaIn || pvaOut)
1203                 FIXME("unsupported arguments\n");
1204             return exec_editmode(This);
1205         case IDM_BASELINEFONT3:
1206             return exec_baselinefont3(This);
1207         case IDM_HORIZONTALLINE:
1208             if(pvaIn || pvaOut)
1209                 FIXME("unsupported arguments\n");
1210             return exec_horizontalline(This);
1211         case IDM_ORDERLIST:
1212             if(pvaIn || pvaOut)
1213                 FIXME("unsupported arguments\n");
1214             return exec_orderlist(This);
1215         case IDM_UNORDERLIST:
1216             if(pvaIn || pvaOut)
1217                 FIXME("unsupported arguments\n");
1218             return exec_unorderlist(This);
1219         case IDM_INDENT:
1220             if(pvaIn || pvaOut)
1221                 FIXME("unsupported arguments\n");
1222             return exec_indent(This);
1223         case IDM_OUTDENT:
1224             if(pvaIn || pvaOut)
1225                 FIXME("unsupported arguments\n");
1226             return exec_outdent(This);
1227         case IDM_HTMLEDITMODE:
1228             if(pvaIn || pvaOut)
1229                 FIXME("unsupported arguments\n");
1230             return exec_htmleditmode(This);
1231         case IDM_COMPOSESETTINGS:
1232             if(pvaOut)
1233                 FIXME("unsupported arguments\n");
1234             return exec_composesettings(This, pvaIn);
1235         default:
1236             FIXME("unsupported nCmdID %d of CGID_MSHTML group\n", nCmdID);
1237             return OLECMDERR_E_NOTSUPPORTED;
1238         }
1239     }
1240
1241     FIXME("Unsupported pguidCmdGroup %s\n", debugstr_guid(pguidCmdGroup));
1242     return OLECMDERR_E_UNKNOWNGROUP;
1243 }
1244
1245 #undef CMDTARGET_THIS
1246
1247 static const IOleCommandTargetVtbl OleCommandTargetVtbl = {
1248     OleCommandTarget_QueryInterface,
1249     OleCommandTarget_AddRef,
1250     OleCommandTarget_Release,
1251     OleCommandTarget_QueryStatus,
1252     OleCommandTarget_Exec
1253 };
1254
1255 void HTMLDocument_OleCmd_Init(HTMLDocument *This)
1256 {
1257     This->lpOleCommandTargetVtbl = &OleCommandTargetVtbl;
1258 }