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