oleaut32: Use a saner calling convention for the marshaller asm thunks.
[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         {
1153             heap_free(data);
1154             return E_OUTOFMEMORY;
1155         }
1156
1157         task->data = data;
1158
1159         push_task(This, &task->header, switch_proc);
1160         return S_OK;
1161     }
1162
1163     return IInternetProtocolSink_Switch(This->protocol_sink_handler, data);
1164 }
1165
1166 typedef struct {
1167     task_header_t header;
1168
1169     ULONG status_code;
1170     LPWSTR status_text;
1171 } on_progress_task_t;
1172
1173 static void on_progress_proc(BindProtocol *This, task_header_t *t)
1174 {
1175     on_progress_task_t *task = (on_progress_task_t*)t;
1176
1177     IInternetProtocolSink_ReportProgress(This->protocol_sink_handler, task->status_code, task->status_text);
1178
1179     heap_free(task->status_text);
1180     heap_free(task);
1181 }
1182
1183 static HRESULT WINAPI BPInternetProtocolSink_ReportProgress(IInternetProtocolSink *iface,
1184         ULONG ulStatusCode, LPCWSTR szStatusText)
1185 {
1186     BindProtocol *This = impl_from_IInternetProtocolSink(iface);
1187
1188     TRACE("(%p)->(%u %s)\n", This, ulStatusCode, debugstr_w(szStatusText));
1189
1190     if(do_direct_notif(This)) {
1191         IInternetProtocolSink_ReportProgress(This->protocol_sink_handler, ulStatusCode, szStatusText);
1192     }else {
1193         on_progress_task_t *task;
1194
1195         task = heap_alloc(sizeof(on_progress_task_t));
1196
1197         task->status_code = ulStatusCode;
1198         task->status_text = heap_strdupW(szStatusText);
1199
1200         push_task(This, &task->header, on_progress_proc);
1201     }
1202
1203     return S_OK;
1204 }
1205
1206 typedef struct {
1207     task_header_t header;
1208     DWORD bscf;
1209     ULONG progress;
1210     ULONG progress_max;
1211 } report_data_task_t;
1212
1213 static void report_data_proc(BindProtocol *This, task_header_t *t)
1214 {
1215     report_data_task_t *task = (report_data_task_t*)t;
1216
1217     IInternetProtocolSink_ReportData(This->protocol_sink_handler,
1218             task->bscf, task->progress, task->progress_max);
1219
1220     heap_free(task);
1221 }
1222
1223 static HRESULT WINAPI BPInternetProtocolSink_ReportData(IInternetProtocolSink *iface,
1224         DWORD grfBSCF, ULONG ulProgress, ULONG ulProgressMax)
1225 {
1226     BindProtocol *This = impl_from_IInternetProtocolSink(iface);
1227
1228     TRACE("(%p)->(%x %u %u)\n", This, grfBSCF, ulProgress, ulProgressMax);
1229
1230     if(!This->protocol_sink)
1231         return S_OK;
1232
1233     if(!do_direct_notif(This)) {
1234         report_data_task_t *task;
1235
1236         task = heap_alloc(sizeof(report_data_task_t));
1237         if(!task)
1238             return E_OUTOFMEMORY;
1239
1240         task->bscf = grfBSCF;
1241         task->progress = ulProgress;
1242         task->progress_max = ulProgressMax;
1243
1244         push_task(This, &task->header, report_data_proc);
1245         return S_OK;
1246     }
1247
1248     return IInternetProtocolSink_ReportData(This->protocol_sink_handler,
1249             grfBSCF, ulProgress, ulProgressMax);
1250 }
1251
1252 typedef struct {
1253     task_header_t header;
1254
1255     HRESULT hres;
1256     DWORD err;
1257     LPWSTR str;
1258 } report_result_task_t;
1259
1260 static void report_result_proc(BindProtocol *This, task_header_t *t)
1261 {
1262     report_result_task_t *task = (report_result_task_t*)t;
1263
1264     IInternetProtocolSink_ReportResult(This->protocol_sink_handler, task->hres, task->err, task->str);
1265
1266     heap_free(task->str);
1267     heap_free(task);
1268 }
1269
1270 static HRESULT WINAPI BPInternetProtocolSink_ReportResult(IInternetProtocolSink *iface,
1271         HRESULT hrResult, DWORD dwError, LPCWSTR szResult)
1272 {
1273     BindProtocol *This = impl_from_IInternetProtocolSink(iface);
1274
1275     TRACE("(%p)->(%08x %d %s)\n", This, hrResult, dwError, debugstr_w(szResult));
1276
1277     if(!This->protocol_sink)
1278         return E_FAIL;
1279     This->reported_result = TRUE;
1280
1281     if(!do_direct_notif(This)) {
1282         report_result_task_t *task;
1283
1284         task = heap_alloc(sizeof(report_result_task_t));
1285         if(!task)
1286             return E_OUTOFMEMORY;
1287
1288         task->hres = hrResult;
1289         task->err = dwError;
1290         task->str = heap_strdupW(szResult);
1291
1292         push_task(This, &task->header, report_result_proc);
1293         return S_OK;
1294     }
1295
1296     return IInternetProtocolSink_ReportResult(This->protocol_sink_handler, hrResult, dwError, szResult);
1297 }
1298
1299 static const IInternetProtocolSinkVtbl InternetProtocolSinkVtbl = {
1300     BPInternetProtocolSink_QueryInterface,
1301     BPInternetProtocolSink_AddRef,
1302     BPInternetProtocolSink_Release,
1303     BPInternetProtocolSink_Switch,
1304     BPInternetProtocolSink_ReportProgress,
1305     BPInternetProtocolSink_ReportData,
1306     BPInternetProtocolSink_ReportResult
1307 };
1308
1309 static inline BindProtocol *impl_from_IWinInetHttpInfo(IWinInetHttpInfo *iface)
1310 {
1311     return CONTAINING_RECORD(iface, BindProtocol, IWinInetHttpInfo_iface);
1312 }
1313
1314 static HRESULT WINAPI WinInetHttpInfo_QueryInterface(IWinInetHttpInfo *iface, REFIID riid, void **ppv)
1315 {
1316     BindProtocol *This = impl_from_IWinInetHttpInfo(iface);
1317     return IInternetProtocolEx_QueryInterface(&This->IInternetProtocolEx_iface, riid, ppv);
1318 }
1319
1320 static ULONG WINAPI WinInetHttpInfo_AddRef(IWinInetHttpInfo *iface)
1321 {
1322     BindProtocol *This = impl_from_IWinInetHttpInfo(iface);
1323     return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
1324 }
1325
1326 static ULONG WINAPI WinInetHttpInfo_Release(IWinInetHttpInfo *iface)
1327 {
1328     BindProtocol *This = impl_from_IWinInetHttpInfo(iface);
1329     return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
1330 }
1331
1332 static HRESULT WINAPI WinInetHttpInfo_QueryOption(IWinInetHttpInfo *iface, DWORD dwOption,
1333         void *pBuffer, DWORD *pcbBuffer)
1334 {
1335     BindProtocol *This = impl_from_IWinInetHttpInfo(iface);
1336     FIXME("(%p)->(%x %p %p)\n", This, dwOption, pBuffer, pcbBuffer);
1337     return E_NOTIMPL;
1338 }
1339
1340 static HRESULT WINAPI WinInetHttpInfo_QueryInfo(IWinInetHttpInfo *iface, DWORD dwOption,
1341         void *pBuffer, DWORD *pcbBuffer, DWORD *pdwFlags, DWORD *pdwReserved)
1342 {
1343     BindProtocol *This = impl_from_IWinInetHttpInfo(iface);
1344     FIXME("(%p)->(%x %p %p %p %p)\n", This, dwOption, pBuffer, pcbBuffer, pdwFlags, pdwReserved);
1345     return E_NOTIMPL;
1346 }
1347
1348 static const IWinInetHttpInfoVtbl WinInetHttpInfoVtbl = {
1349     WinInetHttpInfo_QueryInterface,
1350     WinInetHttpInfo_AddRef,
1351     WinInetHttpInfo_Release,
1352     WinInetHttpInfo_QueryOption,
1353     WinInetHttpInfo_QueryInfo
1354 };
1355
1356 static inline BindProtocol *impl_from_IServiceProvider(IServiceProvider *iface)
1357 {
1358     return CONTAINING_RECORD(iface, BindProtocol, IServiceProvider_iface);
1359 }
1360
1361 static HRESULT WINAPI BPServiceProvider_QueryInterface(IServiceProvider *iface,
1362         REFIID riid, void **ppv)
1363 {
1364     BindProtocol *This = impl_from_IServiceProvider(iface);
1365     return IInternetProtocolEx_QueryInterface(&This->IInternetProtocolEx_iface, riid, ppv);
1366 }
1367
1368 static ULONG WINAPI BPServiceProvider_AddRef(IServiceProvider *iface)
1369 {
1370     BindProtocol *This = impl_from_IServiceProvider(iface);
1371     return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
1372 }
1373
1374 static ULONG WINAPI BPServiceProvider_Release(IServiceProvider *iface)
1375 {
1376     BindProtocol *This = impl_from_IServiceProvider(iface);
1377     return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
1378 }
1379
1380 static HRESULT WINAPI BPServiceProvider_QueryService(IServiceProvider *iface,
1381         REFGUID guidService, REFIID riid, void **ppv)
1382 {
1383     BindProtocol *This = impl_from_IServiceProvider(iface);
1384
1385     TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
1386
1387     if(!This->service_provider)
1388         return E_NOINTERFACE;
1389
1390     return IServiceProvider_QueryService(This->service_provider, guidService, riid, ppv);
1391 }
1392
1393 static const IServiceProviderVtbl ServiceProviderVtbl = {
1394     BPServiceProvider_QueryInterface,
1395     BPServiceProvider_AddRef,
1396     BPServiceProvider_Release,
1397     BPServiceProvider_QueryService
1398 };
1399
1400 HRESULT create_binding_protocol(BOOL from_urlmon, BindProtocol **protocol)
1401 {
1402     BindProtocol *ret = heap_alloc_zero(sizeof(BindProtocol));
1403
1404     ret->IInternetProtocolEx_iface.lpVtbl   = &BindProtocolVtbl;
1405     ret->IInternetBindInfo_iface.lpVtbl     = &InternetBindInfoVtbl;
1406     ret->IInternetPriority_iface.lpVtbl     = &InternetPriorityVtbl;
1407     ret->IServiceProvider_iface.lpVtbl      = &ServiceProviderVtbl;
1408     ret->IInternetProtocolSink_iface.lpVtbl = &InternetProtocolSinkVtbl;
1409     ret->IWinInetHttpInfo_iface.lpVtbl      = &WinInetHttpInfoVtbl;
1410
1411     ret->default_protocol_handler.IInternetProtocol_iface.lpVtbl = &InternetProtocolHandlerVtbl;
1412     ret->default_protocol_handler.IInternetProtocolSink_iface.lpVtbl = &InternetProtocolSinkHandlerVtbl;
1413
1414     ret->ref = 1;
1415     ret->from_urlmon = from_urlmon;
1416     ret->apartment_thread = GetCurrentThreadId();
1417     ret->notif_hwnd = get_notif_hwnd();
1418     ret->protocol_handler = &ret->default_protocol_handler.IInternetProtocol_iface;
1419     ret->protocol_sink_handler = &ret->default_protocol_handler.IInternetProtocolSink_iface;
1420     InitializeCriticalSection(&ret->section);
1421     ret->section.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": BindProtocol.section");
1422
1423     URLMON_LockModule();
1424
1425     *protocol = ret;
1426     return S_OK;
1427 }