Search code examples
freepascalfindwindowex

Finding correct handle for edit box with FindWindowEx()


I'm trying to post some text to an edit box that is on 3rd level on the windows tree. The following code works ok for notepad (vrr02) but not in another program (Var03).

procedure TEcr01.Button1Click(Sender: TObject);
var Var01, Var02, Var03, vrr01, vrr02: HWND;
    MyTxt : string;
begin
  Var01 := FindWindow('#32770', nil);
  Var02 := FindWindowEx(Var01, 0, '#32770', nil);
  Var03 := FindWindowEx(Var01, Var02, 'Edit', nil);
  vrr01 := FindWindow('notepad', nil);
  vrr02 := FindWindowEx(vrr01, 0, 'edit', nil);
  MyTxt := 'This is some text.';
  SendMessage(Var03, WM_SETTEXT, 0, integer(MyTxt));
  SendMessage(vrr02, WM_SETTEXT, 0, integer(MyTxt));
end;

The following image has in blue the Edit I want to post to but nothing is showing there. What am I doing wrong here?

Spy++ print-screen

Thanks.


Solution

  • With your current code you can't be sure if you've got the window handle you want at any of the stages.

    "#32770" is standard dialog class, there can be many window of this class at any given time in a user session. You're passing nil for lpWindowName parameter in your FindWindow call, documentation states:

    lpWindowName [in, optional]
    Type: LPCTSTR


    The window name (the window's title). If this parameter is NULL, all window names match.

    So there is a probability that you have an entirely different window's handle at Var01 which have the same class but different window title.

    Or none at all. That's why you have to check if the function failed or not after every API call. Refer to the function's documentation for how.


    Var01 := FindWindow('#32770', 'Object Properties');
    Win32Check(Var01 <> 0);
    

    The above call specifies both class name and the window title which as much as guarantees that the function will return the window handle that you want.

    Var02 := FindWindowEx(Var01, 0, '#32770', nil);
    Win32Check(Var02 <> 0);
    

    The call for Var02 looks alright. But Var03's parent is Var02, so you've got the third call wrong again.

    Var03 := FindWindowEx(Var02, 0, 'Edit', nil);
    Win32Check(Var03 <> 0);
    

    This will retrieve the first Edit, the hidden one. You must call FindWindowEx again to retrieve the child you want, specify the previous window as the ChildAfter parameter.

    Var03 := FindWindowEx(Var02, Var03, 'Edit', nil);
    Win32Check(Var03 <> 0);
    

    Also note that SendMessage's fourth parameter is not an integer, always refer to documentation.

    All in all:

    Var01 := FindWindow('#32770', 'Object Properties');
    Win32Check(Var01 <> 0);
    Var02 := FindWindowEx(Var01, 0, '#32770', nil);
    Win32Check(Var02 <> 0);
    Var03 := FindWindowEx(Var02, 0, 'Edit', nil);
    Win32Check(Var03 <> 0);
    Var03 := FindWindowEx(Var02, Var03, 'Edit', nil);
    Win32Check(Var03 <> 0);
    MyTxt := 'This is some text.';
    SendMessage(Var03, WM_SETTEXT, 0, LPARAM(MyTxt));
    SendMessage(vrr02, WM_SETTEXT, 0, LPARAM(MyTxt));