Code:
/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / wpf / src / UIAutomation / Win32Providers / MS / Internal / AutomationProxies / Accessible.cs / 1 / Accessible.cs
//----------------------------------------------------------------------------
//
//
// Copyright (C) Microsoft Corporation. All rights reserved.
//
//
//
// Description: Wraps some of IAccessible to support getting basic properties
// and default action
//
// History:
// 06/02/2003 : BrendanM Ported to WCP
// 03/15/2004 : Micw enhanced to support a native MSAA fallback proxy
//
//---------------------------------------------------------------------------
// PRESHARP: In order to avoid generating warnings about unkown message numbers and unknown pragmas.
#pragma warning disable 1634, 1691
using System;
using System.Diagnostics;
using System.Collections;
using System.Globalization;
using System.Threading;
using System.Windows.Automation;
using System.Windows;
using Accessibility;
using System.Text;
using System.Runtime.InteropServices;
using MS.Win32;
namespace MS.Internal.AutomationProxies
{
// values return from IAccessible.get_accRole.
internal enum AccessibleRole: int
{
TitleBar = 0x1,
MenuBar = 0x2,
ScrollBar = 0x3,
Grip = 0x4,
Sound = 0x5,
Cursor = 0x6,
Caret = 0x7,
Alert = 0x8,
Window = 0x9,
Client = 0xa,
MenuPopup = 0xb,
MenuItem = 0xc,
Tooltip = 0xd,
Application = 0xe,
Document = 0xf,
Pane = 0x10,
Chart = 0x11,
Dialog = 0x12,
Border = 0x13,
Grouping = 0x14,
Separator = 0x15,
ToolBar = 0x16,
StatusBar = 0x17,
Table = 0x18,
ColumnHeader = 0x19,
RowHeader = 0x1a,
Column = 0x1b,
Row = 0x1c,
Cell = 0x1d,
Link = 0x1e,
HelpBalloon = 0x1f,
Character = 0x20,
List = 0x21,
ListItem = 0x22,
Outline = 0x23,
OutlineItem = 0x24,
PageTab = 0x25,
PropertyPage = 0x26,
Indicator = 0x27,
Graphic = 0x28,
StaticText = 0x29,
Text = 0x2a,
PushButton = 0x2b,
CheckButton = 0x2c,
RadioButton = 0x2d,
Combobox = 0x2e,
DropList = 0x2f,
ProgressBar = 0x30,
Dial = 0x31,
HotKeyField = 0x32,
Slider = 0x33,
SpinButton = 0x34,
Diagram = 0x35,
Animation = 0x36,
Equation = 0x37,
ButtonDropDown = 0x38,
ButtonMenu = 0x39,
ButtonDropDownGrid = 0x3a,
Whitespace = 0x3b,
PageTabList = 0x3c,
Clock = 0x3d,
SplitButton = 0x3e,
IpAddress = 0x3f,
OutlineButton = 0x40,
}
// values returned from IAccessible.get_accState.
[Flags]
internal enum AccessibleState: int
{
Normal = 0x00000000,
Unavailable = 0x00000001,
Selected = 0x00000002,
Focused = 0x00000004,
Pressed = 0x00000008,
Checked = 0x00000010,
Mixed = 0x00000020,
ReadOnly = 0x00000040,
HotTracked = 0x00000080,
Default = 0x00000100,
Expanded = 0x00000200,
Collapsed = 0x00000400,
Busy = 0x00000800,
Floating = 0x00001000,
Marqueed = 0x00002000,
Animated = 0x00004000,
Invisible = 0x00008000,
Offscreen = 0x00010000,
Sizeable = 0x00020000,
Moveable = 0x00040000,
SelfVoicing = 0x00080000,
Focusable = 0x00100000,
Selectable = 0x00200000,
Linked = 0x00400000,
Traversed = 0x00800000,
Multiselectable = 0x01000000,
ExtSelectable = 0x02000000,
AlertLow = 0x04000000,
AlertMedium = 0x08000000,
AlertHigh = 0x10000000,
Protected = 0x20000000,
}
internal class Accessible
{
//-----------------------------------------------------
//
// Constructors
//
//-----------------------------------------------------
#region Constructors
//
// called by Wrap to create a node Accessible that manages its children
private Accessible(IAccessible acc, int idChild)
{
Debug.Assert(acc != null, "null IAccessible");
_acc = acc;
_idChild = idChild;
_accessibleChildrenIndex = -1;
}
// Here we are re-implementing AccessibleObjectFromEvent with a critical difference.
// AccessibleObjectFromEvent, via AccessibleObjectFromWindow, will default to a standard implementation
// of IAccessible if the window doesn't have a native implementation.
// However we only want to succeed constructing the object if the window has a native implementation.
internal static Accessible CreateNativeFromEvent(IntPtr hwnd, int idObject, int idChild)
{
// On Vista, pass PID as wParam - allows credUI scenario to work (OLEACC needs to know our PID to
// DuplicateHandle back to this process.)
IntPtr wParam = IntPtr.Zero;
if(Environment.OSVersion.Version.Major >= 6)
wParam = new IntPtr(UnsafeNativeMethods.GetCurrentProcessId());
// send the window a WM_GETOBJECT message requesting the specific object id.
IntPtr lResult = Misc.ProxySendMessage(hwnd, NativeMethods.WM_GETOBJECT, wParam, new IntPtr(idObject));
if (lResult == IntPtr.Zero)
{
return null;
}
// unwrap the pointer that was returned
IAccessible acc = null;
int hr = NativeMethods.S_FALSE;
try
{
hr = UnsafeNativeMethods.ObjectFromLresult(lResult, ref UnsafeNativeMethods.IID_IAccessible, wParam, ref acc);
}
catch (InvalidCastException)
{
// CLR remoting appears to be interfering in cases where the remote IAccessible is a Winforms control -
// the object we get back is a __Transparent proxy, and casting that to IAccessible fails with an exception
// (which is caught and ignored here). See bug #1110719 for details.
// One way around this is to use AccessibleObjectFromWindow - that returns IAccessible instead of IUnknown -
// in effect it does the case in unmanaged code, and seems to avoid this issue. Other winforms code in the
// proxies uses this approach. AccessibleObjectFromWindow will return an OLEACC proxy if one is available,
// however, so we can't use it here, as this code only wants to deal with native IAccessibles.
return null;
}
// ObjectFromLresult returns an IAccessible from the remote process. If that impl is managed, however, then
// the local CLR will set up a CLR-Remoting-based connection instead and bypass COM - this causes problems
// because CLR Remoting typically isn't initalized, so calls fail with a RemotingException: "This remoting
// proxy has no channel sink which means either the server has no registered server channels that are listening,
// or this application has no suitable client channel to talk to the server." - see bug #1519030. The local CLR
// detects that the remote object is a managed impl by QI'ing for a specifc interface (IManagedObject?).
// We can prevent this from happening by dropping the IAccessible we've gotten back from ObjectFromLresult,
// and instead use AccessibleObjectFromWindow: AOFW wraps the real IAccessible in a DynamicAnnotation wrapper
// that passes through all IAccessible (and related interface) calls - but it doesn't pass through the
// IManagedObject interface, so the CLR treats it as a COM object, and continues to use plain COM to access it,
// avoiding the CLR Remoting issues.
//
// In effect, we're sending WM_GETOBJECT to the HWND to see if there's a native impl there, using ObjectFromLresult
// just to free that object, and then using AccessibleObjectFromWindow on the window to get the IAccessible
// that we actually use. (Can't just use AccessibleObjectFromWindow from the start, since that would return
// an oleacc proxy for hwnds that don't support IAccessible natively, and we only care about actual IAccessible
// impls here.)
//
// We used to do use AOFW below only if the acc we got back above was a managed object (checked using
// !Marshal.IsComObject()) - that only protects us from managed IAccessibles we get back directly; we could
// still hit the above issue if we get back a remote unmanaged impl that then returns a maanged impl via
// navigation (Media Center does this). So we now use AOFW all the time.
if(hr == NativeMethods.S_OK && acc != null)
{
object obj = null;
hr = UnsafeNativeMethods.AccessibleObjectFromWindow(hwnd, idObject, ref UnsafeNativeMethods.IID_IUnknown, ref obj);
acc = obj as IAccessible;
}
if (hr != NativeMethods.S_OK || acc == null)
{
return null;
}
// This takes care of calling get_accChild, if necessary...
return AccessibleFromObject(idChild, acc);
}
#if DEBUG
/*
// strictly for debugging purposes:
public override string ToString()
{
try
{
return string.Format( "{0} \"{1}\" {2} {3}", RoleText, Name, _idChild, Window );
}
catch (Exception e)
{
return e.Message;
}
}
[DllImport( "oleacc.dll" )]
internal static extern int GetRoleText( int dwRole, StringBuilder lpszRole, int cchRoleMax );
private string RoleText
{
get
{
const int cch = 64;
StringBuilder sb = new StringBuilder( cch );
int len = GetRoleText( (int)Role, sb, cch );
return sb.ToString().Substring( 0, len );
}
}
*/
#endif
#endregion Constructors
//------------------------------------------------------
//
// Internal Methods
//
//-----------------------------------------------------
#region Internal Methods
// returns a new Accessible for the IAccessible, or null if IAccessible is null
internal static Accessible Wrap(IAccessible acc)
{
return Wrap(acc, NativeMethods.CHILD_SELF);
}
// returns a new Accessible for the IAccessible + child id, or null if IAccessible is null
internal static Accessible Wrap(IAccessible acc, int idChild)
{
return acc != null ? new Accessible(acc, idChild) : null;
}
internal IAccessible IAccessible { get { return _acc; } }
internal int ChildCount { get { return GetChildCount(_acc); } }
internal int ChildId { get { return _idChild; } }
internal string Description { get { return GetDescription(_acc, _idChild); } }
internal string KeyboardShortcut { get { return GetKeyboardShortcut(_acc, _idChild); } }
internal string Name { get { return GetName(_acc, _idChild); } }
internal string DefaultAction { get { return GetDefaultAction(_acc, _idChild); } }
internal AccessibleRole Role { get { return GetRole(_acc, _idChild); } }
internal bool IsPassword { get { return HasState(AccessibleState.Protected); } }
internal bool IsSelected { get { return HasState(AccessibleState.Selected); } }
internal bool IsMultiSelectable { get { return HasState(AccessibleState.Multiselectable); } }
internal bool IsIndeterminate { get { return HasState(AccessibleState.Mixed); } }
internal bool IsChecked { get { return HasState(AccessibleState.Checked); } }
internal bool IsReadOnly { get { return HasState(AccessibleState.ReadOnly); } }
internal bool IsEnabled { get { return ! HasState(AccessibleState.Unavailable); } }
internal bool IsFocused { get { return HasState(AccessibleState.Focused); } }
internal bool IsOffScreen { get { return HasState(AccessibleState.Offscreen); } }
internal Accessible FirstChild
{
get
{
return _idChild == NativeMethods.CHILD_SELF ? GetChildAt(_acc, null, 0) : null;
}
}
internal Accessible LastChild
{
get
{
return _idChild == NativeMethods.CHILD_SELF ? GetChildAt(_acc, null, Accessible.GetChildCount(_acc) - 1) : null;
}
}
internal Accessible NextSibling(Accessible parent)
{
Debug.Assert(parent != null);
// if this object doesn't yet have an index into parent's children find it
object[] children = null; // if we need to get children to find an index; re-use them
if (_accessibleChildrenIndex == -1)
{
children = SetAccessibleChildrenIndexAndGetChildren(parent._acc);
// if unable to find this child (broken IAccessible impl?) bail (
if (_accessibleChildrenIndex == -1)
{
Debug.Assert(false);
return null;
}
}
Accessible rval = null;
if (_accessibleChildrenIndex + 1 < Accessible.GetChildCount(parent._acc))
{
rval = GetChildAt(parent._acc, children, _accessibleChildrenIndex + 1);
}
return rval;
}
internal Accessible PreviousSibling(Accessible parent)
{
Debug.Assert(parent != null);
// if this object doesn't yet have an index into parent's children find it
object[] children = null; // if we need to get children to find an index; re-use them
if (_accessibleChildrenIndex == -1)
{
children = SetAccessibleChildrenIndexAndGetChildren(parent._acc);
// if unable to find this child (broken IAccessible impl?) bail (
if (_accessibleChildrenIndex == -1)
{
Debug.Assert(false);
return null;
}
}
Accessible rval = null;
if (_accessibleChildrenIndex - 1 >= 0)
{
rval = GetChildAt(parent._acc, children, _accessibleChildrenIndex - 1);
}
return rval;
}
internal Accessible Parent
{
get
{
//
// review: I think it might be better to throw an exception here than return a bogus value.
IAccessible rval;
if (_idChild != NativeMethods.CHILD_SELF)
{
rval = _acc; // parent is managing this child
}
else
{
try
{
rval = (IAccessible)_acc.accParent;
}
catch (Exception e)
{
if (HandleIAccessibleException(e))
{
// PerSharp/PreFast will flag this as a warning, 6503/56503: Property get methods should not throw exceptions.
// We are communicate with the underlying control to get the information.
// The control may not be able to give us the information we need.
// Throw the correct exception to communicate the failure.
#pragma warning suppress 6503
throw;
}
return null;
}
}
return Wrap(rval);
}
}
internal int AccessibleChildrenIndex(Accessible parent)
{
// if this is the first time we are called then compute the value and cache it.
if (_accessibleChildrenIndex < 0)
{
SetAccessibleChildrenIndexAndGetChildren(parent._acc);
}
return _accessibleChildrenIndex;
}
internal bool IsAvailableToUser
{
get
{
AccessibleState state = State;
// From MSDN:
// STATE_SYSTEM_INVISIBLE means the object is programmatically hidden. For example, menu items
// are programmatically hidden until a user activates the menu. Because objects with this
// state are not available to users, client applications should not communicate information
// about the object to users. However, if client applications find an object with this state,
// they should check to see if STATE_SYSTEM_OFFSCREEN is also set. If this second state is
// defined, then clients can communicate the information about the object to users.
//
// We're not dealing with menus [in this version of NativeMsaaProxy] so won't worry about them
// here. To "clean up" the tree we'll skip over IAccessibles that have the above states.
// May revisit per user feedback.
if (Accessible.HasState(state, AccessibleState.Invisible) && !Accessible.HasState(state, AccessibleState.Offscreen))
return false;
return true;
}
}
internal bool InSameHwnd(IntPtr hwnd)
{
bool inSameHwnd = Window != IntPtr.Zero && Window == hwnd;
return inSameHwnd;
}
// returns true if accessible object should be exposed to UIA clients.
// accessible objects are exposed UIA if they are visible, not offscreen, and do not correspond to a child window.
internal bool IsExposedToUIA
{
get
{
bool rval = false;
// if the accessible object is "available"...
if (IsAvailableToUser)
{
// ... and is not a child window...
//
AccessibleRole role = Role;
if (role != AccessibleRole.Window)
{
// ... and is not a child window that is trident ...
// (special case since trident doesn't have a ROLE_SYSTEM_WINDOW object for its "Internet Explorer_Server" window.
if (role != AccessibleRole.Client || Description != "MSAAHTML Registered Handler")
{
// then it is visible
rval = true;
}
}
}
return rval;
}
}
internal AccessibleState State
{
get
{
try
{
return (AccessibleState)_acc.get_accState(_idChild);
}
catch (Exception e)
{
if (HandleIAccessibleException(e))
{
// PerSharp/PreFast will flag this as a warning, 6503/56503: Property get methods should not throw exceptions.
// We are communicate with the underlying control to get the information.
// The control may not be able to give us the information we need.
// Throw the correct exception to communicate the failure.
#pragma warning suppress 6503
throw;
}
return AccessibleState.Unavailable;
}
}
}
internal string Value
{
get
{
try
{
string value = FixBstr(_acc.get_accValue(_idChild));
// PerSharp/PreFast will flag this as warning 6507/56507: Prefer 'string.IsNullOrEmpty(value)' over checks for null and/or emptiness.
// Need to convert nulls into an empty string, so need to just test for a null.
// Therefore we can not use IsNullOrEmpty() here, suppress the warning.
#pragma warning suppress 6507
return value != null ? value : "";
}
catch (Exception e)
{
if (HandleIAccessibleException(e))
{
// PerSharp/PreFast will flag this as a warning, 6503/56503: Property get methods should not throw exceptions.
// We are communicate with the underlying control to get the information.
// The control may not be able to give us the information we need.
// Throw the correct exception to communicate the failure.
#pragma warning suppress 6503
throw;
}
return "";
}
}
set
{
try
{
_acc.set_accValue(_idChild, value);
}
catch (Exception e)
{
if (HandleIAccessibleException(e))
{
throw;
}
//
throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed), e);
}
}
}
// Return the Rect that bounds this element in screen coordinates
internal Rect Location
{
get
{
NativeMethods.Win32Rect rcW32 = GetLocation(_acc, _idChild);
return rcW32.ToRect(false);
}
}
internal static Accessible GetFullAccessibleChildByIndex(Accessible accParent, int index)
{
int childCount = 0;
object[] accChildren = Accessible.GetAccessibleChildren(accParent.IAccessible, out childCount);
if (accChildren != null && 0 <= index && index < accChildren.Length)
{
object child = accChildren[index];
IAccessible accChild = child as IAccessible;
if (accChild != null)
{
return Accessible.Wrap(accChild);
}
else if (child is int)
{
int idChild = (int)child;
return Accessible.Wrap(accParent.IAccessible, idChild);
}
}
return null;
}
internal static AccessibleRole GetRole(IAccessible acc, int idChild)
{
AccessibleRole rval;
try
{
object role = acc.get_accRole(idChild);
// get_accRole can return a non-int! for example, Outlook 2003 SUPERGRID entries
// can return the string "Table View". so we return an int if we got one otherwise
// we convert it to the generic "client" role.
rval = (role is int) ? (AccessibleRole)(int)role : AccessibleRole.Client;
}
catch (Exception e)
{
if (HandleIAccessibleException(e))
{
throw;
}
rval = AccessibleRole.Client;
}
return rval;
}
// Get the selected children in a container
internal Accessible [] GetSelection()
{
//
object obj = null;
try
{
obj = _acc.accSelection;
}
catch (Exception e)
{
if (HandleIAccessibleException(e))
{
throw;
}
obj = null;
}
if (obj == null)
{
return null;
}
Accessible [] children = null;
if (obj is int)
{
children = new Accessible[1];
children[0] = AccessibleFromObject(obj, _acc);
}
else if (obj is object)
{
children = new Accessible[1];
children[0] = AccessibleFromObject(obj, _acc);
}
else if (obj is object [])
{
object [] objs = (object [])obj;
children = new Accessible[objs.Length];
for (int i=0;i 0)
{
aChildren = new object[childCount];
// Get the raw children because accNavigate doesn't work
if (UnsafeNativeMethods.AccessibleChildren(accessibleObject, 0, childCount, aChildren, out childrenReturned) == NativeMethods.E_INVALIDARG)
{
System.Diagnostics.Debug.Assert(false, "Call to AccessibleChildren() returned E_INVALIDARG.");
throw new ElementNotAvailableException();
}
}
return aChildren;
}
catch (Exception e)
{
if (HandleIAccessibleException(e))
{
throw;
}
throw new ElementNotAvailableException();
}
}
#endregion
#endregion Internal Methods
//------------------------------------------------------
//
// Private Methods
//
//------------------------------------------------------
#region Private Methods
// Returns a child by index
private static Accessible GetChildAt(IAccessible parent, object [] children, int index)
{
// note: calling AccessibleChildren on Trident and asking for a single child can
// result in a Fatal Execution Engine Error (79697ADA)(80121506).
// Perhaps the implementation ignores the cChildren param?
// To avoid the problem we always ask for all of the children and just
// use the specific one we are interested in.
if (children == null)
{
children = GetChildren(parent);
}
if (children == null)
{
return null;
}
// Paranoia that between calls accChildCount returns different counts
if (index >= children.Length)
index = children.Length - 1;
Accessible nav = AccessibleFromObject(children[index], parent);
if (nav != null)
{
nav._accessibleChildrenIndex = index;
}
return nav;
}
// Find _acc's index among its siblings with optimization to return children collection
// if that would be needed later by the caller
private object [] SetAccessibleChildrenIndexAndGetChildren(IAccessible parent)
{
// this is only called if the index hasn't been set yet.
Debug.Assert(_accessibleChildrenIndex < 0);
object [] children = GetChildren(parent);
if (children == null)
{
return null; // unlikely to happen but...
}
// Try to figure out which child in this array '_acc' is
for (int i=0;i
// Copyright (C) Microsoft Corporation. All rights reserved.
//
//
//
// Description: Wraps some of IAccessible to support getting basic properties
// and default action
//
// History:
// 06/02/2003 : BrendanM Ported to WCP
// 03/15/2004 : Micw enhanced to support a native MSAA fallback proxy
//
//---------------------------------------------------------------------------
// PRESHARP: In order to avoid generating warnings about unkown message numbers and unknown pragmas.
#pragma warning disable 1634, 1691
using System;
using System.Diagnostics;
using System.Collections;
using System.Globalization;
using System.Threading;
using System.Windows.Automation;
using System.Windows;
using Accessibility;
using System.Text;
using System.Runtime.InteropServices;
using MS.Win32;
namespace MS.Internal.AutomationProxies
{
// values return from IAccessible.get_accRole.
internal enum AccessibleRole: int
{
TitleBar = 0x1,
MenuBar = 0x2,
ScrollBar = 0x3,
Grip = 0x4,
Sound = 0x5,
Cursor = 0x6,
Caret = 0x7,
Alert = 0x8,
Window = 0x9,
Client = 0xa,
MenuPopup = 0xb,
MenuItem = 0xc,
Tooltip = 0xd,
Application = 0xe,
Document = 0xf,
Pane = 0x10,
Chart = 0x11,
Dialog = 0x12,
Border = 0x13,
Grouping = 0x14,
Separator = 0x15,
ToolBar = 0x16,
StatusBar = 0x17,
Table = 0x18,
ColumnHeader = 0x19,
RowHeader = 0x1a,
Column = 0x1b,
Row = 0x1c,
Cell = 0x1d,
Link = 0x1e,
HelpBalloon = 0x1f,
Character = 0x20,
List = 0x21,
ListItem = 0x22,
Outline = 0x23,
OutlineItem = 0x24,
PageTab = 0x25,
PropertyPage = 0x26,
Indicator = 0x27,
Graphic = 0x28,
StaticText = 0x29,
Text = 0x2a,
PushButton = 0x2b,
CheckButton = 0x2c,
RadioButton = 0x2d,
Combobox = 0x2e,
DropList = 0x2f,
ProgressBar = 0x30,
Dial = 0x31,
HotKeyField = 0x32,
Slider = 0x33,
SpinButton = 0x34,
Diagram = 0x35,
Animation = 0x36,
Equation = 0x37,
ButtonDropDown = 0x38,
ButtonMenu = 0x39,
ButtonDropDownGrid = 0x3a,
Whitespace = 0x3b,
PageTabList = 0x3c,
Clock = 0x3d,
SplitButton = 0x3e,
IpAddress = 0x3f,
OutlineButton = 0x40,
}
// values returned from IAccessible.get_accState.
[Flags]
internal enum AccessibleState: int
{
Normal = 0x00000000,
Unavailable = 0x00000001,
Selected = 0x00000002,
Focused = 0x00000004,
Pressed = 0x00000008,
Checked = 0x00000010,
Mixed = 0x00000020,
ReadOnly = 0x00000040,
HotTracked = 0x00000080,
Default = 0x00000100,
Expanded = 0x00000200,
Collapsed = 0x00000400,
Busy = 0x00000800,
Floating = 0x00001000,
Marqueed = 0x00002000,
Animated = 0x00004000,
Invisible = 0x00008000,
Offscreen = 0x00010000,
Sizeable = 0x00020000,
Moveable = 0x00040000,
SelfVoicing = 0x00080000,
Focusable = 0x00100000,
Selectable = 0x00200000,
Linked = 0x00400000,
Traversed = 0x00800000,
Multiselectable = 0x01000000,
ExtSelectable = 0x02000000,
AlertLow = 0x04000000,
AlertMedium = 0x08000000,
AlertHigh = 0x10000000,
Protected = 0x20000000,
}
internal class Accessible
{
//-----------------------------------------------------
//
// Constructors
//
//-----------------------------------------------------
#region Constructors
//
// called by Wrap to create a node Accessible that manages its children
private Accessible(IAccessible acc, int idChild)
{
Debug.Assert(acc != null, "null IAccessible");
_acc = acc;
_idChild = idChild;
_accessibleChildrenIndex = -1;
}
// Here we are re-implementing AccessibleObjectFromEvent with a critical difference.
// AccessibleObjectFromEvent, via AccessibleObjectFromWindow, will default to a standard implementation
// of IAccessible if the window doesn't have a native implementation.
// However we only want to succeed constructing the object if the window has a native implementation.
internal static Accessible CreateNativeFromEvent(IntPtr hwnd, int idObject, int idChild)
{
// On Vista, pass PID as wParam - allows credUI scenario to work (OLEACC needs to know our PID to
// DuplicateHandle back to this process.)
IntPtr wParam = IntPtr.Zero;
if(Environment.OSVersion.Version.Major >= 6)
wParam = new IntPtr(UnsafeNativeMethods.GetCurrentProcessId());
// send the window a WM_GETOBJECT message requesting the specific object id.
IntPtr lResult = Misc.ProxySendMessage(hwnd, NativeMethods.WM_GETOBJECT, wParam, new IntPtr(idObject));
if (lResult == IntPtr.Zero)
{
return null;
}
// unwrap the pointer that was returned
IAccessible acc = null;
int hr = NativeMethods.S_FALSE;
try
{
hr = UnsafeNativeMethods.ObjectFromLresult(lResult, ref UnsafeNativeMethods.IID_IAccessible, wParam, ref acc);
}
catch (InvalidCastException)
{
// CLR remoting appears to be interfering in cases where the remote IAccessible is a Winforms control -
// the object we get back is a __Transparent proxy, and casting that to IAccessible fails with an exception
// (which is caught and ignored here). See bug #1110719 for details.
// One way around this is to use AccessibleObjectFromWindow - that returns IAccessible instead of IUnknown -
// in effect it does the case in unmanaged code, and seems to avoid this issue. Other winforms code in the
// proxies uses this approach. AccessibleObjectFromWindow will return an OLEACC proxy if one is available,
// however, so we can't use it here, as this code only wants to deal with native IAccessibles.
return null;
}
// ObjectFromLresult returns an IAccessible from the remote process. If that impl is managed, however, then
// the local CLR will set up a CLR-Remoting-based connection instead and bypass COM - this causes problems
// because CLR Remoting typically isn't initalized, so calls fail with a RemotingException: "This remoting
// proxy has no channel sink which means either the server has no registered server channels that are listening,
// or this application has no suitable client channel to talk to the server." - see bug #1519030. The local CLR
// detects that the remote object is a managed impl by QI'ing for a specifc interface (IManagedObject?).
// We can prevent this from happening by dropping the IAccessible we've gotten back from ObjectFromLresult,
// and instead use AccessibleObjectFromWindow: AOFW wraps the real IAccessible in a DynamicAnnotation wrapper
// that passes through all IAccessible (and related interface) calls - but it doesn't pass through the
// IManagedObject interface, so the CLR treats it as a COM object, and continues to use plain COM to access it,
// avoiding the CLR Remoting issues.
//
// In effect, we're sending WM_GETOBJECT to the HWND to see if there's a native impl there, using ObjectFromLresult
// just to free that object, and then using AccessibleObjectFromWindow on the window to get the IAccessible
// that we actually use. (Can't just use AccessibleObjectFromWindow from the start, since that would return
// an oleacc proxy for hwnds that don't support IAccessible natively, and we only care about actual IAccessible
// impls here.)
//
// We used to do use AOFW below only if the acc we got back above was a managed object (checked using
// !Marshal.IsComObject()) - that only protects us from managed IAccessibles we get back directly; we could
// still hit the above issue if we get back a remote unmanaged impl that then returns a maanged impl via
// navigation (Media Center does this). So we now use AOFW all the time.
if(hr == NativeMethods.S_OK && acc != null)
{
object obj = null;
hr = UnsafeNativeMethods.AccessibleObjectFromWindow(hwnd, idObject, ref UnsafeNativeMethods.IID_IUnknown, ref obj);
acc = obj as IAccessible;
}
if (hr != NativeMethods.S_OK || acc == null)
{
return null;
}
// This takes care of calling get_accChild, if necessary...
return AccessibleFromObject(idChild, acc);
}
#if DEBUG
/*
// strictly for debugging purposes:
public override string ToString()
{
try
{
return string.Format( "{0} \"{1}\" {2} {3}", RoleText, Name, _idChild, Window );
}
catch (Exception e)
{
return e.Message;
}
}
[DllImport( "oleacc.dll" )]
internal static extern int GetRoleText( int dwRole, StringBuilder lpszRole, int cchRoleMax );
private string RoleText
{
get
{
const int cch = 64;
StringBuilder sb = new StringBuilder( cch );
int len = GetRoleText( (int)Role, sb, cch );
return sb.ToString().Substring( 0, len );
}
}
*/
#endif
#endregion Constructors
//------------------------------------------------------
//
// Internal Methods
//
//-----------------------------------------------------
#region Internal Methods
// returns a new Accessible for the IAccessible, or null if IAccessible is null
internal static Accessible Wrap(IAccessible acc)
{
return Wrap(acc, NativeMethods.CHILD_SELF);
}
// returns a new Accessible for the IAccessible + child id, or null if IAccessible is null
internal static Accessible Wrap(IAccessible acc, int idChild)
{
return acc != null ? new Accessible(acc, idChild) : null;
}
internal IAccessible IAccessible { get { return _acc; } }
internal int ChildCount { get { return GetChildCount(_acc); } }
internal int ChildId { get { return _idChild; } }
internal string Description { get { return GetDescription(_acc, _idChild); } }
internal string KeyboardShortcut { get { return GetKeyboardShortcut(_acc, _idChild); } }
internal string Name { get { return GetName(_acc, _idChild); } }
internal string DefaultAction { get { return GetDefaultAction(_acc, _idChild); } }
internal AccessibleRole Role { get { return GetRole(_acc, _idChild); } }
internal bool IsPassword { get { return HasState(AccessibleState.Protected); } }
internal bool IsSelected { get { return HasState(AccessibleState.Selected); } }
internal bool IsMultiSelectable { get { return HasState(AccessibleState.Multiselectable); } }
internal bool IsIndeterminate { get { return HasState(AccessibleState.Mixed); } }
internal bool IsChecked { get { return HasState(AccessibleState.Checked); } }
internal bool IsReadOnly { get { return HasState(AccessibleState.ReadOnly); } }
internal bool IsEnabled { get { return ! HasState(AccessibleState.Unavailable); } }
internal bool IsFocused { get { return HasState(AccessibleState.Focused); } }
internal bool IsOffScreen { get { return HasState(AccessibleState.Offscreen); } }
internal Accessible FirstChild
{
get
{
return _idChild == NativeMethods.CHILD_SELF ? GetChildAt(_acc, null, 0) : null;
}
}
internal Accessible LastChild
{
get
{
return _idChild == NativeMethods.CHILD_SELF ? GetChildAt(_acc, null, Accessible.GetChildCount(_acc) - 1) : null;
}
}
internal Accessible NextSibling(Accessible parent)
{
Debug.Assert(parent != null);
// if this object doesn't yet have an index into parent's children find it
object[] children = null; // if we need to get children to find an index; re-use them
if (_accessibleChildrenIndex == -1)
{
children = SetAccessibleChildrenIndexAndGetChildren(parent._acc);
// if unable to find this child (broken IAccessible impl?) bail (
if (_accessibleChildrenIndex == -1)
{
Debug.Assert(false);
return null;
}
}
Accessible rval = null;
if (_accessibleChildrenIndex + 1 < Accessible.GetChildCount(parent._acc))
{
rval = GetChildAt(parent._acc, children, _accessibleChildrenIndex + 1);
}
return rval;
}
internal Accessible PreviousSibling(Accessible parent)
{
Debug.Assert(parent != null);
// if this object doesn't yet have an index into parent's children find it
object[] children = null; // if we need to get children to find an index; re-use them
if (_accessibleChildrenIndex == -1)
{
children = SetAccessibleChildrenIndexAndGetChildren(parent._acc);
// if unable to find this child (broken IAccessible impl?) bail (
if (_accessibleChildrenIndex == -1)
{
Debug.Assert(false);
return null;
}
}
Accessible rval = null;
if (_accessibleChildrenIndex - 1 >= 0)
{
rval = GetChildAt(parent._acc, children, _accessibleChildrenIndex - 1);
}
return rval;
}
internal Accessible Parent
{
get
{
//
// review: I think it might be better to throw an exception here than return a bogus value.
IAccessible rval;
if (_idChild != NativeMethods.CHILD_SELF)
{
rval = _acc; // parent is managing this child
}
else
{
try
{
rval = (IAccessible)_acc.accParent;
}
catch (Exception e)
{
if (HandleIAccessibleException(e))
{
// PerSharp/PreFast will flag this as a warning, 6503/56503: Property get methods should not throw exceptions.
// We are communicate with the underlying control to get the information.
// The control may not be able to give us the information we need.
// Throw the correct exception to communicate the failure.
#pragma warning suppress 6503
throw;
}
return null;
}
}
return Wrap(rval);
}
}
internal int AccessibleChildrenIndex(Accessible parent)
{
// if this is the first time we are called then compute the value and cache it.
if (_accessibleChildrenIndex < 0)
{
SetAccessibleChildrenIndexAndGetChildren(parent._acc);
}
return _accessibleChildrenIndex;
}
internal bool IsAvailableToUser
{
get
{
AccessibleState state = State;
// From MSDN:
// STATE_SYSTEM_INVISIBLE means the object is programmatically hidden. For example, menu items
// are programmatically hidden until a user activates the menu. Because objects with this
// state are not available to users, client applications should not communicate information
// about the object to users. However, if client applications find an object with this state,
// they should check to see if STATE_SYSTEM_OFFSCREEN is also set. If this second state is
// defined, then clients can communicate the information about the object to users.
//
// We're not dealing with menus [in this version of NativeMsaaProxy] so won't worry about them
// here. To "clean up" the tree we'll skip over IAccessibles that have the above states.
// May revisit per user feedback.
if (Accessible.HasState(state, AccessibleState.Invisible) && !Accessible.HasState(state, AccessibleState.Offscreen))
return false;
return true;
}
}
internal bool InSameHwnd(IntPtr hwnd)
{
bool inSameHwnd = Window != IntPtr.Zero && Window == hwnd;
return inSameHwnd;
}
// returns true if accessible object should be exposed to UIA clients.
// accessible objects are exposed UIA if they are visible, not offscreen, and do not correspond to a child window.
internal bool IsExposedToUIA
{
get
{
bool rval = false;
// if the accessible object is "available"...
if (IsAvailableToUser)
{
// ... and is not a child window...
//
AccessibleRole role = Role;
if (role != AccessibleRole.Window)
{
// ... and is not a child window that is trident ...
// (special case since trident doesn't have a ROLE_SYSTEM_WINDOW object for its "Internet Explorer_Server" window.
if (role != AccessibleRole.Client || Description != "MSAAHTML Registered Handler")
{
// then it is visible
rval = true;
}
}
}
return rval;
}
}
internal AccessibleState State
{
get
{
try
{
return (AccessibleState)_acc.get_accState(_idChild);
}
catch (Exception e)
{
if (HandleIAccessibleException(e))
{
// PerSharp/PreFast will flag this as a warning, 6503/56503: Property get methods should not throw exceptions.
// We are communicate with the underlying control to get the information.
// The control may not be able to give us the information we need.
// Throw the correct exception to communicate the failure.
#pragma warning suppress 6503
throw;
}
return AccessibleState.Unavailable;
}
}
}
internal string Value
{
get
{
try
{
string value = FixBstr(_acc.get_accValue(_idChild));
// PerSharp/PreFast will flag this as warning 6507/56507: Prefer 'string.IsNullOrEmpty(value)' over checks for null and/or emptiness.
// Need to convert nulls into an empty string, so need to just test for a null.
// Therefore we can not use IsNullOrEmpty() here, suppress the warning.
#pragma warning suppress 6507
return value != null ? value : "";
}
catch (Exception e)
{
if (HandleIAccessibleException(e))
{
// PerSharp/PreFast will flag this as a warning, 6503/56503: Property get methods should not throw exceptions.
// We are communicate with the underlying control to get the information.
// The control may not be able to give us the information we need.
// Throw the correct exception to communicate the failure.
#pragma warning suppress 6503
throw;
}
return "";
}
}
set
{
try
{
_acc.set_accValue(_idChild, value);
}
catch (Exception e)
{
if (HandleIAccessibleException(e))
{
throw;
}
//
throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed), e);
}
}
}
// Return the Rect that bounds this element in screen coordinates
internal Rect Location
{
get
{
NativeMethods.Win32Rect rcW32 = GetLocation(_acc, _idChild);
return rcW32.ToRect(false);
}
}
internal static Accessible GetFullAccessibleChildByIndex(Accessible accParent, int index)
{
int childCount = 0;
object[] accChildren = Accessible.GetAccessibleChildren(accParent.IAccessible, out childCount);
if (accChildren != null && 0 <= index && index < accChildren.Length)
{
object child = accChildren[index];
IAccessible accChild = child as IAccessible;
if (accChild != null)
{
return Accessible.Wrap(accChild);
}
else if (child is int)
{
int idChild = (int)child;
return Accessible.Wrap(accParent.IAccessible, idChild);
}
}
return null;
}
internal static AccessibleRole GetRole(IAccessible acc, int idChild)
{
AccessibleRole rval;
try
{
object role = acc.get_accRole(idChild);
// get_accRole can return a non-int! for example, Outlook 2003 SUPERGRID entries
// can return the string "Table View". so we return an int if we got one otherwise
// we convert it to the generic "client" role.
rval = (role is int) ? (AccessibleRole)(int)role : AccessibleRole.Client;
}
catch (Exception e)
{
if (HandleIAccessibleException(e))
{
throw;
}
rval = AccessibleRole.Client;
}
return rval;
}
// Get the selected children in a container
internal Accessible [] GetSelection()
{
//
object obj = null;
try
{
obj = _acc.accSelection;
}
catch (Exception e)
{
if (HandleIAccessibleException(e))
{
throw;
}
obj = null;
}
if (obj == null)
{
return null;
}
Accessible [] children = null;
if (obj is int)
{
children = new Accessible[1];
children[0] = AccessibleFromObject(obj, _acc);
}
else if (obj is object)
{
children = new Accessible[1];
children[0] = AccessibleFromObject(obj, _acc);
}
else if (obj is object [])
{
object [] objs = (object [])obj;
children = new Accessible[objs.Length];
for (int i=0;i 0)
{
aChildren = new object[childCount];
// Get the raw children because accNavigate doesn't work
if (UnsafeNativeMethods.AccessibleChildren(accessibleObject, 0, childCount, aChildren, out childrenReturned) == NativeMethods.E_INVALIDARG)
{
System.Diagnostics.Debug.Assert(false, "Call to AccessibleChildren() returned E_INVALIDARG.");
throw new ElementNotAvailableException();
}
}
return aChildren;
}
catch (Exception e)
{
if (HandleIAccessibleException(e))
{
throw;
}
throw new ElementNotAvailableException();
}
}
#endregion
#endregion Internal Methods
//------------------------------------------------------
//
// Private Methods
//
//------------------------------------------------------
#region Private Methods
// Returns a child by index
private static Accessible GetChildAt(IAccessible parent, object [] children, int index)
{
// note: calling AccessibleChildren on Trident and asking for a single child can
// result in a Fatal Execution Engine Error (79697ADA)(80121506).
// Perhaps the implementation ignores the cChildren param?
// To avoid the problem we always ask for all of the children and just
// use the specific one we are interested in.
if (children == null)
{
children = GetChildren(parent);
}
if (children == null)
{
return null;
}
// Paranoia that between calls accChildCount returns different counts
if (index >= children.Length)
index = children.Length - 1;
Accessible nav = AccessibleFromObject(children[index], parent);
if (nav != null)
{
nav._accessibleChildrenIndex = index;
}
return nav;
}
// Find _acc's index among its siblings with optimization to return children collection
// if that would be needed later by the caller
private object [] SetAccessibleChildrenIndexAndGetChildren(IAccessible parent)
{
// this is only called if the index hasn't been set yet.
Debug.Assert(_accessibleChildrenIndex < 0);
object [] children = GetChildren(parent);
if (children == null)
{
return null; // unlikely to happen but...
}
// Try to figure out which child in this array '_acc' is
for (int i=0;i
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- SymmetricCryptoHandle.cs
- TrustExchangeException.cs
- BitmapInitialize.cs
- DataSourceViewSchemaConverter.cs
- TraceContextRecord.cs
- DirectionalLight.cs
- ConfigurationValidatorBase.cs
- OleDbInfoMessageEvent.cs
- TextProperties.cs
- ProgressBar.cs
- RemoteX509Token.cs
- PrintController.cs
- ParentQuery.cs
- Base64Decoder.cs
- ContainerParagraph.cs
- BuildProvider.cs
- SoapFault.cs
- CallbackValidator.cs
- ProfilePropertyNameValidator.cs
- MemberAccessException.cs
- DefaultValueTypeConverter.cs
- XmlMembersMapping.cs
- SystemIPv4InterfaceProperties.cs
- RenderData.cs
- CookieProtection.cs
- AsymmetricSignatureDeformatter.cs
- ToolboxCategoryItems.cs
- PropertyFilterAttribute.cs
- UICuesEvent.cs
- ApplicationSecurityManager.cs
- AlphabeticalEnumConverter.cs
- securitycriticaldata.cs
- _WinHttpWebProxyDataBuilder.cs
- TextBoxRenderer.cs
- TraceContextEventArgs.cs
- RC2CryptoServiceProvider.cs
- XmlTextReaderImpl.cs
- RetrieveVirtualItemEventArgs.cs
- XmlAttributeAttribute.cs
- CqlLexerHelpers.cs
- ConnectorSelectionGlyph.cs
- DataKeyArray.cs
- ADMembershipUser.cs
- SQLResource.cs
- AssemblyEvidenceFactory.cs
- TreeViewAutomationPeer.cs
- Header.cs
- ProvidersHelper.cs
- PerformanceCounterLib.cs
- BinaryObjectReader.cs
- ConstructorNeedsTagAttribute.cs
- PseudoWebRequest.cs
- ServiceNameElementCollection.cs
- Panel.cs
- ControlAdapter.cs
- ThreadExceptionDialog.cs
- WinInetCache.cs
- IPEndPointCollection.cs
- LayoutEvent.cs
- LineMetrics.cs
- ISAPIApplicationHost.cs
- SharedPerformanceCounter.cs
- XmlSchemaInferenceException.cs
- LogManagementAsyncResult.cs
- LongCountAggregationOperator.cs
- MemberAssignment.cs
- SQLInt32Storage.cs
- CFStream.cs
- ExpressionVisitorHelpers.cs
- PtsCache.cs
- Catch.cs
- SqlGenericUtil.cs
- VarInfo.cs
- BindStream.cs
- ProviderUtil.cs
- ContextMenuStripGroup.cs
- EntityDataSourceMemberPath.cs
- StreamFormatter.cs
- GridItem.cs
- ViewSimplifier.cs
- ConsumerConnectionPoint.cs
- FactoryMaker.cs
- Primitive.cs
- DataViewSettingCollection.cs
- ByteConverter.cs
- Hash.cs
- errorpatternmatcher.cs
- WebSysDefaultValueAttribute.cs
- IdentifierCreationService.cs
- ScriptServiceAttribute.cs
- MsmqHostedTransportManager.cs
- OleDbStruct.cs
- TextTreeNode.cs
- ContextBase.cs
- PathParser.cs
- RegexMatchCollection.cs
- ChannelOptions.cs
- DataContractJsonSerializer.cs
- GridViewColumn.cs
- DataBindingExpressionBuilder.cs