File: src\Framework\MS\Internal\AppModel\ApplicationProxyInternal.cs
Project: wpf\PresentationFramework.csproj (PresentationFramework)
//------------------------------------------------------------------------------
//
// <copyright file="NavAppProxyInternal.cs" company="Microsoft">
//    Copyright (C) Microsoft Corporation.  All rights reserved.
// </copyright>
//
// Description: This is an internal proxy wrapper class over Application class.
//              This derives from MarshalByRefObject and thus facilitates calling
//              the AppCode from DocobjHost that may be running in a different
//              AppDomain.  The other thing it allows is to be able to create
//              the App Object on the right thread by exposing a delegate that
//              could be set to point to the code that creates the AppObject and
//              invoking the delegate from the right thread.
//
// History:
//  07/03/2003 Microsoft  Created
//  10/04/2005 FrankGor Documented & refactored class; primary reason was ensure
//                      disposal of all XpsViewer (DocumentApplication)
//                      resources
//------------------------------------------------------------------------------
 
//**
//** IMPORTANT: Running arbitrary application code in the context of an incoming call from the browser
//**    should be avoided. This could lead to unexpected reentrancy (on either side) or making the
//      browser frame unresponsive while the application code is running. Bug 1139336 illustrates
//      what can happen if the application code enters a local message loop while the browser is
//      blocked. To avoid such situations in general, use Dispatcher.BeginInvoke() instead of making
//      direct calls into unknown code.
 
 
using System;
using System.Diagnostics;
using System.IO;
using System.IO.Packaging;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Security;
using System.Security.Permissions;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Navigation;
using System.Windows.Threading;
 
using MS.Internal;
using MS.Internal.Documents;
using MS.Internal.Documents.Application;
using MS.Internal.IO.Packaging;
using MS.Internal.IO.Packaging.CompoundFile;
using MS.Internal.PresentationFramework;
using MS.Internal.Utility;
using MS.Internal.AppModel;
using MS.Utility;
 
//In order to avoid generating warnings about unknown message numbers and
//unknown pragmas when compiling your C# source code with the actual C# compiler,
//you need to disable warnings 1634 and 1691. (Presharp Documentation)
#pragma warning disable 1634, 1691
 
namespace MS.Internal.AppModel
{
    // All security sensitive classes should be sealed or protected with InheritanceDemand
    internal sealed class ApplicationProxyInternal : MarshalByRefObject
    {
        [Serializable]
        internal class InitData
        {
            internal IServiceProvider ServiceProvider;
            
            /// <SecurityNote>
            /// Critical : Field for critical type IHostBrowser
            /// </SecurityNote>
            [SecurityCritical]
            internal IHostBrowser HostBrowser;
            internal SecurityCriticalDataForSet<MimeType> MimeType;
            internal SecurityCriticalDataForSet<Uri> ActivationUri;
            internal string Fragment;
            internal object UcomLoadIStream;
            internal bool HandleHistoryLoad;
            internal string UserAgentString;
            internal HostingFlags HostingFlags;
            internal Rect WindowRect;
            internal bool ShowWindow;
        };
 
        //------------------------------------------------------
        //
        //  Constructors
        //
        //------------------------------------------------------
        #region Constructors
 
        /// <summary>
        /// ApplicationProxyInternal is created only for browser-hosted applications.
        /// </summary>
        /// <SecurityNote>
        /// Critical:
        ///     1) We want to track creation of ApplicationProxyInternal because it can be used to
        ///        make calls between AppDomains (it's MarshalByRefObject).
        ///     2) It sets BrowserInteropHelper.IsBrowserHosted, which is critical for set.
        /// </SecurityNote>
        [SecurityCritical]
        internal ApplicationProxyInternal()
        {
            EventTrace.EasyTraceEvent(EventTrace.Keyword.KeywordHosting | EventTrace.Keyword.KeywordPerf, EventTrace.Level.Verbose, EventTrace.Event.WpfHost_AppProxyCtor);
 
            if (_proxyInstance != null)
            {
                throw new InvalidOperationException(SR.Get(SRID.MultiSingleton, this.GetType().FullName));
            }
            // Set this here so it will be true for documents or applications (i.e. anything in the browser.)
            BrowserInteropHelper.SetBrowserHosted(true);
            _proxyInstance = this;
        }
 
        #endregion Constructors
 
        //------------------------------------------------------
        //
        //  Internal Methods
        //
        //------------------------------------------------------
        #region Internal Methods
 
