如何通过 UIAutomation 确定按钮是否被按下?

发布于 2024-11-15 07:18:40 字数 292 浏览 3 评论 0原文

我想知道某个按钮是否被按下。这似乎不是按钮的官方属性(不是按钮样式的复选框!),但似乎可以访问,例如,有 BM_GETSTATE 消息应该获得所需的结果。

问题是,我经常没有获得按钮的窗口句柄(它们只是另一个工具栏的一部分,尽管它们可以通过 AutomationElement 来区分)。我需要这样一个 SendMessage 函数的句柄。

那么..我有办法访问该属性吗?我知道它是可以访问的,因为我在其他自动化程序中看到过它,但我只是不知道如何获取它。

我将使用 C#,但任何 C 代码都可以。

非常感谢

I want to find out whether a button is pressed or not. This seems not to be an official property of a button (not a button-style checkbox!), but seems accessible, there is the BM_GETSTATE message for example that should get the desired result.

Problem is, frequently, I dont get window-handles for my buttons (they are just part of another Toolbar, though they can be distinguihed by the AutomationElement). And I would need such a handle for the SendMessage function.

So.. is there a way for me to access that property? I know it is accessible, since I have seen it in other automation-programmes, I just dont konw how to get at it.

I am going to use C#, but any C code would be fine.

Many thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

风和你 2024-11-22 07:18:40

(编辑:所以我终于设法在这里正确设置代码格式 - 只需在开头插入 4 个空格即可。)

享受它,我花了很长时间才让它工作..但现在我感觉已经达到了一个新的目标等级。 :)

(请告诉我如何使其格式正确 - 引用和代码对我来说都失败了)

int res;
#region direct method
int hwnd = ae.Current.NativeWindowHandle;
if (hwnd != 0)
{
    const UInt32 BM_GETSTATE = 0x00F2;
    res = SendMessage(hwnd, BM_GETSTATE, 0, 0);
}
#endregion
else
#region method via toolbar
{
    AutomationElement parent = TreeWalker.RawViewWalker.GetParent(ae);
    while ((parent != null) && (parent.Current.ControlType != ControlType.ToolBar))
        parent = TreeWalker.RawViewWalker.GetParent(ae);
    if (parent != null)
    {
        int toolBarHandle = parent.Current.NativeWindowHandle;
        #region defines
        const int WM_USER = 0x400;
        const int TB_GETSTATE = (WM_USER + 18);
        const int TB_GETBUTTON = (WM_USER + 23);
        const int TB_BUTTONCOUNT = (WM_USER + 24);
        #endregion

        #region get correct child number
        int numButtons = SendMessage(toolBarHandle, TB_BUTTONCOUNT, 0, 0);
        AutomationElement sibling = ae;
        int cnt = -1;
        while (sibling != null)
        {
            sibling = TreeWalker.RawViewWalker.GetPreviousSibling(sibling);
            ++cnt;
        }
        if (cnt >= numButtons)
            cnt = 0; // nonsense value, but pass a valid one
        #endregion

        #region get command id
        TBBUTTON butInfo = new TBBUTTON();
        butInfo.idCommand = 1234;
        uint pid;
        GetWindowThreadProcessId((IntPtr)toolBarHandle, out pid);
        IntPtr process = OpenProcess(ProcessAccessFlags.VMOperation | ProcessAccessFlags.VMRead |
        ProcessAccessFlags.VMWrite | ProcessAccessFlags.QueryInformation, false, pid);

        IntPtr p = VirtualAllocEx(process, IntPtr.Zero, (uint)Marshal.SizeOf(typeof(TBBUTTON)), AllocationType.Commit
                                     , MemoryProtection.ReadWrite);

        int _res = SendMessage(toolBarHandle, TB_GETBUTTON, cnt, p.ToInt32());

        #region getresult
        int read;
        IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(TBBUTTON)));
        Marshal.StructureToPtr(butInfo, ptr, true);
        bool __res = ReadProcessMemory(process, p, ptr, Marshal.SizeOf(typeof(TBBUTTON)), out read);
        System.Diagnostics.Debug.Assert(read == Marshal.SizeOf(typeof(TBBUTTON)));
        butInfo = (TBBUTTON)Marshal.PtrToStructure(ptr, typeof(TBBUTTON));
        #endregion

        int commandId = butInfo.idCommand;
        VirtualFreeEx(process, p, 0, FreeType.Release);

        #endregion

        //!define BST_UNCHECKED      0
        //!define BST_CHECKED        1
        //!define BST_INDETERMINATE  2
        //!define BST_PUSHED         4
        //!define BST_FOCUS          8

        #region get state
        res = SendMessage(toolBarHandle, TB_GETSTATE, commandId, 0);
        #endregion
    }
}
#endregion

