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