HwndTarget.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 / Core / System / Windows / InterOp / HwndTarget.cs / 7 / HwndTarget.cs

                            //------------------------------------------------------------------------------ 
//  Microsoft Avalon
//  Copyright (c) Microsoft Corporation.  All rights reserved.
//
//  File:       HwndTarget.cs 
//
//----------------------------------------------------------------------------- 
using System; 
using System.Diagnostics;
using System.Windows.Threading; 
using System.Threading;
using System.Windows;
using System.Collections.Generic;
using System.Windows.Media; 
using System.Windows.Media.Animation;
using System.Windows.Automation.Provider; 
using System.Windows.Automation.Peers; 
using System.Windows.Media.Composition;
using System.Runtime.InteropServices; 
using System.Security.Permissions;
using System.Security;
using MS.Internal;
using MS.Internal.Automation; 
using MS.Win32;
using MS.Utility; 
using Microsoft.Internal; 
using MS.Internal.PresentationCore;                        // SecurityHelper
 
using SR=MS.Internal.PresentationCore.SR;
using SRID=MS.Internal.PresentationCore.SRID;

#pragma warning disable 1634, 1691  // suppressing PreSharp warnings 

namespace System.Windows.Interop 
{ 
    // This is the internal, more expressive, enum used by the SetRenderingMode method.
    // See the RenderMode enum and the RenderMode property for the public version. 
    internal enum RenderingMode
    {
        Default = MILRTInitializationFlags.MIL_RT_INITIALIZE_DEFAULT,
        Software = MILRTInitializationFlags.MIL_RT_SOFTWARE_ONLY, 
        Hardware = MILRTInitializationFlags.MIL_RT_HARDWARE_ONLY,
        HardwareReference = MILRTInitializationFlags.MIL_RT_HARDWARE_ONLY | MILRTInitializationFlags.MIL_RT_USE_REF_RAST, 
    } 

    // This is the public, more limited, enum exposed for use with the RenderMode property. 
    // See the RenderingMode enum and SetRenderingMode method for the internal version.
    /// 
    ///     Render mode preference.
    ///  
    public enum RenderMode
    { 
        ///  
        /// The rendering layer should use the GPU and CPU as appropriate.
        ///  
        Default,

        /// 
        /// The rendering layer should only use the CPU. 
        /// 
        SoftwareOnly 
    } 

    ///  
    /// The HwndTarget class represents a binding to an HWND.
    /// 
    /// The HwndTarget is not thread-safe. Accessing the HwndTarget from a different
    /// thread than it was created will throw a . 
    public class HwndTarget : CompositionTarget
    { 
        private static int s_dwmRedirectionEnvironmentChanged; 
        private static int s_channelNotifyMessage;
        private static int s_transformHintUpdateMessage; 
        private static int s_updateWindowSettings;

        private MatrixTransform _worldTransform;
        private double _devicePixelsPerInchX; 
        private double _devicePixelsPerInchY;
 
        ///  
        /// Critical -  We don't want partial trust code changing the rendering preference.
        ///  
        private SecurityCriticalDataForSet _renderModePreference = new SecurityCriticalDataForSet(RenderMode.Default);
 	
        ///
        /// Critical - obtained under an elevation. 
        ///
        [SecurityCritical] 
        private NativeMethods.HWND _hWnd; 

        private NativeMethods.RECT _hwndClientRectInScreenCoords; 
        private NativeMethods.RECT _hwndWindowRectInScreenCoords;

        private Color _backgroundColor = Color.FromRgb(0, 0, 0);
 
        private DUCE.MultiChannelResource _compositionTarget =
            new DUCE.MultiChannelResource(); 
 
        private bool _isRenderTargetEnabled = true;
        // private Nullable _colorKey = null; 
        // private double _opacity = 1.0;
        private bool _usesPerPixelOpacity = false;

        // It is important that this start at zero to allow an initial 
        // UpdateWindowSettings(enable) command to enable the render target
        // without a preceeding UpdateWindowSettings(disable) command. 
        private int _disableCookie = 0; 

        // Used to deal with layered window problems. See comments where they are used. 
        private bool _isMinimized = false;
        private bool _isSessionDisconnected = false;
        private bool _isSuspended = false;
 
        /// 
        /// Initializes static variables for this class. 
        ///  
        /// 
        /// Critical        - Calls unsafe method RegisterWindowMessage. 
        /// TreatAsSafe     - No external parameters are taken in.
        /// 
        [SecurityCritical, SecurityTreatAsSafe]
        static HwndTarget() 
        {
            s_dwmRedirectionEnvironmentChanged = UnsafeNativeMethods.RegisterWindowMessage("DwmRedirectionEnvironmentChangedHint"); 
            s_channelNotifyMessage = UnsafeNativeMethods.RegisterWindowMessage("MilChannelNotify"); 
            s_transformHintUpdateMessage = UnsafeNativeMethods.RegisterWindowMessage("TransformHintUpdate");
            s_updateWindowSettings = UnsafeNativeMethods.RegisterWindowMessage("UpdateWindowSettings"); 
        }

        /// 
        /// Attaches a hwndTarget to the hWnd 
        /// 
        ///     This API link demands for UIWindowPermission.AllWindows 
        ///  
        /// 
        /// The HWND to which the HwndTarget will draw. 
        /// 
        ///     Callers must have UIPermission(UIPermissionWindow.AllWindows) to call this API.
        /// 
        ///  
        /// Critical - accepts unmanaged pointer handle.Not safe to create since it
        ///            can be used to draw to a window 
        /// PublicOk - demands UIPermission 
        /// 
        [SecurityCritical] 
        [UIPermissionAttribute(SecurityAction.LinkDemand,Window=UIPermissionWindow.AllWindows)]
        public HwndTarget(IntPtr hwnd)
        {
            bool exceptionThrown = true; 

            AttachToHwnd(hwnd); 
 
            try
            { 
                if (EventTrace.IsEnabled(EventTrace.Flags.performance, EventTrace.Level.normal))
                {
                    EventTrace.EventProvider.TraceEvent(EventTrace.GuidFromId(EventTraceGuidId.MEDIACREATEVISUALGUID), MS.Utility.EventType.Info,
                                                         Dispatcher.GetHashCode(), hwnd.ToInt64()); 
                }
 
                _hWnd = NativeMethods.HWND.Cast(hwnd); 

                // Get the client rectangle... 
                GetWindowRectsInScreenCoordinates();

                // Set device independent resolution to 96 DPI.
                // NativeMethods.HDC hdc = NativeMethods.GetDC(_hWnd); 

                _devicePixelsPerInchX = 96.0f; 
                _devicePixelsPerInchY = 96.0f; 

                // 
                // Determine whether hWnd corresponds to MIL or GDI window.
                //
                IntPtr hdcW = UnsafeNativeMethods.GetDC(
                    new HandleRef(this, _hWnd)); 

                if (hdcW == IntPtr.Zero) 
                { 
                    //
                    // If we were unable to obtain HDC for the given 
                    // window, assume the default of 96 DPI.
                    //

                    _devicePixelsPerInchX = 96.0f; 
                    _devicePixelsPerInchY = 96.0f;
                } 
                else 
                {
                    // 
                    // Obtain and cache DPI values for window's HDC.
                    //

                    _devicePixelsPerInchX = (double)UnsafeNativeMethods.GetDeviceCaps( 
                        new HandleRef(this, hdcW),
                        NativeMethods.LOGPIXELSX); 
 
                    _devicePixelsPerInchY = (double)UnsafeNativeMethods.GetDeviceCaps(
                        new HandleRef(this, hdcW), 
                        NativeMethods.LOGPIXELSY);

                    //
                    // Release DC object. 
                    //
 
                    UnsafeNativeMethods.ReleaseDC( 
                        new HandleRef(this, _hWnd),
                        new HandleRef(this, hdcW)); 
                }

                _worldTransform = new MatrixTransform(new Matrix(
                  _devicePixelsPerInchX * (1.0f / 96.0f), 0, 
                  0, _devicePixelsPerInchY * (1.0f / 96.0f),
                  0, 0)); 
 
                //
                // Register CompositionTarget with MediaContext. 
                //
                MediaContext.RegisterICompositionTarget(Dispatcher, this);

                // 
                // Register this window with MediaContext if it is layered
                // 
                Int32 exStyle = UnsafeNativeMethods.GetWindowLong(_hWnd.MakeHandleRef(this), NativeMethods.GWL_EXSTYLE); 
                if ((exStyle & NativeMethods.WS_EX_LAYERED) != 0)
                { 
                    MediaContext.From(Dispatcher).AddLayeredWindow(this);
                }

                // 
                // Change the window message filter to allow session and transform
                // hint control messages to be sent from the DWM. On down-level 
                // platforms, these calls will result in no-op. 
                //
 
                ChangeWindowMessageFilter((uint)s_dwmRedirectionEnvironmentChanged, 1 /* MSGFLT_ADD */);
                ChangeWindowMessageFilter((uint)s_transformHintUpdateMessage, 1 /* MSGFLT_ADD */);

                // 
                // Hint window redirection layer that Avalon content has been attached
                // to this window. As a result, redirection layer will create necessary 
                // resources and manage clip and position for this window in TS and 
                // Accessibility scenarios. If DWM is not running, this call will result
                // in NoOp. 
                //
                HRESULT.Check(MilContent_AttachToHwnd(_hWnd));

                exceptionThrown = false; 
            }
            finally 
            { 
                //
                // If exception has occurred after we attached this target to 
                // the window, we need to detach from this window. Otherwise, window
                // will be left in a state when no other HwndTarget can be created
                // for it.
                // 
                if(exceptionThrown)
                { 
                    #pragma warning suppress 6031 // Return value ignored on purpose. 
                    VisualTarget_DetachFromHwnd(hwnd);
                } 
            }
        }

