mshtml: Create inner window early in binding process and use it to store current...
[wine] / dlls / mshtml / persist.c
index a299be2..6f62c1b 100644 (file)
 #include "shlguid.h"
 #include "idispids.h"
 
+#define NO_SHLWAPI_REG
+#include "shlwapi.h"
+
 #include "wine/debug.h"
-#include "wine/unicode.h"
 
 #include "mshtml_private.h"
 #include "htmlevent.h"
@@ -42,6 +44,9 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
 
+/* Undocumented notification, see tests */
+#define CMDID_EXPLORER_UPDATEHISTORY 38
+
 typedef struct {
     task_t header;
     HTMLDocumentObj *doc;
@@ -49,13 +54,11 @@ typedef struct {
     LPOLESTR url;
 } download_proc_task_t;
 
-static BOOL use_gecko_script(HTMLWindow *window)
+static BOOL use_gecko_script(HTMLOuterWindow *window)
 {
     DWORD zone;
     HRESULT hres;
 
-    static const WCHAR aboutW[] = {'a','b','o','u','t',':'};
-
     hres = IInternetSecurityManager_MapUrlToZone(window->secmgr, window->url, &zone, 0);
     if(FAILED(hres)) {
         WARN("Could not map %s to zone: %08x\n", debugstr_w(window->url), hres);
@@ -63,37 +66,118 @@ static BOOL use_gecko_script(HTMLWindow *window)
     }
 
     TRACE("zone %d\n", zone);
-    return zone != URLZONE_LOCAL_MACHINE && zone != URLZONE_TRUSTED
-        && strncmpiW(aboutW, window->url, sizeof(aboutW)/sizeof(WCHAR));
+    return zone == URLZONE_UNTRUSTED;
 }
 
-void set_current_mon(HTMLWindow *This, IMoniker *mon)
+static void notify_travellog_update(HTMLDocumentObj *doc)
 {
+    IOleCommandTarget *cmdtrg;
+    HRESULT hres;
+
+    if(!doc->is_webbrowser)
+        return;
+
+    /* Don't notify if we were in about: page */
+    if(doc->basedoc.window->uri) {
+        DWORD scheme;
+
+        hres = IUri_GetScheme(doc->basedoc.window->uri, &scheme);
+        if(SUCCEEDED(hres) && scheme == URL_SCHEME_ABOUT)
+            return;
+    }
+
+    hres = IOleClientSite_QueryInterface(doc->client, &IID_IOleCommandTarget, (void**)&cmdtrg);
+    if(SUCCEEDED(hres)) {
+        VARIANT vin;
+
+        V_VT(&vin) = VT_I4;
+        V_I4(&vin) = 0;
+
+        IOleCommandTarget_Exec(cmdtrg, &CGID_Explorer, CMDID_EXPLORER_UPDATEHISTORY, 0, &vin, NULL);
+        IOleCommandTarget_Release(cmdtrg);
+    }
+}
+
+void set_current_uri(HTMLOuterWindow *window, IUri *uri)
+{
+    if(window->uri) {
+        IUri_Release(window->uri);
+        window->uri = NULL;
+    }
+
+    SysFreeString(window->url);
+    window->url = NULL;
+
+    if(!uri)
+        return;
+
+    IUri_AddRef(uri);
+    window->uri = uri;
+
+    IUri_GetDisplayUri(uri, &window->url);
+}
+
+void set_current_mon(HTMLOuterWindow *This, IMoniker *mon)
+{
+    IUriContainer *uri_container;
+    IUri *uri = NULL;
     HRESULT hres;
 
     if(This->mon) {
+        if(This->doc_obj)
+            notify_travellog_update(This->doc_obj);
         IMoniker_Release(This->mon);
         This->mon = NULL;
     }
 
-    if(This->url) {
-        CoTaskMemFree(This->url);
-        This->url = NULL;
-    }
-
     if(!mon)
         return;
 
     IMoniker_AddRef(mon);
     This->mon = mon;
 
-    hres = IMoniker_GetDisplayName(mon, NULL, NULL, &This->url);
-    if(FAILED(hres))
-        WARN("GetDisplayName failed: %08x\n", hres);
+    hres = IMoniker_QueryInterface(mon, &IID_IUriContainer, (void**)&uri_container);
+    if(SUCCEEDED(hres)) {
+        hres = IUriContainer_GetIUri(uri_container, &uri);
+        IUriContainer_Release(uri_container);
+        if(hres != S_OK) {
+            WARN("GetIUri failed: %08x\n", hres);
+            uri = NULL;
+        }
+    }
+
+    if(!uri) {
+        WCHAR *url;
+
+        hres = IMoniker_GetDisplayName(mon, NULL, NULL, &url);
+        if(SUCCEEDED(hres)) {
+            hres = CreateUri(url, 0, 0, &uri);
+            if(FAILED(hres)) {
+                WARN("CrateUri failed: %08x\n", hres);
+                set_current_uri(This, NULL);
+                This->url = SysAllocString(url);
+                CoTaskMemFree(url);
+                return;
+            }
+            CoTaskMemFree(url);
+        }else {
+            WARN("GetDisplayName failed: %08x\n", hres);
+        }
+    }
 
+    set_current_uri(This, uri);
+    if(uri)
+        IUri_Release(uri);
     set_script_mode(This, use_gecko_script(This) ? SCRIPTMODE_GECKO : SCRIPTMODE_ACTIVESCRIPT);
 }
 
+HRESULT create_relative_uri(HTMLOuterWindow *window, const WCHAR *rel_uri, IUri **uri)
+{
+    return window->uri
+        ? CoInternetCombineUrlEx(window->uri, rel_uri, URL_ESCAPE_SPACES_ONLY|URL_DONT_ESCAPE_EXTRA_INFO, uri, 0)
+        : CreateUri(rel_uri, 0, 0, uri);
+}
+
 void set_download_state(HTMLDocumentObj *doc, int state)
 {
     if(doc->client) {
@@ -180,7 +264,7 @@ static void set_downloading_proc(task_t *_task)
         IDropTarget *drop_target = NULL;
 
         hres = IDocHostUIHandler_GetDropTarget(doc->hostui, NULL /* FIXME */, &drop_target);
-        if(drop_target) {
+        if(SUCCEEDED(hres) && drop_target) {
             FIXME("Use IDropTarget\n");
             IDropTarget_Release(drop_target);
         }
@@ -195,7 +279,7 @@ static void set_downloading_task_destr(task_t *_task)
     heap_free(task);
 }
 
-void prepare_for_binding(HTMLDocument *This, IMoniker *mon, IBindCtx *pibc, BOOL navigated_binding)
+void prepare_for_binding(HTMLDocument *This, IMoniker *mon, BOOL navigated_binding)
 {
     HRESULT hres;
 
@@ -205,7 +289,7 @@ void prepare_for_binding(HTMLDocument *This, IMoniker *mon, IBindCtx *pibc, BOOL
         hres = get_client_disp_property(This->doc_obj->client, DISPID_AMBIENT_SILENT, &silent);
         if(SUCCEEDED(hres)) {
             if(V_VT(&silent) != VT_BOOL)
-                WARN("V_VT(silent) = %d\n", V_VT(&silent));
+                WARN("silent = %s\n", debugstr_variant(&silent));
             else if(V_BOOL(&silent))
                 FIXME("silent == true\n");
         }
@@ -214,7 +298,7 @@ void prepare_for_binding(HTMLDocument *This, IMoniker *mon, IBindCtx *pibc, BOOL
                 DISPID_AMBIENT_OFFLINEIFNOTCONNECTED, &offline);
         if(SUCCEEDED(hres)) {
             if(V_VT(&offline) != VT_BOOL)
-                WARN("V_VT(offline) = %d\n", V_VT(&offline));
+                WARN("offline = %s\n", debugstr_variant(&offline));
             else if(V_BOOL(&offline))
                 FIXME("offline == true\n");
         }
@@ -241,7 +325,7 @@ void prepare_for_binding(HTMLDocument *This, IMoniker *mon, IBindCtx *pibc, BOOL
                 IOleCommandTarget_Exec(cmdtrg, &CGID_ShellDocView, 37, 0, &var, NULL);
             }else {
                 V_VT(&var) = VT_UNKNOWN;
-                V_UNKNOWN(&var) = (IUnknown*)&This->window->IHTMLWindow2_iface;
+                V_UNKNOWN(&var) = (IUnknown*)&This->window->base.IHTMLWindow2_iface;
                 V_VT(&out) = VT_EMPTY;
                 hres = IOleCommandTarget_Exec(cmdtrg, &CGID_ShellDocView, 63, 0, &var, &out);
                 if(SUCCEEDED(hres))
@@ -281,14 +365,14 @@ HRESULT set_moniker(HTMLDocument *This, IMoniker *mon, IBindCtx *pibc, nsChannel
 
     if(SUCCEEDED(hres)) {
         remove_target_tasks(This->task_magic);
-        abort_document_bindings(This->doc_node);
+        abort_window_bindings(This->window->base.inner_window);
 
         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)) {
@@ -315,14 +399,14 @@ HRESULT set_moniker(HTMLDocument *This, IMoniker *mon, IBindCtx *pibc, nsChannel
     return S_OK;
 }
 
-void set_ready_state(HTMLWindow *window, READYSTATE readystate)
+void set_ready_state(HTMLOuterWindow *window, READYSTATE readystate)
 {
     window->readystate = readystate;
 
     if(window->doc_obj && window->doc_obj->basedoc.window == window)
         call_property_onchanged(&window->doc_obj->basedoc.cp_propnotif, DISPID_READYSTATE);
 
-    fire_event(window->doc, EVENTID_READYSTATECHANGE, FALSE, window->doc->node.nsnode, NULL);
+    fire_event(window->base.inner_window->doc, EVENTID_READYSTATECHANGE, FALSE, window->base.inner_window->doc->node.nsnode, NULL);
 
     if(window->frame_element)
         fire_event(window->frame_element->element.node.doc, EVENTID_READYSTATECHANGE,
@@ -335,6 +419,7 @@ static HRESULT get_doc_string(HTMLDocumentNode *This, char **str)
     LPCWSTR strw;
     nsAString nsstr;
     nsresult nsres;
+    HRESULT hres;
 
     if(!This->nsdoc) {
         WARN("NULL nsdoc\n");
@@ -348,8 +433,12 @@ static HRESULT get_doc_string(HTMLDocumentNode *This, char **str)
     }
 
     nsAString_Init(&nsstr, NULL);
-    nsnode_to_nsstring(nsnode, &nsstr);
+    hres = nsnode_to_nsstring(nsnode, &nsstr);
     nsIDOMNode_Release(nsnode);
+    if(FAILED(hres)) {
+        nsAString_Finish(&nsstr);
+        return hres;
+    }
 
     nsAString_GetData(&nsstr, &strw);
     TRACE("%s\n", debugstr_w(strw));
@@ -358,6 +447,8 @@ static HRESULT get_doc_string(HTMLDocumentNode *This, char **str)
 
     nsAString_Finish(&nsstr);
 
+    if(!*str)
+        return E_OUTOFMEMORY;
     return S_OK;
 }
 
@@ -441,12 +532,13 @@ static HRESULT WINAPI PersistMoniker_Load(IPersistMoniker *iface, BOOL fFullyAva
         }
     }
 
-    prepare_for_binding(This, pimkName, pibc, FALSE);
+    prepare_for_binding(This, pimkName, FALSE);
+    call_docview_84(This->doc_obj);
     hres = set_moniker(This, pimkName, pibc, NULL, TRUE);
     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,
@@ -712,13 +804,13 @@ static HRESULT WINAPI PersistStreamInit_Load(IPersistStreamInit *iface, LPSTREAM
         return hres;
     }
 
-    prepare_for_binding(This, mon, NULL, FALSE);
+    prepare_for_binding(This, mon, FALSE);
     hres = set_moniker(This, mon, NULL, NULL, TRUE);
     IMoniker_Release(mon);
     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,
@@ -771,13 +863,13 @@ static HRESULT WINAPI PersistStreamInit_InitNew(IPersistStreamInit *iface)
         return hres;
     }
 
-    prepare_for_binding(This, mon, NULL, FALSE);
+    prepare_for_binding(This, mon, FALSE);
     hres = set_moniker(This, mon, NULL, NULL, FALSE);
     IMoniker_Release(mon);
     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 = {