mshtml: Store URL in unicode in nsURI.
[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 const struct {
915     OLECMDF cmdf;
916     HRESULT (*func)(HTMLDocument*,DWORD,VARIANT*,VARIANT*);
917 } exec_table[OLECMDID_GETPRINTTEMPLATE+1] = {
918     {0},
919     { OLECMDF_SUPPORTED,                  exec_open                 }, /* OLECMDID_OPEN */
920     { OLECMDF_SUPPORTED,                  exec_new                  }, /* OLECMDID_NEW */
921     { OLECMDF_SUPPORTED,                  exec_save                 }, /* OLECMDID_SAVE */
922     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_save_as              }, /* OLECMDID_SAVEAS */
923     { OLECMDF_SUPPORTED,                  exec_save_copy_as         }, /* OLECMDID_SAVECOPYAS */
924     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_print                }, /* OLECMDID_PRINT */
925     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_print_preview        }, /* OLECMDID_PRINTPREVIEW */
926     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_page_setup           }, /* OLECMDID_PAGESETUP */
927     { OLECMDF_SUPPORTED,                  exec_spell                }, /* OLECMDID_SPELL */
928     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_properties           }, /* OLECMDID_PROPERTIES */
929     { OLECMDF_SUPPORTED,                  exec_cut                  }, /* OLECMDID_CUT */
930     { OLECMDF_SUPPORTED,                  exec_copy                 }, /* OLECMDID_COPY */
931     { OLECMDF_SUPPORTED,                  exec_paste                }, /* OLECMDID_PASTE */
932     { OLECMDF_SUPPORTED,                  exec_paste_special        }, /* OLECMDID_PASTESPECIAL */
933     { OLECMDF_SUPPORTED,                  exec_undo                 }, /* OLECMDID_UNDO */
934     { OLECMDF_SUPPORTED,                  exec_rendo                }, /* OLECMDID_REDO */
935     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_select_all           }, /* OLECMDID_SELECTALL */
936     { OLECMDF_SUPPORTED,                  exec_clear_selection      }, /* OLECMDID_CLEARSELECTION */
937     { OLECMDF_SUPPORTED,                  exec_zoom                 }, /* OLECMDID_ZOOM */
938     { OLECMDF_SUPPORTED,                  exec_get_zoom_range       }, /* OLECMDID_GETZOOMRANGE */
939     {0},
940     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_refresh              }, /* OLECMDID_REFRESH */
941     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_stop                 }, /* OLECMDID_STOP */
942     {0},{0},{0},{0},{0},{0},
943     { OLECMDF_SUPPORTED,                  exec_stop_download        }, /* OLECMDID_STOPDOWNLOAD */
944     {0},{0},
945     { OLECMDF_SUPPORTED,                  exec_delete               }, /* OLECMDID_DELETE */
946     {0},{0},
947     { OLECMDF_SUPPORTED,                  exec_enable_interaction   }, /* OLECMDID_ENABLE_INTERACTION */
948     { OLECMDF_SUPPORTED,                  exec_on_unload            }, /* OLECMDID_ONUNLOAD */
949     {0},{0},{0},{0},{0},
950     { OLECMDF_SUPPORTED,                  exec_show_page_setup      }, /* OLECMDID_SHOWPAGESETUP */
951     { OLECMDF_SUPPORTED,                  exec_show_print           }, /* OLECMDID_SHOWPRINT */
952     {0},{0},
953     { OLECMDF_SUPPORTED,                  exec_close                }, /* OLECMDID_CLOSE */
954     {0},{0},{0},
955     { OLECMDF_SUPPORTED,                  exec_set_print_template   }, /* OLECMDID_SETPRINTTEMPLATE */
956     { OLECMDF_SUPPORTED,                  exec_get_print_template   }  /* OLECMDID_GETPRINTTEMPLATE */
957 };
958
959 static HRESULT WINAPI OleCommandTarget_QueryInterface(IOleCommandTarget *iface, REFIID riid, void **ppv)
960 {
961     HTMLDocument *This = CMDTARGET_THIS(iface);
962     return IHTMLDocument2_QueryInterface(HTMLDOC(This), riid, ppv);
963 }
964
965 static ULONG WINAPI OleCommandTarget_AddRef(IOleCommandTarget *iface)
966 {
967     HTMLDocument *This = CMDTARGET_THIS(iface);
968     return IHTMLDocument2_AddRef(HTMLDOC(This));
969 }
970
971 static ULONG WINAPI OleCommandTarget_Release(IOleCommandTarget *iface)
972 {
973     HTMLDocument *This = CMDTARGET_THIS(iface);
974     return IHTMLDocument_Release(HTMLDOC(This));
975 }
976
977 static HRESULT WINAPI OleCommandTarget_QueryStatus(IOleCommandTarget *iface, const GUID *pguidCmdGroup,
978         ULONG cCmds, OLECMD prgCmds[], OLECMDTEXT *pCmdText)
979 {
980     HTMLDocument *This = CMDTARGET_THIS(iface);
981     HRESULT hres = S_OK, hr;
982
983     TRACE("(%p)->(%s %d %p %p)\n", This, debugstr_guid(pguidCmdGroup), cCmds, prgCmds, pCmdText);
984
985     if(!pguidCmdGroup) {
986         ULONG i;
987
988         for(i=0; i<cCmds; i++) {
989             if(prgCmds[i].cmdID<OLECMDID_OPEN || prgCmds[i].cmdID>OLECMDID_GETPRINTTEMPLATE) {
990                 WARN("Unsupported cmdID = %d\n", prgCmds[i].cmdID);
991                 prgCmds[i].cmdf = 0;
992                 hres = OLECMDERR_E_NOTSUPPORTED;
993             }else {
994                 if(prgCmds[i].cmdID == OLECMDID_OPEN || prgCmds[i].cmdID == OLECMDID_NEW) {
995                     IOleCommandTarget *cmdtrg = NULL;
996                     OLECMD olecmd;
997
998                     prgCmds[i].cmdf = OLECMDF_SUPPORTED;
999                     if(This->client) {
1000                         hr = IOleClientSite_QueryInterface(This->client, &IID_IOleCommandTarget,
1001                                 (void**)&cmdtrg);
1002                         if(SUCCEEDED(hr)) {
1003                             olecmd.cmdID = prgCmds[i].cmdID;
1004                             olecmd.cmdf = 0;
1005
1006                             hr = IOleCommandTarget_QueryStatus(cmdtrg, NULL, 1, &olecmd, NULL);
1007                             if(SUCCEEDED(hr) && olecmd.cmdf)
1008                                 prgCmds[i].cmdf = olecmd.cmdf;
1009                         }
1010                     }else {
1011                         ERR("This->client == NULL, native would crash\n");
1012                     }
1013                 }else {
1014                     prgCmds[i].cmdf = exec_table[prgCmds[i].cmdID].cmdf;
1015                     TRACE("cmdID = %d  returning %x\n", prgCmds[i].cmdID, prgCmds[i].cmdf);
1016                 }
1017                 hres = S_OK;
1018             }
1019         }
1020
1021         if(pCmdText)
1022             FIXME("Set pCmdText\n");
1023     }else if(IsEqualGUID(&CGID_MSHTML, pguidCmdGroup)) {
1024         ULONG i;
1025
1026         for(i=0; i<cCmds; i++) {
1027             switch(prgCmds[i].cmdID) {
1028             case IDM_COPY:
1029                 FIXME("CGID_MSHTML: IDM_COPY\n");
1030                 prgCmds[i].cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
1031                 break;
1032             case IDM_CUT:
1033                 FIXME("CGID_MSHTML: IDM_CUT\n");
1034                 prgCmds[i].cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
1035                 break;
1036             case IDM_FONTNAME:
1037                 TRACE("CGID_MSHTML: IDM_FONTNAME\n");
1038                 prgCmds[i].cmdf = query_edit_status(This, NULL);
1039                 break;
1040             case IDM_FONTSIZE:
1041                 TRACE("CGID_MSHTML: IDM_FONTSIZE\n");
1042                 prgCmds[i].cmdf = query_edit_status(This, NULL);
1043                 break;
1044             case IDM_PRINT:
1045                 FIXME("CGID_MSHTML: IDM_PRINT\n");
1046                 prgCmds[i].cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
1047                 break;
1048             case IDM_PASTE:
1049                 FIXME("CGID_MSHTML: IDM_PASTE\n");
1050                 prgCmds[i].cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
1051                 break;
1052             case IDM_BOLD:
1053                 TRACE("CGID_MSHTML: IDM_BOLD\n");
1054                 prgCmds[i].cmdf = query_edit_status(This, NSCMD_BOLD);
1055                 break;
1056             case IDM_FORECOLOR:
1057                 TRACE("CGID_MSHTML: IDM_FORECOLOR\n");
1058                 prgCmds[i].cmdf = query_edit_status(This, NULL);
1059                 break;
1060             case IDM_ITALIC:
1061                 TRACE("CGID_MSHTML: IDM_ITALIC\n");
1062                 prgCmds[i].cmdf = query_edit_status(This, NSCMD_ITALIC);
1063                 break;
1064             case IDM_JUSTIFYCENTER:
1065                 TRACE("CGID_MSHTML: IDM_JUSTIFYCENTER\n");
1066                 prgCmds[i].cmdf = query_align_status(This, NSALIGN_CENTER);
1067                 break;
1068             case IDM_JUSTIFYLEFT:
1069                 TRACE("CGID_MSHTML: IDM_JUSTIFYLEFT\n");
1070                 prgCmds[i].cmdf = query_align_status(This, NSALIGN_LEFT);
1071                 break;
1072             case IDM_JUSTIFYRIGHT:
1073                 TRACE("CGID_MSHTML: IDM_JUSTIFYRIGHT\n");
1074                 prgCmds[i].cmdf = query_align_status(This, NSALIGN_RIGHT);
1075                 break;
1076             case IDM_UNDERLINE:
1077                 TRACE("CGID_MSHTML: IDM_UNDERLINE\n");
1078                 prgCmds[i].cmdf = query_edit_status(This, NSCMD_UNDERLINE);
1079                 break;
1080             case IDM_HORIZONTALLINE:
1081                 TRACE("CGID_MSHTML: IDM_HORIZONTALLINE\n");
1082                 prgCmds[i].cmdf = query_edit_status(This, NULL);
1083                 break;
1084             case IDM_ORDERLIST:
1085                 TRACE("CGID_MSHTML: IDM_ORDERLIST\n");
1086                 prgCmds[i].cmdf = query_edit_status(This, NSCMD_OL);
1087                 break;
1088             case IDM_UNORDERLIST:
1089                 TRACE("CGID_MSHTML: IDM_HORIZONTALLINE\n");
1090                 prgCmds[i].cmdf = query_edit_status(This, NSCMD_UL);
1091                 break;
1092             case IDM_INDENT:
1093                 TRACE("CGID_MSHTML: IDM_INDENT\n");
1094                 prgCmds[i].cmdf = query_edit_status(This, NULL);
1095                 break;
1096             case IDM_OUTDENT:
1097                 TRACE("CGID_MSHTML: IDM_OUTDENT\n");
1098                 prgCmds[i].cmdf = query_edit_status(This, NULL);
1099                 break;
1100             case IDM_BLOCKDIRLTR:
1101                 FIXME("CGID_MSHTML: IDM_BLOCKDIRLTR\n");
1102                 prgCmds[i].cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
1103                 break;
1104             case IDM_BLOCKDIRRTL:
1105                 FIXME("CGID_MSHTML: IDM_BLOCKDIRRTL\n");
1106                 prgCmds[i].cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
1107                 break;
1108             default:
1109                 FIXME("CGID_MSHTML: unsupported cmdID %d\n", prgCmds[i].cmdID);
1110                 prgCmds[i].cmdf = 0;
1111             }
1112         }
1113
1114         hres = prgCmds[i-1].cmdf ? S_OK : OLECMDERR_E_NOTSUPPORTED;
1115
1116         if(pCmdText)
1117             FIXME("Set pCmdText\n");
1118     }else {
1119         FIXME("Unsupported pguidCmdGroup %s\n", debugstr_guid(pguidCmdGroup));
1120         hres = OLECMDERR_E_UNKNOWNGROUP;
1121     }
1122
1123     return hres;
1124 }
1125
1126 static HRESULT WINAPI OleCommandTarget_Exec(IOleCommandTarget *iface, const GUID *pguidCmdGroup,
1127         DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
1128 {
1129     HTMLDocument *This = CMDTARGET_THIS(iface);
1130
1131     if(!pguidCmdGroup) {
1132         if(nCmdID<OLECMDID_OPEN || nCmdID>OLECMDID_GETPRINTTEMPLATE || !exec_table[nCmdID].func) {
1133             WARN("Unsupported cmdID = %d\n", nCmdID);
1134             return OLECMDERR_E_NOTSUPPORTED;
1135         }
1136
1137         return exec_table[nCmdID].func(This, nCmdexecopt, pvaIn, pvaOut);
1138     }else if(IsEqualGUID(&CGID_Explorer, pguidCmdGroup)) {
1139         FIXME("unsupported nCmdID %d of CGID_Explorer group\n", nCmdID);
1140         TRACE("%p %p\n", pvaIn, pvaOut);
1141         return OLECMDERR_E_NOTSUPPORTED;
1142     }else if(IsEqualGUID(&CGID_ShellDocView, pguidCmdGroup)) {
1143         FIXME("unsupported nCmdID %d of CGID_ShellDocView group\n", nCmdID);
1144         return OLECMDERR_E_NOTSUPPORTED;
1145     }else if(IsEqualGUID(&CGID_MSHTML, pguidCmdGroup)) {
1146         switch(nCmdID) {
1147         case IDM_FONTNAME:
1148             return exec_fontname(This, pvaIn, pvaOut);
1149         case IDM_FONTSIZE:
1150             return exec_fontsize(This, pvaIn, pvaOut);
1151         case IDM_PRINT:
1152             return exec_print(This, nCmdexecopt, pvaIn, pvaOut);
1153         case IDM_BOLD:
1154             if(pvaIn || pvaOut)
1155                 FIXME("unsupported arguments\n");
1156             return exec_bold(This);
1157         case IDM_FORECOLOR:
1158             return exec_forecolor(This, pvaIn, pvaOut);
1159         case IDM_ITALIC:
1160             if(pvaIn || pvaOut)
1161                 FIXME("unsupported arguments\n");
1162             return exec_italic(This);
1163         case IDM_JUSTIFYCENTER:
1164             if(pvaIn || pvaOut)
1165                 FIXME("unsupported arguments\n");
1166             return exec_justifycenter(This);
1167         case IDM_JUSTIFYLEFT:
1168             if(pvaIn || pvaOut)
1169                 FIXME("unsupported arguments\n");
1170             return exec_justifyleft(This);
1171         case IDM_JUSTIFYRIGHT:
1172             if(pvaIn || pvaOut)
1173                 FIXME("unsupported arguments\n");
1174             return exec_justifyright(This);
1175         case IDM_UNDERLINE:
1176             if(pvaIn || pvaOut)
1177                 FIXME("unsupported arguments\n");
1178             return exec_underline(This);
1179         case IDM_BROWSEMODE:
1180             if(pvaIn || pvaOut)
1181                 FIXME("unsupported arguments\n");
1182             return exec_browsemode(This);
1183         case IDM_EDITMODE:
1184             if(pvaIn || pvaOut)
1185                 FIXME("unsupported arguments\n");
1186             return exec_editmode(This);
1187         case IDM_BASELINEFONT3:
1188             return exec_baselinefont3(This);
1189         case IDM_HORIZONTALLINE:
1190             if(pvaIn || pvaOut)
1191                 FIXME("unsupported arguments\n");
1192             return exec_horizontalline(This);
1193         case IDM_ORDERLIST:
1194             if(pvaIn || pvaOut)
1195                 FIXME("unsupported arguments\n");
1196             return exec_orderlist(This);
1197         case IDM_UNORDERLIST:
1198             if(pvaIn || pvaOut)
1199                 FIXME("unsupported arguments\n");
1200             return exec_unorderlist(This);
1201         case IDM_INDENT:
1202             if(pvaIn || pvaOut)
1203                 FIXME("unsupported arguments\n");
1204             return exec_indent(This);
1205         case IDM_OUTDENT:
1206             if(pvaIn || pvaOut)
1207                 FIXME("unsupported arguments\n");
1208             return exec_outdent(This);
1209         default:
1210             FIXME("unsupported nCmdID %d of CGID_MSHTML group\n", nCmdID);
1211             return OLECMDERR_E_NOTSUPPORTED;
1212         }
1213     }
1214
1215     FIXME("Unsupported pguidCmdGroup %s\n", debugstr_guid(pguidCmdGroup));
1216     return OLECMDERR_E_UNKNOWNGROUP;
1217 }
1218
1219 #undef CMDTARGET_THIS
1220
1221 static const IOleCommandTargetVtbl OleCommandTargetVtbl = {
1222     OleCommandTarget_QueryInterface,
1223     OleCommandTarget_AddRef,
1224     OleCommandTarget_Release,
1225     OleCommandTarget_QueryStatus,
1226     OleCommandTarget_Exec
1227 };
1228
1229 void HTMLDocument_OleCmd_Init(HTMLDocument *This)
1230 {
1231     This->lpOleCommandTargetVtbl = &OleCommandTargetVtbl;
1232 }