none
Can't get UIAutomationElement BoundingRectangle in win7

    Question

  • I use IRawElementProviderFragment for testing,but I can't get UIAutomationElement BoundingRectangle in win7.

    when I use VisualUIAutomationVerify to test,it stops working.

    I read the articl about dpi,and use PhysicalPoint,but i seems useless.

        internal class CommonDataGridViewCell :
            IRawElementProviderFragment,
            IGridItemProvider,
            IValueProvider,
            ISelectionItemProvider
        {
            private CommonDataGridView _grid;
            private CommonDataGridViewRow _row;
            private DataGridViewCell _cell;
            public CommonDataGridViewCell(CommonDataGridView grid, CommonDataGridViewRow row, DataGridViewCell cell)
            {
                if (grid == null)
                {
                    throw new ArgumentNullException("grid");
                }
                if (row == null)
                {
                    throw new ArgumentNullException("row");
                }
                if (cell == null)
                {
                    throw new ArgumentNullException("cell");
                }
                _grid = grid;
                _row = row;
                _cell = cell;
            }
            #region IRawElementProviderSimple Members
            /// <summary>
            /// Retrieves an object that provides support for a control pattern on a UI Automation element.
            /// </summary>
            /// <param name="patternId">Identifier of the pattern.</param>
            /// <returns>
            /// Object that implements the pattern interface, or null if the pattern is not supported.
            /// </returns>
            object IRawElementProviderSimple.GetPatternProvider(int patternId)
            {
                if (patternId.Equals(GridItemPatternIdentifiers.Pattern.Id) ||
                    patternId.Equals(ValuePatternIdentifiers.Pattern.Id) ||
                    patternId.Equals(SelectionItemPatternIdentifiers.Pattern.Id))
                {
                    return this;
                }
                else
                {
                    return null;
                }
            }
            /// <summary>
            /// Retrieves the value of a property supported by the UI Automation provider.
            /// </summary>
            /// <param name="propertyId">The property identifier.</param>
            /// <returns>
            /// The property value, or a null if the property is not supported by this provider, or <see cref="F:System.Windows.Automation.AutomationElementIdentifiers.NotSupported"/> if it is not supported at all.
            /// </returns>
            object IRawElementProviderSimple.GetPropertyValue(int propertyId)
            {
                if (propertyId == AutomationElementIdentifiers.ControlTypeProperty.Id ||
                    propertyId == AutomationElementIdentifiers.LocalizedControlTypeProperty.Id)
                {
                    return ControlType.DataItem.Id;
                }
                else if (propertyId == AutomationElementIdentifiers.AutomationIdProperty.Id)
                {
                    return _grid.Columns[_cell.ColumnIndex].HeaderText;
                }
                else if (propertyId == AutomationElementIdentifiers.NameProperty.Id)
                {
                    return _cell.Value;
                }
                else if (propertyId == AutomationElementIdentifiers.ClassNameProperty.Id)
                {
                    return this.GetType().ToString();
                }
                else if (propertyId == AutomationElementIdentifiers.HasKeyboardFocusProperty.Id)
                {
                    return _cell.IsInEditMode;
                }
                else if (propertyId == AutomationElementIdentifiers.IsEnabledProperty.Id)
                {
                    return _grid.Enabled;
                }
                else if (propertyId == AutomationElementIdentifiers.IsKeyboardFocusableProperty.Id)
                {
                    return _grid.Enabled && _grid.Visible;
                }
                return null;
            }
            /// <summary>
            /// Gets a base provider for this element.
            /// </summary>
            /// <value></value>
            /// <returns>The base provider, or null.</returns>
            IRawElementProviderSimple IRawElementProviderSimple.HostRawElementProvider
            {
                get
                {
                    return null;
                }
            }
            /// <summary>
            /// Gets a value that specifies characteristics of the UI Automation provider; for example, whether it is a client-side or server-side provider.
            /// </summary>
            /// <value></value>
            /// <returns>Either <see cref="F:System.Windows.Automation.Provider.ProviderOptions.ClientSideProvider"/> or <see cref="F:System.Windows.Automation.Provider.ProviderOptions.ServerSideProvider"/>.</returns>
            ProviderOptions IRawElementProviderSimple.ProviderOptions
            {
                get
                {
                    return ProviderOptions.ServerSideProvider;
                }
            }
            #endregion
            #region IRawElementProviderFragment Members
            /// <summary>
            /// Gets the bounding rectangle of this element.
            /// </summary>
            /// <value></value>
            /// <returns>The bounding rectangle, in screen coordinates.</returns>
            System.Windows.Rect IRawElementProviderFragment.BoundingRectangle
            {
                get
                {
                    var cellPoint = _grid.GetCellDisplayRectangle(_cell.ColumnIndex, _cell.RowIndex, true);
                    var formPoint = new Point(cellPoint.X, cellPoint.Y);
                    _grid.Invoke(new Action(() => formPoint = _grid.PointToScreen(formPoint)));
                    var topPoint = new CursorPoint() { X = formPoint.X, Y = formPoint.Y };
                    var widthPoint = new CursorPoint() {X = cellPoint.Width + formPoint.X, Y = formPoint.Y};
                    var heightPoint = new CursorPoint() {X = formPoint.X, Y = formPoint.Y + cellPoint.Height};
                    _grid.Invoke(new Action(() =>
                        {
                            try
                            {
                                LogicalToPhysicalPoint(_grid.Handle, ref topPoint);
                                LogicalToPhysicalPoint(_grid.Handle, ref widthPoint);
                                LogicalToPhysicalPoint(_grid.Handle, ref heightPoint);
                            }
                            catch (Exception)
                            {
                                ;
                            }
                        }));
                    var width = widthPoint.X - topPoint.X;
                    var height = heightPoint.Y - topPoint.Y;
                    return new System.Windows.Rect(topPoint.X, topPoint.Y, width, height);
                }
            }
            /// <summary>
            /// Retrieves the root node of the fragment.
            /// </summary>
            /// <value></value>
            /// <returns>The root node. </returns>
            IRawElementProviderFragmentRoot IRawElementProviderFragment.FragmentRoot
            {
                get
                {
                    return _row;
                }
            }
            /// <summary>
            /// Retrieves an array of fragment roots that are embedded in the UI Automation element tree rooted at the current element.
            /// </summary>
            /// <returns>An array of root fragments, or null.</returns>
            IRawElementProviderSimple[] IRawElementProviderFragment.GetEmbeddedFragmentRoots()
            {
                return null;
            }
            /// <summary>
            /// Retrieves the runtime identifier of an element.
            /// </summary>
            /// <returns>
            /// The unique run-time identifier of the element.
            /// </returns>
            int[] IRawElementProviderFragment.GetRuntimeId()
            {
                return new int[] { AutomationInteropProvider.AppendRuntimeId, _cell.ColumnIndex };
            }
            /// <summary>
            /// Retrieves the UI Automation element in a specified direction within the tree.
            /// </summary>
            /// <param name="direction">The direction in which to navigate.</param>
            /// <returns>
            /// The element in the specified direction, or null if there is no element in that direction
            /// </returns>
            IRawElementProviderFragment IRawElementProviderFragment.Navigate(NavigateDirection direction)
            {
                switch (direction)
                {
                    case NavigateDirection.NextSibling:
                        if (_cell.ColumnIndex < _grid.Columns.Count - 1)
                        {
                            return new CommonDataGridViewCell(_grid, _row, _cell.OwningRow.Cells[_cell.ColumnIndex + 1]);
                        }
                        break;
                    case NavigateDirection.PreviousSibling:
                        if (_cell.ColumnIndex > 0)
                        {
                            return new CommonDataGridViewCell(_grid, _row, _cell.OwningRow.Cells[_cell.ColumnIndex - 1]);
                        }
                        break;
                    case NavigateDirection.Parent:
                        return new CommonDataGridViewRow(_grid, _cell.OwningRow);
                }
                return null;
            }
            /// <summary>
            /// Sets the focus to this element.
            /// </summary>
            void IRawElementProviderFragment.SetFocus()
            {
                _grid.Invoke(new MethodInvoker(delegate()
                {
                    _grid.CurrentCell = _cell;
                }));
            }
            #endregion
            #region IGridItemProvider Members
            /// <summary>
            /// Gets the ordinal number of the column that contains the cell or item.
            /// </summary>
            /// <value></value>
            /// <returns>A zero-based ordinal number that identifies the column containing the cell or item.</returns>
            int IGridItemProvider.Column
            {
                get
                {
                    return _cell.ColumnIndex;
                }
            }
            /// <summary>
            /// Gets the number of columns spanned by a cell or item.
            /// </summary>
            /// <value></value>
            /// <returns>The number of columns spanned. </returns>
            int IGridItemProvider.ColumnSpan
            {
                get
                {
                    return 1;
                }
            }
            /// <summary>
            /// Gets a UI Automation provider that implements <see cref="T:System.Windows.Automation.Provider.IGridProvider"/> and represents the container of the cell or item.
            /// </summary>
            /// <value></value>
            /// <returns>A UI Automation provider that implements the <see cref="T:System.Windows.Automation.GridPattern"/> and represents the cell or item container. </returns>
            IRawElementProviderSimple IGridItemProvider.ContainingGrid
            {
                get
                {
                    return _grid;
                }
            }
            /// <summary>
            /// Gets the ordinal number of the row that contains the cell or item.
            /// </summary>
            /// <value></value>
            /// <returns>A zero-based ordinal number that identifies the row containing the cell or item. </returns>
            int IGridItemProvider.Row
            {
                get
                {
                    return _cell.RowIndex;
                }
            }
            /// <summary>
            /// Gets the number of rows spanned by a cell or item.
            /// </summary>
            /// <value></value>
            /// <returns>The number of rows spanned. </returns>
            int IGridItemProvider.RowSpan
            {
                get
                {
                    return 1;
                }
            }
            #endregion
            #region IValueProvider Members
            /// <summary>
            /// Gets a value that specifies whether the value of a control is read-only.
            /// </summary>
            /// <value></value>
            /// <returns>true if the value is read-only; false if it can be modified. </returns>
            bool IValueProvider.IsReadOnly
            {
                get
                {
                    return _cell.State == DataGridViewElementStates.ReadOnly;
                }
            }
            /// <summary>
            /// Sets the value of a control.
            /// </summary>
            /// <param name="value"></param>
            /// <exception cref="T:System.InvalidOperationException">If locale-specific information is passed to a control in an incorrect format such as an incorrectly formatted date. </exception>
            /// <exception cref="T:System.ArgumentException">If a new value cannot be converted from a string to a format the control recognizes.</exception>
            /// <exception cref="T:System.Windows.Automation.ElementNotEnabledException">When an attempt is made to manipulate a control that is not enabled.</exception>
            void IValueProvider.SetValue(string value)
            {
                // Check if we are enabled
                if (!(bool)((IRawElementProviderSimple)this).GetPropertyValue(AutomationElementIdentifiers.IsEnabledProperty.Id))
                {
                    throw new ElementNotEnabledException();
                }
                // Check if we are read only
                if (((IValueProvider)this).IsReadOnly)
                {
                    throw new InvalidOperationException("Cannot set the value on a ReadOnly field!");
                }
                // Set Value
                _grid.Invoke(new MethodInvoker(delegate()
                {
                    _grid.BeginEdit(false);
                    _cell.Value = value;
                    _grid.CommitEdit(DataGridViewDataErrorContexts.Commit);
                    _grid.EndEdit();
                }));
            }
            /// <summary>
            /// Gets the value of the control.
            /// </summary>
            /// <value></value>
            /// <returns>The value of the control as a string. </returns>
            string IValueProvider.Value
            {
                get
                {
                    return _cell.Value == null ? null : _cell.Value.ToString();
                }
            }
            #endregion
            #region ISelectionItemProvider Members
            /// <summary>
            /// Adds the current element to the collection of selected items.
            /// </summary>
            void ISelectionItemProvider.AddToSelection()
            {
                _grid.Invoke(new MethodInvoker(() =>
                {
                    _cell.Selected = true;
                }));
            }
            /// <summary>
            /// Gets a value that indicates whether an item is selected.
            /// </summary>
            /// <value></value>
            /// <returns>true if the element is selected; otherwise false.</returns>
            bool ISelectionItemProvider.IsSelected
            {
                get
                {
                    bool selected = false;
                    _grid.Invoke(new MethodInvoker(() => { selected = _grid.CurrentCell.Equals(_cell); }));
                    return selected;
                }
            }
            /// <summary>
            /// Removes the current element from the collection of selected items.
            /// </summary>
            void ISelectionItemProvider.RemoveFromSelection()
            {
                _grid.Invoke(new MethodInvoker(() =>
                {
                    _cell.Selected = false;
                }));
            }
            /// <summary>
            /// Deselects any selected items and then selects the current element.
            /// </summary>
            void ISelectionItemProvider.Select()
            {
                _grid.Invoke(new MethodInvoker( () =>
                {
                    foreach (DataGridViewCell cell in _grid.SelectedCells)
                    {
                        cell.Selected = false;
                    }
                    _cell.Selected = true;
                }));
            }
            /// <summary>
            /// Gets the UI Automation provider that implements <see cref="T:System.Windows.Automation.Provider.ISelectionProvider"/> and acts as the container for the calling object.
            /// </summary>
            /// <value></value>
            /// <returns>The provider that supports <see cref="T:System.Windows.Automation.Provider.ISelectionProvider"/>. </returns>
            IRawElementProviderSimple ISelectionItemProvider.SelectionContainer
            {
                get
                {
                    return _grid;
                }
            }
            #endregion
            public struct CursorPoint
            {
                public int X;
                public int Y;
            }
            [System.Runtime.InteropServices.DllImport("user32.dll")]
            internal static extern bool LogicalToPhysicalPoint(IntPtr hnd, ref CursorPoint lpPoint);
            [System.Runtime.InteropServices.DllImport("user32.dll")]
            internal static extern bool GetPhysicalCursorPos(ref CursorPoint lpPoint);
        }


    • Edited by suriyel Sunday, January 27, 2013 7:23 PM add details
    • Moved by Mike Feng Monday, January 28, 2013 8:23 AM
    Sunday, January 27, 2013 7:16 PM

All replies


  • My computer uses 96 dpi,but uispy stills can not get the table cell's BoundingRectangle and it will make uispy stop working.

    What's worse,the open source project White also failed in my testing.After debuging,I find it stops and waiting at this line:

      public object GetCurrentPropertyValue(AutomationProperty property, bool ignoreDefaultValue)
            {
                Utility.ValidateArgumentNonNull(property, "property");
                try
                {
                    object obj = this._obj.GetCurrentPropertyValueEx(property.Id, (ignoreDefaultValue) ? 1 : 0);
                    return Utility.WrapObjectAsProperty(property, obj);
                }
                catch (System.Runtime.InteropServices.COMException e)
                {
                    Exception newEx; if (Utility.ConvertException(e, out newEx)) { throw newEx; } else { throw; }
                }
    
            }
    I think maybe the UIAutomation has some bug in win7.

     


    • Edited by suriyel Sunday, January 27, 2013 8:30 PM
    Sunday, January 27, 2013 8:28 PM
  • Hi Suriyel,

    I have moved this thread to UI automation forum for more responses. Thank you for understanding and support.

    Best regards,


    Mike Feng
    MSDN Community Support | Feedback to us
    Develop and promote your apps in Windows Store
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Monday, January 28, 2013 8:22 AM