ChangeWindowMessageFilterEx() 返回错误代码 5

ChangeWindowMessageFilterEx() Returns Error Code 5

本文关键字:错误代码 返回 ChangeWindowMessageFilterEx      更新时间:2023-10-16

我想获取窗口中复选框的状态。

所以我用了SendMessage(hwnd, BM_GETCHECK, NULL, NULL),但它总是返回0。为了知道为什么,我使用了 GetLastError((,它返回了 5。

在Microsoft的文档中,它说"当消息被UIPI阻止时,使用GetLastError检索的最后一个错误设置为5(拒绝访问(。

因此,经过一些研究,我使用ChangeWindowMessageFilterEx(hwnd, BM_GETCHECK, MSGFLT_ALLOW, 0)来绕过特权问题。

ChangeWindowMessageFilterEx()也给出错误代码 5 并返回 false。

但是,当我使用ChangeWindowMessageFilter()时,它返回 true 并给出错误代码 0。但SendMessage(hwnd, BM_GETCHECK, NULL, NULL)仍然给出错误代码 5。

方法1

status = ChangeWindowMessageFilterEx(hwnd, BM_GETCHECK, MSGFLT_ALLOW, 0); //returns false
error = ::GetLastError(); // gives error code 5
chk_state = SendMessage(hwnd, BM_GETCHECK, NULL, NULL);

方法2

status = ChangeWindowMessageFilter(BM_GETCHECK, MSGFLT_ADD); //returns true
error = ::GetLastError() // gives error code 0
chk_state = SendMessage(hwnd, BM_GETCHECK, NULL, NULL);
error = ::GetLastError(); // gives error code 5   

我在这里做错了什么?

终于找到了获取复选框状态的替代方法。检查.exe是救世主。感谢韩@Rita - MSFT建议检查.exe。由于更改权限/访问权限或绕过 UIPI 限制并不复杂,因此我们决定使用 UIAutomation。我们使用UIAutomation检索了设置窗口中的所有数据!

有两种方法可以获取此方案的复选框状态。

  1. 以与目标程序相同或更高的完整性级别运行程序,例如,在提升模式下运行程序可能会有所帮助,因为大多数程序都在高完整性下运行。您还可以在清单中指定级别,如下所示(请参阅/MANIFESTUAC(

    /MANIFESTUAC:level=_level

  2. 跨权限级别绕过 SendMessage 的 UIPI 限制可用于使用程序应用程序清单中的特殊安全属性(称为 UIAccess(的 UI 自动化程序。下面是 UIAccess 程序的应用程序清单条目的示例。

    <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3"> <security> <requestedPrivileges> <requestedExecutionLevel level="asInvoker" UIAccess="true" /> </requestedPrivileges> </security> </trustInfo>

通过在 requestPrivileges 属性中指定UIAccess="true">,应用程序声明了绕过跨权限级别发送窗口消息的 UIPI 限制的要求。Windows Vista 在启动具有 UIAccess 权限的应用程序之前实现以下策略检查。

  • 应用程序必须具有可验证的数字签名 使用链接到受信任根的数字证书 本地计算机受信任的根证书颁发机构证书 商店。

  • 应用程序必须安装在本地文件夹应用程序中 只能由管理员写入的目录,例如 程序文件目录。UI 自动化允许的目录 应用有:

    %
    • 程序文件%及其子目录。
    • %WinDir% 及其子目录,但由于标准用户具有写入访问权限而被排除的几个子目录除外。

有关详细信息,请参阅文档:

强制性完整性控制

但现在唯一的问题是只有在将鼠标悬停在该元素上后才能检索复选框状态。我正在为此找到解决方案。无论如何,如果你能对此有所了解,那就太好了。

我们可以通过窗口处理程序获取元素,而不是在鼠标悬停后获取元素。以下是获取复选框状态的代码供您参考:

CoInitialize(NULL);
IUIAutomation * UIAutomation;
InitializeUIAutomation(&UIAutomation);
IUIAutomationElement *targetIUIAutomationElement;
UIAutomation->ElementFromHandle((UIA_HWND)0x513F8,&targetIUIAutomationElement);
VARIANT checkboxState;
targetIUIAutomationElement->GetCurrentPropertyValue(UIA_ToggleToggleStatePropertyId,&checkboxState);
if(checkboxState.lVal== ToggleState_Off)
std::cout << "The check box is not checked...n";
else if(checkboxState.lVal == ToggleState_On)
std::cout << "The check box is checked...n";
else
std::cout << "The checkbox is in indeterminate...n";

如果您只想查询复选框的状态,而不是使用 SendMessage,您可以只检查可访问性树。 也就是说,使用与屏幕阅读器相同的 API。

从 AccessObjectFromWindow 和朋友开始。