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
- Validator.cs
- RegexWriter.cs
- DataGridViewCellEventArgs.cs
- AutomationPattern.cs
- URLString.cs
- QilLoop.cs
- TemplateParser.cs
- NotificationContext.cs
- ObservableCollection.cs
- Canvas.cs
- TableLayoutPanel.cs
- DNS.cs
- RadioButtonFlatAdapter.cs
- ThreadLocal.cs
- ResolvePPIDRequest.cs
- StorageFunctionMapping.cs
- AsymmetricKeyExchangeDeformatter.cs
- connectionpool.cs
- GridItemPattern.cs
- RestHandlerFactory.cs
- HwndSourceKeyboardInputSite.cs
- JapaneseLunisolarCalendar.cs
- StubHelpers.cs
- ConnectionProviderAttribute.cs
- PanningMessageFilter.cs
- ContentPlaceHolder.cs
- InfoCardRSAOAEPKeyExchangeDeformatter.cs
- ClientOptions.cs
- XhtmlConformanceSection.cs
- ConfigurationElementProperty.cs
- Comparer.cs
- RtfFormatStack.cs
- GZipDecoder.cs
- _NetworkingPerfCounters.cs
- safesecurityhelperavalon.cs
- BindToObject.cs
- XPathExpr.cs
- CodeTypeParameterCollection.cs
- SplitContainer.cs
- CollectionChangeEventArgs.cs
- ReflectPropertyDescriptor.cs
- SaveFileDialog.cs
- MultiSelector.cs
- NumericUpDownAcceleration.cs
- ContractNamespaceAttribute.cs
- WebServiceAttribute.cs
- BufferModesCollection.cs
- WrappedIUnknown.cs
- ReverseQueryOperator.cs
- PathGeometry.cs
- ADConnectionHelper.cs
- Pair.cs
- TypedTableBaseExtensions.cs
- XPathDocumentNavigator.cs
- SessionState.cs
- InputBinder.cs
- MouseButton.cs
- ListViewItemSelectionChangedEvent.cs
- ConditionedDesigner.cs
- MaskDescriptor.cs
- ConstraintStruct.cs
- DataSourceCache.cs
- TemplateBindingExtensionConverter.cs
- DecoderReplacementFallback.cs
- MessageBox.cs
- TextServicesProperty.cs
- SapiAttributeParser.cs
- SymDocumentType.cs
- WindowsToolbarItemAsMenuItem.cs
- DataServiceConfiguration.cs
- ToolTipService.cs
- SQLMembershipProvider.cs
- SqlBuilder.cs
- ToolStripDropDown.cs
- StringPropertyBuilder.cs
- ComponentManagerBroker.cs
- MemberInfoSerializationHolder.cs
- SelectionProviderWrapper.cs
- ProcessHostFactoryHelper.cs
- Input.cs
- AuthenticationSection.cs
- StateDesigner.cs
- InheritanceAttribute.cs
- DataBoundControlHelper.cs
- CheckedListBox.cs
- InputProviderSite.cs
- DesignerActionItem.cs
- FixedPageProcessor.cs
- SkipQueryOptionExpression.cs
- SiteMapProvider.cs
- TypedAsyncResult.cs
- DesignerSerializationOptionsAttribute.cs
- MessageSecurityVersion.cs
- streamingZipPartStream.cs
- LightweightCodeGenerator.cs
- RegistrationServices.cs
- CollectionChangeEventArgs.cs
- EntityConnectionStringBuilderItem.cs
- Frame.cs
- SessionStateContainer.cs