Delphi 查找標題已知的窗口句柄,遍歷窗口控件句柄(轉)


 

 

                   

用我的方法來控制其他程序窗體上的窗口控件,必須先了解什么是 回調函數。我的理解是這樣的: 


回 調函數寫出來不是自己的程序去調用的,反而是讓其他的東西去調用,比如windows操作系統,比如其他的程序等等之類的。但是什么時候被調用卻不知道 了。回調函數一般是按照調用者的要求定義好參數和返回值的類型,你向調用者提供你的回調函數的入口地址,然后調用者有什么事件發生的時候就可以隨時按照你 提供的地址調用這個函數通知你,並按照預先規定好的形式傳遞參數。所以很多人打比方,說回調函數還真有點像您隨身帶的BP機:告訴別人號碼,在它有事情時 Call您!

所以一個回調函數寫出來之后,一定有個注冊的動作,就是告訴調用者,你怎么樣找到我寫的函數。某些Windows API 函數會要求以回調函數地址作為其參數之一,例如SetTimer 、LineDDA 、EnumObjects,以及我們下面要用到的EnumWindows。

在Delphi里聲明一個回調函數的格式很簡單,例如:

function EnumWindowsProc(AhWnd:LongInt;lParam:LongInt):boolean;stdcall;

首先是函數名稱可以隨便亂取,但函數參數的類型一般不得亂來,其順序,數據類型等都有規定的,因為這些都是讓其他程序調用的,他們已經規定好了的,但參數名稱可以隨便亂叫。注意后面一定要帶上“stdcall”,

stdcall是標准調用,也就是說采用標准windows參數傳遞方式來調用函數。

編寫函數體就很簡單了,利用傳遞過來的參數就可以了,只要記住,這些參數是別人送給你的,你只要知道這些參數代表了什么意思。

再看個向調用者注冊回調函數入口地址的函數。
function EnumWindows(lpEnumFunc: TFNWndEnumProc; lParam: LPARAM): BOOL; stdcall;

TFNWndEnumProc其實就是指針類型。其中的lpEnumFunc就是回調函數的入口地址了。

下面是調用EnumWindows的格式:
EnumWindows(@EnumWindowsProc,0);

通過向系統注冊回調函數的入口地址,系統就能在需要的時候,調用回調函數,傳遞參數給它,也許這些參數就是我們想要的。

EnumWindows函數的功能是:枚舉屏幕上所有程序中的頂層窗口,將窗口句柄以參數的形式傳遞給回調函數。找到一個窗口,就調用一次回調函數。枚舉結束的條件是:要么枚舉完所有的窗口,要么回調函數返回False。

lParam: LPARAM參數是程序定義的值,這個值被傳遞到回調函數。

回過頭來再看一下EnumWindowsProc:

function EnumWindowsProc(AhWnd:LongInt;lParam:LongInt):boolean;stdcall;

當系統找到了一個窗口后,就開始調用這個回調函數,將窗口的句柄作為第一個參數傳遞過來,將在EnumWindows中lParam: LPARAM這個程序定義的值作為第二個參數傳遞過來。

所以我們可以在EnumWindowsProc函數中利用傳遞過來的兩個參數來做某些處理了。

下面我們新建一個程序列舉系統中所有程序的頂層窗口,我們要得到窗口的標題,要得到窗口類名稱。

得到窗口標題用:

function GetWindowText(hWnd: HWND; lpString: PChar; nMaxCount: Integer): Integer; stdcall;

該函數功能是將窗口句柄為hWnd的窗口的標題拷入到一個緩沖區lpString。nMaxCount是拷入緩沖區內的最大的字符數。

要得到窗口標題還可以發送消息:WM_GETTEXT,其實GetWindowText就是發送WM_GETTEXT消息的。

要得到窗口類名稱用:

function GetClassName(hWnd: HWND; lpClassName: PChar; nMaxCount: Integer): Integer; stdcall;

其參數意義和上面的函數差不多。不詳細解釋了。

我們先編寫回調函數:EnumWindowsProc。現在告訴自己,我們已經有了兩個參數的值了。這兩個參數是系統給我們的.

為了顯示窗口標題和類名,我們用一個TMemo控件。

先在interface部分聲明函數。

function EnumWindowsProc(AhWnd:LongInt;AForm:TForm1):boolean;stdcall;

注意我將第二個參數改了,不要緊,到時候調用的時候注意看。

然后在implementation部分定義函數:
function EnumWindowsProc(AhWnd:LongInt;AForm:TForm1):boolean;
var
lpszClassName,lpszWindowText:array[0..254] of char; //定義兩個緩沖區。
begin
GetWindowText(AhWnd,lpszWindowText,254);//得到窗口標題
GetClassName(AhWnd,lpszClassName,254);//得到窗口類名。
Aform.memo1.lines.add(StrPas(lpszWindowText));
Aform.memo1.lines.add(StrPas(lpszClassName));
Aform.memo1.lines.add('--------------------');
Result:=True;
end;

