如何控制其他程序窗體上的窗口控件:上
首先申明:我是菜鳥,我只不過想把困繞了我很長時間的問題的解決方案發表出來,免得以後我又忘記,同時給還不知道這些小知識的同僚一些幫助。各位不要笑我的淺薄。同時為了表示我的低級,我會很羅嗦的講一些基本的東西,這些都是我的理解,很不准確。
用我的方法來控制其他程序窗體上的窗口控件,必須先了解什麼是回調函數。我的理解是這樣的:
回調函數寫出來不是自己的程序去調用的,反而是讓其他的東西去調用,比如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;
程序清單如下:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Memo1: TMemo;
btn_listwindow: TButton;
procedure btn_listwindowClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
function EnumWindowsProc(AhWnd:LongInt;AForm:TForm1):boolean;stdcall;
implementation
{$R *.dfm}
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;
procedure TForm1.btn_listwindowClick(Sender: TObject);
begin
EnumWindows(@EnumWindowsProc,LongInt(self));
end;
end.
F9,運行,看看結果。最好是F7單步跟蹤調試一下,看看回調函數是怎麼被調用的。