回 調函數寫出來不是本身的程序去調用的,反而是讓其餘的東西去調用,好比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;
===================================================================================================html
有了回調函數的概念及上面的例子,咱們能夠繼續了。其實想要找到一個標題已知的窗口句柄,用一個API函數就能夠了:FindWindow.windows
其函數原形是:函數
function FindWindow(lpClassName, lpWindowName: PChar): HWND; stdcall;工具
lpClassName:窗口類名.若是隻知道標題,能夠爲空.窗口類名能夠用不少工具得到.如winsignt32.
lpWindowName:窗口標題.spa
調用方式舉例:操作系統
var wndhwnd:HWND;
wndhwnd:=FindWindow(nil,'某窗口標題');
if wndhwnd<>0 then file://找到此窗口句柄.
begin
xxxxx
end
else begin
MessageBox(self.handle,'沒找到該窗口句柄','提示',0);
end;指針
有了這個窗口句柄,就離咱們的初始目的不遠了:控制其餘窗體上的窗口控件.orm
一樣,首先要獲得其餘窗體上窗口控件的句柄.咱們用這個API函數:EnumChildWindows.htm
其函數原形是:
function EnumChildWindows(hWndParent: HWND; lpEnumFunc: TFNWndEnumProc;
lParam: LPARAM): BOOL; stdcall;blog
這個函數和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')));就能夠給控件發送文本.其餘還能夠發送不一樣的消息能夠作不少事情.