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