我正在尝试使用 delphi 编程访问第三方应用程序的“文本框”,因此我需要使用 FindWindowEx(...) 函数找到每个“文本框”的句柄。
问题是,由于所有文本框都具有相同的类名和“无窗口名称”,所以这个函数可以给我第一个 TextBOx 句柄!
如何在没有名称的情况下获取其余的文本框句柄?
提前致谢。
我正在尝试使用 delphi 编程访问第三方应用程序的“文本框”,因此我需要使用 FindWindowEx(...) 函数找到每个“文本框”的句柄。
问题是,由于所有文本框都具有相同的类名和“无窗口名称”,所以这个函数可以给我第一个 TextBOx 句柄!
如何在没有名称的情况下获取其余的文本框句柄?
提前致谢。
您可以使用EnumChildWindows
枚举第三方应用程序窗口的所有子窗口,并测试每个枚举窗口的类名,看它是否是“文本框”类。例子:
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;
为了FindWindowEx()
有效使用,您需要提前了解窗口 UI 的结构,例如通过 Spy++、Winspector 或其他类似工具。这样您就可以知道有多少控件具有相同的类类型、它们的父/子关系彼此之间的关系等,以便您可以进行FindWindowEx()
相应的编码。或者,如果目标 UI 使用 Dialog ID(VCL 不使用,但 Microsoft 通常使用),那么您可以直接使用GetDlgItem()
来获取所需控件的句柄,而无需在代码中寻找它们(同样,Spy++ 和类似的工具可以向您显示这些 ID 是什么,以便您对其进行编码)。
基于 @Sertac Akyus 我的 Delphi 7 (2002) 32 位代码,用于 Windows 10 64 位 Pro 远程(本地桌面)应用程序:(注意:我不知道为什么,但是这里所有带有 @s 的代码都不起作用!):
| Win32API | 描述 | |:-------- | ----- | | GetClassName(winHandle, @s, 长度(s)+1); | 这似乎行不通!| | GetClassName(winHandle, PChar(s), Length(s)+1); | 这行得通!|
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
希望这比其他许多关于 SO 的文章更有帮助。乔,延斯