예제 #1
0
        /// <summary> Called by the browser to serialize the entire journal or just the index of
        /// the current entry. The second case is when an internal Journal update needs to be
        /// reflected in the TravelLog.
        /// </summary>
        /// <param name="arg"> true is the entire Journal is to serialized </param>
        private object _GetSaveHistoryBytesDelegate(object arg)
        {
            bool entireJournal = (bool)arg;

            SaveHistoryReturnInfo info = new SaveHistoryReturnInfo();

            // DevDiv 716414 / DevDiv2 196517 & 224724:
            // Checking _serviceProvider for null due to COM reentrancy issues observed by customers.
            // Users who perform frequent refreshes may experience shutdown while we are still starting up and are not fully initialized.
            // The ServiceProvider field is one of the last things to be set during initialization, so if this is null
            // we know that we have not finished initialization much less run the app and thus have no need to save history.
            if (_serviceProvider == null)
            {
                return(null);
            }

            // When we are here, the browser has just started to shut down, so we should only check
            // whether the application object is shutting down.
            if (Application.IsApplicationObjectShuttingDown == true)
            {
                return(null);
            }

            Invariant.Assert(_rbw.Value != null, "BrowserJournalingError: _rbw should not be null");

            Journal journal = _rbw.Value.Journal;

            Invariant.Assert(journal != null, "BrowserJournalingError: Could not get internal journal for the window");

            JournalEntry entry;

            if (entireJournal) // The application is about to be shut down...
            {
                NavigationService topNavSvc = _rbw.Value.NavigationService;
                try
                {
                    topNavSvc.RequestCustomContentStateOnAppShutdown();
                }
                catch (Exception e)
                {
                    if (CriticalExceptions.IsCriticalException(e))
                    {
                        throw;
                    }
                }

                journal.PruneKeepAliveEntries();

                // Since the current page is not added to the journal until it is replaced,
                // we add it here explicitly to the internal Journal before serializing it.
                entry = topNavSvc.MakeJournalEntry(JournalReason.NewContentNavigation);
                if (entry != null && !entry.IsAlive())
                {
                    if (entry.JEGroupState.JournalDataStreams != null)
                    {
                        entry.JEGroupState.JournalDataStreams.PrepareForSerialization();
                    }
                    journal.UpdateCurrentEntry(entry);
                }
                else // Maybe the current content is null or a PageFunction doesn't want to be journaled.
                {   // Then the previous navigable page, if any, should be remembered as current.
                    entry = journal.GetGoBackEntry();
                    // i. _LoadHistoryStreamDelegate() has a similar special case.
                }
            }
            else
            {   // (Brittle) Assumption: GetSaveHistoryBytes() is called after the current entry has
                // been updated in the internal journal but before the new navigation is committed.
                // This means journal.CurrentEntry is what was just added (or updated).
                // Note that it would be wrong to call topNavSvc.MakeJournalEntry() in this case because
                // the navigation that just took place may be in a different NavigationService (in a
                // frame), and here we don't know which one it is.
                entry = journal.CurrentEntry;

                // The entry may be null here when the user has selected "New Window" or pressed Ctrl+N.
                // In this case the browser calls us on IPersistHistory::Save and then throws that data
                // away.  Hopefully at some point in the future that saved data will be loaded in the new
                // window via IPersistHistory::Load.  This unusual behavior is tracked in bug 1353584.
            }

            if (entry != null)
            {
                info.title   = entry.Name;
                info.entryId = entry.Id;
            }
            else
            {
                info.title = _rbw.Value.Title;
            }

            // We only use the base URI here because the travel log will validate a file URI when making a PIDL.
            // We use the URI stored in the JournalEntry, and the travel log doesn't care what the URI is, so
            // duplicates don't matter.
            info.uri = BindUriHelper.UriToString(Uri);

            MemoryStream saveStream = new MemoryStream();

            saveStream.Seek(0, SeekOrigin.Begin);

            if (entireJournal)
            {
                //Save the Journal and BaseUri also. We don't need BaseUri except for the xaml case
                //since this is set specially for the container case (ssres scheme). Exe case
                //will pretty much set it to the exe path. For the xaml case it is set to the path
                //of the first uri(eg BaseDir\page1.xaml) that was navigated to.
                //BaseDir/Subdir/page2.xaml is also considered to be in the same extent and when
                //we navigate back to the app from a webpage, the baseUri should still be BaseDir
                //not BaseDir/Subdir. We were setting the BaseDir from JournalEntry.Uri but we may
                //end up setting BaseUri to BaseDir/Subdir which is not the same. So explicitly
                //persist BaseUri as well
                BrowserJournal browserJournal = new BrowserJournal(journal, BindUriHelper.BaseUri);

                new SecurityPermission(SecurityPermissionFlag.SerializationFormatter).Assert();
                try
                {
                    saveStream.WriteByte(BrowserJournalHeader);
                    BinaryFormatter formatter = new BinaryFormatter();
                    formatter.Serialize(saveStream, browserJournal);
                }
                catch (Exception e)
                {
                    if (CriticalExceptions.IsCriticalException(e))
                    {
                        throw;
                    }

                    // The application is shutting down and the exception would not be reported anyway.
                    // This is here to help with debugging and failure analysis.
                    Invariant.Assert(false, "Failed to serialize the navigation journal: " + e);
                }
                finally
                {
                    CodeAccessPermission.RevertAll();
                }
            }
            else
            {
                saveStream.WriteByte(JournalIdHeader);
                WriteInt32(saveStream, info.entryId);
            }

            info.saveByteArray = saveStream.ToArray();
            ((IDisposable)saveStream).Dispose();

            return(info);
        }
