XappLauncher.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / wpf / src / Framework / MS / Internal / AppModel / XappLauncher.cs / 3 / XappLauncher.cs

                            using System; 
using System.Deployment.Application;
using System.Runtime.Remoting;
using System.Security;
using System.Security.Policy; 
using System.Xml;
using System.Windows; 
using System.Windows.Controls; 
using System.Windows.Interop;
using System.Windows.Navigation; 
using System.Windows.Threading;
using System.Runtime.InteropServices;
using System.Diagnostics;
using MS.Internal; 
using MS.Internal.PresentationFramework;
using MS.Internal.Utility; 
using Microsoft.Internal.DeploymentUI; 
using Microsoft.Win32;
using System.Reflection; 
using MS.Utility;
using System.Windows.Input;
using System.Security.Permissions;
 
namespace MS.Internal.AppModel
{ 
    internal class XappLauncherApp : Application 
    {
        internal XappLauncherApp(Uri deploymentManifest, string applicationId, 
            IBrowserCallbackServices browser, DocObjHost.ApplicationRunnerCallback applicationRunner,
            INativeProgressPage nativeProgressPage,
            string progressPageAssembly, string progressPageClass, string errorPageAssembly, string errorPageClass)
        { 
            _deploymentManifest = deploymentManifest;
            _applicationId = applicationId; 
            _browser = browser; 
            _applicationRunnerCallback = applicationRunner;
            _fwlinkUri = null; 
            this.Startup += new StartupEventHandler(XappLauncherApp_Startup);
            this.Exit += new ExitEventHandler(XappLauncherApp_Exit);
            this.Navigated += new NavigatedEventHandler(XappLauncherApp_Navigated);
 
            _nativeProgressPage = nativeProgressPage;
            _progressPageAssembly = progressPageAssembly; 
            _progressPageClass = progressPageClass; 
            _errorPageAssembly = errorPageAssembly;
            _errorPageClass = errorPageClass; 
        }

        void OnCommandRefresh(object sender, RoutedEventArgs e)
        { 
            HandleRefresh();
        } 
 
        void OnCommandStop(object sender, RoutedEventArgs e)
        { 
            UserStop();
        }

        void XappLauncherApp_Startup(object sender, StartupEventArgs e) 
        {
            if (EventTrace.IsEnabled(EventTrace.Flags.performance, EventTrace.Level.verbose)) 
            { 
                EventTrace.EventProvider.TraceEvent(EventTrace.Level.verbose,
                    EventTrace.GuidFromId(EventTraceGuidId.HOSTINGGUID), (byte)EventTrace.HostingEvent.XappLauncherAppStartup); 
            }

            CreateApplicationIdentity();
            if (_identity != null) 
            {
                TryApplicationIdActivation(); 
            } 
            else
            { 
                TryUriActivation();
            }
        }
 
        void XappLauncherApp_Exit(object sender, ExitEventArgs e)
        { 
            if (EventTrace.IsEnabled(EventTrace.Flags.performance, EventTrace.Level.verbose)) 
            {
                EventTrace.EventProvider.TraceEvent(EventTrace.Level.verbose, 
                    EventTrace.GuidFromId(EventTraceGuidId.HOSTINGGUID), (byte)EventTrace.HostingEvent.XappLauncherAppExit, _runApplication);
            }

            Invariant.Assert(!_isInAsynchronousOperation, 
                "Async downloading should have been canceled before XappLauncherApp exits.");
 
            if (_runApplication) 
            {
                _applicationRunnerCallback(new DocObjHost.ApplicationRunner(_applicationRunner)); 
            }

            _browser = null;
            _applicationRunner = null; 
            _applicationRunnerCallback = null;
        } 
 

        /// 
        ///    Critical: This code calls into critical code GetAppWindow
        ///    TreatAsSafe: There exists a demand here
        ///
        [SecurityCritical, SecurityTreatAsSafe] 
        void XappLauncherApp_Navigated(object sender, NavigationEventArgs e)
        { 
            if (EventTrace.IsEnabled(EventTrace.Flags.performance, EventTrace.Level.verbose)) 
            {
                EventTrace.EventProvider.TraceEvent(EventTrace.Level.verbose, 
                    EventTrace.GuidFromId(EventTraceGuidId.HOSTINGGUID), (byte)EventTrace.HostingEvent.XappLauncherAppNavigated);
            }

            if (IsShuttingDown) 
                return;
 
            if (!_commandBindingsRegistered) 
            {
                _commandBindingsRegistered = true; 

                // These bindings handle the commands sent by the browser when the stop/refresh buttons are pressed. If nothing in the
                // page has focus, they will be sent directly to the window.
                // SP2 Update: DocObjHost.ExecCommand() now also handles these commands, either directly from 
                // the browser or from the native progress page.
                MainWindow.CommandBindings.Add(new CommandBinding(NavigationCommands.BrowseStop, new ExecutedRoutedEventHandler(OnCommandStop))); 
                MainWindow.CommandBindings.Add(new CommandBinding(NavigationCommands.Refresh, new ExecutedRoutedEventHandler(OnCommandRefresh))); 
            }
 
            SecurityHelper.DemandUIWindowPermission();
            NavigationWindow navWin = GetAppWindow();
            Invariant.Assert(navWin != null, "A RootBrowserWindow should have been created.");
            while (navWin.CanGoBack) 
            {
                navWin.RemoveBackEntry(); 
            } 
        }
 
        void StartAsynchronousOperation()
        {
            Debug.Assert(!_isInAsynchronousOperation && !IsCanceledOrShuttingDown);
            _isInAsynchronousOperation = true; 
            ChangeBrowserDownloadState(_isInAsynchronousOperation);
        } 
 
        void ClearAsynchronousOperationStatus()
        { 
            _isInAsynchronousOperation = false;
            ChangeBrowserDownloadState(_isInAsynchronousOperation);
        }
 

        private object UserRefresh(object unused) 
        { 
            HandleRefresh();
            return null; 
        }

        internal override void PerformNavigationStateChangeTasks(
            bool isNavigationInitiator, bool playNavigatingSound, NavigationStateChange state) 
        {
            // Do not play sounds or start and stop the globe on when navigations 
            // occur because the progress page is merely an enhanced visual experience 
            // during the actual navigation to the application.  Conceptually it  should
            // appear as something that happens during navigation and not a series of 
            // discrete navigations.

            // We do need to ensure that the Stop and Refresh buttons are in the correct state
            // while downloading the app. 
            if (isNavigationInitiator && state == NavigationStateChange.Completed)
            { 
                UpdateBrowserCommands(); 
            }
        } 

        // This function gets called when the browser refresh button in clicked.
        // This'll cause the browser to navigate the address bar
        /// 
        ///  Critical: Accesses BrowserCallbackServices to navigate
        ///  TreatAsSafe: only navigates to a safe, already validated _deploymentManifest. 
        ///  Potentially, this could be a DOS attack FOR THE APP ONLY if refresh was called constantly, but that is 
        ///  below the bar for critical code progagation, as the user can recover and the system is not destabilized.
        /// 
        [SecurityCritical, SecurityTreatAsSafe]
        internal void HandleRefresh()
        {
            lock (_lockObject) // we do this in case the refresh button is getting clicked rapidly, before the navigation happens 
            {
                if (!_refreshing) 
                { 
                    _refreshing = true;
                    BrowserCallbackServices.DelegateNavigation(_deploymentManifest.ToString(), null, null); 
                }
            }
        }
 
        /// 
        /// Critical: Calls IBrowserCallbackServices.ChangeDownloadState which is critical 
        /// TreatAsSafe: Changing the download state is safe 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        private void ChangeBrowserDownloadState(bool newState)
        {
            // start or stop waving the flag
            // When shutting down, which may happen during deployment, IBrowserCallbackServices may become 
            // unavailable. Calling ChangeBrowserDownloadState(false) should not trigger an exception then.
            try 
            { 
                _browser.ChangeDownloadState(newState);
            } 
            catch (COMException)
            {
                if (newState || !IsShuttingDown)
                    throw; 
            }
            catch (InvalidOperationException) 
            { 
                if (newState || !IsShuttingDown)
                    throw; 
            }
        }

        private void TryApplicationIdActivation() 
        {
            Dispatcher.Invoke( 
                DispatcherPriority.Input, 
                new DispatcherOperationCallback(DoDirectActivation),
                null); 
        }

        private void TryUriActivation()
        { 
            EventTrace.NormalTraceEvent(EventTraceGuidId.HOSTINGGUID, (byte)EventTrace.HostingEvent.FirstTimeActivation);
 
            _hostingManager = new InPlaceHostingManager(_deploymentManifest); 

            // Ordering is important here - downloading the manifest is done asynchronously 
            // so can be started before we spend time setting up the UI.  This saves us some
            // time - especially during cold-start scenarios.

            // Calling it through the dispatcher makes sure the right context and exception 
            // handling is used.  DispatcherPriority.Send has it executed synchronously.
            Dispatcher.Invoke( 
                DispatcherPriority.Send, 
                new DispatcherOperationCallback(DoGetManifestAsync),
                null); 

            DoDownloadUI();
        }
 
        ///
        ///     Critical: calls ApplicationTrustCollection.Item which LinkDemands 
        ///     TreatAsSafe: Caller can't hand in an arbitrary item string 
        ///
        [SecurityCritical, SecurityTreatAsSafe] 
        private object DoDirectActivation(object unused)
        {
            if (IsCanceledOrShuttingDown)
                return null; 

            try 
            { 
                // Verify that this app is actually cached. This is because the call to
                // CreatePartialActivationContext can succeed when we don't want it to; 
                // it appears to be insensitive to some parts of the ApplicationIdentity,
                // or it tries to make things work when they really should fail. Looking
                // at the UserApplicationTrusts does a better comparison.
                if (ApplicationSecurityManager.UserApplicationTrusts[_identity.ToString()] != null) 
                {
                    _context = ActivationContext.CreatePartialActivationContext(_identity); 
                    _applicationRunner = new DocObjHost.ApplicationRunner(ExecuteDirectApplication); 
                    _runApplication = true;
                    this.Shutdown(); 
                }
                else
                {
                    TryUriActivation(); 
                }
            } 
            catch(Exception exception) 
            {
                // Delete the cached trust decision to force going down the full ClickOnce path next time 
                DeleteCachedApplicationTrust(_identity);

                // Fatal error like NullReferenceException and SEHException should not be ignored.
                if (exception is NullReferenceException || exception is SEHException) 
                {
                    throw; 
                } 
                else
                { 
                    TryUriActivation();
                }
            }
 
            return null;
        } 
 
