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
- StateMachineWorkflow.cs
- Guid.cs
- ReaderContextStackData.cs
- XPathItem.cs
- LogRecordSequence.cs
- DataGridViewAutoSizeColumnModeEventArgs.cs
- XmlMapping.cs
- WindowsRegion.cs
- MimeXmlReflector.cs
- DataContractSerializer.cs
- MetadataPropertyvalue.cs
- PointIndependentAnimationStorage.cs
- JsonServiceDocumentSerializer.cs
- MarkupCompiler.cs
- WindowsToolbar.cs
- StringBuilder.cs
- NeutralResourcesLanguageAttribute.cs
- AxisAngleRotation3D.cs
- Misc.cs
- ValueTypeFixupInfo.cs
- XamlWriter.cs
- EntityProviderServices.cs
- ImageAttributes.cs
- LateBoundBitmapDecoder.cs
- ELinqQueryState.cs
- TargetParameterCountException.cs
- RenamedEventArgs.cs
- HttpFormatExtensions.cs
- QilReplaceVisitor.cs
- TextTreeText.cs
- MD5CryptoServiceProvider.cs
- NumberFunctions.cs
- handlecollector.cs
- __ComObject.cs
- Operator.cs
- InvalidTimeZoneException.cs
- RawStylusInput.cs
- RecordsAffectedEventArgs.cs
- PackageFilter.cs
- ListView.cs
- OpenTypeCommon.cs
- QuestionEventArgs.cs
- QueryGenerator.cs
- AggregateNode.cs
- UInt64.cs
- KnownTypesHelper.cs
- WorkflowValidationFailedException.cs
- HMACSHA512.cs
- InstanceData.cs
- ObjectResult.cs
- UnauthorizedAccessException.cs
- ConsoleKeyInfo.cs
- StorageRoot.cs
- ThreadPoolTaskScheduler.cs
- WebPartManagerInternals.cs
- XmlDocumentViewSchema.cs
- XmlTextReader.cs
- StringFunctions.cs
- ListBindingHelper.cs
- NamedObject.cs
- ValidatorCompatibilityHelper.cs
- SqlServices.cs
- UrlAuthFailedErrorFormatter.cs
- InheritanceRules.cs
- PolyQuadraticBezierSegment.cs
- RunClient.cs
- BaseParaClient.cs
- SemaphoreSecurity.cs
- CellParagraph.cs
- TypeDescriptionProviderAttribute.cs
- EventlogProvider.cs
- DataGridTextBoxColumn.cs
- ColumnMapVisitor.cs
- XmlPreloadedResolver.cs
- SessionEndedEventArgs.cs
- CodeCatchClauseCollection.cs
- ModelPropertyDescriptor.cs
- InkCanvasFeedbackAdorner.cs
- DesignerActionService.cs
- odbcmetadatacollectionnames.cs
- CheckBoxBaseAdapter.cs
- DataGridViewRow.cs
- SqlHelper.cs
- ProjectionPruner.cs
- CodeIndexerExpression.cs
- Facet.cs
- SqlCharStream.cs
- ToolStripContentPanel.cs
- Pen.cs
- NotFiniteNumberException.cs
- HtmlInputPassword.cs
- RowsCopiedEventArgs.cs
- ExtendedProtectionPolicyTypeConverter.cs
- OneOfConst.cs
- MsdtcWrapper.cs
- TextTreeTextElementNode.cs
- QuaternionRotation3D.cs
- SpecialFolderEnumConverter.cs
- FontNameConverter.cs
- BindingContext.cs