        public override object InitializeLifetimeService()
        {
            //Keeps it alive until the AppDomain is teared down which is what we want.
            //Otherwise the .Net remoting infrastructure releases all remote objects in 5 mins
            //if there are no sponsors registered with the lease manager for the remote object.
            //This is an alternative to the client side registering a sponsor by the server object
            //marking itself to be kept alive for the life of the AppDomain.
            return null;
        }
 
        //Creates the internal RootBrowserWindow. If the startup Uri points
        //to a Window/NavigationWindow, we still need to create this empty
        //RootBrowserWindow so we can repaint properly inside the browser window
 
        ///<SecurityNote>
        ///  Critical as this code invokes a delegate that accesses critical data.
        ///  TreatAsSafe - creating the browser window for your content to be hosted in is considered safe.
        ///                       this is considered safe - as you can only control the internal window of the browser.
        ///                       you cannot change styles of the actual browser window ( verified this).
        ///                       Dangerous behaviors ( e.g. ShowInTaskbar = false) don't work when in browser hosted.
        ///
        ///</SecurityNote>
        [SecurityCritical, SecurityTreatAsSafe ]
        internal void CreateRootBrowserWindow()
        {
            if (_rbw.Value == null)
            {
 
                Application.Current.Dispatcher.Invoke(
                                    DispatcherPriority.Send,
                                    new DispatcherOperationCallback(_CreateRootBrowserWindowCallback),
                                    null);
            }
        }
 
        internal bool FocusedElementWantsBackspace()
        {
            TextBoxBase textBoxBase = Keyboard.FocusedElement as TextBoxBase;
            if (textBoxBase != null)
            {
                return true; // textBoxBase.IsEmpty
            }
 
            PasswordBox passwordBox = Keyboard.FocusedElement as PasswordBox;
            if (passwordBox != null)
            {
                return true; // passwordBox.IsEmpty
            }
 
            return false;
        }
 
        ///<SecurityNote>
        ///  Critical as this code calls the critical RootBrowserWindow.CreateAndInitialize()
        ///</SecurityNote>
        [SecurityCritical]
        private object _CreateRootBrowserWindowCallback(object unused)
        {
            EventTrace.EasyTraceEvent(EventTrace.Keyword.KeywordHosting | EventTrace.Keyword.KeywordPerf, EventTrace.Event.WpfHost_RootBrowserWindowSetupStart);
 
            RootBrowserWindow = RootBrowserWindow.CreateAndInitialize();
 
            EventTrace.EasyTraceEvent(EventTrace.Keyword.KeywordHosting | EventTrace.Keyword.KeywordPerf, EventTrace.Event.WpfHost_RootBrowserWindowSetupEnd);
 
            return null ;
        }
 
        // Calls the Run method on the app object.
        ///<SecurityNote>
        /// Critical - creates a critical delegate, provides the path to LoadFromContainer, which
        ///            is critical, and also calls InitContainer which is critical.  Accesses
        ///            several critical data values (_path, _container, _storageRoot).
        ///          - also sets Uri and _mimeType, which are critical.
        ///</SecurityNote>
        [SecurityCritical]
        internal int Run(InitData initData)
        {
            EventTrace.EasyTraceEvent(EventTrace.Keyword.KeywordHosting | EventTrace.Keyword.KeywordPerf, EventTrace.Level.Verbose, EventTrace.Event.WpfHost_AppProxyRunStart);
 
            // Keep in mind that Run() is called once in the default AppDomain and then in the XBAP's domain.
            // We want initialization of statics to happen in both AppDomains.
 
            if (!AppDomain.CurrentDomain.IsDefaultAppDomain())
            {
                // Since IHostBrowser was marshaled from the default AppDomain as a managed interface, we get
                // a Remoting transparent proxy here. Any calls on the interface would have to first be marshaled
                // to the default AppDomain, where the CLR will realize it's actually a COM interface. This is 
                // wasteful since the object lives in the browser process. So, to shake off the Remoting layer,
                // we round-trip the IHostBrowser reference through IUknown/IntPtr.
                IntPtr pObj = Marshal.GetIUnknownForObject(initData.HostBrowser);
                try { initData.HostBrowser = (IHostBrowser)Marshal.GetObjectForIUnknown(pObj); }
                finally { Marshal.Release(pObj); }
            }
            BrowserInteropHelper.HostBrowser = initData.HostBrowser;
 
            MimeType mimeType = initData.MimeType.Value;
            _mimeType.Value = mimeType;
            Uri = initData.ActivationUri.Value;
            WpfWebRequestHelper.DefaultUserAgent = initData.UserAgentString;
            BrowserInteropHelper.HostingFlags = initData.HostingFlags;
 
            // These methods are asynchronous.
            // If the RootBrowserWindow is not created yet, only the size for it will be stored.
            Move(initData.WindowRect);
            Show(initData.ShowWindow);
 
            switch (mimeType)
            {
                case MimeType.Markup:
                    // Make a dummy application (in lieu of the one provided by the defunct XamlViewer.xbap).
                    Invariant.Assert(AppDomain.CurrentDomain.FriendlyName == "XamlViewer");
                    Application app = new Application();
                    app.StartupUri = Uri;
                    // Any URL #fragment is appended to StartupUri in _RunDelegate().
                    // For history navigation, ApplicationProxyInternal has already started navigation to the
                    // last journal entry captured. (This journal entry may include a #fragment target and/or
                    // a CustomContentState.)
                    break;
 
                case MimeType.Application:
                    //This is a browser app, the application object has already been created
                    break;
 
                case MimeType.Document:
                    throw new NotImplementedException(); // removed in v4
                case MimeType.Unknown:
                default:
                    throw new InvalidOperationException();
            }
 
            // Set the Application.MimeType
            // Since loading containers causes the application to be constructed now,
            // the initial setting of the MimeType does not get passed to the application.
            Application.Current.MimeType = mimeType;
            ServiceProvider = initData.ServiceProvider; // also sets Application.ServiceProvider
 
            Application.Current.Dispatcher.Invoke(
                DispatcherPriority.Send,
                new DispatcherOperationCallback(_RunDelegate),
                initData);
 
            int exitCode = Application.Current.RunInternal(null);
 
            EventTrace.EasyTraceEvent(EventTrace.Keyword.KeywordHosting | EventTrace.Keyword.KeywordPerf, EventTrace.Level.Verbose, EventTrace.Event.WpfHost_AppProxyRunEnd);
 
            return exitCode;
        }
 
