读取外部程序的标题和内容

Delphi 为我们提供了三个方便的函数:
GlobalAllocPtr   {简化自 API 的 GlobalAlloc}
GlobalReAllocPtr {简化自 API 的 GlobalReAlloc}
GlobalFreePtr    {简化自 API 的 GlobalFree}
读写本程序以外的数据时可以使用它们, 很方便, 譬如:
p := GlobalAllocPtr(0, Len);      {分配}
p := GlobalReAllocPtr(p, Len, 0); {重分配}
GlobalFreePtr(p);                 {释放}
注意 GlobalAllocPtr 的第一个参数和 GlobalReAllocPtr 的最后一个参数, 上面给的都是 0;
这两个参数的意义是一样的, 规范一点应该写成 GMEM_FIXED (表示分配固定内存), 常用的参数还有:
GMEM_MOVEABLE {分配可移动内存}
GMEM_ZEROINIT {同时清空内存}
GHND          {分配可移动内存同时清空}
GPTR          {分配固定内存同时清空}
procedure TForm1.Button2Click(Sender: TObject);
var
  p: Pointer;
  Len: Integer;
begin
  Len := 6+1;                    {假如想要读出 6 个字符, 要流出结束的空字符}
  p := GlobalAllocPtr(0, Len*2); {分配内存 Len*2 是针对双字节字符}
  SendMessage(Memo1.Handle, WM_GETTEXT, Len, Cardinal(p));
  ShowMessage(PChar(p)); {CodeGe}

  {在上一例的基础上继续, 先获取实际长度}
  Len := SendMessage(Memo1.Handle, WM_GETTEXTLENGTH, 0, 0);
  Len := (Len + 1) * 2;
  p := GlobalReAllocPtr(p, Len, GHND); {重新分配内存}
  SendMessage(Memo1.Handle, WM_GETTEXT, Len, Cardinal(p));
  ShowMessage(PChar(p)); {CodeGear Delphi 2009}
  GlobalFreePtr(p);
end;

{获取已打开的所有记事本的标题}
procedure TForm1.Button1Click(Sender: TObject);
var
  h: HWnd;
  p: array[0..254] of char;
begin
  Memo1.Clear;
  h := GetWindow(Handle, GW_HWNDFIRST);
  while h <> 0 do
  begin
    GetClassName(h, p, Length(p));
    if p = 'Notepad' then
    begin
      GetWindowText(h, p, Length(p));
      Memo1.Lines.Add(p);
    end;
    h := GetWindow(h, GW_HWNDNEXT);
  end;
end;
--------------- 读取记事本的标题 ----------------------------------
procedure TForm1.Button1Click(Sender: TObject);
var
p: Pointer;
Len: Integer;
h:hwnd;
begin
h:=findwindow('notepad',nil);
Len := 6+1; {假如想要读出 6 个字符, 要留出结束的空字符}
p := GlobalAllocPtr(0, Len*2); {分配内存 Len*2 是针对双字节字符}
SendMessage(h, WM_GETTEXT, Len, Cardinal(p));
ShowMessage(PChar(p)); {CodeGe}
GlobalFreePtr(p);
end;

 

--------------- 读取记事本的内容 ----------------------------------

procedure TForm1.Button1Click(Sender: TObject);

var
  h: HWND;
  p: Pointer;
  Len: Integer;
begin
  h := FindWindow('Notepad', nil);
  if h = 0 then Exit;
  h := GetWindow(h, GW_CHILD);
  if h = 0 then Exit;
  Len := SendMessage(h, WM_GETTEXTLENGTH, 0, 0) + 1;
  p := GlobalAllocPtr(0, Len * SizeOf(Char));
  SendMessage(h, WM_GETTEXT, Len, Cardinal(p));
  ShowMessage(PChar(p));
  GlobalFreePtr(p);
end;


