- Create another branch for networking fixes
[reactos.git] / dll / win32 / 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 }