        ///
        ///    Critical: This code calls into critical code which has link demand (Activator.CreateInstance) 
        ///    TreatAsSafe: There exists a demand here
        ///
        [SecurityCritical, SecurityTreatAsSafe]
        private void ExecuteDirectApplication() 
        {
            SecurityHelper.DemandUnmanagedCode(); 
            try 
            {
                if (EventTrace.IsEnabled(EventTrace.Flags.performance)) 
                {
                    EventTrace.EventProvider.TraceEvent(EventTrace.GuidFromId(EventTraceGuidId.HOSTINGGUID), (byte)EventTrace.HostingEvent.ClickOnceActivationStart, KnownBoxes.BooleanBoxes.TrueBox);
                }
                ObjectHandle oh = Activator.CreateInstance(_context); 
                if (PresentationAppDomainManager.SaveAppDomain)
                { 
                    AppDomain newDomain = oh.Unwrap() as AppDomain; 
                    PresentationAppDomainManager.NewAppDomain = newDomain;
                } 

                EventTrace.NormalTraceEvent(EventTraceGuidId.HOSTINGGUID, (byte)EventTrace.HostingEvent.ClickOnceActivationEnd);
            }
            catch (Exception exception) 
            {
                // Delete the cached trust decision to force going down the full ClickOnce path next time 
                DeleteCachedApplicationTrust(_identity); 

                // Fatal error like NullReferenceException and SEHException should not be ignored. 
                if (exception is NullReferenceException || exception is SEHException)
                {
                    throw;
                } 
                else
                { 
                    TryUriActivation(); 
                }
            } 
        }

        /// 
        /// Critical: Calls the critical SetStatusText(). 
        /// TreatAsSafe: The status message is fixed, coming from a string table.
        ///  
        [SecurityCritical, SecurityTreatAsSafe] 
        private object DoGetManifestAsync(object notUsed)
        { 
            if (IsCanceledOrShuttingDown)
                return null;

            EventTrace.NormalTraceEvent(EventTraceGuidId.HOSTINGGUID, (byte)EventTrace.HostingEvent.DownloadDeplManifestStart); 

            StartAsynchronousOperation(); 
            SetStatusText(SR.Get(SRID.HostingStatusDownloadAppInfo)); 

            _hostingManager.GetManifestCompleted += new EventHandler(GetManifestCompleted); 
            // Possible reentrancy! When making the outgoing calls to the browser to update its
            // status (above), a pending incoming call can be dispatched. This may be OLECMDID_STOP,
            // which would lead to calling UserStop(), which makes IPHM unusable.
            if (!IsCanceledOrShuttingDown) 
            {
                Debug.Assert(_isInAsynchronousOperation); 
                _hostingManager.GetManifestAsync(); 
            }
            return null; 
        }

        private object GetCustomPage(string pageAssemblyName, string pageClassName)
        { 
            if (EventTrace.IsEnabled(EventTrace.Flags.performance, EventTrace.Level.verbose))
            { 
                EventTrace.EventProvider.TraceEvent(EventTrace.Level.verbose, 
                    EventTrace.GuidFromId(EventTraceGuidId.HOSTINGGUID), (byte)EventTrace.HostingEvent.GetDownloadPageStart, pageClassName);
            } 
            object customPage;
            try
            {
                // Uses custom progress page 
                // If the assembly is not specified, use PresentationUI.
                Assembly customPageAssembly = string.IsNullOrEmpty(pageAssemblyName) ? typeof(TenFeetInstallationProgress).Assembly : Assembly.Load(pageAssemblyName); 
                customPage = customPageAssembly.CreateInstance(pageClassName); 
            }
            catch 
            {
                customPage = null;
            }
            if (EventTrace.IsEnabled(EventTrace.Flags.performance, EventTrace.Level.verbose)) 
            {
                EventTrace.EventProvider.TraceEvent(EventTrace.Level.verbose, 
                    EventTrace.GuidFromId(EventTraceGuidId.HOSTINGGUID), (byte)EventTrace.HostingEvent.GetDownloadPageEnd); 
            }
            return customPage; 
        }

        void GetManifestCompleted(object sender, GetManifestCompletedEventArgs e)
        { 
            Dispatcher.Invoke(
                DispatcherPriority.Send, 
                new DispatcherOperationCallback(DoGetManifestCompleted), 
                e);
        } 

        private object DoGetManifestCompleted(object e)
        {
            EventTrace.NormalTraceEvent(EventTraceGuidId.HOSTINGGUID, (byte)EventTrace.HostingEvent.DownloadDeplManifestEnd); 

            GetManifestCompletedEventArgs args = (GetManifestCompletedEventArgs)e; 
            _getManifestCompletedEventArgs = args; 

            // Race condition: UserStop() can be called after InPlaceHostingManager has completed 
            // the manifest downloading but before this callback is called.
            bool canceled = _canceled || args.Cancelled;

            ClearAsynchronousOperationStatus(); 

            if (IsShuttingDown) 
                return null; 
            if (args.Error != null)
            { 
                // If the async operation failed, it is invalid to request the
                // SupportUri so we simply pass in null.
                HandleError(args.Error, args.LogFilePath, null, null);
                return null; 
            }
            if (canceled) 
            { 
                HandleCancel();
                return null; 
            }

            // args.ApplicationIdentity throws if the operation has been canceled. That's why the above check has
            // to come first. 
            _identity = args.ApplicationIdentity;
 
            if (_progressPage != null) 
            {
                _progressPage.ApplicationName = args.ProductName; 

                // GetManifestCompletedEventArgs.PublisherName doesn't exist.
                // DevDiv bug 166088 tracks this.
                // The retrieval below takes surprisingly little time: < 1 ms. 
                XmlReader rdr = args.DeploymentManifest;
                rdr.MoveToContent(); 
                if (rdr.LocalName == "assembly") 
                {
                    rdr.ReadStartElement(); 
                    while(rdr.NodeType != XmlNodeType.EndElement)
                    {
                        if(rdr.LocalName == "description")
                        { 
                            string publisher = rdr.GetAttribute("publisher", "urn:schemas-microsoft-com:asm.v2");
                            if (!string.IsNullOrEmpty(publisher)) 
                            { 
                                _progressPage.PublisherName = publisher;
                            } 
                            break;
                        }
                        rdr.Skip();
                    } 
                }
            } 
 
            //
            // Start asynchronous application downloading 
            //
            EventTrace.NormalTraceEvent(EventTraceGuidId.HOSTINGGUID, (byte)EventTrace.HostingEvent.DownloadApplicationStart);
            ShowDownloadingStatusMessage();
            StartAsynchronousOperation(); 
            // Possible reentrancy! When making the outgoing calls to the browser to update its
            // status (above), a pending incoming call can be dispatched. This may be OLECMDID_STOP, 
            // which would lead to calling UserStop(), which makes IPHM unusable. 
            if (IsCanceledOrShuttingDown)
                return null; 
            _hostingManager.DownloadProgressChanged += new EventHandler(DownloadProgressChanged);
            _hostingManager.DownloadApplicationCompleted += new EventHandler(DownloadApplicationCompleted);
            _hostingManager.DownloadApplicationAsync();
 
            // Cold-start optimization: While async downloading is underway, do AssertApplicationRequirements.
            // AAR takes 0.8-1.5+ seconds on cold start because it loads all assemblies from which permission 
            // types are referenced. 
            Dispatcher.BeginInvoke(DispatcherPriority.Input,
                new DispatcherOperationCallback(AssertApplicationRequirementsAsync), null); 

            // Cold-start optimization: While we are network-bound, use the CPU and disk to start PFC.
            // This takes up to 2 seconds on Windows XP (it's faster on Vista).
            Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, 
                new DispatcherOperationCallback(StartFontCacheServiceAsync), null);
 
            return null; 
        }
 
        /// 
        /// Critical: Calls the critical SetStatusText().
        /// TreatAsSafe: The status message is fixed, coming from a string table.
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        void ShowDownloadingStatusMessage() 
        { 
            SetStatusText(SR.Get(SRID.HostingStatusDownloadApp));
        } 

        /// 
        /// Critical: Calls the critical SetStatusText().
        /// TreatAsSafe: The status message is fixed, coming from a string table. 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        object AssertApplicationRequirementsAsync(object unused) 
        {
            if (IsCanceledOrShuttingDown) 
                return null;

            if (CheckAccess()) // initial call by Dispatcher?
            { // Do a callback to a thread-pool thread 
                // Status bar is set on the main thread (here) to avoid switching.
                SetStatusText(SR.Get(SRID.HostingStatusVerifying)); 
                DispatcherOperationCallback cb = new DispatcherOperationCallback(AssertApplicationRequirementsAsync); 
                cb.BeginInvoke(null, null, null);
            } 
            else // on a thread-pool thread
            {
                try
                { 
                    if (EventTrace.IsEnabled(EventTrace.Flags.performance, EventTrace.Level.verbose))
                    { 
                        EventTrace.EventProvider.TraceEvent( 
                            EventTrace.GuidFromId(EventTraceGuidId.HOSTINGGUID), (byte)EventTrace.HostingEvent.AssertAppRequirementsStart);
                    } 

                    _hostingManager.AssertApplicationRequirements();

                    if (EventTrace.IsEnabled(EventTrace.Flags.performance, EventTrace.Level.verbose)) 
                    {
                        EventTrace.EventProvider.TraceEvent( 
                            EventTrace.GuidFromId(EventTraceGuidId.HOSTINGGUID), (byte)EventTrace.HostingEvent.AssertAppRequirementsEnd); 
                    }
 
                    // Switch to the main thread to update the status message. This is necessary because the
                    // native IBCS and INativeProgressPage interfaces are not marshalable.
                    Dispatcher.BeginInvoke(DispatcherPriority.Normal, new DispatcherOperationCallback(
                        delegate(object unused3) 
                        {
                            if (_isInAsynchronousOperation) 
                            { 
                                ShowDownloadingStatusMessage();
                            } 
                            return null;
                        }), null);
                }
                catch (Exception exception0) 
                {
                    _assertAppRequirementsFailed = true; 
 
                    // Note that an exception allowed to escape from here will be ----ed by the thread-pool manager.
                    // That's why all further processing is moved to the main thread. 
                    Dispatcher.BeginInvoke(DispatcherPriority.Send, new DispatcherOperationCallback(
                        delegate(object exceptionObj)
                        {
                            Exception exception = (Exception)exceptionObj; 
                            if (CriticalExceptions.IsCriticalException(exception))
                                throw exception; 
 
                            GetManifestCompletedEventArgs args = _getManifestCompletedEventArgs;
                            string version = null; 
                            if (exception is TrustNotGrantedException)
                            {
                                version = GetMissingCustomPermissionVersion(args.ApplicationManifest);
                                if (!string.IsNullOrEmpty(version)) 
                                {
                                    exception = new DependentPlatformMissingException(); 
                                } 
                            }
 
                            HandleError(exception, args.LogFilePath, args.SupportUri, version);
                            return null;
                        }), exception0);
                } 
            }
            return null; 
        } 

