mshtml: Add check for doc_obj being NULL (Coverity).
[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(HTMLDocument *This, const char *cmd, nsICommandParams *nsparam)
43 {
44     nsICommandManager *cmdmgr;
45     nsresult nsres;
46
47     TRACE("(%p)\n", This);
48
49     if(!This->doc_obj || !This->doc_obj->nscontainer)
50         return;
51
52     nsres = get_nsinterface((nsISupports*)This->doc_obj->nscontainer->webbrowser, &IID_nsICommandManager, (void**)&cmdmgr);
53     if(NS_FAILED(nsres)) {
54         ERR("Could not get nsICommandManager: %08x\n", nsres);
55         return;
56     }
57
58     nsres = nsICommandManager_DoCommand(cmdmgr, cmd, nsparam, This->window->nswindow);
59     if(NS_FAILED(nsres))
60         ERR("DoCommand(%s) failed: %08x\n", debugstr_a(cmd), nsres);
61
62     nsICommandManager_Release(cmdmgr);
63 }
64
65 /**********************************************************
66  * IOleCommandTarget implementation
67  */
68
69 #define CMDTARGET_THIS(iface) DEFINE_THIS(HTMLDocument, OleCommandTarget, iface)
70
71 static HRESULT exec_open(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
72 {
73     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
74     return E_NOTIMPL;
75 }
76
77 static HRESULT exec_new(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
78 {
79     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
80     return E_NOTIMPL;
81 }
82
83 static HRESULT exec_save(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
84 {
85     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
86     return E_NOTIMPL;
87 }
88
89 static HRESULT exec_save_as(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
90 {
91     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
92     return E_NOTIMPL;
93 }
94
95 static HRESULT exec_save_copy_as(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
96 {
97     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
98     return E_NOTIMPL;
99 }
100
101 static nsresult set_head_text(nsIPrintSettings *settings, LPCWSTR template, BOOL head, int pos)
102 {
103     if(head) {
104         switch(pos) {
105         case 0:
106             return nsIPrintSettings_SetHeaderStrLeft(settings, template);
107         case 1:
108             return nsIPrintSettings_SetHeaderStrRight(settings, template);
109         case 2:
110             return nsIPrintSettings_SetHeaderStrCenter(settings, template);
111         }
112     }else {
113         switch(pos) {
114         case 0:
115             return nsIPrintSettings_SetFooterStrLeft(settings, template);
116         case 1:
117             return nsIPrintSettings_SetFooterStrRight(settings, template);
118         case 2:
119             return nsIPrintSettings_SetFooterStrCenter(settings, template);
120         }
121     }
122
123     return NS_OK;
124 }
125
126 static void set_print_template(nsIPrintSettings *settings, LPCWSTR template, BOOL head)
127 {
128     PRUnichar nstemplate[200]; /* FIXME: Use dynamic allocation */
129     PRUnichar *p = nstemplate;
130     LPCWSTR ptr=template;
131     int pos=0;
132
133     while(*ptr) {
134         if(*ptr != '&') {
135             *p++ = *ptr++;
136             continue;
137         }
138
139         switch(*++ptr) {
140         case '&':
141             *p++ = '&';
142             *p++ = '&';
143             ptr++;
144             break;
145         case 'b': /* change align */
146             ptr++;
147             *p = 0;
148             set_head_text(settings, nstemplate, head, pos);
149             p = nstemplate;
150             pos++;
151             break;
152         case 'd': { /* short date */
153             SYSTEMTIME systime;
154             GetLocalTime(&systime);
155             GetDateFormatW(LOCALE_SYSTEM_DEFAULT, 0, &systime, NULL, p,
156                     sizeof(nstemplate)-(p-nstemplate)*sizeof(WCHAR));
157             p += strlenW(p);
158             ptr++;
159             break;
160         }
161         case 'p': /* page number */
162             *p++ = '&';
163             *p++ = 'P';
164             ptr++;
165             break;
166         case 'P': /* page count */
167             *p++ = '?'; /* FIXME */
168             ptr++;
169             break;
170         case 'u':
171             *p++ = '&';
172             *p++ = 'U';
173             ptr++;
174             break;
175         case 'w':
176             /* FIXME: set window title */
177             ptr++;
178             break;
179         default:
180             *p++ = '&';
181             *p++ = *ptr++;
182         }
183     }
184
185     *p = 0;
186     set_head_text(settings, nstemplate, head, pos);
187
188     while(++pos < 3)
189         set_head_text(settings, p, head, pos);
190 }
191
192 static void set_default_templates(nsIPrintSettings *settings)
193 {
194     WCHAR buf[64];
195
196     static const PRUnichar empty[] = {0};
197
198     nsIPrintSettings_SetHeaderStrLeft(settings, empty);
199     nsIPrintSettings_SetHeaderStrRight(settings, empty);
200     nsIPrintSettings_SetHeaderStrCenter(settings, empty);
201     nsIPrintSettings_SetFooterStrLeft(settings, empty);
202     nsIPrintSettings_SetFooterStrRight(settings, empty);
203     nsIPrintSettings_SetFooterStrCenter(settings, empty);
204
205     if(LoadStringW(get_shdoclc(), IDS_PRINT_HEADER_TEMPLATE, buf,
206                    sizeof(buf)/sizeof(WCHAR)))
207         set_print_template(settings, buf, TRUE);
208
209
210     if(LoadStringW(get_shdoclc(), IDS_PRINT_FOOTER_TEMPLATE, buf,
211                    sizeof(buf)/sizeof(WCHAR)))
212         set_print_template(settings, buf, FALSE);
213
214 }
215
216 static HRESULT exec_print(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
217 {
218     nsIWebBrowserPrint *nsprint;
219     nsIPrintSettings *settings;
220     nsresult nsres;
221
222     TRACE("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
223
224     if(pvaOut)
225         FIXME("unsupported pvaOut\n");
226
227     if(!This->doc_obj->nscontainer)
228         return S_OK;
229
230     nsres = get_nsinterface((nsISupports*)This->doc_obj->nscontainer->webbrowser, &IID_nsIWebBrowserPrint,
231             (void**)&nsprint);
232     if(NS_FAILED(nsres)) {
233         ERR("Could not get nsIWebBrowserPrint: %08x\n", nsres);
234         return S_OK;
235     }
236
237     nsres = nsIWebBrowserPrint_GetGlobalPrintSettings(nsprint, &settings);
238     if(NS_FAILED(nsres))
239         ERR("GetCurrentPrintSettings failed: %08x\n", nsres);
240
241     set_default_templates(settings);
242
243     if(pvaIn) {
244         switch(V_VT(pvaIn)) {
245         case VT_BYREF|VT_ARRAY: {
246             VARIANT *opts;
247             DWORD opts_cnt;
248
249             if(V_ARRAY(pvaIn)->cDims != 1)
250                 WARN("cDims = %d\n", V_ARRAY(pvaIn)->cDims);
251
252             SafeArrayAccessData(V_ARRAY(pvaIn), (void**)&opts);
253             opts_cnt = V_ARRAY(pvaIn)->rgsabound[0].cElements;
254
255             if(opts_cnt >= 1) {
256                 switch(V_VT(opts)) {
257                 case VT_BSTR:
258                     TRACE("setting footer %s\n", debugstr_w(V_BSTR(opts)));
259                     set_print_template(settings, V_BSTR(opts), TRUE);
260                     break;
261                 case VT_NULL:
262                     break;
263                 default:
264                     WARN("V_VT(opts) = %d\n", V_VT(opts));
265                 }
266             }
267
268             if(opts_cnt >= 2) {
269                 switch(V_VT(opts+1)) {
270                 case VT_BSTR:
271                     TRACE("setting footer %s\n", debugstr_w(V_BSTR(opts+1)));
272                     set_print_template(settings, V_BSTR(opts+1), FALSE);
273                     break;
274                 case VT_NULL:
275                     break;
276                 default:
277                     WARN("V_VT(opts) = %d\n", V_VT(opts+1));
278                 }
279             }
280
281             if(opts_cnt >= 3)
282                 FIXME("Unsupported opts_cnt %d\n", opts_cnt);
283
284             SafeArrayUnaccessData(V_ARRAY(pvaIn));
285             break;
286         }
287         default:
288             FIXME("unsupported vt %x\n", V_VT(pvaIn));
289         }
290     }
291
292     nsres = nsIWebBrowserPrint_Print(nsprint, settings, NULL);
293     if(NS_FAILED(nsres))
294         ERR("Print failed: %08x\n", nsres);
295
296     nsIWebBrowserPrint_Release(nsprint);
297
298     return S_OK;
299 }
300
301 static HRESULT exec_print_preview(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
302 {
303     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
304     return E_NOTIMPL;
305 }
306
307 static HRESULT exec_page_setup(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
308 {
309     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
310     return E_NOTIMPL;
311 }
312
313 static HRESULT exec_spell(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
314 {
315     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
316     return E_NOTIMPL;
317 }
318
319 static HRESULT exec_properties(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
320 {
321     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
322     return E_NOTIMPL;
323 }
324
325 static HRESULT exec_cut(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
326 {
327     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
328     return E_NOTIMPL;
329 }
330
331 static HRESULT exec_copy(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
332 {
333     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
334     return E_NOTIMPL;
335 }
336
337 static HRESULT exec_paste(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
338 {
339     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
340     return E_NOTIMPL;
341 }
342
343 static HRESULT exec_paste_special(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
344 {
345     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
346     return E_NOTIMPL;
347 }
348
349 static HRESULT exec_undo(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
350 {
351     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
352     return E_NOTIMPL;
353 }
354
355 static HRESULT exec_rendo(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
356 {
357     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
358     return E_NOTIMPL;
359 }
360
361 static HRESULT exec_select_all(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
362 {
363     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
364     return E_NOTIMPL;
365 }
366
367 static HRESULT exec_clear_selection(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
368 {
369     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
370     return E_NOTIMPL;
371 }
372
373 static HRESULT exec_zoom(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
374 {
375     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
376     return E_NOTIMPL;
377 }
378
379 static HRESULT exec_get_zoom_range(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
380 {
381     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
382     return E_NOTIMPL;
383 }
384
385 static HRESULT exec_refresh(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
386 {
387     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
388     return E_NOTIMPL;
389 }
390
391 static HRESULT exec_stop(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
392 {
393     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
394     return E_NOTIMPL;
395 }
396
397 static HRESULT exec_stop_download(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
398 {
399     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
400     return E_NOTIMPL;
401 }
402
403 static HRESULT exec_find(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
404 {
405     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
406     return E_NOTIMPL;
407 }
408
409 static HRESULT exec_delete(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
410 {
411     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
412     return E_NOTIMPL;
413 }
414
415 static HRESULT exec_enable_interaction(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
416 {
417     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
418     return E_NOTIMPL;
419 }
420
421 static HRESULT exec_on_unload(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
422 {
423     TRACE("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
424
425     /* Tests show that we have nothing more to do here */
426
427     if(pvaOut) {
428         V_VT(pvaOut) = VT_BOOL;
429         V_BOOL(pvaOut) = VARIANT_TRUE;
430     }
431
432     return S_OK;
433 }
434
435 static HRESULT exec_show_page_setup(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
436 {
437     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
438     return E_NOTIMPL;
439 }
440
441 static HRESULT exec_show_print(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
442 {
443     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
444     return E_NOTIMPL;
445 }
446
447 static HRESULT exec_close(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
448 {
449     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
450     return E_NOTIMPL;
451 }
452
453 static HRESULT exec_set_print_template(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
454 {
455     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
456     return E_NOTIMPL;
457 }
458
459 static HRESULT exec_get_print_template(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
460 {
461     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
462     return E_NOTIMPL;
463 }
464
465 static HRESULT query_mshtml_copy(HTMLDocument *This, OLECMD *cmd)
466 {
467     FIXME("(%p)\n", This);
468     cmd->cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
469     return S_OK;
470 }
471
472 static HRESULT exec_mshtml_copy(HTMLDocument *This, DWORD cmdexecopt, VARIANT *in, VARIANT *out)
473 {
474     TRACE("(%p)->(%08x %p %p)\n", This, cmdexecopt, in, out);
475
476     if(This->doc_obj->usermode == EDITMODE)
477         return editor_exec_copy(This, cmdexecopt, in, out);
478
479     do_ns_command(This, NSCMD_COPY, NULL);
480     return S_OK;
481 }
482
483 static HRESULT query_mshtml_cut(HTMLDocument *This, OLECMD *cmd)
484 {
485     FIXME("(%p)\n", This);
486     cmd->cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
487     return S_OK;
488 }
489
490 static HRESULT exec_mshtml_cut(HTMLDocument *This, DWORD cmdexecopt, VARIANT *in, VARIANT *out)
491 {
492     TRACE("(%p)->(%08x %p %p)\n", This, cmdexecopt, in, out);
493
494     if(This->doc_obj->usermode == EDITMODE)
495         return editor_exec_cut(This, cmdexecopt, in, out);
496
497     FIXME("Unimplemented in browse mode\n");
498     return E_NOTIMPL;
499 }
500
501 static HRESULT query_mshtml_paste(HTMLDocument *This, OLECMD *cmd)
502 {
503     FIXME("(%p)\n", This);
504     cmd->cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
505     return S_OK;
506 }
507
508 static HRESULT exec_mshtml_paste(HTMLDocument *This, DWORD cmdexecopt, VARIANT *in, VARIANT *out)
509 {
510     TRACE("(%p)->(%08x %p %p)\n", This, cmdexecopt, in, out);
511
512     if(This->doc_obj->usermode == EDITMODE)
513         return editor_exec_paste(This, cmdexecopt, in, out);
514
515     FIXME("Unimplemented in browse mode\n");
516     return E_NOTIMPL;
517 }
518
519 static HRESULT exec_browsemode(HTMLDocument *This, DWORD cmdexecopt, VARIANT *in, VARIANT *out)
520 {
521     WARN("(%p)->(%08x %p %p)\n", This, cmdexecopt, in, out);
522
523     if(in || out)
524         FIXME("unsupported args\n");
525
526     This->doc_obj->usermode = BROWSEMODE;
527
528     return S_OK;
529 }
530
531 static HRESULT exec_editmode(HTMLDocument *This, DWORD cmdexecopt, VARIANT *in, VARIANT *out)
532 {
533     IMoniker *mon;
534     HRESULT hres;
535
536     TRACE("(%p)->(%08x %p %p)\n", This, cmdexecopt, in, out);
537
538     if(in || out)
539         FIXME("unsupported args\n");
540
541     if(This->doc_obj->usermode == EDITMODE)
542         return S_OK;
543
544     This->doc_obj->usermode = EDITMODE;
545
546     if(This->window->mon) {
547         CLSID clsid = IID_NULL;
548         hres = IMoniker_GetClassID(This->window->mon, &clsid);
549         if(SUCCEEDED(hres)) {
550             /* We should use IMoniker::Save here */
551             FIXME("Use CLSID %s\n", debugstr_guid(&clsid));
552         }
553     }
554
555     if(This->doc_obj->frame)
556         IOleInPlaceFrame_SetStatusText(This->doc_obj->frame, NULL);
557
558     This->window->readystate = READYSTATE_UNINITIALIZED;
559
560     if(This->doc_obj->client) {
561         IOleCommandTarget *cmdtrg;
562
563         hres = IOleClientSite_QueryInterface(This->doc_obj->client, &IID_IOleCommandTarget,
564                 (void**)&cmdtrg);
565         if(SUCCEEDED(hres)) {
566             VARIANT var;
567
568             V_VT(&var) = VT_I4;
569             V_I4(&var) = 0;
570             IOleCommandTarget_Exec(cmdtrg, &CGID_ShellDocView, 37, 0, &var, NULL);
571
572             IOleCommandTarget_Release(cmdtrg);
573         }
574     }
575
576     if(This->doc_obj->hostui) {
577         DOCHOSTUIINFO hostinfo;
578
579         memset(&hostinfo, 0, sizeof(DOCHOSTUIINFO));
580         hostinfo.cbSize = sizeof(DOCHOSTUIINFO);
581         hres = IDocHostUIHandler_GetHostInfo(This->doc_obj->hostui, &hostinfo);
582         if(SUCCEEDED(hres))
583             /* FIXME: use hostinfo */
584             TRACE("hostinfo = {%u %08x %08x %s %s}\n",
585                     hostinfo.cbSize, hostinfo.dwFlags, hostinfo.dwDoubleClick,
586                     debugstr_w(hostinfo.pchHostCss), debugstr_w(hostinfo.pchHostNS));
587     }
588
589     update_doc(This, UPDATE_UI);
590
591     if(This->window->mon) {
592         /* FIXME: We should find nicer way to do this */
593         remove_target_tasks(This->task_magic);
594
595         mon = This->window->mon;
596         IMoniker_AddRef(mon);
597     }else {
598         static const WCHAR about_blankW[] = {'a','b','o','u','t',':','b','l','a','n','k',0};
599
600         hres = CreateURLMoniker(NULL, about_blankW, &mon);
601         if(FAILED(hres)) {
602             FIXME("CreateURLMoniker failed: %08x\n", hres);
603             return hres;
604         }
605     }
606
607     hres = IPersistMoniker_Load(PERSISTMON(This), TRUE, mon, NULL, 0);
608     IMoniker_Release(mon);
609     if(FAILED(hres))
610         return hres;
611
612     if(This->doc_obj->ui_active) {
613         if(This->doc_obj->ip_window)
614             call_set_active_object(This->doc_obj->ip_window, NULL);
615         if(This->doc_obj->hostui)
616             IDocHostUIHandler_HideUI(This->doc_obj->hostui);
617     }
618
619     if(This->doc_obj->ui_active) {
620         RECT rcBorderWidths;
621
622         if(This->doc_obj->hostui)
623             IDocHostUIHandler_ShowUI(This->doc_obj->hostui, DOCHOSTUITYPE_AUTHOR, ACTOBJ(This), CMDTARGET(This),
624                 This->doc_obj->frame, This->doc_obj->ip_window);
625
626         if(This->doc_obj->ip_window)
627             call_set_active_object(This->doc_obj->ip_window, ACTOBJ(This));
628
629         memset(&rcBorderWidths, 0, sizeof(rcBorderWidths));
630         if(This->doc_obj->frame)
631             IOleInPlaceFrame_SetBorderSpace(This->doc_obj->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->doc_obj->client) {
793                         hr = IOleClientSite_QueryInterface(This->doc_obj->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(HTMLDocumentObj *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->basedoc), 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->basedoc), &CGID_MSHTML, cmdid, 0, NULL, NULL);
917 }
918
919 void HTMLDocument_OleCmd_Init(HTMLDocument *This)
920 {
921     This->lpOleCommandTargetVtbl = &OleCommandTargetVtbl;
922 }