        ///  
        /// AttachToHwnd
        ///  
        /// 
        /// Critical as it calls a function that performs an elevation (IsWindow).
        /// 
        [SecurityCritical]
        internal void AttachToHwnd(IntPtr hwnd)
        {
            int processId = 0; 
            int threadId = UnsafeNativeMethods.GetWindowThreadProcessId(
                new HandleRef(this, hwnd), 
                out processId 
                );
 
            if (!UnsafeNativeMethods.IsWindow(new HandleRef(this, hwnd)))
            {
                throw new ArgumentException(
                    SR.Get(SRID.HwndTarget_InvalidWindowHandle), 
                    "hwnd"
                    ); 
            } 
            else if (processId != SafeNativeMethods.GetCurrentProcessId())
            { 
                throw new ArgumentException(
                    SR.Get(SRID.HwndTarget_InvalidWindowProcess),
                    "hwnd"
                    ); 
            }
            else if (threadId != SafeNativeMethods.GetCurrentThreadId()) 
            { 
                throw new ArgumentException(
                    SR.Get(SRID.HwndTarget_InvalidWindowThread), 
                    "hwnd"
                    );
            }
 
            int hr = VisualTarget_AttachToHwnd(hwnd);
 
            if (HRESULT.Failed(hr)) 
            {
                if (hr == unchecked((int)0x80070005)) // E_ACCESSDENIED 
                {
                    throw new InvalidOperationException(
                        SR.Get(SRID.HwndTarget_WindowAlreadyHasContent)
                        ); 
                }
                else 
                { 
                    HRESULT.Check(hr);
                } 
            }
        }

        ///  
        ///     Critical: This code causes unmanaged code elevation
        ///  
        [SecurityCritical,SuppressUnmanagedCodeSecurity] 
        [DllImport(DllImport.MilCore, EntryPoint = "MilVisualTarget_AttachToHwnd")]
        internal static extern int VisualTarget_AttachToHwnd( 
            IntPtr hwnd
            );

 
        /// 
        ///     Critical: This code causes unmanaged code elevation 
        ///  
        [SecurityCritical, SuppressUnmanagedCodeSecurity]
        [DllImport(DllImport.MilCore, EntryPoint = "MilVisualTarget_DetachFromHwnd")] 
        internal static extern int VisualTarget_DetachFromHwnd(
            IntPtr hwnd
            );
 
        /// 
        ///     Critical: This code causes unmanaged code elevation 
        ///  
        [SecurityCritical, SuppressUnmanagedCodeSecurity]
        [DllImport(DllImport.MilCore)] 
        internal static extern int MilContent_AttachToHwnd(
            IntPtr hwnd
            );
 
        /// 
        ///     Critical: This code causes unmanaged code elevation 
        ///  
        [SecurityCritical, SuppressUnmanagedCodeSecurity]
        [DllImport(DllImport.MilCore)] 
        internal static extern int MilContent_DetachFromHwnd(
            IntPtr hwnd
            );
 
        /// 
        /// Allow lower integrity applications to send specified window messages 
        /// in case we are elevated. Failure is non-fatal and on down-level 
        /// platforms this call will result in a no-op.
        ///  
        /// 
        /// Critical -- Calls unsafe native methods GetModuleHandle and GetProcAddress.
        ///             Manually elevates unmanaged code permissions to pinvoke through
        ///             a function pointer. 
        /// 
        [SecurityCritical] 
        private void ChangeWindowMessageFilter(uint message, uint flag) 
        {
            // Find the address of SetProcessDPIAware in user32.dll. 
            IntPtr user32Module = UnsafeNativeMethods.GetModuleHandle("user32.dll");

            // Get the address of the function. If this fails it means the OS
            // doesn't support per-process DPI scaling, in which case we don't 
            // need to do anything further.
            IntPtr functionAddress = UnsafeNativeMethods.GetProcAddressNoThrow( 
                    new HandleRef(null, user32Module), 
                    "ChangeWindowMessageFilter");
 
            if  (functionAddress != IntPtr.Zero)
            {
                // Convert the function pointer into a callable delegate and then call it
                ChangeWindowMessageFilterNative function = Marshal.GetDelegateForFunctionPointer( 
                    functionAddress,
                    typeof(ChangeWindowMessageFilterNative)) as ChangeWindowMessageFilterNative; 
 
                // In order to call the function we need unmanaged code access,
                // because the function is native code. 
                (new SecurityPermission(SecurityPermissionFlag.UnmanagedCode)).Assert();
                try
                {
                    function(message, flag); 
                }
                finally 
                { 
                    SecurityPermission.RevertAssert();
                } 
            }
        }

        ///  
        /// Prototype for user32's ChangeWindowMessageFilter function, which we load dynamically on Longhorn.
        ///  
        private delegate void ChangeWindowMessageFilterNative(uint message, uint flag); 

        internal void SetRenderingMode(RenderingMode mode) 
        {
            //
            // If ForceLocalTransport is set then the transport is connected to a client (magnifier) that cannot
            // handle our transport protocol version. Therefore we force software rendering so that the rendered 
            // content is available through NTUser redirection. If software is not allowed an exception is thrown.
            // 
            if (MediaSystem.ForcedLocalTransport) // present using bitblt if a local transport was forced 
            {
                if (mode == RenderingMode.Hardware || 
                    mode == RenderingMode.HardwareReference)
                {
                    throw new InvalidOperationException(SR.Get(SRID.HwndTarget_HardwareNotSupportDueToProtocolMismatch));
                } 
                else
                { 
                    Debug.Assert(mode == RenderingMode.Software || mode == RenderingMode.Default); 
                    // If the mode is default we can chose what works. When we have a mismatched transport protocol version
                    // we need to fallback to software rendering. 
                    mode = RenderingMode.Software;
                }
            }
 
            // Select the render target initialization flags based on the requested
            // rendering mode. 
 
            List channels = MediaContext.From(Dispatcher).GetChannels(this);
 
            foreach (DUCE.ChannelSet channelSet in channels)
            {
                DUCE.Channel channel = channelSet.Channel;
 
                DUCE.CompositionTarget.SetRenderingMode(
                    _compositionTarget.GetHandle(channel), 
                    (MILRTInitializationFlags)mode, 
                    channel);
            } 
        }

