mshtml: Use ActiveScript for JavaScript in about protocol documents.
[wine] / dlls / mshtml / olecmd.c
1 /*
2  * Copyright 2005-2007 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
21 #define COBJMACROS
22
23 #include "windef.h"
24 #include "winbase.h"
25 #include "winuser.h"
26 #include "ole2.h"
27 #include "shlguid.h"
28 #include "mshtmdid.h"
29 #include "idispids.h"
30 #include "mshtmcid.h"
31
32 #include "wine/debug.h"
33 #include "wine/unicode.h"
34
35 #include "mshtml_private.h"
36 #include "resource.h"
37
38 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
39
40 #define NSCMD_COPY "cmd_copy"
41
42 void do_ns_command(NSContainer *This, const char *cmd, nsICommandParams *nsparam)
43 {
44     nsICommandManager *cmdmgr;
45     nsresult nsres;
46
47     TRACE("(%p)\n", This);
48
49     nsres = get_nsinterface((nsISupports*)This->webbrowser, &IID_nsICommandManager, (void**)&cmdmgr);
50     if(NS_FAILED(nsres)) {
51         ERR("Could not get nsICommandManager: %08x\n", nsres);
52         return;
53     }
54
55     nsres = nsICommandManager_DoCommand(cmdmgr, cmd, nsparam, This->doc->window->nswindow);
56     if(NS_FAILED(nsres))
57         ERR("DoCommand(%s) failed: %08x\n", debugstr_a(cmd), nsres);
58
59     nsICommandManager_Release(cmdmgr);
60 }
61
62 /**********************************************************
63  * IOleCommandTarget implementation
64  */
65
66 #define CMDTARGET_THIS(iface) DEFINE_THIS(HTMLDocument, OleCommandTarget, iface)
67
68 static HRESULT exec_open(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
69 {
70     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
71     return E_NOTIMPL;
72 }
73
74 static HRESULT exec_new(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
75 {
76     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
77     return E_NOTIMPL;
78 }
79
80 static HRESULT exec_save(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
81 {
82     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
83     return E_NOTIMPL;
84 }
85
86 static HRESULT exec_save_as(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
87 {
88     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
89     return E_NOTIMPL;
90 }
91
92 static HRESULT exec_save_copy_as(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
93 {
94     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
95     return E_NOTIMPL;
96 }
97
98 static nsresult set_head_text(nsIPrintSettings *settings, LPCWSTR template, BOOL head, int pos)
99 {
100     if(head) {
101         switch(pos) {
102         case 0:
103             return nsIPrintSettings_SetHeaderStrLeft(settings, template);
104         case 1:
105             return nsIPrintSettings_SetHeaderStrRight(settings, template);
106         case 2:
107             return nsIPrintSettings_SetHeaderStrCenter(settings, template);
108         }
109     }else {
110         switch(pos) {
111         case 0:
112             return nsIPrintSettings_SetFooterStrLeft(settings, template);
113         case 1:
114             return nsIPrintSettings_SetFooterStrRight(settings, template);
115         case 2:
116             return nsIPrintSettings_SetFooterStrCenter(settings, template);
117         }
118     }
119
120     return NS_OK;
121 }
122
123 static void set_print_template(nsIPrintSettings *settings, LPCWSTR template, BOOL head)
124 {
125     PRUnichar nstemplate[200]; /* FIXME: Use dynamic allocation */
126     PRUnichar *p = nstemplate;
127     LPCWSTR ptr=template;
128     int pos=0;
129
130     while(*ptr) {
131         if(*ptr != '&') {
132             *p++ = *ptr++;
133             continue;
134         }
135
136         switch(*++ptr) {
137         case '&':
138             *p++ = '&';
139             *p++ = '&';
140             ptr++;
141             break;
142         case 'b': /* change align */
143             ptr++;
144             *p = 0;
145             set_head_text(settings, nstemplate, head, pos);
146             p = nstemplate;
147             pos++;
148             break;
149         case 'd': { /* short date */
150             SYSTEMTIME systime;
151             GetLocalTime(&systime);
152             GetDateFormatW(LOCALE_SYSTEM_DEFAULT, 0, &systime, NULL, p,
153                     sizeof(nstemplate)-(p-nstemplate)*sizeof(WCHAR));
154             p += strlenW(p);
155             ptr++;
156             break;
157         }
158         case 'p': /* page number */
159             *p++ = '&';
160             *p++ = 'P';
161             ptr++;
162             break;
163         case 'P': /* page count */
164             *p++ = '?'; /* FIXME */
165             ptr++;
166             break;
167         case 'u':
168             *p++ = '&';
169             *p++ = 'U';
170             ptr++;
171             break;
172         case 'w':
173             /* FIXME: set window title */
174             ptr++;
175             break;
176         default:
177             *p++ = '&';
178             *p++ = *ptr++;
179         }
180     }
181
182     *p = 0;
183     set_head_text(settings, nstemplate, head, pos);
184
185     while(++pos < 3)
186         set_head_text(settings, p, head, pos);
187 }
188
189 static void set_default_templates(nsIPrintSettings *settings)
190 {
191     WCHAR buf[64];
192
193     static const PRUnichar empty[] = {0};
194
195     nsIPrintSettings_SetHeaderStrLeft(settings, empty);
196     nsIPrintSettings_SetHeaderStrRight(settings, empty);
197     nsIPrintSettings_SetHeaderStrCenter(settings, empty);
198     nsIPrintSettings_SetFooterStrLeft(settings, empty);
199     nsIPrintSettings_SetFooterStrRight(settings, empty);
200     nsIPrintSettings_SetFooterStrCenter(settings, empty);
201
202     if(LoadStringW(get_shdoclc(), IDS_PRINT_HEADER_TEMPLATE, buf,
203                    sizeof(buf)/sizeof(WCHAR)))
204         set_print_template(settings, buf, TRUE);
205
206
207     if(LoadStringW(get_shdoclc(), IDS_PRINT_FOOTER_TEMPLATE, buf,
208                    sizeof(buf)/sizeof(WCHAR)))
209         set_print_template(settings, buf, FALSE);
210
211 }
212
213 static HRESULT exec_print(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
214 {
215     nsIWebBrowserPrint *nsprint;
216     nsIPrintSettings *settings;
217     nsresult nsres;
218
219     TRACE("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
220
221     if(pvaOut)
222         FIXME("unsupported pvaOut\n");
223
224     if(!This->nscontainer)
225         return S_OK;
226
227     nsres = get_nsinterface((nsISupports*)This->nscontainer->webbrowser, &IID_nsIWebBrowserPrint,
228             (void**)&nsprint);
229     if(NS_FAILED(nsres)) {
230         ERR("Could not get nsIWebBrowserPrint: %08x\n", nsres);
231         return S_OK;
232     }
233
234     nsres = nsIWebBrowserPrint_GetGlobalPrintSettings(nsprint, &settings);
235     if(NS_FAILED(nsres))
236         ERR("GetCurrentPrintSettings failed: %08x\n", nsres);
237
238     set_default_templates(settings);
239
240     if(pvaIn) {
241         switch(V_VT(pvaIn)) {
242         case VT_BYREF|VT_ARRAY: {
243             VARIANT *opts;
244             DWORD opts_cnt;
245
246             if(V_ARRAY(pvaIn)->cDims != 1)
247                 WARN("cDims = %d\n", V_ARRAY(pvaIn)->cDims);
248
249             SafeArrayAccessData(V_ARRAY(pvaIn), (void**)&opts);
250             opts_cnt = V_ARRAY(pvaIn)->rgsabound[0].cElements;
251
252             if(opts_cnt >= 1) {
253                 switch(V_VT(opts)) {
254                 case VT_BSTR:
255                     TRACE("setting footer %s\n", debugstr_w(V_BSTR(opts)));
256                     set_print_template(settings, V_BSTR(opts), TRUE);
257                     break;
258                 case VT_NULL:
259                     break;
260                 default:
261                     WARN("V_VT(opts) = %d\n", V_VT(opts));
262                 }
263             }
264
265             if(opts_cnt >= 2) {
266                 switch(V_VT(opts+1)) {
267                 case VT_BSTR:
268                     TRACE("setting footer %s\n", debugstr_w(V_BSTR(opts+1)));
269                     set_print_template(settings, V_BSTR(opts+1), FALSE);
270                     break;
271                 case VT_NULL:
272                     break;
273                 default:
274                     WARN("V_VT(opts) = %d\n", V_VT(opts+1));
275                 }
276             }
277
278             if(opts_cnt >= 3)
279                 FIXME("Unsupported opts_cnt %d\n", opts_cnt);
280
281             SafeArrayUnaccessData(V_ARRAY(pvaIn));
282             break;
283         }
284         default:
285             FIXME("unsupported vt %x\n", V_VT(pvaIn));
286         }
287     }
288
289     nsres = nsIWebBrowserPrint_Print(nsprint, settings, NULL);
290     if(NS_FAILED(nsres))
291         ERR("Print failed: %08x\n", nsres);
292
293     nsIWebBrowserPrint_Release(nsprint);
294
295     return S_OK;
296 }
297
298 static HRESULT exec_print_preview(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
299 {
300     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
301     return E_NOTIMPL;
302 }
303
304 static HRESULT exec_page_setup(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
305 {
306     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
307     return E_NOTIMPL;
308 }
309
310 static HRESULT exec_spell(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
311 {
312     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
313     return E_NOTIMPL;
314 }
315
316 static HRESULT exec_properties(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
317 {
318     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
319     return E_NOTIMPL;
320 }
321
322 static HRESULT exec_cut(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
323 {
324     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
325     return E_NOTIMPL;
326 }
327
328 static HRESULT exec_copy(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
329 {
330     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
331     return E_NOTIMPL;
332 }
333
334 static HRESULT exec_paste(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
335 {
336     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
337     return E_NOTIMPL;
338 }
339
340 static HRESULT exec_paste_special(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
341 {
342     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
343     return E_NOTIMPL;
344 }
345
346 static HRESULT exec_undo(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
347 {
348     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
349     return E_NOTIMPL;
350 }
351
352 static HRESULT exec_rendo(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
353 {
354     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
355     return E_NOTIMPL;
356 }
357
358 static HRESULT exec_select_all(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
359 {
360     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
361     return E_NOTIMPL;
362 }
363
364 static HRESULT exec_clear_selection(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
365 {
366     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
367     return E_NOTIMPL;
368 }
369
370 static HRESULT exec_zoom(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
371 {
372     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
373     return E_NOTIMPL;
374 }
375
376 static HRESULT exec_get_zoom_range(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
377 {
378     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
379     return E_NOTIMPL;
380 }
381
382 static HRESULT exec_refresh(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
383 {
384     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
385     return E_NOTIMPL;
386 }
387
388 static HRESULT exec_stop(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
389 {
390     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
391     return E_NOTIMPL;
392 }
393
394 static HRESULT exec_stop_download(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
395 {
396     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
397     return E_NOTIMPL;
398 }
399
400 static HRESULT exec_find(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
401 {
402     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
403     return E_NOTIMPL;
404 }
405
406 static HRESULT exec_delete(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
407 {
408     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
409     return E_NOTIMPL;
410 }
411
412 static HRESULT exec_enable_interaction(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
413 {
414     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
415     return E_NOTIMPL;
416 }
417
418 static HRESULT exec_on_unload(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
419 {
420     TRACE("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
421
422     /* Tests show that we have nothing more to do here */
423
424     if(pvaOut) {
425         V_VT(pvaOut) = VT_BOOL;
426         V_BOOL(pvaOut) = VARIANT_TRUE;
427     }
428
429     return S_OK;
430 }
431
432 static HRESULT exec_show_page_setup(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
433 {
434     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
435     return E_NOTIMPL;
436 }
437
438 static HRESULT exec_show_print(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
439 {
440     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
441     return E_NOTIMPL;
442 }
443
444 static HRESULT exec_close(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
445 {
446     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
447     return E_NOTIMPL;
448 }
449
450 static HRESULT exec_set_print_template(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
451 {
452     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
453     return E_NOTIMPL;
454 }
455
456 static HRESULT exec_get_print_template(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
457 {
458     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
459     return E_NOTIMPL;
460 }
461
462 static HRESULT query_mshtml_copy(HTMLDocument *This, OLECMD *cmd)
463 {
464     FIXME("(%p)\n", This);
465     cmd->cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
466     return S_OK;
467 }
468
469 static HRESULT exec_mshtml_copy(HTMLDocument *This, DWORD cmdexecopt, VARIANT *in, VARIANT *out)
470 {
471     TRACE("(%p)->(%08x %p %p)\n", This, cmdexecopt, in, out);
472
473     if(This->usermode == EDITMODE)
474         return editor_exec_copy(This, cmdexecopt, in, out);
475
476     do_ns_command(This->nscontainer, NSCMD_COPY, NULL);
477     return S_OK;
478 }
479
480 static HRESULT query_mshtml_cut(HTMLDocument *This, OLECMD *cmd)
481 {
482     FIXME("(%p)\n", This);
483     cmd->cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
484     return S_OK;
485 }
486
487 static HRESULT exec_mshtml_cut(HTMLDocument *This, DWORD cmdexecopt, VARIANT *in, VARIANT *out)
488 {
489     TRACE("(%p)->(%08x %p %p)\n", This, cmdexecopt, in, out);
490
491     if(This->usermode == EDITMODE)
492         return editor_exec_cut(This, cmdexecopt, in, out);
493
494     FIXME("Unimplemented in browse mode\n");
495     return E_NOTIMPL;
496 }
497
498 static HRESULT query_mshtml_paste(HTMLDocument *This, OLECMD *cmd)
499 {
500     FIXME("(%p)\n", This);
501     cmd->cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
502     return S_OK;
503 }
504
505 static HRESULT exec_mshtml_paste(HTMLDocument *This, DWORD cmdexecopt, VARIANT *in, VARIANT *out)
506 {
507     TRACE("(%p)->(%08x %p %p)\n", This, cmdexecopt, in, out);
508
509     if(This->usermode == EDITMODE)
510         return editor_exec_paste(This, cmdexecopt, in, out);
511
512     FIXME("Unimplemented in browse mode\n");
513     return E_NOTIMPL;
514 }
515
516 static HRESULT exec_browsemode(HTMLDocument *This, DWORD cmdexecopt, VARIANT *in, VARIANT *out)
517 {
518     WARN("(%p)->(%08x %p %p)\n", This, cmdexecopt, in, out);
519
520     if(in || out)
521         FIXME("unsupported args\n");
522
523     This->usermode = BROWSEMODE;
524
525     return S_OK;
526 }
527
528 static HRESULT exec_editmode(HTMLDocument *This, DWORD cmdexecopt, VARIANT *in, VARIANT *out)
529 {
530     IMoniker *mon;
531     HRESULT hres;
532
533     TRACE("(%p)->(%08x %p %p)\n", This, cmdexecopt, in, out);
534
535     if(in || out)
536         FIXME("unsupported args\n");
537
538     if(This->usermode == EDITMODE)
539         return S_OK;
540
541     This->usermode = EDITMODE;
542
543     if(This->mon) {
544         CLSID clsid = IID_NULL;
545         hres = IMoniker_GetClassID(This->mon, &clsid);
546         if(SUCCEEDED(hres)) {
547             /* We should use IMoniker::Save here */
548             FIXME("Use CLSID %s\n", debugstr_guid(&clsid));
549         }
550     }
551
552     if(This->frame)
553         IOleInPlaceFrame_SetStatusText(This->frame, NULL);
554
555     This->readystate = READYSTATE_UNINITIALIZED;
556
557     if(This->client) {
558         IOleCommandTarget *cmdtrg;
559
560         hres = IOleClientSite_QueryInterface(This->client, &IID_IOleCommandTarget,
561                 (void**)&cmdtrg);
562         if(SUCCEEDED(hres)) {
563             VARIANT var;
564
565             V_VT(&var) = VT_I4;
566             V_I4(&var) = 0;
567             IOleCommandTarget_Exec(cmdtrg, &CGID_ShellDocView, 37, 0, &var, NULL);
568
569             IOleCommandTarget_Release(cmdtrg);
570         }
571     }
572
573     if(This->hostui) {
574         DOCHOSTUIINFO hostinfo;
575
576         memset(&hostinfo, 0, sizeof(DOCHOSTUIINFO));
577         hostinfo.cbSize = sizeof(DOCHOSTUIINFO);
578         hres = IDocHostUIHandler_GetHostInfo(This->hostui, &hostinfo);
579         if(SUCCEEDED(hres))
580             /* FIXME: use hostinfo */
581             TRACE("hostinfo = {%u %08x %08x %s %s}\n",
582                     hostinfo.cbSize, hostinfo.dwFlags, hostinfo.dwDoubleClick,
583                     debugstr_w(hostinfo.pchHostCss), debugstr_w(hostinfo.pchHostNS));
584     }
585
586     update_doc(This, UPDATE_UI);
587
588     if(This->mon) {
589         /* FIXME: We should find nicer way to do this */
590         remove_doc_tasks(This);
591
592         mon = This->mon;
593         IMoniker_AddRef(mon);
594     }else {
595         static const WCHAR about_blankW[] = {'a','b','o','u','t',':','b','l','a','n','k',0};
596
597         hres = CreateURLMoniker(NULL, about_blankW, &mon);
598         if(FAILED(hres)) {
599             FIXME("CreateURLMoniker failed: %08x\n", hres);
600             return hres;
601         }
602     }
603
604     hres = IPersistMoniker_Load(PERSISTMON(This), TRUE, mon, NULL, 0);
605     IMoniker_Release(mon);
606     if(FAILED(hres))
607         return hres;
608
609     if(This->ui_active) {
610         if(This->ip_window)
611             call_set_active_object(This->ip_window, NULL);
612         if(This->hostui)
613             IDocHostUIHandler_HideUI(This->hostui);
614     }
615
616     if(This->nscontainer)
617         set_ns_editmode(This->nscontainer);
618
619     if(This->ui_active) {
620         RECT rcBorderWidths;
621
622         if(This->hostui)
623             IDocHostUIHandler_ShowUI(This->hostui, DOCHOSTUITYPE_AUTHOR, ACTOBJ(This), CMDTARGET(This),
624                 This->frame, This->ip_window);
625
626         if(This->ip_window)
627             call_set_active_object(This->ip_window, ACTOBJ(This));
628
629         memset(&rcBorderWidths, 0, sizeof(rcBorderWidths));
630         if (This->frame)
631             IOleInPlaceFrame_SetBorderSpace(This->frame, &rcBorderWidths);
632     }
633
634     return S_OK;
635 }
636
637 static HRESULT exec_htmleditmode(HTMLDocument *This, DWORD cmdexecopt, VARIANT *in, VARIANT *out)
638 {
639     FIXME("(%p)->(%08x %p %p)\n", This, cmdexecopt, in, out);
640     return S_OK;
641 }
642
643 static HRESULT exec_baselinefont3(HTMLDocument *This, DWORD cmdexecopt, VARIANT *in, VARIANT *out)
644 {
645     FIXME("(%p)->(%08x %p %p)\n", This, cmdexecopt, in, out);
646     return S_OK;
647 }
648
649 static HRESULT exec_respectvisibility_indesign(HTMLDocument *This, DWORD cmdexecopt,
650         VARIANT *in, VARIANT *out)
651 {
652     FIXME("(%p)->(%08x %p %p)\n", This, cmdexecopt, in, out);
653     return E_NOTIMPL;
654 }
655
656 static HRESULT query_enabled_stub(HTMLDocument *This, OLECMD *cmd)
657 {
658     switch(cmd->cmdID) {
659     case IDM_PRINT:
660         FIXME("CGID_MSHTML: IDM_PRINT\n");
661         cmd->cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
662         break;
663     case IDM_BLOCKDIRLTR:
664         FIXME("CGID_MSHTML: IDM_BLOCKDIRLTR\n");
665         cmd->cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
666         break;
667     case IDM_BLOCKDIRRTL:
668         FIXME("CGID_MSHTML: IDM_BLOCKDIRRTL\n");
669         cmd->cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
670         break;
671     }
672
673     return S_OK;
674 }
675
676 static const struct {
677     OLECMDF cmdf;
678     HRESULT (*func)(HTMLDocument*,DWORD,VARIANT*,VARIANT*);
679 } exec_table[OLECMDID_GETPRINTTEMPLATE+1] = {
680     {0},
681     { OLECMDF_SUPPORTED,                  exec_open                 }, /* OLECMDID_OPEN */
682     { OLECMDF_SUPPORTED,                  exec_new                  }, /* OLECMDID_NEW */
683     { OLECMDF_SUPPORTED,                  exec_save                 }, /* OLECMDID_SAVE */
684     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_save_as              }, /* OLECMDID_SAVEAS */
685     { OLECMDF_SUPPORTED,                  exec_save_copy_as         }, /* OLECMDID_SAVECOPYAS */
686     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_print                }, /* OLECMDID_PRINT */
687     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_print_preview        }, /* OLECMDID_PRINTPREVIEW */
688     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_page_setup           }, /* OLECMDID_PAGESETUP */
689     { OLECMDF_SUPPORTED,                  exec_spell                }, /* OLECMDID_SPELL */
690     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_properties           }, /* OLECMDID_PROPERTIES */
691     { OLECMDF_SUPPORTED,                  exec_cut                  }, /* OLECMDID_CUT */
692     { OLECMDF_SUPPORTED,                  exec_copy                 }, /* OLECMDID_COPY */
693     { OLECMDF_SUPPORTED,                  exec_paste                }, /* OLECMDID_PASTE */
694     { OLECMDF_SUPPORTED,                  exec_paste_special        }, /* OLECMDID_PASTESPECIAL */
695     { OLECMDF_SUPPORTED,                  exec_undo                 }, /* OLECMDID_UNDO */
696     { OLECMDF_SUPPORTED,                  exec_rendo                }, /* OLECMDID_REDO */
697     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_select_all           }, /* OLECMDID_SELECTALL */
698     { OLECMDF_SUPPORTED,                  exec_clear_selection      }, /* OLECMDID_CLEARSELECTION */
699     { OLECMDF_SUPPORTED,                  exec_zoom                 }, /* OLECMDID_ZOOM */
700     { OLECMDF_SUPPORTED,                  exec_get_zoom_range       }, /* OLECMDID_GETZOOMRANGE */
701     {0},
702     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_refresh              }, /* OLECMDID_REFRESH */
703     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_stop                 }, /* OLECMDID_STOP */
704     {0},{0},{0},{0},{0},{0},
705     { OLECMDF_SUPPORTED,                  exec_stop_download        }, /* OLECMDID_STOPDOWNLOAD */
706     {0},
707     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_find                 }, /* OLECMDID_FIND */
708     { OLECMDF_SUPPORTED,                  exec_delete               }, /* OLECMDID_DELETE */
709     {0},{0},
710     { OLECMDF_SUPPORTED,                  exec_enable_interaction   }, /* OLECMDID_ENABLE_INTERACTION */
711     { OLECMDF_SUPPORTED,                  exec_on_unload            }, /* OLECMDID_ONUNLOAD */
712     {0},{0},{0},{0},{0},
713     { OLECMDF_SUPPORTED,                  exec_show_page_setup      }, /* OLECMDID_SHOWPAGESETUP */
714     { OLECMDF_SUPPORTED,                  exec_show_print           }, /* OLECMDID_SHOWPRINT */
715     {0},{0},
716     { OLECMDF_SUPPORTED,                  exec_close                }, /* OLECMDID_CLOSE */
717     {0},{0},{0},
718     { OLECMDF_SUPPORTED,                  exec_set_print_template   }, /* OLECMDID_SETPRINTTEMPLATE */
719     { OLECMDF_SUPPORTED,                  exec_get_print_template   }  /* OLECMDID_GETPRINTTEMPLATE */
720 };
721
722 static const cmdtable_t base_cmds[] = {
723     {IDM_COPY,             query_mshtml_copy,     exec_mshtml_copy},
724     {IDM_PASTE,            query_mshtml_paste,    exec_mshtml_paste},
725     {IDM_CUT,              query_mshtml_cut,      exec_mshtml_cut},
726     {IDM_BROWSEMODE,       NULL,                  exec_browsemode},
727     {IDM_EDITMODE,         NULL,                  exec_editmode},
728     {IDM_PRINT,            query_enabled_stub,    exec_print},
729     {IDM_HTMLEDITMODE,     NULL,                  exec_htmleditmode},
730     {IDM_BASELINEFONT3,    NULL,                  exec_baselinefont3},
731     {IDM_BLOCKDIRLTR,      query_enabled_stub,    NULL},
732     {IDM_BLOCKDIRRTL,      query_enabled_stub,    NULL},
733     {IDM_RESPECTVISIBILITY_INDESIGN, NULL,        exec_respectvisibility_indesign},
734     {0,NULL,NULL}
735 };
736
737 static HRESULT WINAPI OleCommandTarget_QueryInterface(IOleCommandTarget *iface, REFIID riid, void **ppv)
738 {
739     HTMLDocument *This = CMDTARGET_THIS(iface);
740     return IHTMLDocument2_QueryInterface(HTMLDOC(This), riid, ppv);
741 }
742
743 static ULONG WINAPI OleCommandTarget_AddRef(IOleCommandTarget *iface)
744 {
745     HTMLDocument *This = CMDTARGET_THIS(iface);
746     return IHTMLDocument2_AddRef(HTMLDOC(This));
747 }
748
749 static ULONG WINAPI OleCommandTarget_Release(IOleCommandTarget *iface)
750 {
751     HTMLDocument *This = CMDTARGET_THIS(iface);
752     return IHTMLDocument_Release(HTMLDOC(This));
753 }
754
755 static HRESULT query_from_table(HTMLDocument *This, const cmdtable_t *cmdtable, OLECMD *cmd)
756 {
757     const cmdtable_t *iter = cmdtable;
758
759     cmd->cmdf = 0;
760
761     while(iter->id && iter->id != cmd->cmdID)
762         iter++;
763
764     if(!iter->id || !iter->query)
765         return OLECMDERR_E_NOTSUPPORTED;
766
767     return iter->query(This, cmd);
768 }
769
770 static HRESULT WINAPI OleCommandTarget_QueryStatus(IOleCommandTarget *iface, const GUID *pguidCmdGroup,
771         ULONG cCmds, OLECMD prgCmds[], OLECMDTEXT *pCmdText)
772 {
773     HTMLDocument *This = CMDTARGET_THIS(iface);
774     HRESULT hres = S_OK, hr;
775
776     TRACE("(%p)->(%s %d %p %p)\n", This, debugstr_guid(pguidCmdGroup), cCmds, prgCmds, pCmdText);
777
778     if(!pguidCmdGroup) {
779         ULONG i;
780
781         for(i=0; i<cCmds; i++) {
782             if(prgCmds[i].cmdID<OLECMDID_OPEN || prgCmds[i].cmdID>OLECMDID_GETPRINTTEMPLATE) {
783                 WARN("Unsupported cmdID = %d\n", prgCmds[i].cmdID);
784                 prgCmds[i].cmdf = 0;
785                 hres = OLECMDERR_E_NOTSUPPORTED;
786             }else {
787                 if(prgCmds[i].cmdID == OLECMDID_OPEN || prgCmds[i].cmdID == OLECMDID_NEW) {
788                     IOleCommandTarget *cmdtrg = NULL;
789                     OLECMD olecmd;
790
791                     prgCmds[i].cmdf = OLECMDF_SUPPORTED;
792                     if(This->client) {
793                         hr = IOleClientSite_QueryInterface(This->client, &IID_IOleCommandTarget,
794                                 (void**)&cmdtrg);
795                         if(SUCCEEDED(hr)) {
796                             olecmd.cmdID = prgCmds[i].cmdID;
797                             olecmd.cmdf = 0;
798
799                             hr = IOleCommandTarget_QueryStatus(cmdtrg, NULL, 1, &olecmd, NULL);
800                             if(SUCCEEDED(hr) && olecmd.cmdf)
801                                 prgCmds[i].cmdf = olecmd.cmdf;
802                         }
803                     }else {
804                         ERR("This->client == NULL, native would crash\n");
805                     }
806                 }else {
807                     prgCmds[i].cmdf = exec_table[prgCmds[i].cmdID].cmdf;
808                     TRACE("cmdID = %d  returning %x\n", prgCmds[i].cmdID, prgCmds[i].cmdf);
809                 }
810                 hres = S_OK;
811             }
812         }
813
814         if(pCmdText)
815             FIXME("Set pCmdText\n");
816     }else if(IsEqualGUID(&CGID_MSHTML, pguidCmdGroup)) {
817         ULONG i;
818
819         for(i=0; i<cCmds; i++) {
820             HRESULT hres = query_from_table(This, base_cmds, prgCmds+i);
821             if(hres == OLECMDERR_E_NOTSUPPORTED)
822                 hres = query_from_table(This, editmode_cmds, prgCmds+i);
823             if(hres == OLECMDERR_E_NOTSUPPORTED)
824                 FIXME("CGID_MSHTML: unsupported cmdID %d\n", prgCmds[i].cmdID);
825         }
826
827         hres = prgCmds[i-1].cmdf ? S_OK : OLECMDERR_E_NOTSUPPORTED;
828
829         if(pCmdText)
830             FIXME("Set pCmdText\n");
831     }else {
832         FIXME("Unsupported pguidCmdGroup %s\n", debugstr_guid(pguidCmdGroup));
833         hres = OLECMDERR_E_UNKNOWNGROUP;
834     }
835
836     return hres;
837 }
838
839 static HRESULT exec_from_table(HTMLDocument *This, const cmdtable_t *cmdtable, DWORD cmdid,
840                                DWORD cmdexecopt, VARIANT *in, VARIANT *out)
841 {
842     const cmdtable_t *iter = cmdtable;
843
844     while(iter->id && iter->id != cmdid)
845         iter++;
846
847     if(!iter->id || !iter->exec)
848         return OLECMDERR_E_NOTSUPPORTED;
849
850     return iter->exec(This, cmdexecopt, in, out);
851 }
852
853 static HRESULT WINAPI OleCommandTarget_Exec(IOleCommandTarget *iface, const GUID *pguidCmdGroup,
854         DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
855 {
856     HTMLDocument *This = CMDTARGET_THIS(iface);
857
858     if(!pguidCmdGroup) {
859         if(nCmdID<OLECMDID_OPEN || nCmdID>OLECMDID_GETPRINTTEMPLATE || !exec_table[nCmdID].func) {
860             WARN("Unsupported cmdID = %d\n", nCmdID);
861             return OLECMDERR_E_NOTSUPPORTED;
862         }
863
864         return exec_table[nCmdID].func(This, nCmdexecopt, pvaIn, pvaOut);
865     }else if(IsEqualGUID(&CGID_Explorer, pguidCmdGroup)) {
866         FIXME("unsupported nCmdID %d of CGID_Explorer group\n", nCmdID);
867         TRACE("%p %p\n", pvaIn, pvaOut);
868         return OLECMDERR_E_NOTSUPPORTED;
869     }else if(IsEqualGUID(&CGID_ShellDocView, pguidCmdGroup)) {
870         FIXME("unsupported nCmdID %d of CGID_ShellDocView group\n", nCmdID);
871         return OLECMDERR_E_NOTSUPPORTED;
872     }else if(IsEqualGUID(&CGID_MSHTML, pguidCmdGroup)) {
873         HRESULT hres = exec_from_table(This, base_cmds, nCmdID, nCmdexecopt, pvaIn, pvaOut);
874         if(hres == OLECMDERR_E_NOTSUPPORTED)
875             hres = exec_from_table(This, editmode_cmds, nCmdID,
876                                    nCmdexecopt, pvaIn, pvaOut);
877         if(hres == OLECMDERR_E_NOTSUPPORTED)
878             FIXME("unsupported nCmdID %d of CGID_MSHTML group\n", nCmdID);
879
880         return hres;
881     }
882
883     FIXME("Unsupported pguidCmdGroup %s\n", debugstr_guid(pguidCmdGroup));
884     return OLECMDERR_E_UNKNOWNGROUP;
885 }
886
887 #undef CMDTARGET_THIS
888
889 static const IOleCommandTargetVtbl OleCommandTargetVtbl = {
890     OleCommandTarget_QueryInterface,
891     OleCommandTarget_AddRef,
892     OleCommandTarget_Release,
893     OleCommandTarget_QueryStatus,
894     OleCommandTarget_Exec
895 };
896
897 void show_context_menu(HTMLDocument *This, DWORD dwID, POINT *ppt, IDispatch *elem)
898 {
899     HMENU menu_res, menu;
900     DWORD cmdid;
901     HRESULT hres;
902
903     hres = IDocHostUIHandler_ShowContextMenu(This->hostui, dwID, ppt,
904             (IUnknown*)CMDTARGET(This), elem);
905     if(hres == S_OK)
906         return;
907
908     menu_res = LoadMenuW(get_shdoclc(), MAKEINTRESOURCEW(IDR_BROWSE_CONTEXT_MENU));
909     menu = GetSubMenu(menu_res, dwID);
910
911     cmdid = TrackPopupMenu(menu, TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD,
912             ppt->x, ppt->y, 0, This->hwnd, NULL);
913     DestroyMenu(menu_res);
914
915     if(cmdid)
916         IOleCommandTarget_Exec(CMDTARGET(This), &CGID_MSHTML, cmdid, 0, NULL, NULL);
917 }
918
919 void HTMLDocument_OleCmd_Init(HTMLDocument *This)
920 {
921     This->lpOleCommandTargetVtbl = &OleCommandTargetVtbl;
922 }