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