        /// 
        /// Specifies the render mode preference for the window. 
        /// 
        ///  
        ///     This property specifies a preference, it does not necessarily change the actual 
        ///     rendering mode.  Among other things, this can be trumped by the registry settings.
        ///      
        ///     Callers must have UIPermission(UIPermissionWindow.AllWindows) to set this property.
        /// 
        /// 
        ///     Critical: This code influences the low-level rendering code by specifying whether the 
        ///     rendering system should use the GPU or CPU.
        ///     PublicOK: We don't want to enable this in partial trust, so we have a link demand 
        ///     on the setter.  It is not privileged data, so the getter is not protected. 
        /// 
        public RenderMode RenderMode 
        {
            get
            {
                return _renderModePreference.Value; 
            }
 
            // Note: We think it is safe to expose this in partial trust, but doing so would suggest 
            // we should also expose HwndSource (the only way to get to the HwndTarget instance).
            // We don't want to bite off that much exposure at this point in the product, so we enforce 
            // that this is not accessible from partial trust for now.
            [SecurityCritical]
            [UIPermissionAttribute(SecurityAction.LinkDemand, Window = UIPermissionWindow.AllWindows)]
            set 
            {
                if (value != RenderMode.Default && value != RenderMode.SoftwareOnly) 
                { 
                    throw new System.ComponentModel.InvalidEnumArgumentException("value", (int)value, typeof(RenderMode));
                } 

                _renderModePreference.Value = value;

                SetRenderingMode(value == RenderMode.SoftwareOnly ? RenderingMode.Software : RenderingMode.Default); 
            }
        } 
 
        /// 
        /// Dispose cleans up the state associated with HwndTarget. 
        /// 
        /// 
        /// Critical - accesses the _hwnd that is critical, calls unmanaged code
        /// PublicOK - dispose is in effect stoping the contents of the target from 
        /// rendering. Equivalent to removing all elements in window, considered safe.
        ///  
        [SecurityCritical] 
        public override void Dispose()
        { 
           // Its outside the try finally block because we want the exception to be
           // thrown if we are on a different thread and we don't want to call Dispose
           // on base class in that case.
           VerifyAccess(); 

           try 
           { 
                // According to spec: Dispose should not raise exception if called multiple times.
                // This test is needed because the HwndTarget is Disposed from both the media contex and 
                // the hwndsrc.
                if (!IsDisposed)
                {
                    RootVisual = null; 

                    HRESULT.Check(VisualTarget_DetachFromHwnd(_hWnd)); 
 
                    //
                    // Unregister this CompositionTarget from the MediaSystem. 
                    //
                    MediaContext.UnregisterICompositionTarget(Dispatcher, this);

                    // 
                    // Unregister this window with MediaContext if it is layered
                    // 
                    Int32 exStyle = UnsafeNativeMethods.GetWindowLong(_hWnd.MakeHandleRef(this), NativeMethods.GWL_EXSTYLE); 
                    if ((exStyle & NativeMethods.WS_EX_LAYERED) != 0)
                    { 
                        MediaContext.From(Dispatcher).RemoveLayeredWindow(this);
                    }

                    // 
                    // Hint window redirection layer that Avalon content has been detached
                    // from this window. Redirection layer will then have a chance to clean 
                    // up the resources that it created for Avalon hosting. If DWM is not 
                    // running, this call will result in NoOp.
                    // 
                    HRESULT.Check(MilContent_DetachFromHwnd(_hWnd));

                    // Unregister for Fast User Switching messages if necessary
                    if (_usesPerPixelOpacity) 
                    {
                        UnsafeNativeMethods.WTSUnRegisterSessionNotification(_hWnd); 
                    } 
                }
 
            }
            finally
            {
                base.Dispose(); 
            }
        } 
 
        /// 
        /// This method is used to create all uce resources either on Startup or session connect 
        /// 
        /// 
        /// Critical - uses unmanaged pointer handle _hWnd
        /// TreatAsSafe - doesn't return or expose _hWnd 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        internal override void CreateUCEResources(DUCE.Channel channel, DUCE.Channel outOfBandChannel) 
        {
            // create visual target resources 
            // this forces the creation of the media context if we don't already have one.

            base.CreateUCEResources(channel, outOfBandChannel);
 
            Debug.Assert(!_compositionTarget.IsOnChannel(channel));
            Debug.Assert(!_compositionTarget.IsOnChannel(outOfBandChannel)); 
 
            //
            // For each HwndTarget we are building some structures in the UCE. 
            // This includes spinning up a UCE render target. We need to commit the
            // batch for those changes right away, since we need to be able to process
            // the invalidate packages that we send down on WM_PAINTs. If we don't commit
            // right away a WM_PAINT can get fired before we get a chance to commit 
            // the batch.
            // 
 
            //
            // First we create the composition target, composition context, and the composition root node. 
            // Note, that composition target will be created out of band because invalidate
            // command is also sent out of band and that can occur before current channel is committed.
            // We would like to avoid commiting channel here to prevent visual artifacts.
            // 

            bool resourceCreated = _compositionTarget.CreateOrAddRefOnChannel(outOfBandChannel, DUCE.ResourceType.TYPE_HWNDRENDERTARGET); 
            Debug.Assert(resourceCreated); 
            _compositionTarget.DuplicateHandle(outOfBandChannel, channel);
            outOfBandChannel.Commit(); 

            DUCE.CompositionTarget.HwndInitialize(
                _compositionTarget.GetHandle(channel),
                _hWnd, 
                _hwndClientRectInScreenCoords.right - _hwndClientRectInScreenCoords.left,
                _hwndClientRectInScreenCoords.bottom - _hwndClientRectInScreenCoords.top, 
                MediaSystem.ForcedLocalTransport, // present using bitblt if a local transport was forced 
                channel
                ); 

            DUCE.ResourceHandle hWorldTransform = ((DUCE.IResource)_worldTransform).AddRefOnChannel(channel);

            DUCE.CompositionNode.SetTransform( 
                _contentRoot.GetHandle(channel),
                hWorldTransform, 
                channel); 

            DUCE.CompositionTarget.SetClearColor( 
                _compositionTarget.GetHandle(channel),
                _backgroundColor,
                channel);
 
            //
            // Set initial state on the visual target. 
            // 

            Rect clientRect = new Rect( 
                0,
                0,
                (float)(Math.Ceiling((double)(_hwndClientRectInScreenCoords.right - _hwndClientRectInScreenCoords.left))),
                (float)(Math.Ceiling((double)(_hwndClientRectInScreenCoords.bottom - _hwndClientRectInScreenCoords.top)))); 

            StateChangedCallback( 
                new object[] 
                {
                    HostStateFlags.WorldTransform | 
                    HostStateFlags.ClipBounds,
                    _worldTransform.Matrix,
                    clientRect
                }); 

            DUCE.CompositionTarget.SetRoot( 
                _compositionTarget.GetHandle(channel), 
                _contentRoot.GetHandle(channel),
                channel); 

            // reset the disable cookie when creating the slave resource. This happens when creating the
            // managed resource and on handling a connect.
            _disableCookie = 0; 

            // 
            // Finally, update window settings to reflect the state of this object. 
            // Because CreateUCEResources is called for each channel, only call
            // UpdateWindowSettings on that channel this time. 
            //
            DUCE.ChannelSet channelSet;
            channelSet.Channel = channel;
            channelSet.OutOfBandChannel = outOfBandChannel; 
            List channelList = new List();
            channelList.Add(channelSet); 
            UpdateWindowSettings(_isRenderTargetEnabled, channelList); 
        }
 
        /// 
        /// This method is used to release all uce resources either on Shutdown or session disconnect
        /// 
        ///  
        /// Critical - uses unmanaged pointer handle _hWnd
        /// TreatAsSafe - doesn't return or expose _hWnd 
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        internal override void ReleaseUCEResources(DUCE.Channel channel, DUCE.Channel outOfBandChannel) 
        {
            if (_compositionTarget.IsOnChannel(channel))
            {
                // 
                // [....]: If we need to flush the batch we need to render first all visual targets that
                // are still registered with the MediaContext to avoid strutural tearing. 
 

                // Set the composition target root node to null. 
                DUCE.CompositionTarget.SetRoot(
                    _compositionTarget.GetHandle(channel),
                    DUCE.ResourceHandle.Null,
                    channel); 

                _compositionTarget.ReleaseOnChannel(channel); 
            } 

            if (_compositionTarget.IsOnChannel(outOfBandChannel)) 
            {
                _compositionTarget.ReleaseOnChannel(outOfBandChannel);
            }
 
            DUCE.ResourceHandle hWorldTransform = ((DUCE.IResource)_worldTransform).GetHandle(channel);
            if (!hWorldTransform.IsNull) 
            { 
                // Release the world transform from this channel if it's currently on the channel.
                ((DUCE.IResource)_worldTransform).ReleaseOnChannel(channel); 
            }

            // release all the visual target resources.
            base.ReleaseUCEResources(channel, outOfBandChannel); 
        }
 
