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