从Windows应用程序的文本框中抓取文本
本文关键字:抓取 取文本 文本 Windows 应用程序 | 更新日期: 2023-09-27 18:16:41
是否有可能从包含在单独可执行文件中的文本框中抓取文本?我有一个应用程序,有一个调试窗口。调试窗口生成详细日志。然而,日志永远不会保存在任何地方,只能在应用程序中查看。如果应用程序产生一个异常,我想给自己发电子邮件,知道一个异常已经产生,这样我就可以跳进去检查出来。还有一个按钮来复制文本框,所以我想使用spy++来获取命令信息。然而,我不知道从那里去哪里。如有任何建议,不胜感激。
我更喜欢在。net中使用c#,但如果我需要使用c++,我会的。
:
根据这些评论,我试着做了以下事情:
Private Declare Function GETWINDOWTEXT Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As Integer, ByVal lpString As String, ByVal cch As Integer) As Integer
Private Declare Function SetForegroundWindow Lib "user32.dll" (ByVal hwnd As Integer) As Integer
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindow As String) As IntPtr
Private Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As Integer, ByVal hWnd2 As Integer, ByVal lpsz1 As String, ByVal lpsz2 As String) As Integer
Private Declare Ansi Function SendMessage Lib "user32.dll" Alias "SendMessageA" (ByVal hwnd As Integer, ByVal wMsg As Integer, ByVal wParam As Integer, ByVal lParam As String) As Integer
Private Const WM_GETTEXT As Short = &HDS
Private Const WM_GETTEXTLENGTH As Short = &HES
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
Dim hwnd As Integer = FindWindowEx(0, 0, "MyAppForm", "Hello World")
If Not hwnd = 0 Then
SetForegroundWindow(hwnd)
'Dim LabelEx As Integer = FindWindowEx()
Dim TextBoxEx As Integer = FindWindowEx(hwnd, 0, "MyAppTextBox", vbNullString)
Dim txtLength As Long = SendMessage(TextBoxEx, WM_GETTEXTLENGTH, CInt(0), CInt(0)) + 1
Dim txtBuff As String = Space(txtLength)
Dim txtValue As Long = SendMessage(TextBoxEx, WM_GETTEXT, txtLength, txtBuff)
MsgBox(txtBuff)
End If
End Sub
然而,我似乎找不到文本框控件的句柄。当我枚举所有窗口时,我只看到一个TextBox对象,但是在枚举过程中我多次看到父对象。我怎样才能把指针指向窗口内的控件?
UPDATE 2:
我已经上传了一个示例Windows应用程序,以显示我试图访问的应用程序类型。我试图得到两个标签的值,除了文本框。文本框是最重要的。示例Win应用程序如下:http://www.mediafire.com/file/172r2xapj7p4f2f/StatusSimulator.zip
文本抓取由可访问性接口完成。对于托管代码,您可以使用System.Windows.Automation
名称空间中的类。如果您已经有一个窗口句柄,那么提取文本很简单:
AutomationElement.FromHandle(hwnd)
.GetCurrentPropertyValue(ValuePattern.ValueProperty) as string;
(有点困惑,因为问题被标记为c#,你要求c#解决方案,但你的代码样本是在VB。)
当你使用WM_GETTEXT消息时,你提供了一个指向接收文本的缓冲区的指针。如果你将此消息发送到另一个进程的窗口,那么你提供的指针将在你的进程地址空间中,而不是其他进程。
我做过类似的事情(在另一个进程中刮窗),我所做的工作是使用DLL注入。基本上你使用SetWindowsHook并在DLL中提供一个回调。然后,操作系统将DLL加载到其他进程中,您可以计算何时加载到所需的目标进程中。此时,您的代码处于另一个进程中,您可以获得窗口文本。
然后是将它返回到你的应用程序的问题。我自己使用共享内存块来做这件事。也许有一种更简单的方法可以做到这一切,但这在过去对我来说很有效。
您对GetWindowText
的p/Invoke定义不正确。使用P/Invoke String
类型只编组在,而不是出,这就是为什么你没有得到任何文本返回。如果您将lpString参数更改为StringBuffer
,它将工作。
注意,在将StringBuffer传递给GetWindowText
之前,您还需要将其容量设置为1000,因为它需要将已分配的缓冲区传递给它-它不会自行调整StringBuffer的大小。
见定义和示例和pinvoke.net。
<DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
Private Shared Function GetWindowText(ByVal hwnd As IntPtr, ByVal lpString As StringBuilder, ByVal cch As Integer) As Integer
End Function
Private Declare Function SetForegroundWindow Lib "user32.dll" (ByVal hwnd As Integer)
As Integer
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindow As String) As IntPtr
Private Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As Integer, ByVal hWnd2 As Integer, ByVal lpsz1 As String, ByVal lpsz2 As String) As Integer
Private Declare Ansi Function SendMessage Lib "user32.dll" Alias "SendMessageA" (ByVal hwnd As Integer, ByVal wMsg As Integer, ByVal wParam As Integer, ByVal lParam As String) As Integer
Private Const WM_GETTEXT As Short = &HDS
Private Const WM_GETTEXTLENGTH As Short = &HES
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
Dim hwnd As Integer = FindWindowEx(0, 0, "MyAppForm", "Hello World")
If Not hwnd = 0 Then
SetForegroundWindow(hwnd)
'Dim LabelEx As Integer = FindWindowEx()
Dim TextBoxEx As Integer = FindWindowEx(hwnd, 0, "MyAppTextBox", vbNullString)
Dim txtLength As Long = SendMessage(TextBoxEx, WM_GETTEXTLENGTH, CInt(0), CInt(0)) + 1
Dim txtBuff As New System.Text.StringBuilder(txtLength + 1)
GetWindowText(hWnd, txtBuff , txtBuff .Capacity)
Dim txtValue As Long = SendMessage(TextBoxEx, WM_GETTEXT, txtLength, txtBuff)
MsgBox(txtBuff.ToString())
End If
End Sub