        ///  
        /// The HwndTarget needs to see all windows messages so that
        /// it can appropriately react to them. 
        /// 
        /// 
        /// Critical - accepts unmanaged pointer handle, also
        /// Elevates permissions via unsafe native methods, handles messages to 
        /// retrieve automation provider the last one is most risky
        ///  
        [SecurityCritical] 
        internal IntPtr HandleMessage(int msg, IntPtr wparam, IntPtr lparam)
        { 
            IntPtr handled = new IntPtr(0x1); // return 1 if the message is handled by this method exclusively.
            IntPtr unhandled = IntPtr.Zero; // return 0 if other win procs should be called.
            IntPtr result = unhandled;
 
            if (msg == s_dwmRedirectionEnvironmentChanged)
            { 
                System.Windows.Media.MediaSystem.NotifyRedirectionEnvironmentChanged(); 
                return handled;
            } 
            else if (msg == s_channelNotifyMessage)
            {
                MediaContext.From(Dispatcher).NotifyChannelMessage();
            } 
            else if (msg == s_transformHintUpdateMessage)
            { 
                System.Windows.Media.MediaSystem.NotifyTransformHintUpdate((long)wparam); 
                return handled;
            } 
            else if(msg == s_updateWindowSettings)
            {
                // Make sure we enable the render target if the window is visible.
                if(SafeNativeMethods.IsWindowVisible(_hWnd.MakeHandleRef(this))) 
                {
                    UpdateWindowSettings(true); 
                } 
            }
 
            if (IsDisposed)
            {
                return result;
            } 

            switch (msg) 
                { 
                case NativeMethods.WM_ERASEBKGND:
                    result = handled; // Indicates that this message is handled. 
                    break;

                case NativeMethods.WM_PAINT:
                    DoPaint(); 
                    result = handled;
                    break; 
 
                case NativeMethods.WM_SIZE:
                    // 
                    //


 

 
 

 

                    // If the Window is in minimized state, don't do layout. otherwise, in some cases, it would
                    // pollute the measure data based on the Minized window size.
                    if (NativeMethods.IntPtrToInt32(wparam) != NativeMethods.SIZE_MINIMIZED) 
                    {
                        _isMinimized = false; 
                        DoPaint(); 

                        OnResize(); 
                    }
                    else
                    {
                        _isMinimized = true; 
                    }
 
                    break; 

                case NativeMethods.WM_SETTINGCHANGE: 
                    if (OnSettingChange(NativeMethods.IntPtrToInt32(wparam)))
                    {
                        UnsafeNativeMethods.InvalidateRect(_hWnd.MakeHandleRef(this), IntPtr.Zero , true);
                    } 
                    break;
 
                case NativeMethods.WM_GETOBJECT: 
                    result = CriticalHandleWMGetobject( wparam, lparam, RootVisual, _hWnd );
                    break; 

                case NativeMethods.WM_WINDOWPOSCHANGING:
                    OnWindowPosChanging(lparam);
                    break; 

                case NativeMethods.WM_WINDOWPOSCHANGED: 
                    OnWindowPosChanged(lparam); 
                    break;
 
                case NativeMethods.WM_SHOWWINDOW:
                    OnShowWindow(wparam != IntPtr.Zero);
                    break;
 
                case NativeMethods.WM_EXITSIZEMOVE:
                    OnExitSizeMove(); 
                    break; 

                case NativeMethods.WM_STYLECHANGING: 
                    unsafe
                    {
                        NativeMethods.STYLESTRUCT * styleStruct = (NativeMethods.STYLESTRUCT *) lparam;
 
                        if ((int)wparam == NativeMethods.GWL_EXSTYLE)
                        { 
                            if(UsesPerPixelOpacity) 
                            {
                                // We need layered composition to accomplish per-pixel opacity. 
                                //
                                styleStruct->styleNew |= NativeMethods.WS_EX_LAYERED;
                            }
                            else 
                            {
                                // No properties that require layered composition exist. 
                                // Make sure the layered bit is off. 
                                //
                                // Note: this prevents an external program from making 
                                // us system-layered (if we are a top-level window).
                                //
                                // If we are a child window, we still can't stop our
                                // parent from being made system-layered, and we will 
                                // end up leaving visual artifacts on the screen under
                                // WindowsXP. 
                                // 
                                styleStruct->styleNew &= (~NativeMethods.WS_EX_LAYERED);
                            } 
                        }
                    }

                    break; 

                case NativeMethods.WM_STYLECHANGED: 
                    unsafe 
                    {
                        bool updateWindowSettings = false; 

                        NativeMethods.STYLESTRUCT * styleStruct = (NativeMethods.STYLESTRUCT *) lparam;

                        if ((int)wparam == NativeMethods.GWL_STYLE) 
                        {
                            bool oldIsChild = (styleStruct->styleOld & NativeMethods.WS_CHILD) == NativeMethods.WS_CHILD; 
                            bool newIsChild = (styleStruct->styleNew & NativeMethods.WS_CHILD) == NativeMethods.WS_CHILD; 
                            updateWindowSettings = (oldIsChild != newIsChild);
                        } 
                        else
                        {
                            bool oldIsRTL = (styleStruct->styleOld & NativeMethods.WS_EX_LAYOUTRTL) == NativeMethods.WS_EX_LAYOUTRTL;
                            bool newIsRTL  = (styleStruct->styleNew & NativeMethods.WS_EX_LAYOUTRTL) == NativeMethods.WS_EX_LAYOUTRTL; 
                            updateWindowSettings = (oldIsRTL != newIsRTL);
                        } 
 
                        if(updateWindowSettings)
                        { 
                            UpdateWindowSettings();
                        }
                    }
 
                    break;
 
                // 
                //
 



 

 
 

                case NativeMethods.WM_WTSSESSION_CHANGE: 
                    switch (NativeMethods.IntPtrToInt32(wparam))
                    {
                        // Switched to a different user
                        case NativeMethods.WTS_CONSOLE_DISCONNECT: 
                            _isSessionDisconnected = true;
                            break; 
 
                        // Switched back
                        case NativeMethods.WTS_CONSOLE_CONNECT: 
                            _isSessionDisconnected = false;
                            DoPaint();

                            break; 

                        default: 
                            break; 
                    }
 
                    break;

                //
                // 

 
 

                case NativeMethods.WM_POWERBROADCAST: 
                    switch (NativeMethods.IntPtrToInt32(wparam))
                    {
                        case NativeMethods.PBT_APMSUSPEND:
                            _isSuspended = true; 
                            break;
 
                        case NativeMethods.PBT_APMRESUMESUSPEND: 
                        case NativeMethods.PBT_APMRESUMECRITICAL:
                        case NativeMethods.PBT_APMRESUMEAUTOMATIC: 
                            _isSuspended = false;
                            DoPaint();
                            break;
 
                        default:
                            break; 
                    } 
                    break;
 
                default:
                    break;
            }
 
            return result;
        } 
 
        /// 
        /// Paints a rect 
        ///
        /// Note: This gets called a lot to help with layered window problems even when
        ///         the window isn't layered, but that's okay because rcPaint will be empty.
        /// 
        /// 
        ///  
        /// Critical - Elevates permissions via unsafe native methods, calls into begin paint 
        /// 
        [SecurityCritical] 
        private void DoPaint()
        {
            NativeMethods.PAINTSTRUCT ps = new NativeMethods.PAINTSTRUCT();
            NativeMethods.HDC hdc; 

            HandleRef handleRef = new HandleRef(this, _hWnd); 
            hdc.h = UnsafeNativeMethods.BeginPaint(handleRef, ref ps); 
            int retval = UnsafeNativeMethods.GetWindowLong(handleRef, NativeMethods.GWL_EXSTYLE);
 
            NativeMethods.RECT rcPaint = new NativeMethods.RECT(ps.rcPaint_left, ps.rcPaint_top, ps.rcPaint_right, ps.rcPaint_bottom);

            //
            // If we get a BeginPaint with an empty rect then check 
            // if this is a special layered, non-redirected window
            // which would mean we need to do a full paint when it 
            // won't cause a problem. 
            //
            if (rcPaint.IsEmpty 
                && ((retval & NativeMethods.WS_EX_LAYERED) != 0)
                && !UnsafeNativeMethods.GetLayeredWindowAttributes(_hWnd.MakeHandleRef(this), IntPtr.Zero, IntPtr.Zero, IntPtr.Zero)
                && !_isSessionDisconnected
                && !_isMinimized 
                && !_isSuspended)
            { 
                rcPaint = new NativeMethods.RECT( 
                          0,
                          0, 
                          _hwndClientRectInScreenCoords.right - _hwndClientRectInScreenCoords.left,
                          _hwndClientRectInScreenCoords.bottom - _hwndClientRectInScreenCoords.top);
            }
 
            AdjustForRightToLeft(ref rcPaint, handleRef);
 
            if (!rcPaint.IsEmpty) 
            {
                InvalidateRect(rcPaint); 
            }

            UnsafeNativeMethods.EndPaint(_hWnd.MakeHandleRef(this), ref ps);
        } 

