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