//声明:
GetWindow(
  hWnd: HWND; {指定的窗口句柄}
  uCmd: UINT  {指定的关系选项}
): HWND;      {失败返回0; 成功返回符合的窗口句柄}

//uCmd 可选值:
GW_HWNDFIRST = 0; {同级别第一个}
GW_HWNDLAST  = 1; {同级别最后一个}
GW_HWNDNEXT  = 2; {同级别下一个}
GW_HWNDPREV  = 3; {同级别上一个}
GW_OWNER     = 4; {属主窗口}
GW_CHILD     = 5; {子窗口}



{要有个 Memo 接受数据}
procedure TForm1.Button1Click(Sender: TObject);
var
  h: HWnd;
  p: array[0..254] of char;
begin
  h := GetWindow(Handle, GW_HWNDFIRST);
  while h <> 0 do
  begin
    if GetWindowText(h, p, 255) > 0 then Memo1.Lines.Add(p);
    h := GetWindow(h, GW_HWNDNEXT);
  end;
end;


{用 API 实现的获取文本容器中选择的文本的函数}
function GetEditSeleteText(h: HWND): string;
var
  len,sx,ex: Integer; {文本总长度, 选择的开始位置, 选择的结束位置}
  buf: PChar;         {所有文本}
begin
  {获取文本总长度}
  len := SendMessage(h, WM_GETTEXTLENGTH, 0, 0) + 1;
  {为接受所有文本的缓冲区分配内存}
  buf := GlobalAllocPtr(0, len); {这里没有使用 GetMem, 因为需要全局的, 不然无法面对其他程序}
  {获取所有文本}
  SendMessage(h, WM_GETTEXT, len, Longint(buf));
  {获取选择的开始位置和结束位置}
  SendMessage(h, EM_GETSEL, Longint(@sx), Longint(@ex));
  {截取选择的文本}
  Result := Copy(buf, sx+1, ex-sx);
  {释放内存}
  GlobalFreePtr(buf);
end;

{测试 TEdit, 同时与 VCL 的获取方法对比}
procedure TForm1.Button1Click(Sender: TObject);
begin
  ShowMessage(GetEditSeleteText(Edit1.Handle) + ' - ' + Edit1.SelText);
end;



var
  h: HWND;

procedure TForm1.Timer1Timer(Sender: TObject);
var
  pt: TPoint;
  arr: array[0..254] of Char;
begin
  if GetCursorPos(pt) then             {如果能获取点}
  begin
    h := WindowFromPoint(pt);          {返回句柄}
    GetClassName(h, arr, Length(arr)); {获取该句柄窗口的类名}
    Text := arr;                       {显示在标题}
  end;
end;

end.




//声明:
GetClassName(
  hWnd: HWND;         {指定窗口句柄}
  lpClassName: PChar; {缓冲区}
  nMaxCount: Integer  {缓冲区大小}
): Integer;           {返回类名大小; 失败返回 0}

//测试1: 新建一个工程, 主窗口的类名默认是 TForm1, 用程序获取一下看看
var
  ps: array[0..254] of Char;
begin
  GetClassName(Handle, ps, 255);
  ShowMessage(ps); {TForm1}
end;

//测试2: 看看 "计算器" 窗口的类名(先启动计算器)
var
  h: HWND;
  ps: array[0..254] of Char;
begin
  h := FindWindow(nil, '计算器'); {这句是获取计算器窗口的句柄}
  GetClassName(h, ps, 255);
  ShowMessage(ps); {SciCalc}
end;

//测试3: 看看记事本窗口的类名(先重新启动记事本):
var
  h: HWND;
  ps: array[0..254] of Char;
begin
  h := FindWindow(nil, '无标题 - 记事本'); {这句是获取记事本窗口的句柄}
  GetClassName(h, ps, 255);
  ShowMessage(ps); {Notepad}
end;
 
