[INTRIN]
[reactos.git] / reactos / base / shell / ie / ieframe / dochost.c
1 /*
2 * Copyright 2005-2006 Jacek Caban for CodeWeavers
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17 */
18
19 #include "ieframe.h"
20
21 #include <initguid.h>
22
23 DEFINE_OLEGUID(CGID_DocHostCmdPriv, 0x000214D4L, 0, 0);
24
25 #define DOCHOST_DOCCANNAVIGATE 0
26
27 /* Undocumented notification, see mshtml tests */
28 #define CMDID_EXPLORER_UPDATEHISTORY 38
29
30 static ATOM doc_view_atom = 0;
31
32 void push_dochost_task(DocHost *This, task_header_t *task, task_proc_t proc, task_destr_t destr, BOOL send)
33 {
34 BOOL is_empty;
35
36 task->proc = proc;
37 task->destr = destr;
38
39 is_empty = list_empty(&This->task_queue);
40 list_add_tail(&This->task_queue, &task->entry);
41
42 if(send)
43 SendMessageW(This->frame_hwnd, WM_DOCHOSTTASK, 0, 0);
44 else if(is_empty)
45 PostMessageW(This->frame_hwnd, WM_DOCHOSTTASK, 0, 0);
46 }
47
48 LRESULT process_dochost_tasks(DocHost *This)
49 {
50 task_header_t *task;
51
52 while(!list_empty(&This->task_queue)) {
53 task = LIST_ENTRY(This->task_queue.next, task_header_t, entry);
54 list_remove(&task->entry);
55
56 task->proc(This, task);
57 task->destr(task);
58 }
59
60 return 0;
61 }
62
63 void abort_dochost_tasks(DocHost *This, task_proc_t proc)
64 {
65 task_header_t *task, *cursor;
66
67 LIST_FOR_EACH_ENTRY_SAFE(task, cursor, &This->task_queue, task_header_t, entry) {
68 if(proc && proc != task->proc)
69 continue;
70
71 list_remove(&task->entry);
72 task->destr(task);
73 }
74 }
75
76 static void notif_complete(DocHost *This, DISPID dispid)
77 {
78 DISPPARAMS dispparams;
79 VARIANTARG params[2];
80 VARIANT url;
81
82 dispparams.cArgs = 2;
83 dispparams.cNamedArgs = 0;
84 dispparams.rgdispidNamedArgs = NULL;
85 dispparams.rgvarg = params;
86
87 V_VT(params) = (VT_BYREF|VT_VARIANT);
88 V_BYREF(params) = &url;
89
90 V_VT(params+1) = VT_DISPATCH;
91 V_DISPATCH(params+1) = (IDispatch*)This->wb;
92
93 V_VT(&url) = VT_BSTR;
94 V_BSTR(&url) = SysAllocString(This->url);
95
96 TRACE("%d >>>\n", dispid);
97 call_sink(This->cps.wbe2, dispid, &dispparams);
98 TRACE("%d <<<\n", dispid);
99
100 SysFreeString(V_BSTR(&url));
101 This->busy = VARIANT_FALSE;
102 }
103
104 static void object_available(DocHost *This)
105 {
106 IHlinkTarget *hlink;
107 HRESULT hres;
108
109 TRACE("(%p)\n", This);
110
111 if(!This->document) {
112 WARN("document == NULL\n");
113 return;
114 }
115
116 hres = IUnknown_QueryInterface(This->document, &IID_IHlinkTarget, (void**)&hlink);
117 if(SUCCEEDED(hres)) {
118 hres = IHlinkTarget_Navigate(hlink, 0, NULL);
119 IHlinkTarget_Release(hlink);
120 if(FAILED(hres))
121 FIXME("Navigate failed\n");
122 }else {
123 IOleObject *ole_object;
124 RECT rect;
125
126 TRACE("No IHlink iface\n");
127
128 hres = IUnknown_QueryInterface(This->document, &IID_IOleObject, (void**)&ole_object);
129 if(FAILED(hres)) {
130 FIXME("Could not get IOleObject iface: %08x\n", hres);
131 return;
132 }
133
134 GetClientRect(This->hwnd, &rect);
135 hres = IOleObject_DoVerb(ole_object, OLEIVERB_SHOW, NULL, &This->IOleClientSite_iface, -1, This->hwnd, &rect);
136 IOleObject_Release(ole_object);
137 if(FAILED(hres))
138 FIXME("DoVerb failed: %08x\n", hres);
139 }
140 }
141
142 static HRESULT get_doc_ready_state(DocHost *This, READYSTATE *ret)
143 {
144 DISPPARAMS dp = {NULL,NULL,0,0};
145 IDispatch *disp;
146 EXCEPINFO ei;
147 VARIANT var;
148 HRESULT hres;
149
150 hres = IUnknown_QueryInterface(This->document, &IID_IDispatch, (void**)&disp);
151 if(FAILED(hres))
152 return hres;
153
154 hres = IDispatch_Invoke(disp, DISPID_READYSTATE, &IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYGET,
155 &dp, &var, &ei, NULL);
156 IDispatch_Release(disp);
157 if(FAILED(hres)) {
158 WARN("Invoke(DISPID_READYSTATE failed: %08x\n", hres);
159 return hres;
160 }
161
162 if(V_VT(&var) != VT_I4) {
163 WARN("V_VT(var) = %d\n", V_VT(&var));
164 VariantClear(&var);
165 return E_FAIL;
166 }
167
168 *ret = V_I4(&var);
169 return S_OK;
170 }
171
172 static void advise_prop_notif(DocHost *This, BOOL set)
173 {
174 IConnectionPointContainer *cp_container;
175 IConnectionPoint *cp;
176 HRESULT hres;
177
178 hres = IUnknown_QueryInterface(This->document, &IID_IConnectionPointContainer, (void**)&cp_container);
179 if(FAILED(hres))
180 return;
181
182 hres = IConnectionPointContainer_FindConnectionPoint(cp_container, &IID_IPropertyNotifySink, &cp);
183 IConnectionPointContainer_Release(cp_container);
184 if(FAILED(hres))
185 return;
186
187 if(set)
188 hres = IConnectionPoint_Advise(cp, (IUnknown*)&This->IPropertyNotifySink_iface, &This->prop_notif_cookie);
189 else
190 hres = IConnectionPoint_Unadvise(cp, This->prop_notif_cookie);
191 IConnectionPoint_Release(cp);
192
193 if(SUCCEEDED(hres))
194 This->is_prop_notif = set;
195 }
196
197 void set_doc_state(DocHost *This, READYSTATE doc_state)
198 {
199 This->doc_state = doc_state;
200 if(doc_state > This->ready_state)
201 This->ready_state = doc_state;
202 }
203
204 static void update_ready_state(DocHost *This, READYSTATE ready_state)
205 {
206 if(ready_state > READYSTATE_LOADING && This->travellog.loading_pos != -1) {
207 WARN("histupdate not notified\n");
208 This->travellog.position = This->travellog.loading_pos;
209 This->travellog.loading_pos = -1;
210 }
211
212 if(ready_state > READYSTATE_LOADING && This->doc_state <= READYSTATE_LOADING && !This->browser_service /* FIXME */)
213 notif_complete(This, DISPID_NAVIGATECOMPLETE2);
214
215 if(ready_state == READYSTATE_COMPLETE && This->doc_state < READYSTATE_COMPLETE) {
216 set_doc_state(This, READYSTATE_COMPLETE);
217 if(!This->browser_service) /* FIXME: Not fully correct */
218 notif_complete(This, DISPID_DOCUMENTCOMPLETE);
219 }else {
220 set_doc_state(This, ready_state);
221 }
222 }
223
224 typedef struct {
225 task_header_t header;
226 IUnknown *doc;
227 READYSTATE ready_state;
228 } ready_state_task_t;
229
230 static void ready_state_task_destr(task_header_t *_task)
231 {
232 ready_state_task_t *task = (ready_state_task_t*)_task;
233
234 IUnknown_Release(task->doc);
235 heap_free(task);
236 }
237
238 static void ready_state_proc(DocHost *This, task_header_t *_task)
239 {
240 ready_state_task_t *task = (ready_state_task_t*)_task;
241
242 if(task->doc == This->document)
243 update_ready_state(This, task->ready_state);
244 }
245
246 static void push_ready_state_task(DocHost *This, READYSTATE ready_state)
247 {
248 ready_state_task_t *task = heap_alloc(sizeof(ready_state_task_t));
249
250 IUnknown_AddRef(This->document);
251 task->doc = This->document;
252 task->ready_state = ready_state;
253
254 push_dochost_task(This, &task->header, ready_state_proc, ready_state_task_destr, FALSE);
255 }
256
257 static void object_available_task_destr(task_header_t *task)
258 {
259 heap_free(task);
260 }
261
262 static void object_available_proc(DocHost *This, task_header_t *task)
263 {
264 object_available(This);
265 }
266
267 HRESULT dochost_object_available(DocHost *This, IUnknown *doc)
268 {
269 READYSTATE ready_state;
270 task_header_t *task;
271 IOleObject *oleobj;
272 HRESULT hres;
273
274 IUnknown_AddRef(doc);
275 This->document = doc;
276
277 hres = IUnknown_QueryInterface(doc, &IID_IOleObject, (void**)&oleobj);
278 if(SUCCEEDED(hres)) {
279 CLSID clsid;
280
281 hres = IOleObject_GetUserClassID(oleobj, &clsid);
282 if(SUCCEEDED(hres))
283 TRACE("Got clsid %s\n",
284 IsEqualGUID(&clsid, &CLSID_HTMLDocument) ? "CLSID_HTMLDocument" : debugstr_guid(&clsid));
285
286 hres = IOleObject_SetClientSite(oleobj, &This->IOleClientSite_iface);
287 if(FAILED(hres))
288 FIXME("SetClientSite failed: %08x\n", hres);
289
290 IOleObject_Release(oleobj);
291 }else {
292 FIXME("Could not get IOleObject iface: %08x\n", hres);
293 }
294
295 /* FIXME: Call SetAdvise */
296
297 task = heap_alloc(sizeof(*task));
298 push_dochost_task(This, task, object_available_proc, object_available_task_destr, FALSE);
299
300 hres = get_doc_ready_state(This, &ready_state);
301 if(SUCCEEDED(hres)) {
302 if(ready_state == READYSTATE_COMPLETE)
303 push_ready_state_task(This, READYSTATE_COMPLETE);
304 if(ready_state != READYSTATE_COMPLETE || This->doc_navigate)
305 advise_prop_notif(This, TRUE);
306 }else if(!This->doc_navigate) {
307 /* If we can't get document's ready state, there is not much we can do.
308 * Assume that document is complete at this point. */
309 push_ready_state_task(This, READYSTATE_COMPLETE);
310 }
311
312 return S_OK;
313 }
314
315 static LRESULT resize_document(DocHost *This, LONG width, LONG height)
316 {
317 RECT rect = {0, 0, width, height};
318
319 TRACE("(%p)->(%d %d)\n", This, width, height);
320
321 if(This->view)
322 IOleDocumentView_SetRect(This->view, &rect);
323
324 return 0;
325 }
326
327 static LRESULT WINAPI doc_view_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
328 {
329 DocHost *This;
330
331 static const WCHAR wszTHIS[] = {'T','H','I','S',0};
332
333 if(msg == WM_CREATE) {
334 This = *(DocHost**)lParam;
335 SetPropW(hwnd, wszTHIS, This);
336 }else {
337 This = GetPropW(hwnd, wszTHIS);
338 }
339
340 switch(msg) {
341 case WM_SIZE:
342 return resize_document(This, LOWORD(lParam), HIWORD(lParam));
343 }
344
345 return DefWindowProcW(hwnd, msg, wParam, lParam);
346 }
347
348 static void free_travellog_entry(travellog_entry_t *entry)
349 {
350 if(entry->stream)
351 IStream_Release(entry->stream);
352 heap_free(entry->url);
353 }
354
355 static IStream *get_travellog_stream(DocHost *This)
356 {
357 IPersistHistory *persist_history;
358 IStream *stream;
359 HRESULT hres;
360
361 hres = IUnknown_QueryInterface(This->document, &IID_IPersistHistory, (void**)&persist_history);
362 if(FAILED(hres))
363 return NULL;
364
365 hres = CreateStreamOnHGlobal(NULL, TRUE, &stream);
366 if(SUCCEEDED(hres))
367 hres = IPersistHistory_SaveHistory(persist_history, stream);
368 IPersistHistory_Release(persist_history);
369 if(FAILED(hres)) {
370 IStream_Release(stream);
371 return NULL;
372 }
373
374 return stream;
375 }
376
377 static void dump_travellog(DocHost *This)
378 {
379 unsigned i;
380
381 for(i=0; i < This->travellog.length; i++)
382 TRACE("%d: %s %s\n", i, i == This->travellog.position ? "=>" : " ", debugstr_w(This->travellog.log[i].url));
383 if(i == This->travellog.position)
384 TRACE("%d: =>\n", i);
385 }
386
387 static void update_travellog(DocHost *This)
388 {
389 travellog_entry_t *new_entry;
390
391 if(This->travellog.loading_pos == -1) {
392 /* Clear forward history. */
393 if(!This->travellog.log) {
394 This->travellog.log = heap_alloc(4 * sizeof(*This->travellog.log));
395 if(!This->travellog.log)
396 return;
397
398 This->travellog.size = 4;
399 }else if(This->travellog.size < This->travellog.position+1) {
400 travellog_entry_t *new_travellog;
401
402 new_travellog = heap_realloc(This->travellog.log, This->travellog.size*2*sizeof(*This->travellog.log));
403 if(!new_travellog)
404 return;
405
406 This->travellog.log = new_travellog;
407 This->travellog.size *= 2;
408 }
409
410 while(This->travellog.length > This->travellog.position)
411 free_travellog_entry(This->travellog.log + --This->travellog.length);
412 }
413
414 new_entry = This->travellog.log + This->travellog.position;
415
416 new_entry->url = heap_strdupW(This->url);
417 TRACE("Adding %s at %d\n", debugstr_w(This->url), This->travellog.position);
418 if(!new_entry->url)
419 return;
420
421 new_entry->stream = get_travellog_stream(This);
422
423 if(This->travellog.loading_pos == -1) {
424 This->travellog.position++;
425 }else {
426 This->travellog.position = This->travellog.loading_pos;
427 This->travellog.loading_pos = -1;
428 }
429 if(This->travellog.position > This->travellog.length)
430 This->travellog.length = This->travellog.position;
431
432 dump_travellog(This);
433 }
434
435 void create_doc_view_hwnd(DocHost *This)
436 {
437 RECT rect;
438
439 static const WCHAR wszShell_DocObject_View[] =
440 {'S','h','e','l','l',' ','D','o','c','O','b','j','e','c','t',' ','V','i','e','w',0};
441
442 if(!doc_view_atom) {
443 static WNDCLASSEXW wndclass = {
444 sizeof(wndclass),
445 CS_PARENTDC,
446 doc_view_proc,
447 0, 0 /* native uses 4*/, NULL, NULL, NULL,
448 (HBRUSH)(COLOR_WINDOW + 1), NULL,
449 wszShell_DocObject_View,
450 NULL
451 };
452
453 wndclass.hInstance = ieframe_instance;
454
455 doc_view_atom = RegisterClassExW(&wndclass);
456 }
457
458 This->container_vtbl->GetDocObjRect(This, &rect);
459 This->hwnd = CreateWindowExW(0, wszShell_DocObject_View,
460 wszShell_DocObject_View,
461 WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP,
462 rect.left, rect.top, rect.right, rect.bottom, This->frame_hwnd,
463 NULL, ieframe_instance, This);
464 }
465
466 void deactivate_document(DocHost *This)
467 {
468 IOleInPlaceObjectWindowless *winobj;
469 IOleObject *oleobj = NULL;
470 IHlinkTarget *hlink = NULL;
471 HRESULT hres;
472
473 if(!This->document) return;
474
475 if(This->doc_navigate) {
476 IUnknown_Release(This->doc_navigate);
477 This->doc_navigate = NULL;
478 }
479
480 if(This->is_prop_notif)
481 advise_prop_notif(This, FALSE);
482
483 if(This->view)
484 IOleDocumentView_UIActivate(This->view, FALSE);
485
486 hres = IUnknown_QueryInterface(This->document, &IID_IOleInPlaceObjectWindowless,
487 (void**)&winobj);
488 if(SUCCEEDED(hres)) {
489 IOleInPlaceObjectWindowless_InPlaceDeactivate(winobj);
490 IOleInPlaceObjectWindowless_Release(winobj);
491 }
492
493 if(This->view) {
494 IOleDocumentView_Show(This->view, FALSE);
495 IOleDocumentView_CloseView(This->view, 0);
496 IOleDocumentView_SetInPlaceSite(This->view, NULL);
497 IOleDocumentView_Release(This->view);
498 This->view = NULL;
499 }
500
501 hres = IUnknown_QueryInterface(This->document, &IID_IOleObject, (void**)&oleobj);
502 if(SUCCEEDED(hres))
503 IOleObject_Close(oleobj, OLECLOSE_NOSAVE);
504
505 hres = IUnknown_QueryInterface(This->document, &IID_IHlinkTarget, (void**)&hlink);
506 if(SUCCEEDED(hres)) {
507 IHlinkTarget_SetBrowseContext(hlink, NULL);
508 IHlinkTarget_Release(hlink);
509 }
510
511 if(oleobj) {
512 IOleClientSite *client_site = NULL;
513
514 IOleObject_GetClientSite(oleobj, &client_site);
515 if(client_site) {
516 if(client_site == &This->IOleClientSite_iface)
517 IOleObject_SetClientSite(oleobj, NULL);
518 IOleClientSite_Release(client_site);
519 }
520
521 IOleObject_Release(oleobj);
522 }
523
524 IUnknown_Release(This->document);
525 This->document = NULL;
526 }
527
528 HRESULT refresh_document(DocHost *This)
529 {
530 IOleCommandTarget *cmdtrg;
531 VARIANT vin, vout;
532 HRESULT hres;
533
534 if(!This->document) {
535 FIXME("no document\n");
536 return E_FAIL;
537 }
538
539 hres = IUnknown_QueryInterface(This->document, &IID_IOleCommandTarget, (void**)&cmdtrg);
540 if(FAILED(hres))
541 return hres;
542
543 V_VT(&vin) = VT_EMPTY;
544 V_VT(&vout) = VT_EMPTY;
545 hres = IOleCommandTarget_Exec(cmdtrg, NULL, OLECMDID_REFRESH, OLECMDEXECOPT_PROMPTUSER, &vin, &vout);
546 IOleCommandTarget_Release(cmdtrg);
547 if(FAILED(hres))
548 return hres;
549
550 VariantClear(&vout);
551 return S_OK;
552 }
553
554 void release_dochost_client(DocHost *This)
555 {
556 if(This->hwnd) {
557 DestroyWindow(This->hwnd);
558 This->hwnd = NULL;
559 }
560
561 if(This->hostui) {
562 IDocHostUIHandler_Release(This->hostui);
563 This->hostui = NULL;
564 }
565
566 if(This->client_disp) {
567 IDispatch_Release(This->client_disp);
568 This->client_disp = NULL;
569 }
570
571 if(This->frame) {
572 IOleInPlaceFrame_Release(This->frame);
573 This->frame = NULL;
574 }
575 }
576
577 static inline DocHost *impl_from_IOleCommandTarget(IOleCommandTarget *iface)
578 {
579 return CONTAINING_RECORD(iface, DocHost, IOleCommandTarget_iface);
580 }
581
582 static HRESULT WINAPI ClOleCommandTarget_QueryInterface(IOleCommandTarget *iface,
583 REFIID riid, void **ppv)
584 {
585 DocHost *This = impl_from_IOleCommandTarget(iface);
586 return IOleClientSite_QueryInterface(&This->IOleClientSite_iface, riid, ppv);
587 }
588
589 static ULONG WINAPI ClOleCommandTarget_AddRef(IOleCommandTarget *iface)
590 {
591 DocHost *This = impl_from_IOleCommandTarget(iface);
592 return IOleClientSite_AddRef(&This->IOleClientSite_iface);
593 }
594
595 static ULONG WINAPI ClOleCommandTarget_Release(IOleCommandTarget *iface)
596 {
597 DocHost *This = impl_from_IOleCommandTarget(iface);
598 return IOleClientSite_Release(&This->IOleClientSite_iface);
599 }
600
601 static HRESULT WINAPI ClOleCommandTarget_QueryStatus(IOleCommandTarget *iface,
602 const GUID *pguidCmdGroup, ULONG cCmds, OLECMD prgCmds[], OLECMDTEXT *pCmdText)
603 {
604 DocHost *This = impl_from_IOleCommandTarget(iface);
605 ULONG i= 0;
606 FIXME("(%p)->(%s %u %p %p)\n", This, debugstr_guid(pguidCmdGroup), cCmds, prgCmds,
607 pCmdText);
608 while (prgCmds && (cCmds > i)) {
609 FIXME("command_%u: %u, 0x%x\n", i, prgCmds[i].cmdID, prgCmds[i].cmdf);
610 i++;
611 }
612 return E_NOTIMPL;
613 }
614
615 static HRESULT WINAPI ClOleCommandTarget_Exec(IOleCommandTarget *iface,
616 const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn,
617 VARIANT *pvaOut)
618 {
619 DocHost *This = impl_from_IOleCommandTarget(iface);
620
621 TRACE("(%p)->(%s %d %d %s %s)\n", This, debugstr_guid(pguidCmdGroup), nCmdID, nCmdexecopt,
622 debugstr_variant(pvaIn), debugstr_variant(pvaOut));
623
624 if(!pguidCmdGroup) {
625 switch(nCmdID) {
626 case OLECMDID_UPDATECOMMANDS:
627 case OLECMDID_SETDOWNLOADSTATE:
628 return This->container_vtbl->exec(This, pguidCmdGroup, nCmdID, nCmdexecopt, pvaIn, pvaOut);
629 default:
630 FIXME("Unimplemented cmdid %d\n", nCmdID);
631 return E_NOTIMPL;
632 }
633 }
634
635 if(IsEqualGUID(pguidCmdGroup, &CGID_DocHostCmdPriv)) {
636 switch(nCmdID) {
637 case DOCHOST_DOCCANNAVIGATE:
638 if(!pvaIn || V_VT(pvaIn) != VT_UNKNOWN)
639 return E_INVALIDARG;
640
641 if(This->doc_navigate)
642 IUnknown_Release(This->doc_navigate);
643 IUnknown_AddRef(V_UNKNOWN(pvaIn));
644 This->doc_navigate = V_UNKNOWN(pvaIn);
645 return S_OK;
646
647 case 1: {
648 IHTMLWindow2 *win2;
649 SAFEARRAY *sa = V_ARRAY(pvaIn);
650 VARIANT status_code, url, htmlwindow;
651 LONG ind;
652 HRESULT hres;
653
654 if(V_VT(pvaIn) != VT_ARRAY || !sa || (SafeArrayGetDim(sa) != 1))
655 return E_INVALIDARG;
656
657 ind = 0;
658 hres = SafeArrayGetElement(sa, &ind, &status_code);
659 if(FAILED(hres) || V_VT(&status_code)!=VT_I4)
660 return E_INVALIDARG;
661
662 ind = 1;
663 hres = SafeArrayGetElement(sa, &ind, &url);
664 if(FAILED(hres) || V_VT(&url)!=VT_BSTR)
665 return E_INVALIDARG;
666
667 ind = 3;
668 hres = SafeArrayGetElement(sa, &ind, &htmlwindow);
669 if(FAILED(hres) || V_VT(&htmlwindow)!=VT_UNKNOWN || !V_UNKNOWN(&htmlwindow))
670 return E_INVALIDARG;
671
672 hres = IUnknown_QueryInterface(V_UNKNOWN(&htmlwindow), &IID_IHTMLWindow2, (void**)&win2);
673 if(FAILED(hres))
674 return E_INVALIDARG;
675
676 handle_navigation_error(This, V_I4(&status_code), V_BSTR(&url), win2);
677 IHTMLWindow2_Release(win2);
678 return S_OK;
679 }
680
681 default:
682 FIXME("unsupported command %d of CGID_DocHostCmdPriv\n", nCmdID);
683 return E_NOTIMPL;
684 }
685 }
686
687 if(IsEqualGUID(pguidCmdGroup, &CGID_Explorer)) {
688 switch(nCmdID) {
689 case CMDID_EXPLORER_UPDATEHISTORY:
690 update_travellog(This);
691 return S_OK;
692
693 default:
694 FIXME("Unimplemented cmdid %d of CGID_Explorer\n", nCmdID);
695 return E_NOTIMPL;
696 }
697 }
698
699 if(IsEqualGUID(pguidCmdGroup, &CGID_ShellDocView)) {
700 switch(nCmdID) {
701 default:
702 FIXME("Unimplemented cmdid %d of CGID_ShellDocView\n", nCmdID);
703 return E_NOTIMPL;
704 }
705 }
706
707 if(IsEqualGUID(&CGID_DocHostCommandHandler, pguidCmdGroup))
708 return This->container_vtbl->exec(This, pguidCmdGroup, nCmdID, nCmdexecopt, pvaIn, pvaOut);
709
710 FIXME("Unimplemented cmdid %d of group %s\n", nCmdID, debugstr_guid(pguidCmdGroup));
711 return E_NOTIMPL;
712 }
713
714 static const IOleCommandTargetVtbl OleCommandTargetVtbl = {
715 ClOleCommandTarget_QueryInterface,
716 ClOleCommandTarget_AddRef,
717 ClOleCommandTarget_Release,
718 ClOleCommandTarget_QueryStatus,
719 ClOleCommandTarget_Exec
720 };
721
722 static inline DocHost *impl_from_IDocHostUIHandler2(IDocHostUIHandler2 *iface)
723 {
724 return CONTAINING_RECORD(iface, DocHost, IDocHostUIHandler2_iface);
725 }
726
727 static HRESULT WINAPI DocHostUIHandler_QueryInterface(IDocHostUIHandler2 *iface,
728 REFIID riid, void **ppv)
729 {
730 DocHost *This = impl_from_IDocHostUIHandler2(iface);
731 return IOleClientSite_QueryInterface(&This->IOleClientSite_iface, riid, ppv);
732 }
733
734 static ULONG WINAPI DocHostUIHandler_AddRef(IDocHostUIHandler2 *iface)
735 {
736 DocHost *This = impl_from_IDocHostUIHandler2(iface);
737 return IOleClientSite_AddRef(&This->IOleClientSite_iface);
738 }
739
740 static ULONG WINAPI DocHostUIHandler_Release(IDocHostUIHandler2 *iface)
741 {
742 DocHost *This = impl_from_IDocHostUIHandler2(iface);
743 return IOleClientSite_Release(&This->IOleClientSite_iface);
744 }
745
746 static HRESULT WINAPI DocHostUIHandler_ShowContextMenu(IDocHostUIHandler2 *iface,
747 DWORD dwID, POINT *ppt, IUnknown *pcmdtReserved, IDispatch *pdispReserved)
748 {
749 DocHost *This = impl_from_IDocHostUIHandler2(iface);
750 HRESULT hres;
751
752 TRACE("(%p)->(%d %p %p %p)\n", This, dwID, ppt, pcmdtReserved, pdispReserved);
753
754 if(This->hostui) {
755 hres = IDocHostUIHandler_ShowContextMenu(This->hostui, dwID, ppt, pcmdtReserved,
756 pdispReserved);
757 if(hres == S_OK)
758 return S_OK;
759 }
760
761 FIXME("default action not implemented\n");
762 return E_NOTIMPL;
763 }
764
765 static HRESULT WINAPI DocHostUIHandler_GetHostInfo(IDocHostUIHandler2 *iface,
766 DOCHOSTUIINFO *pInfo)
767 {
768 DocHost *This = impl_from_IDocHostUIHandler2(iface);
769 HRESULT hres;
770
771 TRACE("(%p)->(%p)\n", This, pInfo);
772
773 if(This->hostui) {
774 hres = IDocHostUIHandler_GetHostInfo(This->hostui, pInfo);
775 if(SUCCEEDED(hres))
776 return hres;
777 }
778
779 pInfo->dwFlags = DOCHOSTUIFLAG_DISABLE_HELP_MENU | DOCHOSTUIFLAG_OPENNEWWIN
780 | DOCHOSTUIFLAG_URL_ENCODING_ENABLE_UTF8 | DOCHOSTUIFLAG_ENABLE_INPLACE_NAVIGATION
781 | DOCHOSTUIFLAG_IME_ENABLE_RECONVERSION;
782 return S_OK;
783 }
784
785 static HRESULT WINAPI DocHostUIHandler_ShowUI(IDocHostUIHandler2 *iface, DWORD dwID,
786 IOleInPlaceActiveObject *pActiveObject, IOleCommandTarget *pCommandTarget,
787 IOleInPlaceFrame *pFrame, IOleInPlaceUIWindow *pDoc)
788 {
789 DocHost *This = impl_from_IDocHostUIHandler2(iface);
790 FIXME("(%p)->(%d %p %p %p %p)\n", This, dwID, pActiveObject, pCommandTarget,
791 pFrame, pDoc);
792 return E_NOTIMPL;
793 }
794
795 static HRESULT WINAPI DocHostUIHandler_HideUI(IDocHostUIHandler2 *iface)
796 {
797 DocHost *This = impl_from_IDocHostUIHandler2(iface);
798 FIXME("(%p)\n", This);
799 return E_NOTIMPL;
800 }
801
802 static HRESULT WINAPI DocHostUIHandler_UpdateUI(IDocHostUIHandler2 *iface)
803 {
804 DocHost *This = impl_from_IDocHostUIHandler2(iface);
805
806 TRACE("(%p)\n", This);
807
808 if(!This->hostui)
809 return S_FALSE;
810
811 return IDocHostUIHandler_UpdateUI(This->hostui);
812 }
813
814 static HRESULT WINAPI DocHostUIHandler_EnableModeless(IDocHostUIHandler2 *iface,
815 BOOL fEnable)
816 {
817 DocHost *This = impl_from_IDocHostUIHandler2(iface);
818 FIXME("(%p)->(%x)\n", This, fEnable);
819 return E_NOTIMPL;
820 }
821
822 static HRESULT WINAPI DocHostUIHandler_OnDocWindowActivate(IDocHostUIHandler2 *iface,
823 BOOL fActivate)
824 {
825 DocHost *This = impl_from_IDocHostUIHandler2(iface);
826 FIXME("(%p)->(%x)\n", This, fActivate);
827 return E_NOTIMPL;
828 }
829
830 static HRESULT WINAPI DocHostUIHandler_OnFrameWindowActivate(IDocHostUIHandler2 *iface,
831 BOOL fActivate)
832 {
833 DocHost *This = impl_from_IDocHostUIHandler2(iface);
834 FIXME("(%p)->(%x)\n", This, fActivate);
835 return E_NOTIMPL;
836 }
837
838 static HRESULT WINAPI DocHostUIHandler_ResizeBorder(IDocHostUIHandler2 *iface,
839 LPCRECT prcBorder, IOleInPlaceUIWindow *pUIWindow, BOOL fRameWindow)
840 {
841 DocHost *This = impl_from_IDocHostUIHandler2(iface);
842 FIXME("(%p)->(%p %p %X)\n", This, prcBorder, pUIWindow, fRameWindow);
843 return E_NOTIMPL;
844 }
845
846 static HRESULT WINAPI DocHostUIHandler_TranslateAccelerator(IDocHostUIHandler2 *iface,
847 LPMSG lpMsg, const GUID *pguidCmdGroup, DWORD nCmdID)
848 {
849 DocHost *This = impl_from_IDocHostUIHandler2(iface);
850 HRESULT hr = S_FALSE;
851 TRACE("(%p)->(%p %p %d)\n", This, lpMsg, pguidCmdGroup, nCmdID);
852
853 if(This->hostui)
854 hr = IDocHostUIHandler_TranslateAccelerator(This->hostui, lpMsg, pguidCmdGroup, nCmdID);
855
856 return hr;
857 }
858
859 static HRESULT WINAPI DocHostUIHandler_GetOptionKeyPath(IDocHostUIHandler2 *iface,
860 LPOLESTR *pchKey, DWORD dw)
861 {
862 DocHost *This = impl_from_IDocHostUIHandler2(iface);
863
864 TRACE("(%p)->(%p %d)\n", This, pchKey, dw);
865
866 if(This->hostui)
867 return IDocHostUIHandler_GetOptionKeyPath(This->hostui, pchKey, dw);
868
869 return S_OK;
870 }
871
872 static HRESULT WINAPI DocHostUIHandler_GetDropTarget(IDocHostUIHandler2 *iface,
873 IDropTarget *pDropTarget, IDropTarget **ppDropTarget)
874 {
875 DocHost *This = impl_from_IDocHostUIHandler2(iface);
876 FIXME("(%p)\n", This);
877 return E_NOTIMPL;
878 }
879
880 static HRESULT WINAPI DocHostUIHandler_GetExternal(IDocHostUIHandler2 *iface,
881 IDispatch **ppDispatch)
882 {
883 DocHost *This = impl_from_IDocHostUIHandler2(iface);
884
885 TRACE("(%p)->(%p)\n", This, ppDispatch);
886
887 if(This->hostui)
888 return IDocHostUIHandler_GetExternal(This->hostui, ppDispatch);
889
890 if(!This->shell_ui_helper) {
891 HRESULT hres;
892
893 hres = create_shell_ui_helper(&This->shell_ui_helper);
894 if(FAILED(hres))
895 return hres;
896 }
897
898 *ppDispatch = (IDispatch*)This->shell_ui_helper;
899 IDispatch_AddRef(*ppDispatch);
900 return S_OK;
901 }
902
903 static HRESULT WINAPI DocHostUIHandler_TranslateUrl(IDocHostUIHandler2 *iface,
904 DWORD dwTranslate, OLECHAR *pchURLIn, OLECHAR **ppchURLOut)
905 {
906 DocHost *This = impl_from_IDocHostUIHandler2(iface);
907
908 TRACE("(%p)->(%d %s %p)\n", This, dwTranslate, debugstr_w(pchURLIn), ppchURLOut);
909
910 if(This->hostui)
911 return IDocHostUIHandler_TranslateUrl(This->hostui, dwTranslate,
912 pchURLIn, ppchURLOut);
913
914 return S_FALSE;
915 }
916
917 static HRESULT WINAPI DocHostUIHandler_FilterDataObject(IDocHostUIHandler2 *iface,
918 IDataObject *pDO, IDataObject **ppDORet)
919 {
920 DocHost *This = impl_from_IDocHostUIHandler2(iface);
921 FIXME("(%p)->(%p %p)\n", This, pDO, ppDORet);
922 return E_NOTIMPL;
923 }
924
925 static HRESULT WINAPI DocHostUIHandler_GetOverrideKeyPath(IDocHostUIHandler2 *iface,
926 LPOLESTR *pchKey, DWORD dw)
927 {
928 DocHost *This = impl_from_IDocHostUIHandler2(iface);
929 IDocHostUIHandler2 *handler;
930 HRESULT hres;
931
932 TRACE("(%p)->(%p %d)\n", This, pchKey, dw);
933
934 if(!This->hostui)
935 return S_OK;
936
937 hres = IDocHostUIHandler_QueryInterface(This->hostui, &IID_IDocHostUIHandler2,
938 (void**)&handler);
939 if(SUCCEEDED(hres)) {
940 hres = IDocHostUIHandler2_GetOverrideKeyPath(handler, pchKey, dw);
941 IDocHostUIHandler2_Release(handler);
942 return hres;
943 }
944
945 return S_OK;
946 }
947
948 static const IDocHostUIHandler2Vtbl DocHostUIHandler2Vtbl = {
949 DocHostUIHandler_QueryInterface,
950 DocHostUIHandler_AddRef,
951 DocHostUIHandler_Release,
952 DocHostUIHandler_ShowContextMenu,
953 DocHostUIHandler_GetHostInfo,
954 DocHostUIHandler_ShowUI,
955 DocHostUIHandler_HideUI,
956 DocHostUIHandler_UpdateUI,
957 DocHostUIHandler_EnableModeless,
958 DocHostUIHandler_OnDocWindowActivate,
959 DocHostUIHandler_OnFrameWindowActivate,
960 DocHostUIHandler_ResizeBorder,
961 DocHostUIHandler_TranslateAccelerator,
962 DocHostUIHandler_GetOptionKeyPath,
963 DocHostUIHandler_GetDropTarget,
964 DocHostUIHandler_GetExternal,
965 DocHostUIHandler_TranslateUrl,
966 DocHostUIHandler_FilterDataObject,
967 DocHostUIHandler_GetOverrideKeyPath
968 };
969
970 static inline DocHost *impl_from_IPropertyNotifySink(IPropertyNotifySink *iface)
971 {
972 return CONTAINING_RECORD(iface, DocHost, IPropertyNotifySink_iface);
973 }
974
975 static HRESULT WINAPI PropertyNotifySink_QueryInterface(IPropertyNotifySink *iface,
976 REFIID riid, void **ppv)
977 {
978 DocHost *This = impl_from_IPropertyNotifySink(iface);
979 return IOleClientSite_QueryInterface(&This->IOleClientSite_iface, riid, ppv);
980 }
981
982 static ULONG WINAPI PropertyNotifySink_AddRef(IPropertyNotifySink *iface)
983 {
984 DocHost *This = impl_from_IPropertyNotifySink(iface);
985 return IOleClientSite_AddRef(&This->IOleClientSite_iface);
986 }
987
988 static ULONG WINAPI PropertyNotifySink_Release(IPropertyNotifySink *iface)
989 {
990 DocHost *This = impl_from_IPropertyNotifySink(iface);
991 return IOleClientSite_Release(&This->IOleClientSite_iface);
992 }
993
994 static HRESULT WINAPI PropertyNotifySink_OnChanged(IPropertyNotifySink *iface, DISPID dispID)
995 {
996 DocHost *This = impl_from_IPropertyNotifySink(iface);
997
998 TRACE("(%p)->(%d)\n", This, dispID);
999
1000 switch(dispID) {
1001 case DISPID_READYSTATE: {
1002 READYSTATE ready_state;
1003 HRESULT hres;
1004
1005 hres = get_doc_ready_state(This, &ready_state);
1006 if(FAILED(hres))
1007 return hres;
1008
1009 if(ready_state == READYSTATE_COMPLETE && !This->doc_navigate)
1010 advise_prop_notif(This, FALSE);
1011
1012 update_ready_state(This, ready_state);
1013 break;
1014 }
1015 default:
1016 FIXME("unimplemented dispid %d\n", dispID);
1017 return E_NOTIMPL;
1018 }
1019
1020 return S_OK;
1021 }
1022
1023 static HRESULT WINAPI PropertyNotifySink_OnRequestEdit(IPropertyNotifySink *iface, DISPID dispID)
1024 {
1025 DocHost *This = impl_from_IPropertyNotifySink(iface);
1026 FIXME("(%p)->(%d)\n", This, dispID);
1027 return E_NOTIMPL;
1028 }
1029
1030 static const IPropertyNotifySinkVtbl PropertyNotifySinkVtbl = {
1031 PropertyNotifySink_QueryInterface,
1032 PropertyNotifySink_AddRef,
1033 PropertyNotifySink_Release,
1034 PropertyNotifySink_OnChanged,
1035 PropertyNotifySink_OnRequestEdit
1036 };
1037
1038 void DocHost_Init(DocHost *This, IWebBrowser2 *wb, const IDocHostContainerVtbl* container)
1039 {
1040 This->IDocHostUIHandler2_iface.lpVtbl = &DocHostUIHandler2Vtbl;
1041 This->IOleCommandTarget_iface.lpVtbl = &OleCommandTargetVtbl;
1042 This->IPropertyNotifySink_iface.lpVtbl = &PropertyNotifySinkVtbl;
1043
1044 This->wb = wb;
1045 This->container_vtbl = container;
1046
1047 This->ready_state = READYSTATE_UNINITIALIZED;
1048 list_init(&This->task_queue);
1049
1050 This->travellog.loading_pos = -1;
1051
1052 DocHost_ClientSite_Init(This);
1053 DocHost_Frame_Init(This);
1054
1055 ConnectionPointContainer_Init(&This->cps, (IUnknown*)wb);
1056 IEHTMLWindow_Init(This);
1057 NewWindowManager_Init(This);
1058 }
1059
1060 void DocHost_Release(DocHost *This)
1061 {
1062 if(This->shell_ui_helper)
1063 IShellUIHelper2_Release(This->shell_ui_helper);
1064
1065 abort_dochost_tasks(This, NULL);
1066 release_dochost_client(This);
1067 DocHost_ClientSite_Release(This);
1068
1069 ConnectionPointContainer_Destroy(&This->cps);
1070
1071 while(This->travellog.length)
1072 free_travellog_entry(This->travellog.log + --This->travellog.length);
1073 heap_free(This->travellog.log);
1074
1075 heap_free(This->url);
1076 }