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