        ///  
        /// Critical - 1) This method exposes the automation object which can be used to 
        /// query the system for critical information or spoof input.
        /// 2) it Asserts to call ReturnRawElementProvider 
        /// 
        [SecurityCritical]
        private static IntPtr CriticalHandleWMGetobject(IntPtr wparam, IntPtr lparam, Visual root, IntPtr handle)
        { 
            try
            { 
                if (root == null) 
                {
                    // Valid case, but need to handle separately. For now, return 0 to avoid exceptions 
                    // in referencing this later on. Real solution is more complex, see WindowsClient#873800.
                    return IntPtr.Zero;
                }
 
                AutomationPeer peer = null;
 
                if (root.CheckFlagsAnd(VisualFlags.IsUIElement)) 
                {
                    UIElement uiroot = (UIElement)root; 

                    peer = UIElementAutomationPeer.CreatePeerForElement(uiroot);

                    //there si no specific peer for this UIElement, create a generic root 
                    if(peer == null)
                        peer = uiroot.CreateGenericRootAutomationPeer(); 
 
                    if(peer != null)
                        peer.Hwnd = handle; 
                }

                // This can happen if the root visual is not UIElement. In this case,
                // attempt to find one in the visual tree. 
                if (peer == null)
                { 
                    peer = UIElementAutomationPeer.GetRootAutomationPeer(root, handle); 
                }
 
                if (peer == null)
                {
                    return IntPtr.Zero;
                } 

                // get the element proxy 
                // it's ok to pass the same peer as reference connected peer here because 
                // it's guaranteed to be a connected one (it's initialized as root already)
                IRawElementProviderSimple el = ElementProxy.StaticWrap(peer, peer); 

                peer.AddToAutomationEventList();

                // The assert here is considered OK 
                // as we're assuming the WM_GETOBJECT is coming only from a PostMessage of an Hwnd.
                // to do the post message - you needed to have Unmanaged code permission 
                // 

                PermissionSet unpackPermissionSet = new PermissionSet(PermissionState.None); 
                // below permissions needed to unpack an object.
                unpackPermissionSet.AddPermission(new SecurityPermission(SecurityPermissionFlag.SerializationFormatter | SecurityPermissionFlag.UnmanagedCode | SecurityPermissionFlag.RemotingConfiguration));
                unpackPermissionSet.AddPermission(new System.Net.DnsPermission(PermissionState.Unrestricted));
                unpackPermissionSet.AddPermission(new System.Net.SocketPermission(PermissionState.Unrestricted)); 

                unpackPermissionSet.Assert(); 
                try 
                {
                    return AutomationInteropProvider.ReturnRawElementProvider(handle, wparam, lparam, el); 
                }
                finally
                {
                    CodeAccessPermission.RevertAll(); 
                }
            } 
#pragma warning disable 56500 
            catch (Exception e)
            { 
                if(CriticalExceptions.IsCriticalException(e))
                {
                    throw;
                } 

                return new IntPtr(Marshal.GetHRForException(e)); 
            } 
#pragma warning restore 56500
        } 

        /// 
        ///     Adjusts a RECT to compensate for Win32 RTL conversion logic
        ///  
        /// 
        ///     When a window is marked with the WS_EX_LAYOUTRTL style, Win32 
        ///     mirrors the coordinates during the various translation APIs. 
        ///
        ///     Avalon also sets up mirroring transforms so that we properly 
        ///     mirror the output since we render to DirectX, not a GDI DC.
        ///
        ///     Unfortunately, this means that our coordinates are already mirrored
        ///     by Win32, and Avalon mirrors them again.  To solve this 
        ///     problem, we un-mirror the coordinates from Win32 before painting
        ///     in Avalon. 
        ///  
        /// 
        ///     The RECT to be adjusted 
        /// 
        /// 
        /// 
        internal void AdjustForRightToLeft(ref NativeMethods.RECT rc, HandleRef handleRef) 
        {
            int windowStyle = SafeNativeMethods.GetWindowStyle(handleRef, true); 
 
            if(( windowStyle & NativeMethods.WS_EX_LAYOUTRTL ) == NativeMethods.WS_EX_LAYOUTRTL)
            { 
                NativeMethods.RECT rcClient = new NativeMethods.RECT();
                SafeNativeMethods.GetClientRect(handleRef, ref rcClient);

                int width   = rc.right - rc.left;       // preserve width 
                rc.right    = rcClient.right - rc.left; // set right of rect to be as far from right of window as left of rect was from left of window
                rc.left     = rc.right - width;         // restore width by adjusting left and preserving right 
            } 
        }
 
        /// 
        /// Force total re-rendering to handle system parameters change
        /// (font smoothing settings, gamma correction, etc.)
        /// 
        ///true if rerendering was forced
        ///  
        ///   Critical: This can be used to cause annoyance by causing re rendering 
        /// 
        [SecurityCritical] 
        private bool OnSettingChange(Int32 firstParam)
        {
            if ( (int)firstParam == (int)NativeMethods.SPI_SETFONTSMOOTHING ||
                 (int)firstParam == (int)NativeMethods.SPI_SETFONTSMOOTHINGTYPE || 
                 (int)firstParam == (int)NativeMethods.SPI_SETFONTSMOOTHINGCONTRAST ||
                 (int)firstParam == (int)NativeMethods.SPI_SETFONTSMOOTHINGORIENTATION || 
                 (int)firstParam == (int)NativeMethods.SPI_SETDISPLAYPIXELSTRUCTURE || 
                 (int)firstParam == (int)NativeMethods.SPI_SETDISPLAYGAMMA ||
                 (int)firstParam == (int)NativeMethods.SPI_SETDISPLAYCLEARTYPELEVEL || 
                 (int)firstParam == (int)NativeMethods.SPI_SETDISPLAYTEXTCONTRASTLEVEL
                )
            {
                HRESULT.Check(MILUpdateSystemParametersInfo.Update()); 
                return true;
            } 
 
            return false;
        } 

        /// 
        /// Let the DWM know of this HWND as belonging to a MIL/WPF application.
        /// Force total re-rendering to handle system Desktop Window Manager change 
        /// 
        ///  
        ///   Critical: This can be used to cause annoyance by trying to cause re rendering. 
        /// 
        [SecurityCritical] 
        internal void OnDWMCompositionChanged(bool isDesktopCompositionEnabled)
        {
            //
            // Hint window redirection layer that Avalon content has been attached 
            // to this window. As a result, redirection layer will create necessary
            // resources and manage clip and position for this window in TS and 
            // Accessibility scenarios. 
            //
            // We're going to attempt to attach to DWM every time the desktop composition 
            // state changes to ensure that we properly handle DWM crashing/restarting/etc.
            //
            HRESULT.Check(MilContent_AttachToHwnd(_hWnd));
 
            //
 
 
            HRESULT.Check(MILUpdateSystemParametersInfo.Update());
            UnsafeNativeMethods.InvalidateRect(_hWnd.MakeHandleRef(this), IntPtr.Zero , true); 
        }

        /// 
        /// This function should be called to paint the specified 
        /// region of the window along with any other pending
        /// changes.  While this function is generally called 
        /// in response to a WM_PAINT it is up to the user to 
        /// call BeginPaint and EndPaint or to otherwise validate
        /// the bitmap region. 
        /// 
        /// The rectangle that is dirty.
        private void InvalidateRect(NativeMethods.RECT rcDirty)
        { 
            List channels = MediaContext.From(Dispatcher).GetChannels(this);
 
            foreach (DUCE.ChannelSet channelSet in channels) 
            {
                DUCE.Channel channel = channelSet.Channel; 
                DUCE.Channel outOfBandChannel = channelSet.OutOfBandChannel;

                // handle InvalidateRect requests only if we have uce resources.
                if (_compositionTarget.IsOnChannel(channel)) 
                {
                    // 
                    // Send a message with the invalid region to the compositor. We create a little batch to send this 
                    // out of order.
                    // 
                    DUCE.CompositionTarget.Invalidate(
                        _compositionTarget.GetHandle(outOfBandChannel),
                        ref rcDirty,
                        outOfBandChannel); 
                }
            } 
        } 