        ///<SecurityNote>
        ///     Critical as this calls a critical function ( LoadHistoryStream).
        ///</SecurityNote>
        [SecurityCritical]
        private object _RunDelegate( object args )
        {
            InitData initData = (InitData)args;
 
            Application currentApp = Application.Current;
            if (currentApp != null && !(currentApp is XappLauncherApp))
            {
                string fragment = initData.Fragment;
                if (!String.IsNullOrEmpty(fragment) && currentApp.StartupUri != null)
                {
                    // Apply Fragment to Application StartupUri.
                    UriBuilder uriBuilder;
                    Uri absUri = currentApp.StartupUri;
 
                    if (currentApp.StartupUri.IsAbsoluteUri == false)
                    {
                        absUri = new Uri(BindUriHelper.BaseUri, currentApp.StartupUri);
                    }
 
                    uriBuilder = new UriBuilder(absUri);
                    if (fragment.StartsWith(FRAGMENT_MARKER, StringComparison.Ordinal))
                    {
                        fragment = fragment.Substring(FRAGMENT_MARKER.Length);
                    }
                    uriBuilder.Fragment = fragment;
                    currentApp.StartupUri = uriBuilder.Uri;
                }
 
                CreateRootBrowserWindow();
            }
 
            //If we were started through IPersistHistory::Load, load from the history stream instead
            //of navigating to the StartupPage
            if (initData.UcomLoadIStream != null && initData.HandleHistoryLoad)
            {
                LoadHistoryStream(DocObjHost.ExtractComStream(initData.UcomLoadIStream), /*firstHistoryLoad=s*/true);
            }
            return null;
        }
 
        // Show or hide view.
        internal void Show(bool show)
        {
            _show = show;
            if (Application.Current != null && RootBrowserWindow != null)
            {
                Application.Current.Dispatcher.BeginInvoke(
                                    DispatcherPriority.Send,
                                    new DispatcherOperationCallback(_ShowDelegate),
                                    null);
            }
 
        }
 
        private object _ShowDelegate(object ignore)
        {
            // The RBW might be torn down just before the DispatcherOperation is invoked.
            if (RootBrowserWindow == null || Application.IsShuttingDown)
                return null;
 
            if (_show)
            {
                // The window is shown asynchronously (using Visibility, not Show()) to allow first restoring
                // the Journal on history navigation. This prevents bug 1367999.
                _rbw.Value.Visibility = Visibility.Visible;
 
                // initial focus should be on us, not the browser frame
                // Focusing is done asynchronously because Visibility actually changes asynchronously.
                Application.Current.Dispatcher.BeginInvoke(
                    // same priority as used in the Window.Visibility PropertyChangedCallback
                    DispatcherPriority.Normal,
                    new DispatcherOperationCallback(_FocusDelegate), null);
            }
            else
            {
                _rbw.Value.Visibility = Visibility.Hidden;
            }
 
