Atenção: por essa edição ser muito antiga não há arquivo PDF para download. Os artigos dessa edição estão disponíveis somente através do formato HTML.
Um pequeno ladrão
Descobrindo informações secretas das janelas
Apresento-lhes um pequeno programa, muito útil para descobrir algumas informações sobre determinada janela (ou um controle dentro dela).
Alguns desenvolvedores necessitam descobrir informações "secretas" de programas, tais como: nome de janelas, objetos, classes, etc.
O ponto de partida concentra-se na função WindowFromPoint() da API do Windows. Esta função recebe como parâmetro as coordenadas do ponteiro do mouse, no formato da estrutura TPoint, cujos campos são x e y, do tipo inteiro.
Na unit Windows.pas, esta função está declarada da seguinte forma:
type
TPoint = record
x: Longint;
y: Longint;
end;
function WindowFromPoint(Point: TPoint): HWND; stdcall;
O valor de retorno é justamente o Handle da janela (ou do controle dentro da mesma) sobre a qual o mouse está passando. De posse desse Handle, podemos efetuar diversas operações, como por exemplo, obter o título, o nome da classe, a relação dos objetos filhos, seu menu principal, seu menu de controle (System Menu), entre outros. Só depende da sua criatividade (e necessidade).
Para acionar a captura da janela, foi utilizado um componente TTimer com seu intervalo configurado para 100 ms. No evento OnTimer, temos a rotina abaixo:
procedure TForm1.Timer1Timer(Sender: TObject);
begin
GetCursorPos(pt); //Obtém as coordenadas do mouse
h := WindowFromPoint(pt); //Obtém o handle da janela
{DETALHE: O handle retornado pode ser de um controle dentro da janela.}
GetWindowText(h, WndCaption, SizeOf(WndCaption)); //Pega o título
GetClassName(h, WndClass, SizeOf(WndClass)); //Pega o nome da classe.
Label3.Caption := IntToStr(h); //Mostra ...
Label4.Caption := '(' + IntToStr(pt.X) + ', ' + IntToStr(pt.Y) + ')';
Label6.SetTextBuf(WndCaption);
Label8.SetTextBuf(WndClass);
end;
Todas as variáveis utilizadas neste procedimento estão declaradas dentro da classe do form, na seção private:
TForm1 = class(TForm)
...
private
pt: TPoint;
h: THandle;
WndCaption: array[0..127] of char;
WndClass: array[0..127] of char;
end;
Logo na primeira linha do procedimento Timer1Timer(), obtemos as coordenadas do ponteiro do mouse, que é armazenada em pt. Em seguida, recuperamos o Handle do objeto que está naquela região, armazenado na variável h. De posse desse valor, podemos consultar outras informações sobre o objeto:
GetWindowText (h, WndCaption, SizeOf(WndCaption)), retorna o título da janela.
GetClassName (h, WndClass, SizeOf(WndClass)) , retorna nome da classe do objeto.
E, de quebra, uma rotina que envia um comando "clique de mouse" para a Window onde está o ponteiro do mouse (Obs: alguns controles aceitam o click e outros ignoram). Este procedimento está ligado ao evento OnKeyDown do form - e será acionado a cada pressionamento da tecla SHIFT:
procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
var
sc: TPoint;
begin
if Shift = [ssShift] then
begin
sc := pt;
Windows.ScreenToClient(h, sc);
SendMessage(h, WM_LBUTTONDOWN, 0, MakeLong(sc.X, sc.Y));
Sleep(200);
SendMessage(h, WM_LBUTTONUP, 0, MakeLong(sc.X, sc.Y));
end;
end;
Esta procedure envia duas mensagens para a janela cujo Handle está armazenado na variável h, utilizando a função SendMessage(). As mensagens são as seguintes:
WM_LBUTTONDOWN |
Pressionamento do botão primário do mouse. |
WM_LBUTTONDOWN |
Pressionamento do botão primário do mouse. |
Os outros parâmetros de SendMessage() são apenas informações extras, contendo valores úteis para o receptor da mensagem. No caso, o penúltimo parâmetro é o valor de WParam, o qual não será útil para o nosso objetivo. O último parâmetro (valor de LParam) é um valor inteiro, no formato binário, contendo as coordenadas do mouse.
Vamos ao código completo deste aplicativo:
unit uMain;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ExtCtrls;
type
TForm1 = class(TForm)
Label1: TLabel;
Label2: TLabel;
Button1: TButton;
Label3: TLabel;
Label4: TLabel;
Timer1: TTimer;
Label5: TLabel;
Label6: TLabel;
Label7: TLabel;
Label8: TLabel;
procedure Timer1Timer(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
private
pt: TPoint;
h: THandle;
WndCaption: array[0..127] of char;
WndClass: array[0..127] of char;
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.Timer1Timer(Sender: TObject);
begin
GetCursorPos(pt); //Obtém as coordenadas do mouse
h := WindowFromPoint(pt); //Obtém o handle da janela
{DETALHE: O handle retornado pode ser de um controle dentro da janela.}
GetWindowText(h, WndCaption, SizeOf(WndCaption)); //Pega o título
GetClassName(h, WndClass, SizeOf(WndClass)); //Pega o nome da classe.
Label3.Caption := IntToStr(h); //Mostra ...
Label4.Caption := '(' + IntToStr(pt.X) + ', ' + IntToStr(pt.Y) + ')';
Label6.SetTextBuf(WndCaption);
Label8.SetTextBuf(WndClass);
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
Close;
end;
procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
var
sc: TPoint;
begin
if Shift = [ssShift] then
begin
sc := pt;
Windows.ScreenToClient(h, sc);
SendMessage(h, WM_LBUTTONDOWN, 0, MakeLong(sc.X, sc.Y));
Sleep(200);
SendMessage(h, WM_LBUTTONUP, 0, MakeLong(sc.X, sc.Y));
end;
end;
end.