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