-1

I want to get a textbox handle from process name. I checked it with Spy++ (it's an exe found in the internet, so nothing special):

enter image description here

now i want to get this TEdit, but it always return NULL. What am I doing wrong?

[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);
}
Alex Zhukovskiy
  • 9,565
  • 11
  • 75
  • 151
  • Have you verified that the MainWIndowHandle is the window you expect it to be? – Mark Jansen Aug 13 '15 at 14:45
  • What are you planning to do to this window when you find it? For many cases (reading text from it or putting text in it, among others), you might want to consider using [UI Automation](https://msdn.microsoft.com/en-us/library/ms747327(v=vs.110).aspx) instead. It's got a bit of learning curve but it does let you work at a more semantic level than fiddling around with window handles. – Damien_The_Unbeliever Aug 13 '15 at 14:47
  • Call EnumChildWindows and wait until you get one with a class name of `TEdit`. – David Heffernan Aug 13 '15 at 14:50
  • I found what's is wrong: process creates two windows: ExeLock : TApplication and Exe Lock : TFormPassDialog, and the last one is not the child of first. I guess I should enum all windows by caption to get it. – Alex Zhukovskiy Aug 13 '15 at 14:51
  • Hard to see how this could possibly work, you missed the space in "Exe Lock". And *never* use GetProcesses(), that just causes random failure, always GetProcessesByName(). – Hans Passant Aug 13 '15 at 15:15
  • No, I didn't miss it, it's just another window title. See answer below. And thanks for `GetProcesses` remark, I replaced it with `GetProcessByName`. – Alex Zhukovskiy Aug 13 '15 at 15:22

1 Answers1

0

I didn't found it because it creates multiple windows and some of them are hidden (including "main window"). Here is screenshot:

enter image description here

So I just enum every window of a process, find TFormPassDialog and then everything works fine. Here is my code:

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);
    }
}
Alex Zhukovskiy
  • 9,565
  • 11
  • 75
  • 151