xref: /reactos/dll/win32/urlmon/bindprot.c (revision 8c2e9189)
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(IsEqualGUID(&IID_IWinInetInfo, riid)) {
287         TRACE("(%p)->(IID_IWinInetInfo %p)\n", This, ppv);
288 
289         if(This->protocol) {
290             IWinInetInfo *inet_info;
291             HRESULT hres;
292 
293             hres = IInternetProtocol_QueryInterface(This->protocol, &IID_IWinInetInfo, (void**)&inet_info);
294             if(SUCCEEDED(hres)) {
295                 *ppv = &This->IWinInetHttpInfo_iface;
296                 IWinInetInfo_Release(inet_info);
297             }
298         }
299     }else if(IsEqualGUID(&IID_IWinInetHttpInfo, riid)) {
300         TRACE("(%p)->(IID_IWinInetHttpInfo %p)\n", This, ppv);
301 
302         if(This->protocol) {
303             IWinInetHttpInfo *http_info;
304             HRESULT hres;
305 
306             hres = IInternetProtocol_QueryInterface(This->protocol, &IID_IWinInetHttpInfo, (void**)&http_info);
307             if(SUCCEEDED(hres)) {
308                 *ppv = &This->IWinInetHttpInfo_iface;
309                 IWinInetHttpInfo_Release(http_info);
310             }
311         }
312     }else {
313         WARN("not supported interface %s\n", debugstr_guid(riid));
314     }
315 
316     if(!*ppv)
317         return E_NOINTERFACE;
318 
319     IUnknown_AddRef((IUnknown*)*ppv);
320     return S_OK;
321 }
322 
323 static ULONG WINAPI BindProtocol_AddRef(IInternetProtocolEx *iface)
324 {
325     BindProtocol *This = impl_from_IInternetProtocolEx(iface);
326     LONG ref = InterlockedIncrement(&This->ref);
327     TRACE("(%p) ref=%d\n", This, ref);
328     return ref;
329 }
330 
331 static void release_protocol_handler(BindProtocol *This)
332 {
333     if(This->wininet_info) {
334         IWinInetInfo_Release(This->wininet_info);
335         This->wininet_info = NULL;
336     }
337     if(This->wininet_http_info) {
338         IWinInetHttpInfo_Release(This->wininet_http_info);
339         This->wininet_http_info = NULL;
340     }
341     if(This->protocol) {
342         IInternetProtocol_Release(This->protocol);
343         This->protocol = NULL;
344     }
345     if(This->protocol_handler && This->protocol_handler != &This->default_protocol_handler.IInternetProtocol_iface) {
346         IInternetProtocol_Release(This->protocol_handler);
347         This->protocol_handler = &This->default_protocol_handler.IInternetProtocol_iface;
348     }
349     if(This->protocol_sink_handler &&
350        This->protocol_sink_handler != &This->default_protocol_handler.IInternetProtocolSink_iface) {
351         IInternetProtocolSink_Release(This->protocol_sink_handler);
352         This->protocol_sink_handler = &This->default_protocol_handler.IInternetProtocolSink_iface;
353     }
354 }
355 
356 static ULONG WINAPI BindProtocol_Release(IInternetProtocolEx *iface)
357 {
358     BindProtocol *This = impl_from_IInternetProtocolEx(iface);
359     LONG ref = InterlockedDecrement(&This->ref);
360 
361     TRACE("(%p) ref=%d\n", This, ref);
362 
363     if(!ref) {
364         release_protocol_handler(This);
365         if(This->redirect_callback)
366             IBindCallbackRedirect_Release(This->redirect_callback);
367         if(This->bind_info)
368             IInternetBindInfo_Release(This->bind_info);
369         if(This->uri)
370             IUri_Release(This->uri);
371         SysFreeString(This->display_uri);
372 
373         set_binding_sink(This, NULL, NULL);
374 
375         if(This->notif_hwnd)
376             release_notif_hwnd(This->notif_hwnd);
377         This->section.DebugInfo->Spare[0] = 0;
378         DeleteCriticalSection(&This->section);
379 
380         heap_free(This->mime);
381         heap_free(This);
382 
383         URLMON_UnlockModule();
384     }
385 
386     return ref;
387 }
388 
389 static HRESULT WINAPI BindProtocol_Start(IInternetProtocolEx *iface, LPCWSTR szUrl,
390         IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
391         DWORD grfPI, HANDLE_PTR dwReserved)
392 {
393     BindProtocol *This = impl_from_IInternetProtocolEx(iface);
394     IUri *uri;
395     HRESULT hres;
396 
397     TRACE("(%p)->(%s %p %p %08x %lx)\n", This, debugstr_w(szUrl), pOIProtSink,
398             pOIBindInfo, grfPI, dwReserved);
399 
400     hres = CreateUri(szUrl, Uri_CREATE_FILE_USE_DOS_PATH, 0, &uri);
401     if(FAILED(hres))
402         return hres;
403 
404     hres = IInternetProtocolEx_StartEx(&This->IInternetProtocolEx_iface, uri, pOIProtSink,
405             pOIBindInfo, grfPI, (HANDLE*)dwReserved);
406 
407     IUri_Release(uri);
408     return hres;
409 }
410 
411 static HRESULT WINAPI BindProtocol_Continue(IInternetProtocolEx *iface, PROTOCOLDATA *pProtocolData)
412 {
413     BindProtocol *This = impl_from_IInternetProtocolEx(iface);
414 
415     TRACE("(%p)->(%p)\n", This, pProtocolData);
416 
417     return IInternetProtocol_Continue(This->protocol_handler, pProtocolData);
418 }
419 
420 static HRESULT WINAPI BindProtocol_Abort(IInternetProtocolEx *iface, HRESULT hrReason,
421         DWORD dwOptions)
422 {
423     BindProtocol *This = impl_from_IInternetProtocolEx(iface);
424 
425     TRACE("(%p)->(%08x %08x)\n", This, hrReason, dwOptions);
426 
427     return IInternetProtocol_Abort(This->protocol_handler, hrReason, dwOptions);
428 }
429 
430 static HRESULT WINAPI BindProtocol_Terminate(IInternetProtocolEx *iface, DWORD dwOptions)
431 {
432     BindProtocol *This = impl_from_IInternetProtocolEx(iface);
433 
434     TRACE("(%p)->(%08x)\n", This, dwOptions);
435 
436     return IInternetProtocol_Terminate(This->protocol_handler, dwOptions);
437 }
438 
439 static HRESULT WINAPI BindProtocol_Suspend(IInternetProtocolEx *iface)
440 {
441     BindProtocol *This = impl_from_IInternetProtocolEx(iface);
442     FIXME("(%p)\n", This);
443     return E_NOTIMPL;
444 }
445 
446 static HRESULT WINAPI BindProtocol_Resume(IInternetProtocolEx *iface)
447 {
448     BindProtocol *This = impl_from_IInternetProtocolEx(iface);
449     FIXME("(%p)\n", This);
450     return E_NOTIMPL;
451 }
452 
453 static HRESULT WINAPI BindProtocol_Read(IInternetProtocolEx *iface, void *pv,
454         ULONG cb, ULONG *pcbRead)
455 {
456     BindProtocol *This = impl_from_IInternetProtocolEx(iface);
457 
458     TRACE("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead);
459 
460     if(pcbRead)
461         *pcbRead = 0;
462     return IInternetProtocol_Read(This->protocol_handler, pv, cb, pcbRead);
463 }
464 
465 static HRESULT WINAPI BindProtocol_Seek(IInternetProtocolEx *iface, LARGE_INTEGER dlibMove,
466         DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
467 {
468     BindProtocol *This = impl_from_IInternetProtocolEx(iface);
469     FIXME("(%p)->(%d %d %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
470     return E_NOTIMPL;
471 }
472 
473 static HRESULT WINAPI BindProtocol_LockRequest(IInternetProtocolEx *iface, DWORD dwOptions)
474 {
475     BindProtocol *This = impl_from_IInternetProtocolEx(iface);
476 
477     TRACE("(%p)->(%08x)\n", This, dwOptions);
478 
479     return IInternetProtocol_LockRequest(This->protocol_handler, dwOptions);
480 }
481 
482 static HRESULT WINAPI BindProtocol_UnlockRequest(IInternetProtocolEx *iface)
483 {
484     BindProtocol *This = impl_from_IInternetProtocolEx(iface);
485 
486     TRACE("(%p)\n", This);
487 
488     return IInternetProtocol_UnlockRequest(This->protocol_handler);
489 }
490 
491 static HRESULT WINAPI BindProtocol_StartEx(IInternetProtocolEx *iface, IUri *pUri,
492         IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
493         DWORD grfPI, HANDLE *dwReserved)
494 {
495     BindProtocol *This = impl_from_IInternetProtocolEx(iface);
496     IInternetProtocol *protocol = NULL;
497     IInternetProtocolEx *protocolex;
498     IInternetPriority *priority;
499     IServiceProvider *service_provider;
500     BOOL urlmon_protocol = FALSE;
501     CLSID clsid = IID_NULL;
502     LPOLESTR clsid_str;
503     HRESULT hres;
504 
505     TRACE("(%p)->(%p %p %p %08x %p)\n", This, pUri, pOIProtSink, pOIBindInfo, grfPI, dwReserved);
506 
507     if(!pUri || !pOIProtSink || !pOIBindInfo)
508         return E_INVALIDARG;
509 
510     This->pi = grfPI;
511 
512     if(This->uri) {
513         SysFreeString(This->display_uri);
514         IUri_Release(This->uri);
515     }
516     IUri_AddRef(pUri);
517     This->uri = pUri;
518 
519     hres = IInternetProtocolSink_QueryInterface(pOIProtSink, &IID_IServiceProvider,
520                                                 (void**)&service_provider);
521     if(SUCCEEDED(hres)) {
522         /* FIXME: What's protocol CLSID here? */
523         IServiceProvider_QueryService(service_provider, &IID_IInternetProtocol,
524                 &IID_IInternetProtocol, (void**)&protocol);
525         IServiceProvider_Release(service_provider);
526     }
527 
528     if(!protocol) {
529         IClassFactory *cf;
530         IUnknown *unk;
531 
532         hres = get_protocol_handler(pUri, &clsid, &urlmon_protocol, &cf);
533         if(FAILED(hres))
534             return hres;
535 
536         if(This->from_urlmon) {
537             hres = IClassFactory_CreateInstance(cf, NULL, &IID_IInternetProtocol, (void**)&protocol);
538             IClassFactory_Release(cf);
539             if(FAILED(hres))
540                 return hres;
541         }else {
542             hres = IClassFactory_CreateInstance(cf, (IUnknown*)&This->IInternetBindInfo_iface,
543                     &IID_IUnknown, (void**)&unk);
544             IClassFactory_Release(cf);
545             if(FAILED(hres))
546                 return hres;
547 
548             hres = IUnknown_QueryInterface(unk, &IID_IInternetProtocol, (void**)&protocol);
549             IUnknown_Release(unk);
550             if(FAILED(hres))
551                 return hres;
552         }
553     }
554 
555     StringFromCLSID(&clsid, &clsid_str);
556     IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_PROTOCOLCLASSID, clsid_str);
557     CoTaskMemFree(clsid_str);
558 
559     This->protocol = protocol;
560 
561     if(urlmon_protocol) {
562         IInternetProtocol_QueryInterface(protocol, &IID_IWinInetInfo, (void**)&This->wininet_info);
563         IInternetProtocol_QueryInterface(protocol, &IID_IWinInetHttpInfo, (void**)&This->wininet_http_info);
564     }
565 
566     set_binding_sink(This, pOIProtSink, pOIBindInfo);
567 
568     hres = IInternetProtocol_QueryInterface(protocol, &IID_IInternetPriority, (void**)&priority);
569     if(SUCCEEDED(hres)) {
570         IInternetPriority_SetPriority(priority, This->priority);
571         IInternetPriority_Release(priority);
572     }
573 
574     hres = IInternetProtocol_QueryInterface(protocol, &IID_IInternetProtocolEx, (void**)&protocolex);
575     if(SUCCEEDED(hres)) {
576         hres = IInternetProtocolEx_StartEx(protocolex, pUri, &This->IInternetProtocolSink_iface,
577                 &This->IInternetBindInfo_iface, 0, NULL);
578         IInternetProtocolEx_Release(protocolex);
579     }else {
580         hres = IUri_GetDisplayUri(pUri, &This->display_uri);
581         if(FAILED(hres))
582             return hres;
583 
584         hres = IInternetProtocol_Start(protocol, This->display_uri, &This->IInternetProtocolSink_iface,
585                 &This->IInternetBindInfo_iface, 0, 0);
586     }
587 
588     if(SUCCEEDED(hres))
589         process_tasks(This);
590     return hres;
591 }
592 
593 void set_binding_sink(BindProtocol *This, IInternetProtocolSink *sink, IInternetBindInfo *bind_info)
594 {
595     IInternetProtocolSink *prev_sink;
596     IServiceProvider *service_provider = NULL;
597 
598     if(sink)
599         IInternetProtocolSink_AddRef(sink);
600     prev_sink = InterlockedExchangePointer((void**)&This->protocol_sink, sink);
601     if(prev_sink)
602         IInternetProtocolSink_Release(prev_sink);
603 
604     if(sink)
605         IInternetProtocolSink_QueryInterface(sink, &IID_IServiceProvider, (void**)&service_provider);
606     service_provider = InterlockedExchangePointer((void**)&This->service_provider, service_provider);
607     if(service_provider)
608         IServiceProvider_Release(service_provider);
609 
610     if(bind_info)
611         IInternetBindInfo_AddRef(bind_info);
612     bind_info = InterlockedExchangePointer((void**)&This->bind_info, bind_info);
613     if(bind_info)
614         IInternetBindInfo_Release(bind_info);
615 }
616 
617 static const IInternetProtocolExVtbl BindProtocolVtbl = {
618     BindProtocol_QueryInterface,
619     BindProtocol_AddRef,
620     BindProtocol_Release,
621     BindProtocol_Start,
622     BindProtocol_Continue,
623     BindProtocol_Abort,
624     BindProtocol_Terminate,
625     BindProtocol_Suspend,
626     BindProtocol_Resume,
627     BindProtocol_Read,
628     BindProtocol_Seek,
629     BindProtocol_LockRequest,
630     BindProtocol_UnlockRequest,
631     BindProtocol_StartEx
632 };
633 
634 static inline BindProtocol *impl_from_IInternetProtocol(IInternetProtocol *iface)
635 {
636     return CONTAINING_RECORD(iface, BindProtocol, default_protocol_handler.IInternetProtocol_iface);
637 }
638 
639 static HRESULT WINAPI ProtocolHandler_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv)
640 {
641     BindProtocol *This = impl_from_IInternetProtocol(iface);
642 
643     *ppv = NULL;
644     if(IsEqualGUID(&IID_IUnknown, riid)) {
645         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
646         *ppv = &This->default_protocol_handler.IInternetProtocol_iface;
647     }else if(IsEqualGUID(&IID_IInternetProtocolRoot, riid)) {
648         TRACE("(%p)->(IID_IInternetProtocolRoot %p)\n", This, ppv);
649         *ppv = &This->default_protocol_handler.IInternetProtocol_iface;
650     }else if(IsEqualGUID(&IID_IInternetProtocol, riid)) {
651         TRACE("(%p)->(IID_IInternetProtocol %p)\n", This, ppv);
652         *ppv = &This->default_protocol_handler.IInternetProtocol_iface;
653     }else if(IsEqualGUID(&IID_IInternetProtocolSink, riid)) {
654         TRACE("(%p)->(IID_IInternetProtocolSink %p)\n", This, ppv);
655         *ppv = &This->default_protocol_handler.IInternetProtocolSink_iface;
656     }
657 
658     if(*ppv) {
659         IInternetProtocol_AddRef(iface);
660         return S_OK;
661     }
662 
663     WARN("not supported interface %s\n", debugstr_guid(riid));
664     return E_NOINTERFACE;
665 }
666 
667 static ULONG WINAPI ProtocolHandler_AddRef(IInternetProtocol *iface)
668 {
669     BindProtocol *This = impl_from_IInternetProtocol(iface);
670     return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
671 }
672 
673 static ULONG WINAPI ProtocolHandler_Release(IInternetProtocol *iface)
674 {
675     BindProtocol *This = impl_from_IInternetProtocol(iface);
676     return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
677 }
678 
679 static HRESULT WINAPI ProtocolHandler_Start(IInternetProtocol *iface, LPCWSTR szUrl,
680         IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
681         DWORD grfPI, HANDLE_PTR dwReserved)
682 {
683     ERR("Should not be called\n");
684     return E_NOTIMPL;
685 }
686 
687 static HRESULT WINAPI ProtocolHandler_Continue(IInternetProtocol *iface, PROTOCOLDATA *pProtocolData)
688 {
689     BindProtocol *This = impl_from_IInternetProtocol(iface);
690     HRESULT hres;
691 
692     TRACE("(%p)->(%p)\n", This, pProtocolData);
693 
694     hres = IInternetProtocol_Continue(This->protocol, pProtocolData);
695 
696     heap_free(pProtocolData);
697     return hres;
698 }
699 
700 static HRESULT WINAPI ProtocolHandler_Abort(IInternetProtocol *iface, HRESULT hrReason,
701         DWORD dwOptions)
702 {
703     BindProtocol *This = impl_from_IInternetProtocol(iface);
704 
705     TRACE("(%p)->(%08x %08x)\n", This, hrReason, dwOptions);
706 
707     if(This->protocol && !This->reported_result)
708         return IInternetProtocol_Abort(This->protocol, hrReason, dwOptions);
709 
710     return S_OK;
711 }
712 
713 static HRESULT WINAPI ProtocolHandler_Terminate(IInternetProtocol *iface, DWORD dwOptions)
714 {
715     BindProtocol *This = impl_from_IInternetProtocol(iface);
716 
717     TRACE("(%p)->(%08x)\n", This, dwOptions);
718 
719     if(!This->reported_result)
720         return E_FAIL;
721 
722     /* This may get released in Terminate call. */
723     IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
724 
725     IInternetProtocol_Terminate(This->protocol, 0);
726 
727     set_binding_sink(This, NULL, NULL);
728 
729     if(This->bind_info) {
730         IInternetBindInfo_Release(This->bind_info);
731         This->bind_info = NULL;
732     }
733 
734     if(This->redirect_callback) {
735         IBindCallbackRedirect_Release(This->redirect_callback);
736         This->redirect_callback = NULL;
737     }
738 
739     IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
740     return S_OK;
741 }
742 
743 static HRESULT WINAPI ProtocolHandler_Suspend(IInternetProtocol *iface)
744 {
745     BindProtocol *This = impl_from_IInternetProtocol(iface);
746     FIXME("(%p)\n", This);
747     return E_NOTIMPL;
748 }
749 
750 static HRESULT WINAPI ProtocolHandler_Resume(IInternetProtocol *iface)
751 {
752     BindProtocol *This = impl_from_IInternetProtocol(iface);
753     FIXME("(%p)\n", This);
754     return E_NOTIMPL;
755 }
756 
757 static HRESULT WINAPI ProtocolHandler_Read(IInternetProtocol *iface, void *pv,
758         ULONG cb, ULONG *pcbRead)
759 {
760     BindProtocol *This = impl_from_IInternetProtocol(iface);
761     ULONG read = 0;
762     HRESULT hres = S_OK;
763 
764     TRACE("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead);
765 
766     if(This->buf_size) {
767         read = min(cb, This->buf_size);
768         memcpy(pv, This->buf, read);
769 
770         if(read == This->buf_size) {
771             heap_free(This->buf);
772             This->buf = NULL;
773         }else {
774             memmove(This->buf, This->buf+cb, This->buf_size-cb);
775         }
776 
777         This->buf_size -= read;
778     }
779 
780     if(read < cb) {
781         ULONG cread = 0;
782 
783         if(is_apartment_thread(This))
784             This->continue_call++;
785         hres = IInternetProtocol_Read(This->protocol, (BYTE*)pv+read, cb-read, &cread);
786         if(is_apartment_thread(This))
787             This->continue_call--;
788         read += cread;
789     }
790 
791     *pcbRead = read;
792     return hres;
793 }
794 
795 static HRESULT WINAPI ProtocolHandler_Seek(IInternetProtocol *iface, LARGE_INTEGER dlibMove,
796         DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
797 {
798     BindProtocol *This = impl_from_IInternetProtocol(iface);
799     FIXME("(%p)->(%d %d %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
800     return E_NOTIMPL;
801 }
802 
803 static HRESULT WINAPI ProtocolHandler_LockRequest(IInternetProtocol *iface, DWORD dwOptions)
804 {
805     BindProtocol *This = impl_from_IInternetProtocol(iface);
806 
807     TRACE("(%p)->(%08x)\n", This, dwOptions);
808 
809     return IInternetProtocol_LockRequest(This->protocol, dwOptions);
810 }
811 
812 static HRESULT WINAPI ProtocolHandler_UnlockRequest(IInternetProtocol *iface)
813 {
814     BindProtocol *This = impl_from_IInternetProtocol(iface);
815 
816     TRACE("(%p)\n", This);
817 
818     return IInternetProtocol_UnlockRequest(This->protocol);
819 }
820 
821 static const IInternetProtocolVtbl InternetProtocolHandlerVtbl = {
822     ProtocolHandler_QueryInterface,
823     ProtocolHandler_AddRef,
824     ProtocolHandler_Release,
825     ProtocolHandler_Start,
826     ProtocolHandler_Continue,
827     ProtocolHandler_Abort,
828     ProtocolHandler_Terminate,
829     ProtocolHandler_Suspend,
830     ProtocolHandler_Resume,
831     ProtocolHandler_Read,
832     ProtocolHandler_Seek,
833     ProtocolHandler_LockRequest,
834     ProtocolHandler_UnlockRequest
835 };
836 
837 static inline BindProtocol *impl_from_IInternetProtocolSinkHandler(IInternetProtocolSink *iface)
838 {
839     return CONTAINING_RECORD(iface, BindProtocol, default_protocol_handler.IInternetProtocolSink_iface);
840 }
841 
842 static HRESULT WINAPI ProtocolSinkHandler_QueryInterface(IInternetProtocolSink *iface,
843         REFIID riid, void **ppvObject)
844 {
845     BindProtocol *This = impl_from_IInternetProtocolSinkHandler(iface);
846     return IInternetProtocol_QueryInterface(&This->default_protocol_handler.IInternetProtocol_iface,
847             riid, ppvObject);
848 }
849 
850 static ULONG WINAPI ProtocolSinkHandler_AddRef(IInternetProtocolSink *iface)
851 {
852     BindProtocol *This = impl_from_IInternetProtocolSinkHandler(iface);
853     return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
854 }
855 
856 static ULONG WINAPI ProtocolSinkHandler_Release(IInternetProtocolSink *iface)
857 {
858     BindProtocol *This = impl_from_IInternetProtocolSinkHandler(iface);
859     return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
860 }
861 
862 static HRESULT WINAPI ProtocolSinkHandler_Switch(IInternetProtocolSink *iface,
863         PROTOCOLDATA *pProtocolData)
864 {
865     BindProtocol *This = impl_from_IInternetProtocolSinkHandler(iface);
866 
867     TRACE("(%p)->(%p)\n", This, pProtocolData);
868 
869     if(!This->protocol_sink) {
870         IInternetProtocol_Continue(This->protocol_handler, pProtocolData);
871         return S_OK;
872     }
873 
874     return IInternetProtocolSink_Switch(This->protocol_sink, pProtocolData);
875 }
876 
877 static HRESULT WINAPI ProtocolSinkHandler_ReportProgress(IInternetProtocolSink *iface,
878         ULONG status_code, LPCWSTR status_text)
879 {
880     BindProtocol *This = impl_from_IInternetProtocolSinkHandler(iface);
881 
882     TRACE("(%p)->(%s %s)\n", This, debugstr_bindstatus(status_code), debugstr_w(status_text));
883 
884     if(!This->protocol_sink)
885         return S_OK;
886 
887     switch(status_code) {
888     case BINDSTATUS_FINDINGRESOURCE:
889     case BINDSTATUS_CONNECTING:
890     case BINDSTATUS_REDIRECTING:
891     case BINDSTATUS_SENDINGREQUEST:
892     case BINDSTATUS_CACHEFILENAMEAVAILABLE:
893     case BINDSTATUS_DIRECTBIND:
894     case BINDSTATUS_ACCEPTRANGES:
895     case BINDSTATUS_DECODING:
896         IInternetProtocolSink_ReportProgress(This->protocol_sink, status_code, status_text);
897         break;
898 
899     case BINDSTATUS_BEGINDOWNLOADDATA:
900         IInternetProtocolSink_ReportData(This->protocol_sink, This->bscf, This->progress, This->progress_max);
901         break;
902 
903     case BINDSTATUS_MIMETYPEAVAILABLE:
904         mime_available(This, status_text, FALSE);
905         break;
906 
907     case BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE:
908         mime_available(This, status_text, TRUE);
909         break;
910 
911     default:
912         FIXME("unsupported ulStatusCode %u\n", status_code);
913     }
914 
915     return S_OK;
916 }
917 
918 static HRESULT WINAPI ProtocolSinkHandler_ReportData(IInternetProtocolSink *iface,
919         DWORD bscf, ULONG progress, ULONG progress_max)
920 {
921     BindProtocol *This = impl_from_IInternetProtocolSinkHandler(iface);
922 
923     TRACE("(%p)->(%x %u %u)\n", This, bscf, progress, progress_max);
924 
925     This->bscf = bscf;
926     This->progress = progress;
927     This->progress_max = progress_max;
928 
929     if(!This->protocol_sink)
930         return S_OK;
931 
932     if((This->pi & PI_MIMEVERIFICATION) && !This->reported_mime) {
933         BYTE buf[BUFFER_SIZE];
934         DWORD read = 0;
935         LPWSTR mime;
936         HRESULT hres;
937 
938         do {
939             read = 0;
940             if(is_apartment_thread(This))
941                 This->continue_call++;
942             hres = IInternetProtocol_Read(This->protocol, buf,
943                     sizeof(buf)-This->buf_size, &read);
944             if(is_apartment_thread(This))
945                 This->continue_call--;
946             if(FAILED(hres) && hres != E_PENDING)
947                 return hres;
948 
949             if(!This->buf) {
950                 This->buf = heap_alloc(BUFFER_SIZE);
951                 if(!This->buf)
952                     return E_OUTOFMEMORY;
953             }else if(read + This->buf_size > BUFFER_SIZE) {
954                 BYTE *tmp;
955 
956                 tmp = heap_realloc(This->buf, read+This->buf_size);
957                 if(!tmp)
958                     return E_OUTOFMEMORY;
959                 This->buf = tmp;
960             }
961 
962             memcpy(This->buf+This->buf_size, buf, read);
963             This->buf_size += read;
964         }while(This->buf_size < MIME_TEST_SIZE && hres == S_OK);
965 
966         if(This->buf_size < MIME_TEST_SIZE && hres != S_FALSE)
967             return S_OK;
968 
969         bscf = BSCF_FIRSTDATANOTIFICATION;
970         if(hres == S_FALSE)
971             bscf |= BSCF_LASTDATANOTIFICATION|BSCF_DATAFULLYAVAILABLE;
972 
973         if(!This->reported_mime) {
974             BSTR raw_uri;
975 
976             hres = IUri_GetRawUri(This->uri, &raw_uri);
977             if(FAILED(hres))
978                 return hres;
979 
980             hres = FindMimeFromData(NULL, raw_uri, This->buf, min(This->buf_size, MIME_TEST_SIZE),
981                     This->mime, 0, &mime, 0);
982             SysFreeString(raw_uri);
983             if(FAILED(hres))
984                 return hres;
985 
986             heap_free(This->mime);
987             This->mime = heap_strdupW(mime);
988             CoTaskMemFree(mime);
989             This->reported_mime = TRUE;
990             if(This->protocol_sink)
991                 IInternetProtocolSink_ReportProgress(This->protocol_sink, BINDSTATUS_MIMETYPEAVAILABLE, This->mime);
992         }
993     }
994 
995     if(!This->protocol_sink)
996         return S_OK;
997 
998     return IInternetProtocolSink_ReportData(This->protocol_sink, bscf, progress, progress_max);
999 }
1000 
1001 static HRESULT handle_redirect(BindProtocol *This, const WCHAR *url)
1002 {
1003     HRESULT hres;
1004 
1005     if(This->redirect_callback) {
1006         VARIANT_BOOL cancel = VARIANT_FALSE;
1007         IBindCallbackRedirect_Redirect(This->redirect_callback, url, &cancel);
1008         if(cancel)
1009             return INET_E_REDIRECT_FAILED;
1010     }
1011 
1012     if(This->protocol_sink) {
1013         hres = IInternetProtocolSink_ReportProgress(This->protocol_sink, BINDSTATUS_REDIRECTING, url);
1014         if(FAILED(hres))
1015             return hres;
1016     }
1017 
1018     IInternetProtocol_Terminate(This->protocol, 0); /* should this be done in StartEx? */
1019     release_protocol_handler(This);
1020 
1021     return IInternetProtocolEx_Start(&This->IInternetProtocolEx_iface, url, This->protocol_sink, This->bind_info, This->pi, 0);
1022 }
1023 
1024 static HRESULT WINAPI ProtocolSinkHandler_ReportResult(IInternetProtocolSink *iface,
1025         HRESULT hrResult, DWORD dwError, LPCWSTR szResult)
1026 {
1027     BindProtocol *This = impl_from_IInternetProtocolSinkHandler(iface);
1028 
1029     TRACE("(%p)->(%08x %d %s)\n", This, hrResult, dwError, debugstr_w(szResult));
1030 
1031     if(hrResult == INET_E_REDIRECT_FAILED) {
1032         hrResult = handle_redirect(This, szResult);
1033         if(hrResult == S_OK)
1034             return S_OK;
1035         szResult = NULL;
1036     }
1037 
1038     if(This->protocol_sink)
1039         return IInternetProtocolSink_ReportResult(This->protocol_sink, hrResult, dwError, szResult);
1040     return S_OK;
1041 }
1042 
1043 static const IInternetProtocolSinkVtbl InternetProtocolSinkHandlerVtbl = {
1044     ProtocolSinkHandler_QueryInterface,
1045     ProtocolSinkHandler_AddRef,
1046     ProtocolSinkHandler_Release,
1047     ProtocolSinkHandler_Switch,
1048     ProtocolSinkHandler_ReportProgress,
1049     ProtocolSinkHandler_ReportData,
1050     ProtocolSinkHandler_ReportResult
1051 };
1052 
1053 static inline BindProtocol *impl_from_IInternetBindInfo(IInternetBindInfo *iface)
1054 {
1055     return CONTAINING_RECORD(iface, BindProtocol, IInternetBindInfo_iface);
1056 }
1057 
1058 static HRESULT WINAPI BindInfo_QueryInterface(IInternetBindInfo *iface,
1059         REFIID riid, void **ppv)
1060 {
1061     BindProtocol *This = impl_from_IInternetBindInfo(iface);
1062     return IInternetProtocolEx_QueryInterface(&This->IInternetProtocolEx_iface, riid, ppv);
1063 }
1064 
1065 static ULONG WINAPI BindInfo_AddRef(IInternetBindInfo *iface)
1066 {
1067     BindProtocol *This = impl_from_IInternetBindInfo(iface);
1068     return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
1069 }
1070 
1071 static ULONG WINAPI BindInfo_Release(IInternetBindInfo *iface)
1072 {
1073     BindProtocol *This = impl_from_IInternetBindInfo(iface);
1074     return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
1075 }
1076 
1077 static HRESULT WINAPI BindInfo_GetBindInfo(IInternetBindInfo *iface,
1078         DWORD *grfBINDF, BINDINFO *pbindinfo)
1079 {
1080     BindProtocol *This = impl_from_IInternetBindInfo(iface);
1081     HRESULT hres;
1082 
1083     TRACE("(%p)->(%p %p)\n", This, grfBINDF, pbindinfo);
1084 
1085     hres = IInternetBindInfo_GetBindInfo(This->bind_info, grfBINDF, pbindinfo);
1086     if(FAILED(hres)) {
1087         WARN("GetBindInfo failed: %08x\n", hres);
1088         return hres;
1089     }
1090 
1091     if((pbindinfo->dwOptions & BINDINFO_OPTIONS_DISABLEAUTOREDIRECTS) && !This->redirect_callback) {
1092         IServiceProvider *service_provider;
1093 
1094         hres = IInternetProtocolSink_QueryInterface(This->protocol_sink, &IID_IServiceProvider, (void**)&service_provider);
1095         if(SUCCEEDED(hres)) {
1096             hres = IServiceProvider_QueryService(service_provider, &IID_IBindCallbackRedirect, &IID_IBindCallbackRedirect,
1097                                                  (void**)&This->redirect_callback);
1098             IServiceProvider_Release(service_provider);
1099         }
1100     }
1101 
1102     *grfBINDF |= BINDF_FROMURLMON;
1103     return hres;
1104 }
1105 
1106 static HRESULT WINAPI BindInfo_GetBindString(IInternetBindInfo *iface,
1107         ULONG ulStringType, LPOLESTR *ppwzStr, ULONG cEl, ULONG *pcElFetched)
1108 {
1109     BindProtocol *This = impl_from_IInternetBindInfo(iface);
1110 
1111     TRACE("(%p)->(%d %p %d %p)\n", This, ulStringType, ppwzStr, cEl, pcElFetched);
1112 
1113     return IInternetBindInfo_GetBindString(This->bind_info, ulStringType, ppwzStr, cEl, pcElFetched);
1114 }
1115 
1116 static const IInternetBindInfoVtbl InternetBindInfoVtbl = {
1117     BindInfo_QueryInterface,
1118     BindInfo_AddRef,
1119     BindInfo_Release,
1120     BindInfo_GetBindInfo,
1121     BindInfo_GetBindString
1122 };
1123 
1124 static inline BindProtocol *impl_from_IInternetPriority(IInternetPriority *iface)
1125 {
1126     return CONTAINING_RECORD(iface, BindProtocol, IInternetPriority_iface);
1127 }
1128 
1129 static HRESULT WINAPI InternetPriority_QueryInterface(IInternetPriority *iface,
1130         REFIID riid, void **ppv)
1131 {
1132     BindProtocol *This = impl_from_IInternetPriority(iface);
1133     return IInternetProtocolEx_QueryInterface(&This->IInternetProtocolEx_iface, riid, ppv);
1134 }
1135 
1136 static ULONG WINAPI InternetPriority_AddRef(IInternetPriority *iface)
1137 {
1138     BindProtocol *This = impl_from_IInternetPriority(iface);
1139     return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
1140 }
1141 
1142 static ULONG WINAPI InternetPriority_Release(IInternetPriority *iface)
1143 {
1144     BindProtocol *This = impl_from_IInternetPriority(iface);
1145     return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
1146 }
1147 
1148 static HRESULT WINAPI InternetPriority_SetPriority(IInternetPriority *iface, LONG nPriority)
1149 {
1150     BindProtocol *This = impl_from_IInternetPriority(iface);
1151 
1152     TRACE("(%p)->(%d)\n", This, nPriority);
1153 
1154     This->priority = nPriority;
1155     return S_OK;
1156 }
1157 
1158 static HRESULT WINAPI InternetPriority_GetPriority(IInternetPriority *iface, LONG *pnPriority)
1159 {
1160     BindProtocol *This = impl_from_IInternetPriority(iface);
1161 
1162     TRACE("(%p)->(%p)\n", This, pnPriority);
1163 
1164     *pnPriority = This->priority;
1165     return S_OK;
1166 }
1167 
1168 static const IInternetPriorityVtbl InternetPriorityVtbl = {
1169     InternetPriority_QueryInterface,
1170     InternetPriority_AddRef,
1171     InternetPriority_Release,
1172     InternetPriority_SetPriority,
1173     InternetPriority_GetPriority
1174 
1175 };
1176 
1177 static inline BindProtocol *impl_from_IInternetProtocolSink(IInternetProtocolSink *iface)
1178 {
1179     return CONTAINING_RECORD(iface, BindProtocol, IInternetProtocolSink_iface);
1180 }
1181 
1182 static HRESULT WINAPI BPInternetProtocolSink_QueryInterface(IInternetProtocolSink *iface,
1183         REFIID riid, void **ppv)
1184 {
1185     BindProtocol *This = impl_from_IInternetProtocolSink(iface);
1186     return IInternetProtocolEx_QueryInterface(&This->IInternetProtocolEx_iface, riid, ppv);
1187 }
1188 
1189 static ULONG WINAPI BPInternetProtocolSink_AddRef(IInternetProtocolSink *iface)
1190 {
1191     BindProtocol *This = impl_from_IInternetProtocolSink(iface);
1192     return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
1193 }
1194 
1195 static ULONG WINAPI BPInternetProtocolSink_Release(IInternetProtocolSink *iface)
1196 {
1197     BindProtocol *This = impl_from_IInternetProtocolSink(iface);
1198     return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
1199 }
1200 
1201 typedef struct {
1202     task_header_t header;
1203     PROTOCOLDATA *data;
1204 } switch_task_t;
1205 
1206 static void switch_proc(BindProtocol *bind, task_header_t *t)
1207 {
1208     switch_task_t *task = (switch_task_t*)t;
1209 
1210     IInternetProtocol_Continue(bind->protocol_handler, task->data);
1211 
1212     heap_free(task);
1213 }
1214 
1215 static HRESULT WINAPI BPInternetProtocolSink_Switch(IInternetProtocolSink *iface,
1216         PROTOCOLDATA *pProtocolData)
1217 {
1218     BindProtocol *This = impl_from_IInternetProtocolSink(iface);
1219     PROTOCOLDATA *data;
1220 
1221     TRACE("(%p)->(%p)\n", This, pProtocolData);
1222 
1223     TRACE("flags %x state %x data %p cb %u\n", pProtocolData->grfFlags, pProtocolData->dwState,
1224           pProtocolData->pData, pProtocolData->cbData);
1225 
1226     data = heap_alloc(sizeof(PROTOCOLDATA));
1227     if(!data)
1228         return E_OUTOFMEMORY;
1229     memcpy(data, pProtocolData, sizeof(PROTOCOLDATA));
1230 
1231     if((This->pi&PI_APARTMENTTHREADED && pProtocolData->grfFlags&PI_FORCE_ASYNC)
1232             || !do_direct_notif(This)) {
1233         switch_task_t *task;
1234 
1235         task = heap_alloc(sizeof(switch_task_t));
1236         if(!task)
1237         {
1238             heap_free(data);
1239             return E_OUTOFMEMORY;
1240         }
1241 
1242         task->data = data;
1243 
1244         push_task(This, &task->header, switch_proc);
1245         return S_OK;
1246     }
1247 
1248     return IInternetProtocolSink_Switch(This->protocol_sink_handler, data);
1249 }
1250 
1251 typedef struct {
1252     task_header_t header;
1253 
1254     ULONG status_code;
1255     LPWSTR status_text;
1256 } on_progress_task_t;
1257 
1258 static void on_progress_proc(BindProtocol *This, task_header_t *t)
1259 {
1260     on_progress_task_t *task = (on_progress_task_t*)t;
1261 
1262     IInternetProtocolSink_ReportProgress(This->protocol_sink_handler, task->status_code, task->status_text);
1263 
1264     heap_free(task->status_text);
1265     heap_free(task);
1266 }
1267 
1268 static HRESULT WINAPI BPInternetProtocolSink_ReportProgress(IInternetProtocolSink *iface,
1269         ULONG ulStatusCode, LPCWSTR szStatusText)
1270 {
1271     BindProtocol *This = impl_from_IInternetProtocolSink(iface);
1272 
1273     TRACE("(%p)->(%u %s)\n", This, ulStatusCode, debugstr_w(szStatusText));
1274 
1275     if(do_direct_notif(This)) {
1276         IInternetProtocolSink_ReportProgress(This->protocol_sink_handler, ulStatusCode, szStatusText);
1277     }else {
1278         on_progress_task_t *task;
1279 
1280         task = heap_alloc(sizeof(on_progress_task_t));
1281 
1282         task->status_code = ulStatusCode;
1283         task->status_text = heap_strdupW(szStatusText);
1284 
1285         push_task(This, &task->header, on_progress_proc);
1286     }
1287 
1288     return S_OK;
1289 }
1290 
1291 typedef struct {
1292     task_header_t header;
1293     DWORD bscf;
1294     ULONG progress;
1295     ULONG progress_max;
1296 } report_data_task_t;
1297 
1298 static void report_data_proc(BindProtocol *This, task_header_t *t)
1299 {
1300     report_data_task_t *task = (report_data_task_t*)t;
1301 
1302     IInternetProtocolSink_ReportData(This->protocol_sink_handler,
1303             task->bscf, task->progress, task->progress_max);
1304 
1305     heap_free(task);
1306 }
1307 
1308 static HRESULT WINAPI BPInternetProtocolSink_ReportData(IInternetProtocolSink *iface,
1309         DWORD grfBSCF, ULONG ulProgress, ULONG ulProgressMax)
1310 {
1311     BindProtocol *This = impl_from_IInternetProtocolSink(iface);
1312 
1313     TRACE("(%p)->(%x %u %u)\n", This, grfBSCF, ulProgress, ulProgressMax);
1314 
1315     if(!This->protocol_sink)
1316         return S_OK;
1317 
1318     if(!do_direct_notif(This)) {
1319         report_data_task_t *task;
1320 
1321         task = heap_alloc(sizeof(report_data_task_t));
1322         if(!task)
1323             return E_OUTOFMEMORY;
1324 
1325         task->bscf = grfBSCF;
1326         task->progress = ulProgress;
1327         task->progress_max = ulProgressMax;
1328 
1329         push_task(This, &task->header, report_data_proc);
1330         return S_OK;
1331     }
1332 
1333     return IInternetProtocolSink_ReportData(This->protocol_sink_handler,
1334             grfBSCF, ulProgress, ulProgressMax);
1335 }
1336 
1337 typedef struct {
1338     task_header_t header;
1339 
1340     HRESULT hres;
1341     DWORD err;
1342     LPWSTR str;
1343 } report_result_task_t;
1344 
1345 static void report_result_proc(BindProtocol *This, task_header_t *t)
1346 {
1347     report_result_task_t *task = (report_result_task_t*)t;
1348 
1349     IInternetProtocolSink_ReportResult(This->protocol_sink_handler, task->hres, task->err, task->str);
1350 
1351     heap_free(task->str);
1352     heap_free(task);
1353 }
1354 
1355 static HRESULT WINAPI BPInternetProtocolSink_ReportResult(IInternetProtocolSink *iface,
1356         HRESULT hrResult, DWORD dwError, LPCWSTR szResult)
1357 {
1358     BindProtocol *This = impl_from_IInternetProtocolSink(iface);
1359 
1360     TRACE("(%p)->(%08x %d %s)\n", This, hrResult, dwError, debugstr_w(szResult));
1361 
1362     if(!This->protocol_sink)
1363         return E_FAIL;
1364     This->reported_result = TRUE;
1365 
1366     if(!do_direct_notif(This)) {
1367         report_result_task_t *task;
1368 
1369         task = heap_alloc(sizeof(report_result_task_t));
1370         if(!task)
1371             return E_OUTOFMEMORY;
1372 
1373         task->hres = hrResult;
1374         task->err = dwError;
1375         task->str = heap_strdupW(szResult);
1376 
1377         push_task(This, &task->header, report_result_proc);
1378         return S_OK;
1379     }
1380 
1381     return IInternetProtocolSink_ReportResult(This->protocol_sink_handler, hrResult, dwError, szResult);
1382 }
1383 
1384 static const IInternetProtocolSinkVtbl InternetProtocolSinkVtbl = {
1385     BPInternetProtocolSink_QueryInterface,
1386     BPInternetProtocolSink_AddRef,
1387     BPInternetProtocolSink_Release,
1388     BPInternetProtocolSink_Switch,
1389     BPInternetProtocolSink_ReportProgress,
1390     BPInternetProtocolSink_ReportData,
1391     BPInternetProtocolSink_ReportResult
1392 };
1393 
1394 static inline BindProtocol *impl_from_IWinInetHttpInfo(IWinInetHttpInfo *iface)
1395 {
1396     return CONTAINING_RECORD(iface, BindProtocol, IWinInetHttpInfo_iface);
1397 }
1398 
1399 static HRESULT WINAPI WinInetHttpInfo_QueryInterface(IWinInetHttpInfo *iface, REFIID riid, void **ppv)
1400 {
1401     BindProtocol *This = impl_from_IWinInetHttpInfo(iface);
1402     return IInternetProtocolEx_QueryInterface(&This->IInternetProtocolEx_iface, riid, ppv);
1403 }
1404 
1405 static ULONG WINAPI WinInetHttpInfo_AddRef(IWinInetHttpInfo *iface)
1406 {
1407     BindProtocol *This = impl_from_IWinInetHttpInfo(iface);
1408     return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
1409 }
1410 
1411 static ULONG WINAPI WinInetHttpInfo_Release(IWinInetHttpInfo *iface)
1412 {
1413     BindProtocol *This = impl_from_IWinInetHttpInfo(iface);
1414     return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
1415 }
1416 
1417 static HRESULT WINAPI WinInetHttpInfo_QueryOption(IWinInetHttpInfo *iface, DWORD dwOption,
1418         void *pBuffer, DWORD *pcbBuffer)
1419 {
1420     BindProtocol *This = impl_from_IWinInetHttpInfo(iface);
1421     FIXME("(%p)->(%x %p %p)\n", This, dwOption, pBuffer, pcbBuffer);
1422     return E_NOTIMPL;
1423 }
1424 
1425 static HRESULT WINAPI WinInetHttpInfo_QueryInfo(IWinInetHttpInfo *iface, DWORD dwOption,
1426         void *pBuffer, DWORD *pcbBuffer, DWORD *pdwFlags, DWORD *pdwReserved)
1427 {
1428     BindProtocol *This = impl_from_IWinInetHttpInfo(iface);
1429     FIXME("(%p)->(%x %p %p %p %p)\n", This, dwOption, pBuffer, pcbBuffer, pdwFlags, pdwReserved);
1430     return E_NOTIMPL;
1431 }
1432 
1433 static const IWinInetHttpInfoVtbl WinInetHttpInfoVtbl = {
1434     WinInetHttpInfo_QueryInterface,
1435     WinInetHttpInfo_AddRef,
1436     WinInetHttpInfo_Release,
1437     WinInetHttpInfo_QueryOption,
1438     WinInetHttpInfo_QueryInfo
1439 };
1440 
1441 static inline BindProtocol *impl_from_IServiceProvider(IServiceProvider *iface)
1442 {
1443     return CONTAINING_RECORD(iface, BindProtocol, IServiceProvider_iface);
1444 }
1445 
1446 static HRESULT WINAPI BPServiceProvider_QueryInterface(IServiceProvider *iface,
1447         REFIID riid, void **ppv)
1448 {
1449     BindProtocol *This = impl_from_IServiceProvider(iface);
1450     return IInternetProtocolEx_QueryInterface(&This->IInternetProtocolEx_iface, riid, ppv);
1451 }
1452 
1453 static ULONG WINAPI BPServiceProvider_AddRef(IServiceProvider *iface)
1454 {
1455     BindProtocol *This = impl_from_IServiceProvider(iface);
1456     return IInternetProtocolEx_AddRef(&This->IInternetProtocolEx_iface);
1457 }
1458 
1459 static ULONG WINAPI BPServiceProvider_Release(IServiceProvider *iface)
1460 {
1461     BindProtocol *This = impl_from_IServiceProvider(iface);
1462     return IInternetProtocolEx_Release(&This->IInternetProtocolEx_iface);
1463 }
1464 
1465 static HRESULT WINAPI BPServiceProvider_QueryService(IServiceProvider *iface,
1466         REFGUID guidService, REFIID riid, void **ppv)
1467 {
1468     BindProtocol *This = impl_from_IServiceProvider(iface);
1469 
1470     TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
1471 
1472     if(!This->service_provider)
1473         return E_NOINTERFACE;
1474 
1475     return IServiceProvider_QueryService(This->service_provider, guidService, riid, ppv);
1476 }
1477 
1478 static const IServiceProviderVtbl ServiceProviderVtbl = {
1479     BPServiceProvider_QueryInterface,
1480     BPServiceProvider_AddRef,
1481     BPServiceProvider_Release,
1482     BPServiceProvider_QueryService
1483 };
1484 
1485 HRESULT create_binding_protocol(BOOL from_urlmon, BindProtocol **protocol)
1486 {
1487     BindProtocol *ret = heap_alloc_zero(sizeof(BindProtocol));
1488 
1489     ret->IInternetProtocolEx_iface.lpVtbl   = &BindProtocolVtbl;
1490     ret->IInternetBindInfo_iface.lpVtbl     = &InternetBindInfoVtbl;
1491     ret->IInternetPriority_iface.lpVtbl     = &InternetPriorityVtbl;
1492     ret->IServiceProvider_iface.lpVtbl      = &ServiceProviderVtbl;
1493     ret->IInternetProtocolSink_iface.lpVtbl = &InternetProtocolSinkVtbl;
1494     ret->IWinInetHttpInfo_iface.lpVtbl      = &WinInetHttpInfoVtbl;
1495 
1496     ret->default_protocol_handler.IInternetProtocol_iface.lpVtbl = &InternetProtocolHandlerVtbl;
1497     ret->default_protocol_handler.IInternetProtocolSink_iface.lpVtbl = &InternetProtocolSinkHandlerVtbl;
1498 
1499     ret->ref = 1;
1500     ret->from_urlmon = from_urlmon;
1501     ret->apartment_thread = GetCurrentThreadId();
1502     ret->notif_hwnd = get_notif_hwnd();
1503     ret->protocol_handler = &ret->default_protocol_handler.IInternetProtocol_iface;
1504     ret->protocol_sink_handler = &ret->default_protocol_handler.IInternetProtocolSink_iface;
1505     InitializeCriticalSection(&ret->section);
1506     ret->section.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": BindProtocol.section");
1507 
1508     URLMON_LockModule();
1509 
1510     *protocol = ret;
1511     return S_OK;
1512 }
1513