Code:
/ DotNET / DotNET / 8.0 / untmp / WIN_WINDOWS / lh_tools_devdiv_wpf / Windows / wcp / Framework / System / Windows / Interop / DocobjHost.cs / 4 / DocobjHost.cs
//---------------------------------------------------------------------------- // //// Copyright (C) Microsoft Corporation. All rights reserved. // // // Description: // Implements the type used for COM interop by the browser host // // History: // 06/28/01: mwatt: Created // 06/04/03: [....]: Moved over to WCP dir // //--------------------------------------------------------------------------- using System; using System.Diagnostics; using System.Globalization; using System.IO; using System.IO.Packaging; using System.Threading; using System.Net; using System.Reflection; using System.Runtime.InteropServices; using System.Runtime.Remoting; using System.Runtime.Remoting.Lifetime; using System.Security; using System.Security.Permissions; using System.Security.Policy; using System.Windows.Threading; using System.Windows.Navigation; using System.Xml; using Microsoft.Win32.SafeHandles; using MS.Internal.AppModel; using MS.Internal.IO.Packaging.CompoundFile; using MS.Internal.IO.Packaging; using MS.Internal.PresentationFramework; // SecurityHelper using MS.Internal.Progressivity; using MS.Internal.Utility; using MS.Utility; using MS.Win32; using MS.Internal; //In order to avoid generating warnings about unknown message numbers and //unknown pragmas when compiling your C# source code with the actual C# compiler, //you need to disable warnings 1634 and 1691. (Presharp Documentation) #pragma warning disable 1634, 1691 namespace System.Windows.Interop { ////// Interop class used for implementing the managed part of a DocObj Server for browser hosting /// public sealed class DocObjHost : MarshalByRefObject, IServiceProvider, IHostService, IBrowserHostServices, IByteRangeDownloaderService { ////// This is only exposed publically for interop with the browser. /// This is not secure for partial trust. /// ////// Callers must have UnmanagedCode permission to call this API. /// ////// Critical - as we have a treat as safe /// PublicOK - as we have a demand. /// [ SecurityCritical ] public DocObjHost() { EventTrace.NormalTraceEvent(EventTraceGuidId.HOSTINGGUID, (byte)EventTrace.HostingEvent.DocObjHostCreated); SecurityHelper.DemandUnmanagedCode(); _mainThread = Thread.CurrentThread; _initData.Value.ServiceProvider = this; // Thread.ApartmentState is [Obsolete] #pragma warning disable 0618 Debug.Assert(_mainThread.ApartmentState == ApartmentState.STA); #pragma warning restore 0618 } #region Private Data private Thread _mainThread; private ApplicationProxyInternal _appProxyInternal; private SecurityCriticalDataForSet_initData = new SecurityCriticalDataForSet (new ApplicationProxyInternal.InitData()); private SecurityCriticalDataForSet _isViewer; private IntPtr _parent; private IBrowserCallbackServices _browserCallbackServices; private Object _downloader; // byte range downloader #endregion Private Data //***************************************************************************** // // MarshalByRef override // //***************************************************************************** /// /// Return the ILease object, specifying that the lease should never expire /// ///A new ILease object ////// Critical: Elevates via assert to set the InitialLeaseTime /// PublicOk: Always initializes to a constant value (TimeSpan.Zero) /// [SecurityCritical] public override object InitializeLifetimeService() { ILease lease = (ILease)base.InitializeLifetimeService(); Debug.Assert(lease.CurrentState == LeaseState.Initial); (new SecurityPermission(PermissionState.Unrestricted)).Assert(); //BlessedAssert try { lease.InitialLeaseTime = TimeSpan.Zero; // infinite -- never expire } finally { CodeAccessPermission.RevertAssert(); } return lease; } #region IServiceProvider //****************************************************************************** // // IServiceProvider interface implementation // //***************************************************************************** ////// Provides IHostService, IBrowserHostService /// object IServiceProvider.GetService(Type serviceType) { if (serviceType == typeof(IHostService)) { return this; } else if (serviceType == typeof(IBrowserCallbackServices)) { return _browserCallbackServices; } else if (serviceType == typeof(IOleCmdMappingService)) { Invariant.Assert(_appProxyInternal != null); return ((IOleCmdMappingService)_appProxyInternal.OleCmdHelper); } return null; } #endregion IServiceProvider #region IHostService //****************************************************************************** // // IHostService interface implementation // //****************************************************************************** //// Get the proxy for the RootBrowserWindow. // RootBrowserWindowProxy IHostService.RootBrowserWindowProxy { get { return (_appProxyInternal == null) ? null : _appProxyInternal.RootBrowserWindowProxy; } } //// ParentHandle of the host window // ////// Critical: returns the browser window /// IntPtr IHostService.HostWindowHandle { [SecurityCritical] get { return _parent; } } #endregion IHostService #region IBrowserHostServices //***************************************************************************** // // IBrowserHostServices interface implementation // //****************************************************************************** //// Loads and runs the application based on the parameters passed in // // Path to the container or XAML file // Mime type of the content we are trying to load // Marshaled IStream representing the current bind that we want to reuse // PersistHistory load stream // flags specifying container options, such as whether the container is writeable //Int indicating whether the exit code of the application, failure could also // mean that the app was not lauched successfully ////// Critical 1) as the delegate that this code calls CreateAppProxyForDocument, which /// is critical also /// 2) uses the path information (which refers to the actual container or xaml /// file that will be loaded) to determine the activationUri, which is used /// to set the critical InitData.ActivationUri and .MimeType. /// 3) Because it sets _isViewer and _isAvalonTopLevel /// TreatAsSafe 2) Since the path information is coming directly from IE, and is the /// same path that will be used to load the container or xaml file then this /// information should be considered safe (if it was not safe the container /// should fail to load, which would make this data moot). /// [SecurityCritical] int IBrowserHostServices.Run( String path, String debugSecurityZoneURL, String viewerUri, String fragment, String applicationId, MimeType mime, object streamContainer, object ucomLoadIStream, string userAgentString, bool isDebugMode, string progressAssemblyName, string progressClassName, string errorAssemblyName, string errorClassName ) { Invariant.Assert(String.IsNullOrEmpty(path) == false, "path string should not be null or empty when Run method is called."); Invariant.Assert(mime != MimeType.Unknown, "Unknown mime type"); if (EventTrace.IsEnabled(EventTrace.Flags.performance)) { EventTrace.EventProvider.TraceEvent(EventTrace.GuidFromId(EventTraceGuidId.HOSTINGGUID), (byte)EventTrace.HostingEvent.IBHSRunStart, "\""+path+"\"", "\""+applicationId+"\""); } int exitCode = 0; try { Application application = null; ApplicationProxyInternal.InitData initData = _initData.Value; initData.Fragment = fragment; initData.UcomLoadIStream = ucomLoadIStream; initData.HandleHistoryLoad = true; initData.MimeType.Value = mime; initData.UserAgentString = userAgentString; Uri activationUri = new UriBuilder(path).Uri; initData.ActivationUri.Value = activationUri; PresentationAppDomainManager.ActivationUri = activationUri; // We do this here so that it will be set correctly when our deployment application // launches. This matters because if it isn't set when the app ctor is run, then // we will call Dispatcher.Run synchronously, which will make the browser // unresponsive. BrowserInteropHelper.SetBrowserHosted(true); if (!string.IsNullOrEmpty(viewerUri)) { _isViewer.Value = true; } Uri applicationUri = _isViewer.Value ? new UriBuilder(viewerUri).Uri : activationUri; if (isDebugMode) { _browserCallbackServices.ChangeDownloadState(false); // stop waving the flag _browserCallbackServices.UpdateProgress(-1, 0); // make the progress bar go away EnableErrorPage(); _appProxyInternal = new ApplicationLauncherXappDebug(path, debugSecurityZoneURL).Initialize(); } else { switch (mime) { case MimeType.Document: _appProxyInternal = CreateAppProxyForDocument(); if (_appProxyInternal == null) { exitCode = -1; } else { if (streamContainer != null) { IntPtr punk = Marshal.GetIUnknownForObject(streamContainer); _appProxyInternal.StreamContainer = punk; Marshal.Release(punk); } } // Free objects (after the _appProxyInternal.Run(initData) call below). // For the other MIME types, this is done in RunApplication(). _initData.Value = null; break; case MimeType.Markup: case MimeType.Application: // This is a browser hosted express app scenario. // Setup XappLauncherApp with default values, and instantiate // ApplicationProxyInternal for this AppDomain. application = new XappLauncherApp(applicationUri, activationUri, applicationId, _browserCallbackServices, new ApplicationRunnerCallback(RunApplication), progressAssemblyName, progressClassName,errorAssemblyName,errorClassName); // No need to handle history for progress app. Remember // it for the real app. initData.HandleHistoryLoad = false; Invariant.Assert(application != null); _appProxyInternal = new ApplicationProxyInternal(); break; default: exitCode = -1; break; } } if (exitCode != -1) { if (mime == MimeType.Document) { //[[....], 7/27/07] // Unfortunately, XPSViewer relies on the unhandled exception page to report bad XAML. // Ideally, only exceptions from the XamlReader should be caught and shown this way, // in order not to hide platform bugs. But it's more than one place where XAML is // loaded from the XPS package, and in more than one way. A little too much to change // in SP1. EnableErrorPage(); } exitCode = _appProxyInternal.Run(initData); } } catch (Exception ex) { exitCode = -1; // The exception is re-thrown here, but it will get translated to an HRESULT by // COM Interop. That's why ProcessUnhandledException() is called directly. // In most cases it runs a modal loop around the error page and never returns. _browserCallbackServices.ProcessUnhandledException(ex.ToString()); throw; } catch { // This catches non-CLS compliant exceptions. // Not having this clause triggers an FxCop violation. exitCode = -1; _browserCallbackServices.ProcessUnhandledException(SR.Get(SRID.NonClsActivationException)); throw; } finally { Cleanup(exitCode); } if (EventTrace.IsEnabled(EventTrace.Flags.performance)) { EventTrace.EventProvider.TraceEvent(EventTrace.GuidFromId(EventTraceGuidId.HOSTINGGUID), (byte)EventTrace.HostingEvent.IBHSRunEnd, exitCode); } return exitCode; } internal delegate void ApplicationRunner(); internal delegate void ApplicationRunnerCallback(ApplicationRunner runner); // // This method is invoked by the callback that occurs when the download of the app is complete, so that // running the main application happens on the correct thread. // ////// Critical as this code calls a critical method. /// It also sets IsViewer, which is critical. /// Setting _initData.Value = null is also critical, but it's safe. /// [SecurityCritical] internal void RunApplication(ApplicationRunner runner) { if (EventTrace.IsEnabled(EventTrace.Flags.performance, EventTrace.Level.verbose)) { EventTrace.EventProvider.TraceEvent(EventTrace.Level.verbose, EventTrace.GuidFromId(EventTraceGuidId.HOSTINGGUID), (byte)EventTrace.HostingEvent.DocObjHostRunApplicationStart); } // Run the App in the new AppDomain and ask the AppDomainManager // to save it. PresentationAppDomainManager.SaveAppDomain = true; PresentationAppDomainManager.IsViewer = _isViewer.Value; EnableErrorPage(); runner(); if (ApplicationProxyInternal.Current == null) { Debug.Fail("Unexpected reentrant PostShutdown?"); return; } if (PresentationAppDomainManager.NewAppDomain == null) { throw new Exception(SR.Get(SRID.AppActivationException)); } // Create an ApplicationProxyInternal in the new domain. PresentationAppDomainManager appDomainMgrProxy = PresentationAppDomainManager.NewAppDomain.DomainManager as PresentationAppDomainManager; // And replace _appProxyInternal. Invariant.Assert(ApplicationProxyInternal.Current == _appProxyInternal, "AppProxyInternal has shut down unexpectedly."); _appProxyInternal = appDomainMgrProxy.CreateApplicationProxyInternal(); PresentationAppDomainManager.SaveAppDomain = false; // Run the app. ApplicationProxyInternal.InitData initData = _initData.Value; initData.HandleHistoryLoad = true; _appProxyInternal.Run(initData); _initData.Value = null; // free objects if (EventTrace.IsEnabled(EventTrace.Flags.performance, EventTrace.Level.verbose)) { EventTrace.EventProvider.TraceEvent(EventTrace.Level.verbose, EventTrace.GuidFromId(EventTraceGuidId.HOSTINGGUID), (byte)EventTrace.HostingEvent.DocObjHostRunApplicationEnd); } } //// Sets up the interface that the Windows Client host can use to talk back to the browser // // void IBrowserHostServices.SetBrowserCallback(object browserCallbackServices) { Invariant.Assert(browserCallbackServices != null, "Browser interop interface passed in should not be null"); _browserCallbackServices = (IBrowserCallbackServices)browserCallbackServices; } //// Set the parent window of the host window // // ////// Critical because it has the ability to parent window to an arbitrary IntPtr /// This is called via COM interop from the unmanaged side. /// /// [SecurityCritical] void IBrowserHostServices.SetParent(IntPtr hParent) { _parent = hParent; } //// Show or hide view // // // void IBrowserHostServices.Show(bool show) { if (_initData.Value != null) { _initData.Value.ShowWindow = show; } if (_appProxyInternal != null) { _appProxyInternal.Show(show); } } //// For shdocvw LoadHistory support // //bool IBrowserHostServices.IsAppLoaded() { return (_appProxyInternal == null) ? false : _appProxyInternal.IsAppLoaded(); } // // The application sets the Environment.ExitCode to the applications exit code set by // calling Shutdown(exitCode) or in the ShutdownEventArgs // //Environment.ExitCode set by the application object when it Shutdown int IBrowserHostServices.GetApplicationExitCode() { return Environment.ExitCode; } bool IBrowserHostServices.CanInvokeJournalEntry(int entryId) { bool canInvoke = false; if ((this as IBrowserHostServices).IsAppLoaded() == false) { canInvoke = false; } else { canInvoke = _appProxyInternal.CanInvokeJournalEntry(entryId); } return canInvoke; } //// IPersistHistory.SaveHistory implementation called // when hosted in the browser // // The native stream to save the journal information //GCHandle to the saved byte array ////// Critical as this calls a critical method. /// [SecurityCritical] void IBrowserHostServices.SaveHistory(object comIStream, bool persistEntireJournal, out int entryIndex, out string uri, out string title) { if (_appProxyInternal != null) { SaveHistoryHelper(comIStream, persistEntireJournal, out entryIndex, out uri, out title); } else { entryIndex = -1; uri = null; title = null; } } //// IPersistHistory::LoadHistory implementation called // when hosted in the browser // // ////// Critical as this method calls critical methods. /// [SecurityCritical] void IBrowserHostServices.LoadHistory(object ucomIStream) { if (_appProxyInternal != null) { LoadHistoryHelper(ucomIStream, /*firstHistoryLoad=*/false); } } //// IOleCommandTarget::QueryStatus called when hosted in the browser // ////// Critical: This code calls into query status helper /// that can be used to cause an elevation.More importantly the parameters /// that come in here come from the browser and we should not call this from elsewhere /// ////// OleCmdHelper reports errors by throwing ComException. The interop layer takes the /// associated HRESULT and returns it to the native caller. However, to avoid throwing exceptions /// on startup, while _appProxyInternal is not set up yet, this method is marked as [PreserveSig] /// and directly returns an error HRESULT. /// [SecurityCritical] int IBrowserHostServices.QueryStatus(Guid guidCmdGroup, uint command, out uint flags) { flags = 0; if (_appProxyInternal != null) { OleCmdHelper cmdHelper = _appProxyInternal.OleCmdHelper; if (cmdHelper != null) { cmdHelper.QueryStatus(guidCmdGroup, command, ref flags); return NativeMethods.S_OK; } } return OleCmdHelper.OLECMDERR_E_UNKNOWNGROUP; } //// IOleCommandTarget::Exec called when hosted in the browser // ////// Critical: This code calls into ExecCommandHelper helper which can be used to spoof paste. /// More importantly the parameters that come in here come from the browser and we should not call this from elsewhere /// ////// OleCmdHelper reports errors by throwing ComException. The interop layer takes the /// associated HRESULT and returns it to the native caller. However, to avoid throwing exceptions /// on startup, while _appProxyInternal is not set up yet, this method is marked as [PreserveSig] /// and directly returns an error HRESULT. /// [SecurityCritical] int IBrowserHostServices.ExecCommand(Guid guidCommandGroup, uint command, object arg) { if (_appProxyInternal != null) { OleCmdHelper cmdHelper = _appProxyInternal.OleCmdHelper; if (cmdHelper != null) { cmdHelper.ExecCommand(guidCommandGroup, command, arg); return NativeMethods.S_OK; } } return OleCmdHelper.OLECMDERR_E_UNKNOWNGROUP; } //// Move -- standard args // // // // // ////// Critical as this method calls a critical method. /// [SecurityCritical] void IBrowserHostServices.Move(int x, int y, int width, int height) { Rect windowRect = new Rect(x, y, width, height); // Remember the size and position of the browser window. We'll need // to use this in the case of .deploy app where we need to size it // after creating it. Otherwise the window won't render till we resize. // i. _initData is null after the application is started. if (_initData.Value != null) { _initData.Value.WindowRect = windowRect; } if (_appProxyInternal != null) { _appProxyInternal.Move(windowRect); } } ////// This code call into critical code which in turn elevates to /// UI Permissions. This method is not available in the SEE. /// [SecurityCritical] void IBrowserHostServices.PostShutdown() { if (EventTrace.IsEnabled(EventTrace.Flags.debugging, EventTrace.Level.normal)) { EventTrace.EventProvider.TraceEvent(EventTrace.Level.normal, EventTrace.GuidFromId(EventTraceGuidId.HOSTINGGUID), (byte)EventTrace.HostingEvent.PostShutdown); } if (_appProxyInternal != null) { _appProxyInternal.PostShutdown(); } } //// Tell the app to activate/deactivate root browser window // // Activate or Deactivate browser window //////Critical as this calls a critical method. /// [SecurityCritical] void IBrowserHostServices.Activate(bool fActivate) { if (_appProxyInternal != null) { _appProxyInternal.Activate(fActivate); } } void IBrowserHostServices.TabInto(bool forward) { _appProxyInternal.RootBrowserWindowProxy.TabInto(forward); } bool IBrowserHostServices.FocusedElementWantsBackspace() { return _appProxyInternal != null ? _appProxyInternal.FocusedElementWantsBackspace() : false; } #endregion IBrowserHostServices #region ByteRangeDownloader ////// Initialize the downloader for byte range request /// /// url to be downloaded /// temporary file where the downloaded bytes should be saved /// event handle to be raised when a byte range request is done ////// Critical /// 1) creates ByteRangeDownloader which is critical /// [SecurityCritical] void IByteRangeDownloaderService.InitializeByteRangeDownloader( String url, String tempFile, SafeWaitHandle eventHandle) { if (url == null) { throw new ArgumentNullException("url"); } if(tempFile == null) { throw new ArgumentNullException("tempFile"); } if(eventHandle == null) { throw new ArgumentNullException("eventHandle"); } if (eventHandle.IsInvalid || eventHandle.IsClosed) { throw new ArgumentException(SR.Get(SRID.InvalidEventHandle), "eventHandle"); } Uri requestedUri = new Uri(url, UriKind.Absolute); if(tempFile.Length <= 0) { throw new ArgumentException(SR.Get(SRID.InvalidTempFileName), "tempFile"); } ByteRangeDownloader loader = new ByteRangeDownloader(requestedUri, tempFile, eventHandle); // We defined _downloader as Object for performance reasons. If we define it as ByteRangeDownloader the whole // class will be loaded although it might not be used at all. By declaring it as Object we can prevent it // from being loaded. This technique is used in other areas. _downloader = (Object) loader; } ////// Make HTTP byte range web request /// /// byte ranges to be downloaded; byteRanges is one dimensional /// array consisting pairs of offset and length /// number of elements in byteRanges void IByteRangeDownloaderService.RequestDownloadByteRanges (int[] byteRanges, int size) { // // Because of COM Interop Marshalling, we use made byte ranges as one dimensional array // However, since they are pairs of offset and length, it makes more sense to convert // them into two dimensional array in Managed code // if (byteRanges == null) { throw new ArgumentNullException("byteRanges"); } if (byteRanges.Length <= 0 || (byteRanges.Length % 2) != 0) { throw new ArgumentException(SR.Get(SRID.InvalidByteRanges, "byteRanges")); } if (_downloader == null) { throw new InvalidOperationException(SR.Get(SRID.ByteRangeDownloaderNotInitialized)); } ((ByteRangeDownloader) _downloader).RequestByteRanges(ByteRangeDownloader.ConvertByteRanges(byteRanges)); } ////// Get the byte ranges that are downloaded /// /// byte ranges that are downloaded; byteRanges is one dimensional /// array consisting pairs of offset and length /// size of byteRanges void IByteRangeDownloaderService.GetDownloadedByteRanges (out int[] byteRanges, out int size) { // // Because of COM Interop Marshalling, we use made byte ranges as one dimensional array // However, since they are pairs of offset and length, it makes more sense to convert // them into two dimensional array in Managed code // size = 0; byteRanges = null; if (_downloader == null) { throw new InvalidOperationException(SR.Get(SRID.ByteRangeDownloaderNotInitialized)); } int[,] ranges = ((ByteRangeDownloader) _downloader).GetDownloadedByteRanges(); byteRanges = ByteRangeDownloader.ConvertByteRanges(ranges); size = byteRanges.Length; } ////// Release the byte range downloader /// void IByteRangeDownloaderService.ReleaseByteRangeDownloader () { if (_downloader == null) { throw new InvalidOperationException(SR.Get(SRID.ByteRangeDownloaderNotInitialized)); } ((IDisposable) _downloader).Dispose(); _downloader = null; } #endregion ByteRangeDownloader #region Private Helper Methods #region Security Helpers ////// Critical: Calls into a link demanded method /// [SecurityCritical] private ApplicationProxyInternal CreateAppProxyForDocument() { ApplicationProxyInternal appProxy = null; AppDomainSetup domainSetup = new AppDomainSetup(); domainSetup.ApplicationBase = GetXPSViewerPath(); // Create the app domain using a restricted set of permissions, which are a subset of the // typical "Internet Zone" permissions. // (Explicitly, we leave out Web Browser permissions, and we only support SafeImages) PermissionSet permissionSet = new PermissionSet(null); permissionSet.AddPermission(new FileDialogPermission(FileDialogPermissionAccess.Open)); permissionSet.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution)); permissionSet.AddPermission(new UIPermission(UIPermissionWindow.SafeTopLevelWindows)); permissionSet.AddPermission(new UIPermission(UIPermissionClipboard.OwnClipboard)); permissionSet.AddPermission(new MediaPermission(MediaPermissionImage.SafeImage)); // Set up IsolatedStorage permissions: // We allow 20mb of storage space and we isloate the storage on a per domain basis, by user. IsolatedStorageFilePermission storagePermission = new IsolatedStorageFilePermission(PermissionState.Unrestricted); storagePermission.UsageAllowed = IsolatedStorageContainment.DomainIsolationByUser; storagePermission.UserQuota = GetXpsViewerIsolatedStorageUserQuota(); permissionSet.AddPermission(storagePermission); // The AppDomain wants a non-null evidence, so create one with // random URL evidence. System.Text.StringBuilder sb = new System.Text.StringBuilder(); sb.AppendFormat("http://{0}/", Guid.NewGuid().ToString("N", null)); Evidence evidence = new Evidence(new object[] { new Url(sb.ToString()) }, null); //Create the AppDomain and our ApplicationProxy. AppDomain targetAppDomain = AppDomain.CreateDomain( "WCP_Hosted_Application", evidence, domainSetup, permissionSet, null); appProxy = ApplicationProxyInternal.CreateInDomain(targetAppDomain); return appProxy; } #endregion Security Helpers ////// Critical: calls Marshal.ReleaseComObject which LinkDemands /// [SecurityCritical] private void Cleanup(int exitCode) { //No error => don't cleanup if (exitCode == 0) return; // You need to explicitly release the COM object. The RCW doesn't // seem to get garbage collected automatically. // // We don't want to call release multiple times. So call either // on the App or on the Docobj since the ServiceProvider setter // release the _browserCallbackServices com object if (_appProxyInternal != null) { _appProxyInternal.Cleanup(); } else if (_browserCallbackServices != null) { Marshal.ReleaseComObject(_browserCallbackServices); _browserCallbackServices = null; } } // IPersistHistory::SaveHistory implementation called // when hosted in the browser //GCHandle to the saved byte array ////// Critical as this calls a critical method SecuritySuppressedIStream.Write(). /// [SecurityCritical] private void SaveHistoryHelper(object comIStream, bool persistEntireJournal, out int entryIndex, out string uri, out string title) { //out params need to be initialized before control leaves this method (CS0177) uri = title = null; entryIndex = -1; // if (_appProxyInternal == null ) { return; } SecuritySuppressedIStream historyStream = comIStream as SecuritySuppressedIStream; // if (historyStream == null) return; byte [] saveByteArray = _appProxyInternal.GetSaveHistoryBytes( persistEntireJournal, out entryIndex, out uri, out title); if (saveByteArray == null) return; int len = saveByteArray.Length; int bytesWritten = 0; historyStream.Write(saveByteArray, len, out bytesWritten); Invariant.Assert(bytesWritten == len, "Error saving journal stream to native IStream"); } // IPersistHistory::LoadHistory implementation called // when hosted in the browser // ////// Critical as this method accesses other members that are critical. /// [SecurityCritical] private void LoadHistoryHelper(object comIStream, bool firstLoadFromHistory) { if (_appProxyInternal == null) { return; } _appProxyInternal.LoadHistoryStream(ExtractComStream(comIStream), firstLoadFromHistory); } ////// Critical as this calls a critical method SecuritySuppressedIStream.Read(). /// [SecurityCritical] internal static MemoryStream ExtractComStream(object comIStream) { SecuritySuppressedIStream historyStream = comIStream as SecuritySuppressedIStream; if (historyStream == null) { throw new ArgumentNullException("comIStream"); } MemoryStream loadStream = new MemoryStream(); byte[] loadByteArray = new byte[1024]; int bytesRead = 0; do { bytesRead = 0; historyStream.Read(loadByteArray, 1024, out bytesRead); loadStream.Write(loadByteArray, 0, bytesRead); } while (bytesRead > 0); Invariant.Assert(loadStream.Length > 0, "Error reading journal stream from native IStream"); return loadStream; } private bool IsXbapErrorPageDisabled() { object errorPageSetting = Microsoft.Win32.Registry.GetValue( "HKEY_CURRENT_USER\\" + RegistryKeys.WPF_Hosting, RegistryKeys.value_DisableXbapErrorPage, null); if(errorPageSetting == null) { errorPageSetting = Microsoft.Win32.Registry.GetValue( "HKEY_LOCAL_MACHINE\\" + RegistryKeys.WPF_Hosting, RegistryKeys.value_DisableXbapErrorPage, null); } return errorPageSetting is int && (int)errorPageSetting != 0; } ////// Sets up an AppDomain.UnhandledException handler intended to show exceptions from the hosted /// application in the HTML error page. This handler should be activated as late as possible, /// just before the Main() method of the hosted application is called, in order to allow unhandled /// exceptions in the hosting code and ClickOnce to go to Watson. /// In a future release we'll add a Send Error Report button to the error page. Exceptions due to /// platform bugs are currently not handled by it. /// private void EnableErrorPage() { if (!IsXbapErrorPageDisabled()) { AppDomain.CurrentDomain.UnhandledException += this.ProcessUnhandledException; } // Caveats: // -- Debuggers affect exception handling. In particular, doing mixed-mode or // native-only debugging seems to disable this event. Debugging the unmanaged // unhandled-exception handling code is easier when it is called before an exception // occurs. (Add a temporary call somewhere.) // -- AppDomain.add_UnhandledException() requires the given handler to follow the // CLR Constrained Execution Region rules. (It calls RuntimeHelpers.PrepareDelegate().) // See http://blogs.msdn.com/bclteam/archive/2005/06/14/429181.aspx for a discussion. } ////// Critical - calls IBCS.ProcessUnhandledException(), which is Critical. /// TreatAsSafe - Showing the error page is not a privileged operation. An XBAP can always do that /// by throwing some exception. /// [SecurityCritical, SecurityTreatAsSafe] [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.Synchronized)] private void ProcessUnhandledException(object sender, UnhandledExceptionEventArgs e) { // In CLR v2 unhandled exceptions on background threads also terminate the process. That's why // e.IsTerminating appears to be always 'true' here. try { // Exception.ToString() contains the exception type, stack trace, and information about // inner exceptions. If the exception object is not derived from Exception (the CLR // allows throwing anything), we should get at least its type. string errorMessage = e.ExceptionObject.ToString(); Invariant.Assert(_browserCallbackServices != null); // Immediately returning from here makes sure the debugger always gets notified on // unhandled exception. if (Debugger.IsAttached) return; // Issue: If the exception arrives on a thread other than the main one, we can't call // _browserCallbackServices.ProcessUnhandledException(), because COM marshaling for // COleDocument is not available (no typelib or proxy/stub CLSID registered). // The workaround is to make the call via a DLL-exported function. // (This is actually better in a way because proper marshaling would depend on the main // thread actively pumping messages [STA apartment], and we can't be sure where it is // and what it is doing at this point.) // // In the current implementation, the native ProcessUnhandledException() may or may not // return, depending on whether the browser is currently blocked on a call into our // DocObject. if (Thread.CurrentThread == _mainThread) { _browserCallbackServices.ProcessUnhandledException(errorMessage); } else { MS.Win32.UnsafeNativeMethods.ProcessUnhandledException_DLL(errorMessage); } } catch(Exception ex) { Debug.Fail(ex.ToString()); throw; } } ////// Returns the path for the XPSViewer application. /// ///private string GetXPSViewerPath() { // Get the path to the XPSViewer executable from the registry: string xpsViewerPath = Microsoft.Win32.Registry.GetValue( RegistryKeys.HKLM_XpsViewerLocalServer32, null, null) as string; // If the registry value is not found, we consider this a fatal error and will not continue. if( xpsViewerPath == null ) { throw new InvalidOperationException( String.Format( CultureInfo.CurrentCulture, SR.Get(SRID.DocumentApplicationRegistryKeyNotFound), RegistryKeys.HKLM_XpsViewerLocalServer32)); } // The path we get back from the registry contains the name of the XPSViewer // executable -- we only want the path to the viewer, so we strip that off. xpsViewerPath = System.IO.Path.GetDirectoryName(xpsViewerPath); return xpsViewerPath; } /// /// Returns the amount of IsolatedStorage to allot the XPSViewer instance. /// This queries the registry for a DWORD value named "IsolatedStorageUserQuota" in /// HKCU\Software\Microsoft\XPSViewer. If it exists then the value there is used as /// the isolated storage quota; otherwise the default value of 20mb is used. /// ///private int GetXpsViewerIsolatedStorageUserQuota() { int isolatedStorageUserQuota = _defaultXpsIsolatedStorageUserQuota; object isolatedStorageRegistryValue = Microsoft.Win32.Registry.GetValue( RegistryKeys.HKCU_XpsViewer, RegistryKeys.value_IsolatedStorageUserQuota, null); if (isolatedStorageRegistryValue is int) { isolatedStorageUserQuota = (int)isolatedStorageRegistryValue; } return isolatedStorageUserQuota; } #endregion Private Helper Methods //----------------------------------------------------- // // Private Unmanaged Interfaces // //----------------------------------------------------- #region Private Unmanaged Interface imports /// /// Supressing unmanaged code security on Read and Write only as they are the only methods /// currently in use on this interface. The reason that we do not use ISequentialStream /// instead of the full IStream is because IStream is what is passed to the /// IPersistHistory interfaces in native code. /// [Guid("0000000c-0000-0000-C000-000000000046")] [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] [ComImport] private interface SecuritySuppressedIStream { // ISequentialStream portion ////// Critical - Causes an elevation to read from the unmanaged stream /// [SecurityCritical, SuppressUnmanagedCodeSecurity] void Read([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1), Out] Byte[] pv, int cb, out int pcbRead); ////// Critical - Causes an elevation to write to the unmanaged stream /// [SecurityCritical, SuppressUnmanagedCodeSecurity] void Write([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] Byte[] pv, int cb, out int pcbWritten); // IStream portion void Seek(long dlibMove, int dwOrigin, out long plibNewPosition); void SetSize(long libNewSize); void CopyTo(SecuritySuppressedIStream pstm, long cb, out long pcbRead, out long pcbWritten); void Commit(int grfCommitFlags); void Revert(); void LockRegion(long libOffset, long cb, int dwLockType); void UnlockRegion(long libOffset, long cb, int dwLockType); void Stat(out System.Runtime.InteropServices.ComTypes.STATSTG pstatstg, int grfStatFlag); void Clone(out SecuritySuppressedIStream ppstm); } #endregion Private Unmanaged Interface imports // The amount of User Quota to allow for XPSViewer's Isolated Storage (approx 512mb) private const int _defaultXpsIsolatedStorageUserQuota = 512000000; } internal class ApplicationLauncherXappDebug { ////// Critical /// Because it sets critical data _debugSecurityZoneURL /// [SecurityCritical] public ApplicationLauncherXappDebug(string path, string debugSecurityZoneURL) { _deploymentManifestPath = path; // assumed to be .xapp _deploymentManifest = new Uri(path); if (!string.IsNullOrEmpty(debugSecurityZoneURL)) { _debugSecurityZoneURL.Value = new Uri(debugSecurityZoneURL); } _applicationManifestPath = Path.ChangeExtension(path, ".exe.manifest"); _exePath = Path.ChangeExtension(path, ".exe"); } ////// This creates and manipulates protected resources, so it must be critical. /// It has a demand, so it is safe. /// [SecurityCritical, SecurityTreatAsSafe] public ApplicationProxyInternal Initialize() { SecurityHelper.DemandUIWindowPermission(); _context = ActivationContext.CreatePartialActivationContext(GetApplicationIdentity(), new string[] {_deploymentManifestPath, _applicationManifestPath}); // remove cached trust decision ApplicationTrust at = new ApplicationTrust(GetApplicationIdentity()); System.Security.Policy.ApplicationSecurityManager.UserApplicationTrusts.Remove(at); // Determine trust and apply security PresentationAppDomainManager.IsDebug = true; PresentationAppDomainManager.IsViewer = false; PresentationAppDomainManager.DebugSecurityZoneURL = _debugSecurityZoneURL.Value; TrustManagerContext tmc = new TrustManagerContext(); tmc.NoPrompt = true; tmc.Persist = false; tmc.KeepAlive = false; tmc.IgnorePersistedDecision = true; ApplicationSecurityManager.ApplicationTrustManager.DetermineApplicationTrust(_context, tmc); //ApplicationSecurityManager.DetermineApplicationTrust(_context, tmc); PresentationAppDomainManager.SaveAppDomain = true; ObjectHandle oh = Activator.CreateInstance(_context); if (PresentationAppDomainManager.SaveAppDomain) { AppDomain newDomain = oh.Unwrap() as AppDomain; PresentationAppDomainManager.NewAppDomain = newDomain; } // Create an ApplicationProxyInternal in the new domain. PresentationAppDomainManager appDomainMgrProxy = PresentationAppDomainManager.NewAppDomain.DomainManager as PresentationAppDomainManager; ApplicationProxyInternal proxy = appDomainMgrProxy.CreateApplicationProxyInternal(); proxy.SetDebugSecurityZoneURL(_debugSecurityZoneURL.Value); PresentationAppDomainManager.SaveAppDomain = false; return proxy; } private ApplicationIdentity GetApplicationIdentity() { return new ApplicationIdentity( _deploymentManifest.ToString() + "#" + GetIdFromManifest(_deploymentManifestPath) + "/" + GetIdFromManifest(_applicationManifestPath)); } private string GetIdFromManifest(string manifestName) { FileStream fileStream = new FileStream(manifestName, FileMode.Open, FileAccess.Read); try { using (XmlTextReader reader = new XmlTextReader(fileStream)) { reader.WhitespaceHandling = WhitespaceHandling.None; while (reader.Read()) { if (reader.NodeType == XmlNodeType.Element) { if (reader.NamespaceURI != "urn:schemas-microsoft-com:asm.v1") { continue; } if (reader.LocalName == "assemblyIdentity") { string id = string.Empty; while (reader.MoveToNextAttribute()) { if (reader.Name == "name") { id = reader.Value + id; } else if (reader.Name == "xmlns") { // do nothing } else { id = id + ", " + reader.Name + "=" + reader.Value; } } return id; } } } } } finally { fileStream.Close(); } return string.Empty; } string _deploymentManifestPath; Uri _deploymentManifest; string _applicationManifestPath; string _exePath; SecurityCriticalDataForSet_debugSecurityZoneURL = new SecurityCriticalDataForSet (null); ActivationContext _context; } } // 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
- SecurityManager.cs
- ButtonRenderer.cs
- FileReader.cs
- HealthMonitoringSectionHelper.cs
- ProcessInfo.cs
- RegistryPermission.cs
- TypedTableBase.cs
- RegexStringValidatorAttribute.cs
- PointF.cs
- HttpRequest.cs
- AmbientEnvironment.cs
- SQLGuid.cs
- hebrewshape.cs
- SecurityRequiresReviewAttribute.cs
- SmtpReplyReaderFactory.cs
- PixelFormatConverter.cs
- ResourcesBuildProvider.cs
- WebRequest.cs
- RewritingSimplifier.cs
- OptionalMessageQuery.cs
- PrimitiveSchema.cs
- OptimalTextSource.cs
- TableLayoutSettings.cs
- PartialCachingControl.cs
- Model3D.cs
- FillBehavior.cs
- XmlBindingWorker.cs
- FieldDescriptor.cs
- documentsequencetextview.cs
- TaskFileService.cs
- AppModelKnownContentFactory.cs
- DocumentAutomationPeer.cs
- SettingsPropertyIsReadOnlyException.cs
- _DynamicWinsockMethods.cs
- ResourceContainerWrapper.cs
- EntityDataSourceStatementEditor.cs
- DataGridToolTip.cs
- ComplexLine.cs
- DataGridViewRowHeightInfoPushedEventArgs.cs
- StringValidatorAttribute.cs
- CompiledQueryCacheKey.cs
- WebRequestModulesSection.cs
- TemplateControlBuildProvider.cs
- DisplayInformation.cs
- TextServicesContext.cs
- HttpCapabilitiesBase.cs
- BamlResourceDeserializer.cs
- AlgoModule.cs
- MatrixTransform.cs
- ResourceDisplayNameAttribute.cs
- NamespaceQuery.cs
- SqlUserDefinedTypeAttribute.cs
- BackgroundWorker.cs
- CodeGotoStatement.cs
- DesignTimeVisibleAttribute.cs
- SystemWebCachingSectionGroup.cs
- DataControlFieldCollection.cs
- PersonalizablePropertyEntry.cs
- DefaultTraceListener.cs
- DbProviderManifest.cs
- PreloadHost.cs
- DataGridViewColumnTypePicker.cs
- App.cs
- State.cs
- VirtualPathProvider.cs
- OneOfConst.cs
- ObjectSelectorEditor.cs
- SizeIndependentAnimationStorage.cs
- KernelTypeValidation.cs
- DefaultAutoFieldGenerator.cs
- TypedRowHandler.cs
- _Win32.cs
- TypeUtil.cs
- DLinqAssociationProvider.cs
- DataGridPageChangedEventArgs.cs
- SchemaRegistration.cs
- SqlResolver.cs
- CellCreator.cs
- DirectionalLight.cs
- ScriptMethodAttribute.cs
- WmlCommandAdapter.cs
- BaseTemplateParser.cs
- DebugView.cs
- AdapterUtil.cs
- Quack.cs
- UInt64Converter.cs
- DataGridViewDataConnection.cs
- ActivityCodeGenerator.cs
- SecurityTokenAuthenticator.cs
- RowUpdatingEventArgs.cs
- IERequestCache.cs
- DataStreams.cs
- DnsEndPoint.cs
- PropertyValue.cs
- XPathDocumentNavigator.cs
- SqlCharStream.cs
- GridPatternIdentifiers.cs
- keycontainerpermission.cs
- Error.cs
- QuaternionValueSerializer.cs