Hello Dave,
Now I know what we are talking. The link you post is using Accessibilty API
to get an Accessible Automation object of Ribbon control. The Accessiblity
API is implemented in native dll. So from C#, we have to PInvoke to call
into oleacc.dll. It is not as easy as we do callback in C# Office COM AddIn.
I reference a codeproject article,
http://www.codeproject.com/KB/winsdk/MSAA_UI_Automation.aspx
and did a lot of debugging and test. At last I got the following codes work
to get the location of Ribbon button.
----------------native function declarations-----------------
[DllImport("oleacc.dll")]
internal static extern int AccessibleObjectFromWindow(
IntPtr hwnd,
uint id,
ref Guid iid,
[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);
[DllImport("oleacc.dll")]
public static extern uint GetRoleText(uint dwRole, [Out]
StringBuilder lpszRole, uint cchRoleMax);
[DllImport("oleacc.dll")]
public static extern uint GetStateText(uint dwStateBit, [Out]
StringBuilder lpszStateBit, uint cchStateBitMax);
-------------------------------------------------------------------------
-------------Help Functions--------------------------------------
public static string GetStateText(uint stateID)
{
uint maxLength = 1024;
var focusableStateText = new StringBuilder((int)maxLength);
var sizeableStateText = new StringBuilder((int)maxLength);
var moveableStateText = new StringBuilder((int)maxLength);
var invisibleStateText = new StringBuilder((int)maxLength);
var unavailableStateText = new StringBuilder((int)maxLength);
var hasPopupStateText = new StringBuilder((int)maxLength);
if (stateID ==
(MSAAStateConstants.STATE_SYSTEM_FOCUSABLE
| MSAAStateConstants.STATE_SYSTEM_SIZEABLE
| MSAAStateConstants.STATE_SYSTEM_MOVEABLE))
{
GetStateText(MSAAStateConstants.STATE_SYSTEM_FOCUSABLE,
focusableStateText, maxLength);
GetStateText(MSAAStateConstants.STATE_SYSTEM_SIZEABLE,
sizeableStateText, maxLength);
GetStateText(MSAAStateConstants.STATE_SYSTEM_MOVEABLE,
moveableStateText, maxLength);
return focusableStateText + "," + sizeableStateText + "," +
moveableStateText;
}
if (stateID ==
(MSAAStateConstants.STATE_SYSTEM_FOCUSABLE
| MSAAStateConstants.STATE_SYSTEM_INVISIBLE))
{
GetStateText(MSAAStateConstants.STATE_SYSTEM_FOCUSABLE,
focusableStateText, maxLength);
GetStateText(MSAAStateConstants.STATE_SYSTEM_INVISIBLE,
invisibleStateText, maxLength);
return focusableStateText + "," + invisibleStateText;
}
if (stateID ==
(MSAAStateConstants.STATE_SYSTEM_FOCUSABLE
| MSAAStateConstants.STATE_SYSTEM_UNAVAILABLE))
{
GetStateText(MSAAStateConstants.STATE_SYSTEM_FOCUSABLE,
focusableStateText, maxLength);
GetStateText(MSAAStateConstants.STATE_SYSTEM_UNAVAILABLE,
unavailableStateText, maxLength);
return focusableStateText + "," + unavailableStateText;
}
if (stateID ==
(MSAAStateConstants.STATE_SYSTEM_HASPOPUP
| MSAAStateConstants.STATE_SYSTEM_UNAVAILABLE))
{
GetStateText(MSAAStateConstants.STATE_SYSTEM_HASPOPUP,
hasPopupStateText, maxLength);
GetStateText(MSAAStateConstants.STATE_SYSTEM_UNAVAILABLE,
unavailableStateText, maxLength);
return hasPopupStateText + "," + unavailableStateText;
}
var stateText = new StringBuilder((int)maxLength);
GetStateText(stateID, stateText, maxLength);
return stateText.ToString();
}
internal static string GetRoleText(uint roleId)
{
uint maxLength = 1024;
var roleText = new StringBuilder((int)maxLength);
GetRoleText(roleId, roleText, maxLength);
return roleText.ToString();
}
public static IAccessible GetObjectByName(IAccessible objParent,
Regex objName, bool ignoreInvisible)
{
IAccessible objToReturn = default(IAccessible);
if (objParent != null)
{
IAccessible[] children = GetAccessibleChildren(objParent);
foreach (IAccessible child in children)
{
string childName = null;
string childState = string.Empty;
try
{
childName = child.get_accName(0);
childState =
GetStateText(Convert.ToUInt32(child.get_accState(0)));
}
catch (Exception)
{
}
if (ignoreInvisible)
{
if (childName != null
&& objName.Match(childName).Success
&& !childState.Contains("invisible"))
{
return child;
}
}
else
{
if (childName != null
&& objName.Match(childName).Success)
{
return child;
}
}
if (ignoreInvisible)
{
if (!childState.Contains("invisible"))
{
objToReturn = GetObjectByName(child, objName,
ignoreInvisible);
if (objToReturn != default(IAccessible))
{
return objToReturn;
}
}
}
else
{
objToReturn = GetObjectByName(child, objName,
ignoreInvisible);
if (objToReturn != default(IAccessible))
{
return objToReturn;
}
}
}
}
return objToReturn;
}
public static IAccessible[] GetAccessibleChildren(IAccessible
objAccessible)
{
int childCount = 0;
try
{
childCount = objAccessible.accChildCount;
}
catch (Exception ex)
{
childCount = 0;
}
var accObjects = new IAccessible[childCount];
int count = 0;
if (childCount != 0)
{
AccessibleChildren(objAccessible, 0, childCount,
accObjects, ref count);
}
return accObjects;
}
public static IAccessible GetObjectByNameAndRole(IAccessible
objParent, Regex objName, string roleText, bool ignoreInvisible)
{
IAccessible objToReturn = default(IAccessible);
if (objParent != null)
{
IAccessible[] children = GetAccessibleChildren(objParent);
foreach (IAccessible child in children)
{
string childName = null;
string childState = string.Empty;
string childRole = string.Empty;
try
{
childName = child.get_accName(0);
childState =
GetStateText(Convert.ToUInt32(child.get_accState(0)));
childRole =
GetRoleText(Convert.ToUInt32(child.get_accRole(0)));
}
catch (Exception)
{
}
if (ignoreInvisible)
{
if (!string.IsNullOrEmpty(childName)
&& objName.Match(childName).Success
&& childRole == roleText
&& !childState.Contains("invisible"))
{
return child;
}
}
else
{
if (!string.IsNullOrEmpty(childName)
&& objName.Match(childName).Success
&& childRole == roleText)
{
return child;
}
}
if (ignoreInvisible)
{
if (!childState.Contains("invisible"))
{
objToReturn = GetObjectByNameAndRole(child,
objName, roleText, ignoreInvisible);
if (objToReturn != default(IAccessible))
{
return objToReturn;
}
}
}
else
{
objToReturn = GetObjectByNameAndRole(child,
objName, roleText, ignoreInvisible);
if (objToReturn != default(IAccessible))
{
return objToReturn;
}
}
}
}
return objToReturn;
}
public static void GetAccessibleObjectListByRole(IAccessible
objParent, string roleText,
ref List<IAccessible>
accessibleObjList, bool ignoreInvisible)
{
if (objParent != null)
{
IAccessible[] children = GetAccessibleChildren(objParent);
foreach (IAccessible child in children)
{
string roleTextInner = null;
string childState = string.Empty;
try
{
uint roleId =
Convert.ToUInt32(child.get_accRole(0));
roleTextInner = GetRoleText(roleId);
childState =
GetStateText(Convert.ToUInt32(child.get_accState(0)));
}
catch (Exception)
{
}
if (ignoreInvisible)
{
if (roleTextInner == roleText &&
!childState.Contains("invisible"))
{
accessibleObjList.Add(child);
}
}
else
{
if (roleTextInner == roleText)
{
accessibleObjList.Add(child);
}
}
if (ignoreInvisible)
{
if (!childState.Contains("invisible"))
{
GetAccessibleObjectListByRole(child, roleText,
ref accessibleObjList, ignoreInvisible);
}
}
else
{
GetAccessibleObjectListByRole(child, roleText, ref
accessibleObjList, ignoreInvisible);
}
}
}
}
-------------------------------------------------------------------------
------------Codes to get the location of a button--------
object accObject = new object();
var guidAccessible = new
Guid("{618736E0-3C3D-11CF-810C-00AA00389B71}");
IAccessible objWindow = default(IAccessible);
AccessibleObjectFromWindow(
Process.GetCurrentProcess().MainWindowHandle, 0, ref
guidAccessible, ref accObject);
objWindow = (IAccessible)accObject;
Debug.Print(objWindow.accChildCount.ToString());
Debug.Print(objWindow.accName.ToString());
IAccessible Home = GetObjectByNameAndRole(objWindow, new
Regex("Home"),"property page", true);
IAccessible clipBoard = GetObjectByNameAndRole(Home, new
Regex("Clipboard"), "tool bar", true);
IAccessible Paste = GetObjectByNameAndRole(clipBoard, new
Regex("Paste"), "split button", true);
int pxLeft;
int pyTop;
int pcxWidth;
int pcyHeight;
Paste.accLocation(out pxLeft, out pyTop, out pcxWidth, out
pcyHeight, 0);
MessageBox.Show("Left:" + pxLeft + "\r\n" +
"Top:" + pyTop + "\r\n" +
"Width:" + pcxWidth + "\r\n" +
"Height:" + pcyHeight + "\r\n");
-------------------------------------------------------------------------
Hope this helps!
Best regards,
Ji Zhou
Microsoft Online Community Support