Git conversion: Make reactos the root directory, move rosapps, rostests, wallpapers...
[reactos.git] / dll / win32 / urlmon / bindctx.c
diff --git a/dll/win32/urlmon/bindctx.c b/dll/win32/urlmon/bindctx.c
new file mode 100644 (file)
index 0000000..7a81406
--- /dev/null
@@ -0,0 +1,963 @@
+/*
+ * 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 "urlmon_main.h"
+
+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, (void**)&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;
+}