废话不多说直接上源码
以下是MSAA的核心操作源码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using Accessibility;
namespace QQSenders
{
class MSAASupport
{
public const uint OBJID_WINDOW = 0x00000000;
public const uint OBJID_SYSMENU = 0xFFFFFFFF;
public const uint OBJID_TITLEBAR = 0xFFFFFFFE;
public const uint OBJID_MENU = 0xFFFFFFFD;
public const uint OBJID_CLIENT = 0xFFFFFFFC;
public const uint OBJID_VSCROLL = 0xFFFFFFFB;
public const uint OBJID_HSCROLL = 0xFFFFFFFA;
public const uint OBJID_SIZEGRIP = 0xFFFFFFF9;
public const uint OBJID_CARET = 0xFFFFFFF8;
public const uint OBJID_CURSOR = 0xFFFFFFF7;
public const uint OBJID_ALERT = 0xFFFFFFF6;
public const uint OBJID_SOUND = 0xFFFFFFF5;
private IAccessible accessible;
private MSAAProperties properties;
//构造函数
public MSAASupport(IntPtr handle, uint OBJID)
{
object ppvObject = null;
Guid guidCOM = new Guid("618736E0-3C3D-11CF-810C-00AA00389B71");
AccessibleObjectFromWindow(handle, OBJID, ref guidCOM, ref ppvObject);
this.accessible = ppvObject as IAccessible;
if (this.accessible == null)
throw new ArgumentException("当前句柄无效");
this.properties = new MSAAProperties(this.accessible);
}
//构造函数
public MSAASupport(IntPtr handle) : this(handle, OBJID_CLIENT) { }
//构造函数
public MSAASupport(IAccessible accessible)
{
this.accessible = accessible;
if (this.accessible == null)
throw new ArgumentException("当前句柄无效");
this.properties = new MSAAProperties(this.accessible);
}
//构造函数
public MSAASupport(IAccessible accessible, int childId)
{
if (accessible == null)
throw new ArgumentException("当前句柄无效");
if (childId < 0)
throw new ArgumentException("子代元素ID不能为负值");
if (childId == 0)
this.accessible = accessible;
this.properties = new MSAAProperties(accessible, childId);
}
//Accessible 接口
public IAccessible Accessible { get { return this.accessible; } }
//获取 MSAA 属性
public MSAAProperties Properties { get { return this.properties; } }
public static List<MSAASupport> GetAccessibleChildren(IAccessible accessible)
{
int childCount = 0;
try { childCount = accessible.accChildCount; }
catch { }
object[] array = new object[childCount];
int pcObtained = 0;
if (childCount != 0)
AccessibleChildren(accessible, 0, childCount, array, ref pcObtained);
List<MSAASupport> result = new List<MSAASupport>();
for (int i = 0; i < pcObtained; i++)
{
IAccessible child = array[i] as IAccessible;
if (child == null)
result.Add(new MSAASupport(accessible, Convert.ToInt32(array[i])));
else
result.Add(new MSAASupport(child));
}
return result;
}
public List<MSAASupport> GetAccessibleChildren()
{
return GetAccessibleChildren(this.accessible);
}
public static MSAASupport GetAccessibleChild(IAccessible accessible, int[] indexs)
{
if (indexs.Length != 0)
{
List<MSAASupport> children = GetAccessibleChildren(accessible);
MSAASupport child = children[indexs[0]];
if (child.Properties.ChildCount == 0)
return null;
return GetAccessibleChild(child.accessible, indexs.Skip(1).ToArray());
}
else
return new MSAASupport(accessible);
}
public MSAASupport GetAccessibleChild(int[] indexs)
{
return GetAccessibleChild(this.accessible, indexs);
}
#region API
[DllImport("oleacc.dll")]
internal static extern int AccessibleObjectFromWindow(
IntPtr hwnd,
uint dwObjectID,
ref Guid riid,
[In, Out, MarshalAs(UnmanagedType.IUnknown)]
ref object ppvObject
);
[DllImport("oleacc.dll")]
public static extern int AccessibleChildren(
IAccessible paccContainer,
int iChildStart,
int cChildren,
[Out()] [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 4)]
object[] rgvarChildren, ref int pcObtained
);
#endregion
}
}
以下为UI控件元素属性:
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using Accessibility;
namespace QQSenders
{
class MSAAProperties
{
private IAccessible accessible;
private string _name;
private string _role;
private string _state;
private string _value;
private string _description;
private int _childCount;
private Rectangle _loaction;
public string Name { get { return this._name; } }
public string Role { get { return this._role; } }
public string State { get { return this._state; } }
public string Value { get { return this._value; } }
public string Description { get { return this._description; } }
public IAccessible Accessible { get { return this.accessible; } }
public int ChildCount
{
get
{
try { this._childCount = this.accessible.accChildCount; }
catch { this._childCount = 0; }
return this._childCount;
}
}
//构造函数
public MSAAProperties(IAccessible accessible) : this(accessible, 0) { }
//构造函数
public MSAAProperties(IAccessible accessible, int childId)
{
if (accessible == null)
throw new ArgumentNullException();
if (accessible != null)
this.accessible = accessible;
this.GetProperties(childId);
}
//获取元素属性
private void GetProperties(int childId)
{
try { this._name = this.accessible.get_accName(childId); }
catch { }
try { this._value = this.accessible.get_accValue(childId); }
catch { }
try { this._description = this.accessible.get_accDescription(childId); }
catch { }
try
{
uint role = Convert.ToUInt32(this.accessible.get_accRole(childId));
this._role = GetRoleText(role);
}
catch { }
try
{
uint state = Convert.ToUInt32(this.accessible.get_accState(childId));
this._state = this._state = GetStateText(state);
}
catch { }
try
{
int pxLeft, pyTop, pcxWidth, pcyHeight;
this.accessible.accLocation(out pxLeft, out pyTop, out pcxWidth, out pcyHeight, childId);
this._loaction = new Rectangle(pxLeft, pyTop, pcxWidth, pcyHeight);
}
catch { }
}
//获取控件名称
private static string GetRoleText(uint role)
{
StringBuilder lpszRole = new StringBuilder(1024);
GetRoleText(role, lpszRole, 1024);
return lpszRole.ToString();
}
private const uint STATE_SYSTEM_ALERT_HIGH = 0x10000000;
private const uint STATE_SYSTEM_ALERT_LOW = 0x04000000;
private const uint STATE_SYSTEM_ALERT_MEDIUM = 0x08000000;
private const uint STATE_SYSTEM_ANIMATED = 0x00004000;
private const uint STATE_SYSTEM_BUSY = 0x00000800;
private const uint STATE_SYSTEM_CHECKED = 0x00000010;
private const uint STATE_SYSTEM_COLLAPSED = 0x00000400;
private const uint STATE_SYSTEM_DEFAULT = 0x00000100;
private const uint STATE_SYSTEM_EXPANDED = 0x00000200;
private const uint STATE_SYSTEM_EXTSELECTABLE = 0x02000000;
private const uint STATE_SYSTEM_FLOATING = 0x00001000;
private const uint STATE_SYSTEM_FOCUSABLE = 0x00100000;
private const uint STATE_SYSTEM_FOCUSED = 0x00000004;
private const uint STATE_SYSTEM_HASPOPUP = 0x40000000;
private const uint STATE_SYSTEM_HOTTRACKED = 0x00000080;
private const uint STATE_SYSTEM_INVISIBLE = 0x00008000;
private const uint STATE_SYSTEM_LINKED = 0x00400000;
private const uint STATE_SYSTEM_MARQUEED = 0x00002000;
private const uint STATE_SYSTEM_MIXED = 0x00000020;
private const uint STATE_SYSTEM_MOVEABLE = 0x00040000;
private const uint STATE_SYSTEM_MULTISELECTABLE = 0x01000000;
private const uint STATE_SYSTEM_NORMAL = 0x00000000;
private const uint STATE_SYSTEM_OFFSCREEN = 0x00010000;
private const uint STATE_SYSTEM_PRESSED = 0x00000008;
private const uint STATE_SYSTEM_READONLY = 0x00000040;
private const uint STATE_SYSTEM_SELECTABLE = 0x00200000;
private const uint STATE_SYSTEM_SELECTED = 0x00000002;
private const uint STATE_SYSTEM_SELFVOICING = 0x00080000;
private const uint STATE_SYSTEM_SIZEABLE = 0x00020000;
private const uint STATE_SYSTEM_TRAVERSED = 0x00800000;
private const uint STATE_SYSTEM_UNAVAILABLE = 0x00000001;
private const uint STATE_SYSTEM_VALID = 0x1FFFFFFF;
//获取状态文本
private static string GetStateText(uint state)
{
StringBuilder focusableStateText = new StringBuilder(1024);
StringBuilder sizeableStateText = new StringBuilder(1024);
StringBuilder moveableStateText = new StringBuilder(1024);
StringBuilder invisibleStateText = new StringBuilder(1024);
StringBuilder unavailableStateText = new StringBuilder(1024);
StringBuilder hasPopupStateText = new StringBuilder(1024);
if (state == (STATE_SYSTEM_FOCUSABLE | STATE_SYSTEM_SIZEABLE | STATE_SYSTEM_MOVEABLE))
{
GetStateText(STATE_SYSTEM_FOCUSABLE, focusableStateText, 1024);
GetStateText(STATE_SYSTEM_SIZEABLE, sizeableStateText, 1024);
GetStateText(STATE_SYSTEM_MOVEABLE, moveableStateText, 1024);
return focusableStateText + "," + sizeableStateText + "," + moveableStateText;
}
if (state == (STATE_SYSTEM_FOCUSABLE | STATE_SYSTEM_INVISIBLE))
{
GetStateText(STATE_SYSTEM_FOCUSABLE, focusableStateText, 1024);
GetStateText(STATE_SYSTEM_INVISIBLE, invisibleStateText, 1024);
return focusableStateText + "," + invisibleStateText;
}
if (state == (STATE_SYSTEM_FOCUSABLE | STATE_SYSTEM_UNAVAILABLE))
{
GetStateText(STATE_SYSTEM_FOCUSABLE, focusableStateText, 1024);
GetStateText(STATE_SYSTEM_UNAVAILABLE, unavailableStateText, 1024);
return focusableStateText + "," + unavailableStateText;
}
if (state == (STATE_SYSTEM_HASPOPUP | STATE_SYSTEM_UNAVAILABLE))
{
GetStateText(STATE_SYSTEM_HASPOPUP, hasPopupStateText, 1024);
GetStateText(STATE_SYSTEM_UNAVAILABLE, unavailableStateText, 1024);
return hasPopupStateText + "," + unavailableStateText;
}
var stateText = new StringBuilder((int)1024);
GetStateText(state, stateText, 1024);
return stateText.ToString();
}
#region API
[DllImport("oleacc.dll")]
private static extern uint GetRoleText(
uint dwRole,
StringBuilder lpszRole,
uint cchRoleMax
);
[DllImport("oleacc.dll")]
private static extern uint GetStateText(
uint dwStateBit,
StringBuilder lpszStateBit,
uint cchStateBitMax
);
#endregion
}
}
获取群组按钮位置:
MSAASupport support = new MSAASupport(this.process.Handle);
support = support.GetAccessibleChild(new int[] { 4, 1, 5, 0, 0, 0, 0, 0 });
List<MSAASupport> children = support.GetAccessibleChildren();
support = children.Find(i => i.Properties.Description == "群聊");