        ///  
        /// Calling this function causes us to update state to reflect a
        /// size change of the underlying HWND
        /// 
        /// 
        /// Critical - accesses a critical member (_hwnd)
        /// TreatAsSafe - uses the _hwnd to call a safeNativeMethods. Data is cached - but not considered critical. 
        /// 
        [SecurityCritical, SecurityTreatAsSafe ]
        private void OnResize() 
        {
#if DEBUG
            MediaTrace.HwndTarget.Trace("OnResize");
#endif 

            // handle OnResize requests only if we have uce resources. 
            if (_compositionTarget.IsOnAnyChannel) 
            {
                MediaContext mctx = MediaContext.From(Dispatcher); 

                //
                // Let the render target know that window size has changed.
                // 

                UpdateWindowSettings(); 
 
                //
                // Push client size chnage to the visual target. 
                //
                Rect clientRect = new Rect(
                    0,
                    0, 
                    (float)(Math.Ceiling((double)(_hwndClientRectInScreenCoords.right - _hwndClientRectInScreenCoords.left))),
                    (float)(Math.Ceiling((double)(_hwndClientRectInScreenCoords.bottom - _hwndClientRectInScreenCoords.top)))); 
 
                StateChangedCallback(
                    new object[] { HostStateFlags.ClipBounds, null, clientRect }); 

                mctx.Resize(this);

                // To ensure that the client area and the non-client area resize 
                // together, we need to wait, on resize, for the composition
                // engine to present the resized frame. The call to CompleteRender 
                // blocks until that happens. 

                mctx.CompleteRender(); 
            }
        }

 
        /// 
        /// Calculates the client and window rectangle in screen coordinates. 
        ///  
        ///
        /// Critical - calls critical methods (ClientToScreen) 
        /// TreatAsSafe - no information returned, coordinates stored in member field.
        ///
        [SecurityCritical, SecurityTreatAsSafe]
        private void GetWindowRectsInScreenCoordinates() 
        {
            NativeMethods.RECT rcClient = new NativeMethods.RECT(); 
 
            //
            // Get the window and client rectangles 
            //

            SafeNativeMethods.GetWindowRect(_hWnd.MakeHandleRef(this), ref _hwndWindowRectInScreenCoords);
            SafeNativeMethods.GetClientRect(_hWnd.MakeHandleRef(this), ref rcClient); 

 
            NativeMethods.POINT ptClientTopLeft = new NativeMethods.POINT(rcClient.left, rcClient.top); 
            UnsafeNativeMethods.ClientToScreen(_hWnd.MakeHandleRef(this), ptClientTopLeft);
 
            NativeMethods.POINT ptClientBottomRight = new NativeMethods.POINT(rcClient.right, rcClient.bottom);
            UnsafeNativeMethods.ClientToScreen(_hWnd.MakeHandleRef(this), ptClientBottomRight);

            if(ptClientBottomRight.x >= ptClientTopLeft.x) 
            {
                _hwndClientRectInScreenCoords.left = ptClientTopLeft.x; 
                _hwndClientRectInScreenCoords.right = ptClientBottomRight.x; 
            }
            else 
            {
                // RTL windows will cause the right edge to be on the left...
                _hwndClientRectInScreenCoords.left = ptClientBottomRight.x;
                _hwndClientRectInScreenCoords.right = ptClientTopLeft.x; 
            }
 
            if(ptClientBottomRight.y >= ptClientTopLeft.y) 
            {
                _hwndClientRectInScreenCoords.top = ptClientTopLeft.y; 
                _hwndClientRectInScreenCoords.bottom = ptClientBottomRight.y;
            }
            else
            { 
                // RTL windows will cause the right edge to be on the left...
                // This doesn't affect top/bottom, but the code should be symmetrical. 
                _hwndClientRectInScreenCoords.top = ptClientBottomRight.y; 
                _hwndClientRectInScreenCoords.bottom = ptClientTopLeft.y;
            } 

            //
        }
 
        ///
        /// Critical - accepts an unmanaged pointer to a structure 
        /// 
        [SecurityCritical]
        private void OnWindowPosChanging(IntPtr lParam) 
        {
            _windowPosChanging = true;

            UpdateWindowPos(lParam); 
        }
 
        /// 
        /// Critical - accepts an unmanaged pointer to a structure
        /// 
        [SecurityCritical]
        private void OnWindowPosChanged(IntPtr lParam)
        {
            _windowPosChanging = false; 

            UpdateWindowPos(lParam); 
        } 

        /// 
        /// Critical - accepts an unmanaged pointer to a structure
        ///
        [SecurityCritical]
        private void UpdateWindowPos(IntPtr lParam) 
        {
            // 
            // We need to update the window settings used by the render thread when 
            // 1) The size or position of the render target needs to change
            // 2) The render target needs to be enabled or disabled. 
            //
            // Further, we need to synchronize the render thread during sizing operations.
            // This is because some APIs that the render thread uses (such as
            // UpdateLayeredWindow) have the unintended side-effect of also changing the 
            // window size.  We can't let the render thread and the UI thread fight
            // over setting the window size. 
            // 
            // Generally, Windows sends our window to messages that bracket the size
            // operation: 
            // 1) WM_WINDOWPOSCHANGING
            //    Here we synchronize with the render thread, and ask the render thread
            //    to not render to this window for a while.
            // 2) WM_WINDOWPOSCHANGED 
            //    This is after the window size has actually been changed, so we tell
            //    the render thread that it can render to the window again. 
            // 
            // However, there are complications.  Sometimes Windows will send a
            // WM_WINDOWPOSCHANGING without sending a WM_WINDOWPOSCHANGED.  This happens 
            // when the window size is not really going to change.  Also note that
            // more than just size/position information is provided by these messages.
            // We'll get these messages when nothing but the z-order changes for instance.
            // 

 
            // 
            // The first order of business is to determine if the render target
            // size or position changed.  If so, we need to pass this information to 
            // the render thread.
            //
            NativeMethods.WINDOWPOS windowPos = (NativeMethods.WINDOWPOS)UnsafeNativeMethods.PtrToStructure(lParam, typeof(NativeMethods.WINDOWPOS));
            bool isMove = (windowPos.flags & NativeMethods.SWP_NOMOVE) == 0; 
            bool isSize = (windowPos.flags & NativeMethods.SWP_NOSIZE) == 0;
            bool positionChanged = (isMove || isSize); 
            if (positionChanged) 
            {
                // 
                // We have found that sometimes we get told that the size or position
                // of the window has changed, when it really hasn't.  So we double
                // check here.  This is critical because we won't be given a
                // WM_WINDOWPOSCHANGED unless the size or position really had changed. 
                //
                if (!isMove) 
                { 
                    // This is just to avoid any possible integer overflow problems.
                    windowPos.x = windowPos.y = 0; 
                }
                if (!isSize)
                {
                    // This is just to avoid any possible integer overflow problems. 
                    windowPos.cx = windowPos.cy = 0;
                } 
 
                //
                // WINDOWPOS stores the window coordinates relative to its parent. 
                // If the parent is NULL, then these are already screen coordinates.
                // Otherwise, we need to convert to screen coordinates.
                //
                NativeMethods.RECT windowRectInScreenCoords = new NativeMethods.RECT(windowPos.x, windowPos.y, windowPos.x + windowPos.cx, windowPos.y + windowPos.cy); 
                IntPtr hwndParent = UnsafeNativeMethods.GetParent(new HandleRef(null, windowPos.hwnd));
                if(hwndParent != IntPtr.Zero) 
                { 
                    SafeSecurityHelper.TransformLocalRectToScreen(new HandleRef(null, hwndParent), ref windowRectInScreenCoords);
                } 

                if (!isMove)
                {
                    // We weren't actually moving, so the WINDOWPOS structure 
                    // did not contain valid (x,y) information.  Just use our
                    // old values. 
                    int width = (windowRectInScreenCoords.right - windowRectInScreenCoords.left); 
                    int height = (windowRectInScreenCoords.bottom - windowRectInScreenCoords.top);
                    windowRectInScreenCoords.left = _hwndWindowRectInScreenCoords.left; 
                    windowRectInScreenCoords.right = windowRectInScreenCoords.left + width;
                    windowRectInScreenCoords.top = _hwndWindowRectInScreenCoords.top;
                    windowRectInScreenCoords.bottom = windowRectInScreenCoords.top + height;
                } 

                if (!isSize) 
                { 
                    // We weren't actually sizing, so the WINDOWPOS structure
                    // did not contain valid (cx,cy) information.  Just use our 
                    // old values.
                    int width = (_hwndWindowRectInScreenCoords.right - _hwndWindowRectInScreenCoords.left);
                    int height = (_hwndWindowRectInScreenCoords.bottom - _hwndWindowRectInScreenCoords.top);
 
                    windowRectInScreenCoords.right = windowRectInScreenCoords.left + width;
                    windowRectInScreenCoords.bottom = windowRectInScreenCoords.top + height; 
                } 

                positionChanged = (   _hwndWindowRectInScreenCoords.left != windowRectInScreenCoords.left 
                                   || _hwndWindowRectInScreenCoords.top != windowRectInScreenCoords.top
                                   || _hwndWindowRectInScreenCoords.right != windowRectInScreenCoords.right
                                   || _hwndWindowRectInScreenCoords.bottom != windowRectInScreenCoords.bottom);
            } 

 
            // 
            // The second order of business is to determine whether or not the render
            // target should be enabled.  If we are disabling the render target, then 
            // we need to synchronize with the render thread.  Basically,
            // a WM_WINDOWPOSCHANGED always enables the render target it the window is
            // visible.  And a WM_WINDOWPOSCHANGING will disable the render target
            // unless it is not really a size/move, in which case we will not be sent 
            // a WM_WINDOWPOSCHANGED, so we can't disable the render target.
            // 
            bool enableRenderTarget = SafeNativeMethods.IsWindowVisible(_hWnd.MakeHandleRef(this)); 
            if(enableRenderTarget)
            { 
                if(_windowPosChanging && (positionChanged))
                {
                    enableRenderTarget = false;
                } 
            }
 
 
            if (positionChanged || (enableRenderTarget != _isRenderTargetEnabled))
            { 
                UpdateWindowSettings(enableRenderTarget);
            }
        }
 
