Reputation: 113
I'm trying to access a third party application's "Text Boxes" using delphi programming so I need to find the handle of each "Text Box" using FindWindowEx(...) function .
The problem is , as all text boxes have the same class name with "NO window name" this function can just give me the first TextBOx handle !
How can I get the rest of text boxes handles while they have no names ?
Thanks in advance.
Upvotes: 3
Views: 8138
Reputation: 133
based @Sertac Akyus my Delphi 7 (2002) 32-Bit code for a Windows 10 64-Bit Pro
remote (local Desktop) application:
(Note: I do not know why, but all the codes here on SO with @s dont work !) :
| Win32API | desc. |
|:-------- | ----- |
| GetClassName(winHandle, @s, Length(s)+1); | this seems not work ! |
| GetClassName(winHandle, PChar(s), Length(s)+1); | this works ! |
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ComCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
ListBox1: TListBox;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
winHandle: HWND;
winTitle : string;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
var
s: String;
function EnumChildren(hwnd: HWND; lParam: LPARAM): BOOL; stdcall;
var
ClassName: array[0..259] of Char;
begin
Result := True;
GetClassName(hwnd, ClassName, Length(ClassName));
Form1.ListBox1.Items.Add(IntToHex(hwnd,8) + ' ' + ClassName);
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
ListBox1.Items.Clear;
// ---------------------------------
// 1. try to find main window hwnd:
// ---------------------------------
winHandle := FindWindow('TwinMain', nil);
if winHandle < 1 then begin
ListBox1.Items.Add('Error: 1.'); exit; end else
ListBox1.Items.Add('win: 0x' + IntToHex(winHandle,8));
// ---------------------------------
// 2. try to find window title:
// ---------------------------------
SetLength(winTitle, GetWindowTextLength(winHandle));
GetWindowText(winHandle, PChar(winTitle), Length(winTitle)+1);
if Length(Trim(winTitle)) < 2 then begin
ListBox1.Items.Add('Error: 2.'); exit; end else
ListBox1.Items.Add('title: ' + winTitle);
// ---------------------------------
// 3. cross check: try to get class:
// ---------------------------------
SetLength(s, 100);
GetClassName(winHandle, PChar(s), Length(s)+1);
if Length(Trim(s)) < 2 then begin
ListBox1.Items.Add('Error: 3.'); exit; end else
ListBox1.Items.Add('class: ' + s);
EnumChildWindows(winHandle, @EnumChildren, 0);
end;
(* here comes the form1.dfm file: *)
object Form1: TForm1
Left = 192
Top = 125
Width = 389
Height = 328
Caption = 'Form1'
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'MS Sans Serif'
Font.Style = []
OldCreateOrder = False
PixelsPerInch = 96
TextHeight = 13
object Button1: TButton
Left = 56
Top = 48
Width = 75
Height = 25
Caption = 'Button1'
TabOrder = 0
OnClick = Button1Click
end
object ListBox1: TListBox
Left = 24
Top = 112
Width = 305
Height = 145
ItemHeight = 13
TabOrder = 1
end
end
Hope this helps more than many others articles on SO. ciao, Jens
Upvotes: 1
Reputation: 596833
In order to use FindWindowEx()
effectively, you need to know the structure of the window's UI ahead of time, such as via Spy++, Winspector, or other similar tool. That way you know how many controls have the same class type, what their parent/child relationship is in regards to each other, etc so you can code FindWindowEx()
accordingly. Alternatively, if the target UI makes use of Dialog IDs (the VCL does not, but Microsoft usually does), then you can use GetDlgItem()
instead to get the handles of the desired controls directly without having to hunt for them in code (again, Spy++ and similar tools can show you what those IDs are so you can code them).
Upvotes: 3
Reputation: 54812
You can use EnumChildWindows
to enumerate all child windows of the third party application's window and test the class name of each enumerated window to see if it is the "Text Box" class. Example:
function EnumChildren(hwnd: HWND; lParam: LPARAM): BOOL; stdcall;
const
TextBoxClass = 'EDIT'; (?)
var
ClassName: array[0..259] of Char;
begin
Result := True;
GetClassName(hwnd, ClassName, Length(ClassName));
if ClassName = TextBoxClass then
TStrings(lParam).Add(IntToHex(hwnd, 8));
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
Memo1.Clear;
EnumChildWindows(OtherAppWnd, @EnumChildren, UINT_PTR(Memo1.Lines));
end;
Upvotes: 11