DocobjHost.cs source code in C# .NET

Source code for the .NET framework in C#

                        

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

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