WebBrowser.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / wpf / src / Framework / System / Windows / Controls / WebBrowser.cs / 3 / WebBrowser.cs

                            //------------------------------------------------------------------------------ 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// 
//
// Description: 
//      WebBrowser is a wrapper for the webbrowser activex control 
//      Copied from webbrowser.cs in winforms
// 
// History
//  04/17/05    KusumaV      Created
//  02/22/08    huwang       Expose the WebBrowser control
//  04/24/08    ChangoV     Implemented hosting the WebOC in the browser process for IE 7+ Protected Mode 
//-----------------------------------------------------------------------------
 
using System; 
using System.ComponentModel;
using System.Runtime.InteropServices; 
using System.Windows;
using MS.Win32;
using System.Security;
using System.Security.Permissions; 
using System.Windows.Controls.Primitives; //PopupRoot
using MS.Internal.PresentationFramework; 
using MS.Internal.Utility ; 
using MS.Internal.AppModel; //RootBrowserWindow
using System.Windows.Interop; 
using System.Windows.Input;
using System.Windows.Threading;
using System.Diagnostics;
using System.Windows.Navigation; 
using System.IO; //Stream
using System.Threading; // thread 
using MS.Internal; 
using MS.Internal.Controls;
using System.IO.Packaging; 

/* Overview of Keyboard Input Routing for the WebOC

The WebOC receives regular alphanumeric keyboard input via its WndProc. Whoever is running the message loop 
calls DispatchMessage() after any preprocessing and special routing, and the message gets to the WndProc of
the window with focus. 
 
"Accelerator" keys need to be passed to the WebOC via IOleInPlaceActiveObject::TranslateAccelerator().
For example, these include the navigation keys and clipboard keys. Depending on how the WebOC is hosted, 
input messages flow somewhat differently:
 1) Standalone application:
     HwndSource.OnPreprocessMessage() -> InputManager ->(routed event) HwndHost.OnKeyDown() ->
     WebBrowser.IKeyboardInputSink.TranslateAccelerator(). 
 2) In PresentationHost (on our UI thread):
     ComponentDispatcher.ThreadPreprocessMessage() -> WebBrowser.OnPreprocessMessageThunk() -> 
     WebBrowser.IKeyboardInputSink.TranslateAccelerator(). 
    Because a child window HwndSource, which is what we have for the RootBrowserWindow, does not route
    messages directly from the message loop like in case (1), we need an alternate similar solution. That's 
    the WeakEventPreprocesMessage listener. Another supposed benefit of such direct message routing, as opposed
    to letting input events go through our element tree, is to prevent tampering with input destined for the
    WebOC, which may have a frame navigated to a third-party site...
 3) In the browser process (IE 7+, when in protected mode): The WebOC is run on a dedicated thread. There is a 
    message loop running for it. Before calling TranslateMessage & DispatchMessage, it calls WebOC's
    IOleInPlaceActiveObject::TranslateAccelerator(). 
 
Other accelerator handling APIs:
 - IDocHostUIHandler::TranslateAccelerator(): This appears to be called by the WebOC for everything passed to it 
     via IOleInPlaceActiveObject::TranslateAccelerator(), so it's not interesting to us.
 - IOleControlSite::TranslateAccelerator(): The WebOC is passing MSGs it gets via IOleInPlaceActiveObject::
   TranslateAccelerator() and its WndProc but doesn't handle. Our WebBrowserSite takes advantage of this to
   handle tabbing out of the WebOC. 
*/
 
namespace System.Windows.Controls 
{
    /// 
    /// This is a wrapper over the native WebBrowser control implemented in shdocvw.dll.
    ///
    /// 
    /// The WebBrowser class is currently not thread safe. Multi-threading could corrupt the class internal state, 
    /// which could lead to security exploits (see example in devdiv bug #196538). So we enforce thread affinity.
    ///  
    public sealed class WebBrowser : ActiveXHost, IKeyboardInputSink 
    {
        //---------------------------------------------- 
        //
        // Constructors
        //
        //---------------------------------------------- 

        #region Constructor 
 
        static WebBrowser()
        { 
            if (IsWebOCPermissionRestricted)
            {
                RegisterWithRBW();
            } 
            TurnOnXPSP2Mitigations();
        } 
 
        ///
        ///     Critical - accesses critical Ctor and create WeakEventPreprocessMessage. 
        ///     PublicOK - creating web browser considered safe.
        ///
        ///                   Known threats and the justification as to why they are mitigated :
        /// 
        ///                     Uri is validated at set time. An attempts to navigate outside site of origin will fail the demand for web-permission.
        ///                     Attempts to navigate the HTML to another page are mitigated by "Site Lock" feature. 
        ///                     Attempts to show popup's above HTML are mitigated by popup work. 
        ///                     Running script inside WebOC - considered ok as script is Internet Zone.
        ///                     Running activeX controls - considered safe. Equivalent functionality is enabled through web-pages. 
        ///                     Cookies: The WebOC thinks it's a top-level browser. Thus cookies it sets will always
        ///                         have 1st party status, which wouldn't be right if the WebOC is in an XBAP that is
        ///                         third party to the containing HTML page. But now PresentationHost intercepts all
        ///                         calls to the WinInet cookie APIs and will add the 3rd party flag when necessary. 
        ///                         V3 SP2 Update - WebOCHostedInBrowserProcess - The cookie shim does not apply
        ///                             in this case. To prevent the cookie status elevation problem, the native code 
        ///                             in PresentationHostDll fails creating the WebOC. 
        ///
        /// 
        [ SecurityCritical ]
        public WebBrowser()
            : base( WEBOC_GUID , true )
        { 
            // Check whether feature is disabled
            if (SafeSecurityHelper.IsFeatureDisabled(SafeSecurityHelper.KeyToRead.WebBrowserDisable)) 
            { 
                // in case the registry key is '1' then demand unrestricted WebBrowserPermission to create it
                SecurityHelper.DemandWebBrowserPermission(); 
            }
            else
            {
                // Feature is enabled - demand Safe level to create this object, granted in Partial Trust by default 
                (new WebBrowserPermission(WebBrowserPermissionLevel.Safe)).Demand();
            } 
 
            // If the webbrowser permission is restricted, we don't allow webbrowser to be inside Popup.
            if (IsWebOCPermissionRestricted) 
            {
                Loaded += new RoutedEventHandler(LoadedHandler);
            }
 
            // Attach our hook to ComponentDispatcher.ThreadPreprocessMessage. It is the second event called
            // when the messsages are coming in. 
            if (Application.InBrowserHostedApp()) 
            {
                _weakEventPreprocessMessage = new WeakEventPreprocessMessage(this); 
            }

            _hostingAdaptor = IsWebOCHostedInBrowserProcess ?
                new WebOCHostedInBrowserAdaptor(this) : new WebOCHostingAdaptor(this); 
        }
 
        #endregion Constructor 

        //---------------------------------------------- 
        //
        // Public Methods
        //
        //---------------------------------------------- 

        #region Public Methods 
 
        /// 
        /// Navigate to the WebBrowser control to the given uri. 
        /// 
        /// Uri being navigated to.
        public void Navigate(Uri source)
        { 
            Navigate(source, null, null, null);
        } 
 
        /// 
        /// Navigate to the WebBrowser control to the given uri. 
        /// 
        /// Uri being navigated to.
        /// The name of the frame in which to load the document.
        /// HTTP POST data such as form data. 
        /// HTTP headers to add to the default headers.
        public void Navigate(Uri source, string targetFrameName, byte[] postData, string additionalHeaders) 
        { 
            object objTargetFrameName = (object)targetFrameName;
            object objPostData = (object)postData; 
            object objHeaders = (object)additionalHeaders;

            DoNavigate(source, ref objTargetFrameName, ref objPostData, ref objHeaders);
        } 

        ///  
        /// Navigates the the stream of a html page. 
        /// 
        /// The stream that contains the content of a html document 
        public void NavigateToStream(Stream stream)
        {
            if (stream == null)
            { 
                throw new ArgumentNullException("stream");
            } 
 
            DocumentStream = stream;
            // We navigate to "about:blank" when Source is set to null. 
            // When we get NavigateComplete event, we load the stream via the IPersistStreamInit interface.
            Source = null;
        }
 
        /// 
        /// Navigates to the text of a html page. 
        ///  
        /// The string that contains the content of a html document
        public void NavigateToString(String text) 
        {
            if (string.IsNullOrEmpty(text))
            {
                throw new ArgumentNullException("text"); 
            }
 
            MemoryStream ms = new MemoryStream(text.Length); 
            StreamWriter sw = new StreamWriter(ms);
            sw.Write(text); 
            sw.Flush();
            ms.Position = 0;

            NavigateToStream(ms); 
        }
 
        ///  
        /// Navigates the WebBrowser control to the previous page if available.
        ///  
        ///
        ///     Critical - accesses the critical unmanaged interface of the control.
        ///     Public OK - This code does not expose the interface.
        ///               - Going back to the previous page within the WebBrowser control is considered safe. 
        ///
        [SecurityCritical] 
        public void GoBack() 
        {
            VerifyAccess(); 

            AxIWebBrowser2.GoBack();
        }
 
        /// 
        /// Navigates the WebBrowser control to the next page if available. 
        ///  
        ///
        ///     Critical - accesses the critical unmanaged interface of the control. 
        ///     Public OK - This does not expose the interface.
        ///               - Going forward to the next page within the WebBrowser is considered safe.
        ///
        [SecurityCritical] 
        public void GoForward()
        { 
            VerifyAccess(); 

            AxIWebBrowser2.GoForward(); 
        }


        ///  
        /// Refreshes the current page.
        ///  
        /// 
        ///     Critical - accesses the critical unmanaged interface of the control.
        ///     Public OK - This does not expose the interface. 
        ///               - Refreshing the WebBrowser is considered safe.
        ///
        [SecurityCritical]
        public void Refresh() 
        {
            VerifyAccess(); 
 
            AxIWebBrowser2.Refresh();
        } 

        /// 
        /// Refreshes the current page.
        ///  
        ///
        ///     Critical - accesses the critical unmanaged interface of the control. 
        ///     Public OK - This does not expose the interface. 
        ///               - Refreshing the WebBrowser is considered safe.
        /// 
        /// Whether to refresh without cache validation by sending "Pragma:no-cache" header to the server.
        [SecurityCritical]
        public void Refresh(bool noCache)
        { 
            VerifyAccess();
 
            // Out of the three options of RefreshConstants, we only expose two: REFRESH_NORMAL and REFRESH_COMPLETELY, 
            // because the thrid option, RefreshConstants.REFRESH_IFEXPIRED, is not implemented by IWebBrowser2.Refresh.
            // And those two options cover the common scenarios. 
            //
            // enum RefreshConstants{
            //      REFRESH_NORMAL = 0,
            //      REFRESH_IFEXPIRED = 1 /* Not supported by IWebBrowser2*/, 
            //      REFRESH_COMPLETELY = 3
            // } 
            int refreshOption = noCache ? 3 : 0; 
            object refreshOptionObject = (object) refreshOption;
            AxIWebBrowser2.Refresh2(ref refreshOptionObject); 
        }

        /// 
        /// Executes an Active Scripting function defined in the HTML document currently loaded in the WebBrowser control. 
        /// 
        /// The name of the script method to invoke. 
        /// The object returned by the Active Scripting call. 
        public object InvokeScript(string scriptName)
        { 
            return InvokeScript(scriptName, null);
        }

        ///  
        /// Executes an Active Scripting function defined in the HTML document currently loaded in the WebBrowser control.
        ///  
        /// The name of the script method to invoke. 
        /// 
        /// The object returned by the Active Scripting call. 
        /// 
        /// Critical: Calls critical property and method.
        /// Public OK - Demand WebPermission to protect againt cross domain scripting attacks.
        ///           - We count on WebOC to "sandbox" the script to the zone of the page. 
        /// 
        [SecurityCritical] 
        public object InvokeScript(string scriptName, params object[] args) 
        {
            VerifyAccess(); 

            if (string.IsNullOrEmpty(scriptName))
            {
                throw new ArgumentNullException("scriptName"); 
            }
 
            // Protect against the cross domain scripting attacks. 
            // We rely on the site locking feature in gerneral. But in IE 6 server side redirect is not blocked.
            // (In IE 7 it is blocked by turning on the DOCHOSTUIFLAG.ENABLE_REDIRECT_NOTIFICATION flag so that 
            // the additional BeforeNavigate2 event is fired for server side redirect.)

            // If it is our internal navigation to blank for navigating to null or load stream,
            // or before any navigation has happened, Source will be null. 
            Uri currentSource = Source;
            if (currentSource != null) 
            { 
                SecurityHelper.DemandWebPermission(currentSource);
            } 

            UnsafeNativeMethods.IDispatch scriptObject = null;
            // Throw if the current document object is not avaiable.
            UnsafeNativeMethods.IHTMLDocument htmlDocument = NativeHTMLDocument; 
            if (htmlDocument != null)
            { 
                scriptObject = htmlDocument.GetScript() as UnsafeNativeMethods.IDispatch; 
            }
 
            object retVal = null;
            if (scriptObject != null)
            {
                NativeMethods.tagDISPPARAMS dp = new NativeMethods.tagDISPPARAMS(); 
                dp.rgvarg = IntPtr.Zero;
                try 
                { 
                    // If we use reflection to call script code, we need to Assert for the UnmanagedCode permission.
                    // But it will be a security issue when the WPF app makes a framework object available to the 
                    // hosted script via ObjectForScripting or as paramter of InvokeScript, and calls the framework
                    // API that demands the UnmanagedCode permission. We do not want the demand to succeed. However,
                    // The stack walk will igore the native frames and keeps going until it reaches the Assert.
                    // That is why we switch to invoking the script via IDispatch with SUCS on the methods. 
                    Guid guid = Guid.Empty;
                    string[] names = new string[] { scriptName }; 
                    int[] dispids = new int[] { NativeMethods.DISPID_UNKNOWN }; 
                    scriptObject.GetIDsOfNames(ref guid, names, 1,
                                            Thread.CurrentThread.CurrentCulture.LCID, dispids); 
                    if (args != null)
                    {
                        // Reverse the arg order so that parms read naturally after IDispatch. (WinForms bug 187662)
                        Array.Reverse(args); 
                    }
                    dp.rgvarg = (args == null) ? IntPtr.Zero : UnsafeNativeMethods.ArrayToVARIANTHelper.ArrayToVARIANTVector(args); 
                    dp.cArgs = (uint)((args == null) ? 0 : args.Length); 
                    dp.rgdispidNamedArgs = IntPtr.Zero;
                    dp.cNamedArgs = 0; 

                    object[] retVals = new object[1];

                    scriptObject.Invoke(dispids[0], ref guid, Thread.CurrentThread.CurrentCulture.LCID, 
                            NativeMethods.DISPATCH_METHOD, dp,
                            retVals, new NativeMethods.tagEXCEPINFO(), null); 
 
                    retVal = retVals[0];
                } 
                finally
                {
                    if (dp.rgvarg != IntPtr.Zero)
                    { 
                        UnsafeNativeMethods.ArrayToVARIANTHelper.FreeVARIANTVector(dp.rgvarg, args.Length);
                    } 
                } 
            }
            else 
            {
                throw new InvalidOperationException(SR.Get(SRID.CannotInvokeScript));
            }
            return retVal; 
        }
 
        #endregion Public Methods 

        //---------------------------------------------- 
        //
        // Public Properties
        //
        //---------------------------------------------- 

        #region Public Properties 
 
        /// 
        /// Gets or sets the current uri of the WebBrowser control. 
        /// 
        /// 
        ///     Critical - Accesses the critical unmanaged interface of the control.
        ///     Public OK - This does not expose the interface. 
        ///               - Return the current uri is considered as safe because we only allow navigation to
        ///                 site-of-origin for top level navigation in parital trust. 
        ///  
        public Uri Source
        { 
            set
            {
                VerifyAccess();
 
                Navigate(value);
            } 
            [SecurityCritical] 
            get
            { 
                VerifyAccess();

                // Current url, return IWebBrowser2.LocationURL.
                string urlString = AxIWebBrowser2.LocationURL; 

                // When source set to null or navigating to stream/string, we navigate to "about:blank" 
                // internally. Make sure we return null in those cases. 
                if (InternalBlankNavigation)
                { 
                    Invariant.Assert(string.Compare(urlString, AboutBlankUriString, StringComparison.OrdinalIgnoreCase) == 0);
                    urlString = null;
                }
 
                return (string.IsNullOrEmpty(urlString) ? null : new Uri(urlString));
            } 
        } 

        ///  
        /// Gets a value indicating whether a previous page in navigation history is available.
        /// 
        public bool CanGoBack
        { 
            get
            { 
                VerifyAccess(); 

                return (!IsDisposed && _canGoBack); 
            }
        }

        ///  
        /// Gets a value indicating whether a subsequent page in navigation history is available.
        ///  
        public bool CanGoForward 
        {
            get 
            {
                VerifyAccess();

                return (!IsDisposed && _canGoForward); 
            }
        } 
 
        /// 
        /// Gets or sets an object that can be accessed by scripting code that is contained 
        /// within a Web page in the WebBrowser control.
        /// 
        /// 
        ///     Critical: Calls Marshal.IsTypeVisibleFromCom(), which has a LinkDemand for UnmanagedCode. 
        ///     PublicOK: We do not expose any security critical info.
        ///  
        public object ObjectForScripting 
        {
            get 
            {
                VerifyAccess();

                return _objectForScripting; 
            }
            [SecurityCritical] 
            set 
            {
                VerifyAccess(); 

                if (value != null)
                {
                    Type t = value.GetType(); 
                    if (!System.Runtime.InteropServices.Marshal.IsTypeVisibleFromCom(t))
                    { 
                        throw new ArgumentException(SR.Get(SRID.NeedToBeComVisible)); 
                    }
                } 

                _objectForScripting = value;
                _hostingAdaptor.ObjectForScripting = value;
            } 
        }
 
        ///  
        /// The HtmlDocument for page hosted in the html page.  If no page is loaded, it returns null.
        ///  
        ///
        ///     Critical - exposes the critical unmanaged interface of the DOM object.
        ///     Public OK - Demands unrestricted WebPermission.
        /// 
        public object Document
        { 
            [SecurityCritical] 
            get
            { 
                VerifyAccess();

                SecurityHelper.DemandUnmanagedCode();
 
                return AxIWebBrowser2.Document;
            } 
        } 

        #endregion Public Properties 

        //----------------------------------------------
        //
        // Public Events 
        //
        //---------------------------------------------- 
 
        #region Public Events
 
        /// 
        /// Raised before a navigation takes place. This event is fired only for
        /// top-level page navigations.
        /// Canceling this event prevents the WebBrowser control from navigating. 
        /// 
        public event NavigatingCancelEventHandler Navigating; 
 
        /// 
        /// Raised after navigation the target has been found and the download has begun. This event 
        /// is fired only for top-level page navigations.
        /// 
        public event NavigatedEventHandler Navigated;
 
        /// 
        /// Raised when the WebBrowser control finishes loading a document. This event 
        /// is fired only for top-level page navigations. 
        /// 
        public event LoadCompletedEventHandler LoadCompleted; 

        #endregion Public Events

        //---------------------------------------------- 
        //
        // Protected Methods 
        // 
        //----------------------------------------------
 
        #region Protected Methods

        protected override void Dispose(bool disposing)
        { 
            base.Dispose(disposing);
 
            if (disposing) 
            {
                if (_weakEventPreprocessMessage != null) 
                {
                    _weakEventPreprocessMessage.Dispose();
                    _weakEventPreprocessMessage = null;
                } 
            }
        } 
 
        #endregion Protected Methods
 
        //----------------------------------------------
        //
        // Internal Methods
        // 
        //----------------------------------------------
 
        #region Internal Methods 

        internal void OnNavigating(NavigatingCancelEventArgs e) 
        {
            VerifyAccess();

            if (Navigating != null) 
            {
                Navigating(this, e); 
            } 
        }
 
        internal void OnNavigated(NavigationEventArgs e)
        {
            VerifyAccess();
 
            if (Navigated != null)
            { 
                Navigated(this, e); 
            }
        } 

        internal void OnLoadCompleted(NavigationEventArgs e)
        {
            VerifyAccess(); 

            if (LoadCompleted != null) 
            { 
                LoadCompleted(this, e);
            } 
        }


        ///  
        /// Critical: As a native object, the WebOC should not be exposed directly to partial-trust code.
        ///  
        [SecurityCritical] 
        internal override object CreateActiveXObject(Guid clsid)
        { 
            Debug.Assert(clsid == WEBOC_GUID);
            return _hostingAdaptor.CreateWebOC();
        }
 
        /// This will be called when the native ActiveX control has just been created.
        /// Inheritors of this class can override this method to cast the nativeActiveXObject 
        /// parameter to the appropriate interface. They can then cache this interface 
        /// value in a member variable. However, they must release this value when
        /// DetachInterfaces is called (by setting the cached interface variable to null). 
        /// 
        ///     Critical: This code can be exploited to pass in a bogus Activex object
        /// 
        [SecurityCritical] 
        internal override void AttachInterfaces(object nativeActiveXObject)
        { 
            //cache the interface 
            this._axIWebBrowser2 = (UnsafeNativeMethods.IWebBrowser2)nativeActiveXObject;
 
            //
            //Initializations
            //
            //By default _axIWebBrowser2.RegisterAsDropTarget and _axIWebBrowser2.RegisterAsBrowser 
            //are set to false. Since we control navigations through webbrowser events, we can set these
            //to true if needed to allow drag n drop of documents on to the control and 
            //allow frame targetting respectively. Think its better to lock it down until this is spec-ed out 

            //Set Silent property to true to suppress error dialogs (or demand permission for it here and 
            //set it accordingly)
        }

        /// See AttachInterfaces for a description of when to override DetachInterfaces. 
        /// 
        ///     Critical: This code references the critical object _axIWebBrowser2 
        ///     TreatAsSafe: It does not expose it 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        internal override void DetachInterfaces()
        {
            //clear the interface. Base will release the COMObject
            _axIWebBrowser2 = null; 
        }
 
        ///  
        ///     Attaches to the DWebBrowserEvents2 connection point.
        ///  
        ///
        ///     Critical - uses the critical _axIWebBrowser2 and calls _hostingAdaptor.CreateEventSink().
        ///     TreatAsSafe - registering to handle events is ok. The event sink object is not exposed.
        /// 
        [ SecurityCritical, SecurityTreatAsSafe ]
        internal override void CreateSink() 
        { 
            Debug.Assert(_axIWebBrowser2 != null);
            _cookie = new ConnectionPointCookie(_axIWebBrowser2, 
                    _hostingAdaptor.CreateEventSink(),
                    typeof(UnsafeNativeMethods.DWebBrowserEvents2));
        }
 
        ///
        ///     Releases the DWebBrowserEvents2 connection point. 
        /// 
        /// 
        /// Critical: Disconnecting the event sink breaks the site-locking feature. 
        /// 
        [SecurityCritical]
        internal override void DetachSink()
        { 
            //If we have a cookie get rid of it
            if ( _cookie != null) 
            { 
                _cookie.Disconnect();
                _cookie = null; 
            }
        }

        /// 
        ///     Needs to link-demand as base method link-demanded.
        /// 
        ///     Critical - calls critical WebBrowserSite - ctor. 
        ///
        [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)] 
        [SecurityCritical]
        internal override ActiveXSite CreateActiveXSite()
        {
            return new WebBrowserSite(this); 
        }
 
        ///  
        ///     GetDrawing - Returns the drawing content of this Visual.
        ///  
        /// 
        ///     This returns a bitmap obtained by calling the PrintWindow Win32 API.
        /// 
        ///  
        ///     Critical:This code Asserts an elevated permission.
        ///     TreatAsSafe: only site of origin pages can be loaded in PT, so giving out a bitmap of this window is OK. 
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        internal override System.Windows.Media.DrawingGroup GetDrawing() 
        {
            // SecurityHelper.DemandWebPermission(_source.Value); // _source is null by now...

            (new UIPermission(UIPermissionWindow.AllWindows)).Assert(); // Blessed assert 
            try
            { 
                return base.GetDrawing(); 
            }
            finally 
            {
                UIPermission.RevertAssert();
            }
        } 

        #endregion Internal Methods 
 
        //----------------------------------------------
        // 
        // Internal Properties
        //
        //----------------------------------------------
 
        #region Internal Properties
 
        ///  
        ///     Critical: This code exposes an unmanaged interface with SupressUnmanagedCodeSecurity
        ///               attribute on some methods. 
        /// 
        [SecurityCritical]
        internal UnsafeNativeMethods.IHTMLDocument NativeHTMLDocument
        { 
            [SecurityCritical]
            get 
            { 
                object objDoc = AxIWebBrowser2.Document;
                if (objDoc != null) 
                {
                    UnsafeNativeMethods.IHTMLDocument iHTMLDocument = objDoc as UnsafeNativeMethods.IHTMLDocument;

                    // Demand WebPermission NetworkAccess.Connect if we expose this publicly 
                    return iHTMLDocument;
                } 
                return null; 
            }
        } 

        /// 
        ///     Critical: This code exposes an unmanaged interface with SupressUnmanagedCodeSecurity
        ///               attribute on some methods 
        /// 
        [DebuggerBrowsable(DebuggerBrowsableState.Never)] 
        internal UnsafeNativeMethods.IWebBrowser2 AxIWebBrowser2 
        {
            [SecurityCritical] 
            get
            {
                if (_axIWebBrowser2 == null)
                { 
                    if (!IsDisposed)
                    { 
                        //This should call AttachInterfaces which will set this member variable 
                        //We don't want to force the state to InPlaceActive yet since we don't
                        //have the parent handle yet. 
                        TransitionUpTo(ActiveXHelper.ActiveXState.Running);
                    }
                    else
                    { 
                        throw new System.ObjectDisposedException(GetType().Name);
                    } 
                } 
                // We still don't have _axIWebBrowser2. Throw an exception.
                if (_axIWebBrowser2 == null) 
                {
                    throw new InvalidOperationException(SR.Get(SRID.WebBrowserNoCastToIWebBrowser2));
                }
                return _axIWebBrowser2; 
            }
        } 
 
        internal WebOCHostingAdaptor HostingAdaptor { get { return _hostingAdaptor; } }
 
        internal Stream DocumentStream
        {
            get
            { 
                return _documentStream;
            } 
            set 
            {
                _documentStream = value; 
            }
        }

        // This property indicates whether we are navigating to "about:blank" internally 
        // because Source is set to null or navigating to stream.
        ///  
        ///    Critical: _internalBlankNavigation is involved in making security decisions. 
        ///              We navigate to about:blank internally when navigating to null or navigation to string/stream.
        ///              This flag is used to avoid security check per navigation source in order to enable navigation 
        ///              to about:blank in partial trust.
        ///              Setting this property to true will by pass the site locking logic. Currently it is only true when
        ///              navigating to about:blank internally for the scenarios described above.
        ///  
        internal bool InternalBlankNavigation
        { 
            get 
            {
                return _internalBlankNavigation.Value; 
            }
            [SecurityCritical]
            set
            { 
                _internalBlankNavigation.Value = value;
            } 
        } 

        ///  
        /// Starting from v3 SP2, we host the WebOC in the IE 7+ browser process when it's running at low
        /// integrity level ('protected mode'). This is to prevent elevation of privilege via our process in
        /// case a bug in the WebOC is exploited. PresentationHost is on IE's silent elevation list; thus,
        /// potentially bigger damange could be effected by running malicious code in our process. 
        /// 
        internal static bool IsWebOCHostedInBrowserProcess 
        { 
            get
            { 
                return BrowserInteropHelper.IsBrowserLowIntegrityProcess.Value &&
                       IsWebOCPermissionRestricted;
            }
        } 

        #endregion Internal Properties 
 
        //----------------------------------------------
        // 
        // Internal Fields
        //
        //----------------------------------------------
 
        #region Internal Fields
 
        internal bool _canGoBack; 
        internal bool _canGoForward;
        internal const string AboutBlankUriString = "about:blank"; 

        #endregion Internal Fields

        //---------------------------------------------- 
        //
        // Private Methods 
        // 
        //----------------------------------------------
 
        #region Private Methods

        /// 
        ///     Critical:This code gets critical data, PresentationSource 
        ///     TreatAsSafe: The PresentationSource is not exposed.
        ///  
        [SecurityCritical, SecurityTreatAsSafe] 
        private void LoadedHandler(object sender, RoutedEventArgs args)
        { 
            PresentationSource pSource = PresentationSource.CriticalFromVisual(this);

            // Note that we cannot assert this condition here. The reason is that this element might have
            // been disconnected from the tree through one of its parents even while it waited for the 
            // pending Loaded event to fire. More details for this scenario can be found in the
            // Windows OS Bug#1981485. 
            // Invariant.Assert(pSource != null, "Loaded has fired. PresentationSource shouldn't be null"); 

            if (pSource != null && pSource.RootVisual is PopupRoot) 
            {
                throw new InvalidOperationException(SR.Get(SRID.CannotBeInsidePopup));
            }
        } 

        private static void RegisterWithRBW() 
        { 
            // if we are browser hosted, rbw should have been created here.
            // 
            if (RootBrowserWindow != null)
            {
                RootBrowserWindow.AddLayoutUpdatedHandler();
            } 
        }
 
        // Turn on all the XPSP2 mitigations. 
        // We do it programmatically instead of adding reg-keys.
        // So that these are on on all avalon apps. 
        ///
        ///     Critical - calls critical code.
        ///        TreatAsSafe - turns on all the XPSP2 features that make the browser more lock-downed.
        /// 
        [ SecurityCritical, SecurityTreatAsSafe ]
        private static void TurnOnXPSP2Mitigations() 
        { 
            if (Environment.OSVersion.Version.Major == 5 && Environment.OSVersion.Version.Minor == 2)
            { 
                // XPSP2 mitigations - not available on Server 2003.
                // DevDiv
                return ;
            } 

            // NOTE: If the WebOC is hosted in the browser's process, the flags we set here will have no 
            // effect on it. This is somewhat unfortunate because we may get differences in behavior, but it 
            // shouldn't be much of a security issue because we host the WebOC in the browser's process when
            // it is running at low integrity level (IE 'protected mode'), so the WebOC is in a stronger 
            // sandbox there.

            // DevDiv bug 163248 - additional mitigations needed for IE 7.
 
            UnsafeNativeMethods.CoInternetSetFeatureEnabled( NativeMethods.FEATURE_OBJECT_CACHING, NativeMethods.SET_FEATURE_ON_PROCESS, true ) ;
            UnsafeNativeMethods.CoInternetSetFeatureEnabled( NativeMethods.FEATURE_ZONE_ELEVATION, NativeMethods.SET_FEATURE_ON_PROCESS, true ) ; 
            UnsafeNativeMethods.CoInternetSetFeatureEnabled( NativeMethods.FEATURE_MIME_HANDLING, NativeMethods.SET_FEATURE_ON_PROCESS, true ) ; 
            UnsafeNativeMethods.CoInternetSetFeatureEnabled( NativeMethods.FEATURE_MIME_SNIFFING, NativeMethods.SET_FEATURE_ON_PROCESS, true ) ;
            UnsafeNativeMethods.CoInternetSetFeatureEnabled( NativeMethods.FEATURE_WINDOW_RESTRICTIONS, NativeMethods.SET_FEATURE_ON_PROCESS, true ) ; 
            UnsafeNativeMethods.CoInternetSetFeatureEnabled( NativeMethods.FEATURE_WEBOC_POPUPMANAGEMENT, NativeMethods.SET_FEATURE_ON_PROCESS, true ) ;
            UnsafeNativeMethods.CoInternetSetFeatureEnabled( NativeMethods.FEATURE_BEHAVIORS, NativeMethods.SET_FEATURE_ON_PROCESS, true ) ;
            UnsafeNativeMethods.CoInternetSetFeatureEnabled( NativeMethods.FEATURE_DISABLE_MK_PROTOCOL, NativeMethods.SET_FEATURE_ON_PROCESS, true ) ;
            UnsafeNativeMethods.CoInternetSetFeatureEnabled( NativeMethods.FEATURE_LOCALMACHINE_LOCKDOWN, NativeMethods.SET_FEATURE_ON_PROCESS, true ) ; 
            UnsafeNativeMethods.CoInternetSetFeatureEnabled( NativeMethods.FEATURE_SECURITYBAND, NativeMethods.SET_FEATURE_ON_PROCESS, true ) ;
            UnsafeNativeMethods.CoInternetSetFeatureEnabled( NativeMethods.FEATURE_RESTRICT_ACTIVEXINSTALL, NativeMethods.SET_FEATURE_ON_PROCESS, true ) ; 
            UnsafeNativeMethods.CoInternetSetFeatureEnabled( NativeMethods.FEATURE_VALIDATE_NAVIGATE_URL, NativeMethods.SET_FEATURE_ON_PROCESS, true ) ; 
            UnsafeNativeMethods.CoInternetSetFeatureEnabled( NativeMethods.FEATURE_RESTRICT_FILEDOWNLOAD, NativeMethods.SET_FEATURE_ON_PROCESS, true ) ;
            UnsafeNativeMethods.CoInternetSetFeatureEnabled( NativeMethods.FEATURE_ADDON_MANAGEMENT, NativeMethods.SET_FEATURE_ON_PROCESS, true ) ; 
            UnsafeNativeMethods.CoInternetSetFeatureEnabled( NativeMethods.FEATURE_PROTOCOL_LOCKDOWN, NativeMethods.SET_FEATURE_ON_PROCESS, true ) ;
            UnsafeNativeMethods.CoInternetSetFeatureEnabled( NativeMethods.FEATURE_HTTP_USERNAME_PASSWORD_DISABLE, NativeMethods.SET_FEATURE_ON_PROCESS, true ) ;
            UnsafeNativeMethods.CoInternetSetFeatureEnabled( NativeMethods.FEATURE_SAFE_BINDTOOBJECT , NativeMethods.SET_FEATURE_ON_PROCESS, true ) ;
            UnsafeNativeMethods.CoInternetSetFeatureEnabled( NativeMethods.FEATURE_UNC_SAVEDFILECHECK , NativeMethods.SET_FEATURE_ON_PROCESS, true ) ; 
            UnsafeNativeMethods.CoInternetSetFeatureEnabled( NativeMethods.FEATURE_GET_URL_DOM_FILEPATH_UNENCODED , NativeMethods.SET_FEATURE_ON_PROCESS, true ) ;
        } 
 
        ///
        ///     Critical - Can be used to spoof HTTP headers. 
        ///              - Can do cross-domain communication via HTTP POST data.
        ///              - Can be used to enable navigation to about:blank in PT.
        ///    TreatAsSafe - We only allow site-of-origin navigation programmatically for both top level
        ///                - and sub frame navigations. Spoofing against the SOO is not considered dangerous. 
        ///
        [SecurityCritical, SecurityTreatAsSafe] 
        private void DoNavigate(Uri source, ref object targetFrameName, ref object postData, ref object headers) 
        {
            VerifyAccess(); 

            // When source set to null or navigating to stream/string, we navigate to "about:blank" internally.
            if (source == null)
            { 
                InternalBlankNavigation = true;
                source = new Uri(AboutBlankUriString); 
            } 
            else
            { 
                InternalBlankNavigation = false;
            }

            if (!source.IsAbsoluteUri) 
            {
                throw new ArgumentException(SR.Get(SRID.AbsoluteUriOnly), "source"); 
            } 

            // Resolve Pack://siteoforigin. 
            if (PackUriHelper.IsPackUri(source))
            {
                source = BaseUriHelper.ConvertPackUriToAbsoluteExternallyVisibleUri(source);
            } 

            // Block popup window. We attempted to use the default popup Manager to block pup-up windows, 
            // by passing the BrowserNavConstants.NewWindowsManaged flag to WebBrowser 
            // But it did not work. New browser windows still can be opened with "_blank" in Internet zone.
            // So demand unrestricted WebPermission until we figure out a better solution. 
            if (!string.IsNullOrEmpty((string)targetFrameName))
            {
                (new System.Net.WebPermission(PermissionState.Unrestricted)).Demand();
            } 
            else
            { 
                // site locking. 
                // Note: navigation to "about:blank" is not enabled in partial trust. If we are navigating to
                // "about:blank" internally as a result of setting source to null or navigating to stream/string, 
                // do not demand WebPermission.
                if (!InternalBlankNavigation)
                {
                    // we currently demand for both top level and subframe navigations. 
                    // If we allow sub frames to navigate out of site of origin programmtically, we must block cross domain communication
                    // of all kinds, so demand when additional headers and postData are set for sub frame navigation. 
                    // The headers can be used to spoof referer headers. 
                    SecurityHelper.DemandWebPermission(source);
                } 
            }

            //
            object flags = (object)null; // UnsafeNativeMethods.BrowserNavConstants.NewWindowsManaged; 
            object sourceString = (object)BindUriHelper.UriToString(source);
 
            try 
            {
                AxIWebBrowser2.Navigate2(ref sourceString, ref flags, ref targetFrameName, ref postData, ref headers); 
            }
            catch (COMException ce)
            {
                // Clear internal state if Navigation fails. 
                InternalBlankNavigation = false;
                DocumentStream = null; 
 
                // "the operation was canceled by the user" - navigation failed
                // ignore this error, IE has already alerted the user. 
                if ((uint)unchecked(ce.ErrorCode) != (uint)unchecked(0x800704c7))
                {
                    throw;
                } 
            }
        } 
 
        /// 
        /// This method helps work around IE 6 WebOC bugs related to activation state change. The problem seems 
        /// to be fixed in IE 7.
        ///   * When the security 'goldbar' pops up, it acquires focus. When the user unblocks the control,
        ///     focus is set to the main WebOC window, but it doesn't call us on IOleInPlaceSite.OnUIActivate()
        ///     like it normally does when it gets focus. This leaves the ActiveXState at InPlaceActive, but 
        ///     it should be UIActive. Because of this, the invariant assert in TranslateAccelerator() was
        ///     failing on a key down - WOSB 1961596. 
        ///   * Similar case from DevDiv bug 121501: Clicking on a combobox to get its drop down list. If the 
        ///     WebOC doesn't have focus before that, it acquires it, but doesn't call OnUIActivate(). This
        ///     fails the Assert in OnPreprocessMessageThunk(). 
        /// 
        private void SyncUIActiveState()
        {
            if (ActiveXState != ActiveXHelper.ActiveXState.UIActive && ((IKeyboardInputSink)this).HasFocusWithin()) 
            {
                Invariant.Assert(ActiveXState == ActiveXHelper.ActiveXState.InPlaceActive); 
                ActiveXState = ActiveXHelper.ActiveXState.UIActive; 
            }
        } 

        /// 
        ///     Gives the component a chance to process keyboard input.
        ///     Return value is true if handled, false if not.  Components 
        ///     will generally call a child component's TranslateAccelerator
        ///     if they can't handle the input themselves.  The message must 
        ///     either be WM_KEYDOWN or WM_SYSKEYDOWN.  It is illegal to 
        ///     modify the MSG structure, it's passed by reference only as
        ///     a performance optimization. 
        /// 
        ///
        ///     Critical - access critical data ActiveXInPlaceActiveObject and can be used to spoof input
        ///     TreatAsSafe: The interface declaration for this method has a demand on it. 
        ///
        [SecurityCritical, SecurityTreatAsSafe] 
        bool IKeyboardInputSink.TranslateAccelerator(ref MSG msg, ModifierKeys modifiers) 
        {
            SyncUIActiveState(); 
            Invariant.Assert(ActiveXState >= ActiveXHelper.ActiveXState.UIActive, "Should be at least UIActive when we are processing accelerator keys");

            return (ActiveXInPlaceActiveObject.TranslateAccelerator(ref msg) == 0);
        } 

        ///  
        ///     Set focus to the first or last tab stop. If it can't, because it has no tab stops, 
        ///     the return value is false.
        ///  
        ///
        ///     Critical: calls the critical DoVerb(), which sets focus on the control.
        ///     PublicOK: Setting focus on the WebOC is okay. Script is allowed to do that.
        /// 
        [SecurityCritical]
        bool IKeyboardInputSink.TabInto(TraversalRequest request) 
        { 
            Invariant.Assert(ActiveXState >= ActiveXHelper.ActiveXState.InPlaceActive, "Should be at least InPlaceActive when tabbed into");
 
            bool activated = DoVerb(NativeMethods.OLEIVERB_UIACTIVATE);

            if (activated)
            { 
                this.ActiveXState = ActiveXHelper.ActiveXState.UIActive;
            } 
 
            return activated;
        } 

        ///
        ///     Critical - critical because it can be used to spoof input
        /// 
        /// 
        /// This method is called only when the WebOC is hosted in an XBAP and actually hosted in our 
        /// process (not IsWebOCHostedInBrowserProcess). See overview of keyboard input handling at the top 
        /// of the file.
        ///  
        [SecurityCritical]
        private void OnPreprocessMessageThunk(ref MSG msg, ref bool handled)
        {
            // only handle it when the focus is within. 
            if ((handled) || !((IKeyboardInputSink)this).HasFocusWithin())
            { 
                return; 
            }
 
            SyncUIActiveState();
            Invariant.Assert(ActiveXState >= ActiveXHelper.ActiveXState.UIActive, "Should be at least UIActive when we are focused");

            switch (msg.message) 
            {
                case NativeMethods.WM_SYSKEYUP: 
                case NativeMethods.WM_SYSKEYDOWN: 
                case NativeMethods.WM_KEYUP:
                case NativeMethods.WM_KEYDOWN: 
                    handled = ((IKeyboardInputSink)this).TranslateAccelerator(ref msg, ModifierKeys.None);
                    break;
            }
        } 

        #endregion Private Methods 
 
        //----------------------------------------------
        // 
        // Private Properties
        //
        //----------------------------------------------
 
        #region Private Properties
 
        ///  
        /// Critical - Retrieves RBW and sets it on _rbw.
        /// TreatAsSafe - The RBW is exposed via Application.MainWindow anyhow. 
        /// 
        private static RootBrowserWindow RootBrowserWindow
        {
            [SecurityCritical, SecurityTreatAsSafe] 
            get
            { 
                if (_rbw.Value == null) 
                {
                    if (Application.Current != null) 
                    {
                        _rbw.Value = Application.Current.MainWindow as RootBrowserWindow;
                    }
                } 

                return _rbw.Value; 
            } 
        }
 
        /// 
        /// returns whether this is a restricted WebBrowser
        /// 
        ///  
        /// Critical - it accesses critical data (_isWebOCPermissionChecked, _isWebOCPermissionRestricted)
        /// TreatAsSafe - it's safe to return whether it has restricted permission. 
        ///  
        private static bool IsWebOCPermissionRestricted
        { 
            [SecurityCritical, SecurityTreatAsSafe]
            get
            {
                if (!_isWebOCPermissionChecked) 
                {
                    _isWebOCPermissionRestricted = ! SecurityHelper.CallerHasUnrestrictedWebBrowserPermission(); 
                    _isWebOCPermissionChecked = true; 
                }
                return _isWebOCPermissionRestricted; 
            }
        }

        #endregion Private Properties 

        //---------------------------------------------- 
        // 
        // Private Fields
        // 
        //----------------------------------------------

        #region Private Fields
 
        private static readonly Guid WEBOC_GUID = new Guid("8856f961-340a-11d0-a96b-00c04fd705a2");
 
        // Reference to the native ActiveX control's IWebBrowser2 
        // Do not reference this directly. Use the AxIWebBrowser2 property instead since that
        // will cause the object to be instantiated if it is not already created. 
        /// 
        /// Critical - This code can be exploited to call Navigate on a page and it holds a COM interface
        /// 
        [SecurityCritical] 
        private UnsafeNativeMethods.IWebBrowser2                 _axIWebBrowser2;
 
        WebOCHostingAdaptor                                     _hostingAdaptor; 

        // To hook up events from the native WebBrowser 
        private ConnectionPointCookie                           _cookie;

        /// 
        ///     Critical for set - We want to protect the RBW from being set from non-trusted sources. 
        ///                        There's no need to make it SecurityCritical because it's exposed anyhow via Application.MainWindow.
        ///  
        private static SecurityCriticalDataForSet _rbw; 

        ///  
        /// determines whether _isWebOCPermissionRestricted was initialized or not yet.
        /// 
        /// 
        /// Critical - it indicates whether _isWebOCPermissionRestricted has been intialized or not. 
        /// 
        [SecurityCritical] 
        private static bool                                      _isWebOCPermissionChecked; 

        ///  
        /// Critical - it determines whether this is a restricted WebBrowser.
        /// 
        [SecurityCritical]
        private static bool                                      _isWebOCPermissionRestricted; 

        private WeakEventPreprocessMessage                         _weakEventPreprocessMessage; 
 
        private object                                           _objectForScripting;
        private Stream                                           _documentStream; 

        /// 
        ///    Critical: _internalBlankNavigation is involved in making security decisions.
        ///              We navigate to about:blank internally when navigating to null or navigation to string/stream. 
        ///              This flag is used to avoid security check per navigation source in order to enable navigation
        ///              to about:blank in partial trust. 
        ///              Setting this property to true will by pass the site locking logic. Currently it is only true when 
        ///              navigating to about:blank internally for the scenarios described above.
        ///  
        private SecurityCriticalDataForSet                    _internalBlankNavigation;

        #endregion Private Fields
 
        //----------------------------------------------
        // 
        // Private Classes 
        //
        //---------------------------------------------- 

        #region Private Class

        ///  
        /// Logical extension to class WebBrowser. Exposes a minimal polymorphic interface that lets us host
        /// the WebOC either in-process or in the browser process (when IsWebOCHostedInBrowserProcess==true). 
        /// This base class handles the in-process hosting. 
        /// 
        internal class WebOCHostingAdaptor 
        {
            internal WebOCHostingAdaptor(WebBrowser webBrowser)
            {
                _webBrowser = webBrowser; 
            }
 
            internal virtual object ObjectForScripting 
            {
                get { return _webBrowser.ObjectForScripting; } 
                set { }
            }

            ///  
            /// Critical: As a native object, the WebOC should not be exposed to partial-trust code.
            ///  
            [SecurityCritical] 
            internal virtual object CreateWebOC()
            { 
                Guid clsid = WEBOC_GUID;
                return UnsafeNativeMethods.CoCreateInstance(ref clsid, null, NativeMethods.CLSCTX_INPROC_SERVER, ref NativeMethods.IID_IUnknown);
            }
 
            /// 
            /// Critical: WebBrowserEvent instances should not be exposed to partial-trust code. 
            ///  
            [SecurityCritical]
            internal virtual object CreateEventSink() 
            {
                return new WebBrowserEvent(_webBrowser);
            }
 
            protected WebBrowser _webBrowser;
        }; 
 
        /// 
        /// Used when WebBrowser.IsWebOCHostedInBrowserProcess. 
        /// 
        private class WebOCHostedInBrowserAdaptor : WebOCHostingAdaptor
        {
            internal WebOCHostedInBrowserAdaptor(WebBrowser webBrowser) : base(webBrowser) { } 

            ///  
            /// Critical: Calls the native CoRegisterPSClsid(). 
            /// TAS: Enabling a specific interface to be marshaled. The proxy-stub code is in our PHProxy DLL.
            ///  
            [SecurityCritical, SecurityTreatAsSafe]
            static WebOCHostedInBrowserAdaptor()
            {
                // IDocHostUIHandler is not marshalable ... probably because no one has needed to use it 
                // cross-thread. PresentationHostProxy.dll is compiled with a clone of it and contains
                // proxy-stub code for it. Registering the proxy-stub this way rather than in the registry 
                // is cleaner because it applies only to our scenarios. 
                // The same thing is done in the browser process, by our in-proc handler.
                Guid iidDHUIH = typeof(UnsafeNativeMethods.IDocHostUIHandler).GUID; 
                Guid clsidPresHostProxy = new Guid("e302cb55-5f9d-41a3-9ef3-61827fb8b46d");
                int hr = UnsafeNativeMethods.CoRegisterPSClsid(ref iidDHUIH, ref clsidPresHostProxy);
                if (hr != NativeMethods.S_OK)
                { 
                    Marshal.ThrowExceptionForHR(hr);
                } 
            } 

            ///  
            /// Critical: Calls the SUC'd CreateIDispatchSTAForwarder().
            /// TAS: Wrapping a managed object in a native one that trivially delegates IDispatch calls is safe.
            /// 
            [SecurityCritical, SecurityTreatAsSafe] 
            internal override object ObjectForScripting
            { 
                get 
                {
                    return _threadBoundObjectForScripting; 
                }
                [SecurityCritical, SecurityTreatAsSafe]
                set
                { 
                    _threadBoundObjectForScripting =
                        value == null ? null : ActiveXHelper.CreateIDispatchSTAForwarder(value); 
                } 
            }
 
            /// 
            /// Critical: As a native object, the WebOC should not be exposed to partial-trust code.
            /// 
            [SecurityCritical] 
            internal override object CreateWebOC()
            { 
                IntPtr pWebOC = Application.Current.BrowserCallbackServices.CreateWebBrowserControlInBrowserProcess(); 
                object webOC = Marshal.GetTypedObjectForIUnknown(pWebOC, typeof(UnsafeNativeMethods.IWebBrowser2));
                Marshal.Release(pWebOC); 
                return webOC;
            }

            ///  
            /// Critical: WebBrowserEvent instances should not be exposed to partial-trust code.
            ///  
            [SecurityCritical] 
            internal override object CreateEventSink()
            { 
                return ActiveXHelper.CreateIDispatchSTAForwarder(
                    (UnsafeNativeMethods.DWebBrowserEvents2)base.CreateEventSink());
            }
 
            // This is a native object that wraps the ObjectForScripting provided by the application
            // in order to ensure calls arrive on WebBrowser's thread. 
            object _threadBoundObjectForScripting; 
        };
 
        private class WeakEventPreprocessMessage : WeakReference
        {
            /// 
            ///     Critical: This code calls attaches an arbitrary window 
            ///     to the call path for the component dispatcher call back.
            ///     Assert in the code. 
            ///  
            [SecurityCritical]
            public WeakEventPreprocessMessage(WebBrowser webBrowser): base(webBrowser) 
            {
                (new UIPermission(PermissionState.Unrestricted)).Assert(); // Blessed assert
                try
                { 
                    // We are attaching to this second-chance event handler because the first-chance
                    // handler is already being used to let the host preprocess messages and send certain 
                    // messages directly to the browser frame. 
                    ComponentDispatcher.ThreadPreprocessMessage +=
                                    new ThreadMessageEventHandler(this.OnPreprocessMessage); 
                }
                finally
                {
                    UIPermission.RevertAssert(); 
                }
            } 
 
            /// 
            ///     Critical: This code calls critcal method OnPreprocessMessageThunk 
            /// 
            [SecurityCritical]
            public void OnPreprocessMessage(ref MSG msg, ref bool handled)
            { 
                WebBrowser webBrowser = this.Target as WebBrowser;
                if(null != webBrowser) 
                { 
                    webBrowser.OnPreprocessMessageThunk(ref msg, ref handled);
                } 
                else
                {
                    Dispose();
                } 
            }
 
            ///  
            ///     Critical:This code calls into ComponentDispatcher
            ///     to disconnect a listener. Assert in the code. 
            ///     TreatAsSafe: This code is ok to call
            /// 
            [SecurityCritical, SecurityTreatAsSafe]
            public void Dispose() 
            {
                (new UIPermission(PermissionState.Unrestricted)).Assert(); // Blessed assert 
                try 
                {
                    ComponentDispatcher.ThreadPreprocessMessage -= 
                                    new ThreadMessageEventHandler(this.OnPreprocessMessage);
                }
                finally
                { 
                    UIPermission.RevertAssert();
                } 
            } 

        } 

        #endregion Private Class
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//------------------------------------------------------------------------------ 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// 
//
// Description: 
//      WebBrowser is a wrapper for the webbrowser activex control 
//      Copied from webbrowser.cs in winforms
// 
// History
//  04/17/05    KusumaV      Created
//  02/22/08    huwang       Expose the WebBrowser control
//  04/24/08    ChangoV     Implemented hosting the WebOC in the browser process for IE 7+ Protected Mode 
//-----------------------------------------------------------------------------
 
using System; 
using System.ComponentModel;
using System.Runtime.InteropServices; 
using System.Windows;
using MS.Win32;
using System.Security;
using System.Security.Permissions; 
using System.Windows.Controls.Primitives; //PopupRoot
using MS.Internal.PresentationFramework; 
using MS.Internal.Utility ; 
using MS.Internal.AppModel; //RootBrowserWindow
using System.Windows.Interop; 
using System.Windows.Input;
using System.Windows.Threading;
using System.Diagnostics;
using System.Windows.Navigation; 
using System.IO; //Stream
using System.Threading; // thread 
using MS.Internal; 
using MS.Internal.Controls;
using System.IO.Packaging; 

/* Overview of Keyboard Input Routing for the WebOC

The WebOC receives regular alphanumeric keyboard input via its WndProc. Whoever is running the message loop 
calls DispatchMessage() after any preprocessing and special routing, and the message gets to the WndProc of
the window with focus. 
 
"Accelerator" keys need to be passed to the WebOC via IOleInPlaceActiveObject::TranslateAccelerator().
For example, these include the navigation keys and clipboard keys. Depending on how the WebOC is hosted, 
input messages flow somewhat differently:
 1) Standalone application:
     HwndSource.OnPreprocessMessage() -> InputManager ->(routed event) HwndHost.OnKeyDown() ->
     WebBrowser.IKeyboardInputSink.TranslateAccelerator(). 
 2) In PresentationHost (on our UI thread):
     ComponentDispatcher.ThreadPreprocessMessage() -> WebBrowser.OnPreprocessMessageThunk() -> 
     WebBrowser.IKeyboardInputSink.TranslateAccelerator(). 
    Because a child window HwndSource, which is what we have for the RootBrowserWindow, does not route
    messages directly from the message loop like in case (1), we need an alternate similar solution. That's 
    the WeakEventPreprocesMessage listener. Another supposed benefit of such direct message routing, as opposed
    to letting input events go through our element tree, is to prevent tampering with input destined for the
    WebOC, which may have a frame navigated to a third-party site...
 3) In the browser process (IE 7+, when in protected mode): The WebOC is run on a dedicated thread. There is a 
    message loop running for it. Before calling TranslateMessage & DispatchMessage, it calls WebOC's
    IOleInPlaceActiveObject::TranslateAccelerator(). 
 
Other accelerator handling APIs:
 - IDocHostUIHandler::TranslateAccelerator(): This appears to be called by the WebOC for everything passed to it 
     via IOleInPlaceActiveObject::TranslateAccelerator(), so it's not interesting to us.
 - IOleControlSite::TranslateAccelerator(): The WebOC is passing MSGs it gets via IOleInPlaceActiveObject::
   TranslateAccelerator() and its WndProc but doesn't handle. Our WebBrowserSite takes advantage of this to
   handle tabbing out of the WebOC. 
*/
 
namespace System.Windows.Controls 
{
    /// 
    /// This is a wrapper over the native WebBrowser control implemented in shdocvw.dll.
    ///
    /// 
    /// The WebBrowser class is currently not thread safe. Multi-threading could corrupt the class internal state, 
    /// which could lead to security exploits (see example in devdiv bug #196538). So we enforce thread affinity.
    ///  
    public sealed class WebBrowser : ActiveXHost, IKeyboardInputSink 
    {
        //---------------------------------------------- 
        //
        // Constructors
        //
        //---------------------------------------------- 

        #region Constructor 
 
        static WebBrowser()
        { 
            if (IsWebOCPermissionRestricted)
            {
                RegisterWithRBW();
            } 
            TurnOnXPSP2Mitigations();
        } 
 
        ///
        ///     Critical - accesses critical Ctor and create WeakEventPreprocessMessage. 
        ///     PublicOK - creating web browser considered safe.
        ///
        ///                   Known threats and the justification as to why they are mitigated :
        /// 
        ///                     Uri is validated at set time. An attempts to navigate outside site of origin will fail the demand for web-permission.
        ///                     Attempts to navigate the HTML to another page are mitigated by "Site Lock" feature. 
        ///                     Attempts to show popup's above HTML are mitigated by popup work. 
        ///                     Running script inside WebOC - considered ok as script is Internet Zone.
        ///                     Running activeX controls - considered safe. Equivalent functionality is enabled through web-pages. 
        ///                     Cookies: The WebOC thinks it's a top-level browser. Thus cookies it sets will always
        ///                         have 1st party status, which wouldn't be right if the WebOC is in an XBAP that is
        ///                         third party to the containing HTML page. But now PresentationHost intercepts all
        ///                         calls to the WinInet cookie APIs and will add the 3rd party flag when necessary. 
        ///                         V3 SP2 Update - WebOCHostedInBrowserProcess - The cookie shim does not apply
        ///                             in this case. To prevent the cookie status elevation problem, the native code 
        ///                             in PresentationHostDll fails creating the WebOC. 
        ///
        /// 
        [ SecurityCritical ]
        public WebBrowser()
            : base( WEBOC_GUID , true )
        { 
            // Check whether feature is disabled
            if (SafeSecurityHelper.IsFeatureDisabled(SafeSecurityHelper.KeyToRead.WebBrowserDisable)) 
            { 
                // in case the registry key is '1' then demand unrestricted WebBrowserPermission to create it
                SecurityHelper.DemandWebBrowserPermission(); 
            }
            else
            {
                // Feature is enabled - demand Safe level to create this object, granted in Partial Trust by default 
                (new WebBrowserPermission(WebBrowserPermissionLevel.Safe)).Demand();
            } 
 
            // If the webbrowser permission is restricted, we don't allow webbrowser to be inside Popup.
            if (IsWebOCPermissionRestricted) 
            {
                Loaded += new RoutedEventHandler(LoadedHandler);
            }
 
            // Attach our hook to ComponentDispatcher.ThreadPreprocessMessage. It is the second event called
            // when the messsages are coming in. 
            if (Application.InBrowserHostedApp()) 
            {
                _weakEventPreprocessMessage = new WeakEventPreprocessMessage(this); 
            }

            _hostingAdaptor = IsWebOCHostedInBrowserProcess ?
                new WebOCHostedInBrowserAdaptor(this) : new WebOCHostingAdaptor(this); 
        }
 
        #endregion Constructor 

        //---------------------------------------------- 
        //
        // Public Methods
        //
        //---------------------------------------------- 

        #region Public Methods 
 
        /// 
        /// Navigate to the WebBrowser control to the given uri. 
        /// 
        /// Uri being navigated to.
        public void Navigate(Uri source)
        { 
            Navigate(source, null, null, null);
        } 
 
        /// 
        /// Navigate to the WebBrowser control to the given uri. 
        /// 
        /// Uri being navigated to.
        /// The name of the frame in which to load the document.
        /// HTTP POST data such as form data. 
        /// HTTP headers to add to the default headers.
        public void Navigate(Uri source, string targetFrameName, byte[] postData, string additionalHeaders) 
        { 
            object objTargetFrameName = (object)targetFrameName;
            object objPostData = (object)postData; 
            object objHeaders = (object)additionalHeaders;

            DoNavigate(source, ref objTargetFrameName, ref objPostData, ref objHeaders);
        } 

        ///  
        /// Navigates the the stream of a html page. 
        /// 
        /// The stream that contains the content of a html document 
        public void NavigateToStream(Stream stream)
        {
            if (stream == null)
            { 
                throw new ArgumentNullException("stream");
            } 
 
            DocumentStream = stream;
            // We navigate to "about:blank" when Source is set to null. 
            // When we get NavigateComplete event, we load the stream via the IPersistStreamInit interface.
            Source = null;
        }
 
        /// 
        /// Navigates to the text of a html page. 
        ///  
        /// The string that contains the content of a html document
        public void NavigateToString(String text) 
        {
            if (string.IsNullOrEmpty(text))
            {
                throw new ArgumentNullException("text"); 
            }
 
            MemoryStream ms = new MemoryStream(text.Length); 
            StreamWriter sw = new StreamWriter(ms);
            sw.Write(text); 
            sw.Flush();
            ms.Position = 0;

            NavigateToStream(ms); 
        }
 
        ///  
        /// Navigates the WebBrowser control to the previous page if available.
        ///  
        ///
        ///     Critical - accesses the critical unmanaged interface of the control.
        ///     Public OK - This code does not expose the interface.
        ///               - Going back to the previous page within the WebBrowser control is considered safe. 
        ///
        [SecurityCritical] 
        public void GoBack() 
        {
            VerifyAccess(); 

            AxIWebBrowser2.GoBack();
        }
 
        /// 
        /// Navigates the WebBrowser control to the next page if available. 
        ///  
        ///
        ///     Critical - accesses the critical unmanaged interface of the control. 
        ///     Public OK - This does not expose the interface.
        ///               - Going forward to the next page within the WebBrowser is considered safe.
        ///
        [SecurityCritical] 
        public void GoForward()
        { 
            VerifyAccess(); 

            AxIWebBrowser2.GoForward(); 
        }


        ///  
        /// Refreshes the current page.
        ///  
        /// 
        ///     Critical - accesses the critical unmanaged interface of the control.
        ///     Public OK - This does not expose the interface. 
        ///               - Refreshing the WebBrowser is considered safe.
        ///
        [SecurityCritical]
        public void Refresh() 
        {
            VerifyAccess(); 
 
            AxIWebBrowser2.Refresh();
        } 

        /// 
        /// Refreshes the current page.
        ///  
        ///
        ///     Critical - accesses the critical unmanaged interface of the control. 
        ///     Public OK - This does not expose the interface. 
        ///               - Refreshing the WebBrowser is considered safe.
        /// 
        /// Whether to refresh without cache validation by sending "Pragma:no-cache" header to the server.
        [SecurityCritical]
        public void Refresh(bool noCache)
        { 
            VerifyAccess();
 
            // Out of the three options of RefreshConstants, we only expose two: REFRESH_NORMAL and REFRESH_COMPLETELY, 
            // because the thrid option, RefreshConstants.REFRESH_IFEXPIRED, is not implemented by IWebBrowser2.Refresh.
            // And those two options cover the common scenarios. 
            //
            // enum RefreshConstants{
            //      REFRESH_NORMAL = 0,
            //      REFRESH_IFEXPIRED = 1 /* Not supported by IWebBrowser2*/, 
            //      REFRESH_COMPLETELY = 3
            // } 
            int refreshOption = noCache ? 3 : 0; 
            object refreshOptionObject = (object) refreshOption;
            AxIWebBrowser2.Refresh2(ref refreshOptionObject); 
        }

        /// 
        /// Executes an Active Scripting function defined in the HTML document currently loaded in the WebBrowser control. 
        /// 
        /// The name of the script method to invoke. 
        /// The object returned by the Active Scripting call. 
        public object InvokeScript(string scriptName)
        { 
            return InvokeScript(scriptName, null);
        }

        ///  
        /// Executes an Active Scripting function defined in the HTML document currently loaded in the WebBrowser control.
        ///  
        /// The name of the script method to invoke. 
        /// 
        /// The object returned by the Active Scripting call. 
        /// 
        /// Critical: Calls critical property and method.
        /// Public OK - Demand WebPermission to protect againt cross domain scripting attacks.
        ///           - We count on WebOC to "sandbox" the script to the zone of the page. 
        /// 
        [SecurityCritical] 
        public object InvokeScript(string scriptName, params object[] args) 
        {
            VerifyAccess(); 

            if (string.IsNullOrEmpty(scriptName))
            {
                throw new ArgumentNullException("scriptName"); 
            }
 
            // Protect against the cross domain scripting attacks. 
            // We rely on the site locking feature in gerneral. But in IE 6 server side redirect is not blocked.
            // (In IE 7 it is blocked by turning on the DOCHOSTUIFLAG.ENABLE_REDIRECT_NOTIFICATION flag so that 
            // the additional BeforeNavigate2 event is fired for server side redirect.)

            // If it is our internal navigation to blank for navigating to null or load stream,
            // or before any navigation has happened, Source will be null. 
            Uri currentSource = Source;
            if (currentSource != null) 
            { 
                SecurityHelper.DemandWebPermission(currentSource);
            } 

            UnsafeNativeMethods.IDispatch scriptObject = null;
            // Throw if the current document object is not avaiable.
            UnsafeNativeMethods.IHTMLDocument htmlDocument = NativeHTMLDocument; 
            if (htmlDocument != null)
            { 
                scriptObject = htmlDocument.GetScript() as UnsafeNativeMethods.IDispatch; 
            }
 
            object retVal = null;
            if (scriptObject != null)
            {
                NativeMethods.tagDISPPARAMS dp = new NativeMethods.tagDISPPARAMS(); 
                dp.rgvarg = IntPtr.Zero;
                try 
                { 
                    // If we use reflection to call script code, we need to Assert for the UnmanagedCode permission.
                    // But it will be a security issue when the WPF app makes a framework object available to the 
                    // hosted script via ObjectForScripting or as paramter of InvokeScript, and calls the framework
                    // API that demands the UnmanagedCode permission. We do not want the demand to succeed. However,
                    // The stack walk will igore the native frames and keeps going until it reaches the Assert.
                    // That is why we switch to invoking the script via IDispatch with SUCS on the methods. 
                    Guid guid = Guid.Empty;
                    string[] names = new string[] { scriptName }; 
                    int[] dispids = new int[] { NativeMethods.DISPID_UNKNOWN }; 
                    scriptObject.GetIDsOfNames(ref guid, names, 1,
                                            Thread.CurrentThread.CurrentCulture.LCID, dispids); 
                    if (args != null)
                    {
                        // Reverse the arg order so that parms read naturally after IDispatch. (WinForms bug 187662)
                        Array.Reverse(args); 
                    }
                    dp.rgvarg = (args == null) ? IntPtr.Zero : UnsafeNativeMethods.ArrayToVARIANTHelper.ArrayToVARIANTVector(args); 
                    dp.cArgs = (uint)((args == null) ? 0 : args.Length); 
                    dp.rgdispidNamedArgs = IntPtr.Zero;
                    dp.cNamedArgs = 0; 

                    object[] retVals = new object[1];

                    scriptObject.Invoke(dispids[0], ref guid, Thread.CurrentThread.CurrentCulture.LCID, 
                            NativeMethods.DISPATCH_METHOD, dp,
                            retVals, new NativeMethods.tagEXCEPINFO(), null); 
 
                    retVal = retVals[0];
                } 
                finally
                {
                    if (dp.rgvarg != IntPtr.Zero)
                    { 
                        UnsafeNativeMethods.ArrayToVARIANTHelper.FreeVARIANTVector(dp.rgvarg, args.Length);
                    } 
                } 
            }
            else 
            {
                throw new InvalidOperationException(SR.Get(SRID.CannotInvokeScript));
            }
            return retVal; 
        }
 
        #endregion Public Methods 

        //---------------------------------------------- 
        //
        // Public Properties
        //
        //---------------------------------------------- 

        #region Public Properties 
 
        /// 
        /// Gets or sets the current uri of the WebBrowser control. 
        /// 
        /// 
        ///     Critical - Accesses the critical unmanaged interface of the control.
        ///     Public OK - This does not expose the interface. 
        ///               - Return the current uri is considered as safe because we only allow navigation to
        ///                 site-of-origin for top level navigation in parital trust. 
        ///  
        public Uri Source
        { 
            set
            {
                VerifyAccess();
 
                Navigate(value);
            } 
            [SecurityCritical] 
            get
            { 
                VerifyAccess();

                // Current url, return IWebBrowser2.LocationURL.
                string urlString = AxIWebBrowser2.LocationURL; 

                // When source set to null or navigating to stream/string, we navigate to "about:blank" 
                // internally. Make sure we return null in those cases. 
                if (InternalBlankNavigation)
                { 
                    Invariant.Assert(string.Compare(urlString, AboutBlankUriString, StringComparison.OrdinalIgnoreCase) == 0);
                    urlString = null;
                }
 
                return (string.IsNullOrEmpty(urlString) ? null : new Uri(urlString));
            } 
        } 

        ///  
        /// Gets a value indicating whether a previous page in navigation history is available.
        /// 
        public bool CanGoBack
        { 
            get
            { 
                VerifyAccess(); 

                return (!IsDisposed && _canGoBack); 
            }
        }

        ///  
        /// Gets a value indicating whether a subsequent page in navigation history is available.
        ///  
        public bool CanGoForward 
        {
            get 
            {
                VerifyAccess();

                return (!IsDisposed && _canGoForward); 
            }
        } 
 
        /// 
        /// Gets or sets an object that can be accessed by scripting code that is contained 
        /// within a Web page in the WebBrowser control.
        /// 
        /// 
        ///     Critical: Calls Marshal.IsTypeVisibleFromCom(), which has a LinkDemand for UnmanagedCode. 
        ///     PublicOK: We do not expose any security critical info.
        ///  
        public object ObjectForScripting 
        {
            get 
            {
                VerifyAccess();

                return _objectForScripting; 
            }
            [SecurityCritical] 
            set 
            {
                VerifyAccess(); 

                if (value != null)
                {
                    Type t = value.GetType(); 
                    if (!System.Runtime.InteropServices.Marshal.IsTypeVisibleFromCom(t))
                    { 
                        throw new ArgumentException(SR.Get(SRID.NeedToBeComVisible)); 
                    }
                } 

                _objectForScripting = value;
                _hostingAdaptor.ObjectForScripting = value;
            } 
        }
 
        ///  
        /// The HtmlDocument for page hosted in the html page.  If no page is loaded, it returns null.
        ///  
        ///
        ///     Critical - exposes the critical unmanaged interface of the DOM object.
        ///     Public OK - Demands unrestricted WebPermission.
        /// 
        public object Document
        { 
            [SecurityCritical] 
            get
            { 
                VerifyAccess();

                SecurityHelper.DemandUnmanagedCode();
 
                return AxIWebBrowser2.Document;
            } 
        } 

        #endregion Public Properties 

        //----------------------------------------------
        //
        // Public Events 
        //
        //---------------------------------------------- 
 
        #region Public Events
 
        /// 
        /// Raised before a navigation takes place. This event is fired only for
        /// top-level page navigations.
        /// Canceling this event prevents the WebBrowser control from navigating. 
        /// 
        public event NavigatingCancelEventHandler Navigating; 
 
        /// 
        /// Raised after navigation the target has been found and the download has begun. This event 
        /// is fired only for top-level page navigations.
        /// 
        public event NavigatedEventHandler Navigated;
 
        /// 
        /// Raised when the WebBrowser control finishes loading a document. This event 
        /// is fired only for top-level page navigations. 
        /// 
        public event LoadCompletedEventHandler LoadCompleted; 

        #endregion Public Events

        //---------------------------------------------- 
        //
        // Protected Methods 
        // 
        //----------------------------------------------
 
        #region Protected Methods

        protected override void Dispose(bool disposing)
        { 
            base.Dispose(disposing);
 
            if (disposing) 
            {
                if (_weakEventPreprocessMessage != null) 
                {
                    _weakEventPreprocessMessage.Dispose();
                    _weakEventPreprocessMessage = null;
                } 
            }
        } 
 
        #endregion Protected Methods
 
        //----------------------------------------------
        //
        // Internal Methods
        // 
        //----------------------------------------------
 
        #region Internal Methods 

        internal void OnNavigating(NavigatingCancelEventArgs e) 
        {
            VerifyAccess();

            if (Navigating != null) 
            {
                Navigating(this, e); 
            } 
        }
 
        internal void OnNavigated(NavigationEventArgs e)
        {
            VerifyAccess();
 
            if (Navigated != null)
            { 
                Navigated(this, e); 
            }
        } 

        internal void OnLoadCompleted(NavigationEventArgs e)
        {
            VerifyAccess(); 

            if (LoadCompleted != null) 
            { 
                LoadCompleted(this, e);
            } 
        }


        ///  
        /// Critical: As a native object, the WebOC should not be exposed directly to partial-trust code.
        ///  
        [SecurityCritical] 
        internal override object CreateActiveXObject(Guid clsid)
        { 
            Debug.Assert(clsid == WEBOC_GUID);
            return _hostingAdaptor.CreateWebOC();
        }
 
        /// This will be called when the native ActiveX control has just been created.
        /// Inheritors of this class can override this method to cast the nativeActiveXObject 
        /// parameter to the appropriate interface. They can then cache this interface 
        /// value in a member variable. However, they must release this value when
        /// DetachInterfaces is called (by setting the cached interface variable to null). 
        /// 
        ///     Critical: This code can be exploited to pass in a bogus Activex object
        /// 
        [SecurityCritical] 
        internal override void AttachInterfaces(object nativeActiveXObject)
        { 
            //cache the interface 
            this._axIWebBrowser2 = (UnsafeNativeMethods.IWebBrowser2)nativeActiveXObject;
 
            //
            //Initializations
            //
            //By default _axIWebBrowser2.RegisterAsDropTarget and _axIWebBrowser2.RegisterAsBrowser 
            //are set to false. Since we control navigations through webbrowser events, we can set these
            //to true if needed to allow drag n drop of documents on to the control and 
            //allow frame targetting respectively. Think its better to lock it down until this is spec-ed out 

            //Set Silent property to true to suppress error dialogs (or demand permission for it here and 
            //set it accordingly)
        }

        /// See AttachInterfaces for a description of when to override DetachInterfaces. 
        /// 
        ///     Critical: This code references the critical object _axIWebBrowser2 
        ///     TreatAsSafe: It does not expose it 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        internal override void DetachInterfaces()
        {
            //clear the interface. Base will release the COMObject
            _axIWebBrowser2 = null; 
        }
 
        ///  
        ///     Attaches to the DWebBrowserEvents2 connection point.
        ///  
        ///
        ///     Critical - uses the critical _axIWebBrowser2 and calls _hostingAdaptor.CreateEventSink().
        ///     TreatAsSafe - registering to handle events is ok. The event sink object is not exposed.
        /// 
        [ SecurityCritical, SecurityTreatAsSafe ]
        internal override void CreateSink() 
        { 
            Debug.Assert(_axIWebBrowser2 != null);
            _cookie = new ConnectionPointCookie(_axIWebBrowser2, 
                    _hostingAdaptor.CreateEventSink(),
                    typeof(UnsafeNativeMethods.DWebBrowserEvents2));
        }
 
        ///
        ///     Releases the DWebBrowserEvents2 connection point. 
        /// 
        /// 
        /// Critical: Disconnecting the event sink breaks the site-locking feature. 
        /// 
        [SecurityCritical]
        internal override void DetachSink()
        { 
            //If we have a cookie get rid of it
            if ( _cookie != null) 
            { 
                _cookie.Disconnect();
                _cookie = null; 
            }
        }

        /// 
        ///     Needs to link-demand as base method link-demanded.
        /// 
        ///     Critical - calls critical WebBrowserSite - ctor. 
        ///
        [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)] 
        [SecurityCritical]
        internal override ActiveXSite CreateActiveXSite()
        {
            return new WebBrowserSite(this); 
        }
 
        ///  
        ///     GetDrawing - Returns the drawing content of this Visual.
        ///  
        /// 
        ///     This returns a bitmap obtained by calling the PrintWindow Win32 API.
        /// 
        ///  
        ///     Critical:This code Asserts an elevated permission.
        ///     TreatAsSafe: only site of origin pages can be loaded in PT, so giving out a bitmap of this window is OK. 
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        internal override System.Windows.Media.DrawingGroup GetDrawing() 
        {
            // SecurityHelper.DemandWebPermission(_source.Value); // _source is null by now...

            (new UIPermission(UIPermissionWindow.AllWindows)).Assert(); // Blessed assert 
            try
            { 
                return base.GetDrawing(); 
            }
            finally 
            {
                UIPermission.RevertAssert();
            }
        } 

        #endregion Internal Methods 
 
        //----------------------------------------------
        // 
        // Internal Properties
        //
        //----------------------------------------------
 
        #region Internal Properties
 
        ///  
        ///     Critical: This code exposes an unmanaged interface with SupressUnmanagedCodeSecurity
        ///               attribute on some methods. 
        /// 
        [SecurityCritical]
        internal UnsafeNativeMethods.IHTMLDocument NativeHTMLDocument
        { 
            [SecurityCritical]
            get 
            { 
                object objDoc = AxIWebBrowser2.Document;
                if (objDoc != null) 
                {
                    UnsafeNativeMethods.IHTMLDocument iHTMLDocument = objDoc as UnsafeNativeMethods.IHTMLDocument;

                    // Demand WebPermission NetworkAccess.Connect if we expose this publicly 
                    return iHTMLDocument;
                } 
                return null; 
            }
        } 

        /// 
        ///     Critical: This code exposes an unmanaged interface with SupressUnmanagedCodeSecurity
        ///               attribute on some methods 
        /// 
        [DebuggerBrowsable(DebuggerBrowsableState.Never)] 
        internal UnsafeNativeMethods.IWebBrowser2 AxIWebBrowser2 
        {
            [SecurityCritical] 
            get
            {
                if (_axIWebBrowser2 == null)
                { 
                    if (!IsDisposed)
                    { 
                        //This should call AttachInterfaces which will set this member variable 
                        //We don't want to force the state to InPlaceActive yet since we don't
                        //have the parent handle yet. 
                        TransitionUpTo(ActiveXHelper.ActiveXState.Running);
                    }
                    else
                    { 
                        throw new System.ObjectDisposedException(GetType().Name);
                    } 
                } 
                // We still don't have _axIWebBrowser2. Throw an exception.
                if (_axIWebBrowser2 == null) 
                {
                    throw new InvalidOperationException(SR.Get(SRID.WebBrowserNoCastToIWebBrowser2));
                }
                return _axIWebBrowser2; 
            }
        } 
 
        internal WebOCHostingAdaptor HostingAdaptor { get { return _hostingAdaptor; } }
 
        internal Stream DocumentStream
        {
            get
            { 
                return _documentStream;
            } 
            set 
            {
                _documentStream = value; 
            }
        }

        // This property indicates whether we are navigating to "about:blank" internally 
        // because Source is set to null or navigating to stream.
        ///  
        ///    Critical: _internalBlankNavigation is involved in making security decisions. 
        ///              We navigate to about:blank internally when navigating to null or navigation to string/stream.
        ///              This flag is used to avoid security check per navigation source in order to enable navigation 
        ///              to about:blank in partial trust.
        ///              Setting this property to true will by pass the site locking logic. Currently it is only true when
        ///              navigating to about:blank internally for the scenarios described above.
        ///  
        internal bool InternalBlankNavigation
        { 
            get 
            {
                return _internalBlankNavigation.Value; 
            }
            [SecurityCritical]
            set
            { 
                _internalBlankNavigation.Value = value;
            } 
        } 

        ///  
        /// Starting from v3 SP2, we host the WebOC in the IE 7+ browser process when it's running at low
        /// integrity level ('protected mode'). This is to prevent elevation of privilege via our process in
        /// case a bug in the WebOC is exploited. PresentationHost is on IE's silent elevation list; thus,
        /// potentially bigger damange could be effected by running malicious code in our process. 
        /// 
        internal static bool IsWebOCHostedInBrowserProcess 
        { 
            get
            { 
                return BrowserInteropHelper.IsBrowserLowIntegrityProcess.Value &&
                       IsWebOCPermissionRestricted;
            }
        } 

        #endregion Internal Properties 
 
        //----------------------------------------------
        // 
        // Internal Fields
        //
        //----------------------------------------------
 
        #region Internal Fields
 
        internal bool _canGoBack; 
        internal bool _canGoForward;
        internal const string AboutBlankUriString = "about:blank"; 

        #endregion Internal Fields

        //---------------------------------------------- 
        //
        // Private Methods 
        // 
        //----------------------------------------------
 
        #region Private Methods

        /// 
        ///     Critical:This code gets critical data, PresentationSource 
        ///     TreatAsSafe: The PresentationSource is not exposed.
        ///  
        [SecurityCritical, SecurityTreatAsSafe] 
        private void LoadedHandler(object sender, RoutedEventArgs args)
        { 
            PresentationSource pSource = PresentationSource.CriticalFromVisual(this);

            // Note that we cannot assert this condition here. The reason is that this element might have
            // been disconnected from the tree through one of its parents even while it waited for the 
            // pending Loaded event to fire. More details for this scenario can be found in the
            // Windows OS Bug#1981485. 
            // Invariant.Assert(pSource != null, "Loaded has fired. PresentationSource shouldn't be null"); 

            if (pSource != null && pSource.RootVisual is PopupRoot) 
            {
                throw new InvalidOperationException(SR.Get(SRID.CannotBeInsidePopup));
            }
        } 

        private static void RegisterWithRBW() 
        { 
            // if we are browser hosted, rbw should have been created here.
            // 
            if (RootBrowserWindow != null)
            {
                RootBrowserWindow.AddLayoutUpdatedHandler();
            } 
        }
 
        // Turn on all the XPSP2 mitigations. 
        // We do it programmatically instead of adding reg-keys.
        // So that these are on on all avalon apps. 
        ///
        ///     Critical - calls critical code.
        ///        TreatAsSafe - turns on all the XPSP2 features that make the browser more lock-downed.
        /// 
        [ SecurityCritical, SecurityTreatAsSafe ]
        private static void TurnOnXPSP2Mitigations() 
        { 
            if (Environment.OSVersion.Version.Major == 5 && Environment.OSVersion.Version.Minor == 2)
            { 
                // XPSP2 mitigations - not available on Server 2003.
                // DevDiv
                return ;
            } 

            // NOTE: If the WebOC is hosted in the browser's process, the flags we set here will have no 
            // effect on it. This is somewhat unfortunate because we may get differences in behavior, but it 
            // shouldn't be much of a security issue because we host the WebOC in the browser's process when
            // it is running at low integrity level (IE 'protected mode'), so the WebOC is in a stronger 
            // sandbox there.

            // DevDiv bug 163248 - additional mitigations needed for IE 7.
 
            UnsafeNativeMethods.CoInternetSetFeatureEnabled( NativeMethods.FEATURE_OBJECT_CACHING, NativeMethods.SET_FEATURE_ON_PROCESS, true ) ;
            UnsafeNativeMethods.CoInternetSetFeatureEnabled( NativeMethods.FEATURE_ZONE_ELEVATION, NativeMethods.SET_FEATURE_ON_PROCESS, true ) ; 
            UnsafeNativeMethods.CoInternetSetFeatureEnabled( NativeMethods.FEATURE_MIME_HANDLING, NativeMethods.SET_FEATURE_ON_PROCESS, true ) ; 
            UnsafeNativeMethods.CoInternetSetFeatureEnabled( NativeMethods.FEATURE_MIME_SNIFFING, NativeMethods.SET_FEATURE_ON_PROCESS, true ) ;
            UnsafeNativeMethods.CoInternetSetFeatureEnabled( NativeMethods.FEATURE_WINDOW_RESTRICTIONS, NativeMethods.SET_FEATURE_ON_PROCESS, true ) ; 
            UnsafeNativeMethods.CoInternetSetFeatureEnabled( NativeMethods.FEATURE_WEBOC_POPUPMANAGEMENT, NativeMethods.SET_FEATURE_ON_PROCESS, true ) ;
            UnsafeNativeMethods.CoInternetSetFeatureEnabled( NativeMethods.FEATURE_BEHAVIORS, NativeMethods.SET_FEATURE_ON_PROCESS, true ) ;
            UnsafeNativeMethods.CoInternetSetFeatureEnabled( NativeMethods.FEATURE_DISABLE_MK_PROTOCOL, NativeMethods.SET_FEATURE_ON_PROCESS, true ) ;
            UnsafeNativeMethods.CoInternetSetFeatureEnabled( NativeMethods.FEATURE_LOCALMACHINE_LOCKDOWN, NativeMethods.SET_FEATURE_ON_PROCESS, true ) ; 
            UnsafeNativeMethods.CoInternetSetFeatureEnabled( NativeMethods.FEATURE_SECURITYBAND, NativeMethods.SET_FEATURE_ON_PROCESS, true ) ;
            UnsafeNativeMethods.CoInternetSetFeatureEnabled( NativeMethods.FEATURE_RESTRICT_ACTIVEXINSTALL, NativeMethods.SET_FEATURE_ON_PROCESS, true ) ; 
            UnsafeNativeMethods.CoInternetSetFeatureEnabled( NativeMethods.FEATURE_VALIDATE_NAVIGATE_URL, NativeMethods.SET_FEATURE_ON_PROCESS, true ) ; 
            UnsafeNativeMethods.CoInternetSetFeatureEnabled( NativeMethods.FEATURE_RESTRICT_FILEDOWNLOAD, NativeMethods.SET_FEATURE_ON_PROCESS, true ) ;
            UnsafeNativeMethods.CoInternetSetFeatureEnabled( NativeMethods.FEATURE_ADDON_MANAGEMENT, NativeMethods.SET_FEATURE_ON_PROCESS, true ) ; 
            UnsafeNativeMethods.CoInternetSetFeatureEnabled( NativeMethods.FEATURE_PROTOCOL_LOCKDOWN, NativeMethods.SET_FEATURE_ON_PROCESS, true ) ;
            UnsafeNativeMethods.CoInternetSetFeatureEnabled( NativeMethods.FEATURE_HTTP_USERNAME_PASSWORD_DISABLE, NativeMethods.SET_FEATURE_ON_PROCESS, true ) ;
            UnsafeNativeMethods.CoInternetSetFeatureEnabled( NativeMethods.FEATURE_SAFE_BINDTOOBJECT , NativeMethods.SET_FEATURE_ON_PROCESS, true ) ;
            UnsafeNativeMethods.CoInternetSetFeatureEnabled( NativeMethods.FEATURE_UNC_SAVEDFILECHECK , NativeMethods.SET_FEATURE_ON_PROCESS, true ) ; 
            UnsafeNativeMethods.CoInternetSetFeatureEnabled( NativeMethods.FEATURE_GET_URL_DOM_FILEPATH_UNENCODED , NativeMethods.SET_FEATURE_ON_PROCESS, true ) ;
        } 
 
        ///
        ///     Critical - Can be used to spoof HTTP headers. 
        ///              - Can do cross-domain communication via HTTP POST data.
        ///              - Can be used to enable navigation to about:blank in PT.
        ///    TreatAsSafe - We only allow site-of-origin navigation programmatically for both top level
        ///                - and sub frame navigations. Spoofing against the SOO is not considered dangerous. 
        ///
        [SecurityCritical, SecurityTreatAsSafe] 
        private void DoNavigate(Uri source, ref object targetFrameName, ref object postData, ref object headers) 
        {
            VerifyAccess(); 

            // When source set to null or navigating to stream/string, we navigate to "about:blank" internally.
            if (source == null)
            { 
                InternalBlankNavigation = true;
                source = new Uri(AboutBlankUriString); 
            } 
            else
            { 
                InternalBlankNavigation = false;
            }

            if (!source.IsAbsoluteUri) 
            {
                throw new ArgumentException(SR.Get(SRID.AbsoluteUriOnly), "source"); 
            } 

            // Resolve Pack://siteoforigin. 
            if (PackUriHelper.IsPackUri(source))
            {
                source = BaseUriHelper.ConvertPackUriToAbsoluteExternallyVisibleUri(source);
            } 

            // Block popup window. We attempted to use the default popup Manager to block pup-up windows, 
            // by passing the BrowserNavConstants.NewWindowsManaged flag to WebBrowser 
            // But it did not work. New browser windows still can be opened with "_blank" in Internet zone.
            // So demand unrestricted WebPermission until we figure out a better solution. 
            if (!string.IsNullOrEmpty((string)targetFrameName))
            {
                (new System.Net.WebPermission(PermissionState.Unrestricted)).Demand();
            } 
            else
            { 
                // site locking. 
                // Note: navigation to "about:blank" is not enabled in partial trust. If we are navigating to
                // "about:blank" internally as a result of setting source to null or navigating to stream/string, 
                // do not demand WebPermission.
                if (!InternalBlankNavigation)
                {
                    // we currently demand for both top level and subframe navigations. 
                    // If we allow sub frames to navigate out of site of origin programmtically, we must block cross domain communication
                    // of all kinds, so demand when additional headers and postData are set for sub frame navigation. 
                    // The headers can be used to spoof referer headers. 
                    SecurityHelper.DemandWebPermission(source);
                } 
            }

            //
            object flags = (object)null; // UnsafeNativeMethods.BrowserNavConstants.NewWindowsManaged; 
            object sourceString = (object)BindUriHelper.UriToString(source);
 
            try 
            {
                AxIWebBrowser2.Navigate2(ref sourceString, ref flags, ref targetFrameName, ref postData, ref headers); 
            }
            catch (COMException ce)
            {
                // Clear internal state if Navigation fails. 
                InternalBlankNavigation = false;
                DocumentStream = null; 
 
                // "the operation was canceled by the user" - navigation failed
                // ignore this error, IE has already alerted the user. 
                if ((uint)unchecked(ce.ErrorCode) != (uint)unchecked(0x800704c7))
                {
                    throw;
                } 
            }
        } 
 
        /// 
        /// This method helps work around IE 6 WebOC bugs related to activation state change. The problem seems 
        /// to be fixed in IE 7.
        ///   * When the security 'goldbar' pops up, it acquires focus. When the user unblocks the control,
        ///     focus is set to the main WebOC window, but it doesn't call us on IOleInPlaceSite.OnUIActivate()
        ///     like it normally does when it gets focus. This leaves the ActiveXState at InPlaceActive, but 
        ///     it should be UIActive. Because of this, the invariant assert in TranslateAccelerator() was
        ///     failing on a key down - WOSB 1961596. 
        ///   * Similar case from DevDiv bug 121501: Clicking on a combobox to get its drop down list. If the 
        ///     WebOC doesn't have focus before that, it acquires it, but doesn't call OnUIActivate(). This
        ///     fails the Assert in OnPreprocessMessageThunk(). 
        /// 
        private void SyncUIActiveState()
        {
            if (ActiveXState != ActiveXHelper.ActiveXState.UIActive && ((IKeyboardInputSink)this).HasFocusWithin()) 
            {
                Invariant.Assert(ActiveXState == ActiveXHelper.ActiveXState.InPlaceActive); 
                ActiveXState = ActiveXHelper.ActiveXState.UIActive; 
            }
        } 

        /// 
        ///     Gives the component a chance to process keyboard input.
        ///     Return value is true if handled, false if not.  Components 
        ///     will generally call a child component's TranslateAccelerator
        ///     if they can't handle the input themselves.  The message must 
        ///     either be WM_KEYDOWN or WM_SYSKEYDOWN.  It is illegal to 
        ///     modify the MSG structure, it's passed by reference only as
        ///     a performance optimization. 
        /// 
        ///
        ///     Critical - access critical data ActiveXInPlaceActiveObject and can be used to spoof input
        ///     TreatAsSafe: The interface declaration for this method has a demand on it. 
        ///
        [SecurityCritical, SecurityTreatAsSafe] 
        bool IKeyboardInputSink.TranslateAccelerator(ref MSG msg, ModifierKeys modifiers) 
        {
            SyncUIActiveState(); 
            Invariant.Assert(ActiveXState >= ActiveXHelper.ActiveXState.UIActive, "Should be at least UIActive when we are processing accelerator keys");

            return (ActiveXInPlaceActiveObject.TranslateAccelerator(ref msg) == 0);
        } 

        ///  
        ///     Set focus to the first or last tab stop. If it can't, because it has no tab stops, 
        ///     the return value is false.
        ///  
        ///
        ///     Critical: calls the critical DoVerb(), which sets focus on the control.
        ///     PublicOK: Setting focus on the WebOC is okay. Script is allowed to do that.
        /// 
        [SecurityCritical]
        bool IKeyboardInputSink.TabInto(TraversalRequest request) 
        { 
            Invariant.Assert(ActiveXState >= ActiveXHelper.ActiveXState.InPlaceActive, "Should be at least InPlaceActive when tabbed into");
 
            bool activated = DoVerb(NativeMethods.OLEIVERB_UIACTIVATE);

            if (activated)
            { 
                this.ActiveXState = ActiveXHelper.ActiveXState.UIActive;
            } 
 
            return activated;
        } 

        ///
        ///     Critical - critical because it can be used to spoof input
        /// 
        /// 
        /// This method is called only when the WebOC is hosted in an XBAP and actually hosted in our 
        /// process (not IsWebOCHostedInBrowserProcess). See overview of keyboard input handling at the top 
        /// of the file.
        ///  
        [SecurityCritical]
        private void OnPreprocessMessageThunk(ref MSG msg, ref bool handled)
        {
            // only handle it when the focus is within. 
            if ((handled) || !((IKeyboardInputSink)this).HasFocusWithin())
            { 
                return; 
            }
 
            SyncUIActiveState();
            Invariant.Assert(ActiveXState >= ActiveXHelper.ActiveXState.UIActive, "Should be at least UIActive when we are focused");

            switch (msg.message) 
            {
                case NativeMethods.WM_SYSKEYUP: 
                case NativeMethods.WM_SYSKEYDOWN: 
                case NativeMethods.WM_KEYUP:
                case NativeMethods.WM_KEYDOWN: 
                    handled = ((IKeyboardInputSink)this).TranslateAccelerator(ref msg, ModifierKeys.None);
                    break;
            }
        } 

        #endregion Private Methods 
 
        //----------------------------------------------
        // 
        // Private Properties
        //
        //----------------------------------------------
 
        #region Private Properties
 
        ///  
        /// Critical - Retrieves RBW and sets it on _rbw.
        /// TreatAsSafe - The RBW is exposed via Application.MainWindow anyhow. 
        /// 
        private static RootBrowserWindow RootBrowserWindow
        {
            [SecurityCritical, SecurityTreatAsSafe] 
            get
            { 
                if (_rbw.Value == null) 
                {
                    if (Application.Current != null) 
                    {
                        _rbw.Value = Application.Current.MainWindow as RootBrowserWindow;
                    }
                } 

                return _rbw.Value; 
            } 
        }
 
        /// 
        /// returns whether this is a restricted WebBrowser
        /// 
        ///  
        /// Critical - it accesses critical data (_isWebOCPermissionChecked, _isWebOCPermissionRestricted)
        /// TreatAsSafe - it's safe to return whether it has restricted permission. 
        ///  
        private static bool IsWebOCPermissionRestricted
        { 
            [SecurityCritical, SecurityTreatAsSafe]
            get
            {
                if (!_isWebOCPermissionChecked) 
                {
                    _isWebOCPermissionRestricted = ! SecurityHelper.CallerHasUnrestrictedWebBrowserPermission(); 
                    _isWebOCPermissionChecked = true; 
                }
                return _isWebOCPermissionRestricted; 
            }
        }

        #endregion Private Properties 

        //---------------------------------------------- 
        // 
        // Private Fields
        // 
        //----------------------------------------------

        #region Private Fields
 
        private static readonly Guid WEBOC_GUID = new Guid("8856f961-340a-11d0-a96b-00c04fd705a2");
 
        // Reference to the native ActiveX control's IWebBrowser2 
        // Do not reference this directly. Use the AxIWebBrowser2 property instead since that
        // will cause the object to be instantiated if it is not already created. 
        /// 
        /// Critical - This code can be exploited to call Navigate on a page and it holds a COM interface
        /// 
        [SecurityCritical] 
        private UnsafeNativeMethods.IWebBrowser2                 _axIWebBrowser2;
 
        WebOCHostingAdaptor                                     _hostingAdaptor; 

        // To hook up events from the native WebBrowser 
        private ConnectionPointCookie                           _cookie;

        /// 
        ///     Critical for set - We want to protect the RBW from being set from non-trusted sources. 
        ///                        There's no need to make it SecurityCritical because it's exposed anyhow via Application.MainWindow.
        ///  
        private static SecurityCriticalDataForSet _rbw; 

        ///  
        /// determines whether _isWebOCPermissionRestricted was initialized or not yet.
        /// 
        /// 
        /// Critical - it indicates whether _isWebOCPermissionRestricted has been intialized or not. 
        /// 
        [SecurityCritical] 
        private static bool                                      _isWebOCPermissionChecked; 

        ///  
        /// Critical - it determines whether this is a restricted WebBrowser.
        /// 
        [SecurityCritical]
        private static bool                                      _isWebOCPermissionRestricted; 

        private WeakEventPreprocessMessage                         _weakEventPreprocessMessage; 
 
        private object                                           _objectForScripting;
        private Stream                                           _documentStream; 

        /// 
        ///    Critical: _internalBlankNavigation is involved in making security decisions.
        ///              We navigate to about:blank internally when navigating to null or navigation to string/stream. 
        ///              This flag is used to avoid security check per navigation source in order to enable navigation
        ///              to about:blank in partial trust. 
        ///              Setting this property to true will by pass the site locking logic. Currently it is only true when 
        ///              navigating to about:blank internally for the scenarios described above.
        ///  
        private SecurityCriticalDataForSet                    _internalBlankNavigation;

        #endregion Private Fields
 
        //----------------------------------------------
        // 
        // Private Classes 
        //
        //---------------------------------------------- 

        #region Private Class

        ///  
        /// Logical extension to class WebBrowser. Exposes a minimal polymorphic interface that lets us host
        /// the WebOC either in-process or in the browser process (when IsWebOCHostedInBrowserProcess==true). 
        /// This base class handles the in-process hosting. 
        /// 
        internal class WebOCHostingAdaptor 
        {
            internal WebOCHostingAdaptor(WebBrowser webBrowser)
            {
                _webBrowser = webBrowser; 
            }
 
            internal virtual object ObjectForScripting 
            {
                get { return _webBrowser.ObjectForScripting; } 
                set { }
            }

            ///  
            /// Critical: As a native object, the WebOC should not be exposed to partial-trust code.
            ///  
            [SecurityCritical] 
            internal virtual object CreateWebOC()
            { 
                Guid clsid = WEBOC_GUID;
                return UnsafeNativeMethods.CoCreateInstance(ref clsid, null, NativeMethods.CLSCTX_INPROC_SERVER, ref NativeMethods.IID_IUnknown);
            }
 
            /// 
            /// Critical: WebBrowserEvent instances should not be exposed to partial-trust code. 
            ///  
            [SecurityCritical]
            internal virtual object CreateEventSink() 
            {
                return new WebBrowserEvent(_webBrowser);
            }
 
            protected WebBrowser _webBrowser;
        }; 
 
        /// 
        /// Used when WebBrowser.IsWebOCHostedInBrowserProcess. 
        /// 
        private class WebOCHostedInBrowserAdaptor : WebOCHostingAdaptor
        {
            internal WebOCHostedInBrowserAdaptor(WebBrowser webBrowser) : base(webBrowser) { } 

            ///  
            /// Critical: Calls the native CoRegisterPSClsid(). 
            /// TAS: Enabling a specific interface to be marshaled. The proxy-stub code is in our PHProxy DLL.
            ///  
            [SecurityCritical, SecurityTreatAsSafe]
            static WebOCHostedInBrowserAdaptor()
            {
                // IDocHostUIHandler is not marshalable ... probably because no one has needed to use it 
                // cross-thread. PresentationHostProxy.dll is compiled with a clone of it and contains
                // proxy-stub code for it. Registering the proxy-stub this way rather than in the registry 
                // is cleaner because it applies only to our scenarios. 
                // The same thing is done in the browser process, by our in-proc handler.
                Guid iidDHUIH = typeof(UnsafeNativeMethods.IDocHostUIHandler).GUID; 
                Guid clsidPresHostProxy = new Guid("e302cb55-5f9d-41a3-9ef3-61827fb8b46d");
                int hr = UnsafeNativeMethods.CoRegisterPSClsid(ref iidDHUIH, ref clsidPresHostProxy);
                if (hr != NativeMethods.S_OK)
                { 
                    Marshal.ThrowExceptionForHR(hr);
                } 
            } 

            ///  
            /// Critical: Calls the SUC'd CreateIDispatchSTAForwarder().
            /// TAS: Wrapping a managed object in a native one that trivially delegates IDispatch calls is safe.
            /// 
            [SecurityCritical, SecurityTreatAsSafe] 
            internal override object ObjectForScripting
            { 
                get 
                {
                    return _threadBoundObjectForScripting; 
                }
                [SecurityCritical, SecurityTreatAsSafe]
                set
                { 
                    _threadBoundObjectForScripting =
                        value == null ? null : ActiveXHelper.CreateIDispatchSTAForwarder(value); 
                } 
            }
 
            /// 
            /// Critical: As a native object, the WebOC should not be exposed to partial-trust code.
            /// 
            [SecurityCritical] 
            internal override object CreateWebOC()
            { 
                IntPtr pWebOC = Application.Current.BrowserCallbackServices.CreateWebBrowserControlInBrowserProcess(); 
                object webOC = Marshal.GetTypedObjectForIUnknown(pWebOC, typeof(UnsafeNativeMethods.IWebBrowser2));
                Marshal.Release(pWebOC); 
                return webOC;
            }

            ///  
            /// Critical: WebBrowserEvent instances should not be exposed to partial-trust code.
            ///  
            [SecurityCritical] 
            internal override object CreateEventSink()
            { 
                return ActiveXHelper.CreateIDispatchSTAForwarder(
                    (UnsafeNativeMethods.DWebBrowserEvents2)base.CreateEventSink());
            }
 
            // This is a native object that wraps the ObjectForScripting provided by the application
            // in order to ensure calls arrive on WebBrowser's thread. 
            object _threadBoundObjectForScripting; 
        };
 
        private class WeakEventPreprocessMessage : WeakReference
        {
            /// 
            ///     Critical: This code calls attaches an arbitrary window 
            ///     to the call path for the component dispatcher call back.
            ///     Assert in the code. 
            ///  
            [SecurityCritical]
            public WeakEventPreprocessMessage(WebBrowser webBrowser): base(webBrowser) 
            {
                (new UIPermission(PermissionState.Unrestricted)).Assert(); // Blessed assert
                try
                { 
                    // We are attaching to this second-chance event handler because the first-chance
                    // handler is already being used to let the host preprocess messages and send certain 
                    // messages directly to the browser frame. 
                    ComponentDispatcher.ThreadPreprocessMessage +=
                                    new ThreadMessageEventHandler(this.OnPreprocessMessage); 
                }
                finally
                {
                    UIPermission.RevertAssert(); 
                }
            } 
 
            /// 
            ///     Critical: This code calls critcal method OnPreprocessMessageThunk 
            /// 
            [SecurityCritical]
            public void OnPreprocessMessage(ref MSG msg, ref bool handled)
            { 
                WebBrowser webBrowser = this.Target as WebBrowser;
                if(null != webBrowser) 
                { 
                    webBrowser.OnPreprocessMessageThunk(ref msg, ref handled);
                } 
                else
                {
                    Dispose();
                } 
            }
 
            ///  
            ///     Critical:This code calls into ComponentDispatcher
            ///     to disconnect a listener. Assert in the code. 
            ///     TreatAsSafe: This code is ok to call
            /// 
            [SecurityCritical, SecurityTreatAsSafe]
            public void Dispose() 
            {
                (new UIPermission(PermissionState.Unrestricted)).Assert(); // Blessed assert 
                try 
                {
                    ComponentDispatcher.ThreadPreprocessMessage -= 
                                    new ThreadMessageEventHandler(this.OnPreprocessMessage);
                }
                finally
                { 
                    UIPermission.RevertAssert();
                } 
            } 

        } 

        #endregion Private Class
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.

                        

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