Code:
/ DotNET / DotNET / 8.0 / untmp / WIN_WINDOWS / lh_tools_devdiv_wpf / Windows / wcp / Core / System / Windows / InterOp / HwndSource.cs / 4 / HwndSource.cs
//------------------------------------------------------------------------------
// Microsoft Avalon
// Copyright (c) Microsoft Corporation, 2004
//
// File: HwndSource.cs
//-----------------------------------------------------------------------------
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using System.Windows.Threading;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Interop;
using System.Runtime.InteropServices;
using MS.Win32;
using MS.Utility;
using MS.Internal;
using MS.Internal.PresentationCore; // SecurityHelper
using Microsoft.Win32;
using System.Diagnostics;
using System.ComponentModel;
using System;
using System.Security;
using System.Security.Permissions;
using System.IO;
using SR=MS.Internal.PresentationCore.SR;
using SRID=MS.Internal.PresentationCore.SRID;
#pragma warning disable 1634, 1691 // suppressing PreSharp warnings
namespace System.Windows.Interop
{
///
/// The HwndSource class presents content within a Win32 HWND.
///
public class HwndSource : PresentationSource, IDisposable, IWin32Window, IKeyboardInputSink
{
///
/// Critical: This code calls into RegisterWindowMesssage which is critical
/// TreatAsSafe: This is safe to call as no external parameters are taken in
///
[SecurityCritical,SecurityTreatAsSafe]
static HwndSource()
{
_threadSlot = Thread.AllocateDataSlot();
_msgEnableCharMessages = UnsafeNativeMethods.RegisterWindowMessage("HwndSourceEnableCharMessages");
}
///
/// Constructs an instance of the HwndSource class that will always resize to its content size.
///
///
/// The Win32 class styles for this window.
///
///
/// The Win32 styles for this window.
///
///
/// The extended Win32 styles for this window.
///
///
/// The position of the left edge of this window.
///
///
/// The position of the upper edge of this window.
///
///
/// The name of this window.
///
///
/// The Win32 window that should be the parent of this window.
///
///
/// Callers must have UIPermission(UIPermissionWindow.AllWindows) to call this API.
///
///
/// Added a demand - so that this API does not work in InternetZone.
/// Critical: This accesses critical code Initialize
/// PublicOK: This code has a demand which will ensure that it does
/// not work in partial trust without the correct permissions
///
[SecurityCritical]
public HwndSource(
int classStyle,
int style,
int exStyle,
int x,
int y,
string name,
IntPtr parent)
{
SecurityHelper.DemandUIWindowPermission();
HwndSourceParameters param = new HwndSourceParameters(name);
param.WindowClassStyle = classStyle;
param.WindowStyle = style;
param.ExtendedWindowStyle = exStyle;
param.SetPosition(x, y);
param.ParentWindow = parent;
Initialize(param);
}
///
/// Constructs an instance of the HwndSource class. This version requires an
/// explicit width and height be sepecified.
///
///
/// The Win32 class styles for this window.
///
///
/// The Win32 styles for this window.
///
///
/// The extended Win32 styles for this window.
///
///
/// The position of the left edge of this window.
///
///
/// The position of the upper edge of this window.
///
///
/// The width of this window.
///
///
/// The height of this window.
///
///
/// The name of this window.
///
///
/// The Win32 window that should be the parent of this window.
///
///
/// Indicates that HwndSource should include the non-client area
/// of the hwnd when it calls the Layout Manager
///
///
/// Callers must have UIPermission(UIPermissionWindow.AllWindows) to call this API.
///
///
/// Added a demand - so that this API does not work in InternetZone.
/// Critical: This acceses critical code Initialize
/// PublicOK: This code has a demand which will ensure that it does
/// not work in partial trust without the correct permissions
///
[SecurityCritical]
public HwndSource(int classStyle,
int style,
int exStyle,
int x,
int y,
int width,
int height,
string name,
IntPtr parent,
bool adjustSizingForNonClientArea)
{
SecurityHelper.DemandUIWindowPermission();
HwndSourceParameters parameters = new HwndSourceParameters(name, width, height);
parameters.WindowClassStyle = classStyle;
parameters.WindowStyle = style;
parameters.ExtendedWindowStyle = exStyle;
parameters.SetPosition(x, y);
parameters.ParentWindow = parent;
parameters.AdjustSizingForNonClientArea = adjustSizingForNonClientArea;
Initialize(parameters);
}
///
/// Constructs an instance of the HwndSource class. This version requires an
/// explicit width and height be sepecified.
///
///
/// The Win32 class styles for this window.
///
///
/// The Win32 styles for this window.
///
///
/// The extended Win32 styles for this window.
///
///
/// The position of the left edge of this window.
///
///
/// The position of the upper edge of this window.
///
///
/// The width of this window.
///
///
/// The height of this window.
///
///
/// The name of this window.
///
///
/// The Win32 window that should be the parent of this window.
///
///
/// Callers must have UIPermission(UIPermissionWindow.AllWindows) to call this API.
///
///
/// Added a demand - so that this API does not work in InternetZone.
/// Critical: This accesses critical code Initialize
/// PublicOK: This code has a demand which will ensure that it does
/// not work in partial trust without the correct permissions
///
[SecurityCritical]
public HwndSource(
int classStyle,
int style,
int exStyle,
int x,
int y,
int width,
int height,
string name,
IntPtr parent)
{
SecurityHelper.DemandUIWindowPermission();
HwndSourceParameters parameters = new HwndSourceParameters(name, width, height);
parameters.WindowClassStyle = classStyle;
parameters.WindowStyle = style;
parameters.ExtendedWindowStyle = exStyle;
parameters.SetPosition(x, y);
parameters.ParentWindow = parent;
Initialize(parameters);
}
///
/// HwndSource Ctor
///
/// parameter block
///
/// Callers must have UIPermission(UIPermissionWindow.AllWindows) to call this API.
///
///
/// Critical: This acceses critical code Initialize
///
[SecurityCritical]
[UIPermissionAttribute(SecurityAction.LinkDemand, Window = UIPermissionWindow.AllWindows)]
public HwndSource(HwndSourceParameters parameters)
{
Initialize(parameters);
}
///
/// HwndSource Ctor
///
/// parameter block
///
/// Critical: This code access critical (HwndMouseInputProvider, HwndKeyboardInputProvider
/// ,HwndStylusInputProvider and the various hooks)objects and creates the
/// providers under elevation.
///
[SecurityCritical]
private void Initialize(HwndSourceParameters parameters)
{
_mouse = new SecurityCriticalDataClass(new HwndMouseInputProvider(this));
_keyboard = new SecurityCriticalDataClass(new HwndKeyboardInputProvider(this));
_layoutHook = new HwndWrapperHook(LayoutFilterMessage);
_inputHook = new HwndWrapperHook(InputFilterMessage);
_hwndTargetHook = new HwndWrapperHook(HwndTargetFilterMessage);
_publicHook = new HwndWrapperHook(PublicHooksFilterMessage);
// When processing WM_SIZE, LayoutFilterMessage must be invoked before
// HwndTargetFilterMessage. This way layout will be updated before resizing
// HwndTarget, resulting in single render per resize. This means that
// layout hook should appear before HwndTarget hook in the wrapper hooks
// list. If this is done the other way around, first HwndTarget resize will
// force re-render, then layout will be updated according to the new size,
// scheduling another render.
HwndWrapperHook[] wrapperHooks = { _hwndTargetHook, _layoutHook, _inputHook, null };
if(null != parameters.HwndSourceHook)
{
_hooks = new ArrayList(8);
_hooks.Insert(0, parameters.HwndSourceHook);
wrapperHooks[3] = _publicHook;
}
// A window must be marked WS_EX_LAYERED if (and only if):
// 1) it is not a child window
// -- AND --
// 2) a color-key is specified
// 3) or an opacity other than 1.0 is specified
// 4) or per-pixel alpha is requested.
if((parameters.WindowStyle & NativeMethods.WS_CHILD) == 0 &&
( //parameters.ColorKey != null ||
//!MS.Internal.DoubleUtil.AreClose(parameters.Opacity, 1.0) ||
parameters.UsesPerPixelOpacity))
{
parameters.ExtendedWindowStyle |= NativeMethods.WS_EX_LAYERED;
}
else
{
parameters.ExtendedWindowStyle &= (~NativeMethods.WS_EX_LAYERED);
}
_constructionParameters = parameters;
_hwndWrapper = new HwndWrapper(parameters.WindowClassStyle,
parameters.WindowStyle,
parameters.ExtendedWindowStyle,
parameters.PositionX,
parameters.PositionY,
parameters.Width,
parameters.Height,
parameters.WindowName,
parameters.ParentWindow,
wrapperHooks);
_hwndTarget = new HwndTarget(_hwndWrapper.Handle);
//_hwndTarget.ColorKey = parameters.ColorKey;
//_hwndTarget.Opacity = parameters.Opacity;
_hwndTarget.UsesPerPixelOpacity = parameters.UsesPerPixelOpacity;
if(_hwndTarget.UsesPerPixelOpacity)
{
_hwndTarget.BackgroundColor = Colors.Transparent;
// Prevent this window from being themed.
UnsafeNativeMethods.CriticalSetWindowTheme(new HandleRef(this, _hwndWrapper.Handle), "", "");
}
_constructionParameters = null;
if (!parameters.HasAssignedSize)
_sizeToContent = SizeToContent.WidthAndHeight;
_adjustSizingForNonClientArea = parameters.AdjustSizingForNonClientArea;
// Listen to the UIContext.Disposed event so we can clean up.
// The HwndTarget cannot work without a MediaContext which
// is disposed when the UIContext is disposed. So we need to
// dispose the HwndTarget and also never use it again (to
// paint or process input). The easiest way to do this is to just
// dispose the HwndSource at the same time.
_weakShutdownHandler = new WeakEventDispatcherShutdown(this, this.Dispatcher);
// Listen to the HwndWrapper.Disposed event so we can clean up.
// The HwndTarget cannot work without a live HWND, and since
// the HwndSource represents an HWND, we make sure we dispose
// ourselves if the HWND is destroyed out from underneath us.
_hwndWrapper.Disposed += new EventHandler(OnHwndDisposed);
_stylus = new SecurityCriticalDataClass(new HwndStylusInputProvider(this));
// WM_APPCOMMAND events are handled thru this.
_appCommand = new SecurityCriticalDataClass(new HwndAppCommandInputProvider(this));
// Register the top level source with the ComponentDispatcher.
if (0 == ((uint)parameters.WindowStyle & NativeMethods.WS_CHILD))
{
// This code path only gets executed in the non browser hosted case
// because in the browser hosted case the app window is child window
_weakPreprocessMessageHandler = new WeakEventPreprocessMessage(this);
}
AddSource();
// Register dropable window.
// The checking CallerHasPermissionWithAppDomainOptimization will call RegisterDropTarget
// safely without the security exception in case of no unmanaged code permission.
// So RegisterDropTarget will be called safely in case of having the unmanged code permission.
// Otherwise, the security exception cause System.Printing to be instatiated which will
// load system.drawing module.
if (_hwndWrapper.Handle != IntPtr.Zero &&
SecurityHelper.CallerHasPermissionWithAppDomainOptimization(new SecurityPermission(SecurityPermissionFlag.UnmanagedCode)))
{
// This call is safe since DragDrop.RegisterDropTarget is checking the unmanged
// code permission.
DragDrop.RegisterDropTarget(_hwndWrapper.Handle);
_registeredDropTargetCount++;
}
}
///
/// Disposes the object
///
///
/// This API is not available in Internet Zone.
///
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
///
/// Adds a hook that gets called for every window message.
///
///
/// The hook to add.
///
///
/// Callers must have UIPermission(UIPermissionWindow.AllWindows) to call this API.
///
///
/// Critical - uses a critical field.
/// PublicOK - as there's a demand.
///
[SecurityCritical ]
public void AddHook(HwndSourceHook hook)
{
SecurityHelper.DemandUIWindowPermission();
CheckDisposed(true);
if(_hooks == null)
{
_hooks = new ArrayList(8);
_hwndWrapper.AddHook(_publicHook);
}
_hooks.Insert(0, hook);
}
///
/// Removes a hook that was previously added.
///
///
/// The hook to remove.
///
///
/// Callers must have UIPermission(UIPermissionWindow.AllWindows) to call this API.
///
///
/// Critical - accesses a crtical field - _publicHook
/// PublicOK - performs a demand.
///
[SecurityCritical ]
public void RemoveHook(HwndSourceHook hook)
{
SecurityHelper.DemandUIWindowPermission();
//this.VerifyAccess();
if(_hooks != null)
{
_hooks.Remove(hook);
if(_hooks.Count == 0)
{
_hooks = null;
_hwndWrapper.RemoveHook(_publicHook);
}
}
}
///
/// GetInputProvider - Given a InputDevice, returns corresponding Provider
///
/// InputDevice for which we need InputProvider
/// InputProvider, if known
///
/// This API is not available in Internet Zone.
///
///
/// Critical: This code accesses and returns critical data *providers*
///
[SecurityCritical]
internal override IInputProvider GetInputProvider(Type inputDevice)
{
if (inputDevice == typeof(MouseDevice))
return (_mouse != null ? _mouse.Value : null);
if (inputDevice == typeof(KeyboardDevice))
return (_keyboard != null ? _keyboard.Value : null);
if (inputDevice == typeof(StylusDevice))
return (_stylus != null ? _stylus.Value : null);
return null;
}
///
/// Announces when this source is disposed.
///
public event EventHandler Disposed;
///
/// Announces when the SizeToContent property changes on this source.
///
public event EventHandler SizeToContentChanged;
///
/// Whether or not the object is disposed.
///
public override bool IsDisposed {get {return _isDisposed;}}
///
/// The Root Visual for this window. If it is a UIElement
///
///
/// Callers must have UIPermission(UIPermissionWindow.AllWindows) to call this API.
///
///
/// Critical: This code sets a rootvisual which is risky to do because
/// it can destabilize assumptions made in popup code
/// PublicOK: The getter is safe and the setter has a link demand to block unwarrented
/// public use
///
public override Visual RootVisual
{
[SecurityCritical]
get
{
if (_isDisposed)
return null;
return (_rootVisual.Value);
}
[SecurityCritical]
[UIPermissionAttribute(SecurityAction.LinkDemand,Window=UIPermissionWindow.AllWindows)]
set
{
CheckDisposed(true);
RootVisualInternal = value;
}
}
///
/// Critical: Acceses KeyboardInputProvider which is considered as critical data
/// also it can be used to set root visual which is deemed as an unsafe operation
///
private Visual RootVisualInternal
{
[SecurityCritical]
set
{
if (_rootVisual.Value != value)
{
Visual oldRoot = _rootVisual.Value;
if(value != null)
{
_rootVisual.Value = value;
if(_rootVisual.Value is UIElement)
{
((UIElement)(_rootVisual.Value)).LayoutUpdated += new EventHandler(OnLayoutUpdated);
}
if (_hwndTarget != null && _hwndTarget.IsDisposed == false)
{
_hwndTarget.RootVisual = _rootVisual.Value;
}
UIElement.PropagateResumeLayout(null, value);
}
else
{
_rootVisual.Value = null;
if (_hwndTarget != null && !_hwndTarget.IsDisposed)
{
_hwndTarget.RootVisual = null;
}
}
if(oldRoot != null)
{
if(oldRoot is UIElement)
{
((UIElement)oldRoot).LayoutUpdated -= new EventHandler(OnLayoutUpdated);
}
UIElement.PropagateSuspendLayout(oldRoot);
}
RootChanged(oldRoot, _rootVisual.Value);
if (IsLayoutActive() == true)
{
// Call the helper method SetLayoutSize to set Layout's size
SetLayoutSize();
// Post the firing of ContentRendered as Input priority work item so that ContentRendered will be
// fired after render query empties.
this.Dispatcher.BeginInvoke(DispatcherPriority.Loaded, new DispatcherOperationCallback(FireContentRendered), this);
}
else
{
// Even though layout won't run (the root visual is either null or not
// a UIElement), the hit-test results will certainly have changed.
InputManager.SafeCurrentNotifyHitTestInvalidated();
}
// It is possible that someone would have closed the window in one of the
// previous callouts - such as during RootChanged or during the layout
// we syncronously invoke. In such cases, the state of this object would
// have been torn down. We just need to protect against that.
if(_keyboard != null)
{
_keyboard.Value.OnRootChanged(oldRoot, _rootVisual.Value);
}
}
}
}
///
/// Returns the HwndSource that corresponds to the specified window.
///
/// The window.
/// The source that corresponds to the specified window.
///
/// Callers must have UIPermission(UIPermissionWindow.AllWindows) to call this API.
///
///
/// Critical: This information is not ok to expose since this HwndSource
/// is deemed critical to expose
/// PublicOK: There is a demand on this method that prevents this
/// from working in partial trust unless you have the right permissions.
///
[SecurityCritical]
public static HwndSource FromHwnd(IntPtr hwnd)
{
SecurityHelper.DemandUIWindowPermission();
return CriticalFromHwnd(hwnd);
}
///
/// Critical: This code extracts the HwndSource for an HWND
/// This function is only for internal consumption
///
[SecurityCritical]
internal static HwndSource CriticalFromHwnd(IntPtr hwnd)
{
if (hwnd == IntPtr.Zero)
{
throw new ArgumentException(SR.Get(SRID.NullHwnd));
}
HwndSource hwndSource = null;
foreach (PresentationSource source in PresentationSource.CriticalCurrentSources)
{
HwndSource test = source as HwndSource;
if (test != null && test.CriticalHandle == hwnd)
{
// Don't hand out a disposed source.
if (!test.IsDisposed)
hwndSource = test;
break;
}
}
return hwndSource;
}
///
/// The visual manager for the visuals being presented in the source.
/// Type-specific version of the CompositionTarget property for this source.
///
///
/// Critical: Accesses hwndTarget and returns it
/// PublicOk: Protected by a LinkDemand
///
public new HwndTarget CompositionTarget
{
[SecurityCritical]
[UIPermissionAttribute(SecurityAction.LinkDemand,Window=UIPermissionWindow.AllWindows)]
get
{
if (_isDisposed)
return null;
// Even though we created the HwndTarget, it can get disposed out from
// underneath us.
if (_hwndTarget!= null && _hwndTarget.IsDisposed == true)
{
return null;
}
return _hwndTarget;
}
}
///
/// Returns visual target for this source.
///
///
/// Critical: calls get_CompositionTarget() and returns its value.
///
[SecurityCritical]
protected override CompositionTarget GetCompositionTargetCore()
{
return CompositionTarget;
}
///
/// Event invoked when the layout causes the HwndSource to resize automatically.
///
public event AutoResizedEventHandler AutoResized;
///
/// Handler for LayoutUpdated event of a rootVisual.
///
///
/// Critical: This code causes resize of window and accesses HwndTarget
///
[SecurityCritical]
private void OnLayoutUpdated(object obj, EventArgs args)
{
UIElement root = _rootVisual.Value as UIElement;
if(root != null)
{
Size newSize = root.RenderSize;
if ( _previousSize == null
|| !DoubleUtil.AreClose(_previousSize.Value.Width, newSize.Width)
|| !DoubleUtil.AreClose(_previousSize.Value.Height, newSize.Height))
{
// We should update _previousSize, even if the hwnd is not
// sizing to content. This fixes the scenario where:
//
// 1) hwnd is sized to content to say a, b
// 2) hwnd is resize to a bigger size
// 3) hwnd is sized to content to a, b again
_previousSize = newSize;
//
// Don't resize while the Window is in Minimized mode.
//
if (_sizeToContent != SizeToContent.Manual && !_isWindowInMinimizeState )
{
Resize(newSize);
}
}
}
}
///
/// This is called when LayoutManager was updated and its size (the layout size of top element) changed.
/// Ask LayoutManager.Size to see what the new value is.
///
///
/// Critical: This code causes resize of window and accesses HwndTarget
/// TreatAsSafe: In RBW the resize values are clamped also one cannot construct or get to a HwndSource in partial trust
///
[SecurityCritical, SecurityTreatAsSafe]
private void Resize(Size newSize)
{
try
{
_myOwnUpdate = true;
if (IsUsable)
{
// Gather the new client dimensions
Point convertedPt = _hwndTarget.TransformToDevice.Transform(new Point(newSize.Width, newSize.Height));
int frameWidth = 0;
int frameHeight = 0;
// If we're here, and it is the Window case (_adjustSizingForNonClientArea == true)
// we get the size which includes the outside size of the window. For browser case,
// we don't support SizeToContent, so we don't take care of this condition.
// For non-Window cases, we need to calculate the outside size of the window
//
// For windows with UsesPerPixelOpacity, we force the client to
// fill the window, so we don't need to add in any frame space.
//
if (_adjustSizingForNonClientArea == false && !UsesPerPixelOpacity)
{
// Gather current client and frame dimensions from the window
NativeMethods.RECT oldClientRect = new NativeMethods.RECT(0, 0, 0, 0);
SafeNativeMethods.GetClientRect(new HandleRef(this,_hwndWrapper.Handle), ref oldClientRect);
NativeMethods.RECT oldFrameRect = new NativeMethods.RECT(0, 0, 0, 0);
SafeNativeMethods.GetWindowRect(new HandleRef(this,_hwndWrapper.Handle), ref oldFrameRect);
frameWidth = (oldFrameRect.right - oldFrameRect.left) - (oldClientRect.right - oldClientRect.left) ;
frameHeight = (oldFrameRect.bottom - oldFrameRect.top) - (oldClientRect.bottom - oldClientRect.top);
}
// Add the difference between the client and frame dimensions (i.e. the window chrome) to the new client dimensions
RoundDeviceSize(ref convertedPt);
int newWidth = frameWidth + (int)convertedPt.X;
int newHeight = frameHeight + (int)convertedPt.Y;
// Set the new frame size
bool set = UnsafeNativeMethods.SetWindowPos(new HandleRef(this,_hwndWrapper.Handle), new HandleRef(null,IntPtr.Zero), 0, 0, newWidth, newHeight, NativeMethods.SWP_NOMOVE | NativeMethods.SWP_NOZORDER | NativeMethods.SWP_NOACTIVATE);
if (AutoResized != null)
{
AutoResized(this, new AutoResizedEventArgs(newSize));
}
}
}
finally
{
_myOwnUpdate = false;
}
}
// If the root element has Pixel snapping enabled, round the window size to the
// nearest int. Otherwise round the size up to the next int.
private void RoundDeviceSize(ref Point size)
{
UIElement root = _rootVisual.Value as UIElement;
if (root != null && root.SnapsToDevicePixels)
{
size = new Point(DoubleUtil.DoubleToInt(size.X), DoubleUtil.DoubleToInt(size.Y));
}
else
{
size = new Point(Math.Ceiling(size.X), Math.Ceiling(size.Y));
}
}
///
/// Returns the hwnd handle to the window.
///
///
/// Callers must have UIPermission(UIPermissionWindow.AllWindows) to call this API.
///
///
/// Critical:This is not safe to expose in internet zone, it returns a window handle
/// PublicOK: There exists a demand on this code
///
public IntPtr Handle
{
[SecurityCritical]
get
{
SecurityHelper.DemandUIWindowPermission();
return CriticalHandle;
}
}
///
/// Critical:Internal helper to retrieve handle for security purposes only Please
/// DO NOT USE THIS TO EXPOSE HANDLE TO OUTSIDE WORLD
///
internal IntPtr CriticalHandle
{
[FriendAccessAllowed]
[SecurityCritical]
get
{
if (null != _hwndWrapper)
return _hwndWrapper.Handle;
return IntPtr.Zero;
}
}
///
/// Critical: returns the critical _hwndWrapper.
///
internal HwndWrapper HwndWrapper
{
[SecurityCritical]
get { return _hwndWrapper; }
}
// Return whether this presentation source has capture.
///
/// Critical: calls CriticalHandle
/// TreatAsSafe: Returning whether a presentation source has capture is considered safe.
///
internal bool HasCapture
{
[SecurityCritical, SecurityTreatAsSafe]
get
{
IntPtr capture = SafeNativeMethods.GetCapture();
return ( capture == CriticalHandle );
}
}
///
/// Critical - accesses _hwndWrapper.
/// TreatAsSafe - checking for null is considered safe.
///
internal bool IsHandleNull
{
[SecurityCritical, SecurityTreatAsSafe ]
get
{
return _hwndWrapper.Handle == IntPtr.Zero ;
}
}
///
/// Returns the hwnd handle to the window.
///
public HandleRef CreateHandleRef()
{
return new HandleRef(this,Handle);
}
///
/// SizeToContent on HwndSource
///
///
/// The default value is SizeToContent.Manual
///
public SizeToContent SizeToContent
{
get
{
CheckDisposed(true);
return _sizeToContent;
}
set
{
CheckDisposed(true);
if (IsValidSizeToContent(value) != true)
{
throw new InvalidEnumArgumentException("value", (int)value, typeof(SizeToContent));
}
if (_sizeToContent == value)
{
return;
}
_sizeToContent = value;
// we only raise SizeToContentChanged when user interaction caused the change;
// if a developer goes directly to HwndSource and sets SizeToContent, we will
// not notify the wrapping Window
if (IsLayoutActive() == true)
{
// Call the helper method SetLayoutSize to set Layout's size
SetLayoutSize();
}
}
}
///
/// Critical: This code elevates to access hwndtarget
/// TreatAsSafe: ok to expose
///
[SecurityCritical,SecurityTreatAsSafe]
private bool IsLayoutActive()
{
if ((_rootVisual.Value is UIElement) && _hwndTarget!= null && _hwndTarget.IsDisposed == false)
{
return true;
}
return false;
}
///
/// This is the helper method that sets Layout's size basing it on
/// the current value of SizeToContent.
///
///
/// TreatAsSafe: This API could be public in terms of security.
/// It does three calls to UnsafeNativeMethods all in a safe way
/// Critical: Makes 3 calls to UnsafeNativeMethods
///
[SecurityCritical, SecurityTreatAsSafe]
private void SetLayoutSize()
{
Debug.Assert(_hwndTarget!= null, "HwndTarget is null");
Debug.Assert(_hwndTarget.IsDisposed == false, "HwndTarget is disposed");
UIElement rootUIElement = null;
rootUIElement = _rootVisual.Value as UIElement;
if (rootUIElement == null) return;
// [....] - 11/01/2005
// InvalidateMeasure() call is necessary in the following scenario
//
// Window w = new Window();
// w.Measure(new Size(x,y));
// w.Width = x;
// w.Height = y;
// w.Show()
//
// In the above scenario, the Measure call from SetLayoutSize will be opt out
// and window will not receive the MeasureOverride call. As such, the hwnd min/max
// restrictions will not be applied since MeasureOverride did not happen after hwnd
// creation. Thus, we call InvalidatMeasure() to ensure MeasureOverride call on
// Window after hwnd creation.
rootUIElement.InvalidateMeasure();
bool etwEnabled = EventTrace.IsEnabled(EventTrace.Flags.performance, EventTrace.Level.normal);
int ctxHashCode = 0;
if (_sizeToContent == SizeToContent.WidthAndHeight)
{
//setup constraints for measure-to-content
Size sz = new Size(double.PositiveInfinity, double.PositiveInfinity);
if (etwEnabled)
{
ctxHashCode = this.Dispatcher.GetHashCode();
EventTrace.EventProvider.TraceEvent(EventTrace.GuidFromId(EventTraceGuidId.LAYOUTPASSGUID), MS.Utility.EventType.StartEvent, ctxHashCode);
EventTrace.EventProvider.TraceEvent(EventTrace.GuidFromId(EventTraceGuidId.MEASUREGUID), MS.Utility.EventType.StartEvent, ctxHashCode);
}
rootUIElement.Measure(sz);
if (etwEnabled)
{
EventTrace.EventProvider.TraceEvent(EventTrace.GuidFromId(EventTraceGuidId.MEASUREGUID), MS.Utility.EventType.EndEvent);
EventTrace.EventProvider.TraceEvent(EventTrace.GuidFromId(EventTraceGuidId.ARRANGEGUID), MS.Utility.EventType.StartEvent, ctxHashCode);
}
rootUIElement.Arrange(new Rect(new Point(), rootUIElement.DesiredSize));
if (etwEnabled)
{
EventTrace.EventProvider.TraceEvent(EventTrace.GuidFromId(EventTraceGuidId.ARRANGEGUID), MS.Utility.EventType.EndEvent);
EventTrace.EventProvider.TraceEvent(EventTrace.GuidFromId(EventTraceGuidId.LAYOUTPASSGUID), MS.Utility.EventType.EndEvent);
}
}
else
{
// GetSizeFromHwnd sets either the outside size or the client size of the hwnd based on
// _adjustSizeingForNonClientArea flag in logical units.
Size sizeFromHwndLogicalUnits = GetSizeFromHwnd();
Size sz = new Size(
(_sizeToContent == SizeToContent.Width ? double.PositiveInfinity : sizeFromHwndLogicalUnits.Width),
(_sizeToContent == SizeToContent.Height ? double.PositiveInfinity : sizeFromHwndLogicalUnits.Height));
if (etwEnabled)
{
ctxHashCode = this.Dispatcher.GetHashCode();
EventTrace.EventProvider.TraceEvent(EventTrace.GuidFromId(EventTraceGuidId.LAYOUTPASSGUID), MS.Utility.EventType.StartEvent, ctxHashCode);
EventTrace.EventProvider.TraceEvent(EventTrace.GuidFromId(EventTraceGuidId.MEASUREGUID), MS.Utility.EventType.StartEvent, ctxHashCode);
}
rootUIElement.Measure(sz);
if (etwEnabled)
{
EventTrace.EventProvider.TraceEvent(EventTrace.GuidFromId(EventTraceGuidId.MEASUREGUID), MS.Utility.EventType.EndEvent);
EventTrace.EventProvider.TraceEvent(EventTrace.GuidFromId(EventTraceGuidId.ARRANGEGUID), MS.Utility.EventType.StartEvent, ctxHashCode);
}
if (_sizeToContent == SizeToContent.Width) sz = new Size(rootUIElement.DesiredSize.Width, sizeFromHwndLogicalUnits.Height);
else if(_sizeToContent == SizeToContent.Height) sz = new Size(sizeFromHwndLogicalUnits.Width, rootUIElement.DesiredSize.Height);
else sz = sizeFromHwndLogicalUnits;
rootUIElement.Arrange(new Rect(new Point(), sz));
if (etwEnabled)
{
EventTrace.EventProvider.TraceEvent(EventTrace.GuidFromId(EventTraceGuidId.ARRANGEGUID), MS.Utility.EventType.EndEvent);
EventTrace.EventProvider.TraceEvent(EventTrace.GuidFromId(EventTraceGuidId.LAYOUTPASSGUID), MS.Utility.EventType.EndEvent);
}
}
rootUIElement.UpdateLayout();
}
// ///
// /// Specifies the color to display as transparent.
// ///
// ///
// /// Use null to indicate that no color should be transparent.
// ///
// public Nullable ColorKey
// {
// get
// {
// CheckDisposed(true);
//
// HwndTarget hwndTarget = CompositionTarget; // checks for disposed
// if(_hwndTarget != null)
// {
// return _hwndTarget.ColorKey;
// }
// else
// {
// return null;
// }
// }
//
// set
// {
// CheckDisposed(true);
//
// HwndTarget hwndTarget = CompositionTarget; // checks for disposed
// if(_hwndTarget != null)
// {
// _hwndTarget.ColorKey = value;
// }
// }
// }
// ///
// /// 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
// {
// CheckDisposed(true);
//
// HwndTarget hwndTarget = CompositionTarget; // checks for disposed
// if(_hwndTarget != null)
// {
// return _hwndTarget.Opacity;
// }
// else
// {
// return 1.0;
// }
// }
//
// set
// {
// CheckDisposed(true);
//
// HwndTarget hwndTarget = CompositionTarget; // checks for disposed
// if(_hwndTarget != null)
// {
// _hwndTarget.Opacity = value;
// }
// }
// }
///
/// 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: Because it accesses _hwndTarget
/// PublicOK: We don't pass it out; it is just used to query UsesPerPixelOpacity
///
public bool UsesPerPixelOpacity
{
[SecurityCritical]
get
{
CheckDisposed(true);
HwndTarget hwndTarget = CompositionTarget; // checks for disposed
if(_hwndTarget != null)
{
return _hwndTarget.UsesPerPixelOpacity;
}
else
{
return false;
}
}
/* Not allowing this to change at run-time yet.
[SecurityCritical]
set
{
CheckDisposed(true);
HwndTarget hwndTarget = CompositionTarget; // checks for disposed
if(_hwndTarget != null)
{
_hwndTarget.UsesPerPixelOpacity = value;
}
}
*/
}
///
/// Critical: Because it accesses _hwndTarget
/// TreatAsSafe: We don't pass it out; it is just used to convert to logical units
///
[SecurityCritical, SecurityTreatAsSafe]
private Size GetSizeFromHwnd()
{
// Compute View's size and set
NativeMethods.RECT rc = new NativeMethods.RECT(0, 0, 0, 0);
if (_adjustSizingForNonClientArea == true)
{
// get correct size for avalon Window (standalone and browser case)
GetSizeForWindowObject(ref rc);
}
else
{
SafeNativeMethods.GetClientRect(new HandleRef(this,_hwndWrapper.Handle), ref rc);
}
Point convertedPt = _hwndTarget.TransformFromDevice.Transform(new Point(rc.right - rc.left, rc.bottom - rc.top));
return new Size(convertedPt.X, convertedPt.Y);
}
///
/// Critical: This code can be used to spoof input
///
[SecurityCritical]
private IntPtr HwndTargetFilterMessage(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
IntPtr result = IntPtr.Zero ;
if (IsUsable)
{
HwndTarget hwndTarget = _hwndTarget;
if (hwndTarget != null)
{
result = hwndTarget.HandleMessage(msg, wParam, lParam);
if (result != IntPtr.Zero)
{
handled = true;
}
}
}
return result;
}
///
/// Critical:These hooks can all be used for input spoofing
///
[SecurityCritical]
private IntPtr LayoutFilterMessage(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
IntPtr result = IntPtr.Zero ;
// We have to revalidate everything because the Access() call
// could have caused the CLR to enter a nested message pump,
// during which almost anything could have happened that might
// invalidate our checks.
UIElement rootUIElement=null;
rootUIElement = _rootVisual.Value as UIElement;
if (IsUsable && rootUIElement != null)
{
switch (msg)
{
// A window receives this message when the user chooses a command from
// the Window menu or when the user chooses the maximize button, minimize
// button, restore button, or close button.
case NativeMethods.WM_SYSCOMMAND:
{
// The four low-order bits of the wParam parameter are used
// internally by the system.
Int32 sysCommand = NativeMethods.IntPtrToInt32(wParam) & 0xFFF0;
// Turn off SizeToContent if user chooses to maximize or resize.
if ((sysCommand == NativeMethods.SC_MAXIMIZE) ||
(sysCommand == NativeMethods.SC_SIZE))
{
DisableSizeToContent(rootUIElement, hwnd);
}
}
break;
// We get WM_SIZING. It means that user starts resizing the window.
// It is the first notification sent when user resizes (before WM_WINDOWPOSCHANGING)
// and it's not sent if window is resized programmatically.
// SizeToContent is turned off after user resizes.
case NativeMethods.WM_SIZING:
DisableSizeToContent(rootUIElement, hwnd);
break;
// The WM_WINDOWPOSCHANGING message is sent
// 1. when the size, position, or place in the Z order is about to change as a result of a call to
// the SetWindowPos function or other window-management functions. SizeToContent orverrides all in this case.
// 2. when user resizes window. If it's user resize, we have turned SizeToContent off when we get WM_SIZING.
// It is sent before WM_SIZE.
// We can't use WM_GETMINMAXINFO, because if there is no window size change (we still need to make sure
// the client size not change), that notification wouldnt be sent.
case NativeMethods.WM_WINDOWPOSCHANGING:
Process_WM_WINDOWPOSCHANGING(rootUIElement, hwnd, msg, wParam, lParam);
break;
// WM_SIZE message is sent after the size has changed.
// lParam has the new width and height of client area.
// root element's size should be adjust based on the new width and height and SizeToContent's value.
case NativeMethods.WM_SIZE:
Process_WM_SIZE(rootUIElement, hwnd, msg, wParam, lParam);
break;
}
}
// Certain messages need to be processed while we are in the middle
// of construction - and thus an HwndTarget is not available.
if(!handled && (_constructionParameters != null || IsUsable))
{
// Get the usesPerPixelOpacity from either the constructor parameters or the HwndTarget.
bool usesPerPixelOpacity = _constructionParameters != null ? ((HwndSourceParameters)_constructionParameters).UsesPerPixelOpacity : _hwndTarget.UsesPerPixelOpacity;
switch(msg)
{
case NativeMethods.WM_NCCALCSIZE:
{
// Windows that use per-pixel opacity don't get
// their frames drawn by the system. Generally
// this is OK, as users of per-pixel alpha tend
// to be doing customized UI anyways. But we
// don't render correctly if we leave a non-client
// area, so here we expand the client area to
// cover any non-client area.
//
if(usesPerPixelOpacity)
{
if(wParam == IntPtr.Zero)
{
// If wParam is FALSE, lParam points to a RECT
// structure. On entry, the structure contains
// the proposed window rectangle for the
// window. On exit, the structure should
// contain the screen coordinates of the
// corresponding window client area.
//
// Since all we want to do is make the client
// rect the same as the window rect, we don't
// have to do anything.
//
result = IntPtr.Zero;
handled = true;
}
else
{
// If wParam is TRUE, lParam points to an
// NCCALCSIZE_PARAMS structure that contains
// information an application can use to
// calculate the new size and position of
// the client rectangle.
//
// When Windows sends the WM_NCCALCSIZE
// message, the NCCALCSIZE_PARAMS structure
// is filled out like this:
//
// rgrc[0] = new window rectangle (in parent coordinates)
// rgrc[1] = old window rectangle (in parent coordinates)
// rgrc[2] = old client rectangle (in parent coordinates)
//
// Notice that the client rectangle is given
// in parent coordinates, not in client
// coordinates.
//
// When your window procedure returns, Windows
// expects the NCCALCSIZE_PARAMS structure to
// be filled out like this:
//
// rgrc[0] = new client rectangle (in parent coordinates)
//
// Furthermore, if you return anything other
// than 0, Windows expects the remaining two
// rectangles to be filled out like this:
//
// rgrc[1] = destination rectangle (in parent coordinates)
// rgrc[2] = source rectangle (in parent coordinates)
//
// (If you return 0, then Windows assumes that
// the destination rectangle equals the new
// client rectangle and the source rectangle
// equals the old client rectangle.)
//
// Since all we want to do is make the client
// rect the same as the window rect, we don't
// have to do anything.
//
result = IntPtr.Zero;
handled = true;
}
}
}
break;
}
}
return result;
}
///
/// Critical: Because it uses _hwndTarget
///
[SecurityCritical]
private void Process_WM_WINDOWPOSCHANGING(UIElement rootUIElement, IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam)
{
// Only if SizeToContent overrides Win32 sizing change calls.
// If it's coming from OnResize (_myOwnUpdate != true), it means we are adjusting
// to the right size; don't need to do anything here.
if ((_myOwnUpdate != true) && (SizeToContent != SizeToContent.Manual))
{
Size sz = rootUIElement.RenderSize;
Point pt = _hwndTarget.TransformToDevice.Transform(new Point(sz.Width, sz.Height));
RoundDeviceSize(ref pt);
NativeMethods.RECT rect = new NativeMethods.RECT(0, 0, (int)pt.X, (int)pt.Y);
// get the outside size of the window only if LM has the client area
// as its size. LM has the client are when it is not the app model
// window case thus we calculate the outside size here.
//
// For windows with UsesPerPixelOpacity, we force the client to
// fill the window, so we don't need to add in any frame space.
//
if (_adjustSizingForNonClientArea == false && !UsesPerPixelOpacity)
{
// Get the current style and calculate the size to be with the new style.
// If WM_WINDOWPOSCHANGING is sent because of style changes, WM_STYLECHANGED is sent
// before this. The style bits we get here are updated ones, but haven't been applied
// to Window yet. For example, when the window is changing to borderless, without updating the window size,
// the window size will remain the same but the client area will be bigger. So when SizeToContent is on, we calculate
// the window size to be with the new style using AdustWindowRectEx and adjust it to make sure client area is not affected.
int style = NativeMethods.IntPtrToInt32((IntPtr)SafeNativeMethods.GetWindowStyle(new HandleRef(this,_hwndWrapper.Handle), false));
int styleEx = NativeMethods.IntPtrToInt32((IntPtr)SafeNativeMethods.GetWindowStyle(new HandleRef(this,_hwndWrapper.Handle), true));
SafeNativeMethods.AdjustWindowRectEx(ref rect, style, false, styleEx);
}
int newCX = rect.right - rect.left;
int newCY = rect.bottom - rect.top;
// Get WINDOWPOS structure data from lParam; it contains information about the window's
// new size and position.
NativeMethods.WINDOWPOS windowPos = (NativeMethods.WINDOWPOS)UnsafeNativeMethods.PtrToStructure(lParam, typeof(NativeMethods.WINDOWPOS));
bool sizeChanged = false;
// If SWP_NOSIZE is set to ignore cx, cy. It could be a style or position change.
if ((windowPos.flags & NativeMethods.SWP_NOSIZE) == NativeMethods.SWP_NOSIZE)
{
NativeMethods.RECT windowRect = new NativeMethods.RECT(0, 0, 0, 0);
// Get the current Window rect
SafeNativeMethods.GetWindowRect(new HandleRef(this, _hwndWrapper.Handle), ref windowRect);
// If there is no size change with the new style we don't need to do anything.
if ((newCX != (windowRect.right - windowRect.left)) ||
(newCY != (windowRect.bottom - windowRect.top)))
{
// Otherwise unmark the flag to make our changes effective.
windowPos.flags &= ~NativeMethods.SWP_NOSIZE;
// When SWP_NOSIZE is on, the size info in cx and cy is bogus. They are ignored.
// When we turn it off, we need to provide valid value for both of them.
windowPos.cx = newCX;
windowPos.cy = newCY;
sizeChanged = true;
}
}
else
{
// We have excluded SizeToContent == SizeToContent.Manual before entering this.
bool sizeToWidth = (SizeToContent == SizeToContent.Height) ? false : true;
bool sizeToHeight = (SizeToContent == SizeToContent.Width) ? false : true;
// Update WindowPos with the size we want.
if ((sizeToWidth) && (windowPos.cx != newCX))
{
windowPos.cx = newCX;
sizeChanged = true;
}
if ((sizeToHeight) && (windowPos.cy != newCY))
{
windowPos.cy = newCY;
sizeChanged = true;
}
}
// Marshal the structure back only when changed
if (sizeChanged)
{
Marshal.StructureToPtr(windowPos, lParam, true);
}
}
}
///
/// Critical: Because it uses _hwndTarget
///
[SecurityCritical]
private void Process_WM_SIZE(UIElement rootUIElement, IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam)
{
int x = NativeMethods.SignedLOWORD(lParam);
int y = NativeMethods.SignedHIWORD(lParam);
Point pt = new Point(x, y);
bool etwEnabled = EventTrace.IsEnabled(EventTrace.Flags.performance, EventTrace.Level.normal);
int ctxHashCode = 0;
// 1. If it's coming from Layout (_myOwnUpdate), it means we are adjusting
// to the right size; don't need to do anything here.
// 2. If SizeToContent is set to WidthAndHeight, then we maintain the current hwnd size
// in WM_WINDOWPOSCHANGING, so we don't need to re-layout here. If SizeToContent
// is set to Width or Height and developer calls SetWindowPos to set a new
// Width/Height, we need to do a layout.
// 3. We also don't need to do anything if it's minimized.
// Keeps the status of whether the Window is in Minimized state or not.
_isWindowInMinimizeState = (NativeMethods.IntPtrToInt32(wParam) == NativeMethods.SIZE_MINIMIZED) ? true : false;
if ((!_myOwnUpdate) && (_sizeToContent != SizeToContent.WidthAndHeight) && !_isWindowInMinimizeState)
{
Point relevantPt = new Point(pt.X, pt.Y);
// WM_SIZE has the client size of the window.
// for appmodel window case, get the outside size of the hwnd.
if (_adjustSizingForNonClientArea == true)
{
NativeMethods.RECT rect = new NativeMethods.RECT(0, 0, (int)pt.X, (int)pt.Y);
GetSizeForWindowObject(ref rect);
relevantPt.X = rect.right - rect.left;
relevantPt.Y = rect.bottom - rect.top;
}
// The lParam/wParam size and the GetSizeForWindowObject size are
// both in device co-ods, thus we convert to Measure co-ods here.
relevantPt = _hwndTarget.TransformFromDevice.Transform(relevantPt);
Size sz = new Size(
(_sizeToContent == SizeToContent.Width ? double.PositiveInfinity : relevantPt.X),
(_sizeToContent == SizeToContent.Height ? double.PositiveInfinity : relevantPt.Y));
// NOTE: [....] -- 6/03/04
// 962884 Avalon content does not resize when the favorites
// (or other side pane) is closed
//
// The issue is that when the browser shows favorites window, avalon
// window is resized and we get WM_SIZE. Here, we pass the IE window's
// size to Measure so that Computed[Width/Height] gets the correct
// IE window dimensions. Since, IE window's size may not change, the
// call to Measure is optimized out and no layout happens. Invalidating
// layout here ensures that we do layout.
// This can happen only in the Window case
if (_adjustSizingForNonClientArea == true)
{
rootUIElement.InvalidateMeasure();
}
if (etwEnabled)
{
ctxHashCode = this.Dispatcher.GetHashCode();
EventTrace.EventProvider.TraceEvent(EventTrace.GuidFromId(EventTraceGuidId.LAYOUTPASSGUID), MS.Utility.EventType.StartEvent, ctxHashCode);
EventTrace.EventProvider.TraceEvent(EventTrace.GuidFromId(EventTraceGuidId.MEASUREGUID), MS.Utility.EventType.StartEvent, ctxHashCode);
}
rootUIElement.Measure(sz);
if (_sizeToContent == SizeToContent.Width) sz = new Size(rootUIElement.DesiredSize.Width, relevantPt.Y);
else if (_sizeToContent == SizeToContent.Height) sz = new Size(relevantPt.X, rootUIElement.DesiredSize.Height);
else sz = new Size(relevantPt.X, relevantPt.Y);
if (etwEnabled)
{
EventTrace.EventProvider.TraceEvent(EventTrace.GuidFromId(EventTraceGuidId.MEASUREGUID), MS.Utility.EventType.EndEvent);
EventTrace.EventProvider.TraceEvent(EventTrace.GuidFromId(EventTraceGuidId.ARRANGEGUID), MS.Utility.EventType.StartEvent, ctxHashCode);
}
rootUIElement.Arrange(new Rect(new Point(), sz));
if (etwEnabled)
{
EventTrace.EventProvider.TraceEvent(EventTrace.GuidFromId(EventTraceGuidId.ARRANGEGUID), MS.Utility.EventType.EndEvent);
EventTrace.EventProvider.TraceEvent(EventTrace.GuidFromId(EventTraceGuidId.LAYOUTPASSGUID), MS.Utility.EventType.EndEvent);
}
rootUIElement.UpdateLayout(); //finalizes layout
}
}
///
/// Critical: Because it uses _hwndTarget
///
[SecurityCritical]
private void DisableSizeToContent(UIElement rootUIElement, IntPtr hwnd)
{
if (_sizeToContent != SizeToContent.Manual)
{
_sizeToContent = SizeToContent.Manual;
// [....] - 10/27/2005
// 1348020 Window expereience layout issue when SizeToContent is being turned
// off by user interaction
// This bug was caused b/c we were giving rootUIElement.DesiredSize as input
// to Measure/Arrange below. That is incorrect since rootUIElement.DesiredSize may not
// cover the entire hwnd client area.
// GetSizeFromHwnd returns either the outside size or the client size of the hwnd based on
// _adjustSizeingForNonClientArea flag in logical units.
Size sizeLogicalUnits = GetSizeFromHwnd();
rootUIElement.Measure(sizeLogicalUnits);
rootUIElement.Arrange(new Rect(new Point(), sizeLogicalUnits));
rootUIElement.UpdateLayout(); //finalizes layout
if (SizeToContentChanged != null)
{
SizeToContentChanged(this, EventArgs.Empty);
}
}
}
// This method makes sure that we get the size from the correct
// hwnd for the browser case.
///
/// Critical - calls critical methods (HwndSourceHelper.GetHandle and GetAncestor)
/// TreatAsSafe - it's ok to return size of window. it doesn't return info gotten through critical calls.
///
[SecurityCritical, SecurityTreatAsSafe]
private void GetSizeForWindowObject(ref NativeMethods.RECT rc)
{
IntPtr hwndRoot = UnsafeNativeMethods.GetAncestor(new HandleRef(this, CriticalHandle), NativeMethods.GA_ROOT);
SafeNativeMethods.GetWindowRect(new HandleRef(this, hwndRoot), ref rc);
}
///
/// Critical: This is a hook that gets called back with information about messages related to input
/// Calling this from outside or causing this to be invoked could yield risky situations
///
[SecurityCritical]
private IntPtr InputFilterMessage(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
IntPtr result = IntPtr.Zero ;
// NOTE ([....]): invoke _stylus.FilterMessage before _mouse.FilterMessage
// to give _stylus a chance to eat mouse message generated by stylus
if (!_isDisposed && _stylus != null && !handled)
{
result = _stylus.Value.FilterMessage(hwnd, msg, wParam, lParam, ref handled);
}
if (!_isDisposed && _mouse != null && !handled)
{
result = _mouse.Value.FilterMessage(hwnd, msg, wParam, lParam, ref handled);
}
if (!_isDisposed && _keyboard != null && !handled)
{
result = _keyboard.Value.FilterMessage(hwnd, msg, wParam, lParam, ref handled);
}
if (!_isDisposed && _appCommand != null && !handled)
{
result = _appCommand.Value.FilterMessage(hwnd, msg, wParam, lParam, ref handled);
}
return result;
}
///
/// Called from HwndWrapper on all window messages.
///
// assumes Context.Access() is held.
private IntPtr PublicHooksFilterMessage(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
// The default result for messages we handle is 0.
IntPtr result = IntPtr.Zero ;
// Call all of the public hooks
// We do this even if we are disposed because otherwise the hooks
// would never see the WM_DESTROY etc. message.
if (_hooks != null)
{
for (int i = 0, nCount = _hooks.Count; i < nCount; i++)
{
result = ((HwndSourceHook)_hooks[i])(hwnd, msg, wParam, lParam, ref handled);
if(handled)
{
break;
}
}
}
if (NativeMethods.WM_NCDESTROY == msg)
{
// We delivered the message to the hooks and the message
// is WM_NCDESTROY, so our commitments should be finished
// we can do final teardown. (like disposing the _hooks)
OnNoMoreWindowMessages();
}
return result;
}
#region IKeyboardInputSink
private class MSGDATA
{
public MSG msg;
public bool handled;
}
///
/// HwndSource keyboard input is sent through this delegate to check for
/// Child Hwnd interop requirments. If there are no child hwnds or focus
/// is on this non-child hwnd then normal Avalon processing is done.
///
///
/// Critical - This can be used to spoof input
///
[SecurityCritical]
private void OnPreprocessMessageThunk(ref MSG msg, ref bool handled)
{
// VerifyAccess();
if (handled)
{
return;
}
// MITIGATION: HANDLED_KEYDOWN_STILL_GENERATES_CHARS
if(msg.message == _msgEnableCharMessages)
{
// This is our cue to go back to accepting character messages
_eatCharMessages = false;
}
// We only do these message.
switch (msg.message)
{
case NativeMethods.WM_KEYUP:
case NativeMethods.WM_KEYDOWN:
case NativeMethods.WM_SYSKEYUP:
case NativeMethods.WM_SYSKEYDOWN:
case NativeMethods.WM_CHAR:
case NativeMethods.WM_SYSCHAR:
case NativeMethods.WM_DEADCHAR:
case NativeMethods.WM_SYSDEADCHAR:
MSGDATA msgdata = new MSGDATA();
msgdata.msg = msg;
msgdata.handled = handled;
// Do this under the exception filter/handlers of the
// dispatcher for this thread.
//
// NOTE: we lose the "perf optimization" of passing everything
// around by-ref since we have to call through a delegate.
object result = Dispatcher.CurrentDispatcher.Invoke(
DispatcherPriority.Send,
new DispatcherOperationCallback(OnPreprocessMessage),
msgdata);
if (result != null)
{
handled = (bool)result;
}
// the semantics dictate that the callers could change this data.
msg = msgdata.msg;
break;
}
}
///
/// Critical - Can be used to spoof input
///
[SecurityCritical]
private object OnPreprocessMessage(object param)
{
MSGDATA msgdata = (MSGDATA) param;
// At the top level check if someone below us has Focus.
// Mnemonics are broadcast to all branches of the window tree; even
// those that don't have focus. BUT! at least someone under this
// TopLevel window must have focus.
if (!((IKeyboardInputSink)this).HasFocusWithin())
{
return msgdata.handled;
}
ModifierKeys modifierKeys = HwndKeyboardInputProvider.GetSystemModifierKeys();
// Interop with the Interop layer
//
switch (msgdata.msg.message)
{
case NativeMethods.WM_SYSKEYDOWN:
case NativeMethods.WM_KEYDOWN:
// MITIGATION: HANDLED_KEYDOWN_STILL_GENERATES_CHARS
// In case a nested message pump is used before we return
// from processing this message, we disable character
// messages.
_eatCharMessages = true;
// MITIGATION: HANDLED_KEYDOWN_STILL_GENERATES_CHARS
_eatCharMessages = msgdata.handled = CriticalTranslateAccelerator(ref msgdata.msg, modifierKeys);
if(_eatCharMessages)
{
UnsafeNativeMethods.PostMessage(new HandleRef(this, CriticalHandle), _msgEnableCharMessages, IntPtr.Zero, IntPtr.Zero);
}
break;
case NativeMethods.WM_SYSKEYUP:
case NativeMethods.WM_KEYUP:
msgdata.handled = CriticalTranslateAccelerator(ref msgdata.msg, modifierKeys);
break;
case NativeMethods.WM_CHAR:
case NativeMethods.WM_SYSCHAR:
case NativeMethods.WM_DEADCHAR:
case NativeMethods.WM_SYSDEADCHAR:
// MITIGATION: HANDLED_KEYDOWN_STILL_GENERATES_CHARS
if(!_eatCharMessages)
{
msgdata.handled = ((IKeyboardInputSink)this).TranslateChar(ref msgdata.msg, modifierKeys);
if (!msgdata.handled)
{
msgdata.handled = ((IKeyboardInputSink)this).OnMnemonic(ref msgdata.msg, modifierKeys);
}
if (!msgdata.handled)
{
_keyboard.Value.ProcessTextInputAction(msgdata.msg.hwnd, msgdata.msg.message,
msgdata.msg.wParam, msgdata.msg.lParam, ref msgdata.handled);
}
}
break;
}
return msgdata.handled;
}
///
/// Registers a child KeyboardInputSink with this sink. A site
/// is returned.
///
///
/// This API requires unrestricted UI Window permission.
///
///
/// Critical: This API can be used for input spoofing
/// PublicOK: This method has a demand on it.
///
[SecurityCritical, UIPermissionAttribute(SecurityAction.Demand, Unrestricted=true)]
IKeyboardInputSite IKeyboardInputSink.RegisterKeyboardInputSink(IKeyboardInputSink sink)
{
CheckDisposed(true);
if (sink == null)
{
throw new ArgumentNullException("sink");
}
if (sink.KeyboardInputSite != null)
{
throw new ArgumentException(SR.Get(SRID.KeyboardSinkAlreadyOwned));
}
HwndSourceKeyboardInputSite site = new HwndSourceKeyboardInputSite(this, sink);
if (_keyboardInputSinkChildren == null)
_keyboardInputSinkChildren = new List();
_keyboardInputSinkChildren.Add(site);
return site;
}
///
/// Gives the component a chance to process keyboard input.
/// Return value is true if handled, false if not. Components
/// will generally call a child component's TranslateAccelerator
/// if they can't handle the input themselves. The message must
/// either be WM_KEYDOWN or WM_SYSKEYDOWN. It is illegal to
/// modify the MSG structure, it's passed by reference only as
/// a performance optimization.
///
///
/// This API is not available in Internet Zone.
///
///
/// Critical: This API can be used for input spoofing
/// TreatAsSafe: This method has a demand on it.
///
[SecurityCritical, SecurityTreatAsSafe]
bool IKeyboardInputSink.TranslateAccelerator(ref MSG msg, ModifierKeys modifiers)
{
SecurityHelper.DemandUnmanagedCode();
// VerifyAccess();
return CriticalTranslateAccelerator(ref msg, modifiers);
}
///
/// Set focus to the first or last tab stop (according to the
/// TraversalRequest). If it can't, because it has no tab stops,
/// the return value is false.
///
bool IKeyboardInputSink.TabInto(TraversalRequest request)
{
bool traversed = false;
if(request == null)
{
throw new ArgumentNullException("request");
}
UIElement root =_rootVisual.Value as UIElement;
if(root != null)
{
// [....]:
// request.Mode == FocusNavigationDirection.First will navigate to the fist tabstop including root
// request.Mode == FocusNavigationDirection.Last will navigate to the last tabstop including root
traversed = root.MoveFocus(request);
}
return traversed;
}
///
/// The property should start with a null value. The component's
/// container will set this property to a non-null value before
/// any other methods are called. It may be set multiple times,
/// and should be set to null before disposal.
///
///
/// Setting KeyboardInputSite is not available in Internet Zone.
///
///
/// Critical: This API can be used for input spoofing
/// PublicOK: This method has a demand on it.
///
IKeyboardInputSite IKeyboardInputSink.KeyboardInputSite
{
[SecurityCritical]
get
{
SecurityHelper.DemandUnmanagedCode();
return _keyboardInputSite;
}
[SecurityCritical]
set
{
SecurityHelper.DemandUnmanagedCode();
_keyboardInputSite = value;
}
}
///
/// This method is called whenever one of the component's
/// mnemonics is invoked. The message must either be WM_KEYDOWN
/// or WM_SYSKEYDOWN. It's illegal to modify the MSG structrure,
/// it's passed by reference only as a performance optimization.
/// If this component contains child components, the container
/// OnMnemonic will need to call the child's OnMnemonic method.
///
///
/// Critical: This API can be used for input spoofing
/// TreatAsSafe: This method has a demand on it.
///
[SecurityCritical, SecurityTreatAsSafe]
bool IKeyboardInputSink.OnMnemonic(ref MSG msg, ModifierKeys modifiers)
{
// VerifyAccess();
SecurityHelper.DemandUnmanagedCode();
switch(msg.message)
{
case NativeMethods.WM_SYSCHAR:
case NativeMethods.WM_SYSDEADCHAR:
string text = new string((char)msg.wParam, 1);
if ((text != null) && (text.Length > 0))
{
if (AccessKeyManager.IsKeyRegistered(this, text))
{
AccessKeyManager.ProcessKey(this, text, false);
//
return true;
}
}
// these are OK
break;
case NativeMethods.WM_CHAR:
case NativeMethods.WM_DEADCHAR:
// these are OK
break;
default:
throw new ArgumentException(SR.Get(SRID.OnlyAcceptsKeyMessages));
}
// We record the last message that was processed by us.
// This is also checked in WndProc processing to prevent double processing.
_lastKeyboardMessage = msg;
// The Avalon bubble will take care of access key processing for this HWND
// So now we just call the children.
if (null == _keyboardInputSinkChildren)
return false;
foreach ( HwndSourceKeyboardInputSite childSite in _keyboardInputSinkChildren )
{
if (((IKeyboardInputSite)childSite).Sink.OnMnemonic(ref msg, modifiers))
return true;
}
return false;
}
///
/// Gives the component a chance to process keyboard input messages
/// WM_CHAR, WM_SYSCHAR, WM_DEADCHAR or WM_SYSDEADCHAR before calling OnMnemonic.
/// Will return true if "handled" meaning don't pass it to OnMnemonic.
/// The message must be WM_CHAR, WM_SYSCHAR, WM_DEADCHAR or WM_SYSDEADCHAR.
/// It is illegal to modify the MSG structure, it's passed by reference
/// only as a performance optimization.
///
///
/// Critical: This API can be used for input spoofing
/// TreatAsSafe: This method has a demand on it.
///
[SecurityCritical, SecurityTreatAsSafe]
bool IKeyboardInputSink.TranslateChar(ref MSG msg, ModifierKeys modifiers)
{
SecurityHelper.DemandUnmanagedCode();
if(HasFocus)
return false;
IKeyboardInputSink focusSink = this.ChildSinkWithFocus;
if(null != focusSink)
{
return focusSink.TranslateChar(ref msg, modifiers);
}
return false;
}
///
///
///
bool IKeyboardInputSink.HasFocusWithin()
{
if(HasFocus)
{
return true;
}
else
{
if (null == _keyboardInputSinkChildren)
return false;
foreach (HwndSourceKeyboardInputSite site in _keyboardInputSinkChildren)
{
if (((IKeyboardInputSite)site).Sink.HasFocusWithin())
{
return true;
}
}
return false;
}
}
///
/// The method is not part of the interface (IKeyboardInputSink).
///
/// The Site that containes the sink to unregister
///
/// Critical - calls critical methods.
///
[ SecurityCritical ]
internal void CriticalUnregisterKeyboardInputSink(HwndSourceKeyboardInputSite site)
{
if(_isDisposed)
return;
if (null != _keyboardInputSinkChildren)
{
if (!_keyboardInputSinkChildren.Remove(site))
{
throw new InvalidOperationException(SR.Get(SRID.KeyboardSinkNotAChild));
}
}
}
IKeyboardInputSink ChildSinkWithFocus
{
get
{
IKeyboardInputSink ikis=null;
if(null == _keyboardInputSinkChildren)
return null;
foreach (HwndSourceKeyboardInputSite site in _keyboardInputSinkChildren)
{
IKeyboardInputSite isite = (IKeyboardInputSite)site;
if (isite.Sink.HasFocusWithin())
{
ikis = isite.Sink;
break;
}
}
// This private property should only be called correctly.
Debug.Assert(null!=ikis, "ChildSinkWithFocus called when none had focus");
return ikis;
}
}
///
/// Critical: This API could be vulnerable to input spoofing.
///
[SecurityCritical, FriendAccessAllowed]
internal bool CriticalTranslateAccelerator(ref MSG msg, ModifierKeys modifiers)
{
switch (msg.message)
{
case NativeMethods.WM_KEYUP:
case NativeMethods.WM_KEYDOWN:
case NativeMethods.WM_SYSKEYUP:
case NativeMethods.WM_SYSKEYDOWN:
// these are OK
break;
default:
throw new ArgumentException(SR.Get(SRID.OnlyAcceptsKeyMessages));
}
if (_keyboard == null)
return false;
bool handled = false;
// TranslateAccelerator is called recursively on child Hwnds (Source & Host)
// If this is the first Avalon TranslateAccelerator processing then we send the
// key to be processed to the standard Avalon Input Filters and stuff.
if (PerThreadData.TranslateAcceleratorCallDepth == 0)
{
// We record the last message that was processed by us.
// This is also checked in WndProc processing to prevent double processing.
// TranslateAcclerator is called from the pump before DispatchMessage
// and the WndProc is called from DispatchMessage. We have processing
// in both places. If we run the pump we process keyboard message here.
// If we don't own the pump we process them in HwndKeyboardInputProvider.WndProc.
_lastKeyboardMessage = msg;
// NORMAL AVALON KEYBOARD INPUT CASE
// If this is the top most Avalon window (it might be a child Hwnd
// but no Avalon windows above it). And focus is on this window then
// do the Normal Avalon Keyboard input Processing.
if (HasFocus)
{
_keyboard.Value.ProcessKeyAction(ref msg, ref handled);
}
// ELSE the focus is in but not on this HwndSource.
// Do the once only message input filters etc and Tunnel/Bubble down
// to the element that contains the child window with focus.
// The Child HwndHost object will hook OnPreviewKeyDown() etc
// to make the transition to its TranslateAccelerator() between the
// tunnel and the bubble.
else
{
IKeyboardInputSink focusSink = ChildSinkWithFocus;
IInputElement focusElement = (IInputElement)focusSink;
try {
PerThreadData.TranslateAcceleratorCallDepth += 1;
Keyboard.PrimaryDevice.ForceTarget = focusElement;
_keyboard.Value.ProcessKeyAction(ref msg, ref handled);
}
finally
{
Keyboard.PrimaryDevice.ForceTarget = null;
PerThreadData.TranslateAcceleratorCallDepth -= 1;
}
}
}
// ELSE we have seen this MSG before, we are HwndSource decendant of an
// HwndSource (that ancestor presumably did the processing above).
// Here we raise the tunnel/bubble events without the once only keyboard
// input filtering.
else
{
int virtualKey = HwndKeyboardInputProvider.GetVirtualKey(msg.wParam, msg.lParam);
int scanCode = HwndKeyboardInputProvider.GetScanCode(msg.wParam, msg.lParam);
bool isExtendedKey = HwndKeyboardInputProvider.IsExtendedKey(msg.lParam);
Key key = KeyInterop.KeyFromVirtualKey(virtualKey);
RoutedEvent keyPreviewEvent=null;
RoutedEvent keyEvent=null;
switch (msg.message)
{
case NativeMethods.WM_KEYUP:
case NativeMethods.WM_SYSKEYUP:
keyPreviewEvent = Keyboard.PreviewKeyUpEvent;
keyEvent = Keyboard.KeyUpEvent;
break;
case NativeMethods.WM_KEYDOWN:
case NativeMethods.WM_SYSKEYDOWN:
keyPreviewEvent = Keyboard.PreviewKeyDownEvent;
keyEvent = Keyboard.KeyDownEvent;
break;
}
IKeyboardInputSink focusSink = HasFocus ? null : ChildSinkWithFocus;
IInputElement focusElement = focusSink as IInputElement;
// focusElement may be null, in which case Target is just "focus"
try {
Keyboard.PrimaryDevice.ForceTarget = focusElement;
focusElement = Keyboard.PrimaryDevice.Target;
KeyEventArgs tunnelArgs = new KeyEventArgs(Keyboard.PrimaryDevice, this, msg.time, key);
tunnelArgs.ScanCode = scanCode;
tunnelArgs.IsExtendedKey = isExtendedKey;
tunnelArgs.RoutedEvent = keyPreviewEvent;
focusElement.RaiseEvent(tunnelArgs);
handled = tunnelArgs.Handled;
if (!handled)
{
KeyEventArgs bubbleArgs = new KeyEventArgs(Keyboard.PrimaryDevice, this, msg.time, key);
bubbleArgs.ScanCode = scanCode;
bubbleArgs.IsExtendedKey = isExtendedKey;
bubbleArgs.RoutedEvent=keyEvent;
focusElement.RaiseEvent(bubbleArgs);
handled = bubbleArgs.Handled;
if (!handled)
{
// Raise the TranslateAccelerator event on the
// InputManager to allow keyboard navigation to
// happen on a descendent HwndSource
InputManager.UnsecureCurrent.RaiseTranslateAccelerator(bubbleArgs);
handled = bubbleArgs.Handled;
}
}
}
finally
{
Keyboard.PrimaryDevice.ForceTarget = null;
}
}
return handled;
}
#endregion IKeyboardInputSink
internal bool IsRepeatedKeyboardMessage(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam)
{
if (msg != _lastKeyboardMessage.message)
return false;
if (hwnd != _lastKeyboardMessage.hwnd)
return false;
if (wParam != _lastKeyboardMessage.wParam)
return false;
if (lParam != _lastKeyboardMessage.lParam)
return false;
return true;
}
///
/// This event handler is called from HwndWrapper when it is Disposing.
///
// This could happen if someone calls his Dispose before (or instead
// of) our dispose. Or, more likely, the real window was killed by
// something like the user clicking the close box.
private void OnHwndDisposed(object sender, EventArgs args)
{
// This method is called from the HwndWrapper.Dispose().
// So make sure we don't call HwndWrapper.Dispose().
_inRealHwndDispose = true;
Dispose();
}
///
/// Called after the last window message is processed.
///
// HwndSource is required to continue certain operations while,
// and even after, Dispose runs. HwndSource is resposible for
// calling WndProcHooks with every message the window sees.
// Including: WM_CLOSE, WM_DESTROY, WM_NCDESTROY. The doc says
// WM_NCDESTROY is the very last message, so we can release the
// Hooks after that.
// This assumes the Context.Access() is held.
private void OnNoMoreWindowMessages()
{
_hooks.Clear();
_hooks = null;
}
private void OnShutdownFinished(object sender, EventArgs args)
{
// Note: We are already in the context being disposed.
Dispose();
}
//
// NOTE: shutdown order is very important. Review any changes
// carefully.
//
///
/// Critical: This accesses the various sites and providers
/// Safe: Disposing the object is a safe operation.
///
[SecurityCritical, SecurityTreatAsSafe]
private void Dispose(bool disposing)
{
if(disposing)
{
// Make sure all access is synchronized.
// this.VerifyAccess();
if (!_isDisposing)
{
// _isDisposing is a guard against re-entery into this
// routine. We fire Dispose and SourceChanged (RootVisual
// change) events which could cause re-entery.
_isDisposing = true;
// Notify listeners that we are being disposed. We do this
// before we dispose our internal stuff, in case the event
// listener needs to access something.
if(Disposed != null)
{
try
{
Disposed(this, EventArgs.Empty);
}
#pragma warning disable 56500
// We can't tolerate an exception thrown by third-party code to
// abort our Dispose half-way through. So we just eat it.
catch
{
}
#pragma warning restore 56500
Disposed = null;
}
// Remove any listeners of the ContentRendered event
ClearContentRenderedListeners();
// Clear the root visual. This will raise a SourceChanged
// event to registered listeners.
RootVisualInternal = null;
RemoveSource();
// Unregister ourselves if we are a registered KeyboardInputSink.
if(_keyboardInputSite != null)
{
_keyboardInputSite.Unregister();
_keyboardInputSite = null;
}
_keyboardInputSinkChildren = null;
// Dispose the HwndStylusInputProvider BEFORE we destroy the HWND.
// This us because the stylus provider has an async channel and
// they don't want to process data after the HWND is destroyed.
if (_stylus != null)
{
_stylus.Value.Dispose();
_stylus = null;
}
// Our general shut-down principle is to destroy the window
// and let the individual HwndXXX components respons to WM_DESTROY.
//
// (see comment above about disposing the HwndStylusInputProvider)
//
{
if (_hwndTarget != null)
{
_hwndTarget.Dispose();
_hwndTarget = null;
}
if (_hwndWrapper != null)
{
// Revoke the drop target.
if (_hwndWrapper.Handle != IntPtr.Zero && _registeredDropTargetCount > 0)
{
// This call is safe since DragDrop.RevokeDropTarget is checking the unmanged
// code permission.
DragDrop.RevokeDropTarget(_hwndWrapper.Handle);
_registeredDropTargetCount--;
}
// Remove our HwndWrapper.Dispose() hander.
_hwndWrapper.Disposed -= new EventHandler(OnHwndDisposed);
if (!_inRealHwndDispose)
_hwndWrapper.Dispose();
// Don't null out _hwndWrapper after the Dispose().
// Dispose() will start destroying the Window but we
// still need to talk to it during that process while
// the WM_ msgs arrive.
}
}
if(_mouse != null)
{
_mouse.Value.Dispose();
_mouse = null;
}
if(_keyboard != null)
{
_keyboard.Value.Dispose();
_keyboard = null;
}
if (_appCommand != null)
{
_appCommand.Value.Dispose();
_appCommand = null;
}
if(null != _weakShutdownHandler)
{
_weakShutdownHandler.Dispose();
_weakShutdownHandler = null;
}
if(null != _weakPreprocessMessageHandler)
{
_weakPreprocessMessageHandler.Dispose();
_weakPreprocessMessageHandler = null;
}
// We wait to set the "_isDisposed" flag until after the
// Disposed, SourceChange (RootVisual=null), etc. events
// have fired. We want to remain functional should their
// handlers call methods on us.
//
// Note: as the HwndWrapper shuts down, the final few messages
// will continue to pass through our WndProc hook.
_isDisposed = true;
}
}
}
private void CheckDisposed(bool verifyAccess)
{
if(verifyAccess)
{
// this.VerifyAccess();
}
if(_isDisposed)
{
throw new ObjectDisposedException(null, SR.Get(SRID.HwndSourceDisposed));
}
}
///
/// Critical: This code accesses hwndtarget
/// TreatAsSafe: Information is ok to expose
///
private bool IsUsable
{
[SecurityCritical,SecurityTreatAsSafe]
get
{
return _isDisposed == false &&
_hwndTarget != null &&
_hwndTarget.IsDisposed == false;
}
}
///
/// Critical - calls a method with an elevation ( GetFocus )
/// TreatAsSafe - determining whether you have focus within the window is considered safe.
/// Worst case you can know whether keyboard/keypress events will go to the current window.
///
private bool HasFocus
{
[SecurityCritical, SecurityTreatAsSafe]
get
{
return UnsafeNativeMethods.GetFocus() == CriticalHandle;
}
}
private static bool IsValidSizeToContent(SizeToContent value)
{
return value == SizeToContent.Manual ||
value == SizeToContent.Width ||
value == SizeToContent.Height ||
value == SizeToContent.WidthAndHeight;
}
class ThreadDataBlob
{
public int TranslateAcceleratorCallDepth;
}
private static ThreadDataBlob PerThreadData
{
get
{
ThreadDataBlob data;
object obj = Thread.GetData(_threadSlot);
if(null == obj)
{
data = new ThreadDataBlob();
Thread.SetData(_threadSlot, data);
}
else
{
data = (ThreadDataBlob) obj;
}
return data;
}
}
#region WeakEventHandlers
private class WeakEventDispatcherShutdown: WeakReference
{
public WeakEventDispatcherShutdown(HwndSource source, Dispatcher that): base(source)
{
_that = that;
_that.ShutdownFinished += new EventHandler(this.OnShutdownFinished);
}
public void OnShutdownFinished(object sender, EventArgs e)
{
HwndSource source = this.Target as HwndSource;
if(null != source)
{
source.OnShutdownFinished(sender, e);
}
else
{
Dispose();
}
}
public void Dispose()
{
if(null != _that)
{
_that.ShutdownFinished-= new EventHandler(this.OnShutdownFinished);
}
}
private Dispatcher _that;
}
private class WeakEventPreprocessMessage: WeakReference
{
///
/// Critical: This code calls attaches an arbitrary window
/// to the call path for the component dispatcher call back
///
[SecurityCritical]
public WeakEventPreprocessMessage(HwndSource source): base(source)
{
ComponentDispatcher.ThreadPreprocessMessage +=
new ThreadMessageEventHandler(this.OnPreprocessMessage);
}
///
/// Critical: This can be used to spoof and change input
///
[SecurityCritical]
public void OnPreprocessMessage(ref MSG msg, ref bool handled)
{
HwndSource source = this.Target as HwndSource;
if(null != source)
{
source.OnPreprocessMessageThunk(ref msg, ref handled);
}
else
{
Dispose();
}
}
///
/// Critical:This code calls into ComponentDispatcher
/// to disconnect a listener
/// TreatAsSafe: This code is ok to call
///
[SecurityCritical,SecurityTreatAsSafe]
public void Dispose()
{
ComponentDispatcher.ThreadPreprocessMessage -=
new ThreadMessageEventHandler(this.OnPreprocessMessage);
}
}
#endregion WeakEventHandlers
private object _constructionParameters; // boxed HwndSourceParameters
private bool _isDisposed = false;
private bool _isDisposing = false;
private bool _inRealHwndDispose = false;
private bool _adjustSizingForNonClientArea;
private bool _myOwnUpdate;
private bool _isWindowInMinimizeState = false;
private int _registeredDropTargetCount;
private SizeToContent _sizeToContent = SizeToContent.Manual;
private Size? _previousSize;
///
/// Critical:This reference cannot be given out or assigned to outside of a verified
/// elevation. This data is considered critical.
///
[SecurityCritical]
private HwndWrapper _hwndWrapper;
///
/// Critical:This reference cannot be given out or assigned to outside of a verified
/// elevation. This data is considered critical.
///
[SecurityCritical]
private HwndTarget _hwndTarget;
private SecurityCriticalDataForSet _rootVisual;
private ArrayList _hooks;
///
/// Critical:This reference cannot be given out or assigned to outside of a verified
/// elevation. This data is considered critical.
///
private SecurityCriticalDataClass _mouse;
///
/// Critical:This reference cannot be given out or assigned to outside of a verified
/// elevation. This data is considered critical.
///
private SecurityCriticalDataClass _keyboard;
///
/// Critical:This reference cannot be given out or assigned to outside of a verified
/// elevation. This data is considered critical.
///
private SecurityCriticalDataClass _stylus;
///
/// Critical:This reference cannot be given out or assigned to outside of a verified
/// elevation. This data is considered critical.
///
private SecurityCriticalDataClass _appCommand;
WeakEventDispatcherShutdown _weakShutdownHandler;
WeakEventPreprocessMessage _weakPreprocessMessageHandler;
private static System.LocalDataStoreSlot _threadSlot;
private MSG _lastKeyboardMessage;
private List _keyboardInputSinkChildren;
///
/// Critical:This reference cannot be given out or assigned to outside of a verified
/// elevation. This data can be used to spoof input
///
[SecurityCritical]
private IKeyboardInputSite _keyboardInputSite = null;
///
/// Critical:This reference cannot be given out or assigned to outside of a verified
/// elevation. This data can be used to spoof input
///
[SecurityCritical]
private HwndWrapperHook _layoutHook;
///
/// Critical:This reference cannot be given out or assigned to outside of a verified
/// elevation. This data can be used to spoof input
///
[SecurityCritical]
private HwndWrapperHook _inputHook;
///
/// Critical:This reference cannot be given out or assigned to outside of a verified
/// elevation. This data can be used to spoof input
///
[SecurityCritical]
private HwndWrapperHook _hwndTargetHook;
///
/// Critical:This reference cannot be given out or assigned to outside of a verified
/// elevation. This data can be used to spoof input
///
[SecurityCritical]
private HwndWrapperHook _publicHook;
// MITIGATION: HANDLED_KEYDOWN_STILL_GENERATES_CHARS
//
// Avalon relies on the policy that if you handle the KeyDown
// event, you will not get the TextInput events caused by
// pressing the key. This is generally implemented because the
// message pump calls ComponentDispatcher.RaiseThreadMessage and
// we return whether or not the WM_KEYDOWN message was handled,
// and the message pump will only call TranslateMessage() if the
// WM_KEYDOWN was not handled. However, naive message pumps don't
// call ComponentDispatcher.RaiseThreadMessage, and always call
// TranslateMessage, so the WM_CHAR is generated no matter what.
// The best work around we could think of was to eat the WM_CHAR
// messages and not report them to Avalon.
//
[ThreadStatic]
internal static bool _eatCharMessages; // used from HwndKeyboardInputProvider
internal static int _msgEnableCharMessages;
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- InsufficientMemoryException.cs
- CategoryNameCollection.cs
- WebAdminConfigurationHelper.cs
- AccessibleObject.cs
- StreamGeometryContext.cs
- HttpCapabilitiesEvaluator.cs
- BindingMemberInfo.cs
- MultiPropertyDescriptorGridEntry.cs
- TransformBlockRequest.cs
- NativeMethods.cs
- MeasureItemEvent.cs
- SEHException.cs
- LockedHandleGlyph.cs
- TemplateColumn.cs
- ApplicationSettingsBase.cs
- InputProcessorProfilesLoader.cs
- XmlSchemaValidationException.cs
- WindowsFormsSectionHandler.cs
- HostedController.cs
- RowToParametersTransformer.cs
- CapabilitiesRule.cs
- SqlFunctions.cs
- CryptoHelper.cs
- PropertyConverter.cs
- RuntimeResourceSet.cs
- AnnotationMap.cs
- BrowserTree.cs
- ToolstripProfessionalRenderer.cs
- Int64.cs
- TempEnvironment.cs
- LambdaCompiler.Binary.cs
- XmlNodeList.cs
- Manipulation.cs
- XmlToDatasetMap.cs
- KnownBoxes.cs
- LocationChangedEventArgs.cs
- XslNumber.cs
- SiteMapNode.cs
- PersonalizationStateInfoCollection.cs
- PrintPreviewGraphics.cs
- wmiutil.cs
- AsymmetricSignatureDeformatter.cs
- GridSplitter.cs
- XmlPropertyBag.cs
- HitTestWithPointDrawingContextWalker.cs
- XamlTypeMapper.cs
- WorkflowRuntimeServiceElement.cs
- TokenBasedSetEnumerator.cs
- SessionStateItemCollection.cs
- CodeCatchClauseCollection.cs
- TiffBitmapEncoder.cs
- OleDbParameterCollection.cs
- SelectionRangeConverter.cs
- TreeWalker.cs
- TdsParser.cs
- Int32Collection.cs
- AbandonedMutexException.cs
- MasterPageParser.cs
- DBCommandBuilder.cs
- HasCopySemanticsAttribute.cs
- WebScriptEnablingBehavior.cs
- TemplatePropertyEntry.cs
- FixedLineResult.cs
- _DisconnectOverlappedAsyncResult.cs
- AdapterUtil.cs
- DependencyPropertyKind.cs
- CompilerInfo.cs
- EditingMode.cs
- brushes.cs
- SpnEndpointIdentityExtension.cs
- GridViewColumnHeaderAutomationPeer.cs
- IssuanceLicense.cs
- DataObject.cs
- SecurityCriticalDataForSet.cs
- KeyGestureValueSerializer.cs
- SecurityState.cs
- _AutoWebProxyScriptWrapper.cs
- MailWriter.cs
- TdsParser.cs
- SqlCharStream.cs
- ListManagerBindingsCollection.cs
- HotSpotCollection.cs
- MinMaxParagraphWidth.cs
- SelectionItemPattern.cs
- ContainerVisual.cs
- LassoHelper.cs
- ToolStripSystemRenderer.cs
- FieldBuilder.cs
- WebServiceEnumData.cs
- InfiniteIntConverter.cs
- AssemblyUtil.cs
- ConstructorNeedsTagAttribute.cs
- XamlStream.cs
- EntityDataSourceUtil.cs
- SizeF.cs
- Stylesheet.cs
- SequenceDesigner.cs
- ThicknessAnimationUsingKeyFrames.cs
- VisualSerializer.cs
- FormViewUpdatedEventArgs.cs