        ///  
        /// Critical: Calls a method on the SecurityCritical class CacheManager.
        /// TreatAsSafe: Starting the font cache service is safe. An application can do that indirectly
        ///     by using text services.
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        object StartFontCacheServiceAsync(object unused) 
        { 
            if (CheckAccess()) // initial call by Dispatcher?
            { // Do a callback to a thread-pool thread 
                DispatcherOperationCallback cb = new DispatcherOperationCallback(StartFontCacheServiceAsync);
                cb.BeginInvoke(null, null, null);
            }
            else // on a thread-pool thread 
            {
                // Note that an exception allowed to escape from here will be ----ed by the thread-pool manager. 
                // But that's okay in this scenario. 
                EventTrace.NormalTraceEvent(EventTraceGuidId.HOSTINGGUID, (byte)EventTrace.HostingEvent.StartingFontCacheServiceStart);
                MS.Internal.FontCache.CacheManager.GetServerCache(); 
                EventTrace.NormalTraceEvent(EventTraceGuidId.HOSTINGGUID, (byte)EventTrace.HostingEvent.StartingFontCacheServiceEnd);
            }
            return null;
        } 

        ///  
        /// Critical - calls TenFeetInstallationProgressPage, which lives in a non-APTCA assembly. 
        /// TreatAsSafe - demands appropriate permissions.
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        private void DoDownloadUI()
        {
            SecurityHelper.DemandUIWindowPermission(); 
            // ASSUMES ALREADY IN CORRECT CONTEXT
 
            // Note: The custom progress page support was provided for Media Center. Since MC has 
            // deprecated XBAP support, we'll likely counter-deprecate.
 
            bool usingCustomPage = true;
            if (_progressPageClass != null)
            {
                _progressPage = GetCustomPage(_progressPageAssembly, _progressPageClass) as IProgressPage; 
            }
            // If we failed to get a custom page, or didn't even try, use our default. 
            if (_progressPage == null) 
            {
                usingCustomPage = false; 
                Invariant.Assert(_nativeProgressPage != null);
                _progressPage = new NativeProgressPageProxy(_nativeProgressPage);
            }
 
            _progressPage.DeploymentPath = _deploymentManifest;
            _progressPage.StopCallback = new DispatcherOperationCallback(UserStop); 
            _progressPage.RefreshCallback = new DispatcherOperationCallback(UserRefresh); 

            // A "custom" page is a managed one. It needs to be loaded in the RootBrowserWindow. 
            // The RBW is not created in the default AppDomain otherwise. This is what saves significantly
            // from the startup time, especially on cold start.
            if (usingCustomPage)
            { 
                BrowserWindow.Navigate(_progressPage);
            } 
            else 
            {
                // Note: The native progress page may have been shown, due to the cold start heuristic. 
                _nativeProgressPage.Show();
                //Q: What ever hides the native progress page?
                //A: IBrowserCallbackServices.OnBeforeShowNavigationWindow() (in CColeDocument).
                //  This arrangement covers the RBW being shown in either AppDomain. (In the default AppDomain 
                //  we may have to show the deployment failed/canceled page or a custom progress page.)
            } 
        } 

        ///  
        /// The demand below was put here because although PresentationFramework has
        /// APTCA set, the assembly where _progressPage lives (PresentationUI) does not.
        /// Critical: 1) Because it is calling into non-aptca DLL
        ///     2) Calls the critical SetStatusText(). 
        /// TAS: 1) We demand permission
        ///     2) The status message is fixed, coming from a string table. ((1) is sufficient for TAS.) 
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        private void HandleError(Exception exception, string logFilePath, Uri supportUri, string requiredWpfVersion) 
        {
            SecurityHelper.DemandUIWindowPermission();

            ClearAsynchronousOperationStatus(); 

            // Delete the cached trust decision to force going down the full ClickOnce path next time 
            DeleteCachedApplicationTrust(_identity); 

            // If we are being shut down by the browser, don't do anything else. 
            if (IsShuttingDown)
            {
                AbortActivation();
                return; 
            }
 
            // ASSUMES ALREADY IN CORRECT CONTEXT 
            SetStatusText(SR.Get(SRID.HostingStatusFailed));
            string version = String.Empty; 
            MissingDependencyType getWinFXReq = MissingDependencyType.Others;

            if (exception is DependentPlatformMissingException)
            { 
                if (requiredWpfVersion != null)
                { 
                    getWinFXReq = MissingDependencyType.WinFX; 
                    version = requiredWpfVersion;
                    DeploymentExceptionMapper.ConstructFwlinkUrl(version, out _fwlinkUri); 
                }
                else
                {
                    getWinFXReq = DeploymentExceptionMapper.GetWinFXRequirement(exception, _hostingManager, out version, out _fwlinkUri); 
                }
            } 
 
            string errorTitle, errorMessage;
 
            switch(getWinFXReq)
            {
                case MissingDependencyType.WinFX:
                    // Wrong version of Avalon is installed. 
                    errorTitle = SR.Get(SRID.PlatformRequirementTitle);
                    errorMessage = SR.Get(SRID.IncompatibleWinFXText, version); 
                    break; 
                case MissingDependencyType.CLR:
                    // Missing CLR dependency 
                    errorTitle = SR.Get(SRID.PlatformRequirementTitle);
                    errorMessage = SR.Get(SRID.IncompatibleCLRText, version);
                    break;
                default: 
                    // All other deployment exceptions
                    DeploymentExceptionMapper.GetErrorTextFromException(exception, out errorTitle, out errorMessage); 
                    break; 
            }
 
            IErrorPage errorpage = null;

            if (_errorPageClass != null)
            { 
                errorpage = GetCustomPage(_errorPageAssembly, _errorPageClass) as IErrorPage;
            } 
            // If we failed to get a custom page, or didn't even try, use our default. 
            if (errorpage == null)
            { 
                //use default class
                errorpage = new InstallationErrorPage() as IErrorPage;
            }
 
            errorpage.DeploymentPath = _deploymentManifest;
            errorpage.ErrorTitle = errorTitle; 
            errorpage.ErrorText = errorMessage; 
            errorpage.SupportUri = supportUri;
            errorpage.LogFilePath = logFilePath; 
            errorpage.RefreshCallback = new DispatcherOperationCallback(UserRefresh);
            errorpage.GetWinFxCallback = (getWinFXReq != MissingDependencyType.Others)? new DispatcherOperationCallback(GetWinFX) : null;
            errorpage.ErrorFlag = true;
 
            BrowserWindow.Navigate(errorpage);
        } 
 
        /// 
        /// Critical - calls InstallationErrorPage, which lives in a non-APTCA assembly. 
        ///     _progressPage lives in a non-APTCA assembly.
        ///     Also calls the critical SetStatusText().
        /// TreatAsSafe - demands appropriate permissions.
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        private void HandleCancel() 
        { 
            SecurityHelper.DemandUIWindowPermission();
 
            // After _runApplication is set to true, we no longer allow canceling deployment.
            if (_cancelHandled || _runApplication)
                return;
            _cancelHandled = _canceled = true; 

            // Delete the cached trust decision to force going down the full ClickOnce path next time 
            DeleteCachedApplicationTrust(_identity); 

            // If we are being shut down by the browser, don't do anything else. 
            if (IsShuttingDown)
            {
                AbortActivation();
                return; 
            }
 
            CancelAsynchronousOperation(); 

            // ASSUMES ALREADY IN CORRECT CONTEXT 
            SetStatusText(SR.Get(SRID.HostingStatusCancelled));
            string errorTitle, errorMessage;
            DeploymentExceptionMapper.GetErrorTextFromException(null, out errorTitle, out errorMessage);
            IErrorPage errorpage = null; 
            //dont even try to use reflection if assembly name is null
            if (_errorPageAssembly != null || _errorPageClass != null) 
            { 
                errorpage = GetCustomPage(_errorPageAssembly, _errorPageClass) as IErrorPage;
            } 
            //if this is null then there is no custom page so fall back to default ui
            if (errorpage == null)
            {
                //use default class 
                errorpage = new InstallationErrorPage() as IErrorPage;
            } 
 
            errorpage.DeploymentPath = _deploymentManifest;
            errorpage.ErrorTitle = errorTitle; 
            errorpage.ErrorText = errorMessage;
            errorpage.SupportUri = null;
            errorpage.LogFilePath = null;
            errorpage.ErrorFlag = false; 
            errorpage.RefreshCallback = new DispatcherOperationCallback(UserRefresh);
            errorpage.GetWinFxCallback = null; 
 
            BrowserWindow.Navigate(errorpage);
        } 

        void DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
        {
            _bytesDownloaded = e.BytesDownloaded; 
            _bytesTotal = e.TotalBytesToDownload;
 
            if (!_updatePending) 
            {
                _updatePending = true; 
                Dispatcher.BeginInvoke(
                    DispatcherPriority.Background,
                    new DispatcherOperationCallback(DoDownloadProgressChanged),
                    null); 
            }
        } 
 
        /// 
        /// The demand below was put here because although PresentationFramework has 
        /// APTCA set, the assembly where _progressPage lives (PresentationUI) does not.
        /// 
        private object DoDownloadProgressChanged(object unused)
        { 
            if (EventTrace.IsEnabled(EventTrace.Flags.performance, EventTrace.Level.verbose))
            { 
                EventTrace.EventProvider.TraceEvent(EventTrace.Level.verbose, 
                    EventTrace.GuidFromId(EventTraceGuidId.HOSTINGGUID), (byte)EventTrace.HostingEvent.DownloadProgressUpdate, _bytesDownloaded, _bytesTotal);
            } 

            // !_isInAsynchronousOperation implies activation failed or was canceled.
            if (!_isInAsynchronousOperation || IsShuttingDown)
                return null; 
            Debug.Assert(!_canceled);
 
            SecurityHelper.DemandUIWindowPermission(); 

            if (_progressPage != null) 
            {
                _progressPage.UpdateProgress(_bytesDownloaded, _bytesTotal);
            }
            _updatePending = false; 

            return null; 
        } 

        void DownloadApplicationCompleted(object sender, DownloadApplicationCompletedEventArgs e) 
        {
            _hostingManager.DownloadProgressChanged -= new EventHandler(DownloadProgressChanged);
            Dispatcher.Invoke(
                DispatcherPriority.Send, 
                new DispatcherOperationCallback(DoDownloadApplicationCompleted),
                e); 
        } 

