我在網上找到一段代碼,可以實現全局的hooking。它分兩個部分: DLL 和 主程序 hook.exe 原來的代碼是用於keyboard hooking的,但我修改了它,使得可以接收其它message。下面是代碼// DLL 部分
library HookDll;
uses
SysUtils,
Classes,windows, messages;var CurrentHook: HHook;function GlobalKeyBoardHook(code: integer; wParam: word; lParam: longword): longword; stdcall;
begin
if code<0 then
begin
GlobalKeyBoardHook:=CallNextHookEx(CurrentHook,code,wParam,lparam); //then return the value from it.
Exit;
end; // 這裡我們判斷message是否WM_INPUTLANGCHANGE,若是則代表輸入法已改變
if (PMSG(wParam).message = WM_INPUTLANGCHANGE) then
begin
MessageBox(0, 'global input changed', '', 0)
end;
CallNextHookEx(CurrentHook,code,wParam,lparam);
GlobalKeyBoardHook:=0;
Exit;
end;procedure SetHookHandle(HookHandle: HHook); stdcall;
begin
CurrentHook:=HookHandle;
KeyArrayPtr:=0;
end;exports GlobalKeyBoardHook index 1,
SetHookHandle index 2;
beginend.然後是主程序,包含 local.pas 及 global.pas// local.pasunit Local;interfaceuses windows,sysutils, messages;function SetupLocalHook: boolean;
function RemoveLocalHook: boolean;
function KeyBoardHook(code: integer; wParam: word; lParam: longword): longword; stdcall;var CurrentHook: HHook;
HookInstalled: boolean;
implementationfunction SetupLocalHook: boolean;
begin
CurrentHook:=setwindowshookex(WH_GETMESSAGE,@KeyBoardHook,0,GetCurrentThreadID());
if CurrentHook<>0 then SetupLocalHook:=true else SetupLocalHook:=false;
end;function RemoveLocalHook: boolean;
begin
RemoveLocalHook:=UnhookWindowsHookEx(CurrentHook);
end;function KeyBoardHook(code: integer; wParam: word; lParam: longword): longword; stdcall;
begin
if code<0 then
begin
KeyBoardHook := CallNextHookEx(CurrentHook,code,wParam,lparam);
Exit;
end;
// 對於 local hooking (就是衹hook 在本application上),也是檢測是否收到WM_INPUTLANGCHANGE
if (PMSG(lParam).message=WM_INPUTLANGCHANGE) then
MessageBox(0, 'LANG CHANGED', '', 0);
CallNextHookEx(CurrentHook,code,wParam,lparam);
KeyBoardHook:=0;
Exit;
end;end.
// global.pasunit Global;interfaceuses windows,Local;type TSetHookHandle = procedure(HookHandle: HHook); stdcall;var LibLoaded: boolean;
LibHandle: HInst;
HookProcAdd: pointer;
GHookInstalled: boolean;
SetHookHandle: TSetHookHandle;function LoadHookProc: boolean;
function SetupGlobalHook: boolean;implementationfunction LoadHookProc: boolean;
begin
LibHandle:=LoadLibrary('hookdll.dll');
if LibHandle=0 then begin
LoadHookProc:=false;
exit;
end;
HookProcAdd:=GetProcAddress(LibHandle,'GlobalKeyBoardHook');
@SetHookHandle:=GetProcAddress(LibHandle,'SetHookHandle');
if (HookProcAdd=nil)or(@SetHookHandle=nil) then begin //if loading fails, unload library, exit and return false
FreeLibrary(LibHandle);
LoadHookProc:=false;
exit;
end;
LoadHookProc:=true;
end;
function SetupGlobalHook: boolean;
begin
SetupGlobalHook:=false;
if LibLoaded=false then LibLoaded:=LoadHookProc;
if LibLoaded=false then exit;
// 這裡,我們將hook設成可以接收MESSAGE的類型
CurrentHook:=setwindowshookex(WH_GETMESSAGE,HookProcAdd,LibHandle,0);
SetHookHandle(CurrentHook);
if CurrentHook<>0 then SetupGlobalHook:=true;
end;end.
// 主程序unit MainFormUnit;interfaceuses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, Local, global,
StdCtrls;type
TMainForm = class(TForm)
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;var
MainForm: TMainForm;implementation{$R *.DFM}procedure TMainForm.FormCreate(Sender: TObject);
begin
// 建立全局hook
GHookInstalled:=SetupGlobalHook;
end;procedure TMainForm.FormDestroy(Sender: TObject);
begin
RemoveLocalHook;
end;end.
實驗結果表明,如果截取 WM_INPUTLANGCHANGE 是不成功的,但如果換成 WM_INPUTLANGCHANGEREQUEST 則可以,但是 WM_INPUTLANGCHANGEREQUEST 是在輸入法轉換前發出的,我要的是輸入法成功轉換後的消息,請問怎樣做才可以?thanks
library HookDll;
uses
SysUtils,
Classes,windows, messages;var CurrentHook: HHook;function GlobalKeyBoardHook(code: integer; wParam: word; lParam: longword): longword; stdcall;
begin
if code<0 then
begin
GlobalKeyBoardHook:=CallNextHookEx(CurrentHook,code,wParam,lparam); //then return the value from it.
Exit;
end; // 這裡我們判斷message是否WM_INPUTLANGCHANGE,若是則代表輸入法已改變
if (PMSG(wParam).message = WM_INPUTLANGCHANGE) then
begin
MessageBox(0, 'global input changed', '', 0)
end;
CallNextHookEx(CurrentHook,code,wParam,lparam);
GlobalKeyBoardHook:=0;
Exit;
end;procedure SetHookHandle(HookHandle: HHook); stdcall;
begin
CurrentHook:=HookHandle;
KeyArrayPtr:=0;
end;exports GlobalKeyBoardHook index 1,
SetHookHandle index 2;
beginend.然後是主程序,包含 local.pas 及 global.pas// local.pasunit Local;interfaceuses windows,sysutils, messages;function SetupLocalHook: boolean;
function RemoveLocalHook: boolean;
function KeyBoardHook(code: integer; wParam: word; lParam: longword): longword; stdcall;var CurrentHook: HHook;
HookInstalled: boolean;
implementationfunction SetupLocalHook: boolean;
begin
CurrentHook:=setwindowshookex(WH_GETMESSAGE,@KeyBoardHook,0,GetCurrentThreadID());
if CurrentHook<>0 then SetupLocalHook:=true else SetupLocalHook:=false;
end;function RemoveLocalHook: boolean;
begin
RemoveLocalHook:=UnhookWindowsHookEx(CurrentHook);
end;function KeyBoardHook(code: integer; wParam: word; lParam: longword): longword; stdcall;
begin
if code<0 then
begin
KeyBoardHook := CallNextHookEx(CurrentHook,code,wParam,lparam);
Exit;
end;
// 對於 local hooking (就是衹hook 在本application上),也是檢測是否收到WM_INPUTLANGCHANGE
if (PMSG(lParam).message=WM_INPUTLANGCHANGE) then
MessageBox(0, 'LANG CHANGED', '', 0);
CallNextHookEx(CurrentHook,code,wParam,lparam);
KeyBoardHook:=0;
Exit;
end;end.
// global.pasunit Global;interfaceuses windows,Local;type TSetHookHandle = procedure(HookHandle: HHook); stdcall;var LibLoaded: boolean;
LibHandle: HInst;
HookProcAdd: pointer;
GHookInstalled: boolean;
SetHookHandle: TSetHookHandle;function LoadHookProc: boolean;
function SetupGlobalHook: boolean;implementationfunction LoadHookProc: boolean;
begin
LibHandle:=LoadLibrary('hookdll.dll');
if LibHandle=0 then begin
LoadHookProc:=false;
exit;
end;
HookProcAdd:=GetProcAddress(LibHandle,'GlobalKeyBoardHook');
@SetHookHandle:=GetProcAddress(LibHandle,'SetHookHandle');
if (HookProcAdd=nil)or(@SetHookHandle=nil) then begin //if loading fails, unload library, exit and return false
FreeLibrary(LibHandle);
LoadHookProc:=false;
exit;
end;
LoadHookProc:=true;
end;
function SetupGlobalHook: boolean;
begin
SetupGlobalHook:=false;
if LibLoaded=false then LibLoaded:=LoadHookProc;
if LibLoaded=false then exit;
// 這裡,我們將hook設成可以接收MESSAGE的類型
CurrentHook:=setwindowshookex(WH_GETMESSAGE,HookProcAdd,LibHandle,0);
SetHookHandle(CurrentHook);
if CurrentHook<>0 then SetupGlobalHook:=true;
end;end.
// 主程序unit MainFormUnit;interfaceuses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, Local, global,
StdCtrls;type
TMainForm = class(TForm)
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;var
MainForm: TMainForm;implementation{$R *.DFM}procedure TMainForm.FormCreate(Sender: TObject);
begin
// 建立全局hook
GHookInstalled:=SetupGlobalHook;
end;procedure TMainForm.FormDestroy(Sender: TObject);
begin
RemoveLocalHook;
end;end.
實驗結果表明,如果截取 WM_INPUTLANGCHANGE 是不成功的,但如果換成 WM_INPUTLANGCHANGEREQUEST 則可以,但是 WM_INPUTLANGCHANGEREQUEST 是在輸入法轉換前發出的,我要的是輸入法成功轉換後的消息,請問怎樣做才可以?thanks
不對吧,WM_IME_COMPOSITION 是當輸入法編碼狀態改變時而發出的吧,如果衹是用ALT+SHIFT改變keyboard layout,會觸發這個消息?我試了一下,好像不行哦
改为if (wParam=WM_INPUTLANGCHANGE) then接收消息类型的是wParam不是lParam,其实消息就是一个整型的数字,所以也不用强制类型转换直接用就行了
但我用的是 WH_GETMESSAGE hook 哦,在 WINAPI的說明中,它的callback function 是這樣的LRESULT CALLBACK GetMsgProc( int code, // hook code
WPARAM wParam, // removal flag
LPARAM lParam // address of structure with message
);wParam 不對應相應的 message,消息結構在 lParam 中。當然我也實驗過,用 if (wParam=WM_INPUTLANGCHANGE)then ...是不成的。真奇怪,我的代碼可以截到 WM_INPUTLANGCHANGEREQUEST 就是截不了 WM_INPUTLANGCHANGE
When the DefWindowProc function receives the WM_INPUTLANGCHANGEREQUEST message, it activates the new input locale and notifies the application of the change by sending the WM_INPUTLANGCHANGE message. unit Unit1;interfaceuses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;type
TForm1 = class(TForm)
Button1: TButton;
Edit1: TEdit;
procedure FormCreate(Sender: TObject);
private
OldWndProc: TWndMethod;
protected
procedure NewWndProc(var Message: TMessage);
end;var
Form1: TForm1;implementation{$R *.dfm}procedure TForm1.NewWndProc(var Message: TMessage);
begin
if Message.Msg = WM_INPUTLANGCHANGEREQUEST then
begin
ShowMessage('WM_INPUTLANGCHANGEREQUEST');
end;
if Message.Msg = WM_INPUTLANGCHANGE then
begin
ShowMessage('WM_INPUTLANGCHANGE');
end;
OldWndProc(Message);
end;procedure TForm1.FormCreate(Sender: TObject);
begin
OldWndProc := Edit1.WindowProc;
Edit1.WindowProc := NewWndProc;
end;end.
用WH_CALLWNDPROC 钩子就可以。