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

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- CancellationHandlerDesigner.cs
- Point4D.cs
- TemplatedMailWebEventProvider.cs
- InputProcessorProfiles.cs
- SystemResources.cs
- ProjectionCamera.cs
- PerformanceCounterLib.cs
- ButtonField.cs
- VerificationException.cs
- Thread.cs
- Section.cs
- TimelineGroup.cs
- Event.cs
- WindowsListBox.cs
- ImageSourceValueSerializer.cs
- DataAdapter.cs
- DbBuffer.cs
- AdornerPresentationContext.cs
- DesignerActionItemCollection.cs
- assertwrapper.cs
- InvokePattern.cs
- ProjectionPathSegment.cs
- CurrentChangingEventManager.cs
- ViewBase.cs
- SyndicationItem.cs
- AdCreatedEventArgs.cs
- BrowserDefinition.cs
- HashAlgorithm.cs
- graph.cs
- newinstructionaction.cs
- XPathParser.cs
- DependencyObject.cs
- PropertyChangedEventArgs.cs
- DisplayInformation.cs
- TextRenderer.cs
- BitmapFrameDecode.cs
- KerberosTokenFactoryCredential.cs
- CollectionChangedEventManager.cs
- RangeValidator.cs
- HttpRequest.cs
- ColumnClickEvent.cs
- ObjectReferenceStack.cs
- DefaultSection.cs
- CodeGeneratorOptions.cs
- OdbcParameterCollection.cs
- FileLoadException.cs
- DataGridViewCellCancelEventArgs.cs
- FileDialogCustomPlace.cs
- RayMeshGeometry3DHitTestResult.cs
- RefreshEventArgs.cs
- ListDictionary.cs
- XmlDocumentType.cs
- WeakReadOnlyCollection.cs
- FromRequest.cs
- ContainerControl.cs
- TreeNodeClickEventArgs.cs
- XPathSingletonIterator.cs
- Grant.cs
- dataobject.cs
- IncrementalCompileAnalyzer.cs
- ClientType.cs
- QuaternionAnimationBase.cs
- PrivateFontCollection.cs
- XamlRtfConverter.cs
- XmlSchemaSimpleTypeRestriction.cs
- AstTree.cs
- LoadGrammarCompletedEventArgs.cs
- MsmqInputMessage.cs
- TempEnvironment.cs
- CodeMemberField.cs
- CodeCompiler.cs
- IERequestCache.cs
- ContractCodeDomInfo.cs
- NavigateEvent.cs
- Vector3DCollectionConverter.cs
- TrackingExtract.cs
- HostnameComparisonMode.cs
- CodeExpressionCollection.cs
- InputBindingCollection.cs
- GacUtil.cs
- WmpBitmapDecoder.cs
- KeyManager.cs
- DbDataReader.cs
- Variable.cs
- ItemsControlAutomationPeer.cs
- AtomParser.cs
- DbDataRecord.cs
- FixedTextBuilder.cs
- Range.cs
- AppDomainAttributes.cs
- WebPartTransformerAttribute.cs
- SmtpLoginAuthenticationModule.cs
- IndexedWhereQueryOperator.cs
- ToggleProviderWrapper.cs
- HttpListenerPrefixCollection.cs
- SID.cs
- FullTextState.cs
- codemethodreferenceexpression.cs
- DNS.cs
- SmiEventSink.cs