            return null;
        }
 
        /// <SecurityNote>
        /// Critical: Calls the critical UnsafeNativeMethods.SetFocus(), which returns a handle to
        ///     the previously focused window.
        /// Safe: The handle is not disclosed, and focusing the application's own window (RBW) is okay.
        /// </SecurityNote>
        [SecurityCritical, SecurityTreatAsSafe]
        private object _FocusDelegate(object unused)
        {
            if (_rbw.Value != null)
            {
                try
                {
                    MS.Win32.UnsafeNativeMethods.SetFocus(new HandleRef(_rbw.Value, _rbw.Value.CriticalHandle));
                }
#pragma warning disable 6502
                // The browser may temporarily disable the RBW. Then SetFocus() fails.
                // This is known to happen when the browser pops up the modal dialog about the Information Bar.
                catch (System.ComponentModel.Win32Exception)
                {
                    Debug.WriteLine("SetFocus() on RootBrowserWindow failed.");
                }
#pragma warning restore 6502
            }
            return null;
        }
 
        internal void Move(Rect windowRect)
        {
            if (Application.Current != null && RootBrowserWindow != null)
            {
                Application.Current.Dispatcher.BeginInvoke(
                                    DispatcherPriority.Send,
                                    new DispatcherOperationCallback(_MoveDelegate),
                                    windowRect);
            }
            else
            {
                // We got UIActivated too early.  Remember the data passed in.
                _windowRect = windowRect;
                _rectset = true;
            }
        }
 
        private object _MoveDelegate( object moveArgs )
        {
            // The RBW might be closed just before _MoveDelegate() is called. => check _rbw again.
            if (_rbw.Value != null && !Application.IsShuttingDown)
            {
                Rect r = (Rect)moveArgs;
 
                // ResizeMove is implemented by RBW and should be called here
                // since it resizes and moves the WS_CHILD window.  Do not call
                // Height/Width & Top/Left here since they govern the browser
                // window properties.
                _rbw.Value.ResizeMove((int)r.X, (int)r.Y, (int)r.Width, (int)r.Height);
            }
            return null;
        }
 
        // Shutdown the App.
        // Note: The "post" in the method name is legacy. Now all of Application's shutdown work is complete
        // when this method returns. In particular, the managed Dispatcher is shut down.
        ///<SecurityNote>
        ///  Critical: Calls Application.CriticalShutdown().
        ///</SecurityNote>
        [SecurityCritical]
        internal void PostShutdown()
        {
            Cleanup();
            _proxyInstance = null;
 
            Application app = Application.Current;
            if (app != null)
            {
                XappLauncherApp launcherApp = app as XappLauncherApp;
                if (launcherApp != null)
                {
                    launcherApp.AbortActivation();
                    Debug.Assert(Application.IsShuttingDown);
                }
                else
                {
                    //this calls into the internal helper and is hardcoded for a clean
                    // shutdown
                    app.CriticalShutdown(0);
 
                    // The Application.Exit event is raised in a Dispatcher callback at Normal priority.
                    // Blocking on this callback here ensures that the event will be raised before we've
                    // disconnected from the browser. An XBAP may want, in particular, to write a cookie.
                    app.Dispatcher.Invoke(DispatcherPriority.Normal,
                        new DispatcherOperationCallback(delegate(object unused) { return null; }), null);
                }
            }
        }
 
        //
        // Activate or Deactivate RootBrowserWindow
        //
 
        internal void Activate(bool fActivate)
        {
            if (Application.Current != null && RootBrowserWindow != null)
            {
                Application.Current.Dispatcher.BeginInvoke(
                                    DispatcherPriority.Send,
                                    new DispatcherOperationCallback(_ActivateDelegate),
                                    fActivate);
            }
        }
 
        private object _ActivateDelegate(object arg )
        {
            if (RootBrowserWindow != null)
            {
                bool fActivate = (bool)arg;
 
                _rbw.Value.HandleActivate(fActivate);
                if (fActivate)
                {
                    _FocusDelegate(null);
                }
            }
            return null;
        }
 
        internal bool CanInvokeJournalEntry(int entryId)
        {
            if (Application.Current == null)
            {
                return false;
            }
 
            return (bool)Application.Current.Dispatcher.Invoke(
            DispatcherPriority.Send,
                (DispatcherOperationCallback) delegate(object unused)
            {
                NavigationWindow window = Application.Current.MainWindow as NavigationWindow;
 
                if (window == null)
                    return false;
 
                return window.JournalNavigationScope.CanInvokeJournalEntry(entryId);
            },
            null);
        }
 
