shdocvw: Use DocHost, not WebBrowser, in navigate_url.
[wine] / dlls / shdocvw / navigate.c
1 /*
2  * Copyright 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  */
18
19 #define NONAMELESSUNION
20 #define NONAMELESSSTRUCT
21
22 #include "wine/debug.h"
23 #include "wine/unicode.h"
24
25 #include "shdocvw.h"
26 #include "mshtml.h"
27 #include "exdispid.h"
28
29 WINE_DEFAULT_DEBUG_CHANNEL(shdocvw);
30
31 typedef struct {
32     const IBindStatusCallbackVtbl  *lpBindStatusCallbackVtbl;
33     const IHttpNegotiateVtbl       *lpHttpNegotiateVtbl;
34
35     LONG ref;
36
37     HGLOBAL post_data;
38     LPWSTR headers;
39     ULONG post_data_len;
40 } BindStatusCallback;
41
42 #define BINDSC(x)  ((IBindStatusCallback*) &(x)->lpBindStatusCallbackVtbl)
43 #define HTTPNEG(x) ((IHttpNegotiate*)      &(x)->lpHttpNegotiateVtbl)
44
45 static void dump_BINDINFO(BINDINFO *bi)
46 {
47     static const char *BINDINFOF_str[] = {
48         "#0",
49         "BINDINFOF_URLENCODESTGMEDDATA",
50         "BINDINFOF_URLENCODEDEXTRAINFO"
51     };
52
53     static const char *BINDVERB_str[] = {
54         "BINDVERB_GET",
55         "BINDVERB_POST",
56         "BINDVERB_PUT",
57         "BINDVERB_CUSTOM"
58     };
59
60     TRACE("\n"
61             "BINDINFO = {\n"
62             "    %ld, %s,\n"
63             "    {%ld, %p, %p},\n"
64             "    %s,\n"
65             "    %s,\n"
66             "    %s,\n"
67             "    %ld, %08lx, %ld, %ld\n"
68             "    {%ld %p %x},\n"
69             "    %s\n"
70             "    %p, %ld\n"
71             "}\n",
72
73             bi->cbSize, debugstr_w(bi->szExtraInfo),
74             bi->stgmedData.tymed, bi->stgmedData.u.hGlobal, bi->stgmedData.pUnkForRelease,
75             bi->grfBindInfoF > BINDINFOF_URLENCODEDEXTRAINFO
76                 ? "unknown" : BINDINFOF_str[bi->grfBindInfoF],
77             bi->dwBindVerb > BINDVERB_CUSTOM
78                 ? "unknown" : BINDVERB_str[bi->dwBindVerb],
79             debugstr_w(bi->szCustomVerb),
80             bi->cbStgmedData, bi->dwOptions, bi->dwOptionsFlags, bi->dwCodePage,
81             bi->securityAttributes.nLength,
82             bi->securityAttributes.lpSecurityDescriptor,
83             bi->securityAttributes.bInheritHandle,
84             debugstr_guid(&bi->iid),
85             bi->pUnk, bi->dwReserved
86             );
87 }
88
89 #define BINDSC_THIS(iface) DEFINE_THIS(BindStatusCallback, BindStatusCallback, iface)
90
91 static HRESULT WINAPI BindStatusCallback_QueryInterface(IBindStatusCallback *iface,
92                                                         REFIID riid, void **ppv)
93 {
94     BindStatusCallback *This = BINDSC_THIS(iface);
95
96     *ppv = NULL;
97
98     if(IsEqualGUID(&IID_IUnknown, riid)) {
99         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
100         *ppv = BINDSC(This);
101     }else if(IsEqualGUID(&IID_IBindStatusCallback, riid)) {
102         TRACE("(%p)->(IID_IBindStatusCallback %p)\n", This, ppv);
103         *ppv = BINDSC(This);
104     }else if(IsEqualGUID(&IID_IHttpNegotiate, riid)) {
105         TRACE("(%p)->(IID_IHttpNegotiate %p)\n", This, ppv);
106         *ppv = HTTPNEG(This);
107     }
108
109     if(*ppv) {
110         IBindStatusCallback_AddRef(BINDSC(This));
111         return S_OK;
112     }
113
114     WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
115     return E_NOINTERFACE;
116 }
117
118 static ULONG WINAPI BindStatusCallback_AddRef(IBindStatusCallback *iface)
119 {
120     BindStatusCallback *This = BINDSC_THIS(iface);
121     LONG ref = InterlockedIncrement(&This->ref);
122
123     TRACE("(%p) ref=%ld\n", This, ref);
124
125     return ref;
126 }
127
128 static ULONG WINAPI BindStatusCallback_Release(IBindStatusCallback *iface)
129 {
130     BindStatusCallback *This = BINDSC_THIS(iface);
131     LONG ref = InterlockedDecrement(&This->ref);
132
133     TRACE("(%p) ref=%ld\n", This, ref);
134
135     if(!ref) {
136         if(This->post_data)
137             GlobalFree(This->post_data);
138         HeapFree(GetProcessHeap(), 0, This->headers);
139         HeapFree(GetProcessHeap(), 0, This);
140     }
141
142     return ref;
143 }
144
145 static HRESULT WINAPI BindStatusCallback_OnStartBinding(IBindStatusCallback *iface,
146        DWORD dwReserved, IBinding *pbind)
147 {
148     BindStatusCallback *This = BINDSC_THIS(iface);
149     FIXME("(%p)->(%ld %p)\n", This, dwReserved, pbind);
150     return E_NOTIMPL;
151 }
152
153 static HRESULT WINAPI BindStatusCallback_GetPriority(IBindStatusCallback *iface,
154        LONG *pnPriority)
155 {
156     BindStatusCallback *This = BINDSC_THIS(iface);
157     FIXME("(%p)->(%p)\n", This, pnPriority);
158     return E_NOTIMPL;
159 }
160
161 static HRESULT WINAPI BindStatusCallback_OnLowResource(IBindStatusCallback *iface,
162        DWORD reserved)
163 {
164     BindStatusCallback *This = BINDSC_THIS(iface);
165     FIXME("(%p)->(%ld)\n", This, reserved);
166     return E_NOTIMPL;
167 }
168
169 static HRESULT WINAPI BindStatusCallback_OnProgress(IBindStatusCallback *iface,
170         ULONG ulProgress, ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText)
171 {
172     BindStatusCallback *This = BINDSC_THIS(iface);
173     FIXME("(%p)->(%ld %ld %ld %s)\n", This, ulProgress, ulProgressMax, ulStatusCode,
174           debugstr_w(szStatusText));
175     return E_NOTIMPL;
176 }
177
178 static HRESULT WINAPI BindStatusCallback_OnStopBinding(IBindStatusCallback *iface,
179         HRESULT hresult, LPCWSTR szError)
180 {
181     BindStatusCallback *This = BINDSC_THIS(iface);
182     FIXME("(%p)->(%08lx %s)\n", This, hresult, debugstr_w(szError));
183     return E_NOTIMPL;
184 }
185
186 static HRESULT WINAPI BindStatusCallback_GetBindInfo(IBindStatusCallback *iface,
187         DWORD *grfBINDF, BINDINFO *pbindinfo)
188 {
189     BindStatusCallback *This = BINDSC_THIS(iface);
190
191     FIXME("(%p)->(%p %p)\n", This, grfBINDF, pbindinfo);
192
193     memset(pbindinfo, 0, sizeof(BINDINFO));
194     pbindinfo->cbSize = sizeof(BINDINFO);
195
196     pbindinfo->cbStgmedData = This->post_data_len;
197
198     if(This->post_data) {
199         pbindinfo->dwBindVerb = BINDVERB_POST;
200
201         pbindinfo->stgmedData.tymed = TYMED_HGLOBAL;
202         pbindinfo->stgmedData.u.hGlobal = This->post_data;
203         pbindinfo->stgmedData.pUnkForRelease = (IUnknown*)BINDSC(This);
204         IBindStatusCallback_AddRef(BINDSC(This));
205     }
206
207     return S_OK;
208 }
209
210 static HRESULT WINAPI BindStatusCallback_OnDataAvailable(IBindStatusCallback *iface,
211         DWORD grfBSCF, DWORD dwSize, FORMATETC *pformatetc, STGMEDIUM *pstgmed)
212 {
213     BindStatusCallback *This = BINDSC_THIS(iface);
214     FIXME("(%p)->(%08lx %ld %p %p)\n", This, grfBSCF, dwSize, pformatetc, pstgmed);
215     return E_NOTIMPL;
216 }
217
218 #undef BSC_THIS
219
220 static const IBindStatusCallbackVtbl BindStatusCallbackVtbl = {
221     BindStatusCallback_QueryInterface,
222     BindStatusCallback_AddRef,
223     BindStatusCallback_Release,
224     BindStatusCallback_OnStartBinding,
225     BindStatusCallback_GetPriority,
226     BindStatusCallback_OnLowResource,
227     BindStatusCallback_OnProgress,
228     BindStatusCallback_OnStopBinding,
229     BindStatusCallback_GetBindInfo,
230     BindStatusCallback_OnDataAvailable
231 };
232
233 #define HTTPNEG_THIS(iface) DEFINE_THIS(BindStatusCallback, HttpNegotiate, iface)
234
235 static HRESULT WINAPI HttpNegotiate_QueryInterface(IHttpNegotiate *iface,
236                                                    REFIID riid, void **ppv)
237 {
238     BindStatusCallback *This = HTTPNEG_THIS(iface);
239     return IBindStatusCallback_QueryInterface(BINDSC(This), riid, ppv);
240 }
241
242 static ULONG WINAPI HttpNegotiate_AddRef(IHttpNegotiate *iface)
243 {
244     BindStatusCallback *This = HTTPNEG_THIS(iface);
245     return IBindStatusCallback_AddRef(BINDSC(This));
246 }
247
248 static ULONG WINAPI HttpNegotiate_Release(IHttpNegotiate *iface)
249 {
250     BindStatusCallback *This = HTTPNEG_THIS(iface);
251     return IBindStatusCallback_Release(BINDSC(This));
252 }
253
254 static HRESULT WINAPI HttpNegotiate_BeginningTransaction(IHttpNegotiate *iface,
255         LPCWSTR szURL, LPCWSTR szHeaders, DWORD dwReserved, LPWSTR *pszAdditionalHeaders)
256 {
257     BindStatusCallback *This = HTTPNEG_THIS(iface);
258
259     FIXME("(%p)->(%s %s %ld %p)\n", This, debugstr_w(szURL), debugstr_w(szHeaders),
260           dwReserved, pszAdditionalHeaders);
261
262     if(This->headers) {
263         int size = (strlenW(This->headers)+1)*sizeof(WCHAR);
264         *pszAdditionalHeaders = CoTaskMemAlloc(size);
265         memcpy(*pszAdditionalHeaders, This->headers, size);
266     }
267
268     return S_OK;
269 }
270
271 static HRESULT WINAPI HttpNegotiate_OnResponse(IHttpNegotiate *iface,
272         DWORD dwResponseCode, LPCWSTR szResponseHeaders, LPCWSTR szRequestHeaders,
273         LPWSTR *pszAdditionalRequestHeaders)
274 {
275     BindStatusCallback *This = HTTPNEG_THIS(iface);
276     FIXME("(%p)->(%ld %s %s %p)\n", This, dwResponseCode, debugstr_w(szResponseHeaders),
277           debugstr_w(szRequestHeaders), pszAdditionalRequestHeaders);
278     return E_NOTIMPL;
279 }
280
281 #undef HTTPNEG_THIS
282
283 static const IHttpNegotiateVtbl HttpNegotiateVtbl = {
284     HttpNegotiate_QueryInterface,
285     HttpNegotiate_AddRef,
286     HttpNegotiate_Release,
287     HttpNegotiate_BeginningTransaction,
288     HttpNegotiate_OnResponse
289 };
290
291 static IBindStatusCallback *create_callback(DocHost *This, PBYTE post_data,
292         ULONG post_data_len, LPWSTR headers, VARIANT_BOOL *cancel)
293 {
294     BindStatusCallback *ret = HeapAlloc(GetProcessHeap(), 0, sizeof(BindStatusCallback));
295
296     ret->lpBindStatusCallbackVtbl = &BindStatusCallbackVtbl;
297     ret->lpHttpNegotiateVtbl      = &HttpNegotiateVtbl;
298
299     ret->ref = 1;
300     ret->post_data = NULL;
301     ret->post_data_len = post_data_len;
302     ret->headers = NULL;
303
304     if(post_data) {
305         ret->post_data = GlobalAlloc(0, post_data_len);
306         memcpy(ret->post_data, post_data, post_data_len);
307     }
308
309     if(headers) {
310         int size = (strlenW(headers)+1)*sizeof(WCHAR);
311         ret->headers = HeapAlloc(GetProcessHeap(), 0, size);
312         memcpy(ret->headers, headers, size);
313     }
314
315     return BINDSC(ret);
316 }
317
318 static void on_before_navigate2(DocHost *This, LPWSTR url, PBYTE post_data, ULONG post_data_len,
319                                 LPWSTR headers, VARIANT_BOOL *cancel)
320 {
321     VARIANT var_url, var_flags, var_frame_name, var_post_data, var_post_data2, var_headers;
322     DISPPARAMS dispparams;
323     VARIANTARG params[7];
324
325     dispparams.cArgs = 7;
326     dispparams.cNamedArgs = 0;
327     dispparams.rgdispidNamedArgs = NULL;
328     dispparams.rgvarg = params;
329
330     V_VT(params) = VT_BOOL|VT_BYREF;
331     V_BOOLREF(params) = cancel;
332
333     V_VT(params+1) = (VT_BYREF|VT_VARIANT);
334     V_VARIANTREF(params+1) = &var_headers;
335     V_VT(&var_headers) = VT_BSTR;
336     V_BSTR(&var_headers) = headers;
337
338     V_VT(params+2) = (VT_BYREF|VT_VARIANT);
339     V_VARIANTREF(params+2) = &var_post_data2;
340     V_VT(&var_post_data2) = (VT_BYREF|VT_VARIANT);
341     V_VARIANTREF(&var_post_data2) = &var_post_data;
342     VariantInit(&var_post_data);
343
344     if(post_data_len) {
345         SAFEARRAYBOUND bound = {post_data_len, 0};
346         void *data;
347
348         V_VT(&var_post_data) = VT_UI1|VT_ARRAY;
349         V_ARRAY(&var_post_data) = SafeArrayCreate(VT_UI1, 1, &bound);
350
351         SafeArrayAccessData(V_ARRAY(&var_post_data), &data);
352         memcpy(data, post_data, post_data_len);
353         SafeArrayUnaccessData(V_ARRAY(&var_post_data));
354     }
355
356     V_VT(params+3) = (VT_BYREF|VT_VARIANT);
357     V_VARIANTREF(params+3) = &var_frame_name;
358     V_VT(&var_frame_name) = VT_BSTR;
359     V_BSTR(&var_frame_name) = NULL;
360
361     V_VT(params+4) = (VT_BYREF|VT_VARIANT);
362     V_VARIANTREF(params+4) = &var_flags;
363     V_VT(&var_flags) = VT_I4;
364     V_I4(&var_flags) = 0;
365
366     V_VT(params+5) = (VT_BYREF|VT_VARIANT);
367     V_VARIANTREF(params+5) = &var_url;
368     V_VT(&var_url) = VT_BSTR;
369     V_BSTR(&var_url) = SysAllocString(url);
370
371     V_VT(params+6) = (VT_DISPATCH);
372     V_DISPATCH(params+6) = This->disp;
373
374     call_sink(This->cp_wbe2, DISPID_BEFORENAVIGATE2, &dispparams);
375
376     SysFreeString(V_BSTR(&var_url));
377     if(post_data_len)
378         SafeArrayDestroy(V_ARRAY(&var_post_data));
379 }
380
381 static HRESULT navigate(DocHost *This, IMoniker *mon, IBindCtx *bindctx,
382                         IBindStatusCallback *callback)
383 {
384     IOleObject *oleobj;
385     IPersistMoniker *persist;
386     VARIANT_BOOL cancel = VARIANT_FALSE;
387     HRESULT hres;
388
389     if(cancel) {
390         FIXME("Cancel\n");
391         return S_OK;
392     }
393
394     IBindCtx_RegisterObjectParam(bindctx, (LPOLESTR)SZ_HTML_CLIENTSITE_OBJECTPARAM,
395                                  (IUnknown*)CLIENTSITE(This));
396
397     /*
398      * FIXME:
399      * We should use URLMoniker's BindToObject instead creating HTMLDocument here.
400      * This should be fixed when mshtml.dll and urlmon.dll will be good enough.
401      */
402
403     if(This->document)
404         deactivate_document(This);
405
406     hres = CoCreateInstance(&CLSID_HTMLDocument, NULL,
407                             CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER,
408                             &IID_IUnknown, (void**)&This->document);
409
410     if(FAILED(hres)) {
411         ERR("Could not create HTMLDocument: %08lx\n", hres);
412         return hres;
413     }
414
415     hres = IUnknown_QueryInterface(This->document, &IID_IPersistMoniker, (void**)&persist);
416     if(FAILED(hres))
417         return hres;
418
419     if(FAILED(hres)) {
420         IPersistMoniker_Release(persist);
421         return hres;
422     }
423
424     hres = IPersistMoniker_Load(persist, FALSE, mon, bindctx, 0);
425     IPersistMoniker_Release(persist);
426     if(FAILED(hres)) {
427         WARN("Load failed: %08lx\n", hres);
428         return hres;
429     }
430
431     hres = IUnknown_QueryInterface(This->document, &IID_IOleObject, (void**)&oleobj);
432     if(FAILED(hres))
433         return hres;
434
435     hres = IOleObject_SetClientSite(oleobj, CLIENTSITE(This));
436     IOleObject_Release(oleobj);
437
438     PostMessageW(This->hwnd, WB_WM_NAVIGATE2, 0, 0);
439
440     return hres;
441
442 }
443
444 HRESULT navigate_url(DocHost *This, LPCWSTR url, PBYTE post_data, ULONG post_data_len,
445                      LPWSTR headers)
446 {
447     IBindStatusCallback *callback;
448     IMoniker *mon;
449     IBindCtx *bindctx;
450     VARIANT_BOOL cancel = VARIANT_FALSE;
451     HRESULT hres;
452
453     hres = CreateURLMoniker(NULL, url, &mon);
454     if(FAILED(hres)) {
455         WARN("CreateURLMoniker failed: %08lx\n", hres);
456         return hres;
457     }
458
459     IMoniker_GetDisplayName(mon, NULL, NULL, &This->url);
460     TRACE("navigating to %s\n", debugstr_w(This->url));
461
462     callback = create_callback(This, post_data, post_data_len, (LPWSTR)headers, &cancel);
463     CreateAsyncBindCtx(0, callback, 0, &bindctx);
464
465     hres = navigate(This, mon, bindctx, callback);
466
467     IMoniker_Release(mon);
468
469     return hres;
470 }
471
472 HRESULT navigate_hlink(DocHost *This, IMoniker *mon, IBindCtx *bindctx,
473                        IBindStatusCallback *callback)
474 {
475     IHttpNegotiate *http_negotiate;
476     LPWSTR url = NULL;
477     PBYTE post_data = NULL;
478     ULONG post_data_len = 0;
479     LPWSTR headers = NULL;
480     VARIANT_BOOL cancel = VARIANT_FALSE;
481     BINDINFO bindinfo;
482     DWORD bindf = 0;
483     HRESULT hres;
484
485     IMoniker_GetDisplayName(mon, NULL, NULL, &url);
486     TRACE("navigating to %s\n", debugstr_w(url));
487
488     hres = IBindStatusCallback_QueryInterface(callback, &IID_IHttpNegotiate,
489                                               (void**)&http_negotiate);
490     if(SUCCEEDED(hres)) {
491         static const WCHAR null_string[] = {0};
492
493         IHttpNegotiate_BeginningTransaction(http_negotiate, null_string, null_string, 0,
494                                             &headers);
495         IHttpNegotiate_Release(http_negotiate);
496     }
497
498     memset(&bindinfo, 0, sizeof(bindinfo));
499     bindinfo.cbSize = sizeof(bindinfo);
500
501     hres = IBindStatusCallback_GetBindInfo(callback, &bindf, &bindinfo);
502     dump_BINDINFO(&bindinfo);
503     if(bindinfo.dwBindVerb == BINDVERB_POST) {
504         post_data_len = bindinfo.cbStgmedData;
505         if(post_data_len)
506             post_data = bindinfo.stgmedData.u.hGlobal;
507     }
508
509     on_before_navigate2(This, url, post_data, post_data_len, headers, &cancel);
510
511     CoTaskMemFree(headers);
512     ReleaseBindInfo(&bindinfo);
513
514     if(cancel) {
515         FIXME("navigation canceled\n");
516         CoTaskMemFree(url);
517         return S_OK;
518     }
519
520     This->url = url;
521
522     return navigate(This, mon, bindctx, callback);
523 }
524
525 #define HLINKFRAME_THIS(iface) DEFINE_THIS(WebBrowser, HlinkFrame, iface)
526
527 static HRESULT WINAPI HlinkFrame_QueryInterface(IHlinkFrame *iface, REFIID riid, void **ppv)
528 {
529     WebBrowser *This = HLINKFRAME_THIS(iface);
530     return IWebBrowser2_QueryInterface(WEBBROWSER2(This), riid, ppv);
531 }
532
533 static ULONG WINAPI HlinkFrame_AddRef(IHlinkFrame *iface)
534 {
535     WebBrowser *This = HLINKFRAME_THIS(iface);
536     return IWebBrowser2_AddRef(WEBBROWSER2(This));
537 }
538
539 static ULONG WINAPI HlinkFrame_Release(IHlinkFrame *iface)
540 {
541     WebBrowser *This = HLINKFRAME_THIS(iface);
542     return IWebBrowser2_Release(WEBBROWSER2(This));
543 }
544
545 static HRESULT WINAPI HlinkFrame_SetBrowseContext(IHlinkFrame *iface,
546                                                   IHlinkBrowseContext *pihlbc)
547 {
548     WebBrowser *This = HLINKFRAME_THIS(iface);
549     FIXME("(%p)->(%p)\n", This, pihlbc);
550     return E_NOTIMPL;
551 }
552
553 static HRESULT WINAPI HlinkFrame_GetBrowseContext(IHlinkFrame *iface,
554                                                   IHlinkBrowseContext **ppihlbc)
555 {
556     WebBrowser *This = HLINKFRAME_THIS(iface);
557     FIXME("(%p)->(%p)\n", This, ppihlbc);
558     return E_NOTIMPL;
559 }
560
561 static HRESULT WINAPI HlinkFrame_Navigate(IHlinkFrame *iface, DWORD grfHLNF, LPBC pbc,
562                                           IBindStatusCallback *pibsc, IHlink *pihlNavigate)
563 {
564     WebBrowser *This = HLINKFRAME_THIS(iface);
565     IMoniker *mon;
566     LPWSTR location = NULL;
567
568     TRACE("(%p)->(%08lx %p %p %p)\n", This, grfHLNF, pbc, pibsc, pihlNavigate);
569
570     if(grfHLNF)
571         FIXME("unsupported grfHLNF=%08lx\n", grfHLNF);
572
573     /* Windows calls GetTargetFrameName here. */
574
575     IHlink_GetMonikerReference(pihlNavigate, 1, &mon, &location);
576
577     if(location) {
578         FIXME("location = %s\n", debugstr_w(location));
579         CoTaskMemFree(location);
580     }
581
582     /* Windows calls GetHlinkSite here */
583
584     if(grfHLNF & HLNF_OPENINNEWWINDOW) {
585         FIXME("Not supported HLNF_OPENINNEWWINDOW\n");
586         return E_NOTIMPL;
587     }
588
589     return navigate_hlink(&This->doc_host, mon, pbc, pibsc);
590 }
591
592 static HRESULT WINAPI HlinkFrame_OnNavigate(IHlinkFrame *iface, DWORD grfHLNF,
593         IMoniker *pimkTarget, LPCWSTR pwzLocation, LPCWSTR pwzFriendlyName, DWORD dwreserved)
594 {
595     WebBrowser *This = HLINKFRAME_THIS(iface);
596     FIXME("(%p)->(%08lx %p %s %s %ld)\n", This, grfHLNF, pimkTarget, debugstr_w(pwzLocation),
597           debugstr_w(pwzFriendlyName), dwreserved);
598     return E_NOTIMPL;
599 }
600
601 static HRESULT WINAPI HlinkFrame_UpdateHlink(IHlinkFrame *iface, ULONG uHLID,
602         IMoniker *pimkTarget, LPCWSTR pwzLocation, LPCWSTR pwzFriendlyName)
603 {
604     WebBrowser *This = HLINKFRAME_THIS(iface);
605     FIXME("(%p)->(%lu %p %s %s)\n", This, uHLID, pimkTarget, debugstr_w(pwzLocation),
606           debugstr_w(pwzFriendlyName));
607     return E_NOTIMPL;
608 }
609
610 #undef HLINKFRAME_THIS
611
612 static const IHlinkFrameVtbl HlinkFrameVtbl = {
613     HlinkFrame_QueryInterface,
614     HlinkFrame_AddRef,
615     HlinkFrame_Release,
616     HlinkFrame_SetBrowseContext,
617     HlinkFrame_GetBrowseContext,
618     HlinkFrame_Navigate,
619     HlinkFrame_OnNavigate,
620     HlinkFrame_UpdateHlink
621 };
622
623 void WebBrowser_HlinkFrame_Init(WebBrowser *This)
624 {
625     This->lpHlinkFrameVtbl = &HlinkFrameVtbl;
626 }