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