使用SendMessage API获取CheckListBox中项目的状态



我使用一个软件来操作另一个软件,比如软件测试环境,目的是获取一些值并执行一些任务。为此,我使用SendMessage API,它在除了CheckListBox之外的几乎所有Windows控件中都能很好地工作。"slave"软件是在Delphi中创建的,所以,我不确定CheckListBox是否是标准的Windows控件,无论如何,这是MS的文档:
https://learn.microsoft.com/en-us/windows/win32/controls/list-boxes
在这个控件中,我可以获得项目的数量、文本、选择了哪一个,以及许多其他信息,但我无法知道项目是否被检查。我试着使用一些工具,比如"Windows辅助功能洞察"和AutoIt,但没有结果
关于如何获取Delphi CheckListBox中复选框的状态,有什么想法吗
提前谢谢。

Delphi将检查的信息存储在TCheckListBoxDataWrapper对象中。指向该对象的指针存储在复选框项的常规"项数据"中。然后这个对象有一个布尔属性State,您可以在偏移量8处找到它。

注意:如果你的程序的特定Delphi版本的偏移量与8不同,请尝试附近的-4,12,…-它不可能走得很远

要了解是否检查了某个项目,您需要:

  1. 获取指向该项的TCheckListBoxDataWrapper的指针。这可以通过发送LB_GETITEMDATA消息来完成。如果你得到零,它也算作未检查
  2. 由于这个指针指向的是另一个进程中的内存,而不是你的内存,所以你不能简单地取消引用它。相反,你需要使用ReadProcessMemory。知道State属性的偏移量为8,就可以调用ReadProcessMemory(hProcess, itemData + 8, &checked, 1, NULL)将1个字节读入变量checked。(您首先需要使用OpenProcess打开目标进程。(

然后您将在checked中检查项目的状态!1表示已检查,0表示未检查。


如果您以后也需要访问一些其他内部状态,另一个提示:有一个窗口属性ControlOfsXXXXXXXXYYYYYYYYX是窗口所有者的HINSTANCE(基址((通常是00400000(,Y是窗口所有者(十六进制(线程ID(您可以使用GetWindowThreadProcessId来获取它(。您可以使用GetProp来获取该属性的值,该属性将是指向控制对象(在本例中为TCheckListBox本身(的指针。然后,您可以随意使用ReadProcessMemory来获取所需的其他数据。不过,您需要知道偏移量(但您可以使用调试器来尝试找出它们(。用相同的Delphi版本编译一个测试程序并在那里执行访问这些属性的函数是非常有帮助的,然后你可以调试自己的测试程序,更容易地计算偏移量。

一种更先进的方法是将自定义DLL(用同一个Delphi版本编写(注入目标进程,从而可以更直接地访问(读取和写入(这类数据。很久以前我写过一篇关于这个的文章。

正如@CherryDT发布的那样,这是访问CheckListBox状态的方法。我使用AutoIt来测试提示,因为目前这是我测试它的最快方法。
代码:

;------------------------------------------------------------------------------
;   Retuns the state of the indicated item in the CheckListBox control.
;   Parameter:
;       $iPID: process ID (PID)
;       $hWnd: the handle of the CheckListBox control
;       $iIndex: index of the item in the list (0 based)
;------------------------------------------------------------------------------
Func CtrlListBox_GetState($iPID, $hWnd, $iIndex)
Local $hProc                             ; Handle of the process.
Local $pItem                             ; Pointer to the item.
Local $pData = DllStructCreate("byte")   ; Data structure.
Local $iQty                              ; Size of data read.
Local Const $LB_STATE_SHIFT = 8          ; State position in the memory.
$hProc = _WinAPI_OpenProcess(0x1F0FFF, False, $iPID)     ; 0x1F0FFF = PROCESS_ALL_ACCESS
$pItem = _GUICtrlListBox_GetItemData($hWnd, $iIndex) + $LB_STATE_SHIFT
_WinAPI_ReadProcessMemory($hProc, $pItem, DllStructGetPtr($pData), DllStructGetSize($pData), $iQty)
Return DllStructGetData($pData, 1)
EndFunc
;------------------------------------------------------------------------------
;   Retuns the state of the indicated item in the CheckListBox control.
;   Parameter:
;       $iPID: process ID (PID)
;       $hWnd: the handle of the CheckListBox control
;       $iIndex: index of the item in the list (0 based)
;       $bState: state deseired (true or false)
;------------------------------------------------------------------------------
Func CtrlListBox_SetState($iPID, $hWnd, $iIndex, $bState)
Local $hProc                             ; Handle of the process.
Local $pItem                             ; Pointer to the item.
Local $pData = DllStructCreate("byte")   ; Data structure.
Local $iQty                              ; Size of data read.
Local Const $LB_STATE_SHIFT = 8          ; State position in the memory.
if($bState <> 0) Then
DllStructSetData($pData, 1, True)
Else
DllStructSetData($pData, 1, False)
EndIf
$hProc = _WinAPI_OpenProcess(0x1F0FFF, False, $iPID)     ; 0x1F0FFF = PROCESS_ALL_ACCESS
$pItem = _GUICtrlListBox_GetItemData($hWnd, $iIndex) + $LB_STATE_SHIFT
_WinAPI_WriteProcessMemory($hProc, $pItem, DllStructGetPtr($pData), DllStructGetSize($pData), $iQty)
Return DllStructGetData($pData, 1)
EndFunc

我在VB.Net中开发的UI的CheckedListBox中尝试获取复选框的状态时遇到了类似的问题。我想获取状态(选中/取消选中(,这样我就可以在Python+Winium中从我的测试自动化框架开发人员那里执行所需的事件。这是特别需要的,以避免意外取消选中已选中的项目。

在我的研究过程中,我知道使用Winium并不容易,所以我在UI上添加了一个按钮,用于在选中所需复选框之前重置所有复选框。

希望它能有所帮助。

最新更新