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