【问题标题】:Check if a Winform CheckBox is checked through WINAPI only检查是否仅通过 WINAPI 检查 Winform CheckBox
【发布时间】:2015-04-01 13:52:09
【问题描述】:

我的问题是这样的: 我需要检查是否仅通过 WINAPI 检查了来自不同程序的 winform 复选框。

这里我是如何捕捉底层 C# HWND 的: 首先,我使用 EnumWindows 和 EnumChildWindows 获取桌面的所有 HWND,然后我继续使用 GetWindowText 将我想要的文本与窗口文本进行比较,如果匹配 - 我将其返回。

只是为了让事情清楚 - 我可以捕捉到底层的 HWND。如果我打印它的文本和类名,它就是想要的 winform 复选框。

现在,我要检查的复选框具有 WindowsForm.10.BUTTON.app.0.33c0d9d5 类名。使用此功能,我会询问它是否是有效的复选框:

bool isValid(){
    if(!handleToControl) return false;
    LONG_PTR styles = GetWindowLongPtr(handleToControl, GWL_STYLE);
    bool isCheckBox = ((styles & BS_AUTO3STATE) == BS_AUTO3STATE);
    isCheckBox = isCheckBox || ((styles & BS_AUTOCHECKBOX) == BS_AUTOCHECKBOX);
    isCheckBox = isCheckBox || ((styles & BS_CHECKBOX) == BS_CHECKBOX);
    return isCheckBox;
}

现在,该功能确实有效(我在许多本机复选框和 winform 复选框上都检查了它)并且它可以验证它是否是有效的复选框(包括我要检查的复选框)

然后,我尝试使用此功能查看是否选中了 winform 复选框:

bool isChecked(){
    LRESULT _isChecked = SendMessage(handleToControl, BM_GETCHECK, 0, 0);
    bool ic = !(_isChecked == BST_UNCHECKED);
    if (ic)
        return ic;
    ic = ((Button_GetState(handleToControl) & BST_CHECKED) == BST_CHECKED);
    if (ic)
        return ic;

    return false;
}

但我失败得很惨。有人可以看到我的想法/代码有什么问题或提出不同的解决方案吗?

【问题讨论】:

  • MSDN saysIf the button has a style other than those listed, the return value is zero.,也许这就是它不起作用的原因。
  • 好的,还有其他想法如何实现吗?
  • Winforms CheckBox 控件是从头开始重新实现的,它不使用本机 Windows 控件。所以不会响应BM_GETCHECK。它也没有提供替代方案。您需要使用 UI 自动化来到达某个地方,周围有很多库。
  • 那么为什么它会响应 enumchildwindows 、 getwindowtext、getclassname 等?
  • 因为它还是一个窗口,只是不属于复选框对应的内置窗口类。我不确定 WinForms 是否是这种情况,以为只有 WPF 手动绘制所有组件。

标签: c# c++ winforms winapi win32gui


【解决方案1】:

是否使用IAccessibility 选项?

例如

(取自http://bytes.com/topic/net/answers/637107-how-find-out-if-check-box-checked

[DllImport("oleacc.dll")]
internal static extern int AccessibleObjectFromWindow(IntPtr hwnd, uint id, ref Guid iid, [In, Out, MarshalAs(UnmanagedType.IUnknown)] ref object ppvObject); 

internal enum OBJID : uint
{
    WINDOW = 0x00000000,
    SYSMENU = 0xFFFFFFFF,
    TITLEBAR = 0xFFFFFFFE,
    MENU = 0xFFFFFFFD,
    CLIENT = 0xFFFFFFFC,
    VSCROLL = 0xFFFFFFFB,
    HSCROLL = 0xFFFFFFFA,
    SIZEGRIP = 0xFFFFFFF9,
    CARET = 0xFFFFFFF8,
    CURSOR = 0xFFFFFFF7,
    ALERT = 0xFFFFFFF6,
    SOUND = 0xFFFFFFF5,
}

public const long UNCHECKED = 1048576;
public const long CHECKED = 1048592;
public const long UNCHECKED_FOCUSED = 1048580; // if control is focused
public const long CHECKED_FOCUSED = 1048596; // if control is focused

private static bool IsChecked(IntPtr handle) {
    Guid guid = new Guid("{618736E0-3C3D-11CF-810C-00AA00389B71}");
    Object obj = null;
    int retValue = AccessibleObjectFromWindow(handle, (uint) OBJID.CLIENT, ref guid, ref obj);

    if (obj is IAccessible) {
        IAccessible accObj = (IAccessible) obj;
        Object result = accObj.get_accState(0);
        if (result is int) {
            int state = (int) result;
            return (state == CHECKED || state == CHECKED_FOCUSED);
        }
    }
    return false;
}

【讨论】:

  • 呃,你说的肯定是 UI 自动化
  • @DavidHeffernan 不,我认为它们是不同的。您必须将 Accessibility 引用添加到项目中,这与 UI 自动化是分开的。不过我可能是错的。
  • 我会在原生 C++ 中尝试一下。你觉得obj is IAccessible这行可以翻译成if(dynamic_cast<IAccessible>(someVaribale))吗?
  • 在此代码的情况下,您将IID_IAccessible 传递给AccessibleObjectFromWindow();如果对象不是 IAccessible,则函数将失败并显示 E_NOINTERFACE,因此根本不需要该语句。 (它不应该是 IAccessible;AccessibleObjectFromWinow() 是为 IAccessible 设计的...) David Hefferman 建议您使用较新的 UI 自动化 API 而不是古老的 MSAA API。代码不同,但思路是一样的。 Loathing 自己的软件也可能受益,因为 UI 自动化的设计考虑了 .net。
  • 我非常感谢这个页面/cmets。我花了几个小时(可悲地)了解到具有样式的复选框在(如 xaizek 最初指出的那样)时总是返回零(使用 BM_GETCHECK 消息):If the button has a style other than those listed, the return value is zero. 我也非常感谢这段代码,因为它正在工作。 :)
猜你喜欢
  • 2020-09-28
  • 1970-01-01
  • 1970-01-01
  • 2020-12-25
  • 1970-01-01
  • 1970-01-01
  • 2017-12-27
  • 1970-01-01
  • 2017-05-20
相关资源
最近更新 更多