Release 1.5.29.
[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             if(is_apartment_thread(This))
901                 This->continue_call++;
902             hres = IInternetProtocol_Read(This->protocol, buf,
903                     sizeof(buf)-This->buf_size, &read);
904             if(is_apartment_thread(This))
905                 This->continue_call--;
906             if(FAILED(hres) && hres != E_PENDING)
907                 return hres;
908
909             if(!This->buf) {
910                 This->buf = heap_alloc(BUFFER_SIZE);
911                 if(!This->buf)
912                     return E_OUTOFMEMORY;
913             }else if(read + This->buf_size > BUFFER_SIZE) {
914                 BYTE *tmp;
915
916                 tmp = heap_realloc(This->buf, read+This->buf_size);
917                 if(!tmp)
918                     return E_OUTOFMEMORY;
919                 This->buf = tmp;
920             }
921
922             memcpy(This->buf+This->buf_size, buf, read);
923             This->buf_size += read;
924         }while(This->buf_size < MIME_TEST_SIZE && hres == S_OK);
925
926         if(This->buf_size < MIME_TEST_SIZE && hres != S_FALSE)
927             return S_OK;
928
929         bscf = BSCF_FIRSTDATANOTIFICATION;
930         if(hres == S_FALSE)
931             bscf |= BSCF_LASTDATANOTIFICATION|BSCF_DATAFULLYAVAILABLE;
932
933         if(!This->reported_mime) {
934             BSTR raw_uri;
935
936             hres = IUri_GetRawUri(This->uri, &raw_uri);
937             if(FAILED(hres))
938                 return hres;
939
940             hres = FindMimeFromData(NULL, raw_uri, This->buf, min(This->buf_size, MIME_TEST_SIZE),
941                     This->mime, 0, &mime, 0);
942             SysFreeString(raw_uri);
943             if(FAILED(hres))
944                 return hres;
945
946             heap_free(This->mime);
947             This->mime = heap_strdupW(mime);
948             CoTaskMemFree(mime);
949             This->reported_mime = TRUE;
950             if(This->protocol_sink)
951                 IInternetProtocolSink_ReportProgress(This->protocol_sink, BINDSTATUS_MIMETYPEAVAILABLE, This->mime);
952         }
953     }
954
955     if(!This->protocol_sink)
956         return S_OK;
957
958     return IInternetProtocolSink_ReportData(This->protocol_sink, bscf, progress, progress_max);
959 }
960
961 static HRESULT WINAPI ProtocolSinkHandler_ReportResult(IInternetProtocolSink *iface,
962         HRESULT hrResult, DWORD dwError, LPCWSTR szResult)
963 {
964     BindProtocol *This = impl_from_IInternetProtocolSinkHandler(iface);
965
966     TRACE("(%p)->(%08x %d %s)\n", This, hrResult, dwError, debugstr_w(szResult));
967
968     if(This->protocol_sink)
969         return IInternetProtocolSink_ReportResult(This->protocol_sink, hrResult, dwError, szResult);
970     return S_OK;
971 }
972
973 static const IInternetProtocolSinkVtbl InternetProtocolSinkHandlerVtbl = {
974     ProtocolSinkHandler_QueryInterface,
975     ProtocolSinkHandler_AddRef,
976     ProtocolSinkHandler_Release,
977     ProtocolSinkHandler_Switch,
978     ProtocolSinkHandler_ReportProgress,
979     ProtocolSinkHandler_ReportData,
980     ProtocolSinkHandler_ReportResult
981 };
982
983 static inline BindProtocol *impl_from_IInternetBindInfo(IInternetBindInfo *iface)
984 {
985     return CONTAINING_RECORD(iface, BindProtocol, IInternetBindInfo_iface);
986 }
987
988 static HRESULT WINAPI BindInfo_QueryInterface(IInternetBindInfo *iface,
989         REFIID riid, void **ppv)
990 {
991     BindProtocol *This = impl_from_IInternetBindInfo(iface);
992     return IInternetProtocolEx_QueryInterface(&This->IInternetProtocolEx_iface, riid, ppv);
993 }
994
995 static ULONG WINAPI BindInfo_AddRef(IInternetBindInfo *iface)
996 {
997     BindProtocol *This = impl_from_IInternetBindInfo(iface);
998     return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
999 }
1000
1001 static ULONG WINAPI BindInfo_Release(IInternetBindInfo *iface)
1002 {
1003     BindProtocol *This = impl_from_IInternetBindInfo(iface);
1004     return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
1005 }
1006
1007 static HRESULT WINAPI BindInfo_GetBindInfo(IInternetBindInfo *iface,
1008         DWORD *grfBINDF, BINDINFO *pbindinfo)
1009 {
1010     BindProtocol *This = impl_from_IInternetBindInfo(iface);
1011     HRESULT hres;
1012
1013     TRACE("(%p)->(%p %p)\n", This, grfBINDF, pbindinfo);
1014
1015     hres = IInternetBindInfo_GetBindInfo(This->bind_info, grfBINDF, pbindinfo);
1016     if(FAILED(hres)) {
1017         WARN("GetBindInfo failed: %08x\n", hres);
1018         return hres;
1019     }
1020
1021     *grfBINDF |= BINDF_FROMURLMON;
1022     return hres;
1023 }
1024
1025 static HRESULT WINAPI BindInfo_GetBindString(IInternetBindInfo *iface,
1026         ULONG ulStringType, LPOLESTR *ppwzStr, ULONG cEl, ULONG *pcElFetched)
1027 {
1028     BindProtocol *This = impl_from_IInternetBindInfo(iface);
1029
1030     TRACE("(%p)->(%d %p %d %p)\n", This, ulStringType, ppwzStr, cEl, pcElFetched);
1031
1032     return IInternetBindInfo_GetBindString(This->bind_info, ulStringType, ppwzStr, cEl, pcElFetched);
1033 }
1034
1035 static const IInternetBindInfoVtbl InternetBindInfoVtbl = {
1036     BindInfo_QueryInterface,
1037     BindInfo_AddRef,
1038     BindInfo_Release,
1039     BindInfo_GetBindInfo,
1040     BindInfo_GetBindString
1041 };
1042
1043 static inline BindProtocol *impl_from_IInternetPriority(IInternetPriority *iface)
1044 {
1045     return CONTAINING_RECORD(iface, BindProtocol, IInternetPriority_iface);
1046 }
1047
1048 static HRESULT WINAPI InternetPriority_QueryInterface(IInternetPriority *iface,
1049         REFIID riid, void **ppv)
1050 {
1051     BindProtocol *This = impl_from_IInternetPriority(iface);
1052     return IInternetProtocolEx_QueryInterface(&This->IInternetProtocolEx_iface, riid, ppv);
1053 }
1054
1055 static ULONG WINAPI InternetPriority_AddRef(IInternetPriority *iface)
1056 {
1057     BindProtocol *This = impl_from_IInternetPriority(iface);
1058     return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
1059 }
1060
1061 static ULONG WINAPI InternetPriority_Release(IInternetPriority *iface)
1062 {
1063     BindProtocol *This = impl_from_IInternetPriority(iface);
1064     return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
1065 }
1066
1067 static HRESULT WINAPI InternetPriority_SetPriority(IInternetPriority *iface, LONG nPriority)
1068 {
1069     BindProtocol *This = impl_from_IInternetPriority(iface);
1070
1071     TRACE("(%p)->(%d)\n", This, nPriority);
1072
1073     This->priority = nPriority;
1074     return S_OK;
1075 }
1076
1077 static HRESULT WINAPI InternetPriority_GetPriority(IInternetPriority *iface, LONG *pnPriority)
1078 {
1079     BindProtocol *This = impl_from_IInternetPriority(iface);
1080
1081     TRACE("(%p)->(%p)\n", This, pnPriority);
1082
1083     *pnPriority = This->priority;
1084     return S_OK;
1085 }
1086
1087 static const IInternetPriorityVtbl InternetPriorityVtbl = {
1088     InternetPriority_QueryInterface,
1089     InternetPriority_AddRef,
1090     InternetPriority_Release,
1091     InternetPriority_SetPriority,
1092     InternetPriority_GetPriority
1093
1094 };
1095
1096 static inline BindProtocol *impl_from_IInternetProtocolSink(IInternetProtocolSink *iface)
1097 {
1098     return CONTAINING_RECORD(iface, BindProtocol, IInternetProtocolSink_iface);
1099 }
1100
1101 static HRESULT WINAPI BPInternetProtocolSink_QueryInterface(IInternetProtocolSink *iface,
1102         REFIID riid, void **ppv)
1103 {
1104     BindProtocol *This = impl_from_IInternetProtocolSink(iface);
1105     return IInternetProtocolEx_QueryInterface(&This->IInternetProtocolEx_iface, riid, ppv);
1106 }
1107
1108 static ULONG WINAPI BPInternetProtocolSink_AddRef(IInternetProtocolSink *iface)
1109 {
1110     BindProtocol *This = impl_from_IInternetProtocolSink(iface);
1111     return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
1112 }
1113
1114 static ULONG WINAPI BPInternetProtocolSink_Release(IInternetProtocolSink *iface)
1115 {
1116     BindProtocol *This = impl_from_IInternetProtocolSink(iface);
1117     return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
1118 }
1119
1120 typedef struct {
1121     task_header_t header;
1122     PROTOCOLDATA *data;
1123 } switch_task_t;
1124
1125 static void switch_proc(BindProtocol *bind, task_header_t *t)
1126 {
1127     switch_task_t *task = (switch_task_t*)t;
1128
1129     IInternetProtocol_Continue(bind->protocol_handler, task->data);
1130
1131     heap_free(task);
1132 }
1133
1134 static HRESULT WINAPI BPInternetProtocolSink_Switch(IInternetProtocolSink *iface,
1135         PROTOCOLDATA *pProtocolData)
1136 {
1137     BindProtocol *This = impl_from_IInternetProtocolSink(iface);
1138     PROTOCOLDATA *data;
1139
1140     TRACE("(%p)->(%p)\n", This, pProtocolData);
1141
1142     TRACE("flags %x state %x data %p cb %u\n", pProtocolData->grfFlags, pProtocolData->dwState,
1143           pProtocolData->pData, pProtocolData->cbData);
1144
1145     data = heap_alloc(sizeof(PROTOCOLDATA));
1146     if(!data)
1147         return E_OUTOFMEMORY;
1148     memcpy(data, pProtocolData, sizeof(PROTOCOLDATA));
1149
1150     if((This->pi&PI_APARTMENTTHREADED && pProtocolData->grfFlags&PI_FORCE_ASYNC)
1151             || !do_direct_notif(This)) {
1152         switch_task_t *task;
1153
1154         task = heap_alloc(sizeof(switch_task_t));
1155         if(!task)
1156         {
1157             heap_free(data);
1158             return E_OUTOFMEMORY;
1159         }
1160
1161         task->data = data;
1162
1163         push_task(This, &task->header, switch_proc);
1164         return S_OK;
1165     }
1166
1167     return IInternetProtocolSink_Switch(This->protocol_sink_handler, data);
1168 }
1169
1170 typedef struct {
1171     task_header_t header;
1172
1173     ULONG status_code;
1174     LPWSTR status_text;
1175 } on_progress_task_t;
1176
1177 static void on_progress_proc(BindProtocol *This, task_header_t *t)
1178 {
1179     on_progress_task_t *task = (on_progress_task_t*)t;
1180
1181     IInternetProtocolSink_ReportProgress(This->protocol_sink_handler, task->status_code, task->status_text);
1182
1183     heap_free(task->status_text);
1184     heap_free(task);
1185 }
1186
1187 static HRESULT WINAPI BPInternetProtocolSink_ReportProgress(IInternetProtocolSink *iface,
1188         ULONG ulStatusCode, LPCWSTR szStatusText)
1189 {
1190     BindProtocol *This = impl_from_IInternetProtocolSink(iface);
1191
1192     TRACE("(%p)->(%u %s)\n", This, ulStatusCode, debugstr_w(szStatusText));
1193
1194     if(do_direct_notif(This)) {
1195         IInternetProtocolSink_ReportProgress(This->protocol_sink_handler, ulStatusCode, szStatusText);
1196     }else {
1197         on_progress_task_t *task;
1198
1199         task = heap_alloc(sizeof(on_progress_task_t));
1200
1201         task->status_code = ulStatusCode;
1202         task->status_text = heap_strdupW(szStatusText);
1203
1204         push_task(This, &task->header, on_progress_proc);
1205     }
1206
1207     return S_OK;
1208 }
1209
1210 typedef struct {
1211     task_header_t header;
1212     DWORD bscf;
1213     ULONG progress;
1214     ULONG progress_max;
1215 } report_data_task_t;
1216
1217 static void report_data_proc(BindProtocol *This, task_header_t *t)
1218 {
1219     report_data_task_t *task = (report_data_task_t*)t;
1220
1221     IInternetProtocolSink_ReportData(This->protocol_sink_handler,
1222             task->bscf, task->progress, task->progress_max);
1223
1224     heap_free(task);
1225 }
1226
1227 static HRESULT WINAPI BPInternetProtocolSink_ReportData(IInternetProtocolSink *iface,
1228         DWORD grfBSCF, ULONG ulProgress, ULONG ulProgressMax)
1229 {
1230     BindProtocol *This = impl_from_IInternetProtocolSink(iface);
1231
1232     TRACE("(%p)->(%x %u %u)\n", This, grfBSCF, ulProgress, ulProgressMax);
1233
1234     if(!This->protocol_sink)
1235         return S_OK;
1236
1237     if(!do_direct_notif(This)) {
1238         report_data_task_t *task;
1239
1240         task = heap_alloc(sizeof(report_data_task_t));
1241         if(!task)
1242             return E_OUTOFMEMORY;
1243
1244         task->bscf = grfBSCF;
1245         task->progress = ulProgress;
1246         task->progress_max = ulProgressMax;
1247
1248         push_task(This, &task->header, report_data_proc);
1249         return S_OK;
1250     }
1251
1252     return IInternetProtocolSink_ReportData(This->protocol_sink_handler,
1253             grfBSCF, ulProgress, ulProgressMax);
1254 }
1255
1256 typedef struct {
1257     task_header_t header;
1258
1259     HRESULT hres;
1260     DWORD err;
1261     LPWSTR str;
1262 } report_result_task_t;
1263
1264 static void report_result_proc(BindProtocol *This, task_header_t *t)
1265 {
1266     report_result_task_t *task = (report_result_task_t*)t;
1267
1268     IInternetProtocolSink_ReportResult(This->protocol_sink_handler, task->hres, task->err, task->str);
1269
1270     heap_free(task->str);
1271     heap_free(task);
1272 }
1273
1274 static HRESULT WINAPI BPInternetProtocolSink_ReportResult(IInternetProtocolSink *iface,
1275         HRESULT hrResult, DWORD dwError, LPCWSTR szResult)
1276 {
1277     BindProtocol *This = impl_from_IInternetProtocolSink(iface);
1278
1279     TRACE("(%p)->(%08x %d %s)\n", This, hrResult, dwError, debugstr_w(szResult));
1280
1281     if(!This->protocol_sink)
1282         return E_FAIL;
1283     This->reported_result = TRUE;
1284
1285     if(!do_direct_notif(This)) {
1286         report_result_task_t *task;
1287
1288         task = heap_alloc(sizeof(report_result_task_t));
1289         if(!task)
1290             return E_OUTOFMEMORY;
1291
1292         task->hres = hrResult;
1293         task->err = dwError;
1294         task->str = heap_strdupW(szResult);
1295
1296         push_task(This, &task->header, report_result_proc);
1297         return S_OK;
1298     }
1299
1300     return IInternetProtocolSink_ReportResult(This->protocol_sink_handler, hrResult, dwError, szResult);
1301 }
1302
1303 static const IInternetProtocolSinkVtbl InternetProtocolSinkVtbl = {
1304     BPInternetProtocolSink_QueryInterface,
1305     BPInternetProtocolSink_AddRef,
1306     BPInternetProtocolSink_Release,
1307     BPInternetProtocolSink_Switch,
1308     BPInternetProtocolSink_ReportProgress,
1309     BPInternetProtocolSink_ReportData,
1310     BPInternetProtocolSink_ReportResult
1311 };
1312
1313 static inline BindProtocol *impl_from_IWinInetHttpInfo(IWinInetHttpInfo *iface)
1314 {
1315     return CONTAINING_RECORD(iface, BindProtocol, IWinInetHttpInfo_iface);
1316 }
1317
1318 static HRESULT WINAPI WinInetHttpInfo_QueryInterface(IWinInetHttpInfo *iface, REFIID riid, void **ppv)
1319 {
1320     BindProtocol *This = impl_from_IWinInetHttpInfo(iface);
1321     return IInternetProtocolEx_QueryInterface(&This->IInternetProtocolEx_iface, riid, ppv);
1322 }
1323
1324 static ULONG WINAPI WinInetHttpInfo_AddRef(IWinInetHttpInfo *iface)
1325 {
1326     BindProtocol *This = impl_from_IWinInetHttpInfo(iface);
1327     return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
1328 }
1329
1330 static ULONG WINAPI WinInetHttpInfo_Release(IWinInetHttpInfo *iface)
1331 {
1332     BindProtocol *This = impl_from_IWinInetHttpInfo(iface);
1333     return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
1334 }
1335
1336 static HRESULT WINAPI WinInetHttpInfo_QueryOption(IWinInetHttpInfo *iface, DWORD dwOption,
1337         void *pBuffer, DWORD *pcbBuffer)
1338 {
1339     BindProtocol *This = impl_from_IWinInetHttpInfo(iface);
1340     FIXME("(%p)->(%x %p %p)\n", This, dwOption, pBuffer, pcbBuffer);
1341     return E_NOTIMPL;
1342 }
1343
1344 static HRESULT WINAPI WinInetHttpInfo_QueryInfo(IWinInetHttpInfo *iface, DWORD dwOption,
1345         void *pBuffer, DWORD *pcbBuffer, DWORD *pdwFlags, DWORD *pdwReserved)
1346 {
1347     BindProtocol *This = impl_from_IWinInetHttpInfo(iface);
1348     FIXME("(%p)->(%x %p %p %p %p)\n", This, dwOption, pBuffer, pcbBuffer, pdwFlags, pdwReserved);
1349     return E_NOTIMPL;
1350 }
1351
1352 static const IWinInetHttpInfoVtbl WinInetHttpInfoVtbl = {
1353     WinInetHttpInfo_QueryInterface,
1354     WinInetHttpInfo_AddRef,
1355     WinInetHttpInfo_Release,
1356     WinInetHttpInfo_QueryOption,
1357     WinInetHttpInfo_QueryInfo
1358 };
1359
1360 static inline BindProtocol *impl_from_IServiceProvider(IServiceProvider *iface)
1361 {
1362     return CONTAINING_RECORD(iface, BindProtocol, IServiceProvider_iface);
1363 }
1364
1365 static HRESULT WINAPI BPServiceProvider_QueryInterface(IServiceProvider *iface,
1366         REFIID riid, void **ppv)
1367 {
1368     BindProtocol *This = impl_from_IServiceProvider(iface);
1369     return IInternetProtocolEx_QueryInterface(&This->IInternetProtocolEx_iface, riid, ppv);
1370 }
1371
1372 static ULONG WINAPI BPServiceProvider_AddRef(IServiceProvider *iface)
1373 {
1374     BindProtocol *This = impl_from_IServiceProvider(iface);
1375     return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
1376 }
1377
1378 static ULONG WINAPI BPServiceProvider_Release(IServiceProvider *iface)
1379 {
1380     BindProtocol *This = impl_from_IServiceProvider(iface);
1381     return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
1382 }
1383
1384 static HRESULT WINAPI BPServiceProvider_QueryService(IServiceProvider *iface,
1385         REFGUID guidService, REFIID riid, void **ppv)
1386 {
1387     BindProtocol *This = impl_from_IServiceProvider(iface);
1388
1389     TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
1390
1391     if(!This->service_provider)
1392         return E_NOINTERFACE;
1393
1394     return IServiceProvider_QueryService(This->service_provider, guidService, riid, ppv);
1395 }
1396
1397 static const IServiceProviderVtbl ServiceProviderVtbl = {
1398     BPServiceProvider_QueryInterface,
1399     BPServiceProvider_AddRef,
1400     BPServiceProvider_Release,
1401     BPServiceProvider_QueryService
1402 };
1403
1404 HRESULT create_binding_protocol(BOOL from_urlmon, BindProtocol **protocol)
1405 {
1406     BindProtocol *ret = heap_alloc_zero(sizeof(BindProtocol));
1407
1408     ret->IInternetProtocolEx_iface.lpVtbl   = &BindProtocolVtbl;
1409     ret->IInternetBindInfo_iface.lpVtbl     = &InternetBindInfoVtbl;
1410     ret->IInternetPriority_iface.lpVtbl     = &InternetPriorityVtbl;
1411     ret->IServiceProvider_iface.lpVtbl      = &ServiceProviderVtbl;
1412     ret->IInternetProtocolSink_iface.lpVtbl = &InternetProtocolSinkVtbl;
1413     ret->IWinInetHttpInfo_iface.lpVtbl      = &WinInetHttpInfoVtbl;
1414
1415     ret->default_protocol_handler.IInternetProtocol_iface.lpVtbl = &InternetProtocolHandlerVtbl;
1416     ret->default_protocol_handler.IInternetProtocolSink_iface.lpVtbl = &InternetProtocolSinkHandlerVtbl;
1417
1418     ret->ref = 1;
1419     ret->from_urlmon = from_urlmon;
1420     ret->apartment_thread = GetCurrentThreadId();
1421     ret->notif_hwnd = get_notif_hwnd();
1422     ret->protocol_handler = &ret->default_protocol_handler.IInternetProtocol_iface;
1423     ret->protocol_sink_handler = &ret->default_protocol_handler.IInternetProtocolSink_iface;
1424     InitializeCriticalSection(&ret->section);
1425     ret->section.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": BindProtocol.section");
1426
1427     URLMON_LockModule();
1428
1429     *protocol = ret;
1430     return S_OK;
1431 }