        ///  
        /// Critical: Calls the critical SetStatusText().
        /// TreatAsSafe: The status message is fixed, coming from a string table.
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        private object DoDownloadApplicationCompleted(object e)
        { 
            EventTrace.NormalTraceEvent(EventTraceGuidId.HOSTINGGUID, (byte)EventTrace.HostingEvent.DownloadApplicationEnd); 

            DownloadApplicationCompletedEventArgs args = (DownloadApplicationCompletedEventArgs)e; 

            // Race condition: UserStop() can be called after InPlaceHostingManager has completed
            // the downloading but before our callback is called.
            bool canceled = _canceled || args.Cancelled; 

            ClearAsynchronousOperationStatus(); 
            // Shutdown may have started and IBrowserCallbackServices may have become unavailable. 
            // In particular, making calls to the browser, just like above, could cause a pending shutdown
            // call to be dispatched. 
            if (IsShuttingDown)
                return null;

            if (args.Error != null) 
            {
                // IPHM.AssertApplicationRequirements() is called in parallel. If the worker thread catches 
                // an exception, it will do some analysis and call HandleError(). IPHM will also throw an 
                // exception to the main thread, which says AAR() failed. We need to ignore this exception.
                if (!_assertAppRequirementsFailed) 
                {
                    HandleError(args.Error, args.LogFilePath, _getManifestCompletedEventArgs.SupportUri, null);
                }
                return null; 
            }
 
            if (canceled) 
            {
                HandleCancel(); 
                return null;
            }

            SetStatusText(SR.Get(SRID.HostingStatusPreparingToRun)); 
            // This is the last progress message set. It is cleared by
            // IBrowserCallbackServices.OnBeforeShowNavigationWindow() (in CColeDocument). 
 
            // Go through the Dispatcher at a lower priority to allow the above status message to render.
            // There can be a signficant delay between the end of downloading and the rendering of the first 
            // application page, especially on cold start.
            Dispatcher.BeginInvoke(DispatcherPriority.Input, new DispatcherOperationCallback(
                delegate(object unused)
                { 
                    if (!IsCanceledOrShuttingDown)
                    { 
                        _applicationRunner = new DocObjHost.ApplicationRunner(ExecuteDownloadedApplication); 
                        _runApplication = true;
                        Shutdown(); 
                        // The Application.Exit event handler will continue...
                    }
                    return null;
                }), null); 

            return null; 
        } 

        private void ExecuteDownloadedApplication() 
        {
            if (EventTrace.IsEnabled(EventTrace.Flags.performance))
            {
                EventTrace.EventProvider.TraceEvent(EventTrace.GuidFromId(EventTraceGuidId.HOSTINGGUID), (byte)EventTrace.HostingEvent.ClickOnceActivationStart, KnownBoxes.BooleanBoxes.FalseBox); 
            }
 
            ObjectHandle oh = _hostingManager.Execute(); 
            if (PresentationAppDomainManager.SaveAppDomain)
            { 
                AppDomain newDomain = oh.Unwrap() as AppDomain;
                PresentationAppDomainManager.NewAppDomain = newDomain;
            }
 
            EventTrace.NormalTraceEvent(EventTraceGuidId.HOSTINGGUID, (byte)EventTrace.HostingEvent.ClickOnceActivationEnd);
        } 
 
        private object UserStop(object unused)
        { 
            UserStop();
            return null;
        }
        internal void UserStop() 
        {
            if (_isInAsynchronousOperation) 
            { 
                CancelAsynchronousOperation();
            } 
            else
            {
                HandleCancel();
            } 

        } 
 
        internal void AbortActivation()
        { 
            EventTrace.NormalTraceEvent(EventTraceGuidId.HOSTINGGUID, (byte)EventTrace.HostingEvent.AbortingActivation);

            CancelAsynchronousOperation();
            _runApplication = false; 
            Shutdown(ERROR_ACTIVATION_ABORTED);
        } 
 
        private void CancelAsynchronousOperation()
        { 
            lock (_lockObject)
            {
                if (_isInAsynchronousOperation)
                { 
                    Debug.Assert(!_canceled);
                    _canceled = true; 
                    Invariant.Assert(_hostingManager != null, "_hostingManager should not be null if _isInAsynchronousOperation is true"); 
                    _hostingManager.CancelAsync();
                    ClearAsynchronousOperationStatus(); 
                }
            }
        }
 
        private bool IsCanceledOrShuttingDown
        { 
            get 
            {
                Debug.Assert(!(_canceled && _isInAsynchronousOperation)); 
                return _canceled || IsShuttingDown;
            }
        }
 
        /// 
        ///     Critical: This code calls into RootBrowserWindow which is critical 
        ///     TreatAsSafe: There is a demand 
        /// 
        private RootBrowserWindow BrowserWindow 
        {
            [SecurityCritical,SecurityTreatAsSafe]
            get
            { 
                SecurityHelper.DemandUIWindowPermission();
                RootBrowserWindow rbw = (RootBrowserWindow)GetAppWindow(); 
                Invariant.Assert(rbw != null, "Should have instantiated RBW if it wasn't already there"); 
                rbw.ShowsNavigationUI = false; // not needed and not RightToLeft-enabled in this context
                return rbw; 
            }
        }

        private void CreateApplicationIdentity() 
        {
            _identity = null; 
            if (_applicationId != null) 
            {
                try 
                {
                    _identity = new ApplicationIdentity(_applicationId);
                }
                catch(Exception exception) 
                {
                    // Fatal error like NullReferenceException and SEHException should not be ignored. 
                    if (exception is NullReferenceException || exception is SEHException) 
                    {
                        throw; 
                    }

                    // For a non-critical exception, it can be ignored here.
                    // Because the code tries to make an ApplicationIdentity from a string in registry, 
                    // If it fails, it isn’t fatal, the code just needs to do activation from the deployment Uri.
 
                } 
            }
        } 

        /// 
        /// This is necessary as a workaround for various ClickOnce issues and the interaction
        /// between cached trust decisions and our direct activation shortcut. If there is a 
        /// cached trust decision for a given ApplicationIdentity, we will try the direct
        /// activation shortcut. If something goes wrong, we want to delete that cached trust 
        /// decision, so that next time we will be forced to go down the offical ClickOnce 
        /// deployment pathway.
        ///  
        ///
        ///     Critical: calls ApplicationTrustCollection.Remove which LinkDemands
        ///
        [SecurityCritical] 
        private void DeleteCachedApplicationTrust(ApplicationIdentity identity)
        { 
            if (identity != null) 
            {
                ApplicationTrust trust = new ApplicationTrust(identity); 
                // This does not throw if the trust isn't there.
                ApplicationSecurityManager.UserApplicationTrusts.Remove(trust);
            }
        } 

        /// 
        /// This function is private to xapplauncher. It invokes the default browser with Uri 
        /// to WinFXSetup.exe.  Its called from the "Install WinFX" button on the error page
        /// shown when an app requests a different version of WinFX than the one installed. 
        ///
        /// 
        /// Critical - Gets access to critical resource (uri and browsercallback services), calls critical
        /// code (launch browser). 
        /// TreatAsSafe - There exists a demand here.
        ///  
        [SecurityCritical, SecurityTreatAsSafe] 
        private object GetWinFX(object unused)
        { 
            SecurityHelper.DemandUnmanagedCode();

            AppSecurityManager.ShellExecuteDefaultBrowser(_fwlinkUri);
 
            return null;
        } 
 
        ///
        /// Critical - calls SetStatusText which is SUC'ed. 
        ///   There is a trend in newer browsers to restrict setting the status bar from partial-trust code
        ///   to prevent URL spoofing.
        ///
        [SecurityCritical] 
        private void SetStatusText(string newStatusText)
        { 
            IProgressPage2 pp2 = _progressPage as IProgressPage2; 
            if (pp2 != null)
            { 
                pp2.ShowProgressMessage(newStatusText);
            }
            _browser.SetStatusText(newStatusText);
        } 

        ///  
        /// If trust was not granted, it may have been because the assembly of a custom permission 
        /// could not be loaded. In this case, we are interested in custom permissions that are
        /// from WindowsBase. 
        /// 
        /// The XmlReader for the application manifest
        /// If the specified version of WindowsBase could not be loaded, the version, else null.
        private string GetMissingCustomPermissionVersion(XmlReader reader) 
        {
            string requiredVersion = null; 
 
            while (reader.ReadToFollowing("IPermission", "urn:schemas-microsoft-com:asm.v2"))
            { 
                string attr = reader.GetAttribute("class");

                // Strip the first item in the comma-delimited list, which is the permission class
                AssemblyName assyName = new AssemblyName(attr.Substring(attr.IndexOf(",",StringComparison.OrdinalIgnoreCase) + 1)); 
                if (assyName.Name.Equals("WindowsBase", StringComparison.OrdinalIgnoreCase))
                { 
                    try 
                    {
                        Assembly assy = Assembly.Load(assyName); 
                    }
                    catch (Exception e)
                    {
                        // This will give a FileLoadException under the debugger, but a FileNotFoundException otherwise 
                        if (e is System.IO.FileNotFoundException || e is System.IO.FileLoadException)
                        { 
                            requiredVersion = assyName.Version.ToString(); 
                            break;
                        } 
                        else
                        {
                            throw;
                        } 
                    }
                } 
            } 

            reader.Close(); 

            return requiredVersion;
        }
 
        InPlaceHostingManager _hostingManager;
        IBrowserCallbackServices _browser; 
        ApplicationIdentity _identity; 
        Uri _deploymentManifest;
        Uri _fwlinkUri; 
        string _applicationId;
        ActivationContext _context;
        DocObjHost.ApplicationRunnerCallback _applicationRunnerCallback;
        DocObjHost.ApplicationRunner _applicationRunner; 
        INativeProgressPage _nativeProgressPage;
        IProgressPage _progressPage; 
        bool _runApplication; 
        GetManifestCompletedEventArgs _getManifestCompletedEventArgs;
 
        const int ERROR_ACTIVATION_ABORTED = 30; // defined in host\inc\Definitions.hxx

        object _lockObject = new object();
 
        long _bytesDownloaded;
        long _bytesTotal; 
        bool _updatePending; 

        string _progressPageAssembly = null; 
        string _progressPageClass = null;
        string _errorPageAssembly = null;
        string _errorPageClass = null;
 
        bool _commandBindingsRegistered;
 
