Code:
/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / wpf / src / UIAutomation / Win32Providers / MS / Internal / AutomationProxies / ProxySimple.cs / 1 / ProxySimple.cs
//---------------------------------------------------------------------------- // //// Copyright (C) Microsoft Corporation. All rights reserved. // // // // Description: Base class for all the Win32 and office Controls. // // The ProxySimple class is the base class for the leafs // in the raw element tree. Also proxy that directly derives // from this clas should not care about events // // The UIAutomation Simple class is limited to UI elements that are // Hwnd based. This makes it of little use for Win32 and office controls. // The ProxySimple class removes this limitation. This leads to a couple of // changes; RuntTimeID and BoundingRect must be implemented by this object. // // // Class ProxySimple: IRawElementProviderFragment, IRawElementProviderSimple // BoundingRectangle // RuntimeId // Properties // GetPatterns // SetFocus // // Example: ComboboxButton, MenuItem, Office CommandBar button, ListViewSubitem // // // // History: // 07/01/2003 : a-jeanp Created // 08/06/2003: alexsn - Changes that allow more classes to be derived from Simple // Description update //--------------------------------------------------------------------------- // PRESHARP: In order to avoid generating warnings about unkown message numbers and unknown pragmas. #pragma warning disable 1634, 1691 using System; using System.Text; using System.Windows.Automation; using System.Windows.Automation.Provider; using System.Runtime.InteropServices; using System.ComponentModel; using System.Collections; using Accessibility; using System.Windows; using System.Windows.Input; using MS.Win32; namespace MS.Internal.AutomationProxies { // Base Class for all the Windows Control. // Implements the default behavior // // The distinction between Proxy siblings is made through an ID (called _item). // The underlying hwnd is kept, as the proxy parent and a flag to _fSubtree. class ProxySimple : IRawElementProviderSimple, IRawElementProviderFragment { // ----------------------------------------------------- // // Constructors // // ----------------------------------------------------- #region Constructors // Constructor. // Param "hwnd" is the handle to underlying window // Param "parent" is the Parent, must be a ProxyFragment // Param "item" is the ID of item to represent internal ProxySimple(IntPtr hwnd, ProxyFragment parent, int item) { _hwnd = hwnd; _item = item; _parent = parent; // is element a leaf? _fSubTree = (_parent != null); } #endregion // ------------------------------------------------------ // // Patterns Implementation // // ----------------------------------------------------- #region ProxySimple Methods internal virtual ProviderOptions ProviderOptions { get { return ProviderOptions.ClientSideProvider; } } // Returns the bounding rectangle of the control. // If the control is not an hwnd, the subclass should implement this call internal virtual Rect BoundingRectangle { get { if (_hwnd == IntPtr.Zero) { return Rect.Empty; } NativeMethods.Win32Rect controlRectangle = NativeMethods.Win32Rect.Empty; if (!Misc.GetWindowRect(_hwnd, ref controlRectangle)) { return Rect.Empty; } // Don't normalize, consumers & subclasses will normalize with conditionals return controlRectangle.ToRect(false); } } // Sets the focus to this item. // By default, fails internal virtual bool SetFocus() { return false; } // Returns the Run Time Id. // // The RunTimeID is a array of int with RID [0] set to 1 and RID [1] the hwnd // identifier. The remaining of the chain are values one per sub node in // the raw element tree. // Avalon and other none hwnd based elements have RunTimeIDs that never starts // with '1'. This makes the RunTimeId for Win32 controls uniq. // // By default the _item data member is used as ID for each depth // in the element tree internal virtual int [] GetRuntimeId () { if (_fSubTree && !IsHwndElement()) { // add the id for this level at the end of the chain return Misc.AppendToRuntimeId(GetParent().GetRuntimeId(), _item); } else { // UIA handles runtimeID for the HWND part for us return null; } } // Get unique ID for this element... // This is the internal version of GetRuntimeId called when a complete RuntimeId is needed internally (e.g. // RuntimeId is needed to create StructureChangedEventArgs) vs when UIAutomation asks for a RuntimeId // through IRawElementProviderFragment. WCTL #32188 : We need a helper method in UIAutomationCore that takes // an hwnd and returns a RuntimeId. Symptom of this being broken is getting InvalidOperationException // during events with message: Value cannot be null. Parameter name: runtimeId. internal int[] MakeRuntimeId() { int idLen = ( _fSubTree && !IsHwndElement() ) ? 3 : 2; int[] id = new int[idLen]; // Base runtime id is the number indicating Win32Provider + hwnd id[0] = ProxySimple.Win32ProviderRuntimeIdBase; id[1] = _hwnd.ToInt32(); // Append part id to make this unique if ( idLen == 3 ) { id[2] = _item; } return id; } internal virtual IRawElementProviderSimple HostRawElementProvider { get { if (_hwnd == IntPtr.Zero || (GetParent() != null && GetParent()._hwnd == _hwnd)) { return null; } return AutomationInteropProvider.HostProviderFromHandle(_hwnd); } } internal virtual ProxySimple GetParent() { return _parent; } // Process all the Element Properties internal virtual object GetElementProperty(AutomationProperty idProp) { // we can handle some properties locally if (idProp == AutomationElement.LocalizedControlTypeProperty) { return _sType; } else if(idProp == AutomationElement.ControlTypeProperty) { return _cControlType != null ? (object)_cControlType.Id : null; } else if (idProp == AutomationElement.IsContentElementProperty) { return _item >= 0 && _fIsContent; } else if (idProp == AutomationElement.NameProperty) { return LocalizedName; } else if (idProp == AutomationElement.AccessKeyProperty) { return GetAccessKey(); } else if (idProp == AutomationElement.IsEnabledProperty) { return Misc.IsEnabled(_hwnd); } else if (idProp == AutomationElement.IsKeyboardFocusableProperty) { return IsKeyboardFocusable(); } else if (idProp == AutomationElement.ProcessIdProperty) { // Get the pid of the process that the HWND lives in, not the // pid that this proxy lives in uint pid; Misc.GetWindowThreadProcessId(_hwnd, out pid); return (int)pid; } else if (idProp == AutomationElement.ClickablePointProperty) { NativeMethods.Win32Point pt = new NativeMethods.Win32Point(); if (GetClickablePoint(out pt, !IsHwndElement())) { // Due to P/Invoke marshalling issues, the reurn value is in the // form of a {x,y} array instead of using the Point datatype return new double[] { pt.x, pt.y }; } return AutomationElement.NotSupported; } else if (idProp == AutomationElement.HasKeyboardFocusProperty) { // Check first if the hwnd has the Focus // Punt if not the case, drill down otherwise // If already focused, leave as-is. Calling SetForegroundWindow // on an already focused HWND will remove focus! return Misc.GetFocusedWindow() == _hwnd ? IsFocused() : false; } else if (idProp == AutomationElement.AutomationIdProperty) { // PerSharp/PreFast will flag this as a warning 6507/56507: Prefer 'string.IsNullOrEmpty(_sAutomationId)' over checks for null and/or emptiness. // _sAutomationId being null is invalid, while being empty is a valid state. // The use of IsNullOrEmpty while hide this. #pragma warning suppress 6507 System.Diagnostics.Debug.Assert(_sAutomationId != null, "_sAutomationId is null!"); #pragma warning suppress 6507 return _sAutomationId.Length > 0 ? _sAutomationId : null; } else if (idProp == AutomationElement.IsOffscreenProperty) { return IsOffscreen(); } else if (idProp == AutomationElement.HelpTextProperty) { return HelpText; } else if (idProp == AutomationElement.FrameworkIdProperty) { return WindowsFormsHelper.IsWindowsFormsControl(_hwnd) ? "WinForm" : "Win32"; } return null; } internal virtual bool IsKeyboardFocusable() { // if it curently has focus it is obviosly focusable if (Misc.GetFocusedWindow() == _hwnd && IsFocused()) { return true; } // If it's visible and enabled it might be focusable if (SafeNativeMethods.IsWindowVisible(_hwnd) && (bool)GetElementProperty(AutomationElement.IsEnabledProperty)) { // If it is something that we know is focusable and have marked it that way in the specific // proxy it should be focusable. if (IsHwndElement()) { // For a control that has the WS_TABSTOP style set, it should be focusable. // Toolbars are genrealy not focusable but the short cut toolbar on the start menu is. // The WS_TABSTOP will pick this up. if (Misc.IsBitSet(WindowStyle, NativeMethods.WS_TABSTOP)) { return true; } else { return _fIsKeyboardFocusable; } } else { return _fIsKeyboardFocusable; } } return false; } internal virtual bool IsOffscreen() { Rect itemRect = BoundingRectangle; if (itemRect.IsEmpty) { return true; } // As per the specs, IsOffscreen only takes immediate parent-child relationship into account, // so we only need to check if this item in offscreen with respect to its immediate parent. ProxySimple parent = GetParent(); if (parent != null ) { if ((bool)parent.GetElementProperty(AutomationElement.IsOffscreenProperty)) { return true; } // Now check to see if this item in visible on its parent Rect parentRect = parent.BoundingRectangle; if (!parentRect.IsEmpty && !Misc.IsItemVisible(ref parentRect, ref itemRect)) { return true; } } // if this element is not on any monitor than it is off the screen. NativeMethods.Win32Rect itemWin32Rect = new NativeMethods.Win32Rect(itemRect); return UnsafeNativeMethods.MonitorFromRect(ref itemWin32Rect, UnsafeNativeMethods.MONITOR_DEFAULTTONULL) == IntPtr.Zero; } internal virtual string GetAccessKey() { // If the control is part of a dialog box or a form, // get the accelerator from the static preceding that control // on the dialog. if (GetParent() == null && (bool)GetElementProperty(AutomationElement.IsKeyboardFocusableProperty)) { string sRawName = Misc.GetControlName(_hwnd, false); return string.IsNullOrEmpty(sRawName) ? null : Misc.AccessKey(sRawName); } return null; } // Returns a pattern interface if supported. internal virtual object GetPatternProvider(AutomationPattern iid) { return null; } internal virtual ProxySimple[] GetEmbeddedFragmentRoots() { return null; } //Gets the controls help text internal virtual string HelpText { get { return null; } } // Gets the localized name internal virtual string LocalizedName { get { return null; } } #endregion #region Dispatch Event // Dispatch WinEvent notifications // // A Generic mechanism is implemented to support most WinEvents. // On reception of a WinEvent, a Proxy is created and a call to this method // is made. This method then raises a UIAutomation Events based on the // WinEvents IDs. The old value for a property is always set to null internal virtual void DispatchEvents(int eventId, object idProp, int idObject, int idChild) { EventManager.DispatchEvent(this, _hwnd, eventId, idProp, idObject); } internal virtual void RecursiveRaiseEvents(object idProp, AutomationPropertyChangedEventArgs e) { return; } #endregion #region IRawElementProviderSimple // ------------------------------------------------------ // // Default implementation for the IRawElementProviderSimple. // Maps the UIAutomation methods to ProxySimple methods. // // ------------------------------------------------------ ProviderOptions IRawElementProviderSimple.ProviderOptions { get { return ProviderOptions; } } // Return the context associated with this element IRawElementProviderSimple IRawElementProviderSimple.HostRawElementProvider { get { return HostRawElementProvider; } } // Request the closest rectangle encompassing this element Rect IRawElementProviderFragment.BoundingRectangle { get { // Spec says that if an element is offscreen, we have the option of letting // the rect pass through or returning Rect.Empty; here, we intentionally // let it pass through as a convenience for MITA. // ProxySimple.BoundingRectanlgle return BoundingRectangle; } } // Request to return the element in the specified direction // ProxySimple object are leaf so it returns null except for the parent IRawElementProviderFragment IRawElementProviderFragment.Navigate(NavigateDirection direction) { System.Diagnostics.Debug.Assert(_parent != null, "Navigate: Leaf element does not have parent"); switch (direction) { case NavigateDirection.Parent: { return GetParent(); } case NavigateDirection.NextSibling: { // NOTE: Do not use GetParent(), call _parent explicitly return _parent.GetNextSibling(this); } case NavigateDirection.PreviousSibling: { // NOTE: Do not use GetParent(), call _parent explicitly return _parent.GetPreviousSibling(this); } } return null; } IRawElementProviderFragmentRoot IRawElementProviderFragment.FragmentRoot { // NOTE: The implementation below is correct one. // DO NOT CHANGE IT, since things will break // There can be only 1 ROOT for each constellation get { // Traverse up the parents until you find a node with no parents, this is the root ProxySimple walk = this; while (walk.GetParent() != null) { walk = walk.GetParent(); } return walk as IRawElementProviderFragmentRoot; } } // Returns the Run Time Id, an array of ints as the concatenation of IDs. int [] IRawElementProviderFragment.GetRuntimeId () { //ProxySimple.GetRuntimeId (); return GetRuntimeId (); } // Returns a pattern interface if supported. object IRawElementProviderSimple.GetPatternProvider(int patternId) { AutomationPattern iid = AutomationPattern.LookupById(patternId); return GetPatternProvider(iid); } // Returns a given property // UIAutomation as a generic call for all the properties for all the patterns. // This routine splits properties per pattern and calls the appropriate routine // within a pattern. // A default implementation is provided for some properties object IRawElementProviderSimple.GetPropertyValue(int propertyId) { AutomationProperty idProp = AutomationProperty.LookupById(propertyId); return GetElementProperty(idProp); } // If this UI is capable of hosting other UI that also supports UIAutomation, // and the subtree rooted at this element contains such hosted UI fragments, // this should return an array of those fragments. // // If this UI does not host other UI, it may return null. IRawElementProviderSimple[] IRawElementProviderFragment.GetEmbeddedFragmentRoots() { return GetEmbeddedFragmentRoots(); } // Request that focus is set to this item. // The UIAutomation framework will ensure that the UI hosting this fragment // is already focused before calling this method, so this method should only // update its internal focus state; it should not attempt to give its own // HWND the focus, for example. void IRawElementProviderFragment.SetFocus() { // Make sure that the control is enabled if (!SafeNativeMethods.IsWindowEnabled(_hwnd)) { throw new ElementNotEnabledException(); } // A number of the Override Proxies return null from the GetElementProperty() method. If // a SetFocus() was called on them, the case to bool will cause a NullReferenceException. // So make sure the return is of type bool before casting. bool isKeyboardFocusable = true; object isKeyboardFocusableProperty = GetElementProperty(AutomationElement.IsKeyboardFocusableProperty); if (isKeyboardFocusableProperty is bool) { isKeyboardFocusable = (bool)isKeyboardFocusableProperty; } // UIAutomation already focuses the containing HWND for us, so only need to // set focus on the item within that... if (isKeyboardFocusable) { // Then set the focus on this item (virtual methods) SetFocus(); return; } throw new InvalidOperationException(SR.Get(SRID.SetFocusFailed)); } #endregion //----------------------------------------------------- // // Internal Methods // //------------------------------------------------------ #region Internal Methods // Returns the clickable point on the element // In the case when clickable point is obtained - method returns true // In the case when clickable point cannot be obtained - method returns false internal bool GetClickablePoint(out NativeMethods.Win32Point pt, bool fClipClientRect) { NativeMethods.Win32Rect rcItem = new NativeMethods.Win32Rect(BoundingRectangle); // Intersect the bounding Rectangle with the client rectangle for framents // and simple items - use the override flag (used mostly for the non client area if (fClipClientRect && !_fNonClientAreaElement) { NativeMethods.Win32Rect rcOutside = new NativeMethods.Win32Rect(); Misc.GetClientRectInScreenCoordinates(_hwnd, ref rcOutside); if (!Misc.IntersectRect(ref rcItem, ref rcOutside, ref rcItem)) { pt.x = pt.y = 0; return false; } } ArrayList alIn = new ArrayList(100); ArrayList alOut = new ArrayList(100); // Get the mid point to start with pt.x = (rcItem.right - 1 + rcItem.left) / 2; pt.y = (rcItem.bottom - 1 + rcItem.top) / 2; alOut.Add(new ClickablePoint.CPRect(ref rcItem, true)); // First go through all the children to exclude whatever is on top ProxyFragment proxyFrag = this as ProxyFragment; if (proxyFrag != null) { ClickablePoint.ExcludeChildren(proxyFrag, alIn, alOut); } return ClickablePoint.GetPoint(_hwnd, alIn, alOut, ref pt); } internal string GetAccessibleName(int item) { string name = null; IAccessible acc = AccessibleObject; if (acc != null) { name = acc.get_accName(item); name = string.IsNullOrEmpty(name) ? null : name; } return name; } #endregion // ----------------------------------------------------- // // Internal Properties // // ----------------------------------------------------- #region Internal Properties // Returns the IAccessible interface for the container object internal virtual IAccessible AccessibleObject { get { if (_IAccessible == null) { Accessible acc = null; // We need to go search for it _IAccessible = Accessible.AccessibleObjectFromWindow(_hwnd, NativeMethods.OBJID_CLIENT, ref acc) == NativeMethods.S_OK ? acc.IAccessible : null; } return _IAccessible; } set { _IAccessible = value; } } // Get the hwnd for this element internal IntPtr WindowHandle { get { return _hwnd; } } // Reference to the window Handle internal int WindowStyle { get { return Misc.GetWindowStyle(_hwnd); } } //Gets the extended style of the window internal int WindowExStyle { get { return Misc.GetWindowExStyle(_hwnd); } } #endregion // ----------------------------------------------------- // // Internal Fields // // ------------------------------------------------------ #region Internal Fields // Reference to the window Handle internal IntPtr _hwnd; // Is used to discriminate between items in a collection. internal int _item; // Parent of a subtree. internal ProxyFragment _parent; // Localized Control type name. If the control has a ControlType this should not be set. internal string _sType; // Must be set by a subclass, used to return the automation id internal string _sAutomationId = ""; // Used by the IsFocussable Property. // By default all elements are not Keyboard focusable, overide this flag // to change the default behavior. internal bool _fIsKeyboardFocusable; // Top level Desktop window internal static IntPtr _hwndDesktop = UnsafeNativeMethods.GetDesktopWindow(); // Identifies an element as hwnd-based; used as the first value in RuntimeId for Win32 providers. internal const int Win32ProviderRuntimeIdBase = 1; #endregion // ----------------------------------------------------- // // Protected Methods // // ------------------------------------------------------ #region Protected Methods // This routine is only called on elements belonging to an hwnd // that has the focus. // Overload this routine for sub elements within an hwnd that can // have the focus, tab items, listbox items ... // The default implemention is to return true for proxy element // that are hwnd. protected virtual bool IsFocused () { return this is ProxyHwnd; } protected bool IsHwndElement() { return this is ProxyHwnd; } #endregion // ------------------------------------------------------ // // Protected Fields // // ----------------------------------------------------- #region Protected Fields // True if this is a WindowsForms control. // This value is cached and calculated only when needed protected WindowsFormsHelper.FormControlState _windowsForms = WindowsFormsHelper.FormControlState.Undeterminate; // Which Controltype it is, Must be set by a subclass protected ControlType _cControlType; // Must be set by a subclass, // Prevents the generic generation of the persistent IDs protected bool _fHasPersistentID = true; // Used by the GetClickablePoint Logic to figure out if clipping // must happen on the Client Rect or the Non ClientRect protected bool _fNonClientAreaElement; // true if the parent is of type ProxyFragment protected bool _fSubTree; // Tells whether then control is Content or Peripheral protected bool _fIsContent = true; // The IAccessible interface associated with this node protected IAccessible _IAccessible; #endregion } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved. //---------------------------------------------------------------------------- // //// Copyright (C) Microsoft Corporation. All rights reserved. // // // // Description: Base class for all the Win32 and office Controls. // // The ProxySimple class is the base class for the leafs // in the raw element tree. Also proxy that directly derives // from this clas should not care about events // // The UIAutomation Simple class is limited to UI elements that are // Hwnd based. This makes it of little use for Win32 and office controls. // The ProxySimple class removes this limitation. This leads to a couple of // changes; RuntTimeID and BoundingRect must be implemented by this object. // // // Class ProxySimple: IRawElementProviderFragment, IRawElementProviderSimple // BoundingRectangle // RuntimeId // Properties // GetPatterns // SetFocus // // Example: ComboboxButton, MenuItem, Office CommandBar button, ListViewSubitem // // // // History: // 07/01/2003 : a-jeanp Created // 08/06/2003: alexsn - Changes that allow more classes to be derived from Simple // Description update //--------------------------------------------------------------------------- // PRESHARP: In order to avoid generating warnings about unkown message numbers and unknown pragmas. #pragma warning disable 1634, 1691 using System; using System.Text; using System.Windows.Automation; using System.Windows.Automation.Provider; using System.Runtime.InteropServices; using System.ComponentModel; using System.Collections; using Accessibility; using System.Windows; using System.Windows.Input; using MS.Win32; namespace MS.Internal.AutomationProxies { // Base Class for all the Windows Control. // Implements the default behavior // // The distinction between Proxy siblings is made through an ID (called _item). // The underlying hwnd is kept, as the proxy parent and a flag to _fSubtree. class ProxySimple : IRawElementProviderSimple, IRawElementProviderFragment { // ----------------------------------------------------- // // Constructors // // ----------------------------------------------------- #region Constructors // Constructor. // Param "hwnd" is the handle to underlying window // Param "parent" is the Parent, must be a ProxyFragment // Param "item" is the ID of item to represent internal ProxySimple(IntPtr hwnd, ProxyFragment parent, int item) { _hwnd = hwnd; _item = item; _parent = parent; // is element a leaf? _fSubTree = (_parent != null); } #endregion // ------------------------------------------------------ // // Patterns Implementation // // ----------------------------------------------------- #region ProxySimple Methods internal virtual ProviderOptions ProviderOptions { get { return ProviderOptions.ClientSideProvider; } } // Returns the bounding rectangle of the control. // If the control is not an hwnd, the subclass should implement this call internal virtual Rect BoundingRectangle { get { if (_hwnd == IntPtr.Zero) { return Rect.Empty; } NativeMethods.Win32Rect controlRectangle = NativeMethods.Win32Rect.Empty; if (!Misc.GetWindowRect(_hwnd, ref controlRectangle)) { return Rect.Empty; } // Don't normalize, consumers & subclasses will normalize with conditionals return controlRectangle.ToRect(false); } } // Sets the focus to this item. // By default, fails internal virtual bool SetFocus() { return false; } // Returns the Run Time Id. // // The RunTimeID is a array of int with RID [0] set to 1 and RID [1] the hwnd // identifier. The remaining of the chain are values one per sub node in // the raw element tree. // Avalon and other none hwnd based elements have RunTimeIDs that never starts // with '1'. This makes the RunTimeId for Win32 controls uniq. // // By default the _item data member is used as ID for each depth // in the element tree internal virtual int [] GetRuntimeId () { if (_fSubTree && !IsHwndElement()) { // add the id for this level at the end of the chain return Misc.AppendToRuntimeId(GetParent().GetRuntimeId(), _item); } else { // UIA handles runtimeID for the HWND part for us return null; } } // Get unique ID for this element... // This is the internal version of GetRuntimeId called when a complete RuntimeId is needed internally (e.g. // RuntimeId is needed to create StructureChangedEventArgs) vs when UIAutomation asks for a RuntimeId // through IRawElementProviderFragment. WCTL #32188 : We need a helper method in UIAutomationCore that takes // an hwnd and returns a RuntimeId. Symptom of this being broken is getting InvalidOperationException // during events with message: Value cannot be null. Parameter name: runtimeId. internal int[] MakeRuntimeId() { int idLen = ( _fSubTree && !IsHwndElement() ) ? 3 : 2; int[] id = new int[idLen]; // Base runtime id is the number indicating Win32Provider + hwnd id[0] = ProxySimple.Win32ProviderRuntimeIdBase; id[1] = _hwnd.ToInt32(); // Append part id to make this unique if ( idLen == 3 ) { id[2] = _item; } return id; } internal virtual IRawElementProviderSimple HostRawElementProvider { get { if (_hwnd == IntPtr.Zero || (GetParent() != null && GetParent()._hwnd == _hwnd)) { return null; } return AutomationInteropProvider.HostProviderFromHandle(_hwnd); } } internal virtual ProxySimple GetParent() { return _parent; } // Process all the Element Properties internal virtual object GetElementProperty(AutomationProperty idProp) { // we can handle some properties locally if (idProp == AutomationElement.LocalizedControlTypeProperty) { return _sType; } else if(idProp == AutomationElement.ControlTypeProperty) { return _cControlType != null ? (object)_cControlType.Id : null; } else if (idProp == AutomationElement.IsContentElementProperty) { return _item >= 0 && _fIsContent; } else if (idProp == AutomationElement.NameProperty) { return LocalizedName; } else if (idProp == AutomationElement.AccessKeyProperty) { return GetAccessKey(); } else if (idProp == AutomationElement.IsEnabledProperty) { return Misc.IsEnabled(_hwnd); } else if (idProp == AutomationElement.IsKeyboardFocusableProperty) { return IsKeyboardFocusable(); } else if (idProp == AutomationElement.ProcessIdProperty) { // Get the pid of the process that the HWND lives in, not the // pid that this proxy lives in uint pid; Misc.GetWindowThreadProcessId(_hwnd, out pid); return (int)pid; } else if (idProp == AutomationElement.ClickablePointProperty) { NativeMethods.Win32Point pt = new NativeMethods.Win32Point(); if (GetClickablePoint(out pt, !IsHwndElement())) { // Due to P/Invoke marshalling issues, the reurn value is in the // form of a {x,y} array instead of using the Point datatype return new double[] { pt.x, pt.y }; } return AutomationElement.NotSupported; } else if (idProp == AutomationElement.HasKeyboardFocusProperty) { // Check first if the hwnd has the Focus // Punt if not the case, drill down otherwise // If already focused, leave as-is. Calling SetForegroundWindow // on an already focused HWND will remove focus! return Misc.GetFocusedWindow() == _hwnd ? IsFocused() : false; } else if (idProp == AutomationElement.AutomationIdProperty) { // PerSharp/PreFast will flag this as a warning 6507/56507: Prefer 'string.IsNullOrEmpty(_sAutomationId)' over checks for null and/or emptiness. // _sAutomationId being null is invalid, while being empty is a valid state. // The use of IsNullOrEmpty while hide this. #pragma warning suppress 6507 System.Diagnostics.Debug.Assert(_sAutomationId != null, "_sAutomationId is null!"); #pragma warning suppress 6507 return _sAutomationId.Length > 0 ? _sAutomationId : null; } else if (idProp == AutomationElement.IsOffscreenProperty) { return IsOffscreen(); } else if (idProp == AutomationElement.HelpTextProperty) { return HelpText; } else if (idProp == AutomationElement.FrameworkIdProperty) { return WindowsFormsHelper.IsWindowsFormsControl(_hwnd) ? "WinForm" : "Win32"; } return null; } internal virtual bool IsKeyboardFocusable() { // if it curently has focus it is obviosly focusable if (Misc.GetFocusedWindow() == _hwnd && IsFocused()) { return true; } // If it's visible and enabled it might be focusable if (SafeNativeMethods.IsWindowVisible(_hwnd) && (bool)GetElementProperty(AutomationElement.IsEnabledProperty)) { // If it is something that we know is focusable and have marked it that way in the specific // proxy it should be focusable. if (IsHwndElement()) { // For a control that has the WS_TABSTOP style set, it should be focusable. // Toolbars are genrealy not focusable but the short cut toolbar on the start menu is. // The WS_TABSTOP will pick this up. if (Misc.IsBitSet(WindowStyle, NativeMethods.WS_TABSTOP)) { return true; } else { return _fIsKeyboardFocusable; } } else { return _fIsKeyboardFocusable; } } return false; } internal virtual bool IsOffscreen() { Rect itemRect = BoundingRectangle; if (itemRect.IsEmpty) { return true; } // As per the specs, IsOffscreen only takes immediate parent-child relationship into account, // so we only need to check if this item in offscreen with respect to its immediate parent. ProxySimple parent = GetParent(); if (parent != null ) { if ((bool)parent.GetElementProperty(AutomationElement.IsOffscreenProperty)) { return true; } // Now check to see if this item in visible on its parent Rect parentRect = parent.BoundingRectangle; if (!parentRect.IsEmpty && !Misc.IsItemVisible(ref parentRect, ref itemRect)) { return true; } } // if this element is not on any monitor than it is off the screen. NativeMethods.Win32Rect itemWin32Rect = new NativeMethods.Win32Rect(itemRect); return UnsafeNativeMethods.MonitorFromRect(ref itemWin32Rect, UnsafeNativeMethods.MONITOR_DEFAULTTONULL) == IntPtr.Zero; } internal virtual string GetAccessKey() { // If the control is part of a dialog box or a form, // get the accelerator from the static preceding that control // on the dialog. if (GetParent() == null && (bool)GetElementProperty(AutomationElement.IsKeyboardFocusableProperty)) { string sRawName = Misc.GetControlName(_hwnd, false); return string.IsNullOrEmpty(sRawName) ? null : Misc.AccessKey(sRawName); } return null; } // Returns a pattern interface if supported. internal virtual object GetPatternProvider(AutomationPattern iid) { return null; } internal virtual ProxySimple[] GetEmbeddedFragmentRoots() { return null; } //Gets the controls help text internal virtual string HelpText { get { return null; } } // Gets the localized name internal virtual string LocalizedName { get { return null; } } #endregion #region Dispatch Event // Dispatch WinEvent notifications // // A Generic mechanism is implemented to support most WinEvents. // On reception of a WinEvent, a Proxy is created and a call to this method // is made. This method then raises a UIAutomation Events based on the // WinEvents IDs. The old value for a property is always set to null internal virtual void DispatchEvents(int eventId, object idProp, int idObject, int idChild) { EventManager.DispatchEvent(this, _hwnd, eventId, idProp, idObject); } internal virtual void RecursiveRaiseEvents(object idProp, AutomationPropertyChangedEventArgs e) { return; } #endregion #region IRawElementProviderSimple // ------------------------------------------------------ // // Default implementation for the IRawElementProviderSimple. // Maps the UIAutomation methods to ProxySimple methods. // // ------------------------------------------------------ ProviderOptions IRawElementProviderSimple.ProviderOptions { get { return ProviderOptions; } } // Return the context associated with this element IRawElementProviderSimple IRawElementProviderSimple.HostRawElementProvider { get { return HostRawElementProvider; } } // Request the closest rectangle encompassing this element Rect IRawElementProviderFragment.BoundingRectangle { get { // Spec says that if an element is offscreen, we have the option of letting // the rect pass through or returning Rect.Empty; here, we intentionally // let it pass through as a convenience for MITA. // ProxySimple.BoundingRectanlgle return BoundingRectangle; } } // Request to return the element in the specified direction // ProxySimple object are leaf so it returns null except for the parent IRawElementProviderFragment IRawElementProviderFragment.Navigate(NavigateDirection direction) { System.Diagnostics.Debug.Assert(_parent != null, "Navigate: Leaf element does not have parent"); switch (direction) { case NavigateDirection.Parent: { return GetParent(); } case NavigateDirection.NextSibling: { // NOTE: Do not use GetParent(), call _parent explicitly return _parent.GetNextSibling(this); } case NavigateDirection.PreviousSibling: { // NOTE: Do not use GetParent(), call _parent explicitly return _parent.GetPreviousSibling(this); } } return null; } IRawElementProviderFragmentRoot IRawElementProviderFragment.FragmentRoot { // NOTE: The implementation below is correct one. // DO NOT CHANGE IT, since things will break // There can be only 1 ROOT for each constellation get { // Traverse up the parents until you find a node with no parents, this is the root ProxySimple walk = this; while (walk.GetParent() != null) { walk = walk.GetParent(); } return walk as IRawElementProviderFragmentRoot; } } // Returns the Run Time Id, an array of ints as the concatenation of IDs. int [] IRawElementProviderFragment.GetRuntimeId () { //ProxySimple.GetRuntimeId (); return GetRuntimeId (); } // Returns a pattern interface if supported. object IRawElementProviderSimple.GetPatternProvider(int patternId) { AutomationPattern iid = AutomationPattern.LookupById(patternId); return GetPatternProvider(iid); } // Returns a given property // UIAutomation as a generic call for all the properties for all the patterns. // This routine splits properties per pattern and calls the appropriate routine // within a pattern. // A default implementation is provided for some properties object IRawElementProviderSimple.GetPropertyValue(int propertyId) { AutomationProperty idProp = AutomationProperty.LookupById(propertyId); return GetElementProperty(idProp); } // If this UI is capable of hosting other UI that also supports UIAutomation, // and the subtree rooted at this element contains such hosted UI fragments, // this should return an array of those fragments. // // If this UI does not host other UI, it may return null. IRawElementProviderSimple[] IRawElementProviderFragment.GetEmbeddedFragmentRoots() { return GetEmbeddedFragmentRoots(); } // Request that focus is set to this item. // The UIAutomation framework will ensure that the UI hosting this fragment // is already focused before calling this method, so this method should only // update its internal focus state; it should not attempt to give its own // HWND the focus, for example. void IRawElementProviderFragment.SetFocus() { // Make sure that the control is enabled if (!SafeNativeMethods.IsWindowEnabled(_hwnd)) { throw new ElementNotEnabledException(); } // A number of the Override Proxies return null from the GetElementProperty() method. If // a SetFocus() was called on them, the case to bool will cause a NullReferenceException. // So make sure the return is of type bool before casting. bool isKeyboardFocusable = true; object isKeyboardFocusableProperty = GetElementProperty(AutomationElement.IsKeyboardFocusableProperty); if (isKeyboardFocusableProperty is bool) { isKeyboardFocusable = (bool)isKeyboardFocusableProperty; } // UIAutomation already focuses the containing HWND for us, so only need to // set focus on the item within that... if (isKeyboardFocusable) { // Then set the focus on this item (virtual methods) SetFocus(); return; } throw new InvalidOperationException(SR.Get(SRID.SetFocusFailed)); } #endregion //----------------------------------------------------- // // Internal Methods // //------------------------------------------------------ #region Internal Methods // Returns the clickable point on the element // In the case when clickable point is obtained - method returns true // In the case when clickable point cannot be obtained - method returns false internal bool GetClickablePoint(out NativeMethods.Win32Point pt, bool fClipClientRect) { NativeMethods.Win32Rect rcItem = new NativeMethods.Win32Rect(BoundingRectangle); // Intersect the bounding Rectangle with the client rectangle for framents // and simple items - use the override flag (used mostly for the non client area if (fClipClientRect && !_fNonClientAreaElement) { NativeMethods.Win32Rect rcOutside = new NativeMethods.Win32Rect(); Misc.GetClientRectInScreenCoordinates(_hwnd, ref rcOutside); if (!Misc.IntersectRect(ref rcItem, ref rcOutside, ref rcItem)) { pt.x = pt.y = 0; return false; } } ArrayList alIn = new ArrayList(100); ArrayList alOut = new ArrayList(100); // Get the mid point to start with pt.x = (rcItem.right - 1 + rcItem.left) / 2; pt.y = (rcItem.bottom - 1 + rcItem.top) / 2; alOut.Add(new ClickablePoint.CPRect(ref rcItem, true)); // First go through all the children to exclude whatever is on top ProxyFragment proxyFrag = this as ProxyFragment; if (proxyFrag != null) { ClickablePoint.ExcludeChildren(proxyFrag, alIn, alOut); } return ClickablePoint.GetPoint(_hwnd, alIn, alOut, ref pt); } internal string GetAccessibleName(int item) { string name = null; IAccessible acc = AccessibleObject; if (acc != null) { name = acc.get_accName(item); name = string.IsNullOrEmpty(name) ? null : name; } return name; } #endregion // ----------------------------------------------------- // // Internal Properties // // ----------------------------------------------------- #region Internal Properties // Returns the IAccessible interface for the container object internal virtual IAccessible AccessibleObject { get { if (_IAccessible == null) { Accessible acc = null; // We need to go search for it _IAccessible = Accessible.AccessibleObjectFromWindow(_hwnd, NativeMethods.OBJID_CLIENT, ref acc) == NativeMethods.S_OK ? acc.IAccessible : null; } return _IAccessible; } set { _IAccessible = value; } } // Get the hwnd for this element internal IntPtr WindowHandle { get { return _hwnd; } } // Reference to the window Handle internal int WindowStyle { get { return Misc.GetWindowStyle(_hwnd); } } //Gets the extended style of the window internal int WindowExStyle { get { return Misc.GetWindowExStyle(_hwnd); } } #endregion // ----------------------------------------------------- // // Internal Fields // // ------------------------------------------------------ #region Internal Fields // Reference to the window Handle internal IntPtr _hwnd; // Is used to discriminate between items in a collection. internal int _item; // Parent of a subtree. internal ProxyFragment _parent; // Localized Control type name. If the control has a ControlType this should not be set. internal string _sType; // Must be set by a subclass, used to return the automation id internal string _sAutomationId = ""; // Used by the IsFocussable Property. // By default all elements are not Keyboard focusable, overide this flag // to change the default behavior. internal bool _fIsKeyboardFocusable; // Top level Desktop window internal static IntPtr _hwndDesktop = UnsafeNativeMethods.GetDesktopWindow(); // Identifies an element as hwnd-based; used as the first value in RuntimeId for Win32 providers. internal const int Win32ProviderRuntimeIdBase = 1; #endregion // ----------------------------------------------------- // // Protected Methods // // ------------------------------------------------------ #region Protected Methods // This routine is only called on elements belonging to an hwnd // that has the focus. // Overload this routine for sub elements within an hwnd that can // have the focus, tab items, listbox items ... // The default implemention is to return true for proxy element // that are hwnd. protected virtual bool IsFocused () { return this is ProxyHwnd; } protected bool IsHwndElement() { return this is ProxyHwnd; } #endregion // ------------------------------------------------------ // // Protected Fields // // ----------------------------------------------------- #region Protected Fields // True if this is a WindowsForms control. // This value is cached and calculated only when needed protected WindowsFormsHelper.FormControlState _windowsForms = WindowsFormsHelper.FormControlState.Undeterminate; // Which Controltype it is, Must be set by a subclass protected ControlType _cControlType; // Must be set by a subclass, // Prevents the generic generation of the persistent IDs protected bool _fHasPersistentID = true; // Used by the GetClickablePoint Logic to figure out if clipping // must happen on the Client Rect or the Non ClientRect protected bool _fNonClientAreaElement; // true if the parent is of type ProxyFragment protected bool _fSubTree; // Tells whether then control is Content or Peripheral protected bool _fIsContent = true; // The IAccessible interface associated with this node protected IAccessible _IAccessible; #endregion } } // 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
- RoleService.cs
- WebPartConnectionsCancelEventArgs.cs
- AmbientProperties.cs
- DesignerProperties.cs
- HtmlString.cs
- CapabilitiesAssignment.cs
- SecuritySessionServerSettings.cs
- GridViewPageEventArgs.cs
- InputLanguage.cs
- ComponentFactoryHelpers.cs
- AxisAngleRotation3D.cs
- IgnoreSection.cs
- RequestChannel.cs
- GroupDescription.cs
- ValueChangedEventManager.cs
- Triangle.cs
- GridViewRowPresenter.cs
- MemberInfoSerializationHolder.cs
- ListViewTableCell.cs
- InfoCardTrace.cs
- DataTableMapping.cs
- Compiler.cs
- AppLevelCompilationSectionCache.cs
- TextFormatterContext.cs
- FromRequest.cs
- Page.cs
- MailWebEventProvider.cs
- TreeChangeInfo.cs
- AuthenticationModuleElementCollection.cs
- SubclassTypeValidatorAttribute.cs
- ToolTipService.cs
- Marshal.cs
- FirstMatchCodeGroup.cs
- HighlightVisual.cs
- CharacterMetrics.cs
- CustomValidator.cs
- PngBitmapDecoder.cs
- EditorZone.cs
- DataGridColumnCollection.cs
- TextClipboardData.cs
- CompilerResults.cs
- FolderBrowserDialog.cs
- SafeWaitHandle.cs
- DataServiceKeyAttribute.cs
- TextOutput.cs
- WebHeaderCollection.cs
- GenericRootAutomationPeer.cs
- DataSourceCacheDurationConverter.cs
- ExpandSegment.cs
- HandlerBase.cs
- ResourceSetExpression.cs
- DbConnectionStringBuilder.cs
- ClientScriptManager.cs
- CriticalFinalizerObject.cs
- mil_commands.cs
- TraceSwitch.cs
- NaturalLanguageHyphenator.cs
- AspNetSynchronizationContext.cs
- TextBoxBase.cs
- TemplatedEditableDesignerRegion.cs
- WebPermission.cs
- ExtendedPropertyCollection.cs
- ReadOnlyDataSourceView.cs
- CollectionType.cs
- CacheDependency.cs
- TableLayoutColumnStyleCollection.cs
- PublisherMembershipCondition.cs
- SiteOfOriginPart.cs
- ClientSideProviderDescription.cs
- RuleSettingsCollection.cs
- TextEditorCopyPaste.cs
- HybridCollection.cs
- IHttpResponseInternal.cs
- SQLByte.cs
- StreamWriter.cs
- TextOutput.cs
- X500Name.cs
- HashCryptoHandle.cs
- SoapHeaderAttribute.cs
- SocketStream.cs
- wgx_render.cs
- PersonalizationDictionary.cs
- InfoCardTrace.cs
- WebBrowserProgressChangedEventHandler.cs
- PopOutPanel.cs
- ProcessManager.cs
- WindowCollection.cs
- RichTextBox.cs
- DbCommandDefinition.cs
- ScrollBarRenderer.cs
- SqlDataSourceConnectionPanel.cs
- UIElementParagraph.cs
- LocalizationComments.cs
- Soap.cs
- CodeIterationStatement.cs
- ToolStripScrollButton.cs
- PolicyChain.cs
- HttpListenerRequestUriBuilder.cs
- RemotingAttributes.cs
- XmlBinaryReaderSession.cs