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