接着需要做的就是調用EnumWindows函數,注冊回調函數入口地址,讓系統調用回調函數,列舉窗口了。所以再添加一個TButton: btn_listwindow
procedure TForm1.btn_listwindowClick(Sender: TObject);
begin
EnumWindows(@EnumWindowsProc,LongInt(self));
end;

===================================================================================================

 

有了回調函數的概念及上面的例子,我們可以繼續了。其實想要找到一個標題已知的窗口句柄,用一個API函數就可以了:FindWindow.

其函數原形是:

function FindWindow(lpClassName, lpWindowName: PChar): HWND; stdcall;

lpClassName:窗口類名.如果只知道標題,可以為空.窗口類名可以用很多工具獲得.如winsignt32.
lpWindowName:窗口標題.

調用方式舉例:

var wndhwnd:HWND;
wndhwnd:=FindWindow(nil,'某窗口標題');
if wndhwnd<>0 then file://找到此窗口句柄.
begin
xxxxx
end
else begin
MessageBox(self.handle,'沒找到該窗口句柄','提示',0);
end;

有了這個窗口句柄,就離我們的初始目的不遠了:控制其他窗體上的窗口控件.

同樣,首先要得到其他窗體上窗口控件的句柄.我們用這個API函數:EnumChildWindows.

其函數原形是:
function EnumChildWindows(hWndParent: HWND; lpEnumFunc: TFNWndEnumProc;
lParam: LPARAM): BOOL; stdcall;

這個函數和EnumWindow函數很有些想象.其作用也很相似.它的功能就是列舉窗口句柄為hWndParent的窗體上所有的窗口控件的句柄.同樣也是以回調函數參數的形式給出的.

我們再舉一個實際的例子,來說明這個函數的用法.程序的功能是讓用戶輸入一個窗口標題,然后調用FindWindow函數找到此窗口句柄.通過這個句柄,我們在一個Memo里顯示該窗口上所有的窗口控件.

同樣先編寫回調函數.
function EnumChildWndProc(AhWnd:LongInt;
AlParam:lParam):boolean;stdcall;
var
WndClassName: array[0..254] of Char;
WndCaption: array[0..254] of Char;
begin
GetClassName(AhWnd,wndClassName,254);
GetWindowText(aHwnd,WndCaption,254);
with form1.memo1 do
begin
    lines.add( string(wndClassName));
    lines.add( string(wndCaption));
    lines.add('-------');
end;
result:=true;
end;


然后在一事件里調用EnumChildWindows函數.
procedure TForm1.Button1Click(Sender: TObject);
var
hWnd:LongInt;
begin
memo1.Lines.Clear;
Memo1.Lines.Add(Edit1.Text+' 有如下控件類名稱');
hWnd:=FindWindow(nil,pchar(Edit1.Text));
if hWnd<>0 then
begin
    EnumChildWindows(hWnd,@EnumChildWndProc,0);
end
else MessageBox(self.handle,'沒找到該窗口句柄','提示',0);
end;

程序清單如下:
unit Unit1;

interface

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

type
TForm1 = class(TForm)
    Memo1: TMemo; file://用來顯示找到的控件
    Label1: TLabel; 
    Edit1: TEdit;  file://輸入標題.
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
private
    { Private declarations }
public
    { Public declarations }
end;

var
Form1: TForm1;

function EnumChildWndProc(AhWnd:LongInt;
    AlParam:lParam):boolean;stdcall;

implementation


{$R *.dfm}
function EnumChildWndProc(AhWnd:LongInt;
AlParam:lParam):boolean;stdcall;
var
WndClassName: array[0..254] of Char;
WndCaption: array[0..254] of Char;
begin
GetClassName(AhWnd,wndClassName,254);
GetWindowText(aHwnd,WndCaption,254);
with form1.memo1 do
begin
    lines.add( string(wndClassName));
    lines.add( string(wndCaption));
    lines.add('-------');
end;
result:=true;
end;


procedure TForm1.Button1Click(Sender: TObject);
var
hWnd:LongInt;
begin
memo1.Lines.Clear;
Memo1.Lines.Add(Edit1.Text+' 有如下控件類名稱');
hWnd:=FindWindow(nil,pchar(Edit1.Text));
if hWnd<>0 then
begin
    EnumChildWindows(hWnd,@EnumChildWndProc,0);
end
else MessageBox(self.handle,'沒找到該窗口句柄','提示',0);
end;

end.

 

有了控件句柄,我們當然就可以隨心所欲了.比如:

SendMessage(hWnd,WM_SETTEXT,0,LongInt(Pchar('sdafdsf')));就可以給控件發送文本.其他還可以發送不同的消息可以做很多事情.

 

原文URL:http://blog.sina.com.cn/s/blog_4ad042e50102dxdu.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM