从 Process.MainWindowHandle 获取 child window

Obtain child window from Process.MainWindowHandle

我想从进程名称中获取文本框句柄。我用 Spy++ 检查了它(这是一个在互联网上找到的 exe,所以没什么特别的):

现在我想得到这个 TEdit,但它总是 return NULL。我做错了什么?

[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string className, string lpszWindow);

private static void Main(string[] args)
{
    var processes = Process.GetProcesses();
    var proc = Array.Find(processes, x => string.Equals(x.MainWindowTitle, "ExeLock", StringComparison.OrdinalIgnoreCase));
    var handle = proc.MainWindowHandle;


    //IntPtr edit = FindWindowEx(handle, IntPtr.Zero, "TEdit", null);

    IntPtr hwndparent = handle, hwndchild = IntPtr.Zero;
    do
    {
        hwndchild = FindWindowEx(hwndparent, hwndchild, null, null);
    } while (hwndchild != IntPtr.Zero);
}

我没有找到它,因为它创建了多个 windows,其中一些是隐藏的(包括 "main window")。这是屏幕截图:

所以我只是枚举进程的每个 window,找到 TFormPassDialog 然后一切正常。这是我的代码:

class ExeLockFounder
{
    const uint WM_SETTEXT = 0x000C;
    delegate bool EnumDelegate(IntPtr hWnd, IntPtr lParam);

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

    [DllImport("user32.dll", SetLastError = true)]
    private static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string className, string lpszWindow);

    [DllImport("user32.dll")]
    static extern bool EnumThreadWindows(int dwThreadId, EnumDelegate lpfn, IntPtr lParam);

    [DllImport("user32.dll")]
    static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, [MarshalAs(UnmanagedType.LPStr)] string lParam);

    private static IntPtr GetWindowByClassName(IEnumerable<IntPtr> windows, string className)
    {
        foreach (var window in windows)
        {
            var sb = new StringBuilder(256);
            GetClassName(window, sb, sb.Capacity);
            if (sb.ToString() == className)
                return window;
        }
        return IntPtr.Zero;
    }

    static IEnumerable<IntPtr> EnumerateProcessWindowHandles(Process process)
    {
        var handles = new List<IntPtr>();
        foreach (ProcessThread thread in process.Threads)
            EnumThreadWindows(thread.Id, (hWnd, lParam) => { handles.Add(hWnd); return true; }, IntPtr.Zero);
        return handles;
    }

    private readonly IntPtr _editHandle;

    public ExeLockFounder()
    {
        var processes = Process.GetProcessesByName("Setup");
        var proc = Array.Find(processes, x => string.Equals(x.MainWindowTitle, "ExeLock", StringComparison.OrdinalIgnoreCase));

        var windows = EnumerateProcessWindowHandles(proc);
        var hWnd = GetWindowByClassName(windows, "TFormPassDialog");
        _editHandle = FindWindowEx(hWnd, IntPtr.Zero, "TEdit", null);
    }

    public void SendText(string message)
    {
        SendMessage(_editHandle, WM_SETTEXT, IntPtr.Zero, message);
    }
}