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