        bool _isInAsynchronousOperation; 
        volatile bool _canceled;
        bool _cancelHandled; 
        volatile bool _assertAppRequirementsFailed;
        bool _refreshing;
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
using System; 
using System.Deployment.Application;
using System.Runtime.Remoting;
using System.Security;
using System.Security.Policy; 
using System.Xml;
using System.Windows; 
using System.Windows.Controls; 
using System.Windows.Interop;
using System.Windows.Navigation; 
using System.Windows.Threading;
using System.Runtime.InteropServices;
using System.Diagnostics;
using MS.Internal; 
using MS.Internal.PresentationFramework;
using MS.Internal.Utility; 
using Microsoft.Internal.DeploymentUI; 
using Microsoft.Win32;
using System.Reflection; 
using MS.Utility;
using System.Windows.Input;
using System.Security.Permissions;
 
namespace MS.Internal.AppModel
{ 
    internal class XappLauncherApp : Application 
    {
        internal XappLauncherApp(Uri deploymentManifest, string applicationId, 
            IBrowserCallbackServices browser, DocObjHost.ApplicationRunnerCallback applicationRunner,
            INativeProgressPage nativeProgressPage,
            string progressPageAssembly, string progressPageClass, string errorPageAssembly, string errorPageClass)
        { 
            _deploymentManifest = deploymentManifest;
            _applicationId = applicationId; 
            _browser = browser; 
            _applicationRunnerCallback = applicationRunner;
            _fwlinkUri = null; 
            this.Startup += new StartupEventHandler(XappLauncherApp_Startup);
            this.Exit += new ExitEventHandler(XappLauncherApp_Exit);
            this.Navigated += new NavigatedEventHandler(XappLauncherApp_Navigated);
 
            _nativeProgressPage = nativeProgressPage;
            _progressPageAssembly = progressPageAssembly; 
            _progressPageClass = progressPageClass; 
            _errorPageAssembly = errorPageAssembly;
            _errorPageClass = errorPageClass; 
        }

        void OnCommandRefresh(object sender, RoutedEventArgs e)
        { 
            HandleRefresh();
        } 
 
        void OnCommandStop(object sender, RoutedEventArgs e)
        { 
            UserStop();
        }

        void XappLauncherApp_Startup(object sender, StartupEventArgs e) 
        {
            if (EventTrace.IsEnabled(EventTrace.Flags.performance, EventTrace.Level.verbose)) 
            { 
                EventTrace.EventProvider.TraceEvent(EventTrace.Level.verbose,
                    EventTrace.GuidFromId(EventTraceGuidId.HOSTINGGUID), (byte)EventTrace.HostingEvent.XappLauncherAppStartup); 
            }

            CreateApplicationIdentity();
            if (_identity != null) 
            {
                TryApplicationIdActivation(); 
            } 
            else
            { 
                TryUriActivation();
            }
        }
 
        void XappLauncherApp_Exit(object sender, ExitEventArgs e)
        { 
            if (EventTrace.IsEnabled(EventTrace.Flags.performance, EventTrace.Level.verbose)) 
            {
                EventTrace.EventProvider.TraceEvent(EventTrace.Level.verbose, 
                    EventTrace.GuidFromId(EventTraceGuidId.HOSTINGGUID), (byte)EventTrace.HostingEvent.XappLauncherAppExit, _runApplication);
            }

            Invariant.Assert(!_isInAsynchronousOperation, 
                "Async downloading should have been canceled before XappLauncherApp exits.");
 
            if (_runApplication) 
            {
                _applicationRunnerCallback(new DocObjHost.ApplicationRunner(_applicationRunner)); 
            }

            _browser = null;
            _applicationRunner = null; 
            _applicationRunnerCallback = null;
        } 
 

        /// 
        ///    Critical: This code calls into critical code GetAppWindow
        ///    TreatAsSafe: There exists a demand here
        ///
        [SecurityCritical, SecurityTreatAsSafe] 
        void XappLauncherApp_Navigated(object sender, NavigationEventArgs e)
        { 
            if (EventTrace.IsEnabled(EventTrace.Flags.performance, EventTrace.Level.verbose)) 
            {
                EventTrace.EventProvider.TraceEvent(EventTrace.Level.verbose, 
                    EventTrace.GuidFromId(EventTraceGuidId.HOSTINGGUID), (byte)EventTrace.HostingEvent.XappLauncherAppNavigated);
            }

            if (IsShuttingDown) 
                return;
 
            if (!_commandBindingsRegistered) 
            {
                _commandBindingsRegistered = true; 

                // These bindings handle the commands sent by the browser when the stop/refresh buttons are pressed. If nothing in the
                // page has focus, they will be sent directly to the window.
                // SP2 Update: DocObjHost.ExecCommand() now also handles these commands, either directly from 
                // the browser or from the native progress page.
                MainWindow.CommandBindings.Add(new CommandBinding(NavigationCommands.BrowseStop, new ExecutedRoutedEventHandler(OnCommandStop))); 
                MainWindow.CommandBindings.Add(new CommandBinding(NavigationCommands.Refresh, new ExecutedRoutedEventHandler(OnCommandRefresh))); 
            }
 
            SecurityHelper.DemandUIWindowPermission();
            NavigationWindow navWin = GetAppWindow();
            Invariant.Assert(navWin != null, "A RootBrowserWindow should have been created.");
            while (navWin.CanGoBack) 
            {
                navWin.RemoveBackEntry(); 
            } 
        }
 
        void StartAsynchronousOperation()
        {
            Debug.Assert(!_isInAsynchronousOperation && !IsCanceledOrShuttingDown);
            _isInAsynchronousOperation = true; 
            ChangeBrowserDownloadState(_isInAsynchronousOperation);
        } 
 
        void ClearAsynchronousOperationStatus()
        { 
            _isInAsynchronousOperation = false;
            ChangeBrowserDownloadState(_isInAsynchronousOperation);
        }
 

        private object UserRefresh(object unused) 
        { 
            HandleRefresh();
            return null; 
        }

        internal override void PerformNavigationStateChangeTasks(
            bool isNavigationInitiator, bool playNavigatingSound, NavigationStateChange state) 
        {
            // Do not play sounds or start and stop the globe on when navigations 
            // occur because the progress page is merely an enhanced visual experience 
            // during the actual navigation to the application.  Conceptually it  should
            // appear as something that happens during navigation and not a series of 
            // discrete navigations.

            // We do need to ensure that the Stop and Refresh buttons are in the correct state
            // while downloading the app. 
            if (isNavigationInitiator && state == NavigationStateChange.Completed)
            { 
                UpdateBrowserCommands(); 
            }
        } 

        // This function gets called when the browser refresh button in clicked.
        // This'll cause the browser to navigate the address bar
        /// 
        ///  Critical: Accesses BrowserCallbackServices to navigate
        ///  TreatAsSafe: only navigates to a safe, already validated _deploymentManifest. 
        ///  Potentially, this could be a DOS attack FOR THE APP ONLY if refresh was called constantly, but that is 
        ///  below the bar for critical code progagation, as the user can recover and the system is not destabilized.
        /// 
        [SecurityCritical, SecurityTreatAsSafe]
        internal void HandleRefresh()
        {
            lock (_lockObject) // we do this in case the refresh button is getting clicked rapidly, before the navigation happens 
            {
                if (!_refreshing) 
                { 
                    _refreshing = true;
                    BrowserCallbackServices.DelegateNavigation(_deploymentManifest.ToString(), null, null); 
                }
            }
        }
 
        /// 
        /// Critical: Calls IBrowserCallbackServices.ChangeDownloadState which is critical 
        /// TreatAsSafe: Changing the download state is safe 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        private void ChangeBrowserDownloadState(bool newState)
        {
            // start or stop waving the flag
            // When shutting down, which may happen during deployment, IBrowserCallbackServices may become 
            // unavailable. Calling ChangeBrowserDownloadState(false) should not trigger an exception then.
            try 
            { 
                _browser.ChangeDownloadState(newState);
            } 
            catch (COMException)
            {
                if (newState || !IsShuttingDown)
                    throw; 
            }
            catch (InvalidOperationException) 
            { 
                if (newState || !IsShuttingDown)
                    throw; 
            }
        }

        private void TryApplicationIdActivation() 
        {
            Dispatcher.Invoke( 
                DispatcherPriority.Input, 
                new DispatcherOperationCallback(DoDirectActivation),
                null); 
        }

        private void TryUriActivation()
        { 
            EventTrace.NormalTraceEvent(EventTraceGuidId.HOSTINGGUID, (byte)EventTrace.HostingEvent.FirstTimeActivation);
 
            _hostingManager = new InPlaceHostingManager(_deploymentManifest); 

            // Ordering is important here - downloading the manifest is done asynchronously 
            // so can be started before we spend time setting up the UI.  This saves us some
            // time - especially during cold-start scenarios.

            // Calling it through the dispatcher makes sure the right context and exception 
            // handling is used.  DispatcherPriority.Send has it executed synchronously.
            Dispatcher.Invoke( 
                DispatcherPriority.Send, 
                new DispatcherOperationCallback(DoGetManifestAsync),
                null); 

            DoDownloadUI();
        }
 
        ///
        ///     Critical: calls ApplicationTrustCollection.Item which LinkDemands 
        ///     TreatAsSafe: Caller can't hand in an arbitrary item string 
        ///
        [SecurityCritical, SecurityTreatAsSafe] 
        private object DoDirectActivation(object unused)
        {
            if (IsCanceledOrShuttingDown)
                return null; 

            try 
            { 
                // Verify that this app is actually cached. This is because the call to
                // CreatePartialActivationContext can succeed when we don't want it to; 
                // it appears to be insensitive to some parts of the ApplicationIdentity,
                // or it tries to make things work when they really should fail. Looking
                // at the UserApplicationTrusts does a better comparison.
                if (ApplicationSecurityManager.UserApplicationTrusts[_identity.ToString()] != null) 
                {
                    _context = ActivationContext.CreatePartialActivationContext(_identity); 
                    _applicationRunner = new DocObjHost.ApplicationRunner(ExecuteDirectApplication); 
                    _runApplication = true;
                    this.Shutdown(); 
                }
                else
                {
                    TryUriActivation(); 
                }
            } 
            catch(Exception exception) 
            {
                // Delete the cached trust decision to force going down the full ClickOnce path next time 
                DeleteCachedApplicationTrust(_identity);

                // Fatal error like NullReferenceException and SEHException should not be ignored.
                if (exception is NullReferenceException || exception is SEHException) 
                {
                    throw; 
                } 
                else
                { 
                    TryUriActivation();
                }
            }
 
            return null;
        } 
 
