Очистить текст из текстового поля в приложении Windows - PullRequest
5 голосов
/ 04 декабря 2011

Можно ли выскрести текст из текстового поля, которое содержится в отдельном исполняемом файле? У меня есть приложение, которое имеет окно отладки. Окно отладки генерирует подробный журнал. Тем не менее, журнал никогда не сохраняется нигде и может быть просмотрен только в приложении. Если приложение генерирует исключение, я хотел бы написать себе по электронной почте, зная, что исключение было сгенерировано, чтобы я мог прыгнуть и проверить вещи. Также есть кнопка для копирования текстового поля, поэтому я подумал об использовании Spy ++ для получения информации о команде. Тем не менее, я не знаю, куда идти оттуда. Любые указатели очень ценятся.

Я бы предпочел использовать C # в .NET, но если мне нужно будет использовать C ++, я буду.

UPDATE

Основываясь на комментариях, я попытался сделать следующее:

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. Когда я перечисляю все окна, я вижу только один объект TextBox, но я вижу родителя несколько раз в течение перечисления. Как я могу получить указатели на элементы управления в окне?

ОБНОВЛЕНИЕ 2:

Я загрузил пример приложения для Windows, чтобы показать тип приложения, к которому я пытаюсь получить доступ. Я пытаюсь получить значения обеих меток в дополнение к текстовому полю. Текстовое поле является наиболее важным. Пример приложения Win находится здесь: http://www.mediafire.com/file/172r2xapj7p4f2f/StatusSimulator.zip

Ответы [ 3 ]

3 голосов
/ 08 декабря 2011

Очистка текста осуществляется с помощью интерфейсов доступности.Для управляемого кода вы можете использовать классы в пространстве имен System.Windows.Automation.Если у вас уже есть дескриптор окна, то извлечь текст просто:

AutomationElement.FromHandle(hwnd)
                 .GetCurrentPropertyValue(ValuePattern.ValueProperty) as string;

(Вид сбит с толку, поскольку вопрос помечен C #, и вы запрашиваете решение C #, но ваш пример кода находится в VB.)

2 голосов
/ 08 декабря 2011

Когда вы используете сообщение WM_GETTEXT, вы предоставляете указатель на буфер, который получает текст.Если вы отправляете это сообщение окну в другом процессе, то указанный вами указатель будет находиться в адресном пространстве вашего процесса, а не в другом процессе.

Я сделал нечто похожее на это (очистка окон в другом процессе) и что я сделал, который работал, чтобы использовать инъекции DLLВ основном вы используете SetWindowsHook и предоставляете обратный вызов внутри DLL.Затем ОС загружает DLL в другие процессы, и вы выясняете, когда вы загрузили нужный целевой процесс.В этот момент ваш код находится в другом процессе, и вы можете получить текст окна.

Тогда возникает вопрос, как вернуть его в ваше приложение.Я использовал блок общей памяти, чтобы сделать это сам.Может быть, есть более простой способ сделать все это, но это работало для меня в прошлом.

1 голос
/ 09 декабря 2011

Ваше определение P / Invoke для GetWindowText неверно. С P / Invoke String типы только маршалируются, а не выводятся, поэтому вы не получаете текст обратно. Если вы измените параметр lpString на StringBuffer, он будет работать.

Обратите внимание, что вам также необходимо установить емкость StringBuffer равной 1000, прежде чем передавать ее в GetWindowText, поскольку для этого требуется, чтобы ему был передан выделенный буфер - он не будет измерять сам 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
...