shlwapi/tests: Don't crash on NT4.
[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, NULL);
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     if(This->nscontainer)
587         set_ns_editmode(This->nscontainer);
588
589     update_doc(This, UPDATE_UI);
590
591     if(This->mon) {
592         /* FIXME: We should find nicer way to do this */
593         remove_doc_tasks(This);
594
595         mon = This->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->ui_active) {
613         RECT rcBorderWidths;
614
615         if(This->ip_window)
616             call_set_active_object(This->ip_window, NULL);
617         if(This->hostui)
618             IDocHostUIHandler_HideUI(This->hostui);
619
620         if(This->hostui)
621             IDocHostUIHandler_ShowUI(This->hostui, DOCHOSTUITYPE_AUTHOR, ACTOBJ(This), CMDTARGET(This),
622                 This->frame, This->ip_window);
623
624         if(This->ip_window)
625             call_set_active_object(This->ip_window, ACTOBJ(This));
626
627         memset(&rcBorderWidths, 0, sizeof(rcBorderWidths));
628         if (This->frame)
629             IOleInPlaceFrame_SetBorderSpace(This->frame, &rcBorderWidths);
630     }
631
632     return S_OK;
633 }
634
635 static HRESULT exec_htmleditmode(HTMLDocument *This, DWORD cmdexecopt, VARIANT *in, VARIANT *out)
636 {
637     FIXME("(%p)->(%08x %p %p)\n", This, cmdexecopt, in, out);
638     return S_OK;
639 }
640
641 static HRESULT exec_baselinefont3(HTMLDocument *This, DWORD cmdexecopt, VARIANT *in, VARIANT *out)
642 {
643     FIXME("(%p)->(%08x %p %p)\n", This, cmdexecopt, in, out);
644     return S_OK;
645 }
646
647 static HRESULT exec_respectvisibility_indesign(HTMLDocument *This, DWORD cmdexecopt,
648         VARIANT *in, VARIANT *out)
649 {
650     FIXME("(%p)->(%08x %p %p)\n", This, cmdexecopt, in, out);
651     return E_NOTIMPL;
652 }
653
654 static HRESULT query_enabled_stub(HTMLDocument *This, OLECMD *cmd)
655 {
656     switch(cmd->cmdID) {
657     case IDM_PRINT:
658         FIXME("CGID_MSHTML: IDM_PRINT\n");
659         cmd->cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
660         break;
661     case IDM_BLOCKDIRLTR:
662         FIXME("CGID_MSHTML: IDM_BLOCKDIRLTR\n");
663         cmd->cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
664         break;
665     case IDM_BLOCKDIRRTL:
666         FIXME("CGID_MSHTML: IDM_BLOCKDIRRTL\n");
667         cmd->cmdf = OLECMDF_SUPPORTED|OLECMDF_ENABLED;
668         break;
669     }
670
671     return S_OK;
672 }
673
674 static const struct {
675     OLECMDF cmdf;
676     HRESULT (*func)(HTMLDocument*,DWORD,VARIANT*,VARIANT*);
677 } exec_table[OLECMDID_GETPRINTTEMPLATE+1] = {
678     {0},
679     { OLECMDF_SUPPORTED,                  exec_open                 }, /* OLECMDID_OPEN */
680     { OLECMDF_SUPPORTED,                  exec_new                  }, /* OLECMDID_NEW */
681     { OLECMDF_SUPPORTED,                  exec_save                 }, /* OLECMDID_SAVE */
682     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_save_as              }, /* OLECMDID_SAVEAS */
683     { OLECMDF_SUPPORTED,                  exec_save_copy_as         }, /* OLECMDID_SAVECOPYAS */
684     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_print                }, /* OLECMDID_PRINT */
685     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_print_preview        }, /* OLECMDID_PRINTPREVIEW */
686     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_page_setup           }, /* OLECMDID_PAGESETUP */
687     { OLECMDF_SUPPORTED,                  exec_spell                }, /* OLECMDID_SPELL */
688     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_properties           }, /* OLECMDID_PROPERTIES */
689     { OLECMDF_SUPPORTED,                  exec_cut                  }, /* OLECMDID_CUT */
690     { OLECMDF_SUPPORTED,                  exec_copy                 }, /* OLECMDID_COPY */
691     { OLECMDF_SUPPORTED,                  exec_paste                }, /* OLECMDID_PASTE */
692     { OLECMDF_SUPPORTED,                  exec_paste_special        }, /* OLECMDID_PASTESPECIAL */
693     { OLECMDF_SUPPORTED,                  exec_undo                 }, /* OLECMDID_UNDO */
694     { OLECMDF_SUPPORTED,                  exec_rendo                }, /* OLECMDID_REDO */
695     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_select_all           }, /* OLECMDID_SELECTALL */
696     { OLECMDF_SUPPORTED,                  exec_clear_selection      }, /* OLECMDID_CLEARSELECTION */
697     { OLECMDF_SUPPORTED,                  exec_zoom                 }, /* OLECMDID_ZOOM */
698     { OLECMDF_SUPPORTED,                  exec_get_zoom_range       }, /* OLECMDID_GETZOOMRANGE */
699     {0},
700     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_refresh              }, /* OLECMDID_REFRESH */
701     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_stop                 }, /* OLECMDID_STOP */
702     {0},{0},{0},{0},{0},{0},
703     { OLECMDF_SUPPORTED,                  exec_stop_download        }, /* OLECMDID_STOPDOWNLOAD */
704     {0},
705     { OLECMDF_SUPPORTED|OLECMDF_ENABLED,  exec_find                 }, /* OLECMDID_FIND */
706     { OLECMDF_SUPPORTED,                  exec_delete               }, /* OLECMDID_DELETE */
707     {0},{0},
708     { OLECMDF_SUPPORTED,                  exec_enable_interaction   }, /* OLECMDID_ENABLE_INTERACTION */
709     { OLECMDF_SUPPORTED,                  exec_on_unload            }, /* OLECMDID_ONUNLOAD */
710     {0},{0},{0},{0},{0},
711     { OLECMDF_SUPPORTED,                  exec_show_page_setup      }, /* OLECMDID_SHOWPAGESETUP */
712     { OLECMDF_SUPPORTED,                  exec_show_print           }, /* OLECMDID_SHOWPRINT */
713     {0},{0},
714     { OLECMDF_SUPPORTED,                  exec_close                }, /* OLECMDID_CLOSE */
715     {0},{0},{0},
716     { OLECMDF_SUPPORTED,                  exec_set_print_template   }, /* OLECMDID_SETPRINTTEMPLATE */
717     { OLECMDF_SUPPORTED,                  exec_get_print_template   }  /* OLECMDID_GETPRINTTEMPLATE */
718 };
719
720 static const cmdtable_t base_cmds[] = {
721     {IDM_COPY,             query_mshtml_copy,     exec_mshtml_copy},
722     {IDM_PASTE,            query_mshtml_paste,    exec_mshtml_paste},
723     {IDM_CUT,              query_mshtml_cut,      exec_mshtml_cut},
724     {IDM_BROWSEMODE,       NULL,                  exec_browsemode},
725     {IDM_EDITMODE,         NULL,                  exec_editmode},
726     {IDM_PRINT,            query_enabled_stub,    exec_print},
727     {IDM_HTMLEDITMODE,     NULL,                  exec_htmleditmode},
728     {IDM_BASELINEFONT3,    NULL,                  exec_baselinefont3},
729     {IDM_BLOCKDIRLTR,      query_enabled_stub,    NULL},
730     {IDM_BLOCKDIRRTL,      query_enabled_stub,    NULL},
731     {IDM_RESPECTVISIBILITY_INDESIGN, NULL,        exec_respectvisibility_indesign},
732     {0,NULL,NULL}
733 };
734
735 static HRESULT WINAPI OleCommandTarget_QueryInterface(IOleCommandTarget *iface, REFIID riid, void **ppv)
736 {
737     HTMLDocument *This = CMDTARGET_THIS(iface);
738     return IHTMLDocument2_QueryInterface(HTMLDOC(This), riid, ppv);
739 }
740
741 static ULONG WINAPI OleCommandTarget_AddRef(IOleCommandTarget *iface)
742 {
743     HTMLDocument *This = CMDTARGET_THIS(iface);
744     return IHTMLDocument2_AddRef(HTMLDOC(This));
745 }
746
747 static ULONG WINAPI OleCommandTarget_Release(IOleCommandTarget *iface)
748 {
749     HTMLDocument *This = CMDTARGET_THIS(iface);
750     return IHTMLDocument_Release(HTMLDOC(This));
751 }
752
753 static HRESULT query_from_table(HTMLDocument *This, const cmdtable_t *cmdtable, OLECMD *cmd)
754 {
755     const cmdtable_t *iter = cmdtable;
756
757     cmd->cmdf = 0;
758
759     while(iter->id && iter->id != cmd->cmdID)
760         iter++;
761
762     if(!iter->id || !iter->query)
763         return OLECMDERR_E_NOTSUPPORTED;
764
765     return iter->query(This, cmd);
766 }
767
768 static HRESULT WINAPI OleCommandTarget_QueryStatus(IOleCommandTarget *iface, const GUID *pguidCmdGroup,
769         ULONG cCmds, OLECMD prgCmds[], OLECMDTEXT *pCmdText)
770 {
771     HTMLDocument *This = CMDTARGET_THIS(iface);
772     HRESULT hres = S_OK, hr;
773
774     TRACE("(%p)->(%s %d %p %p)\n", This, debugstr_guid(pguidCmdGroup), cCmds, prgCmds, pCmdText);
775
776     if(!pguidCmdGroup) {
777         ULONG i;
778
779         for(i=0; i<cCmds; i++) {
780             if(prgCmds[i].cmdID<OLECMDID_OPEN || prgCmds[i].cmdID>OLECMDID_GETPRINTTEMPLATE) {
781                 WARN("Unsupported cmdID = %d\n", prgCmds[i].cmdID);
782                 prgCmds[i].cmdf = 0;
783                 hres = OLECMDERR_E_NOTSUPPORTED;
784             }else {
785                 if(prgCmds[i].cmdID == OLECMDID_OPEN || prgCmds[i].cmdID == OLECMDID_NEW) {
786                     IOleCommandTarget *cmdtrg = NULL;
787                     OLECMD olecmd;
788
789                     prgCmds[i].cmdf = OLECMDF_SUPPORTED;
790                     if(This->client) {
791                         hr = IOleClientSite_QueryInterface(This->client, &IID_IOleCommandTarget,
792                                 (void**)&cmdtrg);
793                         if(SUCCEEDED(hr)) {
794                             olecmd.cmdID = prgCmds[i].cmdID;
795                             olecmd.cmdf = 0;
796
797                             hr = IOleCommandTarget_QueryStatus(cmdtrg, NULL, 1, &olecmd, NULL);
798                             if(SUCCEEDED(hr) && olecmd.cmdf)
799                                 prgCmds[i].cmdf = olecmd.cmdf;
800                         }
801                     }else {
802                         ERR("This->client == NULL, native would crash\n");
803                     }
804                 }else {
805                     prgCmds[i].cmdf = exec_table[prgCmds[i].cmdID].cmdf;
806                     TRACE("cmdID = %d  returning %x\n", prgCmds[i].cmdID, prgCmds[i].cmdf);
807                 }
808                 hres = S_OK;
809             }
810         }
811
812         if(pCmdText)
813             FIXME("Set pCmdText\n");
814     }else if(IsEqualGUID(&CGID_MSHTML, pguidCmdGroup)) {
815         ULONG i;
816
817         for(i=0; i<cCmds; i++) {
818             HRESULT hres = query_from_table(This, base_cmds, prgCmds+i);
819             if(hres == OLECMDERR_E_NOTSUPPORTED)
820                 hres = query_from_table(This, editmode_cmds, prgCmds+i);
821             if(hres == OLECMDERR_E_NOTSUPPORTED)
822                 FIXME("CGID_MSHTML: unsupported cmdID %d\n", prgCmds[i].cmdID);
823         }
824
825         hres = prgCmds[i-1].cmdf ? S_OK : OLECMDERR_E_NOTSUPPORTED;
826
827         if(pCmdText)
828             FIXME("Set pCmdText\n");
829     }else {
830         FIXME("Unsupported pguidCmdGroup %s\n", debugstr_guid(pguidCmdGroup));
831         hres = OLECMDERR_E_UNKNOWNGROUP;
832     }
833
834     return hres;
835 }
836
837 static HRESULT exec_from_table(HTMLDocument *This, const cmdtable_t *cmdtable, DWORD cmdid,
838                                DWORD cmdexecopt, VARIANT *in, VARIANT *out)
839 {
840     const cmdtable_t *iter = cmdtable;
841
842     while(iter->id && iter->id != cmdid)
843         iter++;
844
845     if(!iter->id || !iter->exec)
846         return OLECMDERR_E_NOTSUPPORTED;
847
848     return iter->exec(This, cmdexecopt, in, out);
849 }
850
851 static HRESULT WINAPI OleCommandTarget_Exec(IOleCommandTarget *iface, const GUID *pguidCmdGroup,
852         DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
853 {
854     HTMLDocument *This = CMDTARGET_THIS(iface);
855
856     if(!pguidCmdGroup) {
857         if(nCmdID<OLECMDID_OPEN || nCmdID>OLECMDID_GETPRINTTEMPLATE || !exec_table[nCmdID].func) {
858             WARN("Unsupported cmdID = %d\n", nCmdID);
859             return OLECMDERR_E_NOTSUPPORTED;
860         }
861
862         return exec_table[nCmdID].func(This, nCmdexecopt, pvaIn, pvaOut);
863     }else if(IsEqualGUID(&CGID_Explorer, pguidCmdGroup)) {
864         FIXME("unsupported nCmdID %d of CGID_Explorer group\n", nCmdID);
865         TRACE("%p %p\n", pvaIn, pvaOut);
866         return OLECMDERR_E_NOTSUPPORTED;
867     }else if(IsEqualGUID(&CGID_ShellDocView, pguidCmdGroup)) {
868         FIXME("unsupported nCmdID %d of CGID_ShellDocView group\n", nCmdID);
869         return OLECMDERR_E_NOTSUPPORTED;
870     }else if(IsEqualGUID(&CGID_MSHTML, pguidCmdGroup)) {
871         HRESULT hres = exec_from_table(This, base_cmds, nCmdID, nCmdexecopt, pvaIn, pvaOut);
872         if(hres == OLECMDERR_E_NOTSUPPORTED)
873             hres = exec_from_table(This, editmode_cmds, nCmdID,
874                                    nCmdexecopt, pvaIn, pvaOut);
875         if(hres == OLECMDERR_E_NOTSUPPORTED)
876             FIXME("unsupported nCmdID %d of CGID_MSHTML group\n", nCmdID);
877
878         return hres;
879     }
880
881     FIXME("Unsupported pguidCmdGroup %s\n", debugstr_guid(pguidCmdGroup));
882     return OLECMDERR_E_UNKNOWNGROUP;
883 }
884
885 #undef CMDTARGET_THIS
886
887 static const IOleCommandTargetVtbl OleCommandTargetVtbl = {
888     OleCommandTarget_QueryInterface,
889     OleCommandTarget_AddRef,
890     OleCommandTarget_Release,
891     OleCommandTarget_QueryStatus,
892     OleCommandTarget_Exec
893 };
894
895 void show_context_menu(HTMLDocument *This, DWORD dwID, POINT *ppt, IDispatch *elem)
896 {
897     HMENU menu_res, menu;
898     DWORD cmdid;
899     HRESULT hres;
900
901     hres = IDocHostUIHandler_ShowContextMenu(This->hostui, dwID, ppt,
902             (IUnknown*)CMDTARGET(This), elem);
903     if(hres == S_OK)
904         return;
905
906     menu_res = LoadMenuW(get_shdoclc(), MAKEINTRESOURCEW(IDR_BROWSE_CONTEXT_MENU));
907     menu = GetSubMenu(menu_res, dwID);
908
909     cmdid = TrackPopupMenu(menu, TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD,
910             ppt->x, ppt->y, 0, This->hwnd, NULL);
911     DestroyMenu(menu_res);
912
913     if(cmdid)
914         IOleCommandTarget_Exec(CMDTARGET(This), &CGID_MSHTML, cmdid, 0, NULL, NULL);
915 }
916
917 void HTMLDocument_OleCmd_Init(HTMLDocument *This)
918 {
919     This->lpOleCommandTargetVtbl = &OleCommandTargetVtbl;
920 }