FindWindow(
  lpClassName,        {窗口的类名}
  lpWindowName: PChar {窗口的标题}
): HWND;              {返回窗口的句柄; 失败返回 0}

//FindWindowEx 比 FindWindow 多出两个句柄参数:
FindWindowEx(
  Parent: HWND;     {要查找子窗口的父窗口句柄}
  Child: HWND;      {子窗口句柄}
  ClassName: PChar; {}
  WindowName: PChar {}
): HWND;
{
如果 Parent 是 0, 则函数以桌面窗口为父窗口, 查找桌面窗口的所有子窗口;
如果  是 HWND_MESSAGE, 函数仅查找所有消息窗口;
子窗口必须是 Parent 窗口的直接子窗口;
如果 Child 是 0, 查找从 Parent 的第一个子窗口开始;
如果 Parent 和 Child 同时是 0, 则函数查找所有的顶层窗口及消息窗口.
}

//测试1: 试着找找新建程序主窗口的句柄
var
  h: HWND;
begin
  {现在我们知道窗口的标题是: Form1、窗口的类名是: TForm1}
  h := FindWindow('TForm1', 'Form1');
  ShowMessage(IntToStr(h));      {656180; 这是随机, 每次启动窗口肯定不一样}

  {假如不知道类名}
  h := FindWindow(nil, 'Form1');
  ShowMessage(IntToStr(h));      {656180}

  {假如不知道标题名}
  h := FindWindow('TForm1', nil);
  ShowMessage(IntToStr(h));      {656180}

  {其实这个窗口的句柄不就是 Self.Handle 吗}
  ShowMessage(IntToStr(Handle)); {656180}
end;

//测试2: 找计算器窗口的句柄(先打开计算器)
var
  h: HWND;
begin
  {如果不是简体中文系统, 这样可能不灵}
  h := FindWindow(nil, '计算器');
  ShowMessage(IntToStr(h)); {1508334}

  {最好这样, 但你得提前知道计算器窗口的类名是: SciCalc}
  h := FindWindow('SciCalc', nil);
  ShowMessage(IntToStr(h)); {1508334}
end;


procedure TForm1.Button1Click(Sender: TObject);
const
  className = 'IEFrame'; {这是 IE 浏览器的类名}
var
  h: HWnd;
  buf: array[Byte] of Char;
begin
  h := GetWindow(Handle, GW_HWNDFIRST);
  while h <> 0 do
  begin
    GetClassName(h, buf, Length(buf));
    if buf = className then {找到咋处理? 显示它的标题吧}
    begin
      GetWindowText(h, buf, Length(buf));
      Memo1.Lines.Add(buf)
    end;
    h := GetWindow(h, GW_HWNDNEXT);
  end;
end;


枚举当前所有的 IE 窗口 


procedure TForm1.Button1Click(Sender: TObject);
const
  className = 'IEFrame'; {这是 IE 浏览器的类名}
var
  h: HWnd;
  buf: array[Byte] of Char;
begin
  h := GetWindow(Handle, GW_HWNDFIRST);
  while h <> 0 do
  begin
    GetClassName(h, buf, Length(buf));
    if buf = className then {找到咋处理? 显示它的标题吧}
    begin
      GetWindowText(h, buf, Length(buf));
      Memo1.Lines.Add(buf)
    end;
    h := GetWindow(h, GW_HWNDNEXT);
  end;
end;

如果有个按钮,是disabled那种效果,就是灰掉,不能点的那种,怎么获取这样按钮句柄呢?
可以从母体中遍历控件找到它.
如果是使用鼠标探测的话, 可以通过判断鼠标指针是否在控件范围内来确认.

怎么判断鼠标指针是否在控件范围内?
可以通过控件的事件:
OnMouseEnter (进入控件范围)
OnMouseLeave (离开控件范围)
也可以用函数: PtInRect


posted @ 2011-11-05 11:56  findumars  Views(1549)  Comments(0Edit  收藏  举报