XappLauncher.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / Orcas / NetFXw7 / wpf / src / Framework / MS / Internal / AppModel / XappLauncher.cs / 2 / 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;
using System.Threading; 

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);
            _assertAppRequirementsEvent = new ManualResetEvent(false);

            // 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) 
                { 
                    if (exception0.GetType() == typeof(InvalidOperationException) &&
                        exception0.Source == "System.Deployment") 
                    { // "No further operations are possible with this instance":
                        // This condition can occur when IPHM.AssertApplicationRequirements() is called after application
                        // downloading has failed. That error may or may not have been reported to the main thread yet.
                        // Presumably, it is the "real" error that failed deployment and should be reported to the user. 
                        // That's why no further handling is done here, and _assertAppRequirementsFailed is not set.
                    } 
                    else 
                    {
                        _assertAppRequirementsFailed = true; 

                        // Note that an exception allowed to escape from here will be caught 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); 
                    } 
                }
                finally 
                {
                    // Synchronize with DoDownloadApplicationCompleted(). [See explanation there.]
                    _assertAppRequirementsEvent.Set();
                } 
            }
            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 caught 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);

            // Using BeginInvoke() to avoid a deadlock. InPlaceHostingManager allows only one thread to run 
            // any one of its methods at a time. The DownloadApplicationCompleted event is raised on the main
            // thread but under IPHM's internal lock. Our handler (DoDownloadApplicationCompleted) needs to 
            // synchronize with the thread that calls IPHM.AssertApplicationRequirements(). That thread may 
            // be trying to call AAR(), which needs to take IPHM's internal lock. But it's already taken by the
            // code that raises the DownloadApplicationCompleted event, and in our handler we wait on AAR() to 
            // complete. => deadlock
            Dispatcher.BeginInvoke(
                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;
 
            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)
            { 
                // Synchronizing with AssertApplicationRequirementsAsync(). (If no error here, AAR must have
                // succeeded too.) IPHM could throw exceptions on both threads, in any order. We should
                // handle only one, and we prefer the one from AAR as it tends to be more meaningful, except
                // in the case when it's InvalidOperationException due to an error already encountered during 
                // application download and IPHM getting set to a dead state internally.
                _assertAppRequirementsEvent.WaitOne(); 
                if (!_assertAppRequirementsFailed) 
                {
                    HandleError(args.Error, args.LogFilePath, _getManifestCompletedEventArgs.SupportUri, null); 
                }
                return null;
            }
 
            // Race condition: UserStop() can be called after InPlaceHostingManager has completed
            // the downloading but before our callback is called. 
            bool canceled = _canceled || args.Cancelled; 
            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
        ///  
    #if DEBUG
        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    #endif
        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(); 
        ManualResetEvent _assertAppRequirementsEvent;
 
        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;
using System.Threading; 

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);
            _assertAppRequirementsEvent = new ManualResetEvent(false);

            // 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) 
                { 
                    if (exception0.GetType() == typeof(InvalidOperationException) &&
                        exception0.Source == "System.Deployment") 
                    { // "No further operations are possible with this instance":
                        // This condition can occur when IPHM.AssertApplicationRequirements() is called after application
                        // downloading has failed. That error may or may not have been reported to the main thread yet.
                        // Presumably, it is the "real" error that failed deployment and should be reported to the user. 
                        // That's why no further handling is done here, and _assertAppRequirementsFailed is not set.
                    } 
                    else 
                    {
                        _assertAppRequirementsFailed = true; 

                        // Note that an exception allowed to escape from here will be caught 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); 
                    } 
                }
                finally 
                {
                    // Synchronize with DoDownloadApplicationCompleted(). [See explanation there.]
                    _assertAppRequirementsEvent.Set();
                } 
            }
            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 caught 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);

            // Using BeginInvoke() to avoid a deadlock. InPlaceHostingManager allows only one thread to run 
            // any one of its methods at a time. The DownloadApplicationCompleted event is raised on the main
            // thread but under IPHM's internal lock. Our handler (DoDownloadApplicationCompleted) needs to 
            // synchronize with the thread that calls IPHM.AssertApplicationRequirements(). That thread may 
            // be trying to call AAR(), which needs to take IPHM's internal lock. But it's already taken by the
            // code that raises the DownloadApplicationCompleted event, and in our handler we wait on AAR() to 
            // complete. => deadlock
            Dispatcher.BeginInvoke(
                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;
 
            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)
            { 
                // Synchronizing with AssertApplicationRequirementsAsync(). (If no error here, AAR must have
                // succeeded too.) IPHM could throw exceptions on both threads, in any order. We should
                // handle only one, and we prefer the one from AAR as it tends to be more meaningful, except
                // in the case when it's InvalidOperationException due to an error already encountered during 
                // application download and IPHM getting set to a dead state internally.
                _assertAppRequirementsEvent.WaitOne(); 
                if (!_assertAppRequirementsFailed) 
                {
                    HandleError(args.Error, args.LogFilePath, _getManifestCompletedEventArgs.SupportUri, null); 
                }
                return null;
            }
 
            // Race condition: UserStop() can be called after InPlaceHostingManager has completed
            // the downloading but before our callback is called. 
            bool canceled = _canceled || args.Cancelled; 
            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
        ///  
    #if DEBUG
        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    #endif
        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(); 
        ManualResetEvent _assertAppRequirementsEvent;
 
        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