        ///
        ///    Critical: This code calls into critical code which has link demand (Activator.CreateInstance) 
        ///    TreatAsSafe: There exists a demand here
        ///
        [SecurityCritical, SecurityTreatAsSafe]
        private void ExecuteDirectApplication() 
        {
            SecurityHelper.DemandUnmanagedCode(); 
            try 
            {
                if (EventTrace.IsEnabled(EventTrace.Flags.performance)) 
                {
                    EventTrace.EventProvider.TraceEvent(EventTrace.GuidFromId(EventTraceGuidId.HOSTINGGUID), (byte)EventTrace.HostingEvent.ClickOnceActivationStart, KnownBoxes.BooleanBoxes.TrueBox);
                }
                ObjectHandle oh = Activator.CreateInstance(_context); 
                if (PresentationAppDomainManager.SaveAppDomain)
                { 
                    AppDomain newDomain = oh.Unwrap() as AppDomain; 
                    PresentationAppDomainManager.NewAppDomain = newDomain;
                } 

                EventTrace.NormalTraceEvent(EventTraceGuidId.HOSTINGGUID, (byte)EventTrace.HostingEvent.ClickOnceActivationEnd);
            }
            catch (Exception exception) 
            {
                // Delete the cached trust decision to force going down the full ClickOnce path next time 
                DeleteCachedApplicationTrust(_identity); 

                // Fatal error like NullReferenceException and SEHException should not be ignored. 
                if (exception is NullReferenceException || exception is SEHException)
                {
                    throw;
                } 
                else
                { 
                    TryUriActivation(); 
                }
            } 
        }

        /// 
        /// Critical: Calls the critical SetStatusText(). 
        /// TreatAsSafe: The status message is fixed, coming from a string table.
        ///  
        [SecurityCritical, SecurityTreatAsSafe] 
        private object DoGetManifestAsync(object notUsed)
        { 
            if (IsCanceledOrShuttingDown)
                return null;

            EventTrace.NormalTraceEvent(EventTraceGuidId.HOSTINGGUID, (byte)EventTrace.HostingEvent.DownloadDeplManifestStart); 

            StartAsynchronousOperation(); 
            SetStatusText(SR.Get(SRID.HostingStatusDownloadAppInfo)); 

            _hostingManager.GetManifestCompleted += new EventHandler(GetManifestCompleted); 
            // Possible reentrancy! When making the outgoing calls to the browser to update its
            // status (above), a pending incoming call can be dispatched. This may be OLECMDID_STOP,
            // which would lead to calling UserStop(), which makes IPHM unusable.
            if (!IsCanceledOrShuttingDown) 
            {
                Debug.Assert(_isInAsynchronousOperation); 
                _hostingManager.GetManifestAsync(); 
            }
            return null; 
        }

        private object GetCustomPage(string pageAssemblyName, string pageClassName)
        { 
            if (EventTrace.IsEnabled(EventTrace.Flags.performance, EventTrace.Level.verbose))
            { 
                EventTrace.EventProvider.TraceEvent(EventTrace.Level.verbose, 
                    EventTrace.GuidFromId(EventTraceGuidId.HOSTINGGUID), (byte)EventTrace.HostingEvent.GetDownloadPageStart, pageClassName);
            } 
            object customPage;
            try
            {
                // Uses custom progress page 
                // If the assembly is not specified, use PresentationUI.
                Assembly customPageAssembly = string.IsNullOrEmpty(pageAssemblyName) ? typeof(TenFeetInstallationProgress).Assembly : Assembly.Load(pageAssemblyName); 
                customPage = customPageAssembly.CreateInstance(pageClassName); 
            }
            catch 
            {
                customPage = null;
            }
            if (EventTrace.IsEnabled(EventTrace.Flags.performance, EventTrace.Level.verbose)) 
            {
                EventTrace.EventProvider.TraceEvent(EventTrace.Level.verbose, 
                    EventTrace.GuidFromId(EventTraceGuidId.HOSTINGGUID), (byte)EventTrace.HostingEvent.GetDownloadPageEnd); 
            }
            return customPage; 
        }

        void GetManifestCompleted(object sender, GetManifestCompletedEventArgs e)
        { 
            Dispatcher.Invoke(
                DispatcherPriority.Send, 
                new DispatcherOperationCallback(DoGetManifestCompleted), 
                e);
        } 

        private object DoGetManifestCompleted(object e)
        {
            EventTrace.NormalTraceEvent(EventTraceGuidId.HOSTINGGUID, (byte)EventTrace.HostingEvent.DownloadDeplManifestEnd); 

            GetManifestCompletedEventArgs args = (GetManifestCompletedEventArgs)e; 
            _getManifestCompletedEventArgs = args; 

            // Race condition: UserStop() can be called after InPlaceHostingManager has completed 
            // the manifest downloading but before this callback is called.
            bool canceled = _canceled || args.Cancelled;

            ClearAsynchronousOperationStatus(); 

            if (IsShuttingDown) 
                return null; 
            if (args.Error != null)
            { 
                // If the async operation failed, it is invalid to request the
                // SupportUri so we simply pass in null.
                HandleError(args.Error, args.LogFilePath, null, null);
                return null; 
            }
            if (canceled) 
            { 
                HandleCancel();
                return null; 
            }

            // args.ApplicationIdentity throws if the operation has been canceled. That's why the above check has
            // to come first. 
            _identity = args.ApplicationIdentity;
 
            if (_progressPage != null) 
            {
                _progressPage.ApplicationName = args.ProductName; 

                // GetManifestCompletedEventArgs.PublisherName doesn't exist.
                // DevDiv bug 166088 tracks this.
                // The retrieval below takes surprisingly little time: < 1 ms. 
                XmlReader rdr = args.DeploymentManifest;
                rdr.MoveToContent(); 
                if (rdr.LocalName == "assembly") 
                {
                    rdr.ReadStartElement(); 
                    while(rdr.NodeType != XmlNodeType.EndElement)
                    {
                        if(rdr.LocalName == "description")
                        { 
                            string publisher = rdr.GetAttribute("publisher", "urn:schemas-microsoft-com:asm.v2");
                            if (!string.IsNullOrEmpty(publisher)) 
                            { 
                                _progressPage.PublisherName = publisher;
                            } 
                            break;
                        }
                        rdr.Skip();
                    } 
                }
            } 
 
            //
            // Start asynchronous application downloading 
            //
            EventTrace.NormalTraceEvent(EventTraceGuidId.HOSTINGGUID, (byte)EventTrace.HostingEvent.DownloadApplicationStart);
            ShowDownloadingStatusMessage();
            StartAsynchronousOperation(); 
            // Possible reentrancy! When making the outgoing calls to the browser to update its
            // status (above), a pending incoming call can be dispatched. This may be OLECMDID_STOP, 
            // which would lead to calling UserStop(), which makes IPHM unusable. 
            if (IsCanceledOrShuttingDown)
                return null; 
            _hostingManager.DownloadProgressChanged += new EventHandler(DownloadProgressChanged);
            _hostingManager.DownloadApplicationCompleted += new EventHandler(DownloadApplicationCompleted);
            _hostingManager.DownloadApplicationAsync();
 
            // Cold-start optimization: While async downloading is underway, do AssertApplicationRequirements.
            // AAR takes 0.8-1.5+ seconds on cold start because it loads all assemblies from which permission 
            // types are referenced. 
            Dispatcher.BeginInvoke(DispatcherPriority.Input,
                new DispatcherOperationCallback(AssertApplicationRequirementsAsync), null); 

            // Cold-start optimization: While we are network-bound, use the CPU and disk to start PFC.
            // This takes up to 2 seconds on Windows XP (it's faster on Vista).
            Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, 
                new DispatcherOperationCallback(StartFontCacheServiceAsync), null);
 
            return null; 
        }
 
        /// 
        /// Critical: Calls the critical SetStatusText().
        /// TreatAsSafe: The status message is fixed, coming from a string table.
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        void ShowDownloadingStatusMessage() 
        { 
            SetStatusText(SR.Get(SRID.HostingStatusDownloadApp));
        } 

        /// 
        /// Critical: Calls the critical SetStatusText().
        /// TreatAsSafe: The status message is fixed, coming from a string table. 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        object AssertApplicationRequirementsAsync(object unused) 
        {
            if (IsCanceledOrShuttingDown) 
                return null;

            if (CheckAccess()) // initial call by Dispatcher?
            { // Do a callback to a thread-pool thread 
                // Status bar is set on the main thread (here) to avoid switching.
                SetStatusText(SR.Get(SRID.HostingStatusVerifying)); 
                DispatcherOperationCallback cb = new DispatcherOperationCallback(AssertApplicationRequirementsAsync); 
                cb.BeginInvoke(null, null, null);
            } 
            else // on a thread-pool thread
            {
                try
                { 
                    if (EventTrace.IsEnabled(EventTrace.Flags.performance, EventTrace.Level.verbose))
                    { 
                        EventTrace.EventProvider.TraceEvent( 
                            EventTrace.GuidFromId(EventTraceGuidId.HOSTINGGUID), (byte)EventTrace.HostingEvent.AssertAppRequirementsStart);
                    } 

                    _hostingManager.AssertApplicationRequirements();

                    if (EventTrace.IsEnabled(EventTrace.Flags.performance, EventTrace.Level.verbose)) 
                    {
                        EventTrace.EventProvider.TraceEvent( 
                            EventTrace.GuidFromId(EventTraceGuidId.HOSTINGGUID), (byte)EventTrace.HostingEvent.AssertAppRequirementsEnd); 
                    }
 
                    // Switch to the main thread to update the status message. This is necessary because the
                    // native IBCS and INativeProgressPage interfaces are not marshalable.
                    Dispatcher.BeginInvoke(DispatcherPriority.Normal, new DispatcherOperationCallback(
                        delegate(object unused3) 
                        {
                            if (_isInAsynchronousOperation) 
                            { 
                                ShowDownloadingStatusMessage();
                            } 
                            return null;
                        }), null);
                }
                catch (Exception exception0) 
                {
                    _assertAppRequirementsFailed = true; 
 
                    // Note that an exception allowed to escape from here will be ----ed by the thread-pool manager.
                    // That's why all further processing is moved to the main thread. 
                    Dispatcher.BeginInvoke(DispatcherPriority.Send, new DispatcherOperationCallback(
                        delegate(object exceptionObj)
                        {
                            Exception exception = (Exception)exceptionObj; 
                            if (CriticalExceptions.IsCriticalException(exception))
                                throw exception; 
 
                            GetManifestCompletedEventArgs args = _getManifestCompletedEventArgs;
                            string version = null; 
                            if (exception is TrustNotGrantedException)
                            {
                                version = GetMissingCustomPermissionVersion(args.ApplicationManifest);
                                if (!string.IsNullOrEmpty(version)) 
                                {
                                    exception = new DependentPlatformMissingException(); 
                                } 
                            }
 
                            HandleError(exception, args.LogFilePath, args.SupportUri, version);
                            return null;
                        }), exception0);
                } 
            }
            return null; 
        } 

