xref: /reactos/dll/win32/urlmon/bindctx.c (revision c2c66aff)
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 
21 static WCHAR bscb_holderW[] = { '_','B','S','C','B','_','H','o','l','d','e','r','_',0 };
22 
23 extern IID IID_IBindStatusCallbackHolder;
24 
25 typedef struct {
26     IBindStatusCallbackEx IBindStatusCallbackEx_iface;
27     IInternetBindInfo     IInternetBindInfo_iface;
28     IServiceProvider      IServiceProvider_iface;
29     IHttpNegotiate2       IHttpNegotiate2_iface;
30     IAuthenticate         IAuthenticate_iface;
31 
32     LONG ref;
33 
34     IBindStatusCallback *callback;
35     IServiceProvider *serv_prov;
36 } BindStatusCallback;
37 
38 static void *get_callback_iface(BindStatusCallback *This, REFIID riid)
39 {
40     void *ret;
41     HRESULT hres;
42 
43     hres = IBindStatusCallback_QueryInterface(This->callback, riid, (void**)&ret);
44     if(FAILED(hres) && This->serv_prov)
45         hres = IServiceProvider_QueryService(This->serv_prov, riid, riid, &ret);
46 
47     return SUCCEEDED(hres) ? ret : NULL;
48 }
49 
50 static IBindStatusCallback *bsch_from_bctx(IBindCtx *bctx)
51 {
52     IBindStatusCallback *bsc;
53     IUnknown *unk;
54     HRESULT hres;
55 
56     hres = IBindCtx_GetObjectParam(bctx, bscb_holderW, &unk);
57     if(FAILED(hres))
58         return NULL;
59 
60     hres = IUnknown_QueryInterface(unk, &IID_IBindStatusCallback, (void**)&bsc);
61     IUnknown_Release(unk);
62     return SUCCEEDED(hres) ? bsc : NULL;
63 }
64 
65 IBindStatusCallback *bsc_from_bctx(IBindCtx *bctx)
66 {
67     BindStatusCallback *holder;
68     IBindStatusCallback *bsc;
69     HRESULT hres;
70 
71     bsc = bsch_from_bctx(bctx);
72     if(!bsc)
73         return NULL;
74 
75     hres = IBindStatusCallback_QueryInterface(bsc, &IID_IBindStatusCallbackHolder, (void**)&holder);
76     if(FAILED(hres))
77         return bsc;
78 
79     if(holder->callback) {
80         IBindStatusCallback_Release(bsc);
81         bsc = holder->callback;
82         IBindStatusCallback_AddRef(bsc);
83     }
84 
85     IBindStatusCallbackEx_Release(&holder->IBindStatusCallbackEx_iface);
86     return bsc;
87 }
88 
89 static inline BindStatusCallback *impl_from_IBindStatusCallbackEx(IBindStatusCallbackEx *iface)
90 {
91     return CONTAINING_RECORD(iface, BindStatusCallback, IBindStatusCallbackEx_iface);
92 }
93 
94 static HRESULT WINAPI BindStatusCallback_QueryInterface(IBindStatusCallbackEx *iface,
95         REFIID riid, void **ppv)
96 {
97     BindStatusCallback *This = impl_from_IBindStatusCallbackEx(iface);
98 
99     *ppv = NULL;
100 
101     if(IsEqualGUID(&IID_IUnknown, riid)) {
102         TRACE("(%p)->(IID_IUnknown, %p)\n", This, ppv);
103         *ppv = &This->IBindStatusCallbackEx_iface;
104     }else if(IsEqualGUID(&IID_IBindStatusCallback, riid)) {
105         TRACE("(%p)->(IID_IBindStatusCallback, %p)\n", This, ppv);
106         *ppv = &This->IBindStatusCallbackEx_iface;
107     }else if(IsEqualGUID(&IID_IBindStatusCallbackEx, riid)) {
108         TRACE("(%p)->(IID_IBindStatusCallback, %p)\n", This, ppv);
109         *ppv = &This->IBindStatusCallbackEx_iface;
110     }else if(IsEqualGUID(&IID_IBindStatusCallbackHolder, riid)) {
111         TRACE("(%p)->(IID_IBindStatusCallbackHolder, %p)\n", This, ppv);
112         *ppv = This;
113     }else if(IsEqualGUID(&IID_IServiceProvider, riid)) {
114         TRACE("(%p)->(IID_IServiceProvider, %p)\n", This, ppv);
115         *ppv = &This->IServiceProvider_iface;
116     }else if(IsEqualGUID(&IID_IHttpNegotiate, riid)) {
117         TRACE("(%p)->(IID_IHttpNegotiate, %p)\n", This, ppv);
118         *ppv = &This->IHttpNegotiate2_iface;
119     }else if(IsEqualGUID(&IID_IHttpNegotiate2, riid)) {
120         TRACE("(%p)->(IID_IHttpNegotiate2, %p)\n", This, ppv);
121         *ppv = &This->IHttpNegotiate2_iface;
122     }else if(IsEqualGUID(&IID_IAuthenticate, riid)) {
123         TRACE("(%p)->(IID_IAuthenticate, %p)\n", This, ppv);
124         *ppv = &This->IAuthenticate_iface;
125     }else if(IsEqualGUID(&IID_IInternetBindInfo, riid)) {
126         TRACE("(%p)->(IID_IInternetBindInfo, %p)\n", This, ppv);
127         *ppv = &This->IInternetBindInfo_iface;
128     }
129 
130     if(*ppv) {
131         IUnknown_AddRef((IUnknown*)*ppv);
132         return S_OK;
133     }
134 
135     TRACE("Unsupported riid = %s\n", debugstr_guid(riid));
136     return E_NOINTERFACE;
137 }
138 
139 static ULONG WINAPI BindStatusCallback_AddRef(IBindStatusCallbackEx *iface)
140 {
141     BindStatusCallback *This = impl_from_IBindStatusCallbackEx(iface);
142     LONG ref = InterlockedIncrement(&This->ref);
143 
144     TRACE("(%p) ref = %d\n", This, ref);
145 
146     return ref;
147 }
148 
149 static ULONG WINAPI BindStatusCallback_Release(IBindStatusCallbackEx *iface)
150 {
151     BindStatusCallback *This = impl_from_IBindStatusCallbackEx(iface);
152     LONG ref = InterlockedDecrement(&This->ref);
153 
154     TRACE("(%p) ref = %d\n", This, ref);
155 
156     if(!ref) {
157         if(This->serv_prov)
158             IServiceProvider_Release(This->serv_prov);
159         IBindStatusCallback_Release(This->callback);
160         heap_free(This);
161     }
162 
163     return ref;
164 }
165 
166 static HRESULT WINAPI BindStatusCallback_OnStartBinding(IBindStatusCallbackEx *iface,
167         DWORD dwReserved, IBinding *pbind)
168 {
169     BindStatusCallback *This = impl_from_IBindStatusCallbackEx(iface);
170 
171     TRACE("(%p)->(%d %p)\n", This, dwReserved, pbind);
172 
173     return IBindStatusCallback_OnStartBinding(This->callback, 0xff, pbind);
174 }
175 
176 static HRESULT WINAPI BindStatusCallback_GetPriority(IBindStatusCallbackEx *iface, LONG *pnPriority)
177 {
178     BindStatusCallback *This = impl_from_IBindStatusCallbackEx(iface);
179 
180     TRACE("(%p)->(%p)\n", This, pnPriority);
181 
182     return IBindStatusCallback_GetPriority(This->callback, pnPriority);
183 }
184 
185 static HRESULT WINAPI BindStatusCallback_OnLowResource(IBindStatusCallbackEx *iface, DWORD reserved)
186 {
187     BindStatusCallback *This = impl_from_IBindStatusCallbackEx(iface);
188 
189     TRACE("(%p)->(%d)\n", This, reserved);
190 
191     return IBindStatusCallback_OnLowResource(This->callback, reserved);
192 }
193 
194 static HRESULT WINAPI BindStatusCallback_OnProgress(IBindStatusCallbackEx *iface, ULONG ulProgress,
195         ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText)
196 {
197     BindStatusCallback *This = impl_from_IBindStatusCallbackEx(iface);
198 
199     TRACE("%p)->(%u %u %s %s)\n", This, ulProgress, ulProgressMax, debugstr_bindstatus(ulStatusCode),
200             debugstr_w(szStatusText));
201 
202     return IBindStatusCallback_OnProgress(This->callback, ulProgress,
203             ulProgressMax, ulStatusCode, szStatusText);
204 }
205 
206 static HRESULT WINAPI BindStatusCallback_OnStopBinding(IBindStatusCallbackEx *iface,
207         HRESULT hresult, LPCWSTR szError)
208 {
209     BindStatusCallback *This = impl_from_IBindStatusCallbackEx(iface);
210 
211     TRACE("(%p)->(%08x %s)\n", This, hresult, debugstr_w(szError));
212 
213     return IBindStatusCallback_OnStopBinding(This->callback, hresult, szError);
214 }
215 
216 static HRESULT WINAPI BindStatusCallback_GetBindInfo(IBindStatusCallbackEx *iface,
217         DWORD *grfBINDF, BINDINFO *pbindinfo)
218 {
219     BindStatusCallback *This = impl_from_IBindStatusCallbackEx(iface);
220     IBindStatusCallbackEx *bscex;
221     HRESULT hres;
222 
223     TRACE("(%p)->(%p %p)\n", This, grfBINDF, pbindinfo);
224 
225     hres = IBindStatusCallback_QueryInterface(This->callback, &IID_IBindStatusCallbackEx, (void**)&bscex);
226     if(SUCCEEDED(hres)) {
227         DWORD bindf2 = 0, reserv = 0;
228 
229         hres = IBindStatusCallbackEx_GetBindInfoEx(bscex, grfBINDF, pbindinfo, &bindf2, &reserv);
230         IBindStatusCallbackEx_Release(bscex);
231     }else {
232         hres = IBindStatusCallback_GetBindInfo(This->callback, grfBINDF, pbindinfo);
233     }
234 
235     return hres;
236 }
237 
238 static HRESULT WINAPI BindStatusCallback_OnDataAvailable(IBindStatusCallbackEx *iface,
239         DWORD grfBSCF, DWORD dwSize, FORMATETC *pformatetc, STGMEDIUM *pstgmed)
240 {
241     BindStatusCallback *This = impl_from_IBindStatusCallbackEx(iface);
242 
243     TRACE("(%p)->(%08x %d %p %p)\n", This, grfBSCF, dwSize, pformatetc, pstgmed);
244 
245     return IBindStatusCallback_OnDataAvailable(This->callback, grfBSCF, dwSize, pformatetc, pstgmed);
246 }
247 
248 static HRESULT WINAPI BindStatusCallback_OnObjectAvailable(IBindStatusCallbackEx *iface,
249         REFIID riid, IUnknown *punk)
250 {
251     BindStatusCallback *This = impl_from_IBindStatusCallbackEx(iface);
252 
253     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), punk);
254 
255     return IBindStatusCallback_OnObjectAvailable(This->callback, riid, punk);
256 }
257 
258 static HRESULT WINAPI BindStatusCallback_GetBindInfoEx(IBindStatusCallbackEx *iface, DWORD *grfBINDF,
259         BINDINFO *pbindinfo, DWORD *grfBINDF2, DWORD *pdwReserved)
260 {
261     BindStatusCallback *This = impl_from_IBindStatusCallbackEx(iface);
262     IBindStatusCallbackEx *bscex;
263     HRESULT hres;
264 
265     TRACE("(%p)->(%p %p %p %p)\n", This, grfBINDF, pbindinfo, grfBINDF2, pdwReserved);
266 
267     hres = IBindStatusCallback_QueryInterface(This->callback, &IID_IBindStatusCallbackEx, (void**)&bscex);
268     if(SUCCEEDED(hres)) {
269         hres = IBindStatusCallbackEx_GetBindInfoEx(bscex, grfBINDF, pbindinfo, grfBINDF2, pdwReserved);
270         IBindStatusCallbackEx_Release(bscex);
271     }else {
272         hres = IBindStatusCallback_GetBindInfo(This->callback, grfBINDF, pbindinfo);
273     }
274 
275     return hres;
276 }
277 
278 static const IBindStatusCallbackExVtbl BindStatusCallbackExVtbl = {
279     BindStatusCallback_QueryInterface,
280     BindStatusCallback_AddRef,
281     BindStatusCallback_Release,
282     BindStatusCallback_OnStartBinding,
283     BindStatusCallback_GetPriority,
284     BindStatusCallback_OnLowResource,
285     BindStatusCallback_OnProgress,
286     BindStatusCallback_OnStopBinding,
287     BindStatusCallback_GetBindInfo,
288     BindStatusCallback_OnDataAvailable,
289     BindStatusCallback_OnObjectAvailable,
290     BindStatusCallback_GetBindInfoEx
291 };
292 
293 static inline BindStatusCallback *impl_from_IServiceProvider(IServiceProvider *iface)
294 {
295     return CONTAINING_RECORD(iface, BindStatusCallback, IServiceProvider_iface);
296 }
297 
298 static HRESULT WINAPI BSCServiceProvider_QueryInterface(IServiceProvider *iface,
299         REFIID riid, void **ppv)
300 {
301     BindStatusCallback *This = impl_from_IServiceProvider(iface);
302     return IBindStatusCallbackEx_QueryInterface(&This->IBindStatusCallbackEx_iface, riid, ppv);
303 }
304 
305 static ULONG WINAPI BSCServiceProvider_AddRef(IServiceProvider *iface)
306 {
307     BindStatusCallback *This = impl_from_IServiceProvider(iface);
308     return IBindStatusCallbackEx_AddRef(&This->IBindStatusCallbackEx_iface);
309 }
310 
311 static ULONG WINAPI BSCServiceProvider_Release(IServiceProvider *iface)
312 {
313     BindStatusCallback *This = impl_from_IServiceProvider(iface);
314     return IBindStatusCallbackEx_Release(&This->IBindStatusCallbackEx_iface);
315 }
316 
317 static HRESULT WINAPI BSCServiceProvider_QueryService(IServiceProvider *iface,
318         REFGUID guidService, REFIID riid, void **ppv)
319 {
320     BindStatusCallback *This = impl_from_IServiceProvider(iface);
321     HRESULT hres;
322 
323     if(IsEqualGUID(&IID_IHttpNegotiate, guidService)) {
324         TRACE("(%p)->(IID_IHttpNegotiate %s %p)\n", This, debugstr_guid(riid), ppv);
325         return IBindStatusCallbackEx_QueryInterface(&This->IBindStatusCallbackEx_iface, riid, ppv);
326     }
327 
328     if(IsEqualGUID(&IID_IHttpNegotiate2, guidService)) {
329         TRACE("(%p)->(IID_IHttpNegotiate2 %s %p)\n", This, debugstr_guid(riid), ppv);
330         return IBindStatusCallbackEx_QueryInterface(&This->IBindStatusCallbackEx_iface, riid, ppv);
331     }
332 
333     if(IsEqualGUID(&IID_IAuthenticate, guidService)) {
334         TRACE("(%p)->(IID_IAuthenticate %s %p)\n", This, debugstr_guid(riid), ppv);
335         return IBindStatusCallbackEx_QueryInterface(&This->IBindStatusCallbackEx_iface, riid, ppv);
336     }
337 
338     TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
339 
340     hres = IBindStatusCallback_QueryInterface(This->callback, riid, ppv);
341     if(SUCCEEDED(hres))
342         return S_OK;
343 
344     if(This->serv_prov) {
345         hres = IServiceProvider_QueryService(This->serv_prov, guidService, riid, ppv);
346         if(SUCCEEDED(hres))
347             return S_OK;
348     }
349 
350     return E_NOINTERFACE;
351 }
352 
353 static const IServiceProviderVtbl BSCServiceProviderVtbl = {
354     BSCServiceProvider_QueryInterface,
355     BSCServiceProvider_AddRef,
356     BSCServiceProvider_Release,
357     BSCServiceProvider_QueryService
358 };
359 
360 static inline BindStatusCallback *impl_from_IHttpNegotiate2(IHttpNegotiate2 *iface)
361 {
362     return CONTAINING_RECORD(iface, BindStatusCallback, IHttpNegotiate2_iface);
363 }
364 
365 static HRESULT WINAPI BSCHttpNegotiate_QueryInterface(IHttpNegotiate2 *iface,
366         REFIID riid, void **ppv)
367 {
368     BindStatusCallback *This = impl_from_IHttpNegotiate2(iface);
369     return IBindStatusCallbackEx_QueryInterface(&This->IBindStatusCallbackEx_iface, riid, ppv);
370 }
371 
372 static ULONG WINAPI BSCHttpNegotiate_AddRef(IHttpNegotiate2 *iface)
373 {
374     BindStatusCallback *This = impl_from_IHttpNegotiate2(iface);
375     return IBindStatusCallbackEx_AddRef(&This->IBindStatusCallbackEx_iface);
376 }
377 
378 static ULONG WINAPI BSCHttpNegotiate_Release(IHttpNegotiate2 *iface)
379 {
380     BindStatusCallback *This = impl_from_IHttpNegotiate2(iface);
381     return IBindStatusCallbackEx_Release(&This->IBindStatusCallbackEx_iface);
382 }
383 
384 static HRESULT WINAPI BSCHttpNegotiate_BeginningTransaction(IHttpNegotiate2 *iface,
385         LPCWSTR szURL, LPCWSTR szHeaders, DWORD dwReserved, LPWSTR *pszAdditionalHeaders)
386 {
387     BindStatusCallback *This = impl_from_IHttpNegotiate2(iface);
388     IHttpNegotiate *http_negotiate;
389     HRESULT hres = S_OK;
390 
391     TRACE("(%p)->(%s %s %d %p)\n", This, debugstr_w(szURL), debugstr_w(szHeaders), dwReserved,
392           pszAdditionalHeaders);
393 
394     *pszAdditionalHeaders = NULL;
395 
396     http_negotiate = get_callback_iface(This, &IID_IHttpNegotiate);
397     if(http_negotiate) {
398         hres = IHttpNegotiate_BeginningTransaction(http_negotiate, szURL, szHeaders,
399                 dwReserved, pszAdditionalHeaders);
400         IHttpNegotiate_Release(http_negotiate);
401     }
402 
403     return hres;
404 }
405 
406 static HRESULT WINAPI BSCHttpNegotiate_OnResponse(IHttpNegotiate2 *iface, DWORD dwResponseCode,
407         LPCWSTR szResponseHeaders, LPCWSTR szRequestHeaders,
408         LPWSTR *pszAdditionalRequestHeaders)
409 {
410     BindStatusCallback *This = impl_from_IHttpNegotiate2(iface);
411     LPWSTR additional_headers = NULL;
412     IHttpNegotiate *http_negotiate;
413     HRESULT hres = S_OK;
414 
415     TRACE("(%p)->(%d %s %s %p)\n", This, dwResponseCode, debugstr_w(szResponseHeaders),
416           debugstr_w(szRequestHeaders), pszAdditionalRequestHeaders);
417 
418     http_negotiate = get_callback_iface(This, &IID_IHttpNegotiate);
419     if(http_negotiate) {
420         hres = IHttpNegotiate_OnResponse(http_negotiate, dwResponseCode, szResponseHeaders,
421                 szRequestHeaders, &additional_headers);
422         IHttpNegotiate_Release(http_negotiate);
423     }
424 
425     if(pszAdditionalRequestHeaders)
426         *pszAdditionalRequestHeaders = additional_headers;
427     else
428         CoTaskMemFree(additional_headers);
429 
430     return hres;
431 }
432 
433 static HRESULT WINAPI BSCHttpNegotiate_GetRootSecurityId(IHttpNegotiate2 *iface,
434         BYTE *pbSecurityId, DWORD *pcbSecurityId, DWORD_PTR dwReserved)
435 {
436     BindStatusCallback *This = impl_from_IHttpNegotiate2(iface);
437     IHttpNegotiate2 *http_negotiate2;
438     HRESULT hres = E_FAIL;
439 
440     TRACE("(%p)->(%p %p %ld)\n", This, pbSecurityId, pcbSecurityId, dwReserved);
441 
442     http_negotiate2 = get_callback_iface(This, &IID_IHttpNegotiate2);
443     if(http_negotiate2) {
444         hres = IHttpNegotiate2_GetRootSecurityId(http_negotiate2, pbSecurityId,
445                 pcbSecurityId, dwReserved);
446         IHttpNegotiate2_Release(http_negotiate2);
447     }
448 
449     return hres;
450 }
451 
452 static const IHttpNegotiate2Vtbl BSCHttpNegotiateVtbl = {
453     BSCHttpNegotiate_QueryInterface,
454     BSCHttpNegotiate_AddRef,
455     BSCHttpNegotiate_Release,
456     BSCHttpNegotiate_BeginningTransaction,
457     BSCHttpNegotiate_OnResponse,
458     BSCHttpNegotiate_GetRootSecurityId
459 };
460 
461 static inline BindStatusCallback *impl_from_IAuthenticate(IAuthenticate *iface)
462 {
463     return CONTAINING_RECORD(iface, BindStatusCallback, IAuthenticate_iface);
464 }
465 
466 static HRESULT WINAPI BSCAuthenticate_QueryInterface(IAuthenticate *iface, REFIID riid, void **ppv)
467 {
468     BindStatusCallback *This = impl_from_IAuthenticate(iface);
469     return IBindStatusCallbackEx_QueryInterface(&This->IBindStatusCallbackEx_iface, riid, ppv);
470 }
471 
472 static ULONG WINAPI BSCAuthenticate_AddRef(IAuthenticate *iface)
473 {
474     BindStatusCallback *This = impl_from_IAuthenticate(iface);
475     return IBindStatusCallbackEx_AddRef(&This->IBindStatusCallbackEx_iface);
476 }
477 
478 static ULONG WINAPI BSCAuthenticate_Release(IAuthenticate *iface)
479 {
480     BindStatusCallback *This = impl_from_IAuthenticate(iface);
481     return IBindStatusCallbackEx_Release(&This->IBindStatusCallbackEx_iface);
482 }
483 
484 static HRESULT WINAPI BSCAuthenticate_Authenticate(IAuthenticate *iface,
485         HWND *phwnd, LPWSTR *pszUsername, LPWSTR *pszPassword)
486 {
487     BindStatusCallback *This = impl_from_IAuthenticate(iface);
488     FIXME("(%p)->(%p %p %p)\n", This, phwnd, pszUsername, pszPassword);
489     return E_NOTIMPL;
490 }
491 
492 static const IAuthenticateVtbl BSCAuthenticateVtbl = {
493     BSCAuthenticate_QueryInterface,
494     BSCAuthenticate_AddRef,
495     BSCAuthenticate_Release,
496     BSCAuthenticate_Authenticate
497 };
498 
499 static inline BindStatusCallback *impl_from_IInternetBindInfo(IInternetBindInfo *iface)
500 {
501     return CONTAINING_RECORD(iface, BindStatusCallback, IInternetBindInfo_iface);
502 }
503 
504 static HRESULT WINAPI BSCInternetBindInfo_QueryInterface(IInternetBindInfo *iface, REFIID riid, void **ppv)
505 {
506     BindStatusCallback *This = impl_from_IInternetBindInfo(iface);
507     return IBindStatusCallbackEx_QueryInterface(&This->IBindStatusCallbackEx_iface, riid, ppv);
508 }
509 
510 static ULONG WINAPI BSCInternetBindInfo_AddRef(IInternetBindInfo *iface)
511 {
512     BindStatusCallback *This = impl_from_IInternetBindInfo(iface);
513     return IBindStatusCallbackEx_AddRef(&This->IBindStatusCallbackEx_iface);
514 }
515 
516 static ULONG WINAPI BSCInternetBindInfo_Release(IInternetBindInfo *iface)
517 {
518     BindStatusCallback *This = impl_from_IInternetBindInfo(iface);
519     return IBindStatusCallbackEx_Release(&This->IBindStatusCallbackEx_iface);
520 }
521 
522 static HRESULT WINAPI BSCInternetBindInfo_GetBindInfo(IInternetBindInfo *iface, DWORD *bindf, BINDINFO *bindinfo)
523 {
524     BindStatusCallback *This = impl_from_IInternetBindInfo(iface);
525     FIXME("(%p)->(%p %p)\n", This, bindf, bindinfo);
526     return E_NOTIMPL;
527 }
528 
529 static HRESULT WINAPI BSCInternetBindInfo_GetBindString(IInternetBindInfo *iface, ULONG string_type,
530         WCHAR **strs, ULONG cnt, ULONG *fetched)
531 {
532     BindStatusCallback *This = impl_from_IInternetBindInfo(iface);
533     IInternetBindInfo *bind_info;
534     HRESULT hres;
535 
536     TRACE("(%p)->(%d %p %d %p)\n", This, string_type, strs, cnt, fetched);
537 
538     hres = IBindStatusCallback_QueryInterface(This->callback, &IID_IInternetBindInfo, (void**)&bind_info);
539     if(FAILED(hres))
540         return hres;
541 
542     hres = IInternetBindInfo_GetBindString(bind_info, string_type, strs, cnt, fetched);
543 
544     IInternetBindInfo_Release(bind_info);
545     return hres;
546 }
547 
548 static IInternetBindInfoVtbl BSCInternetBindInfoVtbl = {
549     BSCInternetBindInfo_QueryInterface,
550     BSCInternetBindInfo_AddRef,
551     BSCInternetBindInfo_Release,
552     BSCInternetBindInfo_GetBindInfo,
553     BSCInternetBindInfo_GetBindString
554 };
555 
556 static void set_callback(BindStatusCallback *This, IBindStatusCallback *bsc)
557 {
558     IServiceProvider *serv_prov;
559     HRESULT hres;
560 
561     if(This->callback)
562         IBindStatusCallback_Release(This->callback);
563     if(This->serv_prov)
564         IServiceProvider_Release(This->serv_prov);
565 
566     IBindStatusCallback_AddRef(bsc);
567     This->callback = bsc;
568 
569     hres = IBindStatusCallback_QueryInterface(bsc, &IID_IServiceProvider, (void**)&serv_prov);
570     This->serv_prov = hres == S_OK ? serv_prov : NULL;
571 }
572 
573 HRESULT wrap_callback(IBindStatusCallback *bsc, IBindStatusCallback **ret_iface)
574 {
575     BindStatusCallback *ret;
576 
577     ret = heap_alloc_zero(sizeof(BindStatusCallback));
578     if(!ret)
579         return E_OUTOFMEMORY;
580 
581     ret->IBindStatusCallbackEx_iface.lpVtbl = &BindStatusCallbackExVtbl;
582     ret->IInternetBindInfo_iface.lpVtbl = &BSCInternetBindInfoVtbl;
583     ret->IServiceProvider_iface.lpVtbl = &BSCServiceProviderVtbl;
584     ret->IHttpNegotiate2_iface.lpVtbl = &BSCHttpNegotiateVtbl;
585     ret->IAuthenticate_iface.lpVtbl = &BSCAuthenticateVtbl;
586 
587     ret->ref = 1;
588     set_callback(ret, bsc);
589 
590     *ret_iface = (IBindStatusCallback*)&ret->IBindStatusCallbackEx_iface;
591     return S_OK;
592 }
593 
594 /***********************************************************************
595  *           RegisterBindStatusCallback (urlmon.@)
596  *
597  * Register a bind status callback.
598  *
599  * PARAMS
600  *  pbc           [I] Binding context
601  *  pbsc          [I] Callback to register
602  *  ppbscPrevious [O] Destination for previous callback
603  *  dwReserved    [I] Reserved, must be 0.
604  *
605  * RETURNS
606  *    Success: S_OK.
607  *    Failure: E_INVALIDARG, if any argument is invalid, or
608  *             E_OUTOFMEMORY if memory allocation fails.
609  */
610 HRESULT WINAPI RegisterBindStatusCallback(IBindCtx *pbc, IBindStatusCallback *pbsc,
611         IBindStatusCallback **ppbscPrevious, DWORD dwReserved)
612 {
613     BindStatusCallback *holder;
614     IBindStatusCallback *bsc, *prev = NULL;
615     HRESULT hres;
616 
617     TRACE("(%p %p %p %x)\n", pbc, pbsc, ppbscPrevious, dwReserved);
618 
619     if (!pbc || !pbsc)
620         return E_INVALIDARG;
621 
622     bsc = bsch_from_bctx(pbc);
623     if(bsc) {
624         hres = IBindStatusCallback_QueryInterface(bsc, &IID_IBindStatusCallbackHolder, (void**)&holder);
625         if(SUCCEEDED(hres)) {
626             if(ppbscPrevious) {
627                 IBindStatusCallback_AddRef(holder->callback);
628                 *ppbscPrevious = holder->callback;
629             }
630 
631             set_callback(holder, pbsc);
632 
633             IBindStatusCallback_Release(bsc);
634             IBindStatusCallbackEx_Release(&holder->IBindStatusCallbackEx_iface);
635             return S_OK;
636         }else {
637             prev = bsc;
638         }
639 
640         IBindCtx_RevokeObjectParam(pbc, bscb_holderW);
641     }
642 
643     hres = wrap_callback(pbsc, &bsc);
644     if(SUCCEEDED(hres)) {
645         hres = IBindCtx_RegisterObjectParam(pbc, bscb_holderW, (IUnknown*)bsc);
646         IBindStatusCallback_Release(bsc);
647     }
648     if(FAILED(hres)) {
649         if(prev)
650             IBindStatusCallback_Release(prev);
651         return hres;
652     }
653 
654     if(ppbscPrevious)
655         *ppbscPrevious = prev;
656     return S_OK;
657 }
658 
659 /***********************************************************************
660  *           RevokeBindStatusCallback (URLMON.@)
661  *
662  * Unregister a bind status callback.
663  *
664  *  pbc           [I] Binding context
665  *  pbsc          [I] Callback to unregister
666  *
667  * RETURNS
668  *    Success: S_OK.
669  *    Failure: E_INVALIDARG, if any argument is invalid
670  */
671 HRESULT WINAPI RevokeBindStatusCallback(IBindCtx *pbc, IBindStatusCallback *pbsc)
672 {
673     IBindStatusCallback *callback;
674 
675     TRACE("(%p %p)\n", pbc, pbsc);
676 
677     if (!pbc || !pbsc)
678         return E_INVALIDARG;
679 
680     callback = bsc_from_bctx(pbc);
681     if(!callback)
682         return S_OK;
683 
684     if(callback == pbsc)
685         IBindCtx_RevokeObjectParam(pbc, bscb_holderW);
686 
687     IBindStatusCallback_Release(callback);
688     return S_OK;
689 }
690 
691 typedef struct {
692     IBindCtx IBindCtx_iface;
693 
694     LONG ref;
695 
696     IBindCtx *bindctx;
697 } AsyncBindCtx;
698 
699 static inline AsyncBindCtx *impl_from_IBindCtx(IBindCtx *iface)
700 {
701     return CONTAINING_RECORD(iface, AsyncBindCtx, IBindCtx_iface);
702 }
703 
704 static HRESULT WINAPI AsyncBindCtx_QueryInterface(IBindCtx *iface, REFIID riid, void **ppv)
705 {
706     AsyncBindCtx *This = impl_from_IBindCtx(iface);
707 
708     *ppv = NULL;
709 
710     if(IsEqualGUID(riid, &IID_IUnknown)) {
711         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
712         *ppv = &This->IBindCtx_iface;
713     }else if(IsEqualGUID(riid, &IID_IBindCtx)) {
714         TRACE("(%p)->(IID_IBindCtx %p)\n", This, ppv);
715         *ppv = &This->IBindCtx_iface;
716     }else if(IsEqualGUID(riid, &IID_IAsyncBindCtx)) {
717         TRACE("(%p)->(IID_IAsyncBindCtx %p)\n", This, ppv);
718         *ppv = &This->IBindCtx_iface;
719     }
720 
721     if(*ppv) {
722         IUnknown_AddRef((IUnknown*)*ppv);
723         return S_OK;
724     }
725 
726     FIXME("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
727     return E_NOINTERFACE;
728 }
729 
730 static ULONG WINAPI AsyncBindCtx_AddRef(IBindCtx *iface)
731 {
732     AsyncBindCtx *This = impl_from_IBindCtx(iface);
733     LONG ref = InterlockedIncrement(&This->ref);
734 
735     TRACE("(%p) ref=%d\n", This, ref);
736 
737     return ref;
738 }
739 
740 static ULONG WINAPI AsyncBindCtx_Release(IBindCtx *iface)
741 {
742     AsyncBindCtx *This = impl_from_IBindCtx(iface);
743     LONG ref = InterlockedDecrement(&This->ref);
744 
745     TRACE("(%p) ref=%d\n", This, ref);
746 
747     if(!ref) {
748         IBindCtx_Release(This->bindctx);
749         heap_free(This);
750     }
751 
752     return ref;
753 }
754 
755 static HRESULT WINAPI AsyncBindCtx_RegisterObjectBound(IBindCtx *iface, IUnknown *punk)
756 {
757     AsyncBindCtx *This = impl_from_IBindCtx(iface);
758 
759     TRACE("(%p)->(%p)\n", This, punk);
760 
761     return IBindCtx_RegisterObjectBound(This->bindctx, punk);
762 }
763 
764 static HRESULT WINAPI AsyncBindCtx_RevokeObjectBound(IBindCtx *iface, IUnknown *punk)
765 {
766     AsyncBindCtx *This = impl_from_IBindCtx(iface);
767 
768     TRACE("(%p %p)\n", This, punk);
769 
770     return IBindCtx_RevokeObjectBound(This->bindctx, punk);
771 }
772 
773 static HRESULT WINAPI AsyncBindCtx_ReleaseBoundObjects(IBindCtx *iface)
774 {
775     AsyncBindCtx *This = impl_from_IBindCtx(iface);
776 
777     TRACE("(%p)\n", This);
778 
779     return IBindCtx_ReleaseBoundObjects(This->bindctx);
780 }
781 
782 static HRESULT WINAPI AsyncBindCtx_SetBindOptions(IBindCtx *iface, BIND_OPTS *pbindopts)
783 {
784     AsyncBindCtx *This = impl_from_IBindCtx(iface);
785 
786     TRACE("(%p)->(%p)\n", This, pbindopts);
787 
788     return IBindCtx_SetBindOptions(This->bindctx, pbindopts);
789 }
790 
791 static HRESULT WINAPI AsyncBindCtx_GetBindOptions(IBindCtx *iface, BIND_OPTS *pbindopts)
792 {
793     AsyncBindCtx *This = impl_from_IBindCtx(iface);
794 
795     TRACE("(%p)->(%p)\n", This, pbindopts);
796 
797     return IBindCtx_GetBindOptions(This->bindctx, pbindopts);
798 }
799 
800 static HRESULT WINAPI AsyncBindCtx_GetRunningObjectTable(IBindCtx *iface, IRunningObjectTable **pprot)
801 {
802     AsyncBindCtx *This = impl_from_IBindCtx(iface);
803 
804     TRACE("(%p)->(%p)\n", This, pprot);
805 
806     return IBindCtx_GetRunningObjectTable(This->bindctx, pprot);
807 }
808 
809 static HRESULT WINAPI AsyncBindCtx_RegisterObjectParam(IBindCtx *iface, LPOLESTR pszkey, IUnknown *punk)
810 {
811     AsyncBindCtx *This = impl_from_IBindCtx(iface);
812 
813     TRACE("(%p)->(%s %p)\n", This, debugstr_w(pszkey), punk);
814 
815     return IBindCtx_RegisterObjectParam(This->bindctx, pszkey, punk);
816 }
817 
818 static HRESULT WINAPI AsyncBindCtx_GetObjectParam(IBindCtx* iface, LPOLESTR pszkey, IUnknown **punk)
819 {
820     AsyncBindCtx *This = impl_from_IBindCtx(iface);
821 
822     TRACE("(%p)->(%s %p)\n", This, debugstr_w(pszkey), punk);
823 
824     return IBindCtx_GetObjectParam(This->bindctx, pszkey, punk);
825 }
826 
827 static HRESULT WINAPI AsyncBindCtx_RevokeObjectParam(IBindCtx *iface, LPOLESTR pszkey)
828 {
829     AsyncBindCtx *This = impl_from_IBindCtx(iface);
830 
831     TRACE("(%p)->(%s)\n", This, debugstr_w(pszkey));
832 
833     return IBindCtx_RevokeObjectParam(This->bindctx, pszkey);
834 }
835 
836 static HRESULT WINAPI AsyncBindCtx_EnumObjectParam(IBindCtx *iface, IEnumString **pszkey)
837 {
838     AsyncBindCtx *This = impl_from_IBindCtx(iface);
839 
840     TRACE("(%p)->(%p)\n", This, pszkey);
841 
842     return IBindCtx_EnumObjectParam(This->bindctx, pszkey);
843 }
844 
845 static const IBindCtxVtbl AsyncBindCtxVtbl =
846 {
847     AsyncBindCtx_QueryInterface,
848     AsyncBindCtx_AddRef,
849     AsyncBindCtx_Release,
850     AsyncBindCtx_RegisterObjectBound,
851     AsyncBindCtx_RevokeObjectBound,
852     AsyncBindCtx_ReleaseBoundObjects,
853     AsyncBindCtx_SetBindOptions,
854     AsyncBindCtx_GetBindOptions,
855     AsyncBindCtx_GetRunningObjectTable,
856     AsyncBindCtx_RegisterObjectParam,
857     AsyncBindCtx_GetObjectParam,
858     AsyncBindCtx_EnumObjectParam,
859     AsyncBindCtx_RevokeObjectParam
860 };
861 
862 static HRESULT init_bindctx(IBindCtx *bindctx, DWORD options,
863        IBindStatusCallback *callback, IEnumFORMATETC *format)
864 {
865     BIND_OPTS bindopts;
866     HRESULT hres;
867 
868     if(options)
869         FIXME("not supported options %08x\n", options);
870     if(format)
871         FIXME("format is not supported\n");
872 
873     bindopts.cbStruct = sizeof(BIND_OPTS);
874     bindopts.grfFlags = BIND_MAYBOTHERUSER;
875     bindopts.grfMode = STGM_READWRITE | STGM_SHARE_EXCLUSIVE;
876     bindopts.dwTickCountDeadline = 0;
877 
878     hres = IBindCtx_SetBindOptions(bindctx, &bindopts);
879     if(FAILED(hres))
880        return hres;
881 
882     if(callback) {
883         hres = RegisterBindStatusCallback(bindctx, callback, NULL, 0);
884         if(FAILED(hres))
885             return hres;
886     }
887 
888     return S_OK;
889 }
890 
891 /***********************************************************************
892  *           CreateAsyncBindCtx (urlmon.@)
893  */
894 HRESULT WINAPI CreateAsyncBindCtx(DWORD reserved, IBindStatusCallback *callback,
895         IEnumFORMATETC *format, IBindCtx **pbind)
896 {
897     IBindCtx *bindctx;
898     HRESULT hres;
899 
900     TRACE("(%08x %p %p %p)\n", reserved, callback, format, pbind);
901 
902     if(!pbind || !callback)
903         return E_INVALIDARG;
904 
905     hres = CreateBindCtx(0, &bindctx);
906     if(FAILED(hres))
907         return hres;
908 
909     hres = init_bindctx(bindctx, 0, callback, format);
910     if(FAILED(hres)) {
911         IBindCtx_Release(bindctx);
912         return hres;
913     }
914 
915     *pbind = bindctx;
916     return S_OK;
917 }
918 
919 /***********************************************************************
920  *           CreateAsyncBindCtxEx (urlmon.@)
921  *
922  * Create an asynchronous bind context.
923  */
924 HRESULT WINAPI CreateAsyncBindCtxEx(IBindCtx *ibind, DWORD options,
925         IBindStatusCallback *callback, IEnumFORMATETC *format, IBindCtx** pbind,
926         DWORD reserved)
927 {
928     AsyncBindCtx *ret;
929     IBindCtx *bindctx;
930     HRESULT hres;
931 
932     TRACE("(%p %08x %p %p %p %d)\n", ibind, options, callback, format, pbind, reserved);
933 
934     if(!pbind)
935         return E_INVALIDARG;
936 
937     if(reserved)
938         WARN("reserved=%d\n", reserved);
939 
940     if(ibind) {
941         IBindCtx_AddRef(ibind);
942         bindctx = ibind;
943     }else {
944         hres = CreateBindCtx(0, &bindctx);
945         if(FAILED(hres))
946             return hres;
947     }
948 
949     ret = heap_alloc(sizeof(AsyncBindCtx));
950 
951     ret->IBindCtx_iface.lpVtbl = &AsyncBindCtxVtbl;
952     ret->ref = 1;
953     ret->bindctx = bindctx;
954 
955     hres = init_bindctx(&ret->IBindCtx_iface, options, callback, format);
956     if(FAILED(hres)) {
957         IBindCtx_Release(&ret->IBindCtx_iface);
958         return hres;
959     }
960 
961     *pbind = &ret->IBindCtx_iface;
962     return S_OK;
963 }
964