wininet: Send notifications from InternetWriteFile.
[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 {
25     const IInternetProtocolVtbl *lpInternetProtocolVtbl;
26     const IInternetBindInfoVtbl *lpInternetBindInfoVtbl;
27     const IInternetPriorityVtbl *lpInternetPriorityVtbl;
28     const IServiceProviderVtbl  *lpServiceProviderVtbl;
29     const IInternetProtocolSinkVtbl *lpInternetProtocolSinkVtbl;
30
31     LONG ref;
32
33     IInternetProtocol *protocol;
34     IInternetBindInfo *bind_info;
35     IInternetProtocolSink *protocol_sink;
36     IServiceProvider *service_provider;
37     IWinInetInfo *wininet_info;
38
39     LONG priority;
40
41     BOOL reported_result;
42     BOOL from_urlmon;
43 } BindProtocol;
44
45 #define PROTOCOL(x)  ((IInternetProtocol*) &(x)->lpInternetProtocolVtbl)
46 #define BINDINFO(x)  ((IInternetBindInfo*) &(x)->lpInternetBindInfoVtbl)
47 #define PRIORITY(x)  ((IInternetPriority*) &(x)->lpInternetPriorityVtbl)
48 #define SERVPROV(x)  ((IServiceProvider*)  &(x)->lpServiceProviderVtbl)
49 #define PROTSINK(x)  ((IInternetProtocolSink*) &(x)->lpInternetProtocolSinkVtbl)
50
51 #define PROTOCOL_THIS(iface) DEFINE_THIS(BindProtocol, InternetProtocol, iface)
52
53 static HRESULT WINAPI BindProtocol_QueryInterface(IInternetProtocol *iface, REFIID riid, void **ppv)
54 {
55     BindProtocol *This = PROTOCOL_THIS(iface);
56
57     *ppv = NULL;
58     if(IsEqualGUID(&IID_IUnknown, riid)) {
59         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
60         *ppv = PROTOCOL(This);
61     }else if(IsEqualGUID(&IID_IInternetProtocolRoot, riid)) {
62         TRACE("(%p)->(IID_IInternetProtocolRoot %p)\n", This, ppv);
63         *ppv = PROTOCOL(This);
64     }else if(IsEqualGUID(&IID_IInternetProtocol, riid)) {
65         TRACE("(%p)->(IID_IInternetProtocol %p)\n", This, ppv);
66         *ppv = PROTOCOL(This);
67     }else if(IsEqualGUID(&IID_IInternetBindInfo, riid)) {
68         TRACE("(%p)->(IID_IInternetBindInfo %p)\n", This, ppv);
69         *ppv = BINDINFO(This);
70     }else if(IsEqualGUID(&IID_IInternetPriority, riid)) {
71         TRACE("(%p)->(IID_IInternetPriority %p)\n", This, ppv);
72         *ppv = PRIORITY(This);
73     }else if(IsEqualGUID(&IID_IAuthenticate, riid)) {
74         FIXME("(%p)->(IID_IAuthenticate %p)\n", This, ppv);
75     }else if(IsEqualGUID(&IID_IServiceProvider, riid)) {
76         TRACE("(%p)->(IID_IServiceProvider %p)\n", This, ppv);
77         *ppv = SERVPROV(This);
78     }else if(IsEqualGUID(&IID_IInternetProtocolSink, riid)) {
79         TRACE("(%p)->(IID_IInternetProtocolSink %p)\n", This, ppv);
80         *ppv = PROTSINK(This);
81     }
82
83     if(*ppv) {
84         IInternetProtocol_AddRef(iface);
85         return S_OK;
86     }
87
88     WARN("not supported interface %s\n", debugstr_guid(riid));
89     return E_NOINTERFACE;
90 }
91
92 static ULONG WINAPI BindProtocol_AddRef(IInternetProtocol *iface)
93 {
94     BindProtocol *This = PROTOCOL_THIS(iface);
95     LONG ref = InterlockedIncrement(&This->ref);
96     TRACE("(%p) ref=%d\n", This, ref);
97     return ref;
98 }
99
100 static ULONG WINAPI BindProtocol_Release(IInternetProtocol *iface)
101 {
102     BindProtocol *This = PROTOCOL_THIS(iface);
103     LONG ref = InterlockedDecrement(&This->ref);
104
105     TRACE("(%p) ref=%d\n", This, ref);
106
107     if(!ref) {
108         if(This->wininet_info)
109             IWinInetInfo_Release(This->wininet_info);
110         if(This->protocol)
111             IInternetProtocol_Release(This->protocol);
112         if(This->bind_info)
113             IInternetBindInfo_Release(This->bind_info);
114
115         set_binding_sink(PROTOCOL(This), NULL);
116         heap_free(This);
117
118         URLMON_UnlockModule();
119     }
120
121     return ref;
122 }
123
124 static HRESULT WINAPI BindProtocol_Start(IInternetProtocol *iface, LPCWSTR szUrl,
125         IInternetProtocolSink *pOIProtSink, IInternetBindInfo *pOIBindInfo,
126         DWORD grfPI, HANDLE_PTR dwReserved)
127 {
128     BindProtocol *This = PROTOCOL_THIS(iface);
129     IInternetProtocol *protocol = NULL;
130     IInternetPriority *priority;
131     IServiceProvider *service_provider;
132     BOOL urlmon_protocol = FALSE;
133     CLSID clsid = IID_NULL;
134     LPOLESTR clsid_str;
135     HRESULT hres;
136
137     TRACE("(%p)->(%s %p %p %08x %lx)\n", This, debugstr_w(szUrl), pOIProtSink,
138             pOIBindInfo, grfPI, dwReserved);
139
140     if(!szUrl || !pOIProtSink || !pOIBindInfo)
141         return E_INVALIDARG;
142
143     hres = IInternetProtocolSink_QueryInterface(pOIProtSink, &IID_IServiceProvider,
144                                                 (void**)&service_provider);
145     if(SUCCEEDED(hres)) {
146         /* FIXME: What's protocol CLSID here? */
147         IServiceProvider_QueryService(service_provider, &IID_IInternetProtocol,
148                                       &IID_IInternetProtocol, (void**)&protocol);
149         IServiceProvider_Release(service_provider);
150     }
151
152     if(!protocol) {
153         IClassFactory *cf;
154         IUnknown *unk;
155
156         hres = get_protocol_handler(szUrl, &clsid, &urlmon_protocol, &cf);
157         if(FAILED(hres))
158             return hres;
159
160         if(This->from_urlmon) {
161             hres = IClassFactory_CreateInstance(cf, NULL, &IID_IInternetProtocol, (void**)&protocol);
162             IClassFactory_Release(cf);
163             if(FAILED(hres))
164                 return hres;
165         }else {
166             hres = IClassFactory_CreateInstance(cf, (IUnknown*)BINDINFO(This),
167                     &IID_IUnknown, (void**)&unk);
168             IClassFactory_Release(cf);
169             if(FAILED(hres))
170                 return hres;
171
172             hres = IUnknown_QueryInterface(unk, &IID_IInternetProtocol, (void**)&protocol);
173             IUnknown_Release(unk);
174             if(FAILED(hres))
175                 return hres;
176         }
177     }
178
179     StringFromCLSID(&clsid, &clsid_str);
180     IInternetProtocolSink_ReportProgress(pOIProtSink, BINDSTATUS_PROTOCOLCLASSID, clsid_str);
181     CoTaskMemFree(clsid_str);
182
183     This->protocol = protocol;
184
185     if(urlmon_protocol)
186         IInternetProtocol_QueryInterface(protocol, &IID_IWinInetInfo, (void**)&This->wininet_info);
187
188     IInternetBindInfo_AddRef(pOIBindInfo);
189     This->bind_info = pOIBindInfo;
190
191     set_binding_sink(PROTOCOL(This), pOIProtSink);
192
193     hres = IInternetProtocol_QueryInterface(protocol, &IID_IInternetPriority, (void**)&priority);
194     if(SUCCEEDED(hres)) {
195         IInternetPriority_SetPriority(priority, This->priority);
196         IInternetPriority_Release(priority);
197     }
198
199     return IInternetProtocol_Start(protocol, szUrl, PROTSINK(This), BINDINFO(This), 0, 0);
200 }
201
202 static HRESULT WINAPI BindProtocol_Continue(IInternetProtocol *iface, PROTOCOLDATA *pProtocolData)
203 {
204     BindProtocol *This = PROTOCOL_THIS(iface);
205
206     TRACE("(%p)->(%p)\n", This, pProtocolData);
207
208     return IInternetProtocol_Continue(This->protocol, pProtocolData);
209 }
210
211 static HRESULT WINAPI BindProtocol_Abort(IInternetProtocol *iface, HRESULT hrReason,
212         DWORD dwOptions)
213 {
214     BindProtocol *This = PROTOCOL_THIS(iface);
215     FIXME("(%p)->(%08x %08x)\n", This, hrReason, dwOptions);
216     return E_NOTIMPL;
217 }
218
219 static HRESULT WINAPI BindProtocol_Terminate(IInternetProtocol *iface, DWORD dwOptions)
220 {
221     BindProtocol *This = PROTOCOL_THIS(iface);
222
223     TRACE("(%p)->(%08x)\n", This, dwOptions);
224
225     if(!This->reported_result)
226         return E_FAIL;
227
228     IInternetProtocol_Terminate(This->protocol, 0);
229
230     set_binding_sink(PROTOCOL(This), NULL);
231
232     if(This->bind_info) {
233         IInternetBindInfo_Release(This->bind_info);
234         This->bind_info = NULL;
235     }
236
237     return S_OK;
238 }
239
240 static HRESULT WINAPI BindProtocol_Suspend(IInternetProtocol *iface)
241 {
242     BindProtocol *This = PROTOCOL_THIS(iface);
243     FIXME("(%p)\n", This);
244     return E_NOTIMPL;
245 }
246
247 static HRESULT WINAPI BindProtocol_Resume(IInternetProtocol *iface)
248 {
249     BindProtocol *This = PROTOCOL_THIS(iface);
250     FIXME("(%p)\n", This);
251     return E_NOTIMPL;
252 }
253
254 static HRESULT WINAPI BindProtocol_Read(IInternetProtocol *iface, void *pv,
255         ULONG cb, ULONG *pcbRead)
256 {
257     BindProtocol *This = PROTOCOL_THIS(iface);
258     ULONG read = 0;
259     HRESULT hres;
260
261     TRACE("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead);
262
263     hres = IInternetProtocol_Read(This->protocol, pv, cb, &read);
264
265     *pcbRead = read;
266     return hres;
267 }
268
269 static HRESULT WINAPI BindProtocol_Seek(IInternetProtocol *iface, LARGE_INTEGER dlibMove,
270         DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
271 {
272     BindProtocol *This = PROTOCOL_THIS(iface);
273     FIXME("(%p)->(%d %d %p)\n", This, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
274     return E_NOTIMPL;
275 }
276
277 static HRESULT WINAPI BindProtocol_LockRequest(IInternetProtocol *iface, DWORD dwOptions)
278 {
279     BindProtocol *This = PROTOCOL_THIS(iface);
280
281     TRACE("(%p)->(%08x)\n", This, dwOptions);
282
283     return IInternetProtocol_LockRequest(This->protocol, dwOptions);
284 }
285
286 static HRESULT WINAPI BindProtocol_UnlockRequest(IInternetProtocol *iface)
287 {
288     BindProtocol *This = PROTOCOL_THIS(iface);
289
290     TRACE("(%p)\n", This);
291
292     return IInternetProtocol_UnlockRequest(This->protocol);
293 }
294
295 void set_binding_sink(IInternetProtocol *bind_protocol, IInternetProtocolSink *sink)
296 {
297     BindProtocol *This = PROTOCOL_THIS(bind_protocol);
298     IInternetProtocolSink *prev_sink;
299     IServiceProvider *service_provider = NULL;
300
301     if(sink)
302         IInternetProtocolSink_AddRef(sink);
303     prev_sink = InterlockedExchangePointer((void**)&This->protocol_sink, sink);
304     if(prev_sink)
305         IInternetProtocolSink_Release(prev_sink);
306
307     if(sink)
308         IInternetProtocolSink_QueryInterface(sink, &IID_IServiceProvider, (void**)&service_provider);
309     service_provider = InterlockedExchangePointer((void**)&This->service_provider, service_provider);
310     if(service_provider)
311         IServiceProvider_Release(service_provider);
312 }
313
314 IWinInetInfo *get_wininet_info(IInternetProtocol *bind_protocol)
315 {
316     BindProtocol *This = PROTOCOL_THIS(bind_protocol);
317
318     return This->wininet_info;
319 }
320
321 #undef PROTOCOL_THIS
322
323 static const IInternetProtocolVtbl BindProtocolVtbl = {
324     BindProtocol_QueryInterface,
325     BindProtocol_AddRef,
326     BindProtocol_Release,
327     BindProtocol_Start,
328     BindProtocol_Continue,
329     BindProtocol_Abort,
330     BindProtocol_Terminate,
331     BindProtocol_Suspend,
332     BindProtocol_Resume,
333     BindProtocol_Read,
334     BindProtocol_Seek,
335     BindProtocol_LockRequest,
336     BindProtocol_UnlockRequest
337 };
338
339 #define BINDINFO_THIS(iface) DEFINE_THIS(BindProtocol, InternetBindInfo, iface)
340
341 static HRESULT WINAPI BindInfo_QueryInterface(IInternetBindInfo *iface,
342         REFIID riid, void **ppv)
343 {
344     BindProtocol *This = BINDINFO_THIS(iface);
345     return IInternetProtocol_QueryInterface(PROTOCOL(This), riid, ppv);
346 }
347
348 static ULONG WINAPI BindInfo_AddRef(IInternetBindInfo *iface)
349 {
350     BindProtocol *This = BINDINFO_THIS(iface);
351     return IBinding_AddRef(PROTOCOL(This));
352 }
353
354 static ULONG WINAPI BindInfo_Release(IInternetBindInfo *iface)
355 {
356     BindProtocol *This = BINDINFO_THIS(iface);
357     return IBinding_Release(PROTOCOL(This));
358 }
359
360 static HRESULT WINAPI BindInfo_GetBindInfo(IInternetBindInfo *iface,
361         DWORD *grfBINDF, BINDINFO *pbindinfo)
362 {
363     BindProtocol *This = BINDINFO_THIS(iface);
364     HRESULT hres;
365
366     TRACE("(%p)->(%p %p)\n", This, grfBINDF, pbindinfo);
367
368     hres = IInternetBindInfo_GetBindInfo(This->bind_info, grfBINDF, pbindinfo);
369     if(FAILED(hres)) {
370         WARN("GetBindInfo failed: %08x\n", hres);
371         return hres;
372     }
373
374     *grfBINDF |= BINDF_FROMURLMON;
375     return hres;
376 }
377
378 static HRESULT WINAPI BindInfo_GetBindString(IInternetBindInfo *iface,
379         ULONG ulStringType, LPOLESTR *ppwzStr, ULONG cEl, ULONG *pcElFetched)
380 {
381     BindProtocol *This = BINDINFO_THIS(iface);
382
383     TRACE("(%p)->(%d %p %d %p)\n", This, ulStringType, ppwzStr, cEl, pcElFetched);
384
385     return IInternetBindInfo_GetBindString(This->bind_info, ulStringType, ppwzStr, cEl, pcElFetched);
386 }
387
388 #undef BINDFO_THIS
389
390 static const IInternetBindInfoVtbl InternetBindInfoVtbl = {
391     BindInfo_QueryInterface,
392     BindInfo_AddRef,
393     BindInfo_Release,
394     BindInfo_GetBindInfo,
395     BindInfo_GetBindString
396 };
397
398 #define PRIORITY_THIS(iface) DEFINE_THIS(BindProtocol, InternetPriority, iface)
399
400 static HRESULT WINAPI InternetPriority_QueryInterface(IInternetPriority *iface,
401         REFIID riid, void **ppv)
402 {
403     BindProtocol *This = PRIORITY_THIS(iface);
404     return IInternetProtocol_QueryInterface(PROTOCOL(This), riid, ppv);
405 }
406
407 static ULONG WINAPI InternetPriority_AddRef(IInternetPriority *iface)
408 {
409     BindProtocol *This = PRIORITY_THIS(iface);
410     return IInternetProtocol_AddRef(PROTOCOL(This));
411 }
412
413 static ULONG WINAPI InternetPriority_Release(IInternetPriority *iface)
414 {
415     BindProtocol *This = PRIORITY_THIS(iface);
416     return IInternetProtocol_Release(PROTOCOL(This));
417 }
418
419 static HRESULT WINAPI InternetPriority_SetPriority(IInternetPriority *iface, LONG nPriority)
420 {
421     BindProtocol *This = PRIORITY_THIS(iface);
422
423     TRACE("(%p)->(%d)\n", This, nPriority);
424
425     This->priority = nPriority;
426     return S_OK;
427 }
428
429 static HRESULT WINAPI InternetPriority_GetPriority(IInternetPriority *iface, LONG *pnPriority)
430 {
431     BindProtocol *This = PRIORITY_THIS(iface);
432
433     TRACE("(%p)->(%p)\n", This, pnPriority);
434
435     *pnPriority = This->priority;
436     return S_OK;
437 }
438
439 #undef PRIORITY_THIS
440
441 static const IInternetPriorityVtbl InternetPriorityVtbl = {
442     InternetPriority_QueryInterface,
443     InternetPriority_AddRef,
444     InternetPriority_Release,
445     InternetPriority_SetPriority,
446     InternetPriority_GetPriority
447
448 };
449
450 #define PROTSINK_THIS(iface) DEFINE_THIS(BindProtocol, InternetProtocolSink, iface)
451
452 static HRESULT WINAPI BPInternetProtocolSink_QueryInterface(IInternetProtocolSink *iface,
453         REFIID riid, void **ppv)
454 {
455     BindProtocol *This = PROTSINK_THIS(iface);
456     return IInternetProtocol_QueryInterface(PROTOCOL(This), riid, ppv);
457 }
458
459 static ULONG WINAPI BPInternetProtocolSink_AddRef(IInternetProtocolSink *iface)
460 {
461     BindProtocol *This = PROTSINK_THIS(iface);
462     return IInternetProtocol_AddRef(PROTOCOL(This));
463 }
464
465 static ULONG WINAPI BPInternetProtocolSink_Release(IInternetProtocolSink *iface)
466 {
467     BindProtocol *This = PROTSINK_THIS(iface);
468     return IInternetProtocol_Release(PROTOCOL(This));
469 }
470
471 static HRESULT WINAPI BPInternetProtocolSink_Switch(IInternetProtocolSink *iface,
472         PROTOCOLDATA *pProtocolData)
473 {
474     BindProtocol *This = PROTSINK_THIS(iface);
475
476     TRACE("(%p)->(%p)\n", This, pProtocolData);
477
478     TRACE("flags %x state %x data %p cb %u\n", pProtocolData->grfFlags, pProtocolData->dwState,
479           pProtocolData->pData, pProtocolData->cbData);
480
481     if(!This->protocol_sink) {
482         IInternetProtocol_Continue(This->protocol, pProtocolData);
483         return S_OK;
484     }
485
486     return IInternetProtocolSink_Switch(This->protocol_sink, pProtocolData);
487 }
488
489 static HRESULT WINAPI BPInternetProtocolSink_ReportProgress(IInternetProtocolSink *iface,
490         ULONG ulStatusCode, LPCWSTR szStatusText)
491 {
492     BindProtocol *This = PROTSINK_THIS(iface);
493
494     TRACE("(%p)->(%u %s)\n", This, ulStatusCode, debugstr_w(szStatusText));
495
496     switch(ulStatusCode) {
497     case BINDSTATUS_FINDINGRESOURCE:
498     case BINDSTATUS_CONNECTING:
499     case BINDSTATUS_BEGINDOWNLOADDATA:
500     case BINDSTATUS_SENDINGREQUEST:
501     case BINDSTATUS_CACHEFILENAMEAVAILABLE:
502     case BINDSTATUS_DIRECTBIND:
503     case BINDSTATUS_ACCEPTRANGES:
504     case BINDSTATUS_MIMETYPEAVAILABLE:
505         if(!This->protocol_sink)
506             return S_OK;
507         return IInternetProtocolSink_ReportProgress(This->protocol_sink,
508                 ulStatusCode, szStatusText);
509
510     case BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE:
511         if(!This->protocol_sink)
512             return S_OK;
513         return IInternetProtocolSink_ReportProgress(This->protocol_sink,
514                 This->from_urlmon ? BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE : BINDSTATUS_MIMETYPEAVAILABLE,
515                                                     szStatusText);
516     default:
517         FIXME("unsupported ulStatusCode %u\n", ulStatusCode);
518     }
519
520     return E_NOTIMPL;
521 }
522
523 static HRESULT WINAPI BPInternetProtocolSink_ReportData(IInternetProtocolSink *iface,
524         DWORD grfBSCF, ULONG ulProgress, ULONG ulProgressMax)
525 {
526     BindProtocol *This = PROTSINK_THIS(iface);
527
528     TRACE("(%p)->(%d %u %u)\n", This, grfBSCF, ulProgress, ulProgressMax);
529
530     if(!This->protocol_sink)
531         return S_OK;
532
533     return IInternetProtocolSink_ReportData(This->protocol_sink, grfBSCF, ulProgress, ulProgressMax);
534 }
535
536 static HRESULT WINAPI BPInternetProtocolSink_ReportResult(IInternetProtocolSink *iface,
537         HRESULT hrResult, DWORD dwError, LPCWSTR szResult)
538 {
539     BindProtocol *This = PROTSINK_THIS(iface);
540
541     TRACE("(%p)->(%08x %d %s)\n", This, hrResult, dwError, debugstr_w(szResult));
542
543     if(!This->protocol_sink)
544         return E_FAIL;
545
546     This->reported_result = TRUE;
547
548     return IInternetProtocolSink_ReportResult(This->protocol_sink, hrResult, dwError, szResult);
549 }
550
551 #undef PROTSINK_THIS
552
553 static const IInternetProtocolSinkVtbl InternetProtocolSinkVtbl = {
554     BPInternetProtocolSink_QueryInterface,
555     BPInternetProtocolSink_AddRef,
556     BPInternetProtocolSink_Release,
557     BPInternetProtocolSink_Switch,
558     BPInternetProtocolSink_ReportProgress,
559     BPInternetProtocolSink_ReportData,
560     BPInternetProtocolSink_ReportResult
561 };
562
563 #define SERVPROV_THIS(iface) DEFINE_THIS(BindProtocol, ServiceProvider, iface)
564
565 static HRESULT WINAPI BPServiceProvider_QueryInterface(IServiceProvider *iface,
566         REFIID riid, void **ppv)
567 {
568     BindProtocol *This = SERVPROV_THIS(iface);
569     return IInternetProtocol_QueryInterface(PROTOCOL(This), riid, ppv);
570 }
571
572 static ULONG WINAPI BPServiceProvider_AddRef(IServiceProvider *iface)
573 {
574     BindProtocol *This = SERVPROV_THIS(iface);
575     return IInternetProtocol_AddRef(PROTOCOL(This));
576 }
577
578 static ULONG WINAPI BPServiceProvider_Release(IServiceProvider *iface)
579 {
580     BindProtocol *This = SERVPROV_THIS(iface);
581     return IInternetProtocol_Release(PROTOCOL(This));
582 }
583
584 static HRESULT WINAPI BPServiceProvider_QueryService(IServiceProvider *iface,
585         REFGUID guidService, REFIID riid, void **ppv)
586 {
587     BindProtocol *This = SERVPROV_THIS(iface);
588
589     TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
590
591     if(!This->service_provider)
592         return E_NOINTERFACE;
593
594     return IServiceProvider_QueryService(This->service_provider, guidService, riid, ppv);
595 }
596
597 #undef SERVPROV_THIS
598
599 static const IServiceProviderVtbl ServiceProviderVtbl = {
600     BPServiceProvider_QueryInterface,
601     BPServiceProvider_AddRef,
602     BPServiceProvider_Release,
603     BPServiceProvider_QueryService
604 };
605
606 HRESULT create_binding_protocol(LPCWSTR url, BOOL from_urlmon, IInternetProtocol **protocol)
607 {
608     BindProtocol *ret = heap_alloc_zero(sizeof(BindProtocol));
609
610     ret->lpInternetProtocolVtbl = &BindProtocolVtbl;
611     ret->lpInternetBindInfoVtbl = &InternetBindInfoVtbl;
612     ret->lpInternetPriorityVtbl = &InternetPriorityVtbl;
613     ret->lpServiceProviderVtbl  = &ServiceProviderVtbl;
614     ret->lpInternetProtocolSinkVtbl = &InternetProtocolSinkVtbl;
615
616     ret->ref = 1;
617     ret->from_urlmon = from_urlmon;
618
619     URLMON_LockModule();
620
621     *protocol = PROTOCOL(ret);
622     return S_OK;
623 }