        bool _windowPosChanging;
 
        private void OnShowWindow(bool enableRenderTarget) 
        {
            if (enableRenderTarget != _isRenderTargetEnabled) 
            {
                UpdateWindowSettings(enableRenderTarget);
            }
        } 

        private void OnExitSizeMove() 
        { 
            if (_windowPosChanging)
            { 
                _windowPosChanging = false;
                UpdateWindowSettings(true);
            }
        } 

        private void UpdateWindowSettings() 
        { 
            UpdateWindowSettings(_isRenderTargetEnabled, null);
        } 

        private void UpdateWindowSettings(bool enableRenderTarget)
        {
            UpdateWindowSettings(enableRenderTarget, null); 
        }
 
        /// 
        /// Critical - calls critical methods (UpdateWindowSettings)
        /// TreatAsSafe - just updates composition information for this window, 
        ///               does not accept arbitrary input.
        ///
        [SecurityCritical, SecurityTreatAsSafe]
        private void UpdateWindowSettings(bool enableRenderTarget, List channelList) 
        {
            bool sendLayeredSuppression = false; 
 
            MediaContext mctx = MediaContext.From(Dispatcher);
            if (_isRenderTargetEnabled != enableRenderTarget) 
            {
                _isRenderTargetEnabled = enableRenderTarget;

                // Basic idea: the render thread and the UI thread have a 
                // race condition when the UI thread wants to modify
                // HWND data and the render thread is using it.  The render 
                // thread can paint garbage on the screen, and it can also 
                // cause the old data to be set again (ULW issue, hence ULWEx).
                // 
                // So we tell the render thread to stop rendering and then we
                // wait for them to stop when disabling the render target by
                // issuing the UpdateWindowSettings command synchronously on
                // an out-of-band channel. 
            }
 
 
            // if we are disconnected we are done.
            if (!_compositionTarget.IsOnAnyChannel) 
            {
                return;
            }
 
            //
            // Calculate the client rectangle in screen coordinates. 
            // 

            GetWindowRectsInScreenCoordinates(); 

            Int32 style = UnsafeNativeMethods.GetWindowLong(_hWnd.MakeHandleRef(this), NativeMethods.GWL_STYLE);
            Int32 exStyle = UnsafeNativeMethods.GetWindowLong(_hWnd.MakeHandleRef(this), NativeMethods.GWL_EXSTYLE);
 
            bool isLayered = (exStyle & NativeMethods.WS_EX_LAYERED) != 0;
 
            bool isChild = (style & NativeMethods.WS_CHILD) != 0; 
            bool isRTL = (exStyle & NativeMethods.WS_EX_LAYOUTRTL) != 0;
 
            int width = _hwndClientRectInScreenCoords.right - _hwndClientRectInScreenCoords.left;
            int height = _hwndClientRectInScreenCoords.bottom - _hwndClientRectInScreenCoords.top;

            MILTransparencyFlags flags = MILTransparencyFlags.Opaque; 
            // if (!DoubleUtil.AreClose(_opacity, 1.0))
            // { 
            //     flags |= MILTransparencyFlags.ConstantAlpha; 
            // }
 
            // if (_colorKey.HasValue)
            // {
            //     flags |= MILTransparencyFlags.ColorKey;
            // } 

            if (_usesPerPixelOpacity) 
            { 
                flags |= MILTransparencyFlags.PerPixelAlpha;
            } 

            if (!isLayered && flags != MILTransparencyFlags.Opaque)
            {
                // The window is not layered, but it should be -- set the layered flag. 
                UnsafeNativeMethods.SetWindowLong(_hWnd.MakeHandleRef(this), NativeMethods.GWL_EXSTYLE, new IntPtr(exStyle | NativeMethods.WS_EX_LAYERED));
 
                mctx.AddLayeredWindow(this); 

                sendLayeredSuppression = true; 
            }
            else if (isLayered && flags == MILTransparencyFlags.Opaque)
            {
                // The window is layered but should not be -- unset the layered flag. 
                UnsafeNativeMethods.SetWindowLong(_hWnd.MakeHandleRef(this), NativeMethods.GWL_EXSTYLE, new IntPtr(exStyle & ~NativeMethods.WS_EX_LAYERED));
 
                mctx.RemoveLayeredWindow(this); 
            }
            else if(isLayered && flags != MILTransparencyFlags.Opaque && _isRenderTargetEnabled && (width == 0 || height == 0)) 
            {
                // The window is already layered, and it should be.  But we are enabling a window
                // that is has a 0-size dimension.  This may cause us to leave the last sprite
                // on the screen.  The best way to get rid of this is to just make the entire 
                // sprite transparent.
 
                NativeMethods.BLENDFUNCTION blend = new NativeMethods.BLENDFUNCTION(); 
                blend.BlendOp = NativeMethods.AC_SRC_OVER;
                blend.SourceConstantAlpha = 0; // transparent 
                UnsafeNativeMethods.UpdateLayeredWindow(_hWnd.h, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, 0, ref blend, NativeMethods.ULW_ALPHA);
            }
            isLayered = (flags != MILTransparencyFlags.Opaque);
 
            // Every UpdateWindowSettings command that disables the render target is
            // assigned a new cookie.  Every UpdateWindowSettings command that enables 
            // the render target uses the most recent cookie.  This allows the 
            // compositor to ignore UpdateWindowSettings(enable) commands that come
            // out of order due to us disabling out-of-band and enabling in-band. 
            if (!_isRenderTargetEnabled)
            {
                _disableCookie++;
            } 

            // 
            // If no channels are specified, call UpdateWindowSettings on all channels 
            //
            if (channelList == null) 
            {
                channelList = mctx.GetChannels(this);
            }
            else 
            {
                // 
                // Channels are specified - this means we're remarshaling this HWndTarget 
                // onto a new channel. Therefore we may need to update the new layered window
                // channel 
                //
                sendLayeredSuppression = true;
            }
 
            //
            // When enabling the render target, stay in-band.  This allows any 
            // client-side rendering instructions to be included in the same packet. 
            // Otherwise pass in the OutOfBand handle.
            // 
            foreach (DUCE.ChannelSet currentChannelSet in channelList)
            {
                DUCE.Channel channel = currentChannelSet.Channel;
                DUCE.Channel outOfBandChannel = currentChannelSet.OutOfBandChannel; 
                DUCE.CompositionTarget.UpdateWindowSettings(
                    _isRenderTargetEnabled ? _compositionTarget.GetHandle(channel) : _compositionTarget.GetHandle(outOfBandChannel), 
                    _hwndClientRectInScreenCoords, 
                    Colors.Transparent, // _colorKey.GetValueOrDefault(Colors.Black),
                    1.0f, // (float)_opacity, 
                    isLayered ? (_usesPerPixelOpacity ? MILWindowLayerType.ApplicationManagedLayer : MILWindowLayerType.SystemManagedLayer) : MILWindowLayerType.NotLayered,
                    flags,
                    isChild,
                    isRTL, 
                    _isRenderTargetEnabled,
                    _disableCookie, 
                    _isRenderTargetEnabled ? channel : outOfBandChannel); 

                if (sendLayeredSuppression && channel.IsLayeredWindowChannel) 
                {
                    DUCE.CompositionTarget.SuppressLayered(
                        _compositionTarget.GetHandle(channel),
                        true, 
                        channel);
                } 
            } 

            if (_isRenderTargetEnabled) 
            {
                //
                // Re-render the visual tree.
                // 

                mctx.PostRender(); 
            } 
            else
            { 
                // If we disabled the render target, we run the risk of leaving it disabled.
                // One such example is when a window is programatically sized, but then
                // GetMinMaxInfo denies the change.  We do not receive any message that would
                // allow us to re-enable the render targer.  To cover these odd cases, we 
                // post ourselves a message to possible re-enable the render target when
                // we are done with the current message processing. 
                UnsafeNativeMethods.PostMessage(new HandleRef(this, _hWnd), s_updateWindowSettings, IntPtr.Zero, IntPtr.Zero); 
            }
        } 

