mshtml: Added IHTMLWindow2::focus implementation.
[wine] / dlls / urlmon / bindprot.c
1 /*
2  * Copyright 2007-2009 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 "urlmon_main.h"
20 #include "wine/debug.h"
21
22 WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
23
24 typedef void (*task_proc_t)(BindProtocol*,task_header_t*);
25
26 struct _task_header_t {
27     task_proc_t proc;
28     task_header_t *next;
29 };
30
31 #define BUFFER_SIZE     2048
32 #define MIME_TEST_SIZE  255
33
34 #define WM_MK_CONTINUE   (WM_USER+101)
35 #define WM_MK_RELEASE    (WM_USER+102)
36
37 static LRESULT WINAPI notif_wnd_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
38 {
39     switch(msg) {
40     case WM_MK_CONTINUE: {
41         BindProtocol *This = (BindProtocol*)lParam;
42         task_header_t *task;
43
44         while(1) {
45             EnterCriticalSection(&This->section);
46
47             task = This->task_queue_head;
48             if(task) {
49                 This->task_queue_head = task->next;
50                 if(!This->task_queue_head)
51                     This->task_queue_tail = NULL;
52             }
53
54             LeaveCriticalSection(&This->section);
55
56             if(!task)
57                 break;
58
59             This->continue_call++;
60             task->proc(This, task);
61             This->continue_call--;
62         }
63
64         IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
65         return 0;
66     }
67     case WM_MK_RELEASE: {
68         tls_data_t *data = get_tls_data();
69
70         if(!--data->notif_hwnd_cnt) {
71             DestroyWindow(hwnd);
72             data->notif_hwnd = NULL;
73         }
74     }
75     }
76
77     return DefWindowProcW(hwnd, msg, wParam, lParam);
78 }
79
80 HWND get_notif_hwnd(void)
81 {
82     static ATOM wnd_class = 0;
83     tls_data_t *tls_data;
84
85     static const WCHAR wszURLMonikerNotificationWindow[] =
86         {'U','R','L',' ','M','o','n','i','k','e','r',' ',
87          'N','o','t','i','f','i','c','a','t','i','o','n',' ','W','i','n','d','o','w',0};
88
89     tls_data = get_tls_data();
90     if(!tls_data)
91         return NULL;
92
93     if(tls_data->notif_hwnd_cnt) {
94         tls_data->notif_hwnd_cnt++;
95         return tls_data->notif_hwnd;
96     }
97
98     if(!wnd_class) {
99         static WNDCLASSEXW wndclass = {
100             sizeof(wndclass), 0,
101             notif_wnd_proc, 0, 0,
102             NULL, NULL, NULL, NULL, NULL,
103             wszURLMonikerNotificationWindow,
104             NULL
105         };
106
107         wndclass.hInstance = hProxyDll;
108
109         wnd_class = RegisterClassExW(&wndclass);
110         if (!wnd_class && GetLastError() == ERROR_CLASS_ALREADY_EXISTS)
111             wnd_class = 1;
112     }
113
114     tls_data->notif_hwnd = CreateWindowExW(0, wszURLMonikerNotificationWindow,
115             wszURLMonikerNotificationWindow, 0, 0, 0, 0, 0, HWND_MESSAGE,
116             NULL, hProxyDll, NULL);
117     if(tls_data->notif_hwnd)
118         tls_data->notif_hwnd_cnt++;
119
120     TRACE("hwnd = %p\n", tls_data->notif_hwnd);
121
122     return tls_data->notif_hwnd;
123 }
124
125 void release_notif_hwnd(HWND hwnd)
126 {
127     tls_data_t *data = get_tls_data();
128
129     if(!data)
130         return;
131
132     if(data->notif_hwnd != hwnd) {
133         PostMessageW(data->notif_hwnd, WM_MK_RELEASE, 0, 0);
134         return;
135     }
136
137     if(!--data->notif_hwnd_cnt) {
138         DestroyWindow(data->notif_hwnd);
139         data->notif_hwnd = NULL;
140     }
141 }
142
143 static void push_task(BindProtocol *This, task_header_t *task, task_proc_t proc)
144 {
145     BOOL do_post = FALSE;
146
147     task->proc = proc;
148     task->next = NULL;
149
150     EnterCriticalSection(&This->section);
151
152     if(This->task_queue_tail) {
153         This->task_queue_tail->next = task;
154         This->task_queue_tail = task;
155     }else {
156         This->task_queue_tail = This->task_queue_head = task;
157         do_post = !This->continue_call;
158     }
159
160     LeaveCriticalSection(&This->section);
161
162     if(do_post) {
163         IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
164         PostMessageW(This->notif_hwnd, WM_MK_CONTINUE, 0, (LPARAM)This);
165     }
166 }
167
168 static inline BOOL do_direct_notif(BindProtocol *This)
169 {
170     return !(This->pi & PI_APARTMENTTHREADED) || (This->apartment_thread == GetCurrentThreadId() && !This->continue_call);
171 }
172
173 static HRESULT handle_mime_filter(BindProtocol *This, IInternetProtocol *mime_filter, LPCWSTR mime)
174 {
175     PROTOCOLFILTERDATA filter_data = { sizeof(PROTOCOLFILTERDATA), NULL, NULL, NULL, 0 };
176     IInternetProtocolSink *protocol_sink, *old_sink;
177     ProtocolProxy *filter_proxy;
178     HRESULT hres;
179
180     hres = IInternetProtocol_QueryInterface(mime_filter, &IID_IInternetProtocolSink, (void**)&protocol_sink);
181     if(FAILED(hres))
182         return hres;
183
184     hres = create_protocol_proxy(&This->default_protocol_handler.IInternetProtocol_iface, This->protocol_sink, &filter_proxy);
185     if(FAILED(hres)) {
186         IInternetProtocolSink_Release(protocol_sink);
187         return hres;
188     }
189
190     old_sink = This->protocol_sink;
191     This->protocol_sink = protocol_sink;
192     This->filter_proxy = filter_proxy;
193
194     IInternetProtocol_AddRef(mime_filter);
195     This->protocol_handler = mime_filter;
196
197     filter_data.pProtocol = &filter_proxy->IInternetProtocol_iface;
198     hres = IInternetProtocol_Start(mime_filter, mime, &filter_proxy->IInternetProtocolSink_iface,
199             &This->IInternetBindInfo_iface, PI_FILTER_MODE|PI_FORCE_ASYNC,
200             (HANDLE_PTR)&filter_data);
201     if(FAILED(hres)) {
202         IInternetProtocolSink_Release(old_sink);
203         return hres;
204     }
205
206     IInternetProtocolSink_ReportProgress(old_sink, BINDSTATUS_LOADINGMIMEHANDLER, NULL);
207     IInternetProtocolSink_Release(old_sink);
208
209     This->pi &= ~PI_MIMEVERIFICATION; /* FIXME: more tests */
210     return S_OK;
211 }
212
213 static void mime_available(BindProtocol *This, LPCWSTR mime, BOOL verified)
214 {
215     IInternetProtocol *mime_filter;
216     HRESULT hres;
217
218     heap_free(This->mime);
219     This->mime = NULL;
220
221     mime_filter = get_mime_filter(mime);
222     if(mime_filter) {
223         TRACE("Got mime filter for %s\n", debugstr_w(mime));
224
225         hres = handle_mime_filter(This, mime_filter, mime);
226         IInternetProtocol_Release(mime_filter);
227         if(FAILED(hres))
228             FIXME("MIME filter failed: %08x\n", hres);
229     }else {
230         This->mime = heap_strdupW(mime);
231
232         if(verified || !(This->pi & PI_MIMEVERIFICATION)) {
233             This->reported_mime = TRUE;
234
235             if(This->protocol_sink)
236                 IInternetProtocolSink_ReportProgress(This->protocol_sink, BINDSTATUS_MIMETYPEAVAILABLE, mime);
237         }
238     }
239 }
240
241 static inline BindProtocol *impl_from_IInternetProtocolEx(IInternetProtocolEx *iface)
242 {
243     return CONTAINING_RECORD(iface, BindProtocol, IInternetProtocolEx_iface);
244 }
245
246 static HRESULT WINAPI BindProtocol_QueryInterface(IInternetProtocolEx *iface, REFIID riid, void **ppv)
247 {
248     BindProtocol *This = impl_from_IInternetProtocolEx(iface);
249
250     *ppv = NULL;
251     if(IsEqualGUID(&IID_IUnknown, riid)) {
252         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
253         *ppv = &This->IInternetProtocolEx_iface;
254     }else if(IsEqualGUID(&IID_IInternetProtocolRoot, riid)) {
255         TRACE("(%p)->(IID_IInternetProtocolRoot %p)\n", This, ppv);
256         *ppv = &This->IInternetProtocolEx_iface;
257     }else if(IsEqualGUID(&IID_IInternetProtocol, riid)) {
258         TRACE("(%p)->(IID_IInternetProtocol %p)\n", This, ppv);
259         *ppv = &This->IInternetProtocolEx_iface;
260     }else if(IsEqualGUID(&IID_IInternetProtocolEx, riid)) {
261         TRACE("(%p)->(IID_IInternetProtocolEx %p)\n", This, ppv);
262         *ppv = &This->IInternetProtocolEx_iface;
263     }else if(IsEqualGUID(&IID_IInternetBindInfo, riid)) {
264         TRACE("(%p)->(IID_IInternetBindInfo %p)\n", This, ppv);
265         *ppv = &This->IInternetBindInfo_iface;
266     }else if(IsEqualGUID(&IID_IInternetPriority, riid)) {
267         TRACE("(%p)->(IID_IInternetPriority %p)\n", This, ppv);
268         *ppv = &This->IInternetPriority_iface;
269     }else if(IsEqualGUID(&IID_IAuthenticate, riid)) {
270         FIXME("(%p)->(IID_IAuthenticate %p)\n", This, ppv);
271     }else if(IsEqualGUID(&IID_IServiceProvider, riid)) {
272         TRACE("(%p)->(IID_IServiceProvider %p)\n", This, ppv);
273         *ppv = &This->IServiceProvider_iface;
274     }else if(IsEqualGUID(&IID_IInternetProtocolSink, riid)) {
275         TRACE("(%p)->(IID_IInternetProtocolSink %p)\n", This, ppv);
276         *ppv = &This->IInternetProtocolSink_iface;
277     }else if(IsEqualGUID(&IID_IWinInetInfo, riid)) {
278         TRACE("(%p)->(IID_IWinInetInfo %p)\n", This, ppv);
279
280         if(This->protocol) {
281             IWinInetInfo *inet_info;
282             HRESULT hres;
283
284             hres = IInternetProtocol_QueryInterface(This->protocol, &IID_IWinInetInfo, (void**)&inet_info);
285             if(SUCCEEDED(hres)) {
286                 *ppv = &This->IWinInetHttpInfo_iface;
287                 IWinInetInfo_Release(inet_info);
288             }
289         }
290     }else if(IsEqualGUID(&IID_IWinInetHttpInfo, riid)) {
291         TRACE("(%p)->(IID_IWinInetHttpInfo %p)\n", This, ppv);
292
293         if(This->protocol) {
294             IWinInetHttpInfo *http_info;
295             HRESULT hres;
296
297             hres = IInternetProtocol_QueryInterface(This->protocol, &IID_IWinInetHttpInfo, (void**)&http_info);
298             if(SUCCEEDED(hres)) {
299                 *ppv = &This->IWinInetHttpInfo_iface;
300                 IWinInetHttpInfo_Release(http_info);
301             }
302         }
303     }else {
304         WARN("not supported interface %s\n", debugstr_guid(riid));
305     }
306
307     if(!*ppv)
308         return E_NOINTERFACE;
309
310     IUnknown_AddRef((IUnknown*)*ppv);
311     return S_OK;
312 }
313
314 static ULONG WINAPI BindProtocol_AddRef(IInternetProtocolEx *iface)
315 {
316     BindProtocol *This = impl_from_IInternetProtocolEx(iface);
317     LONG ref = InterlockedIncrement(&This->ref);
318     TRACE("(%p) ref=%d\n", This, ref);
319     return ref;
320 }
321
322 static ULONG WINAPI BindProtocol_Release(IInternetProtocolEx *iface)
323 {
324     BindProtocol *This = impl_from_IInternetProtocolEx(iface);
325     LONG ref = InterlockedDecrement(&This->ref);
326
327     TRACE("(%p) ref=%d\n", This, ref);
328
329     if(!ref) {
330         if(This->wininet_info)
331             IWinInetInfo_Release(This->wininet_info);
332         if(This->protocol)
333             IInternetProtocol_Release(This->protocol);
334         if(This->bind_info)
335             IInternetBindInfo_Release(This->bind_info);
336         if(This->protocol_handler && This->protocol_handler != &This->default_protocol_handler.IInternetProtocol_iface)
337             IInternetProtocol_Release(This->protocol_handler);
338         if(This->filter_proxy)
339             IInternetProtocol_Release(&This->filter_proxy->IInternetProtocol_iface);
340         if(This->uri)
341             IUri_Release(This->uri);
342
343         set_binding_sink(This, NULL, NULL);
344
345         if(This->notif_hwnd)
346             release_notif_hwnd(This->notif_hwnd);
347         DeleteCriticalSection(&This->section);
348
349         heap_free(This->mime);
350         heap_free(This);
351
352         URLMON_UnlockModule();
353     }
354
355     return ref;
356 }
357
358 static HRESULT WINAPI BindProtocol_Start(IInternetProtocolEx *iface, LPCWSTR szUrl,
359         IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
360         DWORD grfPI, HANDLE_PTR dwReserved)
361 {
362     BindProtocol *This = impl_from_IInternetProtocolEx(iface);
363     IUri *uri;
364     HRESULT hres;
365
366     TRACE("(%p)->(%s %p %p %08x %lx)\n", This, debugstr_w(szUrl), pOIProtSink,
367             pOIBindInfo, grfPI, dwReserved);
368
369     hres = CreateUri(szUrl, Uri_CREATE_FILE_USE_DOS_PATH, 0, &uri);
370     if(FAILED(hres))
371         return hres;
372
373     hres = IInternetProtocolEx_StartEx(&This->IInternetProtocolEx_iface, uri, pOIProtSink,
374             pOIBindInfo, grfPI, (HANDLE*)dwReserved);
375
376     IUri_Release(uri);
377     return hres;
378 }
379
380 static HRESULT WINAPI BindProtocol_Continue(IInternetProtocolEx *iface, PROTOCOLDATA *pProtocolData)
381 {
382     BindProtocol *This = impl_from_IInternetProtocolEx(iface);
383
384     TRACE("(%p)->(%p)\n", This, pProtocolData);
385
386     return IInternetProtocol_Continue(This->protocol_handler, pProtocolData);
387 }
388
389 static HRESULT WINAPI BindProtocol_Abort(IInternetProtocolEx *iface, HRESULT hrReason,
390         DWORD dwOptions)
391 {
392     BindProtocol *This = impl_from_IInternetProtocolEx(iface);
393
394     TRACE("(%p)->(%08x %08x)\n", This, hrReason, dwOptions);
395
396     return IInternetProtocol_Abort(This->protocol_handler, hrReason, dwOptions);
397 }
398
399 static HRESULT WINAPI BindProtocol_Terminate(IInternetProtocolEx *iface, DWORD dwOptions)
400 {
401     BindProtocol *This = impl_from_IInternetProtocolEx(iface);
402
403     TRACE("(%p)->(%08x)\n", This, dwOptions);
404
405     return IInternetProtocol_Terminate(This->protocol_handler, dwOptions);
406 }
407
408 static HRESULT WINAPI BindProtocol_Suspend(IInternetProtocolEx *iface)
409 {
410     BindProtocol *This = impl_from_IInternetProtocolEx(iface);
411     FIXME("(%p)\n", This);
412     return E_NOTIMPL;
413 }
414
415 static HRESULT WINAPI BindProtocol_Resume(IInternetProtocolEx *iface)
416 {
417     BindProtocol *This = impl_from_IInternetProtocolEx(iface);
418     FIXME("(%p)\n", This);
419     return E_NOTIMPL;
420 }
421
422 static HRESULT WINAPI BindProtocol_Read(IInternetProtocolEx *iface, void *pv,
423         ULONG cb, ULONG *pcbRead)
424 {
425     BindProtocol *This = impl_from_IInternetProtocolEx(iface);
426
427     TRACE("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead);
428
429     if(pcbRead)
430         *pcbRead = 0;
431     return IInternetProtocol_Read(This->protocol_handler, pv, cb, pcbRead);
432 }
433
434 static HRESULT WINAPI BindProtocol_Seek(IInternetProtocolEx *iface, LARGE_INTEGER dlibMove,
435         DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
436 {
437     BindProtocol *This = impl_from_IInternetProtocolEx(iface);
438     FIXME("(%p)->(%d %d %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
439     return E_NOTIMPL;
440 }
441
442 static HRESULT WINAPI BindProtocol_LockRequest(IInternetProtocolEx *iface, DWORD dwOptions)
443 {
444     BindProtocol *This = impl_from_IInternetProtocolEx(iface);
445
446     TRACE("(%p)->(%08x)\n", This, dwOptions);
447
448     return IInternetProtocol_LockRequest(This->protocol_handler, dwOptions);
449 }
450
451 static HRESULT WINAPI BindProtocol_UnlockRequest(IInternetProtocolEx *iface)
452 {
453     BindProtocol *This = impl_from_IInternetProtocolEx(iface);
454
455     TRACE("(%p)\n", This);
456
457     return IInternetProtocol_UnlockRequest(This->protocol_handler);
458 }
459
460 static HRESULT WINAPI BindProtocol_StartEx(IInternetProtocolEx *iface, IUri *pUri,
461         IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
462         DWORD grfPI, HANDLE *dwReserved)
463 {
464     BindProtocol *This = impl_from_IInternetProtocolEx(iface);
465     IInternetProtocol *protocol = NULL;
466     IInternetProtocolEx *protocolex;
467     IInternetPriority *priority;
468     IServiceProvider *service_provider;
469     BOOL urlmon_protocol = FALSE;
470     CLSID clsid = IID_NULL;
471     LPOLESTR clsid_str;
472     HRESULT hres;
473
474     TRACE("(%p)->(%p %p %p %08x %p)\n", This, pUri, pOIProtSink, pOIBindInfo, grfPI, dwReserved);
475
476     if(!pUri || !pOIProtSink || !pOIBindInfo)
477         return E_INVALIDARG;
478
479     This->pi = grfPI;
480
481     IUri_AddRef(pUri);
482     This->uri = pUri;
483
484     hres = IInternetProtocolSink_QueryInterface(pOIProtSink, &IID_IServiceProvider,
485                                                 (void**)&service_provider);
486     if(SUCCEEDED(hres)) {
487         /* FIXME: What's protocol CLSID here? */
488         IServiceProvider_QueryService(service_provider, &IID_IInternetProtocol,
489                 &IID_IInternetProtocol, (void**)&protocol);
490         IServiceProvider_Release(service_provider);
491     }
492
493     if(!protocol) {
494         IClassFactory *cf;
495         IUnknown *unk;
496
497         hres = get_protocol_handler(pUri, &clsid, &urlmon_protocol, &cf);
498         if(FAILED(hres))
499             return hres;
500
501         if(This->from_urlmon) {
502             hres = IClassFactory_CreateInstance(cf, NULL, &IID_IInternetProtocol, (void**)&protocol);
503             IClassFactory_Release(cf);
504             if(FAILED(hres))
505                 return hres;
506         }else {
507             hres = IClassFactory_CreateInstance(cf, (IUnknown*)&This->IInternetBindInfo_iface,
508                     &IID_IUnknown, (void**)&unk);
509             IClassFactory_Release(cf);
510             if(FAILED(hres))
511                 return hres;
512
513             hres = IUnknown_QueryInterface(unk, &IID_IInternetProtocol, (void**)&protocol);
514             IUnknown_Release(unk);
515             if(FAILED(hres))
516                 return hres;
517         }
518     }
519
520     StringFromCLSID(&clsid, &clsid_str);
521     IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_PROTOCOLCLASSID, clsid_str);
522     CoTaskMemFree(clsid_str);
523
524     This->protocol = protocol;
525
526     if(urlmon_protocol)
527         IInternetProtocol_QueryInterface(protocol, &IID_IWinInetInfo, (void**)&This->wininet_info);
528
529     set_binding_sink(This, pOIProtSink, pOIBindInfo);
530
531     hres = IInternetProtocol_QueryInterface(protocol, &IID_IInternetPriority, (void**)&priority);
532     if(SUCCEEDED(hres)) {
533         IInternetPriority_SetPriority(priority, This->priority);
534         IInternetPriority_Release(priority);
535     }
536
537     hres = IInternetProtocol_QueryInterface(protocol, &IID_IInternetProtocolEx, (void**)&protocolex);
538     if(SUCCEEDED(hres)) {
539         hres = IInternetProtocolEx_StartEx(protocolex, pUri, &This->IInternetProtocolSink_iface,
540                 &This->IInternetBindInfo_iface, 0, NULL);
541         IInternetProtocolEx_Release(protocolex);
542     }else {
543         BSTR display_uri;
544
545         hres = IUri_GetDisplayUri(pUri, &display_uri);
546         if(FAILED(hres))
547             return hres;
548
549         hres = IInternetProtocol_Start(protocol, display_uri, &This->IInternetProtocolSink_iface,
550                 &This->IInternetBindInfo_iface, 0, 0);
551         SysFreeString(display_uri);
552     }
553
554     return hres;
555 }
556
557 void set_binding_sink(BindProtocol *This, IInternetProtocolSink *sink, IInternetBindInfo *bind_info)
558 {
559     IInternetProtocolSink *prev_sink;
560     IServiceProvider *service_provider = NULL;
561
562     if(sink)
563         IInternetProtocolSink_AddRef(sink);
564     prev_sink = InterlockedExchangePointer((void**)&This->protocol_sink, sink);
565     if(prev_sink)
566         IInternetProtocolSink_Release(prev_sink);
567
568     if(sink)
569         IInternetProtocolSink_QueryInterface(sink, &IID_IServiceProvider, (void**)&service_provider);
570     service_provider = InterlockedExchangePointer((void**)&This->service_provider, service_provider);
571     if(service_provider)
572         IServiceProvider_Release(service_provider);
573
574     if(bind_info)
575         IInternetBindInfo_AddRef(bind_info);
576     bind_info = InterlockedExchangePointer((void**)&This->bind_info, bind_info);
577     if(bind_info)
578         IInternetBindInfo_Release(bind_info);
579 }
580
581 static const IInternetProtocolExVtbl BindProtocolVtbl = {
582     BindProtocol_QueryInterface,
583     BindProtocol_AddRef,
584     BindProtocol_Release,
585     BindProtocol_Start,
586     BindProtocol_Continue,
587     BindProtocol_Abort,
588     BindProtocol_Terminate,
589     BindProtocol_Suspend,
590     BindProtocol_Resume,
591     BindProtocol_Read,
592     BindProtocol_Seek,
593     BindProtocol_LockRequest,
594     BindProtocol_UnlockRequest,
595     BindProtocol_StartEx
596 };
597
598 static inline BindProtocol *impl_from_IInternetProtocol(IInternetProtocol *iface)
599 {
600     return CONTAINING_RECORD(iface, BindProtocol, default_protocol_handler.IInternetProtocol_iface);
601 }
602
603 static HRESULT WINAPI ProtocolHandler_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv)
604 {
605     ERR("should not be called\n");
606     return E_NOINTERFACE;
607 }
608
609 static ULONG WINAPI ProtocolHandler_AddRef(IInternetProtocol *iface)
610 {
611     BindProtocol *This = impl_from_IInternetProtocol(iface);
612     return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
613 }
614
615 static ULONG WINAPI ProtocolHandler_Release(IInternetProtocol *iface)
616 {
617     BindProtocol *This = impl_from_IInternetProtocol(iface);
618     return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
619 }
620
621 static HRESULT WINAPI ProtocolHandler_Start(IInternetProtocol *iface, LPCWSTR szUrl,
622         IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
623         DWORD grfPI, HANDLE_PTR dwReserved)
624 {
625     ERR("Should not be called\n");
626     return E_NOTIMPL;
627 }
628
629 static HRESULT WINAPI ProtocolHandler_Continue(IInternetProtocol *iface, PROTOCOLDATA *pProtocolData)
630 {
631     BindProtocol *This = impl_from_IInternetProtocol(iface);
632     HRESULT hres;
633
634     TRACE("(%p)->(%p)\n", This, pProtocolData);
635
636     hres = IInternetProtocol_Continue(This->protocol, pProtocolData);
637
638     heap_free(pProtocolData);
639     return hres;
640 }
641
642 static HRESULT WINAPI ProtocolHandler_Abort(IInternetProtocol *iface, HRESULT hrReason,
643         DWORD dwOptions)
644 {
645     BindProtocol *This = impl_from_IInternetProtocol(iface);
646
647     TRACE("(%p)->(%08x %08x)\n", This, hrReason, dwOptions);
648
649     if(This->protocol && !This->reported_result)
650         return IInternetProtocol_Abort(This->protocol, hrReason, dwOptions);
651
652     return S_OK;
653 }
654
655 static HRESULT WINAPI ProtocolHandler_Terminate(IInternetProtocol *iface, DWORD dwOptions)
656 {
657     BindProtocol *This = impl_from_IInternetProtocol(iface);
658
659     TRACE("(%p)->(%08x)\n", This, dwOptions);
660
661     if(!This->reported_result)
662         return E_FAIL;
663
664     IInternetProtocol_Terminate(This->protocol, 0);
665
666     if(This->filter_proxy) {
667         IInternetProtocol_Release(&This->filter_proxy->IInternetProtocol_iface);
668         This->filter_proxy = NULL;
669     }
670
671     set_binding_sink(This, NULL, NULL);
672
673     if(This->bind_info) {
674         IInternetBindInfo_Release(This->bind_info);
675         This->bind_info = NULL;
676     }
677
678     return S_OK;
679 }
680
681 static HRESULT WINAPI ProtocolHandler_Suspend(IInternetProtocol *iface)
682 {
683     BindProtocol *This = impl_from_IInternetProtocol(iface);
684     FIXME("(%p)\n", This);
685     return E_NOTIMPL;
686 }
687
688 static HRESULT WINAPI ProtocolHandler_Resume(IInternetProtocol *iface)
689 {
690     BindProtocol *This = impl_from_IInternetProtocol(iface);
691     FIXME("(%p)\n", This);
692     return E_NOTIMPL;
693 }
694
695 static HRESULT WINAPI ProtocolHandler_Read(IInternetProtocol *iface, void *pv,
696         ULONG cb, ULONG *pcbRead)
697 {
698     BindProtocol *This = impl_from_IInternetProtocol(iface);
699     ULONG read = 0;
700     HRESULT hres = S_OK;
701
702     TRACE("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead);
703
704     if(This->buf_size) {
705         read = min(cb, This->buf_size);
706         memcpy(pv, This->buf, read);
707
708         if(read == This->buf_size) {
709             heap_free(This->buf);
710             This->buf = NULL;
711         }else {
712             memmove(This->buf, This->buf+cb, This->buf_size-cb);
713         }
714
715         This->buf_size -= read;
716     }
717
718     if(read < cb) {
719         ULONG cread = 0;
720
721         hres = IInternetProtocol_Read(This->protocol, (BYTE*)pv+read, cb-read, &cread);
722         read += cread;
723     }
724
725     *pcbRead = read;
726     return hres;
727 }
728
729 static HRESULT WINAPI ProtocolHandler_Seek(IInternetProtocol *iface, LARGE_INTEGER dlibMove,
730         DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
731 {
732     BindProtocol *This = impl_from_IInternetProtocol(iface);
733     FIXME("(%p)->(%d %d %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
734     return E_NOTIMPL;
735 }
736
737 static HRESULT WINAPI ProtocolHandler_LockRequest(IInternetProtocol *iface, DWORD dwOptions)
738 {
739     BindProtocol *This = impl_from_IInternetProtocol(iface);
740
741     TRACE("(%p)->(%08x)\n", This, dwOptions);
742
743     return IInternetProtocol_LockRequest(This->protocol, dwOptions);
744 }
745
746 static HRESULT WINAPI ProtocolHandler_UnlockRequest(IInternetProtocol *iface)
747 {
748     BindProtocol *This = impl_from_IInternetProtocol(iface);
749
750     TRACE("(%p)\n", This);
751
752     return IInternetProtocol_UnlockRequest(This->protocol);
753 }
754
755 static const IInternetProtocolVtbl InternetProtocolHandlerVtbl = {
756     ProtocolHandler_QueryInterface,
757     ProtocolHandler_AddRef,
758     ProtocolHandler_Release,
759     ProtocolHandler_Start,
760     ProtocolHandler_Continue,
761     ProtocolHandler_Abort,
762     ProtocolHandler_Terminate,
763     ProtocolHandler_Suspend,
764     ProtocolHandler_Resume,
765     ProtocolHandler_Read,
766     ProtocolHandler_Seek,
767     ProtocolHandler_LockRequest,
768     ProtocolHandler_UnlockRequest
769 };
770
771 static inline BindProtocol *impl_from_IInternetBindInfo(IInternetBindInfo *iface)
772 {
773     return CONTAINING_RECORD(iface, BindProtocol, IInternetBindInfo_iface);
774 }
775
776 static HRESULT WINAPI BindInfo_QueryInterface(IInternetBindInfo *iface,
777         REFIID riid, void **ppv)
778 {
779     BindProtocol *This = impl_from_IInternetBindInfo(iface);
780     return IInternetProtocolEx_QueryInterface(&This->IInternetProtocolEx_iface, riid, ppv);
781 }
782
783 static ULONG WINAPI BindInfo_AddRef(IInternetBindInfo *iface)
784 {
785     BindProtocol *This = impl_from_IInternetBindInfo(iface);
786     return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
787 }
788
789 static ULONG WINAPI BindInfo_Release(IInternetBindInfo *iface)
790 {
791     BindProtocol *This = impl_from_IInternetBindInfo(iface);
792     return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
793 }
794
795 static HRESULT WINAPI BindInfo_GetBindInfo(IInternetBindInfo *iface,
796         DWORD *grfBINDF, BINDINFO *pbindinfo)
797 {
798     BindProtocol *This = impl_from_IInternetBindInfo(iface);
799     HRESULT hres;
800
801     TRACE("(%p)->(%p %p)\n", This, grfBINDF, pbindinfo);
802
803     hres = IInternetBindInfo_GetBindInfo(This->bind_info, grfBINDF, pbindinfo);
804     if(FAILED(hres)) {
805         WARN("GetBindInfo failed: %08x\n", hres);
806         return hres;
807     }
808
809     *grfBINDF |= BINDF_FROMURLMON;
810     return hres;
811 }
812
813 static HRESULT WINAPI BindInfo_GetBindString(IInternetBindInfo *iface,
814         ULONG ulStringType, LPOLESTR *ppwzStr, ULONG cEl, ULONG *pcElFetched)
815 {
816     BindProtocol *This = impl_from_IInternetBindInfo(iface);
817
818     TRACE("(%p)->(%d %p %d %p)\n", This, ulStringType, ppwzStr, cEl, pcElFetched);
819
820     return IInternetBindInfo_GetBindString(This->bind_info, ulStringType, ppwzStr, cEl, pcElFetched);
821 }
822
823 static const IInternetBindInfoVtbl InternetBindInfoVtbl = {
824     BindInfo_QueryInterface,
825     BindInfo_AddRef,
826     BindInfo_Release,
827     BindInfo_GetBindInfo,
828     BindInfo_GetBindString
829 };
830
831 static inline BindProtocol *impl_from_IInternetPriority(IInternetPriority *iface)
832 {
833     return CONTAINING_RECORD(iface, BindProtocol, IInternetPriority_iface);
834 }
835
836 static HRESULT WINAPI InternetPriority_QueryInterface(IInternetPriority *iface,
837         REFIID riid, void **ppv)
838 {
839     BindProtocol *This = impl_from_IInternetPriority(iface);
840     return IInternetProtocolEx_QueryInterface(&This->IInternetProtocolEx_iface, riid, ppv);
841 }
842
843 static ULONG WINAPI InternetPriority_AddRef(IInternetPriority *iface)
844 {
845     BindProtocol *This = impl_from_IInternetPriority(iface);
846     return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
847 }
848
849 static ULONG WINAPI InternetPriority_Release(IInternetPriority *iface)
850 {
851     BindProtocol *This = impl_from_IInternetPriority(iface);
852     return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
853 }
854
855 static HRESULT WINAPI InternetPriority_SetPriority(IInternetPriority *iface, LONG nPriority)
856 {
857     BindProtocol *This = impl_from_IInternetPriority(iface);
858
859     TRACE("(%p)->(%d)\n", This, nPriority);
860
861     This->priority = nPriority;
862     return S_OK;
863 }
864
865 static HRESULT WINAPI InternetPriority_GetPriority(IInternetPriority *iface, LONG *pnPriority)
866 {
867     BindProtocol *This = impl_from_IInternetPriority(iface);
868
869     TRACE("(%p)->(%p)\n", This, pnPriority);
870
871     *pnPriority = This->priority;
872     return S_OK;
873 }
874
875 static const IInternetPriorityVtbl InternetPriorityVtbl = {
876     InternetPriority_QueryInterface,
877     InternetPriority_AddRef,
878     InternetPriority_Release,
879     InternetPriority_SetPriority,
880     InternetPriority_GetPriority
881
882 };
883
884 static inline BindProtocol *impl_from_IInternetProtocolSink(IInternetProtocolSink *iface)
885 {
886     return CONTAINING_RECORD(iface, BindProtocol, IInternetProtocolSink_iface);
887 }
888
889 static HRESULT WINAPI BPInternetProtocolSink_QueryInterface(IInternetProtocolSink *iface,
890         REFIID riid, void **ppv)
891 {
892     BindProtocol *This = impl_from_IInternetProtocolSink(iface);
893     return IInternetProtocolEx_QueryInterface(&This->IInternetProtocolEx_iface, riid, ppv);
894 }
895
896 static ULONG WINAPI BPInternetProtocolSink_AddRef(IInternetProtocolSink *iface)
897 {
898     BindProtocol *This = impl_from_IInternetProtocolSink(iface);
899     return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
900 }
901
902 static ULONG WINAPI BPInternetProtocolSink_Release(IInternetProtocolSink *iface)
903 {
904     BindProtocol *This = impl_from_IInternetProtocolSink(iface);
905     return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
906 }
907
908 typedef struct {
909     task_header_t header;
910     PROTOCOLDATA *data;
911 } switch_task_t;
912
913 static void switch_proc(BindProtocol *bind, task_header_t *t)
914 {
915     switch_task_t *task = (switch_task_t*)t;
916
917     IInternetProtocol_Continue(bind->protocol_handler, task->data);
918
919     heap_free(task);
920 }
921
922 static HRESULT WINAPI BPInternetProtocolSink_Switch(IInternetProtocolSink *iface,
923         PROTOCOLDATA *pProtocolData)
924 {
925     BindProtocol *This = impl_from_IInternetProtocolSink(iface);
926     PROTOCOLDATA *data;
927
928     TRACE("(%p)->(%p)\n", This, pProtocolData);
929
930     TRACE("flags %x state %x data %p cb %u\n", pProtocolData->grfFlags, pProtocolData->dwState,
931           pProtocolData->pData, pProtocolData->cbData);
932
933     data = heap_alloc(sizeof(PROTOCOLDATA));
934     if(!data)
935         return E_OUTOFMEMORY;
936     memcpy(data, pProtocolData, sizeof(PROTOCOLDATA));
937
938     if(!do_direct_notif(This)) {
939         switch_task_t *task;
940
941         task = heap_alloc(sizeof(switch_task_t));
942         if(!task)
943             return E_OUTOFMEMORY;
944
945         task->data = data;
946
947         push_task(This, &task->header, switch_proc);
948         return S_OK;
949     }
950
951     if(!This->protocol_sink) {
952         IInternetProtocol_Continue(This->protocol_handler, data);
953         return S_OK;
954     }
955
956     return IInternetProtocolSink_Switch(This->protocol_sink, data);
957 }
958
959 static void report_progress(BindProtocol *This, ULONG status_code, LPCWSTR status_text)
960 {
961     switch(status_code) {
962     case BINDSTATUS_FINDINGRESOURCE:
963     case BINDSTATUS_CONNECTING:
964     case BINDSTATUS_REDIRECTING:
965     case BINDSTATUS_BEGINDOWNLOADDATA:
966     case BINDSTATUS_SENDINGREQUEST:
967     case BINDSTATUS_CACHEFILENAMEAVAILABLE:
968     case BINDSTATUS_DIRECTBIND:
969     case BINDSTATUS_ACCEPTRANGES:
970         if(This->protocol_sink)
971             IInternetProtocolSink_ReportProgress(This->protocol_sink, status_code, status_text);
972         break;
973
974     case BINDSTATUS_MIMETYPEAVAILABLE:
975         mime_available(This, status_text, FALSE);
976         break;
977
978     case BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE:
979         mime_available(This, status_text, TRUE);
980         break;
981
982     default:
983         FIXME("unsupported ulStatusCode %u\n", status_code);
984     }
985 }
986
987 typedef struct {
988     task_header_t header;
989
990     ULONG status_code;
991     LPWSTR status_text;
992 } on_progress_task_t;
993
994 static void on_progress_proc(BindProtocol *This, task_header_t *t)
995 {
996     on_progress_task_t *task = (on_progress_task_t*)t;
997
998     report_progress(This, task->status_code, task->status_text);
999
1000     heap_free(task->status_text);
1001     heap_free(task);
1002 }
1003
1004 static HRESULT WINAPI BPInternetProtocolSink_ReportProgress(IInternetProtocolSink *iface,
1005         ULONG ulStatusCode, LPCWSTR szStatusText)
1006 {
1007     BindProtocol *This = impl_from_IInternetProtocolSink(iface);
1008
1009     TRACE("(%p)->(%u %s)\n", This, ulStatusCode, debugstr_w(szStatusText));
1010
1011     if(do_direct_notif(This)) {
1012         report_progress(This, ulStatusCode, szStatusText);
1013     }else {
1014         on_progress_task_t *task;
1015
1016         task = heap_alloc(sizeof(on_progress_task_t));
1017
1018         task->status_code = ulStatusCode;
1019         task->status_text = heap_strdupW(szStatusText);
1020
1021         push_task(This, &task->header, on_progress_proc);
1022     }
1023
1024     return S_OK;
1025 }
1026
1027 static HRESULT report_data(BindProtocol *This, DWORD bscf, ULONG progress, ULONG progress_max)
1028 {
1029     if(!This->protocol_sink)
1030         return S_OK;
1031
1032     if((This->pi & PI_MIMEVERIFICATION) && !This->reported_mime) {
1033         BYTE buf[BUFFER_SIZE];
1034         DWORD read = 0;
1035         LPWSTR mime;
1036         HRESULT hres;
1037
1038         do {
1039             read = 0;
1040             hres = IInternetProtocol_Read(This->protocol, buf,
1041                     sizeof(buf)-This->buf_size, &read);
1042             if(FAILED(hres) && hres != E_PENDING)
1043                 return hres;
1044
1045             if(!This->buf) {
1046                 This->buf = heap_alloc(BUFFER_SIZE);
1047                 if(!This->buf)
1048                     return E_OUTOFMEMORY;
1049             }else if(read + This->buf_size > BUFFER_SIZE) {
1050                 BYTE *tmp;
1051
1052                 tmp = heap_realloc(This->buf, read+This->buf_size);
1053                 if(!tmp)
1054                     return E_OUTOFMEMORY;
1055                 This->buf = tmp;
1056             }
1057
1058             memcpy(This->buf+This->buf_size, buf, read);
1059             This->buf_size += read;
1060         }while(This->buf_size < MIME_TEST_SIZE && hres == S_OK);
1061
1062         if(This->buf_size < MIME_TEST_SIZE && hres != S_FALSE)
1063             return S_OK;
1064
1065         bscf = BSCF_FIRSTDATANOTIFICATION;
1066         if(hres == S_FALSE)
1067             bscf |= BSCF_LASTDATANOTIFICATION|BSCF_DATAFULLYAVAILABLE;
1068
1069         if(!This->reported_mime) {
1070             BSTR raw_uri;
1071
1072             hres = IUri_GetRawUri(This->uri, &raw_uri);
1073             if(FAILED(hres))
1074                 return hres;
1075
1076             hres = FindMimeFromData(NULL, raw_uri, This->buf, min(This->buf_size, MIME_TEST_SIZE),
1077                     This->mime, 0, &mime, 0);
1078             SysFreeString(raw_uri);
1079             if(FAILED(hres))
1080                 return hres;
1081
1082             mime_available(This, mime, TRUE);
1083             CoTaskMemFree(mime);
1084         }
1085     }
1086
1087     if(!This->protocol_sink)
1088         return S_OK;
1089
1090     return IInternetProtocolSink_ReportData(This->protocol_sink, bscf, progress, progress_max);
1091 }
1092
1093 typedef struct {
1094     task_header_t header;
1095     DWORD bscf;
1096     ULONG progress;
1097     ULONG progress_max;
1098 } report_data_task_t;
1099
1100 static void report_data_proc(BindProtocol *This, task_header_t *t)
1101 {
1102     report_data_task_t *task = (report_data_task_t*)t;
1103
1104     report_data(This, task->bscf, task->progress, task->progress_max);
1105     heap_free(task);
1106 }
1107
1108 static HRESULT WINAPI BPInternetProtocolSink_ReportData(IInternetProtocolSink *iface,
1109         DWORD grfBSCF, ULONG ulProgress, ULONG ulProgressMax)
1110 {
1111     BindProtocol *This = impl_from_IInternetProtocolSink(iface);
1112
1113     TRACE("(%p)->(%d %u %u)\n", This, grfBSCF, ulProgress, ulProgressMax);
1114
1115     if(!This->protocol_sink)
1116         return S_OK;
1117
1118     if(!do_direct_notif(This)) {
1119         report_data_task_t *task;
1120
1121         task = heap_alloc(sizeof(report_data_task_t));
1122         if(!task)
1123             return E_OUTOFMEMORY;
1124
1125         task->bscf = grfBSCF;
1126         task->progress = ulProgress;
1127         task->progress_max = ulProgressMax;
1128
1129         push_task(This, &task->header, report_data_proc);
1130         return S_OK;
1131     }
1132
1133     return report_data(This, grfBSCF, ulProgress, ulProgressMax);
1134 }
1135
1136 typedef struct {
1137     task_header_t header;
1138
1139     HRESULT hres;
1140     DWORD err;
1141     LPWSTR str;
1142 } report_result_task_t;
1143
1144 static void report_result_proc(BindProtocol *This, task_header_t *t)
1145 {
1146     report_result_task_t *task = (report_result_task_t*)t;
1147
1148     if(This->protocol_sink)
1149         IInternetProtocolSink_ReportResult(This->protocol_sink, task->hres, task->err, task->str);
1150
1151     heap_free(task->str);
1152     heap_free(task);
1153 }
1154
1155 static HRESULT WINAPI BPInternetProtocolSink_ReportResult(IInternetProtocolSink *iface,
1156         HRESULT hrResult, DWORD dwError, LPCWSTR szResult)
1157 {
1158     BindProtocol *This = impl_from_IInternetProtocolSink(iface);
1159
1160     TRACE("(%p)->(%08x %d %s)\n", This, hrResult, dwError, debugstr_w(szResult));
1161
1162     if(!This->protocol_sink)
1163         return E_FAIL;
1164
1165     This->reported_result = TRUE;
1166
1167     if(!do_direct_notif(This)) {
1168         report_result_task_t *task;
1169
1170         task = heap_alloc(sizeof(report_result_task_t));
1171         if(!task)
1172             return E_OUTOFMEMORY;
1173
1174         task->hres = hrResult;
1175         task->err = dwError;
1176         task->str = heap_strdupW(szResult);
1177
1178         push_task(This, &task->header, report_result_proc);
1179         return S_OK;
1180     }
1181
1182     return IInternetProtocolSink_ReportResult(This->protocol_sink, hrResult, dwError, szResult);
1183 }
1184
1185 static const IInternetProtocolSinkVtbl InternetProtocolSinkVtbl = {
1186     BPInternetProtocolSink_QueryInterface,
1187     BPInternetProtocolSink_AddRef,
1188     BPInternetProtocolSink_Release,
1189     BPInternetProtocolSink_Switch,
1190     BPInternetProtocolSink_ReportProgress,
1191     BPInternetProtocolSink_ReportData,
1192     BPInternetProtocolSink_ReportResult
1193 };
1194
1195 static inline BindProtocol *impl_from_IWinInetHttpInfo(IWinInetHttpInfo *iface)
1196 {
1197     return CONTAINING_RECORD(iface, BindProtocol, IWinInetHttpInfo_iface);
1198 }
1199
1200 static HRESULT WINAPI WinInetHttpInfo_QueryInterface(IWinInetHttpInfo *iface, REFIID riid, void **ppv)
1201 {
1202     BindProtocol *This = impl_from_IWinInetHttpInfo(iface);
1203     return IInternetProtocolEx_QueryInterface(&This->IInternetProtocolEx_iface, riid, ppv);
1204 }
1205
1206 static ULONG WINAPI WinInetHttpInfo_AddRef(IWinInetHttpInfo *iface)
1207 {
1208     BindProtocol *This = impl_from_IWinInetHttpInfo(iface);
1209     return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
1210 }
1211
1212 static ULONG WINAPI WinInetHttpInfo_Release(IWinInetHttpInfo *iface)
1213 {
1214     BindProtocol *This = impl_from_IWinInetHttpInfo(iface);
1215     return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
1216 }
1217
1218 static HRESULT WINAPI WinInetHttpInfo_QueryOption(IWinInetHttpInfo *iface, DWORD dwOption,
1219         void *pBuffer, DWORD *pcbBuffer)
1220 {
1221     BindProtocol *This = impl_from_IWinInetHttpInfo(iface);
1222     FIXME("(%p)->(%x %p %p)\n", This, dwOption, pBuffer, pcbBuffer);
1223     return E_NOTIMPL;
1224 }
1225
1226 static HRESULT WINAPI WinInetHttpInfo_QueryInfo(IWinInetHttpInfo *iface, DWORD dwOption,
1227         void *pBuffer, DWORD *pcbBuffer, DWORD *pdwFlags, DWORD *pdwReserved)
1228 {
1229     BindProtocol *This = impl_from_IWinInetHttpInfo(iface);
1230     FIXME("(%p)->(%x %p %p %p %p)\n", This, dwOption, pBuffer, pcbBuffer, pdwFlags, pdwReserved);
1231     return E_NOTIMPL;
1232 }
1233
1234 static const IWinInetHttpInfoVtbl WinInetHttpInfoVtbl = {
1235     WinInetHttpInfo_QueryInterface,
1236     WinInetHttpInfo_AddRef,
1237     WinInetHttpInfo_Release,
1238     WinInetHttpInfo_QueryOption,
1239     WinInetHttpInfo_QueryInfo
1240 };
1241
1242 static inline BindProtocol *impl_from_IServiceProvider(IServiceProvider *iface)
1243 {
1244     return CONTAINING_RECORD(iface, BindProtocol, IServiceProvider_iface);
1245 }
1246
1247 static HRESULT WINAPI BPServiceProvider_QueryInterface(IServiceProvider *iface,
1248         REFIID riid, void **ppv)
1249 {
1250     BindProtocol *This = impl_from_IServiceProvider(iface);
1251     return IInternetProtocolEx_QueryInterface(&This->IInternetProtocolEx_iface, riid, ppv);
1252 }
1253
1254 static ULONG WINAPI BPServiceProvider_AddRef(IServiceProvider *iface)
1255 {
1256     BindProtocol *This = impl_from_IServiceProvider(iface);
1257     return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
1258 }
1259
1260 static ULONG WINAPI BPServiceProvider_Release(IServiceProvider *iface)
1261 {
1262     BindProtocol *This = impl_from_IServiceProvider(iface);
1263     return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
1264 }
1265
1266 static HRESULT WINAPI BPServiceProvider_QueryService(IServiceProvider *iface,
1267         REFGUID guidService, REFIID riid, void **ppv)
1268 {
1269     BindProtocol *This = impl_from_IServiceProvider(iface);
1270
1271     TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
1272
1273     if(!This->service_provider)
1274         return E_NOINTERFACE;
1275
1276     return IServiceProvider_QueryService(This->service_provider, guidService, riid, ppv);
1277 }
1278
1279 static const IServiceProviderVtbl ServiceProviderVtbl = {
1280     BPServiceProvider_QueryInterface,
1281     BPServiceProvider_AddRef,
1282     BPServiceProvider_Release,
1283     BPServiceProvider_QueryService
1284 };
1285
1286 HRESULT create_binding_protocol(BOOL from_urlmon, BindProtocol **protocol)
1287 {
1288     BindProtocol *ret = heap_alloc_zero(sizeof(BindProtocol));
1289
1290     ret->IInternetProtocolEx_iface.lpVtbl   = &BindProtocolVtbl;
1291     ret->IInternetBindInfo_iface.lpVtbl     = &InternetBindInfoVtbl;
1292     ret->IInternetPriority_iface.lpVtbl     = &InternetPriorityVtbl;
1293     ret->IServiceProvider_iface.lpVtbl      = &ServiceProviderVtbl;
1294     ret->IInternetProtocolSink_iface.lpVtbl = &InternetProtocolSinkVtbl;
1295     ret->IWinInetHttpInfo_iface.lpVtbl      = &WinInetHttpInfoVtbl;
1296
1297     ret->default_protocol_handler.IInternetProtocol_iface.lpVtbl = &InternetProtocolHandlerVtbl;
1298
1299     ret->ref = 1;
1300     ret->from_urlmon = from_urlmon;
1301     ret->apartment_thread = GetCurrentThreadId();
1302     ret->notif_hwnd = get_notif_hwnd();
1303     ret->protocol_handler = &ret->default_protocol_handler.IInternetProtocol_iface;
1304     InitializeCriticalSection(&ret->section);
1305
1306     URLMON_LockModule();
1307
1308     *protocol = ret;
1309     return S_OK;
1310 }