        // Private class just to facilitate passing of data back to GetSaveHistoryBytes.
        private class SaveHistoryReturnInfo
        {
            internal string uri;
            internal string title;
            internal int entryId;
            internal byte[] saveByteArray ;
        }
 
        /// <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>
        ///<SecurityNote>
        ///     Critical as this method accesses critical data.
        ///              and we elevate for serialization permission.
        ///</SecurityNote>
        [SecurityCritical]
        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 ;
        }
 
        //CASRemoval:[SecurityPermission(SecurityAction.Assert, SerializationFormatter = true)]
 
        ///<SecurityNote>
        ///     Critical as the delegate that this method invokes accesses critical data.
        ///</SecurityNote>
        [SecurityCritical]
        internal byte[] GetSaveHistoryBytes(bool persistEntireJournal, out int journalEntryId, out string uriString, out string titleString)
        {
            SaveHistoryReturnInfo info = null ;
 
            if (Application.Current != null)
            {
                info = ( SaveHistoryReturnInfo) Application.Current.Dispatcher.Invoke(
                                DispatcherPriority.Send,
                                new DispatcherOperationCallback(_GetSaveHistoryBytesDelegate) ,
                                persistEntireJournal);
            }
 
            if ( info != null )
            {
                journalEntryId = info.entryId;
                uriString = info.uri;
                titleString = info.title;
                return info.saveByteArray;
            }
            else
            {
                journalEntryId = 0;
                uriString = null;
                titleString = null;
                return null;
            }
        }
 
        ///<SecurityNote>
        ///     Critical as the delegate that this method invokes accesses critical data.
        ///</SecurityNote>
        [SecurityCritical]
        internal void LoadHistoryStream(MemoryStream loadStream, bool firstLoadFromHistory)
        {
            if (Application.Current == null)
            {
                return;
            }
 
            LoadHistoryStreamInfo info = new LoadHistoryStreamInfo();
            info.loadStream = loadStream ;
            info.firstLoadFromHistory = firstLoadFromHistory ;
 
            Application.Current.Dispatcher.Invoke(
                        DispatcherPriority.Send,
                        new DispatcherOperationCallback(_LoadHistoryStreamDelegate),
                        info);
        }
 
        private class LoadHistoryStreamInfo
        {
            internal MemoryStream loadStream ;
            internal bool firstLoadFromHistory;
        }
 
