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