urlmon: Added more RegiterBindStatusCallback tests.
diff --git a/dlls/urlmon/tests/url.c b/dlls/urlmon/tests/url.c
index 36b5dd0..da57ce8 100644
--- a/dlls/urlmon/tests/url.c
+++ b/dlls/urlmon/tests/url.c
@@ -73,6 +73,8 @@
 DEFINE_EXPECT(QueryInterface_IInternetBindInfo);
 DEFINE_EXPECT(QueryInterface_IAuthenticate);
 DEFINE_EXPECT(QueryInterface_IInternetProtocol);
+DEFINE_EXPECT(QueryService_IAuthenticate);
+DEFINE_EXPECT(QueryService_IInternetProtocol);
 DEFINE_EXPECT(BeginningTransaction);
 DEFINE_EXPECT(OnResponse);
 DEFINE_EXPECT(QueryInterface_IHttpNegotiate2);
@@ -110,7 +112,7 @@
 static const WCHAR MK_URL[] = {'m','k',':','@','M','S','I','T','S','t','o','r','e',':',
     't','e','s','t','.','c','h','m',':',':','/','b','l','a','n','k','.','h','t','m','l',0};
 
-
+static WCHAR BSCBHolder[] = { '_','B','S','C','B','_','H','o','l','d','e','r','_',0 };
 
 static const WCHAR wszIndexHtml[] = {'i','n','d','e','x','.','h','t','m','l',0};
 
@@ -473,6 +475,9 @@
     ok(pbSecurityId != NULL, "pbSecurityId == NULL\n");
     ok(pcbSecurityId != NULL, "pcbSecurityId == NULL\n");
 
