mshtml: Create inner window early in binding process and use it to store current binding callback.
diff --git a/dlls/mshtml/binding.h b/dlls/mshtml/binding.h
index 7e3b6d3..2970849 100644
--- a/dlls/mshtml/binding.h
+++ b/dlls/mshtml/binding.h
@@ -111,7 +111,7 @@
 HRESULT navigate_new_window(HTMLOuterWindow*,IUri*,const WCHAR*,IHTMLWindow2**) DECLSPEC_HIDDEN;
 
 HRESULT create_channelbsc(IMoniker*,const WCHAR*,BYTE*,DWORD,nsChannelBSC**) DECLSPEC_HIDDEN;
-HRESULT channelbsc_load_stream(nsChannelBSC*,IStream*) DECLSPEC_HIDDEN;
+HRESULT channelbsc_load_stream(HTMLInnerWindow*,IStream*) DECLSPEC_HIDDEN;
 void channelbsc_set_channel(nsChannelBSC*,nsChannel*,nsIStreamListener*,nsISupports*) DECLSPEC_HIDDEN;
 IUri *nsuri_get_uri(nsWineURI*) DECLSPEC_HIDDEN;
 HRESULT create_relative_uri(HTMLOuterWindow*,const WCHAR*,IUri**) DECLSPEC_HIDDEN;
diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c
index d448614..0ced93d 100644
--- a/dlls/mshtml/htmlwindow.c
+++ b/dlls/mshtml/htmlwindow.c
@@ -197,8 +197,13 @@
 
 static void release_outer_window(HTMLOuterWindow *This)
 {
+    if(This->pending_window) {
+        abort_window_bindings(This->pending_window);
+        This->pending_window->base.outer_window = NULL;
+        IHTMLWindow2_Release(&This->pending_window->base.IHTMLWindow2_iface);
+    }
+
     remove_target_tasks(This->task_magic);
-    set_window_bscallback(This, NULL);
     set_current_mon(This, NULL);
     detach_inner_window(This);
     release_children(This);
@@ -228,9 +233,14 @@
 {
     unsigned i;
 
+    TRACE("%p\n", This);
+
+    abort_window_bindings(This);
     release_script_hosts(This);
 
-    htmldoc_release(&This->doc->basedoc);
+    if(This->doc)
+        htmldoc_release(&This->doc->basedoc);
+
     release_dispex(&This->dispex);
 
     for(i=0; i < This->global_prop_cnt; i++)
@@ -2596,7 +2606,7 @@
     return window;
 }
 
-static HRESULT create_inner_window(HTMLOuterWindow *outer_window, HTMLDocumentNode *doc_node, HTMLInnerWindow **ret)
+static HRESULT create_inner_window(HTMLOuterWindow *outer_window, HTMLInnerWindow **ret)
 {
     HTMLInnerWindow *window;
 
@@ -2610,9 +2620,6 @@
     window->base.outer_window = outer_window;
     window->base.inner_window = window;
 
-    htmldoc_addref(&doc_node->basedoc);
-    window->doc = doc_node;
-
     init_dispex(&window->dispex, (IUnknown*)&window->base.IHTMLWindow2_iface, &HTMLWindow_dispex);
 
     *ret = window;
@@ -2651,7 +2658,9 @@
     window->scriptmode = parent ? parent->scriptmode : SCRIPTMODE_GECKO;
     window->readystate = READYSTATE_UNINITIALIZED;
 
-    hres = update_window_doc(window);
+    hres = create_pending_window(window, NULL);
+    if(SUCCEEDED(hres))
+        hres = update_window_doc(window->pending_window);
     if(FAILED(hres)) {
         IHTMLWindow2_Release(&window->base.IHTMLWindow2_iface);
         return hres;
@@ -2675,54 +2684,54 @@
         list_add_tail(&parent->children, &window->sibling_entry);
     }
 
+    TRACE("%p inner_window %p\n", window, window->base.inner_window);
+
     *ret = window;
     return S_OK;
 }
 
-static HRESULT window_set_docnode(HTMLOuterWindow *window, HTMLDocumentNode *doc_node)
+HRESULT create_pending_window(HTMLOuterWindow *outer_window, nsChannelBSC *channelbsc)
 {
-    HTMLInnerWindow *inner_window;
+    HTMLInnerWindow *pending_window;
     HRESULT hres;
 
-    hres = create_inner_window(window, doc_node, &inner_window);
+    hres = create_inner_window(outer_window, &pending_window);
     if(FAILED(hres))
         return hres;
 
-    detach_inner_window(window);
-    window->base.inner_window = inner_window;
+    if(channelbsc) {
+        IBindStatusCallback_AddRef(&channelbsc->bsc.IBindStatusCallback_iface);
+        pending_window->bscallback = channelbsc;
 
-    if(window->doc_obj && window->doc_obj->basedoc.window == window) {
-        if(window->doc_obj->basedoc.doc_node)
-            htmldoc_release(&window->doc_obj->basedoc.doc_node->basedoc);
-        window->doc_obj->basedoc.doc_node = doc_node;
-        if(doc_node)
-            htmldoc_addref(&doc_node->basedoc);
+        channelbsc->window = outer_window;
     }
 
-    if(doc_node && window->doc_obj && window->doc_obj->usermode == EDITMODE) {
-        nsAString mode_str;
-        nsresult nsres;
-
-        static const PRUnichar onW[] = {'o','n',0};
-
-        nsAString_Init(&mode_str, onW);
-        nsres = nsIDOMHTMLDocument_SetDesignMode(doc_node->nsdoc, &mode_str);
-        nsAString_Finish(&mode_str);
-        if(NS_FAILED(nsres))
-            ERR("SetDesignMode failed: %08x\n", nsres);
+    if(outer_window->pending_window) {
+        abort_window_bindings(outer_window->pending_window);
+        outer_window->pending_window->base.outer_window = NULL;
+        IHTMLWindow2_Release(&outer_window->pending_window->base.IHTMLWindow2_iface);
     }
 
+    outer_window->pending_window = pending_window;
     return S_OK;
 }
 
-HRESULT update_window_doc(HTMLOuterWindow *window)
+HRESULT update_window_doc(HTMLInnerWindow *window)
 {
+    HTMLOuterWindow *outer_window = window->base.outer_window;
     nsIDOMHTMLDocument *nshtmldoc;
     nsIDOMDocument *nsdoc;
     nsresult nsres;
     HRESULT hres;
 
-    nsres = nsIDOMWindow_GetDocument(window->nswindow, &nsdoc);
+    assert(!window->doc);
+
+    if(!outer_window) {
+        ERR("NULL outer window\n");
+        return E_UNEXPECTED;
+    }
+
+    nsres = nsIDOMWindow_GetDocument(outer_window->nswindow, &nsdoc);
     if(NS_FAILED(nsres) || !nsdoc) {
         ERR("GetDocument failed: %08x\n", nsres);
         return E_FAIL;
@@ -2735,21 +2744,40 @@
         return E_FAIL;
     }
 
-    if(!window->base.inner_window || window->base.inner_window->doc->nsdoc != nshtmldoc) {
-        HTMLDocumentNode *doc;
+    hres = create_doc_from_nsdoc(nshtmldoc, outer_window->doc_obj, outer_window, &window->doc);
+    nsIDOMHTMLDocument_Release(nshtmldoc);
+    if(FAILED(hres))
+        return hres;
 
-        hres = create_doc_from_nsdoc(nshtmldoc, window->doc_obj, window, &doc);
-        if(SUCCEEDED(hres)) {
-            hres = window_set_docnode(window, doc);
-            htmldoc_release(&doc->basedoc);
-        }else {
-            ERR("create_doc_from_nsdoc failed: %08x\n", hres);
-        }
-    }else {
-        hres = S_OK;
+    if(outer_window->doc_obj->usermode == EDITMODE) {
+        nsAString mode_str;
+        nsresult nsres;
+
+        static const PRUnichar onW[] = {'o','n',0};
+
+        nsAString_Init(&mode_str, onW);
+        nsres = nsIDOMHTMLDocument_SetDesignMode(window->doc->nsdoc, &mode_str);
+        nsAString_Finish(&mode_str);
+        if(NS_FAILED(nsres))
+            ERR("SetDesignMode failed: %08x\n", nsres);
     }
 
-    nsIDOMHTMLDocument_Release(nshtmldoc);
+    if(window != outer_window->pending_window) {
+        ERR("not current pending window\n");
+        return S_OK;
+    }
+
+    detach_inner_window(outer_window);
+    outer_window->base.inner_window = window;
+    outer_window->pending_window = NULL;
+
+    if(outer_window->doc_obj && (outer_window->doc_obj->basedoc.window == outer_window || !outer_window->doc_obj->basedoc.window)) {
+        if(outer_window->doc_obj->basedoc.doc_node)
+            htmldoc_release(&outer_window->doc_obj->basedoc.doc_node->basedoc);
+        outer_window->doc_obj->basedoc.doc_node = window->doc;
+        htmldoc_addref(&window->doc->basedoc);
+    }
+
     return hres;
 }
 
diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h
index b63ad53..f0dde6c 100644
--- a/dlls/mshtml/mshtml_private.h
+++ b/dlls/mshtml/mshtml_private.h
@@ -326,7 +326,7 @@
     HTMLFrameBase *frame_element;
     READYSTATE readystate;
 
-    nsChannelBSC *bscallback;
+    HTMLInnerWindow *pending_window;
     IMoniker *mon;
     IUri *uri;
     BSTR url;
@@ -361,6 +361,7 @@
     DWORD global_prop_cnt;
     DWORD global_prop_size;
 
+    nsChannelBSC *bscallback;
     struct list bindings;
 };
 
@@ -665,7 +666,7 @@
 HRESULT create_document_fragment(nsIDOMNode*,HTMLDocumentNode*,HTMLDocumentNode**) DECLSPEC_HIDDEN;
 
 HRESULT HTMLOuterWindow_Create(HTMLDocumentObj*,nsIDOMWindow*,HTMLOuterWindow*,HTMLOuterWindow**) DECLSPEC_HIDDEN;
-HRESULT update_window_doc(HTMLOuterWindow*) DECLSPEC_HIDDEN;
+HRESULT update_window_doc(HTMLInnerWindow*) DECLSPEC_HIDDEN;
 HTMLOuterWindow *nswindow_to_window(const nsIDOMWindow*) DECLSPEC_HIDDEN;
 void get_top_window(HTMLOuterWindow*,HTMLOuterWindow**) DECLSPEC_HIDDEN;
 HRESULT HTMLOptionElementFactory_Create(HTMLInnerWindow*,HTMLOptionElementFactory**) DECLSPEC_HIDDEN;
@@ -750,11 +751,11 @@
 nsresult get_nsinterface(nsISupports*,REFIID,void**) DECLSPEC_HIDDEN;
 nsIWritableVariant *create_nsvariant(void) DECLSPEC_HIDDEN;
 
-void set_window_bscallback(HTMLOuterWindow*,nsChannelBSC*) DECLSPEC_HIDDEN;
+HRESULT create_pending_window(HTMLOuterWindow*,nsChannelBSC*) DECLSPEC_HIDDEN;
 void set_current_mon(HTMLOuterWindow*,IMoniker*) DECLSPEC_HIDDEN;
 void set_current_uri(HTMLOuterWindow*,IUri*) DECLSPEC_HIDDEN;
 HRESULT start_binding(HTMLOuterWindow*,HTMLInnerWindow*,BSCallback*,IBindCtx*) DECLSPEC_HIDDEN;
-HRESULT async_start_doc_binding(HTMLOuterWindow*,nsChannelBSC*) DECLSPEC_HIDDEN;
+HRESULT async_start_doc_binding(HTMLOuterWindow*,HTMLInnerWindow*) DECLSPEC_HIDDEN;
 void abort_window_bindings(HTMLInnerWindow*) DECLSPEC_HIDDEN;
 void set_download_state(HTMLDocumentObj*,int) DECLSPEC_HIDDEN;
 void call_docview_84(HTMLDocumentObj*) DECLSPEC_HIDDEN;
diff --git a/dlls/mshtml/navigate.c b/dlls/mshtml/navigate.c
index c07fd90..1fe4f9d 100644
--- a/dlls/mshtml/navigate.c
+++ b/dlls/mshtml/navigate.c
@@ -725,8 +725,6 @@
     TRACE("(%p %p %p %p)\n", window, inner_window, bscallback, bctx);
 
     bscallback->window = inner_window;
-    if(!inner_window && window)
-        bscallback->window = window->base.inner_window;
 
     /* NOTE: IE7 calls IsSystemMoniker here*/
 
@@ -995,12 +993,7 @@
     }
 
     if(This->window) {
-        list_remove(&This->bsc.entry);
-        list_init(&This->bsc.entry);
-        update_window_doc(This->window);
-        if(This->window->base.inner_window != This->bsc.window)
-            This->bsc.window = This->window->base.inner_window;
-        list_add_head(&This->bsc.window->bindings, &This->bsc.entry);
+        update_window_doc(This->bsc.window);
         if(This->window->readystate != READYSTATE_LOADING)
             set_ready_state(This->window, READYSTATE_LOADING);
     }
@@ -1331,6 +1324,7 @@
 
     IBindStatusCallback_AddRef(&This->bsc.IBindStatusCallback_iface);
     task->bsc = This;
+
     push_task(&task->header, stop_request_proc, stop_request_task_destr, This->window->doc_obj->basedoc.task_magic);
     return S_OK;
 }
@@ -1650,59 +1644,40 @@
     return S_OK;
 }
 
-void set_window_bscallback(HTMLOuterWindow *window, nsChannelBSC *callback)
-{
-    if(window->bscallback) {
-        if(window->bscallback->bsc.binding)
-            IBinding_Abort(window->bscallback->bsc.binding);
-        window->bscallback->bsc.window = NULL;
-        window->bscallback->window = NULL;
-        IBindStatusCallback_Release(&window->bscallback->bsc.IBindStatusCallback_iface);
-    }
-
-    window->bscallback = callback;
-
-    if(callback) {
-        callback->window = window;
-        IBindStatusCallback_AddRef(&callback->bsc.IBindStatusCallback_iface);
-        callback->bsc.window = window->base.inner_window;
-    }
-}
-
 typedef struct {
     task_t header;
     HTMLOuterWindow *window;
-    nsChannelBSC *bscallback;
+    HTMLInnerWindow *pending_window;
 } start_doc_binding_task_t;
 
 static void start_doc_binding_proc(task_t *_task)
 {
     start_doc_binding_task_t *task = (start_doc_binding_task_t*)_task;
 
-    start_binding(task->window, NULL, (BSCallback*)task->bscallback, NULL);
+    start_binding(task->window, task->pending_window, &task->pending_window->bscallback->bsc, NULL);
 }
 
 static void start_doc_binding_task_destr(task_t *_task)
 {
     start_doc_binding_task_t *task = (start_doc_binding_task_t*)_task;
 
-    IBindStatusCallback_Release(&task->bscallback->bsc.IBindStatusCallback_iface);
+    IHTMLWindow2_Release(&task->pending_window->base.IHTMLWindow2_iface);
     heap_free(task);
 }
 
-HRESULT async_start_doc_binding(HTMLOuterWindow *window, nsChannelBSC *bscallback)
+HRESULT async_start_doc_binding(HTMLOuterWindow *window, HTMLInnerWindow *pending_window)
 {
     start_doc_binding_task_t *task;
 
-    TRACE("%p\n", bscallback);
+    TRACE("%p\n", pending_window);
 
     task = heap_alloc(sizeof(start_doc_binding_task_t));
     if(!task)
         return E_OUTOFMEMORY;
 
     task->window = window;
-    task->bscallback = bscallback;
-    IBindStatusCallback_AddRef(&bscallback->bsc.IBindStatusCallback_iface);
+    task->pending_window = pending_window;
+    IHTMLWindow2_AddRef(&pending_window->base.IHTMLWindow2_iface);
 
     push_task(&task->header, start_doc_binding_proc, start_doc_binding_task_destr, window->task_magic);
     return S_OK;
@@ -1710,28 +1685,40 @@
 
 void abort_window_bindings(HTMLInnerWindow *window)
 {
-    BSCallback *iter, *next;
+    BSCallback *iter;
 
-    LIST_FOR_EACH_ENTRY_SAFE(iter, next, &window->bindings, BSCallback, entry) {
+    while(!list_empty(&window->bindings)) {
+        iter = LIST_ENTRY(window->bindings.next, BSCallback, entry);
+
         TRACE("Aborting %p\n", iter);
 
+        IBindStatusCallback_AddRef(&iter->IBindStatusCallback_iface);
+
         if(iter->window && iter->window->doc)
             remove_target_tasks(iter->window->doc->basedoc.task_magic);
 
         if(iter->binding)
             IBinding_Abort(iter->binding);
-        else {
-            list_remove(&iter->entry);
-            list_init(&iter->entry);
+        else
             iter->vtbl->stop_binding(iter, E_ABORT);
-        }
 
         iter->window = NULL;
+        list_remove(&iter->entry);
+        list_init(&iter->entry);
+
+        IBindStatusCallback_Release(&iter->IBindStatusCallback_iface);
+    }
+
+    if(window->bscallback) {
+        window->bscallback->window = NULL;
+        IBindStatusCallback_Release(&window->bscallback->bsc.IBindStatusCallback_iface);
+        window->bscallback = NULL;
     }
 }
 
-HRESULT channelbsc_load_stream(nsChannelBSC *bscallback, IStream *stream)
+HRESULT channelbsc_load_stream(HTMLInnerWindow *pending_window, IStream *stream)
 {
+    nsChannelBSC *bscallback = pending_window->bscallback;
     HRESULT hres = S_OK;
 
     if(!bscallback->nschannel) {
@@ -1743,7 +1730,7 @@
     if(!bscallback->nschannel->content_type)
         return E_OUTOFMEMORY;
 
-    list_add_head(&bscallback->bsc.window->bindings, &bscallback->bsc.entry);
+    bscallback->bsc.window = pending_window;
     if(stream)
         hres = read_stream_data(bscallback, stream);
     if(SUCCEEDED(hres))
@@ -1839,14 +1826,14 @@
 
     hres = set_moniker(&task->window->doc_obj->basedoc, task->mon, NULL, task->bscallback, TRUE);
     if(SUCCEEDED(hres))
-        start_binding(task->window, NULL, (BSCallback*)task->bscallback, NULL);
+        start_binding(task->window, task->window->pending_window, &task->bscallback->bsc, NULL);
 }
 
 static void navigate_task_destr(task_t *_task)
 {
     navigate_task_t *task = (navigate_task_t*)_task;
 
-    IUnknown_Release((IUnknown*)task->bscallback);
+    IBindStatusCallback_Release(&task->bscallback->bsc.IBindStatusCallback_iface);
     IMoniker_Release(task->mon);
     heap_free(task);
 }
@@ -1946,7 +1933,7 @@
 
         task = heap_alloc(sizeof(*task));
         if(!task) {
-            IUnknown_Release((IUnknown*)bsc);
+            IBindStatusCallback_Release(&bsc->bsc.IBindStatusCallback_iface);
             IMoniker_Release(mon);
             return E_OUTOFMEMORY;
         }
@@ -1963,7 +1950,7 @@
     }else {
         navigate_javascript_task_t *task;
 
-        IUnknown_Release((IUnknown*)bsc);
+        IBindStatusCallback_Release(&bsc->bsc.IBindStatusCallback_iface);
         IMoniker_Release(mon);
 
         task = heap_alloc(sizeof(*task));
diff --git a/dlls/mshtml/nsio.c b/dlls/mshtml/nsio.c
index e177390..0a8a124 100644
--- a/dlls/mshtml/nsio.c
+++ b/dlls/mshtml/nsio.c
@@ -1016,9 +1016,12 @@
     channelbsc_set_channel(bscallback, This, listener, context);
 
     if(is_doc_channel) {
-        set_window_bscallback(window, bscallback);
-        async_start_doc_binding(window, bscallback);
+        hres = create_pending_window(window, bscallback);
+        if(SUCCEEDED(hres))
+            async_start_doc_binding(window, window->pending_window);
         IUnknown_Release((IUnknown*)bscallback);
+        if(FAILED(hres))
+            return NS_ERROR_UNEXPECTED;
     }else {
         start_binding_task_t *task = heap_alloc(sizeof(start_binding_task_t));
 
diff --git a/dlls/mshtml/persist.c b/dlls/mshtml/persist.c
index cb148c4..6f62c1b 100644
--- a/dlls/mshtml/persist.c
+++ b/dlls/mshtml/persist.c
@@ -370,9 +370,9 @@
         hres = load_nsuri(This->window, nsuri, bscallback, 0/*LOAD_INITIAL_DOCUMENT_URI*/);
         nsISupports_Release((nsISupports*)nsuri); /* FIXME */
         if(SUCCEEDED(hres))
-            set_window_bscallback(This->window, bscallback);
+            hres = create_pending_window(This->window, bscallback);
         if(bscallback != async_bsc)
-            IUnknown_Release((IUnknown*)bscallback);
+            IUnknown_Release(&bscallback->bsc.IBindStatusCallback_iface);
     }
 
     if(FAILED(hres)) {
@@ -538,7 +538,7 @@
     if(FAILED(hres))
         return hres;
 
-    return start_binding(This->window, NULL, (BSCallback*)This->window->bscallback, pibc);
+    return start_binding(This->window, This->window->pending_window, (BSCallback*)This->window->pending_window->bscallback, pibc);
 }
 
 static HRESULT WINAPI PersistMoniker_Save(IPersistMoniker *iface, IMoniker *pimkName,
@@ -810,7 +810,7 @@
     if(FAILED(hres))
         return hres;
 
-    return channelbsc_load_stream(This->window->bscallback, pStm);
+    return channelbsc_load_stream(This->window->pending_window, pStm);
 }
 
 static HRESULT WINAPI PersistStreamInit_Save(IPersistStreamInit *iface, LPSTREAM pStm,
@@ -869,7 +869,7 @@
     if(FAILED(hres))
         return hres;
 
-    return channelbsc_load_stream(This->window->bscallback, NULL);
+    return channelbsc_load_stream(This->window->pending_window, NULL);
 }
 
 static const IPersistStreamInitVtbl PersistStreamInitVtbl = {