【问题标题】:Listbox content in another application另一个应用程序中的列表框内容
【发布时间】:2012-08-22 10:30:23
【问题描述】:

如何在另一个应用程序的窗口中读取列表框项?我可以获得窗口的句柄,但我不知道访问其中组件的明确方法。

【问题讨论】:

  • 您将需要使用 VirtualAlloc 在目标进程中分配内存。然后发送 windows 消息以获取项目文本。使用 ReadProcessMemory 将其读入您的进程。
  • @David,我在我的 Windows 7 机器上使用已删除帖子中的代码没有问题(这两个应用程序都是 Delphi,当然以相同的高度运行)。
  • @TLama 嗯,我可能错了

标签: delphi winapi listbox delphi-7 listboxitems


【解决方案1】:

您可以尝试从以下项目中获取一些东西,其中显示了,如何枚举子窗口,为给定的类名过滤它们以及如何获取列表框的项目。我会评论它,但这将是一个漫长的故事,所以请把它当作一个临时帖子...

Unit1.pas

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TEnumData = class
    ClassName: string;
    HandleItems: TStrings;
  end;

type
  TForm1 = class(TForm)
    CloneListBox: TListBox;
    HandleEdit: TEdit;
    HandleListBox: TListBox;
    HandleEnumButton: TButton;
    procedure HandleEnumButtonClick(Sender: TObject);
    procedure HandleListBoxClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

function EnumCallback(Handle: HWND; EnumData: TEnumData): BOOL; stdcall;
var
  Buffer: array[0..255] of Char;
begin
  Result := True;
  if GetClassName(Handle, Buffer, 256) <> 0 then
    if Buffer = EnumData.ClassName then
      EnumData.HandleItems.Add(IntToStr(Handle));
end;

procedure GetListBoxItems(Handle: HWND; Target: TListBox);
var
  I: Integer;
  ItemCount: Integer;
  TextBuffer: string;
  TextLength: Integer;
begin
  ItemCount := SendMessage(Handle, LB_GETCOUNT, 0, 0);
  if ItemCount <> LB_ERR then
  begin
    Target.Items.BeginUpdate;
    try
      Target.Clear;
      for I := 0 to ItemCount - 1 do
      begin
        TextLength := SendMessage(Handle, LB_GETTEXTLEN, I, 0);
        SetLength(TextBuffer, TextLength);
        SendMessage(Handle, LB_GETTEXT, I, LPARAM(PChar(TextBuffer)));
        Target.Items.Add(TextBuffer);
      end;
    finally
      Target.Items.EndUpdate;
    end;
  end;
end;

procedure TForm1.HandleEnumButtonClick(Sender: TObject);
var
  EnumData: TEnumData;
begin
  EnumData := TEnumData.Create;
  try
    EnumData.ClassName := 'TListBox';
    EnumData.HandleItems := HandleListBox.Items;
    EnumChildWindows(StrToInt(HandleEdit.Text), @EnumCallback, LPARAM(EnumData));
  finally
    EnumData.Free;
  end;
end;

procedure TForm1.HandleListBoxClick(Sender: TObject);
var
  SourceHandle: Integer;
begin
  if TryStrToInt(HandleListBox.Items[HandleListBox.ItemIndex], SourceHandle) then
    GetListBoxItems(SourceHandle, CloneListBox);
end;

end.

Unit1.dfm

object Form1: TForm1
  Left = 0
  Top = 0
  Caption = 'Form1'
  ClientHeight = 259
  ClientWidth = 460
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'Tahoma'
  Font.Style = []
  OldCreateOrder = False
  PixelsPerInch = 96
  TextHeight = 13
  object CloneListBox: TListBox
    Left = 224
    Top = 8
    Width = 228
    Height = 243
    ItemHeight = 13
    TabOrder = 0
  end
  object HandleEnumButton: TButton
    Left = 127
    Top = 8
    Width = 88
    Height = 25
    Caption = 'Enumerate'
    TabOrder = 1
    OnClick = HandleEnumButtonClick
  end
  object HandleListBox: TListBox
    Left = 8
    Top = 40
    Width = 207
    Height = 211
    ItemHeight = 13
    TabOrder = 2
    OnClick = HandleListBoxClick
  end
  object HandleEdit: TEdit
    Left = 8
    Top = 8
    Width = 113
    Height = 21
    TabOrder = 3
    Text = '0'
  end
end

Project1.dpr

program Project1;

uses
  Forms,
  Unit1 in 'Unit1.pas' {Form1};

{$R *.res}

begin
  Application.Initialize;
  Application.MainFormOnTaskbar := True;
  Application.CreateForm(TForm1, Form1);
  Application.Run;
end.

【讨论】:

    【解决方案2】:

    使用 EnumChildWindows 获取子控件列表(当主窗口句柄已知时)。

    然后查看MSDN 上的 LB_GETTEXT 消息(或 Delphi WinSDK 帮助)。不要忘记检查字符串长度(LB_GETTEXTLEN)并分配内存缓冲区

    【讨论】:

    • 如何获取组件(例如那个 Listbox)句柄?
    • 为什么会有组件?那可能根本不是德尔福。或者 Delphi 用不同的编译选项编译。或不同的 Delphi/VCL 版本。在所有这些情况下,您可能认为这些根本不是组件。唯一可以确定的就是 Windows。所以 - Windows 方法肯定会起作用(除非有错误)。其余的都是一厢情愿。您认为“我使用 TListBox 组件创建 Windows 列表框,因此每个创建的列表框都是使用我的 TListBox 组件版本完成的”。根本不是这样。
    • 我使用 EnumChildWindows 得到的唯一东西是一个名为“TspSkinAnimateGauge”的组件,我在自己的程序上测试了 EnumChildWindows,它运行良好,但在目标程序上没有我想要的。问题出在哪里?
    • 也许根本没有列表框,所以你可以随心所欲地尖叫LB_消息,但它不会响应.... :) 尝试 spy++ 来确认这是一个列表框,然后不是其他动物。
    • 就像科比克说的。要么你有一个控件来响应 Windows 规则的消息,要么没有。你可以写一个组合框,我不知道,它会以完全不同的方式响应编辑消息并作为奖励。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多