        ///<SecurityNote>
        ///     Critical as this method accesses critical data.
        ///</SecurityNote>
        [SecurityCritical]
        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)
            {
                // Patch for WOSB 1834243: 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;
                }
 
                //
 
 
 
 
                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;
        }
 
        /// <SecurityNote>
        /// Critical - Makes a trust decision about whether to perform a BinaryFormatter.Deserialize (a privilaged operation) on untrusted data.
        /// </SecurityNote>
        [SecurityCritical]
        private object DeserializeJournaledObject(MemoryStream inputStream)
        {
            object deserialized = null;
            
            int header = inputStream.ReadByte();
            if (header >= 0)
            {
                switch((byte)header)
                {
                    case JournalIdHeader : 
                    {
                        deserialized = ReadInt32(inputStream);
                        break;
                    }
                    
                    case BrowserJournalHeader:
                    {
                        try
                        {
                            new SecurityPermission(SecurityPermissionFlag.SerializationFormatter).Demand();
                            BinaryFormatter formatter = new BinaryFormatter();
                            deserialized = formatter.Deserialize(inputStream);
                        }
                        catch (SecurityException)
                        {
                            deserialized = null;
                        }
                        
                        break;
                    }
                    
                    default:
                    {
                        throw new FormatException();
                    }
                }
            }
            
            return deserialized;
        }
 
        // See if an App instance is currently loaded.
        internal bool IsAppLoaded()
        {
            return (Application.Current == null ? false : true);
        }
 
        // Return the internal static variable _shutdown.
        internal bool IsShutdown()
        {
            return Application.IsShuttingDown;
        }
 
        /// <SecurityNote>
        /// Critical:
        ///  1) Accesses _storageRoot, _container, _packageStream, _unmanagedStream
        ///
        /// TreatAsSafe:
        ///  1) Doesn't disclose _storageRoot, _container, _packageStream,
        ///     _unmanagedStream
        /// </SecurityNote>
        [SecurityCritical, SecurityTreatAsSafe]
        internal void Cleanup()
        {
            if (Application.Current != null)
            {
                IBrowserCallbackServices bcs = Application.Current.BrowserCallbackServices;
                if (bcs != null)
                {
                    Debug.Assert(!Application.IsApplicationObjectShuttingDown);
                    // Marshal.ReleaseComObject(bcs) has to be called so that the refcount of the
                    // native objects goes to zero for clean shutdown. But it should not be called
                    // right away, because there may still be DispatcherOperations in the queue
                    // that will attempt to use IBCS, especially during downloading/activation.
                    // Last, it can't be called with prioroty lower than Normal, because that's
                    // the priority of Applicatoin.ShudownCallback(), which shuts down the
                    // Dispatcher.
                    Application.Current.Dispatcher.BeginInvoke(
                        DispatcherPriority.Normal, new DispatcherOperationCallback(ReleaseBrowserCallback), bcs);
                }
            }
 
            ServiceProvider = null;
            ClearRootBrowserWindow();
 
            if (_storageRoot != null && _storageRoot.Value != null  )
            {
                _storageRoot.Value.Close();
            }
 
            // Due to the dependecies the following objects have to be released
            // in the following order: _document, DocumentManager,
            // _packageStream, _unmanagedStream.
 
            if (_document.Value is PackageDocument)
            {
                // We are about to close the package ad remove it from the Preloaded Packages Store.
                // Let's make sure that the data structures are consistent. The package that we hold is
                // actually in the store under the URI that we think it should be using
                Debug.Assert(((PackageDocument)_document.Value).Package ==
                                    PreloadedPackages.GetPackage(PackUriHelper.GetPackageUri(PackUriHelper.Create(Uri))));
 
                // We need to remove the Package from the PreloadedPackage storage,
                // so that potential future requests would fail in a way of returning a null (resource not found)
                // rather then return a Package or stream that is already Closed
                PreloadedPackages.RemovePackage(PackUriHelper.GetPackageUri(PackUriHelper.Create(Uri)));
 
                ((PackageDocument)_document.Value).Dispose();
                _document.Value = null;
            }
 
            if (_mimeType.Value == MimeType.Document)
            {
                DocumentManager.CleanUp();
            }
 
            if (_packageStream.Value != null)
            {
                _packageStream.Value.Close();
            }
 
            if (_unmanagedStream.Value != null)
            {
                Marshal.ReleaseComObject(_unmanagedStream.Value);
                _unmanagedStream = new SecurityCriticalData<object>(null);
            }
        }
 
        /// <SecurityNote>
        /// Critical: Calls Marshal.ReleaseComObject(), which has a LinkDemand for unmanaged code.
        /// </SecurityNote>
        [SecurityCritical]
        private object ReleaseBrowserCallback(object browserCallback)
        {
            Marshal.ReleaseComObject(browserCallback);
            BrowserInteropHelper.ReleaseBrowserInterfaces();
            return null;
        }
 
        #endregion Internal Methods
 
        //------------------------------------------------------
        //
        //  Internal Properties
        //
        //------------------------------------------------------
        #region Internal Properties
 
        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
        internal RootBrowserWindowProxy RootBrowserWindowProxy
        {
            get
            {
                if (_rbwProxy.Value == null)
                {
                    CreateRootBrowserWindow();
                }
                return _rbwProxy.Value;
            }
        }
 
        ///<SecurityNote>
        /// Critical as the setter stores the critical RBW reference
        ///</SecurityNote>
        internal RootBrowserWindow RootBrowserWindow
        {
            get
            {
                return _rbw.Value;
            }
            [SecurityCritical]
            private set
            {
                _rbw.Value = value;
                if (value == null)
                {
                    _rbwProxy.Value = null;
                }
                else
                {
                    _rbwProxy.Value = new RootBrowserWindowProxy(value);
 
                    if (_rectset == true)
                    {
                        // If UIActivation already happened, set the size with
                        // cached values.
                        Move(_windowRect);
                        _rectset = false;
                    }
 
                    //Incase Show() was called before we had a chance to create the window
                    //If the old and new values are the same, this will be a no-op anyway
                    Show(_show);
                }
            }
        }
 
        internal bool RootBrowserWindowCreated { get { return _rbw.Value != null; } }
 
        internal OleCmdHelper OleCmdHelper
        {
            get
            {
                if (Application.Current == null)
                {
                    return null;
                }
 
                return (OleCmdHelper) Application.Current.Dispatcher.Invoke(
                DispatcherPriority.Send,
                (DispatcherOperationCallback) delegate(object unused)
                {
                    // V3.5: Check for Application object shutting down only.
                    // Consider to check for Browser shutting down.
                    if (Application.IsApplicationObjectShuttingDown == true)
                        return null;
 
                    if (_oleCmdHelper == null)
                    {
                        _oleCmdHelper = new OleCmdHelper();
                    }
                    return _oleCmdHelper;
                },
                null);
            }
        }
 
        /// <SecurityNote>
        /// Critical: Returns a critical object, which can be used cross-AppDomain.
        /// </SecurityNote>
        internal static ApplicationProxyInternal Current
        {
            [SecurityCritical]
            get { return _proxyInstance; }
        }
 
        /// <SecurityNote>
        /// Critical:
        ///  - sets _criticalUri which is critical
        /// </SecurityNote>
        internal Uri Uri
        {
            get
            {
                return _criticalUri.Value;
            }
            [SecurityCritical]
            private set
            {
                _criticalUri.Value = value;
 
                // We need to set these properties now, because there are times during the application's lifetime
                // when the source URI would be useful, but the ApplicationProxyInternal has come and gone.
                // If there is DebugSecurityZoneUrl, SiteOfOriginContainer.BrowserSource would have been set to that value.
                // We don't want to overwrite that, so check whether the value is null or not before setting.
                if (SiteOfOriginContainer.BrowserSource == null)
                {
                    SiteOfOriginContainer.BrowserSource = value;
                }
            }
        }
 
        /// <SecurityNote>
        /// Critical:
        ///  - sets SiteOfOriginContainer.DebugSeurityZoneURL which is critical
        /// </SecurityNote>
        [SecurityCritical]
        internal void SetDebugSecurityZoneURL(Uri debugSecurityZoneURL)
        {
            SiteOfOriginContainer.BrowserSource = debugSecurityZoneURL;
        }
 
        /// <SecurityNote>
        ///     Critical - An external caller is setting the stream that we are using.  This is external
        ///                data from the web.
        /// </SecurityNote>
        internal object StreamContainer
        {
            [SecurityCritical]
            set
            {
                _unmanagedStream = new SecurityCriticalData<object>(Marshal.GetObjectForIUnknown((IntPtr)value));
            }
        }
 
        #endregion Internal Properties
 
        //------------------------------------------------------
        //
        //  Private Methods
        //
        //------------------------------------------------------
        #region Private Methods
 
        private void OnStartup(Object sender, StartupEventArgs e)
        {
            //We listen to the Startup event only for history loads in which
            //case we want to do our journaling load instead of StartupUri load
            e.PerformDefaultAction = false;
            Application.Current.Startup -= new System.Windows.StartupEventHandler(this.OnStartup);
        }
 
 
        ///<SecurityNote>
        ///     Critical as this accesses critical data.
        ///     TreatAsSafe - as clearing the RBW is eliminating critical data - and considered safe.
        ///</SecurityNote>
        [SecurityCritical, SecurityTreatAsSafe]
        private void ClearRootBrowserWindow()
        {
            RootBrowserWindow = null;
        }
 
        private static void WriteInt32(Stream stream, int value)
        {
            stream.WriteByte((byte)((value & 0xFF000000) >> 24));
            stream.WriteByte((byte)((value & 0x00FF0000) >> 16));
            stream.WriteByte((byte)((value & 0x0000FF00) >> 8));
            stream.WriteByte((byte)((value & 0x000000FF)));
        }
        
        private static int ReadInt32(Stream stream)
        {
            int value = 0;
            for (int i = 0; i < 4; i++)
            {
                int b = stream.ReadByte();
                if (b < 0) 
                {
                    throw new EndOfStreamException();
                }
                
                value = (value << 8) | b;
            }
            
            return value;
        }
        
        #endregion Private Methods
 
        #region Private Properties
 
        private IServiceProvider ServiceProvider
        {
            set
            {
                _serviceProvider = value;
 
                if (Application.Current != null)
                {
                    Application.Current.ServiceProvider = value;
                }
            }
        }
 
        #endregion
 
        //------------------------------------------------------
        //
        //  Private Fields
        //
        //------------------------------------------------------
        #region Private Fields
 
        // Instance fields.
 
        // These are fields that moved from DocobjHost class so we can have a
        // unified way of calling for single vs multiple AppDomain scenarios.
 
        ///<SecurityNote>
        /// Critical: We don't want an arbitrary window to be assigned here
        ///   (even though only the real RBW can be created in PT).
        ///</SecurityNote>
        private SecurityCriticalDataForSet<RootBrowserWindow>   _rbw;
 
        ///<SecurityNote>
        /// Critical for the same reason that _rbw is.
        ///</SecurityNote>
        private SecurityCriticalDataForSet<RootBrowserWindowProxy> _rbwProxy;
 
        private bool                _show;
        private OleCmdHelper        _oleCmdHelper;
 
        // The following variables are used to remember the window size until the window is created
        // because the OLE SetRect/Show calls happen before the app and window are created internally
        Rect                        _windowRect;
        bool                        _rectset;
 
        private SecurityCriticalDataForSet<Uri> _criticalUri;
        SecurityCriticalDataClass<StorageRoot> _storageRoot = new SecurityCriticalDataClass<StorageRoot>(null);
        SecurityCriticalDataForSet<MimeType> _mimeType;
        IServiceProvider _serviceProvider ;
 
        /// <SecurityNote>
        /// Critical: ApplicationProxyInternal can be used cross-AppDomain and implements
        ///     critical functionality.
        /// </SecurityNote>
        [SecurityCritical]
        private static ApplicationProxyInternal _proxyInstance;
 
        private const string FRAGMENT_MARKER = "#";
        
        private const byte JournalIdHeader = 0x01;
        private const byte BrowserJournalHeader = 0x02;
 
        #region XpsViewer (DocumentApplication) Specific
        /// <summary>
        /// This is an unmanaged COM IStream that is provided by the byte range downloader
        /// (progressive download) and comes from our unmanaged host.
        /// </summary>
        /// <SecurityNote>
        /// Critical:
        ///  1) this is a pointer to a security suppressed unmanaged stream, using it directly is
        ///     unsafe
        ///  2) the data from this stream likely comes from the internet
        ///
        /// Not Safe:
        ///  1) although we did our best to protect from native exploits, no one is perfect and
        ///     the backing code is unmanaged
        /// </SecurityNote>
        SecurityCriticalData<object> _unmanagedStream = new SecurityCriticalData<object>(null);
 
        /// <summary>
        /// This is a ByteWrapper a managed class that is an adapter from IStream to Stream.
        /// The stream it wraps is the _unmanagedStream.
        /// </summary>
        /// <SecurityNote>
        /// Critical:
        ///  1) we do not want this replaced with another stream after we have made security
        ///     decisions based on its contents (like mime type and start part)
        ///  2) this may be an EncryptedPackage which contains PII (Personally Identifiable
        ///     Information) in clear text; as such we want to audit use so information is
        ///     not leaked
        ///
        /// Not Safe:
        ///  1) we want to audit it is set once
        ///  2) we want to audit for leaks
        /// </SecurityNote>
        SecurityCriticalData<Stream> _packageStream = new SecurityCriticalData<Stream>(null);
 
        /// <summary>
        /// This contains many streams and packages that represent the current 'Package'
        /// for the XpsViewer.
        /// </summary>
        /// <SecurityNote>
        /// Critical:
        ///  1) none of this data can be effectively protected due to the visual tree
        ///     and Package.GetStream model currently in place protecting leaking of this
        ///     has been waived in a security review as it would have no net effect
        ///  2) based on the current hosting design we expect one 'Package' for the lifetime
        ///     of the application, thus this should be audited such that it is set only once
        ///
        /// Not Safe:
        ///  2) we want to audit it is set once
        /// </SecurityNote>
        // The Document has been weakly-typed to avoid PresentationFramework
        // having a type dependency on PresentationUI.  The perf impact of the weak
        // typed variables in this case was determined to be much less than forcing the load
        // of a new assembly when Assembly.GetTypes was called on PresentationFramework.
        SecurityCriticalDataForSet<object> _document;
        #endregion
 
        #endregion Private Fields
 
        #region Private Structs
        /// <summary>
        /// Holder for all things to be persisted in the BrowserJournal before we
        /// navigate away from the app
        /// </summary>
        [Serializable]
        private struct BrowserJournal
        {
            #region Constructors
            internal BrowserJournal(Journal journal, Uri baseUri)
            {
                _journal = journal;
                _baseUri = baseUri;
            }
            #endregion Constructors
 
            #region Properties
            internal Journal Journal
            {
                get { return _journal; }
            }
 
            internal Uri BaseUri
            {
                get { return _baseUri; }
            }
            #endregion Properties
 
            #region Private Fields
            private Journal         _journal;
            private Uri             _baseUri;
            #endregion Private Fields
        }
        #endregion Private Structs
 
    }
}