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