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