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