        /// 
        /// Gets and sets the root Visual of this HwndTarget.
        ///  
        /// 
        ///     Callers must have UIPermission(UIPermissionWindow.AllWindows) to call this API. 
        ///  
        /// 
        ///     Critical: This code accesses HWND which is critical and setting RootVisual 
        ///     is critical
        ///     PublicOK: This code blocks inheritance and public callers via Inheritance (in base class) and link demands
        /// 
        public override Visual RootVisual 
        {
            [SecurityCritical] 
            [UIPermissionAttribute(SecurityAction.LinkDemand, Window = UIPermissionWindow.AllWindows)] 
            set
            { 

                base.RootVisual = value;

                if (value != null) 
                {
                    // UIAutomation listens for the EventObjectUIFragmentCreate WinEvent to 
                    // understand when UI that natively implements UIAutomation comes up 
                    //
 


                    UnsafeNativeMethods.NotifyWinEvent(UnsafeNativeMethods.EventObjectUIFragmentCreate, _hWnd.MakeHandleRef(this), 0, 0);
                } 
            }
        } 
 
        /// 
        /// Returns matrix that can be used to transform coordinates from this 
        /// target to the rendering destination device.
        /// 
        public override Matrix TransformToDevice
        { 
            get
            { 
                VerifyAPIReadOnly(); 
                Matrix m = Matrix.Identity;
                m.Scale(_devicePixelsPerInchX / 96.0, _devicePixelsPerInchY / 96.0); 
                return m;
            }
        }
 
        /// 
        /// Returns matrix that can be used to transform coordinates from 
        /// the rendering destination device to this target. 
        /// 
        public override Matrix TransformFromDevice 
        {
            get
            {
                VerifyAPIReadOnly(); 
                Matrix m = Matrix.Identity;
                m.Scale(96.0 / _devicePixelsPerInchX, 96.0 / _devicePixelsPerInchY); 
                return m; 
            }
        } 

        /// 
        /// This is the color that is drawn before everything else.  If
        /// this color has an alpha component other than 1 it will be ignored. 
        /// 
        public Color BackgroundColor 
        { 
            get
            { 
                VerifyAPIReadOnly();

                return _backgroundColor;
            } 
            set
            { 
                VerifyAPIReadWrite(); 

                if (_backgroundColor != value) 
                {
                    _backgroundColor = value;
                    MediaContext mctx = MediaContext.From(Dispatcher);
 
                    List channels = mctx.GetChannels(this);
                    foreach (DUCE.ChannelSet channelSet in channels) 
                    { 
                        DUCE.Channel channel = channelSet.Channel;
                        if (channel == null) 
                        {
                            // MediaContext is in disconnected state, so we will send
                            // the clear color when CreateUCEResources gets called
                            Debug.Assert(!_compositionTarget.IsOnChannel(channel)); 
                        }
                        else 
                        { 
                            DUCE.CompositionTarget.SetClearColor(
                                _compositionTarget.GetHandle(channel), 
                                _backgroundColor,
                                channel);
                            mctx.PostRender();
                        } 
                    }
                } 
            } 
        }
 
        // /// 
        // ///     Specifies the color to display as transparent.
        // /// 
        // ///  
        // ///     Use null to indicate that no color should be transparent.
        // ///  
        // public Nullable ColorKey 
        // {
        //     get 
        //     {
        //         VerifyAPIReadOnly();
        //
        //         return _colorKey; 
        //     }
        // 
        //     set 
        //     {
        //         VerifyAPIReadWrite(); 
        //
        //         if(_colorKey != value)
        //         {
        //             _colorKey = value; 
        //
        //             UpdateWindowSettings(); 
        //         } 
        //     }
        // } 

        // /// 
        // ///     Specifies the constant opacity to apply to the window.
        // ///  
        // /// 
        // ///     The valid values range from [0..1].  Values outside of this range are clamped. 
        // ///  
        // public double Opacity
        // { 
        //     get
        //     {
        //         VerifyAPIReadOnly();
        // 
        //         return _opacity;
        //     } 
        // 
        //     set
        //     { 
        //         VerifyAPIReadWrite();
        //
        //         if(value < 0.0) value = 0.0;
        //         if(value > 1.0) value = 1.0; 
        //
        //         if(!MS.Internal.DoubleUtil.AreClose(value, _opacity)) 
        //         { 
        //             _opacity = value;
        // 
        //             UpdateWindowSettings();
        //         }
        //     }
        // } 

        ///  
        ///     Specifies whether or not the per-pixel opacity of the window content 
        ///     is respected.
        ///  
        /// 
        ///     By enabling per-pixel opacity, the system will no longer draw the non-client area.
        /// 
        ///  
        /// Critical - accesses critical _hWnd, calls unmanaged code
        /// PublicOK - internal property, hwnd not exposed or modified, WTSRegisterSessionNotification 
        ///            only results in the hwnd getting more messages that we use to enable/disable 
        ///            rendering
        ///  
        public bool UsesPerPixelOpacity
        {
            get
            { 
                VerifyAPIReadOnly();
 
                return _usesPerPixelOpacity; 
            }
 
            [SecurityCritical, SecurityTreatAsSafe]
            internal set
            {
                VerifyAPIReadWrite(); 

                if(_usesPerPixelOpacity != value) 
                { 
                    _usesPerPixelOpacity = value;
 
                    // Register/unregister for Fast User Switching messages only if necessary because
                    // this pinvoke loads wtsapi32.dll
                    if (_usesPerPixelOpacity)
                    { 
                        UnsafeNativeMethods.WTSRegisterSessionNotification(_hWnd, NativeMethods.NOTIFY_FOR_THIS_SESSION);
                    } 
                    else 
                    {
                        UnsafeNativeMethods.WTSUnRegisterSessionNotification(_hWnd); 
                    }

                    UpdateWindowSettings();
                } 
            }
        } 
 
        /// 
        /// Tells a channel to send notifications to a particular target's window. 
        /// 
        /// 
        /// The channel from which we want notifications.
        ///  
        /// 
        /// The target whose window will receive the notifications. 
        ///  
        /// 
        /// Critical        - Calls a critical channel method. 
        /// TreatAsSafe     - We are associated with the window handle that we
        ///                   are passing to the channel, so somebody already
        ///                   decided that it's OK for us to interact with that
        ///                   window. We also registered a window message so 
        ///                   that we can avoid collisions with other messages.
        ///  
        [SecurityCritical, SecurityTreatAsSafe] 
        internal static void SetChannelNotificationWindow(DUCE.Channel channel, HwndTarget target)
        { 
            channel.SetNotificationWindow(target._hWnd, s_channelNotifyMessage);
        }
    }
} 

// 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