编辑:
这里 http://www.andreas-reiff.de/2011/06/c-speicher-anderen-prozess-befullen-lassen-checken-ob-ein-button-gedruckt/ 具有可读代码和解释用一种奇怪的外语......不过,代码注释是英语。希望你觉得它有用。
另外,如果没有这里的信息,我将无法解决这个问题 为什么有些控件没有窗口句柄?

(edit: so I finally managed to make the code format properly here - just insert 4 spaces at the beginning.)

Enjoy it, it took me quite a long time to get it to work.. but now I feel like having reached a new level. :)

(please tell me how to make it format properly - both quote and code failed on me)

int res;
#region direct method
int hwnd = ae.Current.NativeWindowHandle;
if (hwnd != 0)
{
    const UInt32 BM_GETSTATE = 0x00F2;
    res = SendMessage(hwnd, BM_GETSTATE, 0, 0);
}
#endregion
else
#region method via toolbar
{
    AutomationElement parent = TreeWalker.RawViewWalker.GetParent(ae);
    while ((parent != null) && (parent.Current.ControlType != ControlType.ToolBar))
        parent = TreeWalker.RawViewWalker.GetParent(ae);
    if (parent != null)
    {
        int toolBarHandle = parent.Current.NativeWindowHandle;
        #region defines
        const int WM_USER = 0x400;
        const int TB_GETSTATE = (WM_USER + 18);
        const int TB_GETBUTTON = (WM_USER + 23);
        const int TB_BUTTONCOUNT = (WM_USER + 24);
        #endregion

        #region get correct child number
        int numButtons = SendMessage(toolBarHandle, TB_BUTTONCOUNT, 0, 0);
        AutomationElement sibling = ae;
        int cnt = -1;
        while (sibling != null)
        {
            sibling = TreeWalker.RawViewWalker.GetPreviousSibling(sibling);
            ++cnt;
        }
        if (cnt >= numButtons)
            cnt = 0; // nonsense value, but pass a valid one
        #endregion

        #region get command id
        TBBUTTON butInfo = new TBBUTTON();
        butInfo.idCommand = 1234;
        uint pid;
        GetWindowThreadProcessId((IntPtr)toolBarHandle, out pid);
        IntPtr process = OpenProcess(ProcessAccessFlags.VMOperation | ProcessAccessFlags.VMRead |
        ProcessAccessFlags.VMWrite | ProcessAccessFlags.QueryInformation, false, pid);

        IntPtr p = VirtualAllocEx(process, IntPtr.Zero, (uint)Marshal.SizeOf(typeof(TBBUTTON)), AllocationType.Commit
                                     , MemoryProtection.ReadWrite);

        int _res = SendMessage(toolBarHandle, TB_GETBUTTON, cnt, p.ToInt32());

        #region getresult
        int read;
        IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(TBBUTTON)));
        Marshal.StructureToPtr(butInfo, ptr, true);
        bool __res = ReadProcessMemory(process, p, ptr, Marshal.SizeOf(typeof(TBBUTTON)), out read);
        System.Diagnostics.Debug.Assert(read == Marshal.SizeOf(typeof(TBBUTTON)));
        butInfo = (TBBUTTON)Marshal.PtrToStructure(ptr, typeof(TBBUTTON));
        #endregion

        int commandId = butInfo.idCommand;
        VirtualFreeEx(process, p, 0, FreeType.Release);

        #endregion

        //!define BST_UNCHECKED      0
        //!define BST_CHECKED        1
        //!define BST_INDETERMINATE  2
        //!define BST_PUSHED         4
        //!define BST_FOCUS          8

        #region get state
        res = SendMessage(toolBarHandle, TB_GETSTATE, commandId, 0);
        #endregion
    }
}
#endregion

EDIT:
Here http://www.andreas-reiff.de/2011/06/c-speicher-anderen-prozess-befullen-lassen-checken-ob-ein-button-gedruckt/ with readable code and explanations in a strange, foreign language.. code comments are english, though. hope you find it useful.
Also, I would not have been able to solve this without the info here How come some controls don't have a windows handle?.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文