        ///  
        /// Critical: Calls a method on the SecurityCritical class CacheManager.
        /// TreatAsSafe: Starting the font cache service is safe. An application can do that indirectly
        ///     by using text services.
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        object StartFontCacheServiceAsync(object unused) 
        { 
            if (CheckAccess()) // initial call by Dispatcher?
            { // Do a callback to a thread-pool thread 
                DispatcherOperationCallback cb = new DispatcherOperationCallback(StartFontCacheServiceAsync);
                cb.BeginInvoke(null, null, null);
            }
            else // on a thread-pool thread 
            {
                // Note that an exception allowed to escape from here will be ----ed by the thread-pool manager. 
                // But that's okay in this scenario. 
                EventTrace.NormalTraceEvent(EventTraceGuidId.HOSTINGGUID, (byte)EventTrace.HostingEvent.StartingFontCacheServiceStart);
                MS.Internal.FontCache.CacheManager.GetServerCache(); 
                EventTrace.NormalTraceEvent(EventTraceGuidId.HOSTINGGUID, (byte)EventTrace.HostingEvent.StartingFontCacheServiceEnd);
            }
            return null;
        } 

        ///  
        /// Critical - calls TenFeetInstallationProgressPage, which lives in a non-APTCA assembly. 
        /// TreatAsSafe - demands appropriate permissions.
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        private void DoDownloadUI()
        {
            SecurityHelper.DemandUIWindowPermission(); 
            // ASSUMES ALREADY IN CORRECT CONTEXT
 
            // Note: The custom progress page support was provided for Media Center. Since MC has 
            // deprecated XBAP support, we'll likely counter-deprecate.
 
            bool usingCustomPage = true;
            if (_progressPageClass != null)
            {
                _progressPage = GetCustomPage(_progressPageAssembly, _progressPageClass) as IProgressPage; 
            }
            // If we failed to get a custom page, or didn't even try, use our default. 
            if (_progressPage == null) 
            {
                usingCustomPage = false; 
                Invariant.Assert(_nativeProgressPage != null);
                _progressPage = new NativeProgressPageProxy(_nativeProgressPage);
            }
 
            _progressPage.DeploymentPath = _deploymentManifest;
            _progressPage.StopCallback = new DispatcherOperationCallback(UserStop); 
            _progressPage.RefreshCallback = new DispatcherOperationCallback(UserRefresh); 

            // A "custom" page is a managed one. It needs to be loaded in the RootBrowserWindow. 
            // The RBW is not created in the default AppDomain otherwise. This is what saves significantly
            // from the startup time, especially on cold start.
            if (usingCustomPage)
            { 
                BrowserWindow.Navigate(_progressPage);
            } 
            else 
            {
                // Note: The native progress page may have been shown, due to the cold start heuristic. 
                _nativeProgressPage.Show();
                //Q: What ever hides the native progress page?
                //A: IBrowserCallbackServices.OnBeforeShowNavigationWindow() (in CColeDocument).
                //  This arrangement covers the RBW being shown in either AppDomain. (In the default AppDomain 
                //  we may have to show the deployment failed/canceled page or a custom progress page.)
            } 
        } 

        ///  
        /// The demand below was put here because although PresentationFramework has
        /// APTCA set, the assembly where _progressPage lives (PresentationUI) does not.
        /// Critical: 1) Because it is calling into non-aptca DLL
        ///     2) Calls the critical SetStatusText(). 
        /// TAS: 1) We demand permission
        ///     2) The status message is fixed, coming from a string table. ((1) is sufficient for TAS.) 
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        private void HandleError(Exception exception, string logFilePath, Uri supportUri, string requiredWpfVersion) 
        {
            SecurityHelper.DemandUIWindowPermission();

            ClearAsynchronousOperationStatus(); 

            // Delete the cached trust decision to force going down the full ClickOnce path next time 
            DeleteCachedApplicationTrust(_identity); 

            // If we are being shut down by the browser, don't do anything else. 
            if (IsShuttingDown)
            {
                AbortActivation();
                return; 
            }
 
            // ASSUMES ALREADY IN CORRECT CONTEXT 
            SetStatusText(SR.Get(SRID.HostingStatusFailed));
            string version = String.Empty; 
            MissingDependencyType getWinFXReq = MissingDependencyType.Others;

            if (exception is DependentPlatformMissingException)
            { 
                if (requiredWpfVersion != null)
                { 
                    getWinFXReq = MissingDependencyType.WinFX; 
                    version = requiredWpfVersion;
                    DeploymentExceptionMapper.ConstructFwlinkUrl(version, out _fwlinkUri); 
                }
                else
                {
                    getWinFXReq = DeploymentExceptionMapper.GetWinFXRequirement(exception, _hostingManager, out version, out _fwlinkUri); 
                }
            } 
 
            string errorTitle, errorMessage;
 
            switch(getWinFXReq)
            {
                case MissingDependencyType.WinFX:
                    // Wrong version of Avalon is installed. 
                    errorTitle = SR.Get(SRID.PlatformRequirementTitle);
                    errorMessage = SR.Get(SRID.IncompatibleWinFXText, version); 
                    break; 
                case MissingDependencyType.CLR:
                    // Missing CLR dependency 
                    errorTitle = SR.Get(SRID.PlatformRequirementTitle);
                    errorMessage = SR.Get(SRID.IncompatibleCLRText, version);
                    break;
                default: 
                    // All other deployment exceptions
                    DeploymentExceptionMapper.GetErrorTextFromException(exception, out errorTitle, out errorMessage); 
                    break; 
            }
 
            IErrorPage errorpage = null;

            if (_errorPageClass != null)
            { 
                errorpage = GetCustomPage(_errorPageAssembly, _errorPageClass) as IErrorPage;
            } 
            // If we failed to get a custom page, or didn't even try, use our default. 
            if (errorpage == null)
            { 
                //use default class
                errorpage = new InstallationErrorPage() as IErrorPage;
            }
 
            errorpage.DeploymentPath = _deploymentManifest;
            errorpage.ErrorTitle = errorTitle; 
            errorpage.ErrorText = errorMessage; 
            errorpage.SupportUri = supportUri;
            errorpage.LogFilePath = logFilePath; 
            errorpage.RefreshCallback = new DispatcherOperationCallback(UserRefresh);
            errorpage.GetWinFxCallback = (getWinFXReq != MissingDependencyType.Others)? new DispatcherOperationCallback(GetWinFX) : null;
            errorpage.ErrorFlag = true;
 
            BrowserWindow.Navigate(errorpage);
        } 
 
        /// 
        /// Critical - calls InstallationErrorPage, which lives in a non-APTCA assembly. 
        ///     _progressPage lives in a non-APTCA assembly.
        ///     Also calls the critical SetStatusText().
        /// TreatAsSafe - demands appropriate permissions.
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        private void HandleCancel() 
        { 
            SecurityHelper.DemandUIWindowPermission();
 
            // After _runApplication is set to true, we no longer allow canceling deployment.
            if (_cancelHandled || _runApplication)
                return;
            _cancelHandled = _canceled = true; 

            // Delete the cached trust decision to force going down the full ClickOnce path next time 
            DeleteCachedApplicationTrust(_identity); 

            // If we are being shut down by the browser, don't do anything else. 
            if (IsShuttingDown)
            {
                AbortActivation();
                return; 
            }
 
            CancelAsynchronousOperation(); 

            // ASSUMES ALREADY IN CORRECT CONTEXT 
            SetStatusText(SR.Get(SRID.HostingStatusCancelled));
            string errorTitle, errorMessage;
            DeploymentExceptionMapper.GetErrorTextFromException(null, out errorTitle, out errorMessage);
            IErrorPage errorpage = null; 
            //dont even try to use reflection if assembly name is null
            if (_errorPageAssembly != null || _errorPageClass != null) 
            { 
                errorpage = GetCustomPage(_errorPageAssembly, _errorPageClass) as IErrorPage;
            } 
            //if this is null then there is no custom page so fall back to default ui
            if (errorpage == null)
            {
                //use default class 
                errorpage = new InstallationErrorPage() as IErrorPage;
            } 
 
            errorpage.DeploymentPath = _deploymentManifest;
            errorpage.ErrorTitle = errorTitle; 
            errorpage.ErrorText = errorMessage;
            errorpage.SupportUri = null;
            errorpage.LogFilePath = null;
            errorpage.ErrorFlag = false; 
            errorpage.RefreshCallback = new DispatcherOperationCallback(UserRefresh);
            errorpage.GetWinFxCallback = null; 
 
            BrowserWindow.Navigate(errorpage);
        } 

        void DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
        {
            _bytesDownloaded = e.BytesDownloaded; 
            _bytesTotal = e.TotalBytesToDownload;
 
            if (!_updatePending) 
            {
                _updatePending = true; 
                Dispatcher.BeginInvoke(
                    DispatcherPriority.Background,
                    new DispatcherOperationCallback(DoDownloadProgressChanged),
                    null); 
            }
        } 
 
        /// 
        /// The demand below was put here because although PresentationFramework has 
        /// APTCA set, the assembly where _progressPage lives (PresentationUI) does not.
        /// 
        private object DoDownloadProgressChanged(object unused)
        { 
            if (EventTrace.IsEnabled(EventTrace.Flags.performance, EventTrace.Level.verbose))
            { 
                EventTrace.EventProvider.TraceEvent(EventTrace.Level.verbose, 
                    EventTrace.GuidFromId(EventTraceGuidId.HOSTINGGUID), (byte)EventTrace.HostingEvent.DownloadProgressUpdate, _bytesDownloaded, _bytesTotal);
            } 

            // !_isInAsynchronousOperation implies activation failed or was canceled.
            if (!_isInAsynchronousOperation || IsShuttingDown)
                return null; 
            Debug.Assert(!_canceled);
 
            SecurityHelper.DemandUIWindowPermission(); 

            if (_progressPage != null) 
            {
                _progressPage.UpdateProgress(_bytesDownloaded, _bytesTotal);
            }
            _updatePending = false; 

            return null; 
        } 

        void DownloadApplicationCompleted(object sender, DownloadApplicationCompletedEventArgs e) 
        {
            _hostingManager.DownloadProgressChanged -= new EventHandler(DownloadProgressChanged);
            Dispatcher.Invoke(
                DispatcherPriority.Send, 
                new DispatcherOperationCallback(DoDownloadApplicationCompleted),
                e); 
        } 

