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