+    if(pbSecurityId == (void*)0xdeadbeef)
+        return E_NOTIMPL;
+
     if(pcbSecurityId) {
         ok(*pcbSecurityId == 512, "*pcbSecurityId=%d, expected 512\n", *pcbSecurityId);
         *pcbSecurityId = sizeof(sec_id);
@@ -495,6 +500,48 @@
 
 static IHttpNegotiate2 HttpNegotiate = { &HttpNegotiateVtbl };
 
+static HRESULT WINAPI ServiceProvider_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv)
+{
+    ok(0, "unexpected call\n");
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI ServiceProvider_AddRef(IServiceProvider *iface)
+{
+    return 2;
+}
+
+static ULONG WINAPI ServiceProvider_Release(IServiceProvider *iface)
+{
+    return 1;
+}
+
+static HRESULT WINAPI ServiceProvider_QueryService(IServiceProvider *iface,
+        REFGUID guidService, REFIID riid, void **ppv)
+{
+    if(IsEqualGUID(&IID_IAuthenticate, guidService)) {
+        CHECK_EXPECT(QueryService_IAuthenticate);
+        return E_NOTIMPL;
+    }
+
+    if(IsEqualGUID(&IID_IInternetProtocol, guidService)) {
+        CHECK_EXPECT2(QueryService_IInternetProtocol);
+        return E_NOTIMPL;
+    }
+
+    ok(0, "unexpected service %s\n", debugstr_guid(guidService));
+    return E_NOINTERFACE;
+}
+
+static IServiceProviderVtbl ServiceProviderVtbl = {
+    ServiceProvider_QueryInterface,
+    ServiceProvider_AddRef,
+    ServiceProvider_Release,
+    ServiceProvider_QueryService
+};
+
+static IServiceProvider ServiceProvider = { &ServiceProviderVtbl };
+
 static HRESULT WINAPI statusclb_QueryInterface(IBindStatusCallback *iface, REFIID riid, void **ppv)
 {
     if(IsEqualGUID(&IID_IInternetProtocol, riid)) {
@@ -508,8 +555,9 @@
     }
     else if (IsEqualGUID(&IID_IServiceProvider, riid))
     {
-        CHECK_EXPECT(QueryInterface_IServiceProvider);
-        return E_NOINTERFACE;
+        CHECK_EXPECT2(QueryInterface_IServiceProvider);
+        *ppv = &ServiceProvider;
+        return S_OK;
     }
     else if (IsEqualGUID(&IID_IHttpNegotiate, riid))
     {
@@ -571,6 +619,10 @@
     CHECK_EXPECT(OnStartBinding);
 
     ok(pib != NULL, "pib should not be NULL\n");
+    ok(dwReserved == 0xff, "dwReserved=%x\n", dwReserved);
+
+    if(pib == (void*)0xdeadbeef)
+        return S_OK;
 
     hres = IBinding_QueryInterface(pib, &IID_IMoniker, (void**)&mon);
     ok(hres == E_NOINTERFACE, "IBinding should not have IMoniker interface\n");
@@ -760,7 +812,7 @@
 
     SET_EXPECT(QueryInterface_IServiceProvider);
     hres = CreateAsyncBindCtx(0, &bsc, NULL, &bctx);
-    ok(SUCCEEDED(hres), "CreateAsyncBindCtx failed: %08x\n", hres);
+    ok(hres == S_OK, "CreateAsyncBindCtx failed: %08x\n", hres);
     CHECK_CALLED(QueryInterface_IServiceProvider);
 
     bindopts.cbStruct = sizeof(bindopts);
@@ -846,6 +898,198 @@
         IBindCtx_Release(bctx);
 }
 
+static void test_bscholder(IBindStatusCallback *holder)
+{
+    IServiceProvider *serv_prov;
+    IHttpNegotiate *http_negotiate, *http_negotiate_serv;
+    IHttpNegotiate2 *http_negotiate2, *http_negotiate2_serv;
+    IAuthenticate *authenticate, *authenticate_serv;
+    IInternetProtocol *protocol;
+    BINDINFO bindinfo = {sizeof(bindinfo)};
+    LPWSTR wstr;
+    DWORD dw;
+    HRESULT hres;
+
+    static const WCHAR emptyW[] = {0};
+
+    hres = IBindStatusCallback_QueryInterface(holder, &IID_IServiceProvider, (void**)&serv_prov);
+    ok(hres == S_OK, "Could not get IServiceProvider interface: %08x\n", hres);
+
+    dw = 0xdeadbeef;
+    SET_EXPECT(GetBindInfo);
+    hres = IBindStatusCallback_GetBindInfo(holder, &dw, &bindinfo);
+    ok(hres == S_OK, "GetBindInfo failed: %08x\n", hres);
+    CHECK_CALLED(GetBindInfo);
+
+    SET_EXPECT(OnStartBinding);
+    hres = IBindStatusCallback_OnStartBinding(holder, 0, (void*)0xdeadbeef);
+    ok(hres == S_OK, "OnStartBinding failed: %08x\n", hres);
+    CHECK_CALLED(OnStartBinding);
+
+    hres = IBindStatusCallback_QueryInterface(holder, &IID_IHttpNegotiate, (void**)&http_negotiate);
+    ok(hres == S_OK, "Could not get IHttpNegotiate interface: %08x\n", hres);
+
+    wstr = (void*)0xdeadbeef;
+    hres = IHttpNegotiate_BeginningTransaction(http_negotiate, urls[test_protocol], (void*)0xdeadbeef, 0xff, &wstr);
+    ok(hres == S_OK, "BeginningTransaction failed: %08x\n", hres);
+    ok(wstr == NULL, "wstr = %p\n", wstr);
+
+    SET_EXPECT(QueryInterface_IHttpNegotiate);
+    hres = IServiceProvider_QueryService(serv_prov, &IID_IHttpNegotiate, &IID_IHttpNegotiate,
+                                         (void**)&http_negotiate_serv);
+    ok(hres == S_OK, "Could not get IHttpNegotiate service: %08x\n", hres);
+    CHECK_CALLED(QueryInterface_IHttpNegotiate);
+
+    ok(http_negotiate == http_negotiate_serv, "http_negotiate != http_negotiate_serv\n");
+
+    wstr = (void*)0xdeadbeef;
+    SET_EXPECT(BeginningTransaction);
+    hres = IHttpNegotiate_BeginningTransaction(http_negotiate_serv, urls[test_protocol], emptyW, 0, &wstr);
+    CHECK_CALLED(BeginningTransaction);
+    ok(hres == S_OK, "BeginningTransaction failed: %08x\n", hres);
+    ok(wstr == NULL, "wstr = %p\n", wstr);
+
+    IHttpNegotiate_Release(http_negotiate_serv);
+
+    hres = IServiceProvider_QueryService(serv_prov, &IID_IHttpNegotiate, &IID_IHttpNegotiate,
+                                         (void**)&http_negotiate_serv);
+    ok(hres == S_OK, "Could not get IHttpNegotiate service: %08x\n", hres);
+    ok(http_negotiate == http_negotiate_serv, "http_negotiate != http_negotiate_serv\n");
+    IHttpNegotiate_Release(http_negotiate_serv);
+
+    hres = IBindStatusCallback_QueryInterface(holder, &IID_IHttpNegotiate2, (void**)&http_negotiate2);
+    ok(hres == S_OK, "Could not get IHttpNegotiate2 interface: %08x\n", hres);
+
+    hres = IHttpNegotiate2_GetRootSecurityId(http_negotiate2, (void*)0xdeadbeef, (void*)0xdeadbeef, 0);
+    ok(hres == E_FAIL, "GetRootSecurityId failed: %08x\n", hres);
+
+    IHttpNegotiate_Release(http_negotiate2);
+
+    SET_EXPECT(QueryInterface_IHttpNegotiate2);
+    hres = IServiceProvider_QueryService(serv_prov, &IID_IHttpNegotiate2, &IID_IHttpNegotiate2,
+                                         (void**)&http_negotiate2_serv);
+    ok(hres == S_OK, "Could not get IHttpNegotiate2 service: %08x\n", hres);
+    CHECK_CALLED(QueryInterface_IHttpNegotiate2);
+    ok(http_negotiate2 == http_negotiate2_serv, "http_negotiate != http_negotiate_serv\n");
+
+    SET_EXPECT(GetRootSecurityId);
+    hres = IHttpNegotiate2_GetRootSecurityId(http_negotiate2, (void*)0xdeadbeef, (void*)0xdeadbeef, 0);
+    ok(hres == E_NOTIMPL, "GetRootSecurityId failed: %08x\n", hres);
+    CHECK_CALLED(GetRootSecurityId);
+
+    IHttpNegotiate_Release(http_negotiate2_serv);
+
+    SET_EXPECT(OnProgress_FINDINGRESOURCE);
+    hres = IBindStatusCallback_OnProgress(holder, 0, 0, BINDSTATUS_FINDINGRESOURCE, NULL);
+    ok(hres == S_OK, "OnProgress failed: %08x\n", hres);
+    CHECK_CALLED(OnProgress_FINDINGRESOURCE);
+
+    SET_EXPECT(OnResponse);
+    wstr = (void*)0xdeadbeef;
+    hres = IHttpNegotiate_OnResponse(http_negotiate, 200, emptyW, NULL, NULL);
+    ok(hres == S_OK, "OnResponse failed: %08x\n", hres);
+    CHECK_CALLED(OnResponse);
+
+    IHttpNegotiate_Release(http_negotiate);
+
+    hres = IBindStatusCallback_QueryInterface(holder, &IID_IAuthenticate, (void**)&authenticate);
+    ok(hres == S_OK, "Could not get IAuthenticate interface: %08x\n", hres);
+
+    SET_EXPECT(QueryInterface_IAuthenticate);
+    SET_EXPECT(QueryService_IAuthenticate);
+    hres = IServiceProvider_QueryService(serv_prov, &IID_IAuthenticate, &IID_IAuthenticate,
+                                         (void**)&authenticate_serv);
+    ok(hres == S_OK, "Could not get IAuthenticate service: %08x\n", hres);
+    CHECK_CALLED(QueryInterface_IAuthenticate);
+    CHECK_CALLED(QueryService_IAuthenticate);
+    ok(authenticate == authenticate_serv, "authenticate != authenticate_serv\n");
+    IAuthenticate_Release(authenticate_serv);
+
+    hres = IServiceProvider_QueryService(serv_prov, &IID_IAuthenticate, &IID_IAuthenticate,
+                                         (void**)&authenticate_serv);
+    ok(hres == S_OK, "Could not get IAuthenticate service: %08x\n", hres);
+    ok(authenticate == authenticate_serv, "authenticate != authenticate_serv\n");
+
+    IAuthenticate_Release(authenticate);
+    IAuthenticate_Release(authenticate_serv);
+
+    SET_EXPECT(OnStopBinding);
+    hres = IBindStatusCallback_OnStopBinding(holder, S_OK, NULL);
+    ok(hres == S_OK, "OnStopBinding failed: %08x\n", hres);
+    CHECK_CALLED(OnStopBinding);
+
+    SET_EXPECT(QueryInterface_IInternetProtocol);
+    SET_EXPECT(QueryService_IInternetProtocol);
+    hres = IServiceProvider_QueryService(serv_prov, &IID_IInternetProtocol, &IID_IInternetProtocol,
+                                         (void**)&protocol);
+    ok(hres == E_NOINTERFACE, "QueryService(IInternetProtocol) failed: %08x\n", hres);
+    CHECK_CALLED(QueryInterface_IInternetProtocol);
+    CHECK_CALLED(QueryService_IInternetProtocol);
+
+    IServiceProvider_Release(serv_prov);
+}
+
+static void test_RegisterBindStatusCallback(void)
+{
+    IBindStatusCallback *prevbsc, *clb;
+    IBindCtx *bindctx;
+    IUnknown *unk;
+    HRESULT hres;
+
+    hres = CreateBindCtx(0, &bindctx);
+    ok(hres == S_OK, "BindCtx failed: %08x\n", hres);
+
+    SET_EXPECT(QueryInterface_IServiceProvider);
+
+    hres = IBindCtx_RegisterObjectParam(bindctx, BSCBHolder, (IUnknown*)&bsc);
+    ok(hres == S_OK, "RegisterObjectParam failed: %08x\n", hres);
+
+    SET_EXPECT(QueryInterface_IBindStatusCallback);
+    SET_EXPECT(QueryInterface_IBindStatusCallbackHolder);
+    prevbsc = (void*)0xdeadbeef;
+    hres = RegisterBindStatusCallback(bindctx, &bsc, &prevbsc, 0);
+    ok(hres == S_OK, "RegisterBindStatusCallback failed: %08x\n", hres);
+    ok(prevbsc == &bsc, "prevbsc=%p\n", prevbsc);
+    CHECK_CALLED(QueryInterface_IBindStatusCallback);
+    CHECK_CALLED(QueryInterface_IBindStatusCallbackHolder);
+
+    CHECK_CALLED(QueryInterface_IServiceProvider);
+
+    hres = IBindCtx_GetObjectParam(bindctx, BSCBHolder, &unk);
+    ok(hres == S_OK, "GetObjectParam failed: %08x\n", hres);
+
+    hres = IUnknown_QueryInterface(unk, &IID_IBindStatusCallback, (void**)&clb);
+    IUnknown_Release(unk);
+    ok(hres == S_OK, "QueryInterface(IID_IBindStatusCallback) failed: %08x\n", hres);
+    ok(clb != &bsc, "bsc == clb\n");
+
+    test_bscholder(clb);
+
+    IBindStatusCallback_Release(clb);
+
+    hres = RevokeBindStatusCallback(bindctx, &bsc);
+    ok(hres == S_OK, "RevokeBindStatusCallback failed: %08x\n", hres);
+
+    unk = (void*)0xdeadbeef;
+    hres = IBindCtx_GetObjectParam(bindctx, BSCBHolder, &unk);
+    ok(hres == E_FAIL, "GetObjectParam failed: %08x\n", hres);
+    ok(unk == NULL, "unk != NULL\n");
+
+    if(unk)
+        IUnknown_Release(unk);
+
+    hres = RevokeBindStatusCallback(bindctx, (void*)0xdeadbeef);
+    ok(hres == S_OK, "RevokeBindStatusCallback failed: %08x\n", hres);
+
+    hres = RevokeBindStatusCallback(NULL, (void*)0xdeadbeef);
+    ok(hres == E_INVALIDARG, "RevokeBindStatusCallback failed: %08x\n", hres);
+
+    hres = RevokeBindStatusCallback(bindctx, NULL);
+    ok(hres == E_INVALIDARG, "RevokeBindStatusCallback failed: %08x\n", hres);
+
+    IBindCtx_Release(bindctx);
+}
+
 static void test_BindToStorage(int protocol, BOOL emul)
 {
     IMoniker *mon;
@@ -900,6 +1144,8 @@
 
     SET_EXPECT(GetBindInfo);
     SET_EXPECT(QueryInterface_IInternetProtocol);
+    if(!emulate_protocol)
+        SET_EXPECT(QueryService_IInternetProtocol);
     SET_EXPECT(OnStartBinding);
     if(emulate_protocol) {
         SET_EXPECT(Start);
@@ -952,6 +1198,8 @@
 
     CHECK_CALLED(GetBindInfo);
     CHECK_CALLED(QueryInterface_IInternetProtocol);
+    if(!emulate_protocol)
+        CHECK_CALLED(QueryService_IInternetProtocol);
     CHECK_CALLED(OnStartBinding);
     if(emulate_protocol) {
         CHECK_CALLED(Start);
@@ -1053,6 +1301,7 @@
     test_create();
     test_CreateAsyncBindCtx();
     test_CreateAsyncBindCtxEx();
+    test_RegisterBindStatusCallback();
 
     trace("synchronous http test...\n");
     test_BindToStorage(HTTP_TEST, FALSE);