3

我正在尝试使用 delphi 编程访问第三方应用程序的“文本框”,因此我需要使用 FindWindowEx(...) 函数找到每个“文本框”的句柄。

问题是,由于所有文本框都具有相同的类名和“无窗口名称”,所以这个函数可以给我第一个 TextBOx 句柄!

如何在没有名称的情况下获取其余的文本框句柄?

提前致谢。

4

3 回答 3

10

您可以使用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;
于 2012-05-18T15:31:12.670 回答
1

为了FindWindowEx()有效使用,您需要提前了解窗口 UI 的结构,例如通过 Spy++、Winspector 或其他类似工具。这样您就可以知道有多少控件具有相同的类类型、它们的父/子关系彼此之间的关系等,以便您可以进行FindWindowEx()相应的编码。或者,如果目标 UI 使用 Dialog ID(VCL 不使用,但 Microsoft 通常使用),那么您可以直接使用GetDlgItem()来获取所需控件的句柄,而无需在代码中寻找它们(同样,Spy++ 和类似的工具可以向您显示这些 ID 是什么,以便您对其进行编码)。

于 2012-05-18T19:16:04.427 回答
0

基于 @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 的文章更有帮助。乔,延斯

于 2021-12-14T19:40:45.440 回答