/* * Copyright 2007 Jacek Caban for CodeWeavers * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include <stdio.h> #include "urlmon_main.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(urlmon); static WCHAR bscb_holderW[] = { '_','B','S','C','B','_','H','o','l','d','e','r','_',0 }; extern IID IID_IBindStatusCallbackHolder; typedef struct { IBindStatusCallbackEx IBindStatusCallbackEx_iface; IInternetBindInfo IInternetBindInfo_iface; IServiceProvider IServiceProvider_iface; IHttpNegotiate2 IHttpNegotiate2_iface; IAuthenticate IAuthenticate_iface; LONG ref; IBindStatusCallback *callback; IServiceProvider *serv_prov; } BindStatusCallback; static void *get_callback_iface(BindStatusCallback *This, REFIID riid) { void *ret; HRESULT hres; hres = IBindStatusCallback_QueryInterface(This->callback, riid, &ret); if(FAILED(hres) && This->serv_prov) hres = IServiceProvider_QueryService(This->serv_prov, riid, riid, &ret); return SUCCEEDED(hres) ? ret : NULL; } static IBindStatusCallback *bsch_from_bctx(IBindCtx *bctx) { IBindStatusCallback *bsc; IUnknown *unk; HRESULT hres; hres = IBindCtx_GetObjectParam(bctx, bscb_holderW, &unk); if(FAILED(hres)) return NULL; hres = IUnknown_QueryInterface(unk, &IID_IBindStatusCallback, (void**)&bsc); IUnknown_Release(unk); return SUCCEEDED(hres) ? bsc : NULL; } IBindStatusCallback *bsc_from_bctx(IBindCtx *bctx) { BindStatusCallback *holder; IBindStatusCallback *bsc; HRESULT hres; bsc = bsch_from_bctx(bctx); if(!bsc) return NULL; hres = IBindStatusCallback_QueryInterface(bsc, &IID_IBindStatusCallbackHolder, (void**)&holder); if(FAILED(hres)) return bsc; if(holder->callback) { IBindStatusCallback_Release(bsc); bsc = holder->callback; IBindStatusCallback_AddRef(bsc); } IBindStatusCallbackEx_Release(&holder->IBindStatusCallbackEx_iface); return bsc; } static inline BindStatusCallback *impl_from_IBindStatusCallbackEx(IBindStatusCallbackEx *iface) { return CONTAINING_RECORD(iface, BindStatusCallback, IBindStatusCallbackEx_iface); } static HRESULT WINAPI BindStatusCallback_QueryInterface(IBindStatusCallbackEx *iface, REFIID riid, void **ppv) { BindStatusCallback *This = impl_from_IBindStatusCallbackEx(iface); *ppv = NULL; if(IsEqualGUID(&IID_IUnknown, riid)) { TRACE("(%p)->(IID_IUnknown, %p)\n", This, ppv); *ppv = &This->IBindStatusCallbackEx_iface; }else if(IsEqualGUID(&IID_IBindStatusCallback, riid)) { TRACE("(%p)->(IID_IBindStatusCallback, %p)\n", This, ppv); *ppv = &This->IBindStatusCallbackEx_iface; }else if(IsEqualGUID(&IID_IBindStatusCallbackEx, riid)) { TRACE("(%p)->(IID_IBindStatusCallback, %p)\n", This, ppv); *ppv = &This->IBindStatusCallbackEx_iface; }else if(IsEqualGUID(&IID_IBindStatusCallbackHolder, riid)) { TRACE("(%p)->(IID_IBindStatusCallbackHolder, %p)\n", This, ppv); *ppv = This; }else if(IsEqualGUID(&IID_IServiceProvider, riid)) { TRACE("(%p)->(IID_IServiceProvider, %p)\n", This, ppv); *ppv = &This->IServiceProvider_iface; }else if(IsEqualGUID(&IID_IHttpNegotiate, riid)) { TRACE("(%p)->(IID_IHttpNegotiate, %p)\n", This, ppv); *ppv = &This->IHttpNegotiate2_iface; }else if(IsEqualGUID(&IID_IHttpNegotiate2, riid)) { TRACE("(%p)->(IID_IHttpNegotiate2, %p)\n", This, ppv); *ppv = &This->IHttpNegotiate2_iface; }else if(IsEqualGUID(&IID_IAuthenticate, riid)) { TRACE("(%p)->(IID_IAuthenticate, %p)\n", This, ppv); *ppv = &This->IAuthenticate_iface; }else if(IsEqualGUID(&IID_IInternetBindInfo, riid)) { TRACE("(%p)->(IID_IInternetBindInfo, %p)\n", This, ppv); *ppv = &This->IInternetBindInfo_iface; } if(*ppv) { IUnknown_AddRef((IUnknown*)*ppv); return S_OK; } TRACE("Unsupported riid = %s\n", debugstr_guid(riid)); return E_NOINTERFACE; } static ULONG WINAPI BindStatusCallback_AddRef(IBindStatusCallbackEx *iface) { BindStatusCallback *This = impl_from_IBindStatusCallbackEx(iface); LONG ref = InterlockedIncrement(&This->ref); TRACE("(%p) ref = %d\n", This, ref); return ref; } static ULONG WINAPI BindStatusCallback_Release(IBindStatusCallbackEx *iface) { BindStatusCallback *This = impl_from_IBindStatusCallbackEx(iface); LONG ref = InterlockedDecrement(&This->ref); TRACE("(%p) ref = %d\n", This, ref); if(!ref) { if(This->serv_prov) IServiceProvider_Release(This->serv_prov); IBindStatusCallback_Release(This->callback); heap_free(This); } return ref; } static HRESULT WINAPI BindStatusCallback_OnStartBinding(IBindStatusCallbackEx *iface, DWORD dwReserved, IBinding *pbind) { BindStatusCallback *This = impl_from_IBindStatusCallbackEx(iface); TRACE("(%p)->(%d %p)\n", This, dwReserved, pbind); return IBindStatusCallback_OnStartBinding(This->callback, 0xff, pbind); } static HRESULT WINAPI BindStatusCallback_GetPriority(IBindStatusCallbackEx *iface, LONG *pnPriority) { BindStatusCallback *This = impl_from_IBindStatusCallbackEx(iface); TRACE("(%p)->(%p)\n", This, pnPriority); return IBindStatusCallback_GetPriority(This->callback, pnPriority); } static HRESULT WINAPI BindStatusCallback_OnLowResource(IBindStatusCallbackEx *iface, DWORD reserved) { BindStatusCallback *This = impl_from_IBindStatusCallbackEx(iface); TRACE("(%p)->(%d)\n", This, reserved); return IBindStatusCallback_OnLowResource(This->callback, reserved); } static HRESULT WINAPI BindStatusCallback_OnProgress(IBindStatusCallbackEx *iface, ULONG ulProgress, ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText) { BindStatusCallback *This = impl_from_IBindStatusCallbackEx(iface); TRACE("%p)->(%u %u %s %s)\n", This, ulProgress, ulProgressMax, debugstr_bindstatus(ulStatusCode), debugstr_w(szStatusText)); return IBindStatusCallback_OnProgress(This->callback, ulProgress, ulProgressMax, ulStatusCode, szStatusText); } static HRESULT WINAPI BindStatusCallback_OnStopBinding(IBindStatusCallbackEx *iface, HRESULT hresult, LPCWSTR szError) { BindStatusCallback *This = impl_from_IBindStatusCallbackEx(iface); TRACE("(%p)->(%08x %s)\n", This, hresult, debugstr_w(szError)); return IBindStatusCallback_OnStopBinding(This->callback, hresult, szError); } static HRESULT WINAPI BindStatusCallback_GetBindInfo(IBindStatusCallbackEx *iface, DWORD *grfBINDF, BINDINFO *pbindinfo) { BindStatusCallback *This = impl_from_IBindStatusCallbackEx(iface); IBindStatusCallbackEx *bscex; HRESULT hres; TRACE("(%p)->(%p %p)\n", This, grfBINDF, pbindinfo); hres = IBindStatusCallback_QueryInterface(This->callback, &IID_IBindStatusCallbackEx, (void**)&bscex); if(SUCCEEDED(hres)) { DWORD bindf2 = 0, reserv = 0; hres = IBindStatusCallbackEx_GetBindInfoEx(bscex, grfBINDF, pbindinfo, &bindf2, &reserv); IBindStatusCallbackEx_Release(bscex); }else { hres = IBindStatusCallback_GetBindInfo(This->callback, grfBINDF, pbindinfo); } return hres; } static HRESULT WINAPI BindStatusCallback_OnDataAvailable(IBindStatusCallbackEx *iface, DWORD grfBSCF, DWORD dwSize, FORMATETC *pformatetc, STGMEDIUM *pstgmed) { BindStatusCallback *This = impl_from_IBindStatusCallbackEx(iface); TRACE("(%p)->(%08x %d %p %p)\n", This, grfBSCF, dwSize, pformatetc, pstgmed); return IBindStatusCallback_OnDataAvailable(This->callback, grfBSCF, dwSize, pformatetc, pstgmed); } static HRESULT WINAPI BindStatusCallback_OnObjectAvailable(IBindStatusCallbackEx *iface, REFIID riid, IUnknown *punk) { BindStatusCallback *This = impl_from_IBindStatusCallbackEx(iface); TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), punk); return IBindStatusCallback_OnObjectAvailable(This->callback, riid, punk); } static HRESULT WINAPI BindStatusCallback_GetBindInfoEx(IBindStatusCallbackEx *iface, DWORD *grfBINDF, BINDINFO *pbindinfo, DWORD *grfBINDF2, DWORD *pdwReserved) { BindStatusCallback *This = impl_from_IBindStatusCallbackEx(iface); IBindStatusCallbackEx *bscex; HRESULT hres; TRACE("(%p)->(%p %p %p %p)\n", This, grfBINDF, pbindinfo, grfBINDF2, pdwReserved); hres = IBindStatusCallback_QueryInterface(This->callback, &IID_IBindStatusCallbackEx, (void**)&bscex); if(SUCCEEDED(hres)) { hres = IBindStatusCallbackEx_GetBindInfoEx(bscex, grfBINDF, pbindinfo, grfBINDF2, pdwReserved); IBindStatusCallbackEx_Release(bscex); }else { hres = IBindStatusCallback_GetBindInfo(This->callback, grfBINDF, pbindinfo); } return hres; } static const IBindStatusCallbackExVtbl BindStatusCallbackExVtbl = { BindStatusCallback_QueryInterface, BindStatusCallback_AddRef, BindStatusCallback_Release, BindStatusCallback_OnStartBinding, BindStatusCallback_GetPriority, BindStatusCallback_OnLowResource, BindStatusCallback_OnProgress, BindStatusCallback_OnStopBinding, BindStatusCallback_GetBindInfo, BindStatusCallback_OnDataAvailable, BindStatusCallback_OnObjectAvailable, BindStatusCallback_GetBindInfoEx }; static inline BindStatusCallback *impl_from_IServiceProvider(IServiceProvider *iface) { return CONTAINING_RECORD(iface, BindStatusCallback, IServiceProvider_iface); } static HRESULT WINAPI BSCServiceProvider_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv) { BindStatusCallback *This = impl_from_IServiceProvider(iface); return IBindStatusCallbackEx_QueryInterface(&This->IBindStatusCallbackEx_iface, riid, ppv); } static ULONG WINAPI BSCServiceProvider_AddRef(IServiceProvider *iface) { BindStatusCallback *This = impl_from_IServiceProvider(iface); return IBindStatusCallbackEx_AddRef(&This->IBindStatusCallbackEx_iface); } static ULONG WINAPI BSCServiceProvider_Release(IServiceProvider *iface) { BindStatusCallback *This = impl_from_IServiceProvider(iface); return IBindStatusCallbackEx_Release(&This->IBindStatusCallbackEx_iface); } static HRESULT WINAPI BSCServiceProvider_QueryService(IServiceProvider *iface, REFGUID guidService, REFIID riid, void **ppv) { BindStatusCallback *This = impl_from_IServiceProvider(iface); HRESULT hres; if(IsEqualGUID(&IID_IHttpNegotiate, guidService)) { TRACE("(%p)->(IID_IHttpNegotiate %s %p)\n", This, debugstr_guid(riid), ppv); return IBindStatusCallbackEx_QueryInterface(&This->IBindStatusCallbackEx_iface, riid, ppv); } if(IsEqualGUID(&IID_IHttpNegotiate2, guidService)) { TRACE("(%p)->(IID_IHttpNegotiate2 %s %p)\n", This, debugstr_guid(riid), ppv); return IBindStatusCallbackEx_QueryInterface(&This->IBindStatusCallbackEx_iface, riid, ppv); } if(IsEqualGUID(&IID_IAuthenticate, guidService)) { TRACE("(%p)->(IID_IAuthenticate %s %p)\n", This, debugstr_guid(riid), ppv); return IBindStatusCallbackEx_QueryInterface(&This->IBindStatusCallbackEx_iface, riid, ppv); } TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv); hres = IBindStatusCallback_QueryInterface(This->callback, riid, ppv); if(SUCCEEDED(hres)) return S_OK; if(This->serv_prov) { hres = IServiceProvider_QueryService(This->serv_prov, guidService, riid, ppv); if(SUCCEEDED(hres)) return S_OK; } return E_NOINTERFACE; } static const IServiceProviderVtbl BSCServiceProviderVtbl = { BSCServiceProvider_QueryInterface, BSCServiceProvider_AddRef, BSCServiceProvider_Release, BSCServiceProvider_QueryService }; static inline BindStatusCallback *impl_from_IHttpNegotiate2(IHttpNegotiate2 *iface) { return CONTAINING_RECORD(iface, BindStatusCallback, IHttpNegotiate2_iface); } static HRESULT WINAPI BSCHttpNegotiate_QueryInterface(IHttpNegotiate2 *iface, REFIID riid, void **ppv) { BindStatusCallback *This = impl_from_IHttpNegotiate2(iface); return IBindStatusCallbackEx_QueryInterface(&This->IBindStatusCallbackEx_iface, riid, ppv); } static ULONG WINAPI BSCHttpNegotiate_AddRef(IHttpNegotiate2 *iface) { BindStatusCallback *This = impl_from_IHttpNegotiate2(iface); return IBindStatusCallbackEx_AddRef(&This->IBindStatusCallbackEx_iface); } static ULONG WINAPI BSCHttpNegotiate_Release(IHttpNegotiate2 *iface) { BindStatusCallback *This = impl_from_IHttpNegotiate2(iface); return IBindStatusCallbackEx_Release(&This->IBindStatusCallbackEx_iface); } static HRESULT WINAPI BSCHttpNegotiate_BeginningTransaction(IHttpNegotiate2 *iface, LPCWSTR szURL, LPCWSTR szHeaders, DWORD dwReserved, LPWSTR *pszAdditionalHeaders) { BindStatusCallback *This = impl_from_IHttpNegotiate2(iface); IHttpNegotiate *http_negotiate; HRESULT hres = S_OK; TRACE("(%p)->(%s %s %d %p)\n", This, debugstr_w(szURL), debugstr_w(szHeaders), dwReserved, pszAdditionalHeaders); *pszAdditionalHeaders = NULL; http_negotiate = get_callback_iface(This, &IID_IHttpNegotiate); if(http_negotiate) { hres = IHttpNegotiate_BeginningTransaction(http_negotiate, szURL, szHeaders, dwReserved, pszAdditionalHeaders); IHttpNegotiate_Release(http_negotiate); } return hres; } static HRESULT WINAPI BSCHttpNegotiate_OnResponse(IHttpNegotiate2 *iface, DWORD dwResponseCode, LPCWSTR szResponseHeaders, LPCWSTR szRequestHeaders, LPWSTR *pszAdditionalRequestHeaders) { BindStatusCallback *This = impl_from_IHttpNegotiate2(iface); LPWSTR additional_headers = NULL; IHttpNegotiate *http_negotiate; HRESULT hres = S_OK; TRACE("(%p)->(%d %s %s %p)\n", This, dwResponseCode, debugstr_w(szResponseHeaders), debugstr_w(szRequestHeaders), pszAdditionalRequestHeaders); http_negotiate = get_callback_iface(This, &IID_IHttpNegotiate); if(http_negotiate) { hres = IHttpNegotiate_OnResponse(http_negotiate, dwResponseCode, szResponseHeaders, szRequestHeaders, &additional_headers); IHttpNegotiate_Release(http_negotiate); } if(pszAdditionalRequestHeaders) *pszAdditionalRequestHeaders = additional_headers; else CoTaskMemFree(additional_headers); return hres; } static HRESULT WINAPI BSCHttpNegotiate_GetRootSecurityId(IHttpNegotiate2 *iface, BYTE *pbSecurityId, DWORD *pcbSecurityId, DWORD_PTR dwReserved) { BindStatusCallback *This = impl_from_IHttpNegotiate2(iface); IHttpNegotiate2 *http_negotiate2; HRESULT hres = E_FAIL; TRACE("(%p)->(%p %p %ld)\n", This, pbSecurityId, pcbSecurityId, dwReserved); http_negotiate2 = get_callback_iface(This, &IID_IHttpNegotiate2); if(http_negotiate2) { hres = IHttpNegotiate2_GetRootSecurityId(http_negotiate2, pbSecurityId, pcbSecurityId, dwReserved); IHttpNegotiate2_Release(http_negotiate2); } return hres; } static const IHttpNegotiate2Vtbl BSCHttpNegotiateVtbl = { BSCHttpNegotiate_QueryInterface, BSCHttpNegotiate_AddRef, BSCHttpNegotiate_Release, BSCHttpNegotiate_BeginningTransaction, BSCHttpNegotiate_OnResponse, BSCHttpNegotiate_GetRootSecurityId }; static inline BindStatusCallback *impl_from_IAuthenticate(IAuthenticate *iface) { return CONTAINING_RECORD(iface, BindStatusCallback, IAuthenticate_iface); } static HRESULT WINAPI BSCAuthenticate_QueryInterface(IAuthenticate *iface, REFIID riid, void **ppv) { BindStatusCallback *This = impl_from_IAuthenticate(iface); return IBindStatusCallbackEx_QueryInterface(&This->IBindStatusCallbackEx_iface, riid, ppv); } static ULONG WINAPI BSCAuthenticate_AddRef(IAuthenticate *iface) { BindStatusCallback *This = impl_from_IAuthenticate(iface); return IBindStatusCallbackEx_AddRef(&This->IBindStatusCallbackEx_iface); } static ULONG WINAPI BSCAuthenticate_Release(IAuthenticate *iface) { BindStatusCallback *This = impl_from_IAuthenticate(iface); return IBindStatusCallbackEx_Release(&This->IBindStatusCallbackEx_iface); } static HRESULT WINAPI BSCAuthenticate_Authenticate(IAuthenticate *iface, HWND *phwnd, LPWSTR *pszUsername, LPWSTR *pszPassword) { BindStatusCallback *This = impl_from_IAuthenticate(iface); FIXME("(%p)->(%p %p %p)\n", This, phwnd, pszUsername, pszPassword); return E_NOTIMPL; } static const IAuthenticateVtbl BSCAuthenticateVtbl = { BSCAuthenticate_QueryInterface, BSCAuthenticate_AddRef, BSCAuthenticate_Release, BSCAuthenticate_Authenticate }; static inline BindStatusCallback *impl_from_IInternetBindInfo(IInternetBindInfo *iface) { return CONTAINING_RECORD(iface, BindStatusCallback, IInternetBindInfo_iface); } static HRESULT WINAPI BSCInternetBindInfo_QueryInterface(IInternetBindInfo *iface, REFIID riid, void **ppv) { BindStatusCallback *This = impl_from_IInternetBindInfo(iface); return IBindStatusCallbackEx_QueryInterface(&This->IBindStatusCallbackEx_iface, riid, ppv); } static ULONG WINAPI BSCInternetBindInfo_AddRef(IInternetBindInfo *iface) { BindStatusCallback *This = impl_from_IInternetBindInfo(iface); return IBindStatusCallbackEx_AddRef(&This->IBindStatusCallbackEx_iface); } static ULONG WINAPI BSCInternetBindInfo_Release(IInternetBindInfo *iface) { BindStatusCallback *This = impl_from_IInternetBindInfo(iface); return IBindStatusCallbackEx_Release(&This->IBindStatusCallbackEx_iface); } static HRESULT WINAPI BSCInternetBindInfo_GetBindInfo(IInternetBindInfo *iface, DWORD *bindf, BINDINFO *bindinfo) { BindStatusCallback *This = impl_from_IInternetBindInfo(iface); FIXME("(%p)->(%p %p)\n", This, bindf, bindinfo); return E_NOTIMPL; } static HRESULT WINAPI BSCInternetBindInfo_GetBindString(IInternetBindInfo *iface, ULONG string_type, WCHAR **strs, ULONG cnt, ULONG *fetched) { BindStatusCallback *This = impl_from_IInternetBindInfo(iface); IInternetBindInfo *bind_info; HRESULT hres; TRACE("(%p)->(%d %p %d %p)\n", This, string_type, strs, cnt, fetched); hres = IBindStatusCallback_QueryInterface(This->callback, &IID_IInternetBindInfo, (void**)&bind_info); if(FAILED(hres)) return hres; hres = IInternetBindInfo_GetBindString(bind_info, string_type, strs, cnt, fetched); IInternetBindInfo_Release(bind_info); return hres; } static IInternetBindInfoVtbl BSCInternetBindInfoVtbl = { BSCInternetBindInfo_QueryInterface, BSCInternetBindInfo_AddRef, BSCInternetBindInfo_Release, BSCInternetBindInfo_GetBindInfo, BSCInternetBindInfo_GetBindString }; static void set_callback(BindStatusCallback *This, IBindStatusCallback *bsc) { IServiceProvider *serv_prov; HRESULT hres; if(This->callback) IBindStatusCallback_Release(This->callback); if(This->serv_prov) IServiceProvider_Release(This->serv_prov); IBindStatusCallback_AddRef(bsc); This->callback = bsc; hres = IBindStatusCallback_QueryInterface(bsc, &IID_IServiceProvider, (void**)&serv_prov); This->serv_prov = hres == S_OK ? serv_prov : NULL; } HRESULT wrap_callback(IBindStatusCallback *bsc, IBindStatusCallback **ret_iface) { BindStatusCallback *ret; ret = heap_alloc_zero(sizeof(BindStatusCallback)); if(!ret) return E_OUTOFMEMORY; ret->IBindStatusCallbackEx_iface.lpVtbl = &BindStatusCallbackExVtbl; ret->IInternetBindInfo_iface.lpVtbl = &BSCInternetBindInfoVtbl; ret->IServiceProvider_iface.lpVtbl = &BSCServiceProviderVtbl; ret->IHttpNegotiate2_iface.lpVtbl = &BSCHttpNegotiateVtbl; ret->IAuthenticate_iface.lpVtbl = &BSCAuthenticateVtbl; ret->ref = 1; set_callback(ret, bsc); *ret_iface = (IBindStatusCallback*)&ret->IBindStatusCallbackEx_iface; return S_OK; } /*********************************************************************** * RegisterBindStatusCallback (urlmon.@) * * Register a bind status callback. * * PARAMS * pbc [I] Binding context * pbsc [I] Callback to register * ppbscPrevious [O] Destination for previous callback * dwReserved [I] Reserved, must be 0. * * RETURNS * Success: S_OK. * Failure: E_INVALIDARG, if any argument is invalid, or * E_OUTOFMEMORY if memory allocation fails. */ HRESULT WINAPI RegisterBindStatusCallback(IBindCtx *pbc, IBindStatusCallback *pbsc, IBindStatusCallback **ppbscPrevious, DWORD dwReserved) { BindStatusCallback *holder; IBindStatusCallback *bsc, *prev = NULL; HRESULT hres; TRACE("(%p %p %p %x)\n", pbc, pbsc, ppbscPrevious, dwReserved); if (!pbc || !pbsc) return E_INVALIDARG; bsc = bsch_from_bctx(pbc); if(bsc) { hres = IBindStatusCallback_QueryInterface(bsc, &IID_IBindStatusCallbackHolder, (void**)&holder); if(SUCCEEDED(hres)) { if(ppbscPrevious) { IBindStatusCallback_AddRef(holder->callback); *ppbscPrevious = holder->callback; } set_callback(holder, pbsc); IBindStatusCallback_Release(bsc); IBindStatusCallbackEx_Release(&holder->IBindStatusCallbackEx_iface); return S_OK; }else { prev = bsc; } IBindCtx_RevokeObjectParam(pbc, bscb_holderW); } hres = wrap_callback(pbsc, &bsc); if(SUCCEEDED(hres)) { hres = IBindCtx_RegisterObjectParam(pbc, bscb_holderW, (IUnknown*)bsc); IBindStatusCallback_Release(bsc); } if(FAILED(hres)) { if(prev) IBindStatusCallback_Release(prev); return hres; } if(ppbscPrevious) *ppbscPrevious = prev; return S_OK; } /*********************************************************************** * RevokeBindStatusCallback (URLMON.@) * * Unregister a bind status callback. * * pbc [I] Binding context * pbsc [I] Callback to unregister * * RETURNS * Success: S_OK. * Failure: E_INVALIDARG, if any argument is invalid */ HRESULT WINAPI RevokeBindStatusCallback(IBindCtx *pbc, IBindStatusCallback *pbsc) { IBindStatusCallback *callback; TRACE("(%p %p)\n", pbc, pbsc); if (!pbc || !pbsc) return E_INVALIDARG; callback = bsc_from_bctx(pbc); if(!callback) return S_OK; if(callback == pbsc) IBindCtx_RevokeObjectParam(pbc, bscb_holderW); IBindStatusCallback_Release(callback); return S_OK; } typedef struct { IBindCtx IBindCtx_iface; LONG ref; IBindCtx *bindctx; } AsyncBindCtx; static inline AsyncBindCtx *impl_from_IBindCtx(IBindCtx *iface) { return CONTAINING_RECORD(iface, AsyncBindCtx, IBindCtx_iface); } static HRESULT WINAPI AsyncBindCtx_QueryInterface(IBindCtx *iface, REFIID riid, void **ppv) { AsyncBindCtx *This = impl_from_IBindCtx(iface); *ppv = NULL; if(IsEqualGUID(riid, &IID_IUnknown)) { TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv); *ppv = &This->IBindCtx_iface; }else if(IsEqualGUID(riid, &IID_IBindCtx)) { TRACE("(%p)->(IID_IBindCtx %p)\n", This, ppv); *ppv = &This->IBindCtx_iface; }else if(IsEqualGUID(riid, &IID_IAsyncBindCtx)) { TRACE("(%p)->(IID_IAsyncBindCtx %p)\n", This, ppv); *ppv = &This->IBindCtx_iface; } if(*ppv) { IUnknown_AddRef((IUnknown*)*ppv); return S_OK; } FIXME("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv); return E_NOINTERFACE; } static ULONG WINAPI AsyncBindCtx_AddRef(IBindCtx *iface) { AsyncBindCtx *This = impl_from_IBindCtx(iface); LONG ref = InterlockedIncrement(&This->ref); TRACE("(%p) ref=%d\n", This, ref); return ref; } static ULONG WINAPI AsyncBindCtx_Release(IBindCtx *iface) { AsyncBindCtx *This = impl_from_IBindCtx(iface); LONG ref = InterlockedDecrement(&This->ref); TRACE("(%p) ref=%d\n", This, ref); if(!ref) { IBindCtx_Release(This->bindctx); heap_free(This); } return ref; } static HRESULT WINAPI AsyncBindCtx_RegisterObjectBound(IBindCtx *iface, IUnknown *punk) { AsyncBindCtx *This = impl_from_IBindCtx(iface); TRACE("(%p)->(%p)\n", This, punk); return IBindCtx_RegisterObjectBound(This->bindctx, punk); } static HRESULT WINAPI AsyncBindCtx_RevokeObjectBound(IBindCtx *iface, IUnknown *punk) { AsyncBindCtx *This = impl_from_IBindCtx(iface); TRACE("(%p %p)\n", This, punk); return IBindCtx_RevokeObjectBound(This->bindctx, punk); } static HRESULT WINAPI AsyncBindCtx_ReleaseBoundObjects(IBindCtx *iface) { AsyncBindCtx *This = impl_from_IBindCtx(iface); TRACE("(%p)\n", This); return IBindCtx_ReleaseBoundObjects(This->bindctx); } static HRESULT WINAPI AsyncBindCtx_SetBindOptions(IBindCtx *iface, BIND_OPTS *pbindopts) { AsyncBindCtx *This = impl_from_IBindCtx(iface); TRACE("(%p)->(%p)\n", This, pbindopts); return IBindCtx_SetBindOptions(This->bindctx, pbindopts); } static HRESULT WINAPI AsyncBindCtx_GetBindOptions(IBindCtx *iface, BIND_OPTS *pbindopts) { AsyncBindCtx *This = impl_from_IBindCtx(iface); TRACE("(%p)->(%p)\n", This, pbindopts); return IBindCtx_GetBindOptions(This->bindctx, pbindopts); } static HRESULT WINAPI AsyncBindCtx_GetRunningObjectTable(IBindCtx *iface, IRunningObjectTable **pprot) { AsyncBindCtx *This = impl_from_IBindCtx(iface); TRACE("(%p)->(%p)\n", This, pprot); return IBindCtx_GetRunningObjectTable(This->bindctx, pprot); } static HRESULT WINAPI AsyncBindCtx_RegisterObjectParam(IBindCtx *iface, LPOLESTR pszkey, IUnknown *punk) { AsyncBindCtx *This = impl_from_IBindCtx(iface); TRACE("(%p)->(%s %p)\n", This, debugstr_w(pszkey), punk); return IBindCtx_RegisterObjectParam(This->bindctx, pszkey, punk); } static HRESULT WINAPI AsyncBindCtx_GetObjectParam(IBindCtx* iface, LPOLESTR pszkey, IUnknown **punk) { AsyncBindCtx *This = impl_from_IBindCtx(iface); TRACE("(%p)->(%s %p)\n", This, debugstr_w(pszkey), punk); return IBindCtx_GetObjectParam(This->bindctx, pszkey, punk); } static HRESULT WINAPI AsyncBindCtx_RevokeObjectParam(IBindCtx *iface, LPOLESTR pszkey) { AsyncBindCtx *This = impl_from_IBindCtx(iface); TRACE("(%p)->(%s)\n", This, debugstr_w(pszkey)); return IBindCtx_RevokeObjectParam(This->bindctx, pszkey); } static HRESULT WINAPI AsyncBindCtx_EnumObjectParam(IBindCtx *iface, IEnumString **pszkey) { AsyncBindCtx *This = impl_from_IBindCtx(iface); TRACE("(%p)->(%p)\n", This, pszkey); return IBindCtx_EnumObjectParam(This->bindctx, pszkey); } static const IBindCtxVtbl AsyncBindCtxVtbl = { AsyncBindCtx_QueryInterface, AsyncBindCtx_AddRef, AsyncBindCtx_Release, AsyncBindCtx_RegisterObjectBound, AsyncBindCtx_RevokeObjectBound, AsyncBindCtx_ReleaseBoundObjects, AsyncBindCtx_SetBindOptions, AsyncBindCtx_GetBindOptions, AsyncBindCtx_GetRunningObjectTable, AsyncBindCtx_RegisterObjectParam, AsyncBindCtx_GetObjectParam, AsyncBindCtx_EnumObjectParam, AsyncBindCtx_RevokeObjectParam }; static HRESULT init_bindctx(IBindCtx *bindctx, DWORD options, IBindStatusCallback *callback, IEnumFORMATETC *format) { BIND_OPTS bindopts; HRESULT hres; if(options) FIXME("not supported options %08x\n", options); if(format) FIXME("format is not supported\n"); bindopts.cbStruct = sizeof(BIND_OPTS); bindopts.grfFlags = BIND_MAYBOTHERUSER; bindopts.grfMode = STGM_READWRITE | STGM_SHARE_EXCLUSIVE; bindopts.dwTickCountDeadline = 0; hres = IBindCtx_SetBindOptions(bindctx, &bindopts); if(FAILED(hres)) return hres; if(callback) { hres = RegisterBindStatusCallback(bindctx, callback, NULL, 0); if(FAILED(hres)) return hres; } return S_OK; } /*********************************************************************** * CreateAsyncBindCtx (urlmon.@) */ HRESULT WINAPI CreateAsyncBindCtx(DWORD reserved, IBindStatusCallback *callback, IEnumFORMATETC *format, IBindCtx **pbind) { IBindCtx *bindctx; HRESULT hres; TRACE("(%08x %p %p %p)\n", reserved, callback, format, pbind); if(!pbind || !callback) return E_INVALIDARG; hres = CreateBindCtx(0, &bindctx); if(FAILED(hres)) return hres; hres = init_bindctx(bindctx, 0, callback, format); if(FAILED(hres)) { IBindCtx_Release(bindctx); return hres; } *pbind = bindctx; return S_OK; } /*********************************************************************** * CreateAsyncBindCtxEx (urlmon.@) * * Create an asynchronous bind context. */ HRESULT WINAPI CreateAsyncBindCtxEx(IBindCtx *ibind, DWORD options, IBindStatusCallback *callback, IEnumFORMATETC *format, IBindCtx** pbind, DWORD reserved) { AsyncBindCtx *ret; IBindCtx *bindctx; HRESULT hres; TRACE("(%p %08x %p %p %p %d)\n", ibind, options, callback, format, pbind, reserved); if(!pbind) return E_INVALIDARG; if(reserved) WARN("reserved=%d\n", reserved); if(ibind) { IBindCtx_AddRef(ibind); bindctx = ibind; }else { hres = CreateBindCtx(0, &bindctx); if(FAILED(hres)) return hres; } ret = heap_alloc(sizeof(AsyncBindCtx)); ret->IBindCtx_iface.lpVtbl = &AsyncBindCtxVtbl; ret->ref = 1; ret->bindctx = bindctx; hres = init_bindctx(&ret->IBindCtx_iface, options, callback, format); if(FAILED(hres)) { IBindCtx_Release(&ret->IBindCtx_iface); return hres; } *pbind = &ret->IBindCtx_iface; return S_OK; }