예제 #2
0
        private object _LoadHistoryStreamDelegate(object arg)
        {
            Journal      journal = null;
            JournalEntry entry   = null;

            LoadHistoryStreamInfo info = (LoadHistoryStreamInfo)arg;

            if (IsShutdown() == true)
            {
                return(null);
            }

            // Reset the memory stream pointer back to the begining and get the persisted object
            info.loadStream.Seek(0, System.IO.SeekOrigin.Begin);

            object journaledObject = DeserializeJournaledObject(info.loadStream);

            //This is the very first load from history, so need to set the BaseUri and StartupUri.
            if (info.firstLoadFromHistory)
            {
                // The journal does not get saved on Ctrl+N. Because of this,
                // here we can get just an index, like in the 'else' case below.
                if (!(journaledObject is BrowserJournal))
                {
                    return(null);
                }

                BrowserJournal browserJournal = (BrowserJournal)journaledObject;

                journal = browserJournal.Journal;
                entry   = journal.CurrentEntry;
                if (entry == null)                    // See special case in _GetSaveHistoryBytesDelegate().
                {
                    entry = journal.GetGoBackEntry(); // could still be null
                }

                //This will create the frame to use for hosting
                {
                    NavigationService navigationService = null;
                    navigationService = _rbw.Value.NavigationService;
                }
                _rbw.Value.SetJournalForBrowserInterop(journal);

                //This should already be set for the container and exe cases. The former
                //sets it to the transformed ssres scheme and we don't want to overwrite it.
                if (BindUriHelper.BaseUri == null)
                {
                    BindUriHelper.BaseUri = browserJournal.BaseUri;
                }

                //CHECK: For xaml case, what should we set as the Startup Uri ? We set it the initial
                //uri we started with, should this be changed to creating the window explicitly
                //and navigating the window instead of setting the StartupUri?
                //(Application.Current as Application).StartupUri = entry.Uri;

                Debug.Assert(Application.Current != null, "BrowserJournalingError: Application object should already be created");

                if (entry != null)
                {
                    //Prevent navigations to StartupUri for history loads by canceling the StartingUp event
                    Application.Current.Startup += new System.Windows.StartupEventHandler(this.OnStartup);

                    _rbw.Value.JournalNavigationScope.NavigateToEntry(entry);
                }
                //else: fall back on navigating to StartupUri
            }
            else
            {
                if (!(journaledObject is int))
                {
                    return(null);
                }

                journal = _rbw.Value.Journal;

                int index = journal.FindIndexForEntryWithId((int)journaledObject);

                Debug.Assert(journal[index].Id == (int)journaledObject, "BrowserJournalingError: Index retrieved from journal stream does not match index of journal entry");

                // Check whether the navigation is canceled.
                if (!_rbw.Value.JournalNavigationScope.NavigateToEntry(index))
                {
                    // When the navigation is canceled, we want to notify browser to prevent the internal journal from
                    // getting out of sync with the browser's.
                    // The exception will be caught by the interop layer and browser will cancel the navigation as a result.

                    // If the navigation is initiated pragmatically by calling GoBack/Forward (comparing to user initiated
                    // by clicking the back/forward button),  this will result in a managed exception at the call to ibcs.GoBack()
                    // in rbw.GoBackOverride(). rbw catches the exception when this happens.

                    throw new OperationCanceledException();
                }
            }

            return(null);
        }
        private object _GetSaveHistoryBytesDelegate(object arg) 
        {
            bool entireJournal = (bool)arg;

            SaveHistoryReturnInfo info = new SaveHistoryReturnInfo(); 

            // When we are here, the browser has just started to shut down, so we should only check 
            // whether the application object is shutting down. 
            if (Application.IsApplicationObjectShuttingDown == true)
                return null; 

            Invariant.Assert(_rbw.Value != null, "BrowserJournalingError: _rbw should not be null");

            Journal journal = _rbw.Value.Journal; 
            Invariant.Assert(journal != null, "BrowserJournalingError: Could not get internal journal for the window");
 
            JournalEntry entry; 
            if (entireJournal) // The application is about to be shut down...
            { 
                NavigationService topNavSvc = _rbw.Value.NavigationService;
                try
                {
                    topNavSvc.RequestCustomContentStateOnAppShutdown(); 
                }
                catch(Exception e) 
                { 
                    if(CriticalExceptions.IsCriticalException(e))
                    { 
                        throw;
                    }
                }
 
                journal.PruneKeepAliveEntries();
 
                // Since the current page is not added to the journal until it is replaced, 
                // we add it here explicitly to the internal Journal before serializing it.
                entry = topNavSvc.MakeJournalEntry(JournalReason.NewContentNavigation); 
                if (entry != null && !entry.IsAlive())
                {
                    if (entry.JEGroupState.JournalDataStreams != null)
                    { 
                        entry.JEGroupState.JournalDataStreams.PrepareForSerialization();
                    } 
                    journal.UpdateCurrentEntry(entry); 
                }
                else // Maybe the current content is null or a PageFunction doesn't want to be journaled. 
                {   // Then the previous navigable page, if any, should be remembered as current.
                    entry = journal.GetGoBackEntry();
                    // i. _LoadHistoryStreamDelegate() has a similar special case.
                } 
            }
            else 
            {   // (Brittle) Assumption: GetSaveHistoryBytes() is called after the current entry has 
                // been updated in the internal journal but before the new navigation is committed.
                // This means journal.CurrentEntry is what was just added (or updated). 
                // Note that it would be wrong to call topNavSvc.MakeJournalEntry() in this case because
                // the navigation that just took place may be in a different NavigationService (in a
                // frame), and here we don't know which one it is.
                entry = journal.CurrentEntry; 

                // The entry may be null here when the user has selected "New Window" or pressed Ctrl+N. 
                // In this case the browser calls us on IPersistHistory::Save and then throws that data 
                // away.  Hopefully at some point in the future that saved data will be loaded in the new
                // window via IPersistHistory::Load.  This unusual behavior is tracked in bug 1353584. 
            }

            if (entry != null)
            { 
                info.title = entry.Name;
                info.entryId = entry.Id; 
            } 
            else
            { 
                info.title = _rbw.Value.Title;
            }

            // We only use the base URI here because the travel log will validate a file URI when making a PIDL. 
            // We use the URI stored in the JournalEntry, and the travel log doesn't care what the URI is, so
            // duplicates don't matter. 
            info.uri = BindUriHelper.UriToString(Uri); 

            MemoryStream saveStream = new MemoryStream(); 
            BinaryFormatter formatter = new BinaryFormatter();

            saveStream.Seek(0, SeekOrigin.Begin);
            object objectToSave = info.entryId; 

            if (entireJournal) 
            { 
                //Save the Journal and BaseUri also. We don't need BaseUri except for the xaml case
                //since this is set specially for the container case (ssres scheme). Exe case 
                //will pretty much set it to the exe path. For the xaml case it is set to the path
                //of the first uri(eg BaseDir\page1.xaml) that was navigated to.
                //BaseDir/Subdir/page2.xaml is also considered to be in the same extent and when
                //we navigate back to the app from a webpage, the baseUri should still be BaseDir 
                //not BaseDir/Subdir. We were setting the BaseDir from JournalEntry.Uri but we may
                //end up setting BaseUri to BaseDir/Subdir which is not the same. So explicitly 
                //persist BaseUri as well 
                BrowserJournal browserJournal = new BrowserJournal(journal, BindUriHelper.BaseUri);
                objectToSave = browserJournal; 
            }

            new SecurityPermission(SecurityPermissionFlag.SerializationFormatter).Assert();
            try 
            {
                formatter.Serialize(saveStream, objectToSave); 
            } 
            catch(Exception e)
            { 
                if(CriticalExceptions.IsCriticalException(e))
                {
                    throw;
                } 

                // The application is shutting down and the exception would not be reported anyway. 
                // This is here to help with debugging and failure analysis. 
                Invariant.Assert(false, "Failed to serialize the navigation journal: " + e);
            } 
            finally
            {
                CodeAccessPermission.RevertAll() ;
            } 

            info.saveByteArray = saveStream.ToArray(); 
            ((IDisposable)saveStream).Dispose(); 

            return info ; 
        }