        ///  
        /// Critical: Calls the critical SetStatusText().
        /// TreatAsSafe: The status message is fixed, coming from a string table.
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        private object DoDownloadApplicationCompleted(object e)
        { 
            EventTrace.NormalTraceEvent(EventTraceGuidId.HOSTINGGUID, (byte)EventTrace.HostingEvent.DownloadApplicationEnd); 

            DownloadApplicationCompletedEventArgs args = (DownloadApplicationCompletedEventArgs)e; 

            // Race condition: UserStop() can be called after InPlaceHostingManager has completed
            // the downloading but before our callback is called.
            bool canceled = _canceled || args.Cancelled; 

            ClearAsynchronousOperationStatus(); 
            // Shutdown may have started and IBrowserCallbackServices may have become unavailable. 
            // In particular, making calls to the browser, just like above, could cause a pending shutdown
            // call to be dispatched. 
            if (IsShuttingDown)
                return null;

            if (args.Error != null) 
            {
                // IPHM.AssertApplicationRequirements() is called in parallel. If the worker thread catches 
                // an exception, it will do some analysis and call HandleError(). IPHM will also throw an 
                // exception to the main thread, which says AAR() failed. We need to ignore this exception.
                if (!_assertAppRequirementsFailed) 
                {
                    HandleError(args.Error, args.LogFilePath, _getManifestCompletedEventArgs.SupportUri, null);
                }
                return null; 
            }
 
            if (canceled) 
            {
                HandleCancel(); 
                return null;
            }

            SetStatusText(SR.Get(SRID.HostingStatusPreparingToRun)); 
            // This is the last progress message set. It is cleared by
            // IBrowserCallbackServices.OnBeforeShowNavigationWindow() (in CColeDocument). 
 
            // Go through the Dispatcher at a lower priority to allow the above status message to render.
            // There can be a signficant delay between the end of downloading and the rendering of the first 
            // application page, especially on cold start.
            Dispatcher.BeginInvoke(DispatcherPriority.Input, new DispatcherOperationCallback(
                delegate(object unused)
                { 
                    if (!IsCanceledOrShuttingDown)
                    { 
                        _applicationRunner = new DocObjHost.ApplicationRunner(ExecuteDownloadedApplication); 
                        _runApplication = true;
                        Shutdown(); 
                        // The Application.Exit event handler will continue...
                    }
                    return null;
                }), null); 

            return null; 
        } 

        private void ExecuteDownloadedApplication() 
        {
            if (EventTrace.IsEnabled(EventTrace.Flags.performance))
            {
                EventTrace.EventProvider.TraceEvent(EventTrace.GuidFromId(EventTraceGuidId.HOSTINGGUID), (byte)EventTrace.HostingEvent.ClickOnceActivationStart, KnownBoxes.BooleanBoxes.FalseBox); 
            }
 
            ObjectHandle oh = _hostingManager.Execute(); 
            if (PresentationAppDomainManager.SaveAppDomain)
            { 
                AppDomain newDomain = oh.Unwrap() as AppDomain;
                PresentationAppDomainManager.NewAppDomain = newDomain;
            }
 
            EventTrace.NormalTraceEvent(EventTraceGuidId.HOSTINGGUID, (byte)EventTrace.HostingEvent.ClickOnceActivationEnd);
        } 
 
        private object UserStop(object unused)
        { 
            UserStop();
            return null;
        }
        internal void UserStop() 
        {
            if (_isInAsynchronousOperation) 
            { 
                CancelAsynchronousOperation();
            } 
            else
            {
                HandleCancel();
            } 

        } 
 
        internal void AbortActivation()
        { 
            EventTrace.NormalTraceEvent(EventTraceGuidId.HOSTINGGUID, (byte)EventTrace.HostingEvent.AbortingActivation);

            CancelAsynchronousOperation();
            _runApplication = false; 
            Shutdown(ERROR_ACTIVATION_ABORTED);
        } 
 
        private void CancelAsynchronousOperation()
        { 
            lock (_lockObject)
            {
                if (_isInAsynchronousOperation)
                { 
                    Debug.Assert(!_canceled);
                    _canceled = true; 
                    Invariant.Assert(_hostingManager != null, "_hostingManager should not be null if _isInAsynchronousOperation is true"); 
                    _hostingManager.CancelAsync();
                    ClearAsynchronousOperationStatus(); 
                }
            }
        }
 
        private bool IsCanceledOrShuttingDown
        { 
            get 
            {
                Debug.Assert(!(_canceled && _isInAsynchronousOperation)); 
                return _canceled || IsShuttingDown;
            }
        }
 
        /// 
        ///     Critical: This code calls into RootBrowserWindow which is critical 
        ///     TreatAsSafe: There is a demand 
        /// 
        private RootBrowserWindow BrowserWindow 
        {
            [SecurityCritical,SecurityTreatAsSafe]
            get
            { 
                SecurityHelper.DemandUIWindowPermission();
                RootBrowserWindow rbw = (RootBrowserWindow)GetAppWindow(); 
                Invariant.Assert(rbw != null, "Should have instantiated RBW if it wasn't already there"); 
                rbw.ShowsNavigationUI = false; // not needed and not RightToLeft-enabled in this context
                return rbw; 
            }
        }

        private void CreateApplicationIdentity() 
        {
            _identity = null; 
            if (_applicationId != null) 
            {
                try 
                {
                    _identity = new ApplicationIdentity(_applicationId);
                }
                catch(Exception exception) 
                {
                    // Fatal error like NullReferenceException and SEHException should not be ignored. 
                    if (exception is NullReferenceException || exception is SEHException) 
                    {
                        throw; 
                    }

                    // For a non-critical exception, it can be ignored here.
                    // Because the code tries to make an ApplicationIdentity from a string in registry, 
                    // If it fails, it isn’t fatal, the code just needs to do activation from the deployment Uri.
 
                } 
            }
        } 

        /// 
        /// This is necessary as a workaround for various ClickOnce issues and the interaction
        /// between cached trust decisions and our direct activation shortcut. If there is a 
        /// cached trust decision for a given ApplicationIdentity, we will try the direct
        /// activation shortcut. If something goes wrong, we want to delete that cached trust 
        /// decision, so that next time we will be forced to go down the offical ClickOnce 
        /// deployment pathway.
        ///  
        ///
        ///     Critical: calls ApplicationTrustCollection.Remove which LinkDemands
        ///
        [SecurityCritical] 
        private void DeleteCachedApplicationTrust(ApplicationIdentity identity)
        { 
            if (identity != null) 
            {
                ApplicationTrust trust = new ApplicationTrust(identity); 
                // This does not throw if the trust isn't there.
                ApplicationSecurityManager.UserApplicationTrusts.Remove(trust);
            }
        } 

        /// 
        /// This function is private to xapplauncher. It invokes the default browser with Uri 
        /// to WinFXSetup.exe.  Its called from the "Install WinFX" button on the error page
        /// shown when an app requests a different version of WinFX than the one installed. 
        ///
        /// 
        /// Critical - Gets access to critical resource (uri and browsercallback services), calls critical
        /// code (launch browser). 
        /// TreatAsSafe - There exists a demand here.
        ///  
        [SecurityCritical, SecurityTreatAsSafe] 
        private object GetWinFX(object unused)
        { 
            SecurityHelper.DemandUnmanagedCode();

            AppSecurityManager.ShellExecuteDefaultBrowser(_fwlinkUri);
 
            return null;
        } 
 
        ///
        /// Critical - calls SetStatusText which is SUC'ed. 
        ///   There is a trend in newer browsers to restrict setting the status bar from partial-trust code
        ///   to prevent URL spoofing.
        ///
        [SecurityCritical] 
        private void SetStatusText(string newStatusText)
        { 
            IProgressPage2 pp2 = _progressPage as IProgressPage2; 
            if (pp2 != null)
            { 
                pp2.ShowProgressMessage(newStatusText);
            }
            _browser.SetStatusText(newStatusText);
        } 

        ///  
        /// If trust was not granted, it may have been because the assembly of a custom permission 
        /// could not be loaded. In this case, we are interested in custom permissions that are
        /// from WindowsBase. 
        /// 
        /// The XmlReader for the application manifest
        /// If the specified version of WindowsBase could not be loaded, the version, else null.
        private string GetMissingCustomPermissionVersion(XmlReader reader) 
        {
            string requiredVersion = null; 
 
            while (reader.ReadToFollowing("IPermission", "urn:schemas-microsoft-com:asm.v2"))
            { 
                string attr = reader.GetAttribute("class");

                // Strip the first item in the comma-delimited list, which is the permission class
                AssemblyName assyName = new AssemblyName(attr.Substring(attr.IndexOf(",",StringComparison.OrdinalIgnoreCase) + 1)); 
                if (assyName.Name.Equals("WindowsBase", StringComparison.OrdinalIgnoreCase))
                { 
                    try 
                    {
                        Assembly assy = Assembly.Load(assyName); 
                    }
                    catch (Exception e)
                    {
                        // This will give a FileLoadException under the debugger, but a FileNotFoundException otherwise 
                        if (e is System.IO.FileNotFoundException || e is System.IO.FileLoadException)
                        { 
                            requiredVersion = assyName.Version.ToString(); 
                            break;
                        } 
                        else
                        {
                            throw;
                        } 
                    }
                } 
            } 

            reader.Close(); 

            return requiredVersion;
        }
 
        InPlaceHostingManager _hostingManager;
        IBrowserCallbackServices _browser; 
        ApplicationIdentity _identity; 
        Uri _deploymentManifest;
        Uri _fwlinkUri; 
        string _applicationId;
        ActivationContext _context;
        DocObjHost.ApplicationRunnerCallback _applicationRunnerCallback;
        DocObjHost.ApplicationRunner _applicationRunner; 
        INativeProgressPage _nativeProgressPage;
        IProgressPage _progressPage; 
        bool _runApplication; 
        GetManifestCompletedEventArgs _getManifestCompletedEventArgs;
 
        const int ERROR_ACTIVATION_ABORTED = 30; // defined in host\inc\Definitions.hxx

        object _lockObject = new object();
 
        long _bytesDownloaded;
        long _bytesTotal; 
        bool _updatePending; 

        string _progressPageAssembly = null; 
        string _progressPageClass = null;
        string _errorPageAssembly = null;
        string _errorPageClass = null;
 
        bool _commandBindingsRegistered;
 
        bool _isInAsynchronousOperation; 
        volatile bool _canceled;
        bool _cancelHandled; 
        volatile bool _assertAppRequirementsFailed;
        bool _refreshing;
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK