RootBrowserWindow.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ DotNET / DotNET / 8.0 / untmp / WIN_WINDOWS / lh_tools_devdiv_wpf / Windows / wcp / Framework / MS / Internal / AppModel / RootBrowserWindow.cs / 5 / RootBrowserWindow.cs

                            //---------------------------------------------------------------------------- 
//
// File: RootBrowserWindow.cs
//
// Description: This class will implement the hosting and bridging logic 
//              between the browser and Avalon.  This will be the top
//              level "frame" that hosts all content in IE.  This class 
//              will not be public. 
//
// Created: 04/28/03 
//
// Copyright (C) 2001 by Microsoft Corporation.  All rights reserved.
//
//  History: 
//      [....]  06/11/03    moved over to wcp tree
//--------------------------------------------------------------------------- 
using System; 
using System.Diagnostics;
using System.Runtime.InteropServices; 
using System.Security;
using System.Security.Permissions;
using System.Text;
 
using System.Windows;
using System.Windows.Automation.Peers; 
using System.Windows.Navigation; 
using System.Windows.Controls;
using System.ComponentModel; 
using System.Windows.Controls.Primitives;
using System.Windows.Media;
using System.Windows.Threading;
using System.Windows.Documents; 
using System.Windows.Input;
using System.Windows.Interop; 
using System.Collections; 
using System.Collections.Generic;
using System.Printing; 
using System.Windows.Xps;
using MS.Internal.Controls; //WebBrowser
using MS.Win32;
using MS.Internal.Utility; 
using MS.Utility;
using MS.Internal; 
using MS.Internal.PresentationFramework;                   // SecurityHelper 
using MS.Internal.Commands;
using System.Windows.Xps.Packaging; 

//In order to avoid generating warnings about unknown message numbers and
//unknown pragmas when compiling your C# source code with the actual C# compiler,
//you need to disable warnings 1634 and 1691. (Presharp Documentation) 
#pragma warning disable 1634, 1691
 
 
namespace MS.Internal.AppModel
{ 

    /// 
    ///
    ///  
    internal sealed class RootBrowserWindow : NavigationWindow, IWindowService, IJournalNavigationScopeHost
    { 
        //---------------------------------------------- 
        //
        // Constructors 
        //
        //----------------------------------------------
        #region Constructors
 

        static RootBrowserWindow() 
        { 
            CommandHelpers.RegisterCommandHandler(typeof(RootBrowserWindow), ApplicationCommands.Print,
                    new ExecutedRoutedEventHandler(OnCommandPrint), new CanExecuteRoutedEventHandler(OnQueryEnabledCommandPrint)); 
        }

        /// 
        /// 
        /// 
        ///  
        ///     Critical:Calls base class constructor that is only present for RBW scenario 
        /// 
        [SecurityCritical] 
        private RootBrowserWindow():base(true)
        {
            // Allow tabbing out to the browser - see KeyInputSite and OnKeyDown().
            // IE 6 doesn't provide the necessary support. 
            if (!IsDownlevelPlatform)
            { 
                SetValue(KeyboardNavigation.TabNavigationProperty, KeyboardNavigationMode.Continue); 
                SetValue(KeyboardNavigation.ControlTabNavigationProperty, KeyboardNavigationMode.Continue);
            } 
        }
        #endregion Constructors

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

        /// 
        /// Creates AutomationPeer ()
        ///  
        protected override AutomationPeer OnCreateAutomationPeer()
        { 
            return new RootBrowserWindowAutomationPeer(this); 
        }
 
        protected override void OnInitialized(EventArgs args)
        {
            AddHandler(Hyperlink.RequestSetStatusBarEvent, new RoutedEventHandler(OnRequestSetStatusBar));
            base.OnInitialized(args); 
        }
 
        protected override Size MeasureOverride(Size constraint) 
        {
            return base.MeasureOverride(GetSizeInLogicalUnits()); 
        }

        protected override Size ArrangeOverride(Size arrangeBounds)
        { 
            // Get the size of the avalon window and pass it to
            // the base implementation. The return value tells the Size 
            // that we are occupying.  Since, we are RBW we will occupy the 
            // entire available size and thus we don't care what our child wants.
            base.ArrangeOverride(GetSizeInLogicalUnits()); 
            return arrangeBounds;
        }

        protected override void OnActivated(EventArgs e) 
        {
        } 
 
        protected override void OnDeactivated(EventArgs e)
        { 
        }

        protected override void OnStateChanged(EventArgs e)
        { 
        }
 
        protected override void OnLocationChanged(EventArgs e) 
        {
        } 

        protected override void OnClosing(CancelEventArgs e)
        {
        } 

        protected override void OnClosed(EventArgs e) 
        { 
        }
 
        ///
        /// Critical - calls the SUC'd IBCS.PostReadyStateChange().
        /// TreatAsSafe - Only READYSTATE_COMPLETE is posted, once, at the end of the activation sequence,
        ///     when the browser expects it. 
        ///
        [SecurityCritical, SecurityTreatAsSafe] 
        protected override void OnContentRendered(EventArgs e) 
        {
            base.OnContentRendered(e); 

            // Posting READYSTATE_COMPLETE triggers the WebOC's DocumentComplete event.
            // Media Center, in particular, uses this to make the WebOC it hosts visible.
            if (!_loadingCompletePosted) 
            {
                Browser.PostReadyStateChange(READYSTATE_COMPLETE); 
                _loadingCompletePosted = true; 
            }
        } 

        protected override void OnKeyDown(KeyEventArgs e)
        {
            // In browser apps, Ctrl+Tab switches tabs. F6 simulates it here. 
            if (e.Key == Key.F6 && (e.KeyboardDevice.Modifiers & ~ModifierKeys.Shift) == 0)
            { 
                if (KeyboardNavigation.Navigate( 
                        e.KeyboardDevice.FocusedElement as DependencyObject ?? this,
                        Key.Tab, e.KeyboardDevice.Modifiers | ModifierKeys.Control)) 
                {
                    e.Handled = true;
                }
            } 

            if (!e.Handled) 
            { 
                base.OnKeyDown(e);
            } 
        }

        #endregion Protected methods
 
        //----------------------------------------------
        // 
        // Internal Methods 
        //
        //---------------------------------------------- 
        #region Internal Methods

        /// 
        ///     Creates the RBW object and sets the Style property on it 
        ///     to the correct value
        ///  
        ///  
        ///     Critical: Calls RBW class constructor
        ///  
        [SecurityCritical]
        internal static RootBrowserWindow CreateAndInitialize()
        {
            RootBrowserWindow rbw = new RootBrowserWindow(); 
            rbw.InitializeRBWStyle();
            return rbw; 
        } 

        ///  
        /// Critical: This code elevates to all window permission
        /// 
        [SecurityCritical]
        internal override void CreateAllStyle() 
        {
            Invariant.Assert(App != null, "RootBrowserWindow must be created in an Application"); 
 
            IHostService ihs = (IHostService)App.GetService(typeof(IHostService));
 
            Invariant.Assert(ihs!=null, "IHostService in RootBrowserWindow cannot be null");
            Invariant.Assert(ihs.HostWindowHandle != IntPtr.Zero, "IHostService.HostWindowHandle in RootBrowserWindow cannot be null");

            //This sets the _ownerHandle correctly and will be used to create the _sourceWindow 
            //with the correct parent
            UIPermission uip = new UIPermission(UIPermissionWindow.AllWindows); 
            uip.Assert();//Blessed Assert to set owner handle and to set styles 
            try
            { 
                this.OwnerHandle = ihs.HostWindowHandle;
                this.Win32Style = NativeMethods.WS_CHILD | NativeMethods.WS_CLIPCHILDREN | NativeMethods.WS_CLIPSIBLINGS;
            }
            finally 
            {
                CodeAccessPermission.RevertAssert(); 
            } 

        } 

        /// 
        ///     Override for SourceWindow creation.
        ///     Virtual only so that we may assert. 
        /// 
        ///  
        ///     Critical: This code calls  critical function CreateSourceWindowImpl 
        ///         Elevates to set up the IKeyboardInputSite for the HwndSource.
        ///         Calls critical function GetForegroundWindow(). 
        /// 
        [SecurityCritical]
        internal override void CreateSourceWindowImpl()
        { 
            base.CreateSourceWindowImpl();
            Invariant.Assert(IsSourceWindowNull == false, "Failed to create HwndSourceWindow for browser hosting"); 
 
            // _sourceWindowCreationCompleted specifies that HwndSource creation has completed.  This is used
            // to minimize the SetWindowPos calls from ResizeMove when Height/Width is set prior to calling 
            // show on RBW (this also occurs when Height/Width is set in the style of RBW)
            _sourceWindowCreationCompleted = true;

            if (_rectSet) 
            {
                _rectSet = false; 
                ResizeMove(_xDeviceUnits, _yDeviceUnits, _widthDeviceUnits, _heightDeviceUnits); 
            }
 
            SetUpInputHooks();

            //
            // While the RBW is created and shown, the Top Browser window should have already been created and shown, 
            // Browser doesn't notify this RBW of the activation status again unless user activates/deactivates the main
            // window. It is time to transfer the Top Browser Window's activation status to this RBW so that user's 
            // code can get correct status through property IsActivate. 
            //
 
            IBrowserCallbackServices ibcs = Browser;

            if (ibcs != null)
            { 
                IntPtr topWindow = UnsafeNativeMethods.GetAncestor(new HandleRef(this, CriticalHandle), 2/*GA_ROOT*/);
                Debug.Assert(topWindow != IntPtr.Zero); 
                IntPtr activeWindow = UnsafeNativeMethods.GetForegroundWindow(); 
                HandleActivate(activeWindow == topWindow);
            } 

        }

        // No need to clear App.MainWindow for RBW case.  It throws an exception if attempted 
        internal override void TryClearingMainWindow()
        { 
        } 

        internal override void CorrectStyleForBorderlessWindowCase() 
        {
        }

        internal override void GetRequestedDimensions(ref double requestedLeft, ref double requestedTop, ref double requestedWidth, ref double requestedHeight) 
        {
            requestedTop = 0; 
            requestedLeft = 0; 
            requestedWidth = this.Width;
            requestedHeight = this.Height; 
        }

        ///
        ///     Critical - It also calls critical method (SetRootVisual) 
        ///
        [SecurityCritical] 
        internal override void SetupInitialState(double requestedTop, double requestedLeft, double requestedWidth, double requestedHeight) 
        {
            // If RBW Height/Width was set before calling show in RBW, we need 
            // to update the browser with that size now
            SetBrowserSize();
            SetRootVisual();
        } 

        internal override int nCmdForShow() 
        { 
            return NativeMethods.SW_SHOW;
        } 

        internal override bool HandleWmNcHitTestMsg(IntPtr lParam, ref IntPtr refInt)
        {
            return false; 
        }
 
        internal override WindowMinMax GetWindowMinMax() 
        {
            return new WindowMinMax(0, double.PositiveInfinity); 
        }

        // RBW overrides WmMoveChangedHelper default behavior where it calls
        // either SetValue/CoerceValue on Top/Left DPs since that will 
        // throw an exception for RBW.  Furthermore, in RBW, we don't want
        // to fire LocationChanged event. 
        internal override void WmMoveChangedHelper() 
        {
        } 

        /// 
        ///     Resizes and moves the RBW (which is a WS_CHILD window).  This is called by
        ///     AppProxyInternal when the host callsbacks into it with the new size/location. 
        ///     We need this internal since Height/Width/Top/Left on RBW govern the host'ss
        ///     properties. 
        ///  
        /// 
        ///     The location of WS_CHILD window is relative to it parent window thus when the 
        ///     browser moves it does not call this method since the relative position of this window
        ///     wrt the browser hasn't changed.
        /// 
        /// New left of the RBW 
        /// New top of the RBW
        /// New width of the RBW 
        /// New height of the RBW 
        ///
        ///     Critical as this method handles critical data. 
        ///     TreatAsSafe - as the RBW is always contained within the browser's window.
        ///                          you can move the internal window all you want - but given that you're really
        ///                          contained within the BrowserWindow - the worse you could do is make some of your content not visible.
        /// 
        [SecurityCritical, SecurityTreatAsSafe]
        internal void ResizeMove(int xDeviceUnits, int yDeviceUnits, int widthDeviceUnits, int heightDeviceUnits) 
        { 
            // _sourceWindowCreationCompleted specifies that HwndSource creation has completed.  This is used
            // to minimize the SetWindowPos calls from ResizeMove when Height/Width is set prior to calling 
            // show on RBW (this also occurs when Height/Width is set in the style of RBW).  Thus, we want to
            // resize the underlying avalon hwnd only after its creation is completed
            if (_sourceWindowCreationCompleted == false)
            { 
                _xDeviceUnits = xDeviceUnits;
                _yDeviceUnits = yDeviceUnits; 
                _widthDeviceUnits = widthDeviceUnits; 
                _heightDeviceUnits = heightDeviceUnits;
 
                _rectSet = true;

                return;
            } 

            Invariant.Assert(IsSourceWindowNull == false, "sourceWindow cannot be null if _sourceWindowCreationCompleted is true"); 
 
            HandleRef handleRef;
            handleRef = new HandleRef( this, CriticalHandle ) ; 

            UnsafeNativeMethods.SetWindowPos( handleRef ,
                           NativeMethods.NullHandleRef,
                           xDeviceUnits, 
                           yDeviceUnits,
                           widthDeviceUnits, 
                           heightDeviceUnits, 
                           NativeMethods.SWP_NOZORDER
                           | NativeMethods.SWP_NOACTIVATE 
                           | NativeMethods.SWP_SHOWWINDOW);
        }

        ///  
        ///     This is called when the Title dependency property changes in the Window.
        ///  
        /// 
        /// Critical - calls SUC'd IBCS.SetTitle
        /// TreatAsSafe - setting the text on the browser's window is considered safe. 
        ///                 - spoofing is not possible as the browser prepends it's own string to the string
        ///                      e.g. Microsoft Internet Explorer
        ///                 - it can be done in partial trust in HTML via the TITLE tag.
        /// 
        [SecurityCritical, SecurityTreatAsSafe]
        internal override void UpdateTitle(string titleStr) 
        { 
            Invariant.Assert(App != null, "Application object must not be null for RootBrowserWindow");
 
            IBrowserCallbackServices ibcs = Browser;
            if (ibcs != null)
            {
                string title = PruneTitleString(titleStr); 

                // SHOULD NOT CALL BASE; BASE IMPLEMENTS TEXT PROPERTY ON WINDOW 
                ibcs.SetTitle(title); 

            } 
        }

        /// 
        ///     This is called by NavigationService to set the status bar content 
        ///     for the browser
        ///  
        ///  
        ///     We propagate object.ToString() to the browser's status bar.
        ///  
        ///
        ///     Critical - calls SetStatusText which is SUC'ed.
        ///     TreatAsSafe - setting the status bar text of the browser considered safe.
        ///                   IE/MSRC does not consider hostile setting of text ( even for hyperlink spoofing) 
        ///                   to be an exploit.
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        internal void SetStatusBarText(string statusString)
        { 
            Invariant.Assert(App != null, "Application object must not be null for RootBrowserWindow");
            IBrowserCallbackServices ibcs = Browser;
            if (ibcs != null)
            { 
                ibcs.SetStatusText(statusString);
            } 
        } 

        ///  
        ///     Called to update Height of the browser.  Currently, this method is called from
        ///     two places:
        ///
        ///     1) OnHeightInvalidated from window.cs 
        ///     2) SetBrowserSize in RBW
        ///  
        /// 
        ///     Critical - Can be used to change the size of the browser
        ///     TreatAsSafe - clamps values so that window cannot be sized greater than desktop bounds. 
        ///
        [SecurityCritical, SecurityTreatAsSafe]
        internal override void UpdateHeight(double newHeightLogicalUnits)
        { 
            Point sizeDeviceUnits = LogicalToDeviceUnits(new Point(0, newHeightLogicalUnits));
            int heightDeviceUnits = (int)Math.Round(sizeDeviceUnits.Y); 
 
            IBrowserCallbackServices ibcs = Browser;
            if (ibcs != null) 
            {
                //
                // Note: right now IE is clipping browser height to desktop size.
                // However it should be clipped to available desktop size. See Windows OS Bug #1045038 
                // The code below is to fix this for now.
                // Even if IE's code is changed - likely we keep this as defense in-depth. 
                // 

                int maxHeightDeviceUnits = GetMaxWindowHeight(); 
                heightDeviceUnits = heightDeviceUnits > maxHeightDeviceUnits ? maxHeightDeviceUnits : heightDeviceUnits;
                heightDeviceUnits = heightDeviceUnits < MIN_BROWSER_HEIGHT_DEVICE_UNITS ? MIN_BROWSER_HEIGHT_DEVICE_UNITS : heightDeviceUnits;
                ibcs.SetHeight(heightDeviceUnits);
            } 
        }
 
        /// 
        ///     Critical - Can be used to change the size of the browser
        ///     TreatAsSafe - clamps values so that window cannot be sized greater than desktop bounds. 
        ///
        [SecurityCritical, SecurityTreatAsSafe]
        internal override void UpdateWidth(double newWidthLogicalUnits)
        { 
            Point sizeDeviceUnits = LogicalToDeviceUnits(new Point(newWidthLogicalUnits, 0));
            int widthDeviceUnits  = (int)Math.Round(sizeDeviceUnits.X); 
 
            IBrowserCallbackServices ibcs = Browser;
            if (ibcs != null) 
            {
                //
                // Note: right now IE is clipping browser width to desktop size.
                // However it should be clipped to available desktop size. See Windows OS Bug #1045038 
                // The code below is to fix this for now.
                // Even if IE's code is changed - likely we keep this as defense in-depth. 
                // 
                int maxWidthDeviceUnits = GetMaxWindowWidth();
                widthDeviceUnits = widthDeviceUnits > maxWidthDeviceUnits ? maxWidthDeviceUnits : widthDeviceUnits; 

                widthDeviceUnits = widthDeviceUnits < MIN_BROWSER_WIDTH_DEVICE_UNITS ? MIN_BROWSER_WIDTH_DEVICE_UNITS : widthDeviceUnits;
                ibcs.SetWidth(widthDeviceUnits);
            } 
        }
 
        ///  
        /// When being reloaded from history in the browser, we need to
        /// set up the journal again 
        /// 
        /// 
        internal void SetJournalForBrowserInterop(Journal journal)
        { 
            Invariant.Assert(journal != null, "Failed to get Journal for browser integration");
            base.JournalNavigationScope.Journal = journal; 
        } 

        void IJournalNavigationScopeHost.OnJournalAvailable() 
        {
            base.Journal.BackForwardStateChange += new EventHandler(HandleBackForwardStateChange);
        }
 
        // For downlevel platforms, we don't have integration with the journal, so we have to
        // use our own Journal. 
        /// 
        ///     Critical - calls IBCS.GoBack
        /// 
        [SecurityCritical]
        bool IJournalNavigationScopeHost.GoBackOverride()
        {
            if (HasTravelLogIntegration) 
            {
                IBrowserCallbackServices ibcs = Browser; 
                if (ibcs != null) 
                {
                    try 
                    {
                        ibcs.GoBack();
                    }
#pragma warning disable 6502 // PRESharp - Catch statements should not have empty bodies 
                    catch (OperationCanceledException)
                    { 
                        // Catch the OperationCanceledException when the navigation is canceled. 
                        // See comments in applicationproxyinternal._LoadHistoryStreamDelegate.
                    } 
#pragma warning restore 6502
                }
                return true;
            } 
            return false; // Proceed with internal GoBack.
        } 
 
        // For downlevel platforms, we don't have integration with the journal, so we have to
        // use our own Journal. 
        ///
        ///     Critical - calls IBCS.GoForward
        ///
        [SecurityCritical] 
        bool IJournalNavigationScopeHost.GoForwardOverride()
        { 
            if (HasTravelLogIntegration) 
            {
                IBrowserCallbackServices ibcs = Browser; 
                if (ibcs != null)
                {
                    try
                    { 
                        ibcs.GoForward();
                    } 
#pragma warning disable 6502 // PRESharp - Catch statements should not have empty bodies 
                    catch (OperationCanceledException)
                    { 
                        // Catch the OperationCanceledException when the navigation is canceled.
                        // See comments in applicationproxyinternal._LoadHistoryStreamDelegate.
                    }
#pragma warning restore 6502 
                }
                return true; 
            } 
            return false; // Proceed with internal GoForward.
        } 

        internal override void VerifyApiSupported()
        {
            throw new InvalidOperationException(SR.Get(SRID.NotSupportedInBrowser)); 
        }
 
        internal override void ClearResizeGripControl(Control oldCtrl) 
        {
            // don't do anything here since we do not support 
            // ResizeGrip for RBW
        }

        internal override void SetResizeGripControl(Control ctrl) 
        {
            // don't do anything here since we do not support 
            // ResizeGrip for RBW 
        }
 
        // This is called in weboc's static constructor.
        internal void AddLayoutUpdatedHandler()
        {
            LayoutUpdated += new EventHandler(OnLayoutUpdated); 
        }
 
        internal void TabInto(bool forward) 
        {
            TraversalRequest tr = new TraversalRequest( 
                forward ? FocusNavigationDirection.First : FocusNavigationDirection.Last);
            MoveFocus(tr);
        }
 
        #endregion Internal Methods
 
        //---------------------------------------------- 
        //
        // Private Methods 
        //
        //----------------------------------------------
        #region Private methods
        ///  
        ///     Sets the correct style property on the RBW object based on the
        ///     browser version 
        ///  
        private void InitializeRBWStyle()
        { 
            // If we are on a downlevel platform, then we don't integrate with the browser's
            // travellog, so we have to use our own Journal and supply our own navigation chrome.
            if (!HasTravelLogIntegration)
            { 
                SetResourceReference(StyleProperty, SystemParameters.NavigationChromeDownLevelStyleKey);
 
                // if the Template property is not defined in a custom style, the property system gets 
                // the Template property value for the NavigationWindow from the theme file.  Since,
                // we want to get the Template property value from the browser styles, we need to 
                // set the DefaultStyleKeyProperty here.
                SetValue(DefaultStyleKeyProperty, SystemParameters.NavigationChromeDownLevelStyleKey);
            }
            else 
            {
                SetResourceReference(StyleProperty, SystemParameters.NavigationChromeStyleKey); 
 
                // if the Template property is not defined in a custom style, the property system gets
                // the Template property value for the NavigationWindow from the theme file.  Since, 
                // we want to get the Template property value from the browser styles, we need to
                // set the DefaultStyleKeyProperty here.
                SetValue(DefaultStyleKeyProperty, SystemParameters.NavigationChromeStyleKey);
            } 
        }
 
        /// 
        ///     Critical - elevates to get access to the HwndSource and installs hooks
        /// 
        [SecurityCritical]
        private void SetUpInputHooks()
        {
            IKeyboardInputSink sink; 
            new UIPermission(PermissionState.Unrestricted).Assert(); //BlessedAssert
            try 
            { 
                _inputPostFilter = new HwndWrapperHook(BrowserInteropHelper.PostFilterInput);
                HwndSource hwndSource = base.HwndSourceWindow; 
                hwndSource.HwndWrapper.AddHookLast(_inputPostFilter);

                sink = (IKeyboardInputSink)hwndSource;
            } 
            finally
            { 
                UIPermission.RevertAll(); 
            }
            new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Assert(); //BlessedAssert 
            try
            {
                Debug.Assert(sink.KeyboardInputSite == null);
                sink.KeyboardInputSite = new KeyInputSite(new SecurityCriticalData(sink)); 
            }
            finally 
            { 
                SecurityPermission.RevertAll();
            } 
        }

        /// 
        ///     Updates browser size if Height/Width is not set to default value (NaN).  This 
        ///     means that Height/Width was set prior to calling Show on RBW and we need to
        ///     propagate that to the browser.  This method is called from SetupInitialize which 
        ///     is called from CreateSourceWindowImpl 
        /// 
        private void SetBrowserSize() 
        {
            Point requestedSizeDeviceUnits = LogicalToDeviceUnits(new Point(this.Width, this.Height));

            // if Width was specified 
            if (!DoubleUtil.IsNaN(this.Width))
            { 
                // at this stage, ActualWidth/Height is not set since 
                // layout has not happened (it happens when we set the
                // RootVisual of the HwndSource) 
                UpdateWidth(requestedSizeDeviceUnits.X);
            }

            // if Height was specified 
            if (!DoubleUtil.IsNaN(this.Height))
            { 
                // at this stage, ActualWidth/Height is not set since 
                // layout has not happened (it happens when we set the
                // RootVisual of the HwndSource) 
                UpdateHeight(requestedSizeDeviceUnits.Y);
            }
        }
 
        private string PruneTitleString(string rawString)
        { 
            StringBuilder sb = new StringBuilder(); 
            bool inMiddleOfWord = false;
 
            for (int i=0; i < rawString.Length; i++)
            {
                if (Char.IsWhiteSpace(rawString[i]) == false)
                { 
                    sb.Append(rawString[i]);
                    inMiddleOfWord = true; 
                } 
                else
                { 
                    if (inMiddleOfWord == true)
                    {
                        sb.Append(' ');
                        inMiddleOfWord = false; 
                    }
                } 
            } 

            // remove the last space if it exists 
            return sb.ToString().TrimEnd(' ');
        }

        private void OnLayoutUpdated(object obj, EventArgs args) 
        {
            try 
            { 
                VerifyWebOCOverlap(NavigationService);
            } 
            finally
            {
                _webBrowserList.Clear();
            } 
        }
 
        private void VerifyWebOCOverlap(NavigationService navigationService) 
        {
            for (int i = 0; i < navigationService.ChildNavigationServices.Count; i++) 
            {
                NavigationService childNavService = (NavigationService)(navigationService.ChildNavigationServices[i]);
                WebBrowser webBrowser = childNavService.WebBrowser;
                if (webBrowser != null) 
                {
                    for (int j = 0; j < _webBrowserList.Count; j++) 
                    { 
                        // Note: We are using WebBrowser.BoundRect, which is relative to parent window.
                        // Since WebBrowsers are all siblings child windows right now, e.g., we don't allow WebOC inside 
                        // Popup window, this is a better performed way. If we change that, we should make sure the rects
                        // to compare are relative to desktop.
                        Rect rect = Rect.Intersect(webBrowser.BoundRect, _webBrowserList[j].BoundRect);
                        // Only when the intersect rect's Width and Height are both bigger than 0, we consider them overlapping. 
                        // Even when 2 edges are next to each other, it is considered as intersect by the Rect class.
                        if ((rect.Width > 0) && (rect.Height > 0)) 
                        { 
                            throw new InvalidOperationException(SR.Get(SRID.WebBrowserOverlap));
                        } 
                    }
                    _webBrowserList.Add(webBrowser);
                }
                else 
                {
                    VerifyWebOCOverlap(childNavService); 
                } 
            }
        } 

        /// 
        /// We are not using the CanGoBack/CanGoForward property change since that is fired only
        /// if the value changes eg. if we had 3 entries in the backstack, then a back navigation 
        /// won't fire this since the value is still 'true' and has not changed.
        /// What we need is the UpdateView() notification or the BackForwardState change 
        /// notification which is fired from UpdateView() of the Journal. 
        /// Trying to hook the event will create the journal even if there was no navigation
        /// so just using an virtual override to do the work. 
        /// 
        ///
        ///     Critical - as this method calls into Browser call back method for back and forward.
        ///                This is a pinoke call. 
        ///     TreatAsSafe - as this is a safe operation.
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        private void HandleBackForwardStateChange(object sender, EventArgs args)
        { 
            //Nothing to do for downlevel platform
            if (!HasTravelLogIntegration)
                return;
 
            IBrowserCallbackServices ibcs = Browser;
            if (ibcs != null) 
            { 
                ibcs.UpdateBackForwardState();
            } 
        }


        /// 
        /// Given a proposed width - and curWidth - return the MaxWidth the window can be opened to.
        /// Used to prevent sizing of window > desktop bounds in browser. 
        /// 
        ///
        /// Critical - calls back to browser to get the current left. 
        /// TreatAsSafe - this value isn't returned or stored.
        ///               value returned is the current maximum width allowed considered safe.
        ///
        [SecurityCritical, SecurityTreatAsSafe ] 
        private int GetMaxWindowWidth()
        { 
            NativeMethods.RECT desktopArea = WorkAreaBoundsForNearestMonitor; 
            int browserLeft = 0;
            int curBrowserWidth = 0; 
            IBrowserCallbackServices ibcs = Browser;

            bool successful = false ;
 
            successful = (ibcs != null) && ibcs.GetLeft(ref browserLeft );
 
            if ( ! successful ) 
            {
                browserLeft = 0; 
            }

            successful = (ibcs != null) && ibcs.GetWidth(ref curBrowserWidth);
 
            if (! successful)
            { 
                curBrowserWidth = 0; 
            }
 
            int availableWidth = desktopArea.right - browserLeft;
            int maxWidth = availableWidth > curBrowserWidth ? availableWidth : curBrowserWidth;

            return maxWidth; 
        }
 
        /// 
        /// Given a proposed height - and curHeight - return the MaxHeight the window can be opened to.
        /// Used to prevent sizing of window > desktop bounds in browser. 
        ///
        ///
        /// Critical - calls back to browser to get the current top.
        /// TreatAsSafe - this value isn't returned or stored. 
        ///               value returned is the current maximum height allowed considered safe.
        /// 
        [SecurityCritical, SecurityTreatAsSafe ] 
        private int GetMaxWindowHeight()
        { 
            NativeMethods.RECT desktopArea = WorkAreaBoundsForNearestMonitor;
            int browserTop = 0;
            int curBrowserHeight = 0;
            IBrowserCallbackServices ibcs = Browser; 
            bool successful = false ;
 
            successful = (ibcs != null) && ibcs.GetTop(ref browserTop ); 

            if ( ! successful ) 
            {
                browserTop = 0;
            }
 
            successful = (ibcs != null) && ibcs.GetHeight(ref curBrowserHeight);
 
            if ( ! successful ) 
            {
                curBrowserHeight = 0; 
            }

            int availableHeight =  desktopArea.bottom - browserTop ;
            int maxHeight = availableHeight > curBrowserHeight ? availableHeight : curBrowserHeight; 

            return maxHeight; 
        } 

 
        ///
        ///For browser hosting cases, we get the rects through OLE activation before we create the
        ///RootBrowserWindow. Even if SourceWindow or Handle are null, we can return the cached rects
        /// 
        private Size GetSizeInLogicalUnits()
        { 
            Size size; 

            // Adding check for IsCompositionTargetInvalid as part of the fix for WOSB 1453012 
            if (IsSourceWindowNull || IsCompositionTargetInvalid)
            {
                // return _widthDeviceUnits & _heightDeviceUnits if hwndsource is not yet available.
                // We will resize when hwnd becomes available, because the DeviceToLogicalUnits calculation 
                // depends on hwnd being available. If it's not high dpi, the second resize will be optimized
                // by layout system. 
                size = new Size(_widthDeviceUnits, _heightDeviceUnits); 
            }
            else 
            {
                // It's better to get WindowSize instead of doing WindowSize.Width & WindowSize.Height
                // because WindowSize queries HwndSource.
                size = WindowSize; 
                Point ptLogicalUnits = DeviceToLogicalUnits(new Point(size.Width, size.Height));
                size = new Size(ptLogicalUnits.X, ptLogicalUnits.Y); 
            } 

            return size; 
        }

        private void OnRequestSetStatusBar(object sender, RoutedEventArgs e)
        { 
            RequestSetStatusBarEventArgs statusEvent = e as RequestSetStatusBarEventArgs;
 
            if ( statusEvent != null ) 
            {
                SetStatusBarText(statusEvent.Text); 
            }
        }

 
        ///
        /// Prints the content of the App's MainWindow.  The logic is that if the content is not visual but IInputElement 
        /// we will try to let it handle the command first. If it does not handle the print command we will get the corresponding 
        /// visual in the visual tree and use that to print.
        /// 
        private static void OnCommandPrint(object sender, ExecutedRoutedEventArgs e)
        {
#if !DONOTREFPRINTINGASMMETA
            RootBrowserWindow rbw = sender as RootBrowserWindow; 
            Invariant.Assert(rbw != null);
 
            if (! rbw._isPrintingFromRBW) 
            {
                Visual vis = rbw.Content as Visual; 

                if (vis == null)
                {
                    // If the content is not Visual but IInputElement, try to let it handle the command first. 
                    // This is for the document scenario. Printing a document is different from printing a visual.
                    // Printing a visual is to print how it is rendered on screen. Printing a doc prints the full 
                    // doc inculding the part that is not visible. There might be other functionalities that are 
                    // specific for document. FlowDocument's viewer knows how to print the doc.
                    IInputElement target = rbw.Content as IInputElement; 

                    if (target != null)
                    {
                        // CanExecute will bubble up. If nobody between the content and rbw can handle it, 
                        // It would call back on RBW again. Use _isPrintingFromRBW to prevent the loop.
                        rbw._isPrintingFromRBW = true; 
                        try 
                        {
                            if (ApplicationCommands.Print.CanExecute(null, target)) 
                            {
                                ApplicationCommands.Print.Execute(null, target);
                                return;
                            } 
                        }
                        finally 
                        { 
                            rbw._isPrintingFromRBW = false;
                        } 
                    }
                }

                // Let the user choose a printer and set print options. 
                PrintDialog printDlg = new PrintDialog();
 
                // If the user pressed the OK button on the print dialog, we proceed 
                if (printDlg.ShowDialog() == true)
                { 
                    string printJobDescription = GetPrintJobDescription(App.MainWindow);

                    // If the root is not visual and does not know how to print itself, we find the
                    // corresponding visual and use that to print. 
                    if (vis == null)
                    { 
                        INavigatorImpl navigator = rbw as INavigatorImpl; 
                        Invariant.Assert(navigator != null);
 
                        vis = navigator.FindRootViewer();
                        Invariant.Assert(vis != null);
                    }
 
                    // Area we can print to for the chosen printer
                    Rect imageableRect = GetImageableRect(printDlg); 
 
                    // We print Visuals aligned with the top/left corner of the printable area.
                    // We do not attempt to print very large Visuals across multiple pages. 
                    // Any portion that doesn't fit on a single page will get cropped by the
                    // print system.

                    // Used to draw our visual into another visual for printing purposes 
                    VisualBrush visualBrush = new VisualBrush(vis);
                    visualBrush.Stretch = Stretch.None; 
 
                    // Visual we will print - containing a rectangle the size of our
                    // original Visual but offset into the printable area 
                    DrawingVisual drawingVisual = new DrawingVisual();
                    DrawingContext context = drawingVisual.RenderOpen();
                    context.DrawRectangle(visualBrush,
                                          null, 
                                          new Rect(imageableRect.X,
                                                   imageableRect.Y, 
                                                   vis.VisualDescendantBounds.Width, 
                                                   vis.VisualDescendantBounds.Height));
                    context.Close(); 

                    printDlg.PrintVisual(drawingVisual, printJobDescription);
                }
            } 
#endif // DONOTREFPRINTINGASMMETA
        } 
 
        private static void OnQueryEnabledCommandPrint(object sender, CanExecuteRoutedEventArgs  e)
        { 
            RootBrowserWindow rbw = sender as RootBrowserWindow;
            Invariant.Assert(rbw != null);

            if ((!e.Handled) && (!rbw._isPrintingFromRBW)) 
            {
                // While we could print null it doesn't really make sense to do so 
                e.CanExecute = rbw.Content != null; 
            }
        } 

        ///
        /// Critical - calls out to PrintDialog to get the PrintQueue and its PrintCapabilities
        /// TreatAsSafe - these values aren't returned or stored 
        ///
        [SecurityCritical, SecurityTreatAsSafe] 
        private static Rect GetImageableRect(PrintDialog dialog) 
        {
            Invariant.Assert(dialog != null, "Dialog should not be null."); 

            PrintQueue queue = null;
            PrintCapabilities capabilities = null;
            PageImageableArea imageableArea = null; 
            Rect imageableRect = Rect.Empty;
 
            // This gets the PringDocumentImageableArea.OriginWidth/OriginHeight 
            // of the PrintQueue the user chose in the dialog.
            CodeAccessPermission printp = new System.Drawing.Printing.PrintingPermission(PermissionState.Unrestricted); 
            printp.Assert();//Blessed Assert to get PageImageableArea
            try
            {
                queue = dialog.PrintQueue; 
                if (queue != null)
                { 
                    capabilities = queue.GetPrintCapabilities(); 
                }
            } 
            finally
            {
                CodeAccessPermission.RevertAssert();
            } 

            if (capabilities != null) 
            { 
                imageableArea = capabilities.PageImageableArea;
                if (imageableArea != null) 
                {
                    imageableRect = new Rect(imageableArea.OriginWidth,
                                             imageableArea.OriginHeight,
                                             imageableArea.ExtentWidth, 
                                             imageableArea.ExtentHeight);
                } 
            } 

            // If for any reason we couldn't get the actual printer's values 
            // we fallback to a constant and the values available from the
            // PrintDialog.
            if (imageableRect == Rect.Empty)
            { 
                imageableRect = new Rect(NON_PRINTABLE_MARGIN,
                    NON_PRINTABLE_MARGIN, 
                    dialog.PrintableAreaWidth, 
                    dialog.PrintableAreaHeight);
            } 

            return imageableRect;
        }
 
        /// 
        ///    Generate the title of the print job for a given Window. 
        ///  
        private static string GetPrintJobDescription(Window window)
        { 
            Invariant.Assert(window != null, "Window should not be null.");

            string description = null;
            string pageTitle = null; 

            // Get the window title 
            string windowTitle = window.Title; 
            if (windowTitle != null)
            { 
                windowTitle = windowTitle.Trim();
            }

            // Get the page title, if available 
            Page page = window.Content as Page;
            if (page != null) 
            { 
                pageTitle = page.Title;
                if (pageTitle != null) 
                {
                    pageTitle = pageTitle.Trim();
                }
            } 

            // If window and page title are available, use them together, 
            // otherwise use which ever is available 
            if (!String.IsNullOrEmpty(windowTitle))
            { 
                if (!String.IsNullOrEmpty(pageTitle))
                {
                    description = SR.Get(SRID.PrintJobDescription, windowTitle, pageTitle);
                } 
                else
                { 
                    description = windowTitle; 
                }
            } 

            // No window title so use the page title on its own
            if (description == null && !String.IsNullOrEmpty(pageTitle))
            { 
                description = pageTitle;
            } 
 
            // If neither window or page titles are available, try and use
            // the source URI for the content 
            if (description == null && BrowserInteropHelper.Source != null)
            {
                Uri source = BrowserInteropHelper.Source;
                if (source.IsFile) 
                {
                    description = source.LocalPath; 
                } 
                else
                { 
                    description = source.ToString();
                }
            }
 
            // If no other option, use a localized constant
            if (description == null) 
            { 
                description = SR.Get(SRID.UntitledPrintJobDescription);
            } 

            return description;
        }
 

        #endregion Private methods 
 
        //----------------------------------------------
        // 
        // Private Properties
        //
        //----------------------------------------------
        #region Private properties 
        private static Application App
        { 
            get { return Application.Current; } 
        }
 

        private static IBrowserCallbackServices Browser
        {
            get 
            {
                // There will be no IBrowserCallbackServices available in some situations, e.g., during shutdown 
                IBrowserCallbackServices ibcs = (App == null ? null : App.BrowserCallbackServices); 
                return ibcs;
            } 
        }

        ///
        /// Critical - calls the SUC'd IBCS.IsDownlevelPlatform. 
        /// TreatAsSafe - this information is okay to give out.
        /// 
        private bool IsDownlevelPlatform 
        {
            [SecurityCritical, SecurityTreatAsSafe] 
            get
            {
                if (!_isDownlevelPlatformValid)
                { 
                    IBrowserCallbackServices ibcs = Browser;
                    _isDownlevelPlatform = (ibcs != null) ? ibcs.IsDownlevelPlatform() : false; 
 
                    _isDownlevelPlatformValid = true;
                } 
                return _isDownlevelPlatform;
            }
        }
 
        internal bool HasTravelLogIntegration
        { 
            get 
            {
                return !IsDownlevelPlatform && BrowserInteropHelper.IsAvalonTopLevel; 
            }
        }

        #endregion Private properties 

        //---------------------------------------------- 
        // 
        // Private Classes
        // 
        //----------------------------------------------
        #region Private Classes

        ///  
        /// This class is used to print objects which are not directly supported by XpsDocumentWriter.
        /// It's sole purpose is to make a non-abstract version of Visual. 
        ///  
        private class PrintVisual : ContainerVisual { }
 

        private class KeyInputSite : IKeyboardInputSite
        {
            internal KeyInputSite(SecurityCriticalData sink) 
            {
                _sink = sink; 
            } 

            ///  
            /// Critical: sets critical data.
            /// Safe: setting to null is okay.
            /// 
            [SecurityCritical, SecurityTreatAsSafe] 
            void IKeyboardInputSite.Unregister()
            { 
                _sink = new SecurityCriticalData(null); 
            }
 
            /// 
            /// Critical: IKeyboardInputSink could be used to spoof input.
            /// 
            IKeyboardInputSink IKeyboardInputSite.Sink 
            {
                [SecurityCritical] 
                get { return _sink.Value; } 
            }
 
            /// 
            /// Critical: calls the SUC'd IBCS.TabOut().
            /// Safe: tabbing out of the application is safe.
            ///  
            [SecurityCritical, SecurityTreatAsSafe]
            bool IKeyboardInputSite.OnNoMoreTabStops(TraversalRequest request) 
            { 
                return Browser.TabOut(request.FocusNavigationDirection == FocusNavigationDirection.Next);
                // i. Tabbing-in is handled by ApplicationProxyInternal. 
            }

            /// 
            /// Critical: The encapsulated interface could be used to spoof input. 
            /// 
            SecurityCriticalData _sink; 
        }; 

        #endregion Private Classes 


        //----------------------------------------------
        // 
        // Private Members
        // 
        //---------------------------------------------- 
        #region private members
 
        //Cache the values until the HwndSourceWindow is created
        private int  _xDeviceUnits, _yDeviceUnits, _widthDeviceUnits, _heightDeviceUnits;
        private bool _rectSet;
 
        private bool _isPrintingFromRBW;
        private bool _isDownlevelPlatformValid; 
        private bool _isDownlevelPlatform; 
        private bool _sourceWindowCreationCompleted;
 
        private List _webBrowserList = new List();

        /// 
        /// The event delegate has to be stored because HwndWrapper keeps only a weak reference to it. 
        /// 
        ///  
        /// Critical: could be used to spoof input 
        /// 
        [SecurityCritical] 
        private HwndWrapperHook _inputPostFilter;

        private bool _loadingCompletePosted;
        const int READYSTATE_COMPLETE = 4; 

        // Fallback constant for the size of non-printable margin.  This is used if 
        // we cant retrieve the actual size from the PrintQueue. 
        private const int NON_PRINTABLE_MARGIN = 15;
 
        //
        // Setting these as the min-browser width & height.
        // Note that we can't use User's min window-width & height - these are specifically about browser window.
        // 
        private const int MIN_BROWSER_WIDTH_DEVICE_UNITS = 200;
 
        private const int MIN_BROWSER_HEIGHT_DEVICE_UNITS = 200; 
        #endregion private members
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.


                        

Link Menu

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