开发者

Reading text from an external applications textbox

开发者 https://www.devze.com 2023-04-07 16:29 出处:网络
I am trying to extend some features of a external programm that is not able to use plugins or something. So I have to write my own app that reads the text from a textbox from this exter开发者_如何学Py

I am trying to extend some features of a external programm that is not able to use plugins or something. So I have to write my own app that reads the text from a textbox from this exter开发者_如何学Pythonnal application and trigger some own actions.

By using the FindWindow API in user32.dll I allready catched up the handle for the external application. But now I am kind of stuck. By using Spy++ from the Visual Studio Tools I got the information that the class name from the control I would like to read from is "WindowsForms10.EDIT.app.0.218f99c", but there are several of them. Additionally every time the external app starts it creates a new control id for the textbox I want to read.

How can I get it managed to identify a certain textbox and read the value of it? Can anybody give me a hint or kind of advice?


The Code in C#

public static class ModApi
{
    [DllImport("user32.dll", EntryPoint = "FindWindowA", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
    private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

    [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
    private static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);

    [DllImport("user32.dll", EntryPoint = "SendMessageTimeout", SetLastError = true, CharSet = CharSet.Auto)]
    public static extern uint SendMessageTimeoutText(IntPtr hWnd, int Msg, int countOfChars, StringBuilder text, uint flags, uint uTImeoutj, uint result);

    [DllImport("user32.dll", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
    static internal extern bool EnumChildWindows(IntPtr hWndParent, funcCallBackChild funcCallBack, IntPtr lParam);

    public delegate bool funcCallBackChild(IntPtr hWnd, IntPtr lParam);


    public static ArrayList TextBoxStrings = new ArrayList();
    public static void ParseWindowControls(string WindowTitle)
    {
        IntPtr hWnd = FindWindow(null, WindowTitle);
        TextBoxStrings.Clear();


        funcCallBackChild MyCallBack = EnumChildWindowsProc;
        EnumChildWindows(hWnd, MyCallBack, IntPtr.Zero);
    }

    private static bool EnumChildWindowsProc(IntPtr hWndParent, IntPtr lParam)
    {
        var buffer = new StringBuilder(256);
        long Retval = GetClassName(hWndParent, buffer, buffer.Capacity);
        if (buffer.ToString() == "Edit" || buffer.ToString() == "Static")
        {
            TextBoxStrings.Add(GetText(hWndParent));
        }

        return true;
    }

    private static string GetText(IntPtr hwnd)
    {
        var text = new StringBuilder(1024);
        if (SendMessageTimeoutText(hwnd, 0xd, 1024, text, 0x2, 1000, 0) != 0)
        {
            return text.ToString();
        }

        return "";
    }
}


After stumbling through several pages I found the solution how to retrieve the contents from a textbox from an external application. I think this code could be usefull for others too, so here is the result:

Module modApi

    Private Declare Function FindWindow Lib "user32.dll" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As IntPtr
    Private Declare Function GetClassName Lib "user32.dll" Alias "GetClassNameA" (ByVal hwnd As IntPtr, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long
    Private Declare Function SendMessageTimeoutString Lib "user32.dll" Alias "SendMessageTimeoutA" (ByVal hwnd As IntPtr, ByVal msg As Long, ByVal wParam As Long, ByVal lParam As String, ByVal fuFlags As Long, ByVal uTimeout As Long, ByVal lpdwResult As Long) As Long
    Friend Declare Function EnumChildWindows Lib "user32.dll" (ByVal hWndParent As IntPtr, ByVal funcCallBack As funcCallBackChild, ByVal lParam As IntPtr) As Boolean

    Public Delegate Function funcCallBackChild(ByVal hWnd As IntPtr, ByVal lParam As IntPtr) As Boolean

    Public TextBoxStrings As ArrayList = New ArrayList

    Public Sub ParseWindowControls(ByVal WindowTitle As String)
        Dim hWnd As IntPtr = FindWindow(vbNullString, WindowTitle)
        TextBoxStrings.Clear()
        If hWnd Then
            Dim MyCallBack As New funcCallBackChild(AddressOf EnumChildWindowsProc)
            EnumChildWindows(hWnd, MyCallBack, IntPtr.Zero)
        Else
            MsgBox("Could not find window!", vbOKOnly + vbExclamation, "Error")
        End If
    End Sub

    Private Function EnumChildWindowsProc(ByVal hWndParent As IntPtr, ByVal lParam As IntPtr) As Boolean
        Dim Buffer As String = Space(256)
        Dim Retval As Long = GetClassName(hWndParent, Buffer, Len(Buffer))
        If Left(Buffer, Retval) = "WindowsForms10.EDIT.app.0.218f99c" Then
            TextBoxStrings.Add(GetText(hWndParent))
        End If
        EnumChildWindowsProc = True
    End Function

    Private Function GetText(ByVal hwnd As IntPtr) As String
        Dim sText As String = Space(1024)
        If SendMessageTimeoutString(hwnd, &HD, 1024, sText, &H2, 1000, 0) <> 0 Then
            GetText = Left(sText, InStr(sText, vbNullChar) - 1)
            Exit Function
        End If
        GetText = ""
    End Function

End Module

You can pass a window title to the sub ParseWindowControls(). The sub tries to find the requested window. If the window is found it begins to gather all controls found in this application. The callback examines the found control if it meets my specifications (textbox) and stores the text in a arraylist. Later you just have to know the index of your requestet textbox and get it out of the arraylist. That's it. Hope this helps others too.

0

精彩评论

暂无评论...
验证码 换一张
取 消