user32/tests: Disable IME for msg tests.
[wine] / dlls / shdocvw / navigate.c
1 /*
2  * Copyright 2006-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 #define NONAMELESSUNION
20 #define NONAMELESSSTRUCT
21
22 #include "wine/debug.h"
23
24 #include "shdocvw.h"
25 #include "exdispid.h"
26 #include "shellapi.h"
27 #include "winreg.h"
28 #include "shlwapi.h"
29 #include "wininet.h"
30 #include "mshtml.h"
31
32 WINE_DEFAULT_DEBUG_CHANNEL(shdocvw);
33
34 static const WCHAR emptyW[] = {0};
35
36 typedef struct {
37     IBindStatusCallback  IBindStatusCallback_iface;
38     IHttpNegotiate       IHttpNegotiate_iface;
39
40     LONG ref;
41
42     DocHost *doc_host;
43
44     LPWSTR url;
45     HGLOBAL post_data;
46     BSTR headers;
47     ULONG post_data_len;
48 } BindStatusCallback;
49
50 static void dump_BINDINFO(BINDINFO *bi)
51 {
52     static const char * const BINDINFOF_str[] = {
53         "#0",
54         "BINDINFOF_URLENCODESTGMEDDATA",
55         "BINDINFOF_URLENCODEDEXTRAINFO"
56     };
57
58     static const char * const BINDVERB_str[] = {
59         "BINDVERB_GET",
60         "BINDVERB_POST",
61         "BINDVERB_PUT",
62         "BINDVERB_CUSTOM"
63     };
64
65     TRACE("\n"
66             "BINDINFO = {\n"
67             "    %d, %s,\n"
68             "    {%d, %p, %p},\n"
69             "    %s,\n"
70             "    %s,\n"
71             "    %s,\n"
72             "    %d, %08x, %d, %d\n"
73             "    {%d %p %x},\n"
74             "    %s\n"
75             "    %p, %d\n"
76             "}\n",
77
78             bi->cbSize, debugstr_w(bi->szExtraInfo),
79             bi->stgmedData.tymed, bi->stgmedData.u.hGlobal, bi->stgmedData.pUnkForRelease,
80             bi->grfBindInfoF > BINDINFOF_URLENCODEDEXTRAINFO
81                 ? "unknown" : BINDINFOF_str[bi->grfBindInfoF],
82             bi->dwBindVerb > BINDVERB_CUSTOM
83                 ? "unknown" : BINDVERB_str[bi->dwBindVerb],
84             debugstr_w(bi->szCustomVerb),
85             bi->cbstgmedData, bi->dwOptions, bi->dwOptionsFlags, bi->dwCodePage,
86             bi->securityAttributes.nLength,
87             bi->securityAttributes.lpSecurityDescriptor,
88             bi->securityAttributes.bInheritHandle,
89             debugstr_guid(&bi->iid),
90             bi->pUnk, bi->dwReserved
91             );
92 }
93
94 static void set_status_text(BindStatusCallback *This, LPCWSTR str)
95 {
96     VARIANTARG arg;
97     DISPPARAMS dispparams = {&arg, NULL, 1, 0};
98
99     if(!This->doc_host)
100         return;
101
102     V_VT(&arg) = VT_BSTR;
103     V_BSTR(&arg) = str ? SysAllocString(str) : NULL;
104     call_sink(This->doc_host->cps.wbe2, DISPID_STATUSTEXTCHANGE, &dispparams);
105     VariantClear(&arg);
106
107     if(This->doc_host->frame)
108         IOleInPlaceFrame_SetStatusText(This->doc_host->frame, str);
109 }
110
111 static HRESULT set_dochost_url(DocHost *This, const WCHAR *url)
112 {
113     WCHAR *new_url;
114
115     if(url) {
116         new_url = heap_strdupW(url);
117         if(!new_url)
118             return E_OUTOFMEMORY;
119     }else {
120         new_url = NULL;
121     }
122
123     heap_free(This->url);
124     This->url = new_url;
125
126     This->container_vtbl->SetURL(This, This->url);
127     return S_OK;
128 }
129
130 static inline BindStatusCallback *impl_from_IBindStatusCallback(IBindStatusCallback *iface)
131 {
132     return CONTAINING_RECORD(iface, BindStatusCallback, IBindStatusCallback_iface);
133 }
134
135 static HRESULT WINAPI BindStatusCallback_QueryInterface(IBindStatusCallback *iface,
136                                                         REFIID riid, void **ppv)
137 {
138     BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
139
140     if(IsEqualGUID(&IID_IUnknown, riid)) {
141         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
142         *ppv = &This->IBindStatusCallback_iface;
143     }else if(IsEqualGUID(&IID_IBindStatusCallback, riid)) {
144         TRACE("(%p)->(IID_IBindStatusCallback %p)\n", This, ppv);
145         *ppv = &This->IBindStatusCallback_iface;
146     }else if(IsEqualGUID(&IID_IHttpNegotiate, riid)) {
147         TRACE("(%p)->(IID_IHttpNegotiate %p)\n", This, ppv);
148         *ppv = &This->IHttpNegotiate_iface;
149     }else {
150         *ppv = NULL;
151         WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
152         return E_NOINTERFACE;
153     }
154
155     IUnknown_AddRef((IUnknown*)*ppv);
156     return S_OK;
157 }
158
159 static ULONG WINAPI BindStatusCallback_AddRef(IBindStatusCallback *iface)
160 {
161     BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
162     LONG ref = InterlockedIncrement(&This->ref);
163
164     TRACE("(%p) ref=%d\n", This, ref);
165
166     return ref;
167 }
168
169 static ULONG WINAPI BindStatusCallback_Release(IBindStatusCallback *iface)
170 {
171     BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
172     LONG ref = InterlockedDecrement(&This->ref);
173
174     TRACE("(%p) ref=%d\n", This, ref);
175
176     if(!ref) {
177         if(This->doc_host)
178             IOleClientSite_Release(&This->doc_host->IOleClientSite_iface);
179         if(This->post_data)
180             GlobalFree(This->post_data);
181         SysFreeString(This->headers);
182         heap_free(This->url);
183         heap_free(This);
184     }
185
186     return ref;
187 }
188
189 static HRESULT WINAPI BindStatusCallback_OnStartBinding(IBindStatusCallback *iface,
190        DWORD dwReserved, IBinding *pbind)
191 {
192     BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
193
194     TRACE("(%p)->(%d %p)\n", This, dwReserved, pbind);
195
196     return S_OK;
197 }
198
199 static HRESULT WINAPI BindStatusCallback_GetPriority(IBindStatusCallback *iface,
200        LONG *pnPriority)
201 {
202     BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
203     FIXME("(%p)->(%p)\n", This, pnPriority);
204     return E_NOTIMPL;
205 }
206
207 static HRESULT WINAPI BindStatusCallback_OnLowResource(IBindStatusCallback *iface,
208        DWORD reserved)
209 {
210     BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
211     FIXME("(%p)->(%d)\n", This, reserved);
212     return E_NOTIMPL;
213 }
214
215 static HRESULT WINAPI BindStatusCallback_OnProgress(IBindStatusCallback *iface,
216         ULONG ulProgress, ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText)
217 {
218     BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
219
220     TRACE("(%p)->(%d %d %d %s)\n", This, ulProgress, ulProgressMax, ulStatusCode,
221           debugstr_w(szStatusText));
222
223     switch(ulStatusCode) {
224     case BINDSTATUS_REDIRECTING:
225         return set_dochost_url(This->doc_host, szStatusText);
226     case BINDSTATUS_BEGINDOWNLOADDATA:
227         set_status_text(This, szStatusText); /* FIXME: "Start downloading from site: %s" */
228         return S_OK;
229     case BINDSTATUS_ENDDOWNLOADDATA:
230         set_status_text(This, szStatusText); /* FIXME: "Downloading from site: %s" */
231         return S_OK;
232     case BINDSTATUS_CLASSIDAVAILABLE:
233     case BINDSTATUS_MIMETYPEAVAILABLE:
234     case BINDSTATUS_BEGINSYNCOPERATION:
235     case BINDSTATUS_ENDSYNCOPERATION:
236         return S_OK;
237     default:
238         FIXME("status code %u\n", ulStatusCode);
239     }
240
241     return S_OK;
242 }
243
244 static HRESULT WINAPI BindStatusCallback_OnStopBinding(IBindStatusCallback *iface,
245         HRESULT hresult, LPCWSTR szError)
246 {
247     BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
248
249     TRACE("(%p)->(%08x %s)\n", This, hresult, debugstr_w(szError));
250
251     set_status_text(This, emptyW);
252
253     if(This->doc_host) {
254         IOleClientSite_Release(&This->doc_host->IOleClientSite_iface);
255         This->doc_host = NULL;
256     }
257
258     return S_OK;
259 }
260
261 static HRESULT WINAPI BindStatusCallback_GetBindInfo(IBindStatusCallback *iface,
262         DWORD *grfBINDF, BINDINFO *pbindinfo)
263 {
264     BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
265
266     TRACE("(%p)->(%p %p)\n", This, grfBINDF, pbindinfo);
267
268     *grfBINDF = BINDF_ASYNCHRONOUS;
269
270     if(This->post_data) {
271         pbindinfo->dwBindVerb = BINDVERB_POST;
272
273         pbindinfo->stgmedData.tymed = TYMED_HGLOBAL;
274         pbindinfo->stgmedData.u.hGlobal = This->post_data;
275         pbindinfo->cbstgmedData = This->post_data_len;
276         pbindinfo->stgmedData.pUnkForRelease = (IUnknown*)&This->IBindStatusCallback_iface;
277         IBindStatusCallback_AddRef(&This->IBindStatusCallback_iface);
278     }
279
280     return S_OK;
281 }
282
283 static HRESULT WINAPI BindStatusCallback_OnDataAvailable(IBindStatusCallback *iface,
284         DWORD grfBSCF, DWORD dwSize, FORMATETC *pformatetc, STGMEDIUM *pstgmed)
285 {
286     BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
287     FIXME("(%p)->(%08x %d %p %p)\n", This, grfBSCF, dwSize, pformatetc, pstgmed);
288     return E_NOTIMPL;
289 }
290
291 static HRESULT WINAPI BindStatusCallback_OnObjectAvailable(IBindStatusCallback *iface,
292         REFIID riid, IUnknown *punk)
293 {
294     BindStatusCallback *This = impl_from_IBindStatusCallback(iface);
295
296     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), punk);
297
298     return dochost_object_available(This->doc_host, punk);
299 }
300
301 static const IBindStatusCallbackVtbl BindStatusCallbackVtbl = {
302     BindStatusCallback_QueryInterface,
303     BindStatusCallback_AddRef,
304     BindStatusCallback_Release,
305     BindStatusCallback_OnStartBinding,
306     BindStatusCallback_GetPriority,
307     BindStatusCallback_OnLowResource,
308     BindStatusCallback_OnProgress,
309     BindStatusCallback_OnStopBinding,
310     BindStatusCallback_GetBindInfo,
311     BindStatusCallback_OnDataAvailable,
312     BindStatusCallback_OnObjectAvailable
313 };
314
315 static inline BindStatusCallback *impl_from_IHttpNegotiate(IHttpNegotiate *iface)
316 {
317     return CONTAINING_RECORD(iface, BindStatusCallback, IHttpNegotiate_iface);
318 }
319
320 static HRESULT WINAPI HttpNegotiate_QueryInterface(IHttpNegotiate *iface,
321                                                    REFIID riid, void **ppv)
322 {
323     BindStatusCallback *This = impl_from_IHttpNegotiate(iface);
324     return IBindStatusCallback_QueryInterface(&This->IBindStatusCallback_iface, riid, ppv);
325 }
326
327 static ULONG WINAPI HttpNegotiate_AddRef(IHttpNegotiate *iface)
328 {
329     BindStatusCallback *This = impl_from_IHttpNegotiate(iface);
330     return IBindStatusCallback_AddRef(&This->IBindStatusCallback_iface);
331 }
332
333 static ULONG WINAPI HttpNegotiate_Release(IHttpNegotiate *iface)
334 {
335     BindStatusCallback *This = impl_from_IHttpNegotiate(iface);
336     return IBindStatusCallback_Release(&This->IBindStatusCallback_iface);
337 }
338
339 static HRESULT WINAPI HttpNegotiate_BeginningTransaction(IHttpNegotiate *iface,
340         LPCWSTR szURL, LPCWSTR szHeaders, DWORD dwReserved, LPWSTR *pszAdditionalHeaders)
341 {
342     BindStatusCallback *This = impl_from_IHttpNegotiate(iface);
343
344     TRACE("(%p)->(%s %s %d %p)\n", This, debugstr_w(szURL), debugstr_w(szHeaders),
345           dwReserved, pszAdditionalHeaders);
346
347     if(This->headers) {
348         int size = (strlenW(This->headers)+1)*sizeof(WCHAR);
349         *pszAdditionalHeaders = CoTaskMemAlloc(size);
350         memcpy(*pszAdditionalHeaders, This->headers, size);
351     }
352
353     return S_OK;
354 }
355
356 static HRESULT WINAPI HttpNegotiate_OnResponse(IHttpNegotiate *iface,
357         DWORD dwResponseCode, LPCWSTR szResponseHeaders, LPCWSTR szRequestHeaders,
358         LPWSTR *pszAdditionalRequestHeaders)
359 {
360     BindStatusCallback *This = impl_from_IHttpNegotiate(iface);
361     TRACE("(%p)->(%d %s %s %p)\n", This, dwResponseCode, debugstr_w(szResponseHeaders),
362           debugstr_w(szRequestHeaders), pszAdditionalRequestHeaders);
363     return S_OK;
364 }
365
366 static const IHttpNegotiateVtbl HttpNegotiateVtbl = {
367     HttpNegotiate_QueryInterface,
368     HttpNegotiate_AddRef,
369     HttpNegotiate_Release,
370     HttpNegotiate_BeginningTransaction,
371     HttpNegotiate_OnResponse
372 };
373
374 static BindStatusCallback *create_callback(DocHost *doc_host, LPCWSTR url, PBYTE post_data,
375         ULONG post_data_len, LPCWSTR headers)
376 {
377     BindStatusCallback *ret = heap_alloc(sizeof(BindStatusCallback));
378
379     ret->IBindStatusCallback_iface.lpVtbl = &BindStatusCallbackVtbl;
380     ret->IHttpNegotiate_iface.lpVtbl      = &HttpNegotiateVtbl;
381
382     ret->ref = 1;
383     ret->url = heap_strdupW(url);
384     ret->post_data = NULL;
385     ret->post_data_len = post_data_len;
386     ret->headers = headers ? SysAllocString(headers) : NULL;
387
388     ret->doc_host = doc_host;
389     IOleClientSite_AddRef(&doc_host->IOleClientSite_iface);
390
391     if(post_data) {
392         ret->post_data = GlobalAlloc(0, post_data_len);
393         memcpy(ret->post_data, post_data, post_data_len);
394     }
395
396     return ret;
397 }
398
399 static void on_before_navigate2(DocHost *This, LPCWSTR url, SAFEARRAY *post_data, LPWSTR headers, VARIANT_BOOL *cancel)
400 {
401     VARIANT var_url, var_flags, var_frame_name, var_post_data, var_post_data2, var_headers;
402     DISPPARAMS dispparams;
403     VARIANTARG params[7];
404
405     dispparams.cArgs = 7;
406     dispparams.cNamedArgs = 0;
407     dispparams.rgdispidNamedArgs = NULL;
408     dispparams.rgvarg = params;
409
410     This->busy = VARIANT_TRUE;
411
412     V_VT(params) = VT_BOOL|VT_BYREF;
413     V_BOOLREF(params) = cancel;
414
415     V_VT(params+1) = (VT_BYREF|VT_VARIANT);
416     V_VARIANTREF(params+1) = &var_headers;
417     V_VT(&var_headers) = VT_BSTR;
418     V_BSTR(&var_headers) = headers;
419
420     V_VT(params+2) = (VT_BYREF|VT_VARIANT);
421     V_VARIANTREF(params+2) = &var_post_data2;
422     V_VT(&var_post_data2) = (VT_BYREF|VT_VARIANT);
423     V_VARIANTREF(&var_post_data2) = &var_post_data;
424
425     if(post_data) {
426         V_VT(&var_post_data) = VT_UI1|VT_ARRAY;
427         V_ARRAY(&var_post_data) = post_data;
428     }else {
429         V_VT(&var_post_data) = VT_EMPTY;
430     }
431
432     V_VT(params+3) = (VT_BYREF|VT_VARIANT);
433     V_VARIANTREF(params+3) = &var_frame_name;
434     V_VT(&var_frame_name) = VT_BSTR;
435     V_BSTR(&var_frame_name) = NULL;
436
437     V_VT(params+4) = (VT_BYREF|VT_VARIANT);
438     V_VARIANTREF(params+4) = &var_flags;
439     V_VT(&var_flags) = VT_I4;
440     V_I4(&var_flags) = 0;
441
442     V_VT(params+5) = (VT_BYREF|VT_VARIANT);
443     V_VARIANTREF(params+5) = &var_url;
444     V_VT(&var_url) = VT_BSTR;
445     V_BSTR(&var_url) = SysAllocString(url);
446
447     V_VT(params+6) = (VT_DISPATCH);
448     V_DISPATCH(params+6) = This->disp;
449
450     call_sink(This->cps.wbe2, DISPID_BEFORENAVIGATE2, &dispparams);
451
452     SysFreeString(V_BSTR(&var_url));
453 }
454
455 /* FIXME: urlmon should handle it */
456 static BOOL try_application_url(LPCWSTR url)
457 {
458     SHELLEXECUTEINFOW exec_info;
459     WCHAR app[64];
460     HKEY hkey;
461     DWORD res, type;
462     HRESULT hres;
463
464     static const WCHAR wszURLProtocol[] = {'U','R','L',' ','P','r','o','t','o','c','o','l',0};
465
466     hres = CoInternetParseUrl(url, PARSE_SCHEMA, 0, app, sizeof(app)/sizeof(WCHAR), NULL, 0);
467     if(FAILED(hres))
468         return FALSE;
469
470     res = RegOpenKeyW(HKEY_CLASSES_ROOT, app, &hkey);
471     if(res != ERROR_SUCCESS)
472         return FALSE;
473
474     res = RegQueryValueExW(hkey, wszURLProtocol, NULL, &type, NULL, NULL);
475     RegCloseKey(hkey);
476     if(res != ERROR_SUCCESS || type != REG_SZ)
477         return FALSE;
478
479     TRACE("openning application %s\n", debugstr_w(app));
480  
481     memset(&exec_info, 0, sizeof(exec_info));
482     exec_info.cbSize = sizeof(exec_info);
483     exec_info.lpFile = url;
484     exec_info.nShow = SW_SHOW;
485
486     return ShellExecuteExW(&exec_info);
487 }
488
489 static HRESULT create_moniker(LPCWSTR url, IMoniker **mon)
490 {
491     WCHAR new_url[INTERNET_MAX_URL_LENGTH];
492     DWORD size;
493     HRESULT hres;
494
495     if(PathIsURLW(url))
496         return CreateURLMoniker(NULL, url, mon);
497
498     if(url[1] == ':') {
499         size = sizeof(new_url);
500         hres = UrlCreateFromPathW(url, new_url, &size, 0);
501         if(FAILED(hres)) {
502             WARN("UrlCreateFromPathW failed: %08x\n", hres);
503             return hres;
504         }
505     }else {
506         size = sizeof(new_url)/sizeof(WCHAR);
507         hres = UrlApplySchemeW(url, new_url, &size, URL_APPLY_GUESSSCHEME);
508         TRACE("got %s\n", debugstr_w(new_url));
509         if(FAILED(hres)) {
510             WARN("UrlApplyScheme failed: %08x\n", hres);
511             return hres;
512         }
513     }
514
515     return CreateURLMoniker(NULL, new_url, mon);
516 }
517
518 static HRESULT bind_to_object(DocHost *This, IMoniker *mon, LPCWSTR url, IBindCtx *bindctx,
519                               IBindStatusCallback *callback)
520 {
521     IUnknown *unk = NULL;
522     WCHAR *display_name;
523     HRESULT hres;
524
525     if(mon) {
526         IMoniker_AddRef(mon);
527     }else {
528         hres = create_moniker(url, &mon);
529         if(FAILED(hres))
530             return hres;
531     }
532
533     hres = IMoniker_GetDisplayName(mon, 0, NULL, &display_name);
534     if(FAILED(hres)) {
535         FIXME("GetDisplayName failed: %08x\n", hres);
536         return hres;
537     }
538
539     hres = set_dochost_url(This, display_name);
540     CoTaskMemFree(display_name);
541     if(FAILED(hres))
542         return hres;
543
544     IBindCtx_RegisterObjectParam(bindctx, (LPOLESTR)SZ_HTML_CLIENTSITE_OBJECTPARAM,
545                                  (IUnknown*)&This->IOleClientSite_iface);
546
547     hres = IMoniker_BindToObject(mon, bindctx, NULL, &IID_IUnknown, (void**)&unk);
548     if(SUCCEEDED(hres)) {
549         hres = S_OK;
550         if(unk)
551             IUnknown_Release(unk);
552     }else if(try_application_url(url)) {
553         hres = S_OK;
554     }else {
555         FIXME("BindToObject failed: %08x\n", hres);
556     }
557
558     IMoniker_Release(mon);
559     return S_OK;
560 }
561
562 static void html_window_navigate(DocHost *This, IHTMLPrivateWindow *window, BSTR url, BSTR headers, SAFEARRAY *post_data)
563 {
564     VARIANT headers_var, post_data_var;
565     BSTR empty_str;
566     HRESULT hres;
567
568     hres = set_dochost_url(This, url);
569     if(FAILED(hres))
570         return;
571
572     empty_str = SysAllocStringLen(NULL, 0);
573
574     if(headers) {
575         V_VT(&headers_var) = VT_BSTR;
576         V_BSTR(&headers_var) = headers;
577     }else {
578         V_VT(&headers_var) = VT_EMPTY;
579     }
580
581     if(post_data) {
582         V_VT(&post_data_var) = VT_UI1|VT_ARRAY;
583         V_ARRAY(&post_data_var) = post_data;
584     }else {
585         V_VT(&post_data_var) = VT_EMPTY;
586     }
587
588     set_doc_state(This, READYSTATE_LOADING);
589     hres = IHTMLPrivateWindow_SuperNavigate(window, url, empty_str, NULL, NULL, &post_data_var, &headers_var, 0);
590     SysFreeString(empty_str);
591     if(FAILED(hres))
592         WARN("SuprtNavigate failed: %08x\n", hres);
593 }
594
595 typedef struct {
596     task_header_t header;
597     BSTR url;
598     BSTR headers;
599     SAFEARRAY *post_data;
600     BOOL async_notif;
601 } task_doc_navigate_t;
602
603 static HRESULT free_doc_navigate_task(task_doc_navigate_t *task, BOOL free_task)
604 {
605     SysFreeString(task->url);
606     SysFreeString(task->headers);
607     if(task->post_data)
608         SafeArrayDestroy(task->post_data);
609     if(free_task)
610         heap_free(task);
611     return E_OUTOFMEMORY;
612 }
613
614 static void doc_navigate_proc(DocHost *This, task_header_t *t)
615 {
616     task_doc_navigate_t *task = (task_doc_navigate_t*)t;
617     IHTMLPrivateWindow *priv_window;
618     HRESULT hres;
619
620     if(!This->doc_navigate)
621         return;
622
623     if(task->async_notif) {
624         VARIANT_BOOL cancel = VARIANT_FALSE;
625         on_before_navigate2(This, task->url, task->post_data, task->headers, &cancel);
626         if(cancel) {
627             TRACE("Navigation calnceled\n");
628             free_doc_navigate_task(task, FALSE);
629             return;
630         }
631     }
632
633     hres = IUnknown_QueryInterface(This->doc_navigate, &IID_IHTMLPrivateWindow, (void**)&priv_window);
634     if(SUCCEEDED(hres)) {
635         html_window_navigate(This, priv_window, task->url, task->headers, task->post_data);
636         IHTMLPrivateWindow_Release(priv_window);
637     }else {
638         WARN("Could not get IHTMLPrivateWindow iface: %08x\n", hres);
639     }
640
641     free_doc_navigate_task(task, FALSE);
642 }
643
644 static HRESULT async_doc_navigate(DocHost *This, LPCWSTR url, LPCWSTR headers, PBYTE post_data, ULONG post_data_size,
645         BOOL async_notif)
646 {
647     task_doc_navigate_t *task;
648
649     task = heap_alloc_zero(sizeof(*task));
650     if(!task)
651         return E_OUTOFMEMORY;
652
653     task->url = SysAllocString(url);
654     if(!task->url)
655         return free_doc_navigate_task(task, TRUE);
656
657     if(headers) {
658         task->headers = SysAllocString(headers);
659         if(!task->headers)
660             return free_doc_navigate_task(task, TRUE);
661     }
662
663     if(post_data) {
664         task->post_data = SafeArrayCreateVector(VT_UI1, 0, post_data_size);
665         if(!task->post_data)
666             return free_doc_navigate_task(task, TRUE);
667         memcpy(task->post_data->pvData, post_data, post_data_size);
668     }
669
670     if(!async_notif) {
671         VARIANT_BOOL cancel = VARIANT_FALSE;
672
673         on_before_navigate2(This, task->url, task->post_data, task->headers, &cancel);
674         if(cancel) {
675             TRACE("Navigation calnceled\n");
676             free_doc_navigate_task(task, TRUE);
677             return S_OK;
678         }
679     }
680
681     task->async_notif = async_notif;
682     push_dochost_task(This, &task->header, doc_navigate_proc, FALSE);
683     return S_OK;
684 }
685
686 static HRESULT navigate_bsc(DocHost *This, BindStatusCallback *bsc, IMoniker *mon)
687 {
688     VARIANT_BOOL cancel = VARIANT_FALSE;
689     SAFEARRAY *post_data = NULL;
690     IBindCtx *bindctx;
691     HRESULT hres;
692
693     set_doc_state(This, READYSTATE_LOADING);
694
695     if(bsc->post_data) {
696         post_data = SafeArrayCreateVector(VT_UI1, 0, bsc->post_data_len);
697         memcpy(post_data->pvData, post_data, bsc->post_data_len);
698     }
699
700     on_before_navigate2(This, bsc->url, post_data, bsc->headers, &cancel);
701     if(post_data)
702         SafeArrayDestroy(post_data);
703     if(cancel) {
704         FIXME("Navigation canceled\n");
705         return S_OK;
706     }
707
708     if(This->document)
709         deactivate_document(This);
710
711     CreateAsyncBindCtx(0, &bsc->IBindStatusCallback_iface, 0, &bindctx);
712
713     if(This->frame)
714         IOleInPlaceFrame_EnableModeless(This->frame, FALSE);
715
716     hres = bind_to_object(This, mon, bsc->url, bindctx, &bsc->IBindStatusCallback_iface);
717
718     if(This->frame)
719         IOleInPlaceFrame_EnableModeless(This->frame, TRUE);
720
721     IBindCtx_Release(bindctx);
722
723     return hres;
724 }
725
726 typedef struct {
727     task_header_t header;
728     BindStatusCallback *bsc;
729 } task_navigate_bsc_t;
730
731 static void navigate_bsc_proc(DocHost *This, task_header_t *t)
732 {
733     task_navigate_bsc_t *task = (task_navigate_bsc_t*)t;
734
735     if(!This->hwnd)
736         create_doc_view_hwnd(This);
737
738     navigate_bsc(This, task->bsc, NULL);
739
740     IBindStatusCallback_Release(&task->bsc->IBindStatusCallback_iface);
741 }
742
743
744 HRESULT navigate_url(DocHost *This, LPCWSTR url, const VARIANT *Flags,
745                      const VARIANT *TargetFrameName, VARIANT *PostData, VARIANT *Headers)
746 {
747     PBYTE post_data = NULL;
748     ULONG post_data_len = 0;
749     LPWSTR headers = NULL;
750     HRESULT hres = S_OK;
751
752     TRACE("navigating to %s\n", debugstr_w(url));
753
754     if((Flags && V_VT(Flags) != VT_EMPTY) 
755        || (TargetFrameName && V_VT(TargetFrameName) != VT_EMPTY))
756         FIXME("Unsupported args (Flags %p:%d; TargetFrameName %p:%d)\n",
757                 Flags, Flags ? V_VT(Flags) : -1, TargetFrameName,
758                 TargetFrameName ? V_VT(TargetFrameName) : -1);
759
760     if(PostData && V_VT(PostData) == (VT_ARRAY | VT_UI1) && V_ARRAY(PostData)) {
761         SafeArrayAccessData(V_ARRAY(PostData), (void**)&post_data);
762         post_data_len = V_ARRAY(PostData)->rgsabound[0].cElements;
763     }
764
765     if(Headers && V_VT(Headers) == VT_BSTR) {
766         headers = V_BSTR(Headers);
767         TRACE("Headers: %s\n", debugstr_w(headers));
768     }
769
770     set_doc_state(This, READYSTATE_LOADING);
771     This->ready_state = READYSTATE_LOADING;
772
773     if(This->doc_navigate) {
774         WCHAR new_url[INTERNET_MAX_URL_LENGTH];
775
776         if(PathIsURLW(url)) {
777             new_url[0] = 0;
778         }else {
779             DWORD size;
780
781             size = sizeof(new_url)/sizeof(WCHAR);
782             hres = UrlApplySchemeW(url, new_url, &size,
783                     URL_APPLY_GUESSSCHEME | URL_APPLY_DEFAULT);
784             if(FAILED(hres)) {
785                 WARN("UrlApplyScheme failed: %08x\n", hres);
786                 new_url[0] = 0;
787             }
788         }
789
790         hres = async_doc_navigate(This, *new_url ? new_url : url, headers, post_data,
791                 post_data_len, TRUE);
792     }else {
793         task_navigate_bsc_t *task;
794
795         task = heap_alloc(sizeof(*task));
796         task->bsc = create_callback(This, url, post_data, post_data_len, headers);
797         push_dochost_task(This, &task->header, navigate_bsc_proc, This->url == NULL);
798     }
799
800     if(post_data)
801         SafeArrayUnaccessData(V_ARRAY(PostData));
802
803     return hres;
804 }
805
806 static HRESULT navigate_hlink(DocHost *This, IMoniker *mon, IBindCtx *bindctx,
807                               IBindStatusCallback *callback)
808 {
809     IHttpNegotiate *http_negotiate;
810     BindStatusCallback *bsc;
811     PBYTE post_data = NULL;
812     ULONG post_data_len = 0;
813     LPWSTR headers = NULL, url;
814     BINDINFO bindinfo;
815     DWORD bindf = 0;
816     HRESULT hres;
817
818     hres = IMoniker_GetDisplayName(mon, 0, NULL, &url);
819     if(FAILED(hres))
820         FIXME("GetDisplayName failed: %08x\n", hres);
821
822     hres = IBindStatusCallback_QueryInterface(callback, &IID_IHttpNegotiate,
823                                               (void**)&http_negotiate);
824     if(SUCCEEDED(hres)) {
825         static const WCHAR null_string[] = {0};
826
827         IHttpNegotiate_BeginningTransaction(http_negotiate, null_string, null_string, 0,
828                                             &headers);
829         IHttpNegotiate_Release(http_negotiate);
830     }
831
832     memset(&bindinfo, 0, sizeof(bindinfo));
833     bindinfo.cbSize = sizeof(bindinfo);
834
835     hres = IBindStatusCallback_GetBindInfo(callback, &bindf, &bindinfo);
836     dump_BINDINFO(&bindinfo);
837     if(bindinfo.dwBindVerb == BINDVERB_POST) {
838         post_data_len = bindinfo.cbstgmedData;
839         if(post_data_len)
840             post_data = bindinfo.stgmedData.u.hGlobal;
841     }
842
843     if(This->doc_navigate) {
844         hres = async_doc_navigate(This, url, headers, post_data, post_data_len, FALSE);
845     }else {
846         bsc = create_callback(This, url, post_data, post_data_len, headers);
847         hres = navigate_bsc(This, bsc, mon);
848         IBindStatusCallback_Release(&bsc->IBindStatusCallback_iface);
849     }
850
851     CoTaskMemFree(url);
852     CoTaskMemFree(headers);
853     ReleaseBindInfo(&bindinfo);
854
855     return hres;
856 }
857
858 HRESULT go_home(DocHost *This)
859 {
860     HKEY hkey;
861     DWORD res, type, size;
862     WCHAR wszPageName[MAX_PATH];
863     static const WCHAR wszAboutBlank[] = {'a','b','o','u','t',':','b','l','a','n','k',0};
864     static const WCHAR wszStartPage[] = {'S','t','a','r','t',' ','P','a','g','e',0};
865     static const WCHAR wszSubKey[] = {'S','o','f','t','w','a','r','e','\\',
866                                       'M','i','c','r','o','s','o','f','t','\\',
867                                       'I','n','t','e','r','n','e','t',' ','E','x','p','l','o','r','e','r','\\',
868                                       'M','a','i','n',0};
869
870     res = RegOpenKeyW(HKEY_CURRENT_USER, wszSubKey, &hkey);
871     if (res != ERROR_SUCCESS)
872         return navigate_url(This, wszAboutBlank, NULL, NULL, NULL, NULL);
873
874     size = sizeof(wszPageName);
875     res = RegQueryValueExW(hkey, wszStartPage, NULL, &type, (LPBYTE)wszPageName, &size);
876     RegCloseKey(hkey);
877     if (res != ERROR_SUCCESS || type != REG_SZ)
878         return navigate_url(This, wszAboutBlank, NULL, NULL, NULL, NULL);
879
880     return navigate_url(This, wszPageName, NULL, NULL, NULL, NULL);
881 }
882
883 static inline HlinkFrame *impl_from_IHlinkFrame(IHlinkFrame *iface)
884 {
885     return CONTAINING_RECORD(iface, HlinkFrame, IHlinkFrame_iface);
886 }
887
888 static HRESULT WINAPI HlinkFrame_QueryInterface(IHlinkFrame *iface, REFIID riid, void **ppv)
889 {
890     HlinkFrame *This = impl_from_IHlinkFrame(iface);
891     return IUnknown_QueryInterface(This->outer, riid, ppv);
892 }
893
894 static ULONG WINAPI HlinkFrame_AddRef(IHlinkFrame *iface)
895 {
896     HlinkFrame *This = impl_from_IHlinkFrame(iface);
897     return IUnknown_AddRef(This->outer);
898 }
899
900 static ULONG WINAPI HlinkFrame_Release(IHlinkFrame *iface)
901 {
902     HlinkFrame *This = impl_from_IHlinkFrame(iface);
903     return IUnknown_Release(This->outer);
904 }
905
906 static HRESULT WINAPI HlinkFrame_SetBrowseContext(IHlinkFrame *iface,
907                                                   IHlinkBrowseContext *pihlbc)
908 {
909     HlinkFrame *This = impl_from_IHlinkFrame(iface);
910     FIXME("(%p)->(%p)\n", This, pihlbc);
911     return E_NOTIMPL;
912 }
913
914 static HRESULT WINAPI HlinkFrame_GetBrowseContext(IHlinkFrame *iface,
915                                                   IHlinkBrowseContext **ppihlbc)
916 {
917     HlinkFrame *This = impl_from_IHlinkFrame(iface);
918     FIXME("(%p)->(%p)\n", This, ppihlbc);
919     return E_NOTIMPL;
920 }
921
922 static HRESULT WINAPI HlinkFrame_Navigate(IHlinkFrame *iface, DWORD grfHLNF, LPBC pbc,
923                                           IBindStatusCallback *pibsc, IHlink *pihlNavigate)
924 {
925     HlinkFrame *This = impl_from_IHlinkFrame(iface);
926     IMoniker *mon;
927     LPWSTR location = NULL;
928
929     TRACE("(%p)->(%08x %p %p %p)\n", This, grfHLNF, pbc, pibsc, pihlNavigate);
930
931     if(grfHLNF)
932         FIXME("unsupported grfHLNF=%08x\n", grfHLNF);
933
934     /* Windows calls GetTargetFrameName here. */
935
936     IHlink_GetMonikerReference(pihlNavigate, 1, &mon, &location);
937
938     if(location) {
939         FIXME("location = %s\n", debugstr_w(location));
940         CoTaskMemFree(location);
941     }
942
943     /* Windows calls GetHlinkSite here */
944
945     if(grfHLNF & HLNF_OPENINNEWWINDOW) {
946         FIXME("Not supported HLNF_OPENINNEWWINDOW\n");
947         return E_NOTIMPL;
948     }
949
950     return navigate_hlink(This->doc_host, mon, pbc, pibsc);
951 }
952
953 static HRESULT WINAPI HlinkFrame_OnNavigate(IHlinkFrame *iface, DWORD grfHLNF,
954         IMoniker *pimkTarget, LPCWSTR pwzLocation, LPCWSTR pwzFriendlyName, DWORD dwreserved)
955 {
956     HlinkFrame *This = impl_from_IHlinkFrame(iface);
957     FIXME("(%p)->(%08x %p %s %s %d)\n", This, grfHLNF, pimkTarget, debugstr_w(pwzLocation),
958           debugstr_w(pwzFriendlyName), dwreserved);
959     return E_NOTIMPL;
960 }
961
962 static HRESULT WINAPI HlinkFrame_UpdateHlink(IHlinkFrame *iface, ULONG uHLID,
963         IMoniker *pimkTarget, LPCWSTR pwzLocation, LPCWSTR pwzFriendlyName)
964 {
965     HlinkFrame *This = impl_from_IHlinkFrame(iface);
966     FIXME("(%p)->(%u %p %s %s)\n", This, uHLID, pimkTarget, debugstr_w(pwzLocation),
967           debugstr_w(pwzFriendlyName));
968     return E_NOTIMPL;
969 }
970
971 static const IHlinkFrameVtbl HlinkFrameVtbl = {
972     HlinkFrame_QueryInterface,
973     HlinkFrame_AddRef,
974     HlinkFrame_Release,
975     HlinkFrame_SetBrowseContext,
976     HlinkFrame_GetBrowseContext,
977     HlinkFrame_Navigate,
978     HlinkFrame_OnNavigate,
979     HlinkFrame_UpdateHlink
980 };
981
982 static inline HlinkFrame *impl_from_ITargetFrame2(ITargetFrame2 *iface)
983 {
984     return CONTAINING_RECORD(iface, HlinkFrame, IHlinkFrame_iface);
985 }
986
987 static HRESULT WINAPI TargetFrame2_QueryInterface(ITargetFrame2 *iface, REFIID riid, void **ppv)
988 {
989     HlinkFrame *This = impl_from_ITargetFrame2(iface);
990     return IUnknown_QueryInterface(This->outer, riid, ppv);
991 }
992
993 static ULONG WINAPI TargetFrame2_AddRef(ITargetFrame2 *iface)
994 {
995     HlinkFrame *This = impl_from_ITargetFrame2(iface);
996     return IUnknown_AddRef(This->outer);
997 }
998
999 static ULONG WINAPI TargetFrame2_Release(ITargetFrame2 *iface)
1000 {
1001     HlinkFrame *This = impl_from_ITargetFrame2(iface);
1002     return IUnknown_Release(This->outer);
1003 }
1004
1005 static HRESULT WINAPI TargetFrame2_SetFrameName(ITargetFrame2 *iface, LPCWSTR pszFrameName)
1006 {
1007     HlinkFrame *This = impl_from_ITargetFrame2(iface);
1008     FIXME("(%p)->(%s)\n", This, debugstr_w(pszFrameName));
1009     return E_NOTIMPL;
1010 }
1011
1012 static HRESULT WINAPI TargetFrame2_GetFrameName(ITargetFrame2 *iface, LPWSTR *ppszFrameName)
1013 {
1014     HlinkFrame *This = impl_from_ITargetFrame2(iface);
1015     FIXME("(%p)->(%p)\n", This, ppszFrameName);
1016     return E_NOTIMPL;
1017 }
1018
1019 static HRESULT WINAPI TargetFrame2_GetParentFrame(ITargetFrame2 *iface, IUnknown **ppunkParent)
1020 {
1021     HlinkFrame *This = impl_from_ITargetFrame2(iface);
1022     FIXME("(%p)->(%p)\n", This, ppunkParent);
1023     return E_NOTIMPL;
1024 }
1025
1026 static HRESULT WINAPI TargetFrame2_SetFrameSrc(ITargetFrame2 *iface, LPCWSTR pszFrameSrc)
1027 {
1028     HlinkFrame *This = impl_from_ITargetFrame2(iface);
1029     FIXME("(%p)->(%s)\n", This, debugstr_w(pszFrameSrc));
1030     return E_NOTIMPL;
1031 }
1032
1033 static HRESULT WINAPI TargetFrame2_GetFrameSrc(ITargetFrame2 *iface, LPWSTR *ppszFrameSrc)
1034 {
1035     HlinkFrame *This = impl_from_ITargetFrame2(iface);
1036     FIXME("(%p)->()\n", This);
1037     return E_NOTIMPL;
1038 }
1039
1040 static HRESULT WINAPI TargetFrame2_GetFramesContainer(ITargetFrame2 *iface, IOleContainer **ppContainer)
1041 {
1042     HlinkFrame *This = impl_from_ITargetFrame2(iface);
1043     FIXME("(%p)->(%p)\n", This, ppContainer);
1044     return E_NOTIMPL;
1045 }
1046
1047 static HRESULT WINAPI TargetFrame2_SetFrameOptions(ITargetFrame2 *iface, DWORD dwFlags)
1048 {
1049     HlinkFrame *This = impl_from_ITargetFrame2(iface);
1050     FIXME("(%p)->(%x)\n", This, dwFlags);
1051     return E_NOTIMPL;
1052 }
1053
1054 static HRESULT WINAPI TargetFrame2_GetFrameOptions(ITargetFrame2 *iface, DWORD *pdwFlags)
1055 {
1056     HlinkFrame *This = impl_from_ITargetFrame2(iface);
1057     FIXME("(%p)->(%p)\n", This, pdwFlags);
1058     return E_NOTIMPL;
1059 }
1060
1061 static HRESULT WINAPI TargetFrame2_SetFrameMargins(ITargetFrame2 *iface, DWORD dwWidth, DWORD dwHeight)
1062 {
1063     HlinkFrame *This = impl_from_ITargetFrame2(iface);
1064     FIXME("(%p)->(%d %d)\n", This, dwWidth, dwHeight);
1065     return E_NOTIMPL;
1066 }
1067
1068 static HRESULT WINAPI TargetFrame2_GetFrameMargins(ITargetFrame2 *iface, DWORD *pdwWidth, DWORD *pdwHeight)
1069 {
1070     HlinkFrame *This = impl_from_ITargetFrame2(iface);
1071     FIXME("(%p)->(%p %p)\n", This, pdwWidth, pdwHeight);
1072     return E_NOTIMPL;
1073 }
1074
1075 static HRESULT WINAPI TargetFrame2_FindFrame(ITargetFrame2 *iface, LPCWSTR pszTargetName, DWORD dwFlags, IUnknown **ppunkTargetFrame)
1076 {
1077     HlinkFrame *This = impl_from_ITargetFrame2(iface);
1078     FIXME("(%p)->(%s %x %p)\n", This, debugstr_w(pszTargetName), dwFlags, ppunkTargetFrame);
1079     return E_NOTIMPL;
1080 }
1081
1082 static HRESULT WINAPI TargetFrame2_GetTargetAlias(ITargetFrame2 *iface, LPCWSTR pszTargetName, LPWSTR *ppszTargetAlias)
1083 {
1084     HlinkFrame *This = impl_from_ITargetFrame2(iface);
1085     FIXME("(%p)->(%s %p)\n", This, debugstr_w(pszTargetName), ppszTargetAlias);
1086     return E_NOTIMPL;
1087 }
1088
1089 static const ITargetFrame2Vtbl TargetFrame2Vtbl = {
1090     TargetFrame2_QueryInterface,
1091     TargetFrame2_AddRef,
1092     TargetFrame2_Release,
1093     TargetFrame2_SetFrameName,
1094     TargetFrame2_GetFrameName,
1095     TargetFrame2_GetParentFrame,
1096     TargetFrame2_SetFrameSrc,
1097     TargetFrame2_GetFrameSrc,
1098     TargetFrame2_GetFramesContainer,
1099     TargetFrame2_SetFrameOptions,
1100     TargetFrame2_GetFrameOptions,
1101     TargetFrame2_SetFrameMargins,
1102     TargetFrame2_GetFrameMargins,
1103     TargetFrame2_FindFrame,
1104     TargetFrame2_GetTargetAlias
1105 };
1106
1107 BOOL HlinkFrame_QI(HlinkFrame *This, REFIID riid, void **ppv)
1108 {
1109     if(IsEqualGUID(&IID_IHlinkFrame, riid)) {
1110         TRACE("(%p)->(IID_IHlinkFrame %p)\n", This, ppv);
1111         *ppv = &This->IHlinkFrame_iface;
1112     }else if(IsEqualGUID(&IID_ITargetFrame2, riid)) {
1113         TRACE("(%p)->(IID_ITargetFrame2 %p)\n", This, ppv);
1114         *ppv = &This->ITargetFrame2_iface;
1115     }else {
1116         return FALSE;
1117     }
1118
1119     IUnknown_AddRef((IUnknown*)*ppv);
1120     return TRUE;
1121 }
1122
1123 void HlinkFrame_Init(HlinkFrame *This, IUnknown *outer, DocHost *doc_host)
1124 {
1125     This->IHlinkFrame_iface.lpVtbl   = &HlinkFrameVtbl;
1126     This->ITargetFrame2_iface.lpVtbl = &TargetFrame2Vtbl;
1127
1128     This->outer = outer;
1129     This->doc_host = doc_host;
1130 }