Windows メッセージ マネージャーは、アプリケーションが制御されたメッセージ フローにアクセスする機能を提供します。
'c4 のいわゆるフック (HOOK) メカニズム。フックには多くの種類があり、それぞれ特定の種類または範囲のメッセージをキャプチャするために使用されます。例: キーボード メッセージ、マウス メッセージなど。ここでは、DELPHI で DLL プログラムを作成する方法と、独自のプログラムにキーボード フック関数をインストールして使用する方法について説明するため、キーボード フックの使用を例として取り上げます。また、異なるプログラムが同じ DLL ファイルを使用する場合にデータを共有する方法についても説明します。 。
1. フックフィルター関数の作成手順
フック フィルター関数は独立したモジュール内に存在する必要があるため、最初に DLL フレームワークを生成し、次にフック関数コードとその他の関連関数コードをそこに追加する必要があります。ここでは、キーボードフックフィルター関数の記述を例として説明します。具体的な手順は次のとおりです。
1. まず DLL バスケットを生成します 2
2. 独自のキーボード フック フィルター関数を作成する
フック フィルター関数はコールバック関数である必要があり、その関数の形式は次のとおりです。
functionKeyHookPROc(
iCode:整数;
wParam:WPARAM;
lParam:LPARAM ): LRESULT; ;エクスポート;
生成された DLL フレームワークに独自のキーボード フック処理関数を追加して、キーボード メッセージを処理します。
コードは次のとおりです:…
if(iCode>=0) から開始
Result:=0; //初期化戻り値
// ここに独自のコードを追加します
それ以外で終了
始める
結果:=CallNextHook(hOldKeyHook,iCode,wParam,lParam);
//hOldKeyHook は保存されたオリジナルのキーボード フィルター関数ですか?
終わり;
3. キーボードフックフィルター機能をインストールする
フックをインストールするには、_fd フィルター関数で SetWindowsHookEx 関数を呼び出す必要があります (Windows 3.0 の SetWindowsHook フック インストール関数は現在廃止されています)。この関数のプロトタイプは次のとおりです。
HHOOK SetWindowsHookEx(
int idHook, // インストールされていますか?_b3 サブタイプ
HOOKPROC lpfn, //フックフィルター??f 番号アドレス
HINSTANCE hMod, //タスクハンドル
DWord dwThreadId // フックの目的
);
?_a8 は多くの場合、MakeProcInstance 関数を呼び出して出力関数のプリアンブルのエントリ アドレスを取得し、このアドレスを SetWindowsHookEx の 2 番目のパラメーター lpfn として使用する必要があることに注意してください。ただし、Delphi は「スマート コールバック」を提供しているため、MakeProcInstance を省略し、フック フィルター関数名を直接エントリ アドレスとして使用できます。
このように、アプリケーションの _c3GetMessage または PeekMessage 関数がメッセージ キューからメッセージを読み取る場合、または処理するキー メッセージ (WM_KEYDOWN または WM_KEYUP) がある場合、システムはフック フィルター関数 KeyHookProc を呼び出してキーボード メッセージを処理します。
4. フックフィルター機能をアンインストールします。
フック関数が不要になった場合は、UnHookWindowsHookProc を呼び出して、インストールされているフックをアンインストールしてシステム リソースを解放する必要があります。
完全なプログラムリストは次のとおりです?_ba
ライブラリキーフック;
Windows を使用します。
const BUFFER_SIZE=16*1024;
const HOOK_MEM_FILENAME='SAMPLE KEY_HOOK_MEM_FILE';
const HOOK_MUTEX_NAME ='SAMPLE KEY_HOOK_MUTEX_NAME';
タイプ
TShared=レコード
キー: Char の array[0..BUFFER_SIZE]。
KeyCount : 整数;
終わり;
P共有=^TS共有;
変数
MemFile、HookMutex: THandle;
hOldKeyHook: Hフック;
ProcSaveExit: ポインタ;
共有: P共有;
//キーボードフックフィルター関数
関数 KeyHookProc(iCode: 整数; wParam: WPARAM ; lParam: LPARAM):LRESULT
;標準呼び出し;
const KeyPressMask = $80000000;
始める
iCode < 0 の場合
結果 := CallNextHookEx(hOldKeyHook, iCode, wParam, lParam)
そうでなければ始まる
if ((lParam および KeyPressMask)= 0) then // キーが押されました
始める
Shared^.Keys[Shared^.KeyCount]:=Char(wParam と $00ff);
Inc(共有^.KeyCount);
Shared^.KeyCount>=BUFFER_SIZE-1 の場合、Shared^.KeyCount:=0;
終わり;
iCode:=-1;
結果 := CallNextHookEx(hOldKeyHook, iCode, wParam, lParam);
終わり;
終わり;
//フックフィルター関数を設定する
関数 EnableKeyHook: BOOL;
始める
Shared^.KeyCount:=0; //キーボードポインタを初期化します。
hOldKeyHook=0 の場合は開始します
hOldKeyHook := SetWindowsHookEx(WH_KEYBOARD,
キーフックプロシージャ、
Hインスタンス、
0);
終わり;
結果 := (hOldKeyHook <> 0);
終わり;
//アンドゥフックフィルタ関数
関数 DisableKeyHook: BOOL;
始める
hOldKeyHook<> 0 の場合
始める
UnHookWindowsHookEx(hOldKeyHook); // キーボードフックのフックを解除します。
hOldKeyHook:= 0;
共有^.KeyCount:=0;
終わり;
結果 := (hOldKeyHook = 0);
終わり;
//キーボードバッファ内のキーストローク数を取得します。
関数 GetKeyCount :Integer;
始める
結果:=Shared^.KeyCount;
終わり;
//キーボードバッファのキーを取得します
関数 GetKey(index:Integer) : エクスポート;
始める
結果:=Shared^.Keys[インデックス];
終わり;
//キーボードバッファをクリアする
プロシージャ ClearKeyString のエクスポート;
始める
共有^.KeyCount:=0;
終わり;
//DLL終了処理プロセス
プロシージャ KeyHookExit まで;
始める
hOldKeyHook <> 0 の場合は DisableKeyHook;
UnMapViewOfFile(Shared); // メモリイメージファイルを解放します。
CloseHandle(MemFile); // 画像ファイルを閉じます。
ExitProc := ProcSaveExit;
終わり;
exports // 出力関数を定義します
キーフックを有効にする、
キーフックを無効にする、
GetKeyCount、
クリアキー文字列、
GetKey;
始める
//DLL初期化部分
HookMutex:=CreateMutex(nil,True,HOOK_MUTEX_NAME);
// メモリイメージファイルを作成してメモリを共有する
MemFile:=OpenFileMapping(FILE_MAP_WRITE,False,
HOOK_MEM_FILENAME);
MemFile=0 の場合
MemFile:=CreateFileMapping($FFFFFFFF,nil,PAGE_READWRITE,0,
SizeOf(TShared) 、HOOK_MEM_FILENAME);
共有:=MapViewOfFile(MemFile,File_MAP_WRITE,0,0,0);
ReleaseMutex(HookMutex);
CloseHandle(HookMutex);
ProcSaveExit := ExitProc // DLL の ExitProc を保存します。
ExitProc := @KeyHookExit // DLL の新しい ExitProc を設定します。
終わり。
//ソースコードの終わり
2. 用意されたキーボードフックフィルター関数を独自のプログラムで使用します。
フック関数のコンパイル後の使用は、実際には非常に簡単です。まず SetWindowsHookEx を呼び出して独自のフック フィルター関数をインストールし、同時に元のフック フィルター関数のアドレスを保存します。このとき、フック関数が機能し、要件に応じてキーボード メッセージを処理します。プログラムの実行が終了するか、キーボード メッセージを監視する必要がなくなったら、UnHookWindowsHookProc 関数を呼び出して、インストールされているフック関数をアンインストールし、元のフック フィルター関数のアドレスを復元します。
以下は、上でコンパイルしたフック関数の使用例です。
ユニットユニット1;
インタフェース
用途
ウィンドウ、メッセージ、SysUtils、クラス、グラフィックス、コントロール、フォーム、ダイアログ、
StdCtrls、ExtCtrls;
タイプ
TForm1 = クラス(TForm)
メモ1: Tメモ;
パネル1: Tパネル;
bSetHook: TButton;
bCancelHook: TButton;
bReadKeys: TButton;
bClearKeys: TButton;
パネル2: Tパネル;
プロシージャ bSetHookClick(Sender: TObject);
プロシージャ bCancelHookClick(Sender: TObject);
プロシージャ bReadKeysClick(Sender: TObject);
プロシージャ bClearKeysClick(Sender: TObject);
終わり;
var Form1: TForm1;
実装
{$R *.DFM}
関数 EnableKeyHook : BOOL ; 外部 'KEYHOOK.DLL';
関数 DisableKeyHook : BOOL ; 外部 'KEYHOOK.DLL';
関数 GetKeyCount : 外部 'KEYHOOK.DLL';
関数 GetKey(idx:Integer) : Char ; 外部 'KEYHOOK.DLL';
プロシージャ ClearKeyString; 外部 'KEYHOOK.DLL';
プロシージャ TForm1.bSetHookClick(Sender: TObject); // キーボード フックを設定します。
始める
キーフックを有効にする;
bSetHook.Enabled :=False;
bCancelHook.Enabled:=True;
bReadKeys.Enabled :=True;
bClearKeys.Enabled :=True;
Panel2.Caption:='キーボードフックが設定されました';
終わり;
プロシージャ TForm1.bCancelHookClick(Sender: TObject); // キーボード フックをアンインストールします
始める
キーフックを無効にする;
bSetHook.Enabled :=True;
bCancelHook.Enabled:=False;
bReadKeys.Enabled :=False;
bClearKeys.Enabled :=False;
Panel2.Caption:='キーボードフックが設定されていません';
終わり;
プロシージャ TForm1.bReadKeysClick(Sender: TObject); // キーストローク履歴を取得します。
変数 i:整数;
始める
Memo1.Lines.Clear; // Memo1 にキー入力履歴を表示します。
for i:=0 から GetKeyCount-1 まで
Memo1.Text:=Memo1.Text+GetKey(i);
終わり;
プロシージャ TForm1.bClearKeysClick(Sender: TObject); // キーストロークの履歴をクリアします
始める
メモ1.クリア;
クリアキー文字列;
終わり;
終わり。
//ソースコードの終わり
3. Windows95でのDLLへの共有メモリの実装
上記のフック関数が配置されている DLL ファイルでは、共有メモリを使用する必要があります。つまり、すべてのキーストローク レコードが同じデータ セグメントに格納されます。なぜこれを行うのでしょうか?これは、Windows95 と Windows3.X では DLL の呼び出し方法が異なるためです。各スレッドがダイナミック リンク ライブラリにログインすると、新しいインスタンス ハンドル (つまり、DLL データ セグメントのハンドル) がダイナミック リンク ライブラリに渡されます。これにより、DLL のさまざまなインスタンスが相互に干渉することがなくなりますが、すべての DLL インスタンスが一連の変数を共有する場合にいくつかの問題が発生します。この問題を解決するために、ここではメモリ マップト ファイルを作成することで解決します。つまり、Windows の OpenFileMapping、CreateFileMapping、および
MapViewOfFile の 3 つの機能を実現します。使用方法:
…
MemFile は THandle 型、Shared はポインタ型、HOOK_MEM_FILENAME は定数文字列です。
…
MemFile:=OpenFileMapping(FILE_MAP_WRITE,False,
HOOK_MEM_FILENAME); //メモリマップされたファイルを開きます
if MemFile=0 then //開くのに失敗した場合?_c2 メモリ マップト ファイルを作成する
MemFile:=CreateFileMapping($FFFFFFFF,nil,PAGE_READWRITE,0,
SizeOf(TShared) 、HOOK_MEM_FILENAME);
// ファイルを変数にマッピングする
共有:=MapViewOfFile(MemFile,File_MAP_WRITE,0,0,0);
これまでのところ、Delphi でフック関数をコンパイルすることがいかに簡単であるかはすでにわかりました。最後に皆さんに注意していただきたいのですが、フック関数は比較的強力ですが、不適切に使用するとシステムの効率に重大な影響を与えるため、システム フックの使用は避けるようにしてください。システムの動作への影響を最小限に抑えるために、使用する必要がある場合は特に注意する必要があります。
【全文終わり】