Hesi
Hesi

Reputation: 113

How to get handles of different controls with the same class name ?

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

Answers (3)

Jens
Jens

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

Remy Lebeau
Remy Lebeau

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

Sertac Akyuz
Sertac Akyuz

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

Related Questions