gdi32: Avoid signed-unsigned integer comparisons.
[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
34 #include "mshtml_private.h"
35 #include "binding.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 static inline HTMLDocument *impl_from_IOleCommandTarget(IOleCommandTarget *iface)
70 {
71     return CONTAINING_RECORD(iface, HTMLDocument, IOleCommandTarget_iface);
72 }
73
74 static HRESULT exec_open(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_new(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(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_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 HRESULT exec_save_copy_as(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
99 {
100     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
101     return E_NOTIMPL;
102 }
103
104 static nsresult set_head_text(nsIPrintSettings *settings, LPCWSTR template, BOOL head, int pos)
105 {
106     if(head) {
107         switch(pos) {
108         case 0:
109             return nsIPrintSettings_SetHeaderStrLeft(settings, template);
110         case 1:
111             return nsIPrintSettings_SetHeaderStrRight(settings, template);
112         case 2:
113             return nsIPrintSettings_SetHeaderStrCenter(settings, template);
114         }
115     }else {
116         switch(pos) {
117         case 0:
118             return nsIPrintSettings_SetFooterStrLeft(settings, template);
119         case 1:
120             return nsIPrintSettings_SetFooterStrRight(settings, template);
121         case 2:
122             return nsIPrintSettings_SetFooterStrCenter(settings, template);
123         }
124     }
125
126     return NS_OK;
127 }
128
129 static void set_print_template(nsIPrintSettings *settings, LPCWSTR template, BOOL head)
130 {
131     PRUnichar nstemplate[200]; /* FIXME: Use dynamic allocation */
132     PRUnichar *p = nstemplate;
133     LPCWSTR ptr=template;
134     int pos=0;
135
136     while(*ptr) {
137         if(*ptr != '&') {
138             *p++ = *ptr++;
139             continue;
140         }
141
142         switch(*++ptr) {
143         case '&':
144             *p++ = '&';
145             *p++ = '&';
146             ptr++;
147             break;
148         case 'b': /* change align */
149             ptr++;
150             *p = 0;
151             set_head_text(settings, nstemplate, head, pos);
152             p = nstemplate;
153             pos++;
154             break;
155         case 'd': { /* short date */
156             SYSTEMTIME systime;
157             GetLocalTime(&systime);
158             GetDateFormatW(LOCALE_SYSTEM_DEFAULT, 0, &systime, NULL, p,
159                     sizeof(nstemplate)-(p-nstemplate)*sizeof(WCHAR));
160             p += strlenW(p);
161             ptr++;
162             break;
163         }
164         case 'p': /* page number */
165             *p++ = '&';
166             *p++ = 'P';
167             ptr++;
168             break;
169         case 'P': /* page count */
170             *p++ = '?'; /* FIXME */
171             ptr++;
172             break;
173         case 'u':
174             *p++ = '&';
175             *p++ = 'U';
176             ptr++;
177             break;
178         case 'w':
179             /* FIXME: set window title */
180             ptr++;
181             break;
182         default:
183             *p++ = '&';
184             *p++ = *ptr++;
185         }
186     }
187
188     *p = 0;
189     set_head_text(settings, nstemplate, head, pos);
190
191     while(++pos < 3)
192         set_head_text(settings, p, head, pos);
193 }
194
195 static void set_default_templates(nsIPrintSettings *settings)
196 {
197     WCHAR buf[64];
198
199     static const PRUnichar empty[] = {0};
200
201     nsIPrintSettings_SetHeaderStrLeft(settings, empty);
202     nsIPrintSettings_SetHeaderStrRight(settings, empty);
203     nsIPrintSettings_SetHeaderStrCenter(settings, empty);
204     nsIPrintSettings_SetFooterStrLeft(settings, empty);
205     nsIPrintSettings_SetFooterStrRight(settings, empty);
206     nsIPrintSettings_SetFooterStrCenter(settings, empty);
207
208     if(LoadStringW(get_shdoclc(), IDS_PRINT_HEADER_TEMPLATE, buf,
209                    sizeof(buf)/sizeof(WCHAR)))
210         set_print_template(settings, buf, TRUE);
211
212
213     if(LoadStringW(get_shdoclc(), IDS_PRINT_FOOTER_TEMPLATE, buf,
214                    sizeof(buf)/sizeof(WCHAR)))
215         set_print_template(settings, buf, FALSE);
216
217 }
218
219 static HRESULT exec_print(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
220 {
221     nsIWebBrowserPrint *nsprint;
222     nsIPrintSettings *settings;
223     nsresult nsres;
224
225     TRACE("(%p)->(%d %s %p)\n", This, nCmdexecopt, debugstr_variant(pvaIn), pvaOut);
226
227     if(pvaOut)
228         FIXME("unsupported pvaOut\n");
229
230     if(!This->doc_obj->nscontainer)
231         return S_OK;
232
233     nsres = get_nsinterface((nsISupports*)This->doc_obj->nscontainer->webbrowser, &IID_nsIWebBrowserPrint,
234             (void**)&nsprint);
235     if(NS_FAILED(nsres)) {
236         ERR("Could not get nsIWebBrowserPrint: %08x\n", nsres);
237         return S_OK;
238     }
239
240     nsres = nsIWebBrowserPrint_GetGlobalPrintSettings(nsprint, &settings);
241     if(NS_FAILED(nsres))
242         ERR("GetCurrentPrintSettings failed: %08x\n", nsres);
243
244     set_default_templates(settings);
245
246     if(pvaIn) {
247         switch(V_VT(pvaIn)) {
248         case VT_BYREF|VT_ARRAY: {
249             VARIANT *opts;
250             DWORD opts_cnt;
251
252             if(V_ARRAY(pvaIn)->cDims != 1)
253                 WARN("cDims = %d\n", V_ARRAY(pvaIn)->cDims);
254
255             SafeArrayAccessData(V_ARRAY(pvaIn), (void**)&opts);
256             opts_cnt = V_ARRAY(pvaIn)->rgsabound[0].cElements;
257
258             if(opts_cnt >= 1) {
259                 switch(V_VT(opts)) {
260                 case VT_BSTR:
261                     TRACE("setting footer %s\n", debugstr_w(V_BSTR(opts)));
262                     set_print_template(settings, V_BSTR(opts), TRUE);
263                     break;
264                 case VT_NULL:
265                     break;
266                 default:
267                     WARN("opts = %s\n", debugstr_variant(opts));
268                 }
269             }
270
271             if(opts_cnt >= 2) {
272                 switch(V_VT(opts+1)) {
273                 case VT_BSTR:
274                     TRACE("setting footer %s\n", debugstr_w(V_BSTR(opts+1)));
275                     set_print_template(settings, V_BSTR(opts+1), FALSE);
276                     break;
277                 case VT_NULL:
278                     break;
279                 default:
280                     WARN("opts[1] = %s\n", debugstr_variant(opts+1));
281                 }
282             }
283
284             if(opts_cnt >= 3)
285                 FIXME("Unsupported opts_cnt %d\n", opts_cnt);
286
287             SafeArrayUnaccessData(V_ARRAY(pvaIn));
288             break;
289         }
290         default:
291             FIXME("unsupported arg %s\n", debugstr_variant(pvaIn));
292         }
293     }
294
295     nsres = nsIWebBrowserPrint_Print(nsprint, settings, NULL);
296     if(NS_FAILED(nsres))
297         ERR("Print failed: %08x\n", nsres);
298
299     nsIWebBrowserPrint_Release(nsprint);
300
301     return S_OK;
302 }
303
304 static HRESULT exec_print_preview(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_page_setup(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_spell(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_properties(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_cut(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_copy(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(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_paste_special(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_undo(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_rendo(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_select_all(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_clear_selection(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_zoom(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_get_zoom_range(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 typedef struct {
389     task_t header;
390     HTMLOuterWindow *window;
391 }refresh_task_t;
392
393 static void refresh_proc(task_t *_task)
394 {
395     refresh_task_t *task = (refresh_task_t*)_task;
396     HTMLOuterWindow *window = task->window;
397
398     TRACE("%p\n", window);
399
400     window->readystate = READYSTATE_UNINITIALIZED;
401
402     if(window->doc_obj && window->doc_obj->client_cmdtrg) {
403         VARIANT var;
404
405         V_VT(&var) = VT_I4;
406         V_I4(&var) = 0;
407         IOleCommandTarget_Exec(window->doc_obj->client_cmdtrg, &CGID_ShellDocView, 37, 0, &var, NULL);
408     }
409
410     load_uri(task->window, task->window->uri, BINDING_REFRESH);
411 }
412
413 static void refresh_destr(task_t *_task)
414 {
415     refresh_task_t *task = (refresh_task_t*)_task;
416
417     IHTMLWindow2_Release(&task->window->base.IHTMLWindow2_iface);
418     heap_free(task);
419 }
420
421 static HRESULT exec_refresh(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
422 {
423     refresh_task_t *task;
424     HRESULT hres;
425
426     TRACE("(%p)->(%d %s %p)\n", This, nCmdexecopt, debugstr_variant(pvaIn), pvaOut);
427
428     if(This->doc_obj->client) {
429         IOleCommandTarget *olecmd;
430
431         hres = IOleClientSite_QueryInterface(This->doc_obj->client, &IID_IOleCommandTarget, (void**)&olecmd);
432         if(SUCCEEDED(hres)) {
433             hres = IOleCommandTarget_Exec(olecmd, &CGID_DocHostCommandHandler, 2300, nCmdexecopt, pvaIn, pvaOut);
434             IOleCommandTarget_Release(olecmd);
435             if(SUCCEEDED(hres))
436                 return S_OK;
437         }
438     }
439
440     if(!This->window)
441         return E_UNEXPECTED;
442
443     task = heap_alloc(sizeof(*task));
444     if(!task)
445         return E_OUTOFMEMORY;
446
447     IHTMLWindow2_AddRef(&This->window->base.IHTMLWindow2_iface);
448     task->window = This->window;
449
450     return push_task(&task->header, refresh_proc, refresh_destr, This->window->task_magic);
451 }
452
453 static HRESULT exec_stop(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_stop_download(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 exec_find(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
466 {
467     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
468     return E_NOTIMPL;
469 }
470
471 static HRESULT exec_delete(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
472 {
473     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
474     return E_NOTIMPL;
475 }
476
477 static HRESULT exec_enable_interaction(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
478 {
479     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
480     return E_NOTIMPL;
481 }
482
483 static HRESULT exec_on_unload(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
484 {
485     TRACE("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
486
487     /* Tests show that we have nothing more to do here */
488
489     if(pvaOut) {
490         V_VT(pvaOut) = VT_BOOL;
491         V_BOOL(pvaOut) = VARIANT_TRUE;
492     }
493
494     return S_OK;
495 }
496
497 static HRESULT exec_show_page_setup(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
498 {
499     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
500     return E_NOTIMPL;
501 }
502
503 static HRESULT exec_show_print(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
504 {
505     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
506     return E_NOTIMPL;
507 }
508
509 static HRESULT exec_close(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
510 {
511     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
512     return E_NOTIMPL;
513 }
514
515 static HRESULT exec_set_print_template(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
516 {
517     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
518     return E_NOTIMPL;
519 }
520
521 static HRESULT exec_get_print_template(HTMLDocument *This, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
522 {
523     FIXME("(%p)->(%d %p %p)\n", This, nCmdexecopt, pvaIn, pvaOut);
524     return E_NOTIMPL;
525 }
526
527 static HRESULT query_mshtml_copy(HTMLDocument *This, OLECMD *cmd)
528 {
529     FIXME("(%p)\n", This);
530     cmd->cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
531     return S_OK;
532 }
533
534 static HRESULT exec_mshtml_copy(HTMLDocument *This, DWORD cmdexecopt, VARIANT *in, VARIANT *out)
535 {
536     TRACE("(%p)->(%08x %p %p)\n", This, cmdexecopt, in, out);
537
538     if(This->doc_obj->usermode == EDITMODE)
539         return editor_exec_copy(This, cmdexecopt, in, out);
540
541     do_ns_command(This, NSCMD_COPY, NULL);
542     return S_OK;
543 }
544
545 static HRESULT query_mshtml_cut(HTMLDocument *This, OLECMD *cmd)
546 {
547     FIXME("(%p)\n", This);
548     cmd->cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
549     return S_OK;
550 }
551
552 static HRESULT exec_mshtml_cut(HTMLDocument *This, DWORD cmdexecopt, VARIANT *in, VARIANT *out)
553 {
554     TRACE("(%p)->(%08x %p %p)\n", This, cmdexecopt, in, out);
555
556     if(This->doc_obj->usermode == EDITMODE)
557         return editor_exec_cut(This, cmdexecopt, in, out);
558
559     FIXME("Unimplemented in browse mode\n");
560     return E_NOTIMPL;
561 }
562
563 static HRESULT query_mshtml_paste(HTMLDocument *This, OLECMD *cmd)
564 {
565     FIXME("(%p)\n", This);
566     cmd->cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
567     return S_OK;
568 }
569
570 static HRESULT exec_mshtml_paste(HTMLDocument *This, DWORD cmdexecopt, VARIANT *in, VARIANT *out)
571 {
572     TRACE("(%p)->(%08x %p %p)\n", This, cmdexecopt, in, out);
573
574     if(This->doc_obj->usermode == EDITMODE)
575         return editor_exec_paste(This, cmdexecopt, in, out);
576
577     FIXME("Unimplemented in browse mode\n");
578     return E_NOTIMPL;
579 }
580
581 static HRESULT exec_browsemode(HTMLDocument *This, DWORD cmdexecopt, VARIANT *in, VARIANT *out)
582 {
583     WARN("(%p)->(%08x %p %p)\n", This, cmdexecopt, in, out);
584
585     if(in || out)
586         FIXME("unsupported args\n");
587
588     This->doc_obj->usermode = BROWSEMODE;
589
590     return S_OK;
591 }
592
593 static HRESULT exec_editmode(HTMLDocument *This, DWORD cmdexecopt, VARIANT *in, VARIANT *out)
594 {
595     IMoniker *mon;
596     HRESULT hres;
597
598     TRACE("(%p)->(%08x %p %p)\n", This, cmdexecopt, in, out);
599
600     if(in || out)
601         FIXME("unsupported args\n");
602
603     if(This->doc_obj->usermode == EDITMODE)
604         return S_OK;
605
606     This->doc_obj->usermode = EDITMODE;
607
608     if(This->window->mon) {
609         CLSID clsid = IID_NULL;
610         hres = IMoniker_GetClassID(This->window->mon, &clsid);
611         if(SUCCEEDED(hres)) {
612             /* We should use IMoniker::Save here */
613             FIXME("Use CLSID %s\n", debugstr_guid(&clsid));
614         }
615     }
616
617     if(This->doc_obj->frame)
618         IOleInPlaceFrame_SetStatusText(This->doc_obj->frame, NULL);
619
620     This->window->readystate = READYSTATE_UNINITIALIZED;
621
622     if(This->doc_obj->client) {
623         IOleCommandTarget *cmdtrg;
624
625         hres = IOleClientSite_QueryInterface(This->doc_obj->client, &IID_IOleCommandTarget,
626                 (void**)&cmdtrg);
627         if(SUCCEEDED(hres)) {
628             VARIANT var;
629
630             V_VT(&var) = VT_I4;
631             V_I4(&var) = 0;
632             IOleCommandTarget_Exec(cmdtrg, &CGID_ShellDocView, 37, 0, &var, NULL);
633
634             IOleCommandTarget_Release(cmdtrg);
635         }
636     }
637
638     if(This->doc_obj->hostui) {
639         DOCHOSTUIINFO hostinfo;
640
641         memset(&hostinfo, 0, sizeof(DOCHOSTUIINFO));
642         hostinfo.cbSize = sizeof(DOCHOSTUIINFO);
643         hres = IDocHostUIHandler_GetHostInfo(This->doc_obj->hostui, &hostinfo);
644         if(SUCCEEDED(hres))
645             /* FIXME: use hostinfo */
646             TRACE("hostinfo = {%u %08x %08x %s %s}\n",
647                     hostinfo.cbSize, hostinfo.dwFlags, hostinfo.dwDoubleClick,
648                     debugstr_w(hostinfo.pchHostCss), debugstr_w(hostinfo.pchHostNS));
649     }
650
651     update_doc(This, UPDATE_UI);
652
653     if(This->window->mon) {
654         /* FIXME: We should find nicer way to do this */
655         remove_target_tasks(This->task_magic);
656
657         mon = This->window->mon;
658         IMoniker_AddRef(mon);
659     }else {
660         static const WCHAR about_blankW[] = {'a','b','o','u','t',':','b','l','a','n','k',0};
661
662         hres = CreateURLMoniker(NULL, about_blankW, &mon);
663         if(FAILED(hres)) {
664             FIXME("CreateURLMoniker failed: %08x\n", hres);
665             return hres;
666         }
667     }
668
669     hres = IPersistMoniker_Load(&This->IPersistMoniker_iface, TRUE, mon, NULL, 0);
670     IMoniker_Release(mon);
671     if(FAILED(hres))
672         return hres;
673
674     if(This->doc_obj->ui_active) {
675         if(This->doc_obj->ip_window)
676             call_set_active_object(This->doc_obj->ip_window, NULL);
677         if(This->doc_obj->hostui)
678             IDocHostUIHandler_HideUI(This->doc_obj->hostui);
679     }
680
681     if(This->doc_obj->ui_active) {
682         RECT rcBorderWidths;
683
684         if(This->doc_obj->hostui)
685             IDocHostUIHandler_ShowUI(This->doc_obj->hostui, DOCHOSTUITYPE_AUTHOR,
686                     &This->IOleInPlaceActiveObject_iface, &This->IOleCommandTarget_iface,
687                     This->doc_obj->frame, This->doc_obj->ip_window);
688
689         if(This->doc_obj->ip_window)
690             call_set_active_object(This->doc_obj->ip_window, &This->IOleInPlaceActiveObject_iface);
691
692         memset(&rcBorderWidths, 0, sizeof(rcBorderWidths));
693         if(This->doc_obj->frame)
694             IOleInPlaceFrame_SetBorderSpace(This->doc_obj->frame, &rcBorderWidths);
695     }
696
697     return S_OK;
698 }
699
700 static HRESULT exec_htmleditmode(HTMLDocument *This, DWORD cmdexecopt, VARIANT *in, VARIANT *out)
701 {
702     FIXME("(%p)->(%08x %p %p)\n", This, cmdexecopt, in, out);
703     return S_OK;
704 }
705
706 static HRESULT exec_baselinefont3(HTMLDocument *This, DWORD cmdexecopt, VARIANT *in, VARIANT *out)
707 {
708     FIXME("(%p)->(%08x %p %p)\n", This, cmdexecopt, in, out);
709     return S_OK;
710 }
711
712 static HRESULT exec_respectvisibility_indesign(HTMLDocument *This, DWORD cmdexecopt,
713         VARIANT *in, VARIANT *out)
714 {
715     FIXME("(%p)->(%08x %p %p)\n", This, cmdexecopt, in, out);
716     return E_NOTIMPL;
717 }
718
719 static HRESULT query_enabled_stub(HTMLDocument *This, OLECMD *cmd)
720 {
721     switch(cmd->cmdID) {
722     case IDM_PRINT:
723         FIXME("CGID_MSHTML: IDM_PRINT\n");
724         cmd->cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
725         break;
726     case IDM_BLOCKDIRLTR:
727         FIXME("CGID_MSHTML: IDM_BLOCKDIRLTR\n");
728         cmd->cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
729         break;
730     case IDM_BLOCKDIRRTL:
731         FIXME("CGID_MSHTML: IDM_BLOCKDIRRTL\n");
732         cmd->cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
733         break;
734     }
735
736     return S_OK;
737 }
738
739 static const struct {
740     OLECMDF cmdf;
741     HRESULT (*func)(HTMLDocument*,DWORD,VARIANT*,VARIANT*);
742 } exec_table[OLECMDID_GETPRINTTEMPLATE+1] = {
743     {0},
744     { OLECMDF_SUPPORTED,                  exec_open                 }, /* OLECMDID_OPEN */
745     { OLECMDF_SUPPORTED,                  exec_new                  }, /* OLECMDID_NEW */
746     { OLECMDF_SUPPORTED,                  exec_save                 }, /* OLECMDID_SAVE */
747     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_save_as              }, /* OLECMDID_SAVEAS */
748     { OLECMDF_SUPPORTED,                  exec_save_copy_as         }, /* OLECMDID_SAVECOPYAS */
749     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_print                }, /* OLECMDID_PRINT */
750     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_print_preview        }, /* OLECMDID_PRINTPREVIEW */
751     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_page_setup           }, /* OLECMDID_PAGESETUP */
752     { OLECMDF_SUPPORTED,                  exec_spell                }, /* OLECMDID_SPELL */
753     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_properties           }, /* OLECMDID_PROPERTIES */
754     { OLECMDF_SUPPORTED,                  exec_cut                  }, /* OLECMDID_CUT */
755     { OLECMDF_SUPPORTED,                  exec_copy                 }, /* OLECMDID_COPY */
756     { OLECMDF_SUPPORTED,                  exec_paste                }, /* OLECMDID_PASTE */
757     { OLECMDF_SUPPORTED,                  exec_paste_special        }, /* OLECMDID_PASTESPECIAL */
758     { OLECMDF_SUPPORTED,                  exec_undo                 }, /* OLECMDID_UNDO */
759     { OLECMDF_SUPPORTED,                  exec_rendo                }, /* OLECMDID_REDO */
760     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_select_all           }, /* OLECMDID_SELECTALL */
761     { OLECMDF_SUPPORTED,                  exec_clear_selection      }, /* OLECMDID_CLEARSELECTION */
762     { OLECMDF_SUPPORTED,                  exec_zoom                 }, /* OLECMDID_ZOOM */
763     { OLECMDF_SUPPORTED,                  exec_get_zoom_range       }, /* OLECMDID_GETZOOMRANGE */
764     {0},
765     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_refresh              }, /* OLECMDID_REFRESH */
766     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_stop                 }, /* OLECMDID_STOP */
767     {0},{0},{0},{0},{0},{0},
768     { OLECMDF_SUPPORTED,                  exec_stop_download        }, /* OLECMDID_STOPDOWNLOAD */
769     {0},
770     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_find                 }, /* OLECMDID_FIND */
771     { OLECMDF_SUPPORTED,                  exec_delete               }, /* OLECMDID_DELETE */
772     {0},{0},
773     { OLECMDF_SUPPORTED,                  exec_enable_interaction   }, /* OLECMDID_ENABLE_INTERACTION */
774     { OLECMDF_SUPPORTED,                  exec_on_unload            }, /* OLECMDID_ONUNLOAD */
775     {0},{0},{0},{0},{0},
776     { OLECMDF_SUPPORTED,                  exec_show_page_setup      }, /* OLECMDID_SHOWPAGESETUP */
777     { OLECMDF_SUPPORTED,                  exec_show_print           }, /* OLECMDID_SHOWPRINT */
778     {0},{0},
779     { OLECMDF_SUPPORTED,                  exec_close                }, /* OLECMDID_CLOSE */
780     {0},{0},{0},
781     { OLECMDF_SUPPORTED,                  exec_set_print_template   }, /* OLECMDID_SETPRINTTEMPLATE */
782     { OLECMDF_SUPPORTED,                  exec_get_print_template   }  /* OLECMDID_GETPRINTTEMPLATE */
783 };
784
785 static const cmdtable_t base_cmds[] = {
786     {IDM_COPY,             query_mshtml_copy,     exec_mshtml_copy},
787     {IDM_PASTE,            query_mshtml_paste,    exec_mshtml_paste},
788     {IDM_CUT,              query_mshtml_cut,      exec_mshtml_cut},
789     {IDM_BROWSEMODE,       NULL,                  exec_browsemode},
790     {IDM_EDITMODE,         NULL,                  exec_editmode},
791     {IDM_PRINT,            query_enabled_stub,    exec_print},
792     {IDM_HTMLEDITMODE,     NULL,                  exec_htmleditmode},
793     {IDM_BASELINEFONT3,    NULL,                  exec_baselinefont3},
794     {IDM_BLOCKDIRLTR,      query_enabled_stub,    NULL},
795     {IDM_BLOCKDIRRTL,      query_enabled_stub,    NULL},
796     {IDM_RESPECTVISIBILITY_INDESIGN, NULL,        exec_respectvisibility_indesign},
797     {0,NULL,NULL}
798 };
799
800 static HRESULT WINAPI OleCommandTarget_QueryInterface(IOleCommandTarget *iface, REFIID riid, void **ppv)
801 {
802     HTMLDocument *This = impl_from_IOleCommandTarget(iface);
803     return htmldoc_query_interface(This, riid, ppv);
804 }
805
806 static ULONG WINAPI OleCommandTarget_AddRef(IOleCommandTarget *iface)
807 {
808     HTMLDocument *This = impl_from_IOleCommandTarget(iface);
809     return htmldoc_addref(This);
810 }
811
812 static ULONG WINAPI OleCommandTarget_Release(IOleCommandTarget *iface)
813 {
814     HTMLDocument *This = impl_from_IOleCommandTarget(iface);
815     return htmldoc_release(This);
816 }
817
818 static HRESULT query_from_table(HTMLDocument *This, const cmdtable_t *cmdtable, OLECMD *cmd)
819 {
820     const cmdtable_t *iter = cmdtable;
821
822     cmd->cmdf = 0;
823
824     while(iter->id && iter->id != cmd->cmdID)
825         iter++;
826
827     if(!iter->id || !iter->query)
828         return OLECMDERR_E_NOTSUPPORTED;
829
830     return iter->query(This, cmd);
831 }
832
833 static HRESULT WINAPI OleCommandTarget_QueryStatus(IOleCommandTarget *iface, const GUID *pguidCmdGroup,
834         ULONG cCmds, OLECMD prgCmds[], OLECMDTEXT *pCmdText)
835 {
836     HTMLDocument *This = impl_from_IOleCommandTarget(iface);
837     HRESULT hres = S_OK, hr;
838
839     TRACE("(%p)->(%s %d %p %p)\n", This, debugstr_guid(pguidCmdGroup), cCmds, prgCmds, pCmdText);
840
841     if(!pguidCmdGroup) {
842         ULONG i;
843
844         for(i=0; i<cCmds; i++) {
845             if(prgCmds[i].cmdID<OLECMDID_OPEN || prgCmds[i].cmdID>OLECMDID_GETPRINTTEMPLATE) {
846                 WARN("Unsupported cmdID = %d\n", prgCmds[i].cmdID);
847                 prgCmds[i].cmdf = 0;
848                 hres = OLECMDERR_E_NOTSUPPORTED;
849             }else {
850                 if(prgCmds[i].cmdID == OLECMDID_OPEN || prgCmds[i].cmdID == OLECMDID_NEW) {
851                     IOleCommandTarget *cmdtrg = NULL;
852                     OLECMD olecmd;
853
854                     prgCmds[i].cmdf = OLECMDF_SUPPORTED;
855                     if(This->doc_obj->client) {
856                         hr = IOleClientSite_QueryInterface(This->doc_obj->client, &IID_IOleCommandTarget,
857                                 (void**)&cmdtrg);
858                         if(SUCCEEDED(hr)) {
859                             olecmd.cmdID = prgCmds[i].cmdID;
860                             olecmd.cmdf = 0;
861
862                             hr = IOleCommandTarget_QueryStatus(cmdtrg, NULL, 1, &olecmd, NULL);
863                             if(SUCCEEDED(hr) && olecmd.cmdf)
864                                 prgCmds[i].cmdf = olecmd.cmdf;
865                         }
866                     }else {
867                         ERR("This->client == NULL, native would crash\n");
868                     }
869                 }else {
870                     prgCmds[i].cmdf = exec_table[prgCmds[i].cmdID].cmdf;
871                     TRACE("cmdID = %d  returning %x\n", prgCmds[i].cmdID, prgCmds[i].cmdf);
872                 }
873                 hres = S_OK;
874             }
875         }
876
877         if(pCmdText)
878             FIXME("Set pCmdText\n");
879     }else if(IsEqualGUID(&CGID_MSHTML, pguidCmdGroup)) {
880         ULONG i;
881
882         for(i=0; i<cCmds; i++) {
883             HRESULT hres = query_from_table(This, base_cmds, prgCmds+i);
884             if(hres == OLECMDERR_E_NOTSUPPORTED)
885                 hres = query_from_table(This, editmode_cmds, prgCmds+i);
886             if(hres == OLECMDERR_E_NOTSUPPORTED)
887                 FIXME("CGID_MSHTML: unsupported cmdID %d\n", prgCmds[i].cmdID);
888         }
889
890         hres = prgCmds[i-1].cmdf ? S_OK : OLECMDERR_E_NOTSUPPORTED;
891
892         if(pCmdText)
893             FIXME("Set pCmdText\n");
894     }else {
895         FIXME("Unsupported pguidCmdGroup %s\n", debugstr_guid(pguidCmdGroup));
896         hres = OLECMDERR_E_UNKNOWNGROUP;
897     }
898
899     return hres;
900 }
901
902 static HRESULT exec_from_table(HTMLDocument *This, const cmdtable_t *cmdtable, DWORD cmdid,
903                                DWORD cmdexecopt, VARIANT *in, VARIANT *out)
904 {
905     const cmdtable_t *iter = cmdtable;
906
907     while(iter->id && iter->id != cmdid)
908         iter++;
909
910     if(!iter->id || !iter->exec)
911         return OLECMDERR_E_NOTSUPPORTED;
912
913     return iter->exec(This, cmdexecopt, in, out);
914 }
915
916 static HRESULT WINAPI OleCommandTarget_Exec(IOleCommandTarget *iface, const GUID *pguidCmdGroup,
917         DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
918 {
919     HTMLDocument *This = impl_from_IOleCommandTarget(iface);
920
921     if(!pguidCmdGroup) {
922         if(nCmdID<OLECMDID_OPEN || nCmdID>OLECMDID_GETPRINTTEMPLATE || !exec_table[nCmdID].func) {
923             WARN("Unsupported cmdID = %d\n", nCmdID);
924             return OLECMDERR_E_NOTSUPPORTED;
925         }
926
927         return exec_table[nCmdID].func(This, nCmdexecopt, pvaIn, pvaOut);
928     }else if(IsEqualGUID(&CGID_Explorer, pguidCmdGroup)) {
929         FIXME("unsupported nCmdID %d of CGID_Explorer group\n", nCmdID);
930         TRACE("%p %p\n", pvaIn, pvaOut);
931         return OLECMDERR_E_NOTSUPPORTED;
932     }else if(IsEqualGUID(&CGID_ShellDocView, pguidCmdGroup)) {
933         FIXME("unsupported nCmdID %d of CGID_ShellDocView group\n", nCmdID);
934         return OLECMDERR_E_NOTSUPPORTED;
935     }else if(IsEqualGUID(&CGID_MSHTML, pguidCmdGroup)) {
936         HRESULT hres = exec_from_table(This, base_cmds, nCmdID, nCmdexecopt, pvaIn, pvaOut);
937         if(hres == OLECMDERR_E_NOTSUPPORTED)
938             hres = exec_from_table(This, editmode_cmds, nCmdID,
939                                    nCmdexecopt, pvaIn, pvaOut);
940         if(hres == OLECMDERR_E_NOTSUPPORTED)
941             FIXME("unsupported nCmdID %d of CGID_MSHTML group\n", nCmdID);
942
943         return hres;
944     }
945
946     FIXME("Unsupported pguidCmdGroup %s\n", debugstr_guid(pguidCmdGroup));
947     return OLECMDERR_E_UNKNOWNGROUP;
948 }
949
950 static const IOleCommandTargetVtbl OleCommandTargetVtbl = {
951     OleCommandTarget_QueryInterface,
952     OleCommandTarget_AddRef,
953     OleCommandTarget_Release,
954     OleCommandTarget_QueryStatus,
955     OleCommandTarget_Exec
956 };
957
958 void show_context_menu(HTMLDocumentObj *This, DWORD dwID, POINT *ppt, IDispatch *elem)
959 {
960     HMENU menu_res, menu;
961     DWORD cmdid;
962
963     if(This->hostui && S_OK == IDocHostUIHandler_ShowContextMenu(This->hostui,
964             dwID, ppt, (IUnknown*)&This->basedoc.IOleCommandTarget_iface, elem))
965         return;
966
967     menu_res = LoadMenuW(get_shdoclc(), MAKEINTRESOURCEW(IDR_BROWSE_CONTEXT_MENU));
968     menu = GetSubMenu(menu_res, dwID);
969
970     cmdid = TrackPopupMenu(menu, TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD,
971             ppt->x, ppt->y, 0, This->hwnd, NULL);
972     DestroyMenu(menu_res);
973
974     if(cmdid)
975         IOleCommandTarget_Exec(&This->basedoc.IOleCommandTarget_iface, &CGID_MSHTML, cmdid, 0,
976                 NULL, NULL);
977 }
978
979 void HTMLDocument_OleCmd_Init(HTMLDocument *This)
980 {
981     This->IOleCommandTarget_iface.lpVtbl = &OleCommandTargetVtbl;
982 }