urlmon: Added support for PI_APARTMENTTHREADED to BindProtocol::ReportProgress.
[wine] / dlls / urlmon / bindprot.c
1 /*
2  * Copyright 2007 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 IInternetProtocolVtbl *lpInternetProtocolVtbl;
37     const IInternetBindInfoVtbl *lpInternetBindInfoVtbl;
38     const IInternetPriorityVtbl *lpInternetPriorityVtbl;
39     const IServiceProviderVtbl  *lpServiceProviderVtbl;
40     const IInternetProtocolSinkVtbl *lpInternetProtocolSinkVtbl;
41
42     LONG ref;
43
44     IInternetProtocol *protocol;
45     IInternetBindInfo *bind_info;
46     IInternetProtocolSink *protocol_sink;
47     IServiceProvider *service_provider;
48     IWinInetInfo *wininet_info;
49
50     LONG priority;
51
52     BOOL reported_result;
53     BOOL from_urlmon;
54     DWORD pi;
55
56     DWORD apartment_thread;
57     HWND notif_hwnd;
58     DWORD continue_call;
59
60     CRITICAL_SECTION section;
61     task_header_t *task_queue_head, *task_queue_tail;
62 };
63
64 #define PROTOCOL(x)  ((IInternetProtocol*) &(x)->lpInternetProtocolVtbl)
65 #define BINDINFO(x)  ((IInternetBindInfo*) &(x)->lpInternetBindInfoVtbl)
66 #define PRIORITY(x)  ((IInternetPriority*) &(x)->lpInternetPriorityVtbl)
67 #define SERVPROV(x)  ((IServiceProvider*)  &(x)->lpServiceProviderVtbl)
68 #define PROTSINK(x)  ((IInternetProtocolSink*) &(x)->lpInternetProtocolSinkVtbl)
69
70 void handle_bindprot_task(void *v)
71 {
72     BindProtocol *This = v;
73     task_header_t *task;
74
75     while(1) {
76         EnterCriticalSection(&This->section);
77
78         task = This->task_queue_head;
79         if(task) {
80             This->task_queue_head = task->next;
81             if(!This->task_queue_head)
82                 This->task_queue_tail = NULL;
83         }
84
85         LeaveCriticalSection(&This->section);
86
87         if(!task)
88             break;
89
90         This->continue_call++;
91         task->proc(This, task);
92         This->continue_call--;
93     }
94
95     IInternetProtocol_Release(PROTOCOL(This));
96 }
97
98 static void push_task(BindProtocol *This, task_header_t *task, task_proc_t proc)
99 {
100     BOOL do_post = FALSE;
101
102     task->proc = proc;
103     task->next = NULL;
104
105     EnterCriticalSection(&This->section);
106
107     if(This->task_queue_tail) {
108         This->task_queue_tail->next = task;
109         This->task_queue_tail = task;
110     }else {
111         This->task_queue_tail = This->task_queue_head = task;
112         do_post = TRUE;
113     }
114
115     LeaveCriticalSection(&This->section);
116
117     if(do_post) {
118         IInternetProtocol_AddRef(PROTOCOL(This));
119         PostMessageW(This->notif_hwnd, WM_MK_CONTINUE2, 0, (LPARAM)This);
120     }
121 }
122
123 static BOOL inline do_direct_notif(BindProtocol *This)
124 {
125     return !(This->pi & PI_APARTMENTTHREADED) || (This->apartment_thread == GetCurrentThreadId() && !This->continue_call);
126 }
127
128 #define PROTOCOL_THIS(iface) DEFINE_THIS(BindProtocol, InternetProtocol, iface)
129
130 static HRESULT WINAPI BindProtocol_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv)
131 {
132     BindProtocol *This = PROTOCOL_THIS(iface);
133
134     *ppv = NULL;
135     if(IsEqualGUID(&IID_IUnknown, riid)) {
136         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
137         *ppv = PROTOCOL(This);
138     }else if(IsEqualGUID(&IID_IInternetProtocolRoot, riid)) {
139         TRACE("(%p)->(IID_IInternetProtocolRoot %p)\n", This, ppv);
140         *ppv = PROTOCOL(This);
141     }else if(IsEqualGUID(&IID_IInternetProtocol, riid)) {
142         TRACE("(%p)->(IID_IInternetProtocol %p)\n", This, ppv);
143         *ppv = PROTOCOL(This);
144     }else if(IsEqualGUID(&IID_IInternetBindInfo, riid)) {
145         TRACE("(%p)->(IID_IInternetBindInfo %p)\n", This, ppv);
146         *ppv = BINDINFO(This);
147     }else if(IsEqualGUID(&IID_IInternetPriority, riid)) {
148         TRACE("(%p)->(IID_IInternetPriority %p)\n", This, ppv);
149         *ppv = PRIORITY(This);
150     }else if(IsEqualGUID(&IID_IAuthenticate, riid)) {
151         FIXME("(%p)->(IID_IAuthenticate %p)\n", This, ppv);
152     }else if(IsEqualGUID(&IID_IServiceProvider, riid)) {
153         TRACE("(%p)->(IID_IServiceProvider %p)\n", This, ppv);
154         *ppv = SERVPROV(This);
155     }else if(IsEqualGUID(&IID_IInternetProtocolSink, riid)) {
156         TRACE("(%p)->(IID_IInternetProtocolSink %p)\n", This, ppv);
157         *ppv = PROTSINK(This);
158     }
159
160     if(*ppv) {
161         IInternetProtocol_AddRef(iface);
162         return S_OK;
163     }
164
165     WARN("not supported interface %s\n", debugstr_guid(riid));
166     return E_NOINTERFACE;
167 }
168
169 static ULONG WINAPI BindProtocol_AddRef(IInternetProtocol *iface)
170 {
171     BindProtocol *This = PROTOCOL_THIS(iface);
172     LONG ref = InterlockedIncrement(&This->ref);
173     TRACE("(%p) ref=%d\n", This, ref);
174     return ref;
175 }
176
177 static ULONG WINAPI BindProtocol_Release(IInternetProtocol *iface)
178 {
179     BindProtocol *This = PROTOCOL_THIS(iface);
180     LONG ref = InterlockedDecrement(&This->ref);
181
182     TRACE("(%p) ref=%d\n", This, ref);
183
184     if(!ref) {
185         if(This->wininet_info)
186             IWinInetInfo_Release(This->wininet_info);
187         if(This->protocol)
188             IInternetProtocol_Release(This->protocol);
189         if(This->bind_info)
190             IInternetBindInfo_Release(This->bind_info);
191
192         set_binding_sink(PROTOCOL(This), NULL);
193
194         if(This->notif_hwnd)
195             release_notif_hwnd(This->notif_hwnd);
196         DeleteCriticalSection(&This->section);
197         heap_free(This);
198
199         URLMON_UnlockModule();
200     }
201
202     return ref;
203 }
204
205 static HRESULT WINAPI BindProtocol_Start(IInternetProtocol *iface, LPCWSTR szUrl,
206         IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
207         DWORD grfPI, HANDLE_PTR dwReserved)
208 {
209     BindProtocol *This = PROTOCOL_THIS(iface);
210     IInternetProtocol *protocol = NULL;
211     IInternetPriority *priority;
212     IServiceProvider *service_provider;
213     BOOL urlmon_protocol = FALSE;
214     CLSID clsid = IID_NULL;
215     LPOLESTR clsid_str;
216     HRESULT hres;
217
218     TRACE("(%p)->(%s %p %p %08x %lx)\n", This, debugstr_w(szUrl), pOIProtSink,
219             pOIBindInfo, grfPI, dwReserved);
220
221     if(!szUrl || !pOIProtSink || !pOIBindInfo)
222         return E_INVALIDARG;
223
224     This->pi = grfPI;
225
226     hres = IInternetProtocolSink_QueryInterface(pOIProtSink, &IID_IServiceProvider,
227                                                 (void**)&service_provider);
228     if(SUCCEEDED(hres)) {
229         /* FIXME: What's protocol CLSID here? */
230         IServiceProvider_QueryService(service_provider, &IID_IInternetProtocol,
231                                       &IID_IInternetProtocol, (void**)&protocol);
232         IServiceProvider_Release(service_provider);
233     }
234
235     if(!protocol) {
236         IClassFactory *cf;
237         IUnknown *unk;
238
239         hres = get_protocol_handler(szUrl, &clsid, &urlmon_protocol, &cf);
240         if(FAILED(hres))
241             return hres;
242
243         if(This->from_urlmon) {
244             hres = IClassFactory_CreateInstance(cf, NULL, &IID_IInternetProtocol, (void**)&protocol);
245             IClassFactory_Release(cf);
246             if(FAILED(hres))
247                 return hres;
248         }else {
249             hres = IClassFactory_CreateInstance(cf, (IUnknown*)BINDINFO(This),
250                     &IID_IUnknown, (void**)&unk);
251             IClassFactory_Release(cf);
252             if(FAILED(hres))
253                 return hres;
254
255             hres = IUnknown_QueryInterface(unk, &IID_IInternetProtocol, (void**)&protocol);
256             IUnknown_Release(unk);
257             if(FAILED(hres))
258                 return hres;
259         }
260     }
261
262     StringFromCLSID(&clsid, &clsid_str);
263     IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_PROTOCOLCLASSID, clsid_str);
264     CoTaskMemFree(clsid_str);
265
266     This->protocol = protocol;
267
268     if(urlmon_protocol)
269         IInternetProtocol_QueryInterface(protocol, &IID_IWinInetInfo, (void**)&This->wininet_info);
270
271     IInternetBindInfo_AddRef(pOIBindInfo);
272     This->bind_info = pOIBindInfo;
273
274     set_binding_sink(PROTOCOL(This), pOIProtSink);
275
276     hres = IInternetProtocol_QueryInterface(protocol, &IID_IInternetPriority, (void**)&priority);
277     if(SUCCEEDED(hres)) {
278         IInternetPriority_SetPriority(priority, This->priority);
279         IInternetPriority_Release(priority);
280     }
281
282     return IInternetProtocol_Start(protocol, szUrl, PROTSINK(This), BINDINFO(This), 0, 0);
283 }
284
285 static HRESULT WINAPI BindProtocol_Continue(IInternetProtocol *iface, PROTOCOLDATA *pProtocolData)
286 {
287     BindProtocol *This = PROTOCOL_THIS(iface);
288
289     TRACE("(%p)->(%p)\n", This, pProtocolData);
290
291     return IInternetProtocol_Continue(This->protocol, pProtocolData);
292 }
293
294 static HRESULT WINAPI BindProtocol_Abort(IInternetProtocol *iface, HRESULT hrReason,
295         DWORD dwOptions)
296 {
297     BindProtocol *This = PROTOCOL_THIS(iface);
298     FIXME("(%p)->(%08x %08x)\n", This, hrReason, dwOptions);
299     return E_NOTIMPL;
300 }
301
302 static HRESULT WINAPI BindProtocol_Terminate(IInternetProtocol *iface, DWORD dwOptions)
303 {
304     BindProtocol *This = PROTOCOL_THIS(iface);
305
306     TRACE("(%p)->(%08x)\n", This, dwOptions);
307
308     if(!This->reported_result)
309         return E_FAIL;
310
311     IInternetProtocol_Terminate(This->protocol, 0);
312
313     set_binding_sink(PROTOCOL(This), NULL);
314
315     if(This->bind_info) {
316         IInternetBindInfo_Release(This->bind_info);
317         This->bind_info = NULL;
318     }
319
320     return S_OK;
321 }
322
323 static HRESULT WINAPI BindProtocol_Suspend(IInternetProtocol *iface)
324 {
325     BindProtocol *This = PROTOCOL_THIS(iface);
326     FIXME("(%p)\n", This);
327     return E_NOTIMPL;
328 }
329
330 static HRESULT WINAPI BindProtocol_Resume(IInternetProtocol *iface)
331 {
332     BindProtocol *This = PROTOCOL_THIS(iface);
333     FIXME("(%p)\n", This);
334     return E_NOTIMPL;
335 }
336
337 static HRESULT WINAPI BindProtocol_Read(IInternetProtocol *iface, void *pv,
338         ULONG cb, ULONG *pcbRead)
339 {
340     BindProtocol *This = PROTOCOL_THIS(iface);
341     ULONG read = 0;
342     HRESULT hres;
343
344     TRACE("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead);
345
346     hres = IInternetProtocol_Read(This->protocol, pv, cb, &read);
347
348     *pcbRead = read;
349     return hres;
350 }
351
352 static HRESULT WINAPI BindProtocol_Seek(IInternetProtocol *iface, LARGE_INTEGER dlibMove,
353         DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
354 {
355     BindProtocol *This = PROTOCOL_THIS(iface);
356     FIXME("(%p)->(%d %d %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
357     return E_NOTIMPL;
358 }
359
360 static HRESULT WINAPI BindProtocol_LockRequest(IInternetProtocol *iface, DWORD dwOptions)
361 {
362     BindProtocol *This = PROTOCOL_THIS(iface);
363
364     TRACE("(%p)->(%08x)\n", This, dwOptions);
365
366     return IInternetProtocol_LockRequest(This->protocol, dwOptions);
367 }
368
369 static HRESULT WINAPI BindProtocol_UnlockRequest(IInternetProtocol *iface)
370 {
371     BindProtocol *This = PROTOCOL_THIS(iface);
372
373     TRACE("(%p)\n", This);
374
375     return IInternetProtocol_UnlockRequest(This->protocol);
376 }
377
378 void set_binding_sink(IInternetProtocol *bind_protocol, IInternetProtocolSink *sink)
379 {
380     BindProtocol *This = PROTOCOL_THIS(bind_protocol);
381     IInternetProtocolSink *prev_sink;
382     IServiceProvider *service_provider = NULL;
383
384     if(sink)
385         IInternetProtocolSink_AddRef(sink);
386     prev_sink = InterlockedExchangePointer((void**)&This->protocol_sink, sink);
387     if(prev_sink)
388         IInternetProtocolSink_Release(prev_sink);
389
390     if(sink)
391         IInternetProtocolSink_QueryInterface(sink, &IID_IServiceProvider, (void**)&service_provider);
392     service_provider = InterlockedExchangePointer((void**)&This->service_provider, service_provider);
393     if(service_provider)
394         IServiceProvider_Release(service_provider);
395 }
396
397 IWinInetInfo *get_wininet_info(IInternetProtocol *bind_protocol)
398 {
399     BindProtocol *This = PROTOCOL_THIS(bind_protocol);
400
401     return This->wininet_info;
402 }
403
404 #undef PROTOCOL_THIS
405
406 static const IInternetProtocolVtbl BindProtocolVtbl = {
407     BindProtocol_QueryInterface,
408     BindProtocol_AddRef,
409     BindProtocol_Release,
410     BindProtocol_Start,
411     BindProtocol_Continue,
412     BindProtocol_Abort,
413     BindProtocol_Terminate,
414     BindProtocol_Suspend,
415     BindProtocol_Resume,
416     BindProtocol_Read,
417     BindProtocol_Seek,
418     BindProtocol_LockRequest,
419     BindProtocol_UnlockRequest
420 };
421
422 #define BINDINFO_THIS(iface) DEFINE_THIS(BindProtocol, InternetBindInfo, iface)
423
424 static HRESULT WINAPI BindInfo_QueryInterface(IInternetBindInfo *iface,
425         REFIID riid, void **ppv)
426 {
427     BindProtocol *This = BINDINFO_THIS(iface);
428     return IInternetProtocol_QueryInterface(PROTOCOL(This), riid, ppv);
429 }
430
431 static ULONG WINAPI BindInfo_AddRef(IInternetBindInfo *iface)
432 {
433     BindProtocol *This = BINDINFO_THIS(iface);
434     return IBinding_AddRef(PROTOCOL(This));
435 }
436
437 static ULONG WINAPI BindInfo_Release(IInternetBindInfo *iface)
438 {
439     BindProtocol *This = BINDINFO_THIS(iface);
440     return IBinding_Release(PROTOCOL(This));
441 }
442
443 static HRESULT WINAPI BindInfo_GetBindInfo(IInternetBindInfo *iface,
444         DWORD *grfBINDF, BINDINFO *pbindinfo)
445 {
446     BindProtocol *This = BINDINFO_THIS(iface);
447     HRESULT hres;
448
449     TRACE("(%p)->(%p %p)\n", This, grfBINDF, pbindinfo);
450
451     hres = IInternetBindInfo_GetBindInfo(This->bind_info, grfBINDF, pbindinfo);
452     if(FAILED(hres)) {
453         WARN("GetBindInfo failed: %08x\n", hres);
454         return hres;
455     }
456
457     *grfBINDF |= BINDF_FROMURLMON;
458     return hres;
459 }
460
461 static HRESULT WINAPI BindInfo_GetBindString(IInternetBindInfo *iface,
462         ULONG ulStringType, LPOLESTR *ppwzStr, ULONG cEl, ULONG *pcElFetched)
463 {
464     BindProtocol *This = BINDINFO_THIS(iface);
465
466     TRACE("(%p)->(%d %p %d %p)\n", This, ulStringType, ppwzStr, cEl, pcElFetched);
467
468     return IInternetBindInfo_GetBindString(This->bind_info, ulStringType, ppwzStr, cEl, pcElFetched);
469 }
470
471 #undef BINDFO_THIS
472
473 static const IInternetBindInfoVtbl InternetBindInfoVtbl = {
474     BindInfo_QueryInterface,
475     BindInfo_AddRef,
476     BindInfo_Release,
477     BindInfo_GetBindInfo,
478     BindInfo_GetBindString
479 };
480
481 #define PRIORITY_THIS(iface) DEFINE_THIS(BindProtocol, InternetPriority, iface)
482
483 static HRESULT WINAPI InternetPriority_QueryInterface(IInternetPriority *iface,
484         REFIID riid, void **ppv)
485 {
486     BindProtocol *This = PRIORITY_THIS(iface);
487     return IInternetProtocol_QueryInterface(PROTOCOL(This), riid, ppv);
488 }
489
490 static ULONG WINAPI InternetPriority_AddRef(IInternetPriority *iface)
491 {
492     BindProtocol *This = PRIORITY_THIS(iface);
493     return IInternetProtocol_AddRef(PROTOCOL(This));
494 }
495
496 static ULONG WINAPI InternetPriority_Release(IInternetPriority *iface)
497 {
498     BindProtocol *This = PRIORITY_THIS(iface);
499     return IInternetProtocol_Release(PROTOCOL(This));
500 }
501
502 static HRESULT WINAPI InternetPriority_SetPriority(IInternetPriority *iface, LONG nPriority)
503 {
504     BindProtocol *This = PRIORITY_THIS(iface);
505
506     TRACE("(%p)->(%d)\n", This, nPriority);
507
508     This->priority = nPriority;
509     return S_OK;
510 }
511
512 static HRESULT WINAPI InternetPriority_GetPriority(IInternetPriority *iface, LONG *pnPriority)
513 {
514     BindProtocol *This = PRIORITY_THIS(iface);
515
516     TRACE("(%p)->(%p)\n", This, pnPriority);
517
518     *pnPriority = This->priority;
519     return S_OK;
520 }
521
522 #undef PRIORITY_THIS
523
524 static const IInternetPriorityVtbl InternetPriorityVtbl = {
525     InternetPriority_QueryInterface,
526     InternetPriority_AddRef,
527     InternetPriority_Release,
528     InternetPriority_SetPriority,
529     InternetPriority_GetPriority
530
531 };
532
533 #define PROTSINK_THIS(iface) DEFINE_THIS(BindProtocol, InternetProtocolSink, iface)
534
535 static HRESULT WINAPI BPInternetProtocolSink_QueryInterface(IInternetProtocolSink *iface,
536         REFIID riid, void **ppv)
537 {
538     BindProtocol *This = PROTSINK_THIS(iface);
539     return IInternetProtocol_QueryInterface(PROTOCOL(This), riid, ppv);
540 }
541
542 static ULONG WINAPI BPInternetProtocolSink_AddRef(IInternetProtocolSink *iface)
543 {
544     BindProtocol *This = PROTSINK_THIS(iface);
545     return IInternetProtocol_AddRef(PROTOCOL(This));
546 }
547
548 static ULONG WINAPI BPInternetProtocolSink_Release(IInternetProtocolSink *iface)
549 {
550     BindProtocol *This = PROTSINK_THIS(iface);
551     return IInternetProtocol_Release(PROTOCOL(This));
552 }
553
554 typedef struct {
555     task_header_t header;
556     PROTOCOLDATA data;
557 } switch_task_t;
558
559 static void switch_proc(BindProtocol *bind, task_header_t *t)
560 {
561     switch_task_t *task = (switch_task_t*)t;
562
563     IInternetProtocol_Continue(bind->protocol, &task->data);
564
565     heap_free(task);
566 }
567
568 static HRESULT WINAPI BPInternetProtocolSink_Switch(IInternetProtocolSink *iface,
569         PROTOCOLDATA *pProtocolData)
570 {
571     BindProtocol *This = PROTSINK_THIS(iface);
572
573     TRACE("(%p)->(%p)\n", This, pProtocolData);
574
575     TRACE("flags %x state %x data %p cb %u\n", pProtocolData->grfFlags, pProtocolData->dwState,
576           pProtocolData->pData, pProtocolData->cbData);
577
578     if(!do_direct_notif(This)) {
579         switch_task_t *task;
580
581         task = heap_alloc(sizeof(switch_task_t));
582         if(!task)
583             return E_OUTOFMEMORY;
584
585         task->data = *pProtocolData;
586
587         push_task(This, &task->header, switch_proc);
588         return S_OK;
589     }
590
591     if(!This->protocol_sink) {
592         IInternetProtocol_Continue(This->protocol, pProtocolData);
593         return S_OK;
594     }
595
596     return IInternetProtocolSink_Switch(This->protocol_sink, pProtocolData);
597 }
598
599 typedef struct {
600     task_header_t header;
601
602     ULONG status_code;
603     LPWSTR status_text;
604 } on_progress_task_t;
605
606 static void on_progress_proc(BindProtocol *This, task_header_t *t)
607 {
608     on_progress_task_t *task = (on_progress_task_t*)t;
609
610     IInternetProtocolSink_ReportProgress(This->protocol_sink, task->status_code, task->status_text);
611
612     heap_free(task->status_text);
613     heap_free(task);
614 }
615
616 static void report_progress(BindProtocol *This, ULONG status_code, LPCWSTR status_text)
617 {
618     if(do_direct_notif(This)) {
619         IInternetProtocolSink_ReportProgress(This->protocol_sink, status_code, status_text);
620     }else {
621         on_progress_task_t *task;
622
623         task = heap_alloc(sizeof(on_progress_task_t));
624
625         task->status_code = status_code;
626         task->status_text = heap_strdupW(status_text);
627
628         push_task(This, &task->header, on_progress_proc);
629     }
630 }
631
632 static HRESULT WINAPI BPInternetProtocolSink_ReportProgress(IInternetProtocolSink *iface,
633         ULONG ulStatusCode, LPCWSTR szStatusText)
634 {
635     BindProtocol *This = PROTSINK_THIS(iface);
636
637     TRACE("(%p)->(%u %s)\n", This, ulStatusCode, debugstr_w(szStatusText));
638
639     switch(ulStatusCode) {
640     case BINDSTATUS_FINDINGRESOURCE:
641     case BINDSTATUS_CONNECTING:
642     case BINDSTATUS_BEGINDOWNLOADDATA:
643     case BINDSTATUS_SENDINGREQUEST:
644     case BINDSTATUS_CACHEFILENAMEAVAILABLE:
645     case BINDSTATUS_DIRECTBIND:
646     case BINDSTATUS_ACCEPTRANGES:
647     case BINDSTATUS_MIMETYPEAVAILABLE:
648         if(!This->protocol_sink)
649             return S_OK;
650         report_progress(This, ulStatusCode, szStatusText);
651         break;
652
653     case BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE:
654         if(!This->protocol_sink)
655             return S_OK;
656         report_progress(This,
657                 This->from_urlmon ? BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE : BINDSTATUS_MIMETYPEAVAILABLE,
658                 szStatusText);
659         break;
660
661     default:
662         FIXME("unsupported ulStatusCode %u\n", ulStatusCode);
663         return E_NOTIMPL;
664     }
665
666     return S_OK;
667 }
668
669 static HRESULT WINAPI BPInternetProtocolSink_ReportData(IInternetProtocolSink *iface,
670         DWORD grfBSCF, ULONG ulProgress, ULONG ulProgressMax)
671 {
672     BindProtocol *This = PROTSINK_THIS(iface);
673
674     TRACE("(%p)->(%d %u %u)\n", This, grfBSCF, ulProgress, ulProgressMax);
675
676     if(!This->protocol_sink)
677         return S_OK;
678
679     return IInternetProtocolSink_ReportData(This->protocol_sink, grfBSCF, ulProgress, ulProgressMax);
680 }
681
682 static HRESULT WINAPI BPInternetProtocolSink_ReportResult(IInternetProtocolSink *iface,
683         HRESULT hrResult, DWORD dwError, LPCWSTR szResult)
684 {
685     BindProtocol *This = PROTSINK_THIS(iface);
686
687     TRACE("(%p)->(%08x %d %s)\n", This, hrResult, dwError, debugstr_w(szResult));
688
689     if(!This->protocol_sink)
690         return E_FAIL;
691
692     This->reported_result = TRUE;
693
694     return IInternetProtocolSink_ReportResult(This->protocol_sink, hrResult, dwError, szResult);
695 }
696
697 #undef PROTSINK_THIS
698
699 static const IInternetProtocolSinkVtbl InternetProtocolSinkVtbl = {
700     BPInternetProtocolSink_QueryInterface,
701     BPInternetProtocolSink_AddRef,
702     BPInternetProtocolSink_Release,
703     BPInternetProtocolSink_Switch,
704     BPInternetProtocolSink_ReportProgress,
705     BPInternetProtocolSink_ReportData,
706     BPInternetProtocolSink_ReportResult
707 };
708
709 #define SERVPROV_THIS(iface) DEFINE_THIS(BindProtocol, ServiceProvider, iface)
710
711 static HRESULT WINAPI BPServiceProvider_QueryInterface(IServiceProvider *iface,
712         REFIID riid, void **ppv)
713 {
714     BindProtocol *This = SERVPROV_THIS(iface);
715     return IInternetProtocol_QueryInterface(PROTOCOL(This), riid, ppv);
716 }
717
718 static ULONG WINAPI BPServiceProvider_AddRef(IServiceProvider *iface)
719 {
720     BindProtocol *This = SERVPROV_THIS(iface);
721     return IInternetProtocol_AddRef(PROTOCOL(This));
722 }
723
724 static ULONG WINAPI BPServiceProvider_Release(IServiceProvider *iface)
725 {
726     BindProtocol *This = SERVPROV_THIS(iface);
727     return IInternetProtocol_Release(PROTOCOL(This));
728 }
729
730 static HRESULT WINAPI BPServiceProvider_QueryService(IServiceProvider *iface,
731         REFGUID guidService, REFIID riid, void **ppv)
732 {
733     BindProtocol *This = SERVPROV_THIS(iface);
734
735     TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
736
737     if(!This->service_provider)
738         return E_NOINTERFACE;
739
740     return IServiceProvider_QueryService(This->service_provider, guidService, riid, ppv);
741 }
742
743 #undef SERVPROV_THIS
744
745 static const IServiceProviderVtbl ServiceProviderVtbl = {
746     BPServiceProvider_QueryInterface,
747     BPServiceProvider_AddRef,
748     BPServiceProvider_Release,
749     BPServiceProvider_QueryService
750 };
751
752 HRESULT create_binding_protocol(LPCWSTR url, BOOL from_urlmon, IInternetProtocol **protocol)
753 {
754     BindProtocol *ret = heap_alloc_zero(sizeof(BindProtocol));
755
756     ret->lpInternetProtocolVtbl = &BindProtocolVtbl;
757     ret->lpInternetBindInfoVtbl = &InternetBindInfoVtbl;
758     ret->lpInternetPriorityVtbl = &InternetPriorityVtbl;
759     ret->lpServiceProviderVtbl  = &ServiceProviderVtbl;
760     ret->lpInternetProtocolSinkVtbl = &InternetProtocolSinkVtbl;
761
762     ret->ref = 1;
763     ret->from_urlmon = from_urlmon;
764     ret->apartment_thread = GetCurrentThreadId();
765     ret->notif_hwnd = get_notif_hwnd();
766     InitializeCriticalSection(&ret->section);
767
768     URLMON_LockModule();
769
770     *protocol = PROTOCOL(ret);
771     return S_OK;
772 }