26 Nov 2004

グローバルフック

キーボード入力をグローバルフックしたくて結構調べたのにあまり無かったのでメモ程度に。

フックはアプリケーションから行おうとするとローカルフックになってしまい、アプリがバックグラウンドに居る時にはフックしてくれない。これは、Windowsメッセージが上流でDispatchされてるから。スイッチングハブが上流に挟まってるのと同じイメージ。このスイッチングハブより上に行かないと自分以外のメッセージを奪い取ってくることができないけど、DLLからフックをするとなんと上流でフックすることが可能となり、グローバルフックになる。

というわけで、グローバルフックのためのDLLを作成。

プロセス間でのデータ共有をしたいので、共有メモリを使うことになります。これは初期化をしないと使えない模様。
フックハンドラ、フックしたときにメッセージを送る先のウィンドウハンドラ、そしてどういうメッセージを送るか、のための変数を用意。
あとついでにDLL自身のインスタンスハンドルを保持するグローバル変数も宣言。

//SharedDataSegment
// if shared data don't initialize , data segment don't allocate

#pragma data_seg(".shareddata")
HHOOK g_hHook = 0; // Handle of identify Hook
static UINT g_Message = -1;
static HWND g_hWnd = NULL;
#pragma data_seg()

static HINSTANCE g_hDllInst = NULL;

DLLのエントリポイントでは、先ほど定義したグローバル変数に自身のインスタンスハンドラを保持させ、後で、グローバルフックチェインに自作フックプロシージャを組み込ませるのに利用。フックしている時にアプリケーションを落とすと、プロセスデタッチが呼ばれる模様。起動は不明(未確認)

//====================
// DLL entry point
//====================

BOOL WINAPI DllMain
(HINSTANCE hInstance, DWORD reason, LPVOID lpReserved)
{
switch(reason){
case DLL_PROCESS_ATTACH:
g_hDllInst = hInstance; // hold dll handle
break;
case DLL_PROCESS_DETACH:
// if detach a process , system call DLL_PROCESS_DETACH.
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
break;
}
return TRUE;
}

フックプロシージャでは、フックの開始の時に、どのhWndに何のMessageを送るかを、指定してもらい、g_hWnd,g_Messageに保持しているため、それをSendMessageしてやる。if分岐では、hWndが存在し、Messageがあるときに、フックを開始しているとしている。最後に次のフックを呼んであげることで、この自作フックプロシージャを、グローバルのフックチェインの中に組み込める。もし最後に次のフックを呼ばないと、そこでフックチェインが切れてしまい、他のアプリにメッセージが届かない、といったことが起こってしまうかも。(やったことないけど。怖いし((;゚Д゚)ガクガクブルブル)

//=========================
// Hook Procedure
//=========================

LRESULT CALLBACK KeyProc
(int nCode , WPARAM wParam , LPARAM lParam)
{
// if SetHook was called
if( g_hWnd != NULL && g_Message != -1){
// send Message to application
SendMessage(g_hWnd , g_Message , wParam , lParam );
}

// Chain to next hook procedure
return CallNextHookEx(g_hHook , nCode , wParam , lParam );
}

次は、1つ目はDLLのインスタンスハンドラを(σ・∀・)σゲッツ!!するための関数。
2つ目はアプリケーション側からフック開始を通知するための関数。これにアプリケーションのhWndとアプリケーション側で処理するメッセージが送られてくるので保存。そしてフックのインストール。今回はキーフックだけど、MSDNを見ればもっと色々なのがあるから試してみるといいかも。
3つ目はフック終了させる関数。これを呼ばないとフックされたままになってしまう。呼ばなくても再起動すればいいけど、メモリリークみたいな感じになるかも。

//====================
// Get Module Handle
//====================

HINSTANCE GetDllInstance()
{
return g_hDllInst;
}

//====================
// Install Hook
//====================

BOOL CALLBACK SetHook( HWND hwnd , UINT mes)
{
// Install hook
g_hHook = ::SetWindowsHookEx(
WH_KEYBOARD , // a kind of hook
(HOOKPROC)KeyProc , // procedure function name
GetDllInstance() , // Hooking Instance
0 );

// for Procedure
g_hWnd = hwnd;
g_Message = mes;

// failed
if(g_hHook == NULL){
return FALSE;
}

// succeeded
return TRUE;
}

//====================
// Uninstall Hook
//====================

BOOL CALLBACK ResetHook()
{
//Uninstall Hook
return ::UnhookWindowsHookEx( g_hHook );
}


昨日の日記でも書いたけど、VC++で作っていると最後の最後で大罠が待っている。アクティブな構成をリリースに変えてリリースビルドにしないとグローバルフックができない。デバッグビルドだとローカルフックだけになってしまっている。TRACEしたい時とかはデバッグでビルドして、サンプルアプリから呼び出して挙動を確かめて、ちゃんと動いていたらリリースビルドにしてグローバルフックさせるのがいいと思う。



オラに元気を ヾ( ゚д゚)ノ゛ハァァァァァ・・・・・・・!

投稿者 hilo : 23:13 | Program関連

トラックバック

このエントリーのトラックバックURL:
http://hilo.s55.xrea.com/tt-cgi/tt_tb.cgi/78

Blog about Free ringtones

Free ringtones : 16 Jan 2007 20:24

コメント

Great work!
[url&eq;http://aqayqsuh.com/bfrw/xubc.html]My homepage[/url] | [url&eq;http://tituzjtq.com/wdtr/fcxz.html]Cool site[/url]

投稿者 Debbie : 15 May 2006 19:42

Nice site!
My homepage | Please visit

投稿者 Abby : 15 May 2006 19:42

Well done!
http://aqayqsuh.com/bfrw/xubc.html | http://czqznslg.com/hwcg/fcrk.html

投稿者 Edward : 15 May 2006 19:42

Thank you!
[url&eq;http://tonhnovs.com/ehjs/jcyh.html]My homepage[/url] | [url&eq;http://ajebndfe.com/iwlo/yeuh.html]Cool site[/url]

投稿者 Heather : 14 Sept 2006 02:53

Thank you!
My homepage | Please visit

投稿者 Emma : 14 Sept 2006 02:54

Great work!
http://tonhnovs.com/ehjs/jcyh.html | http://bkhfwbvr.com/vtkt/ytly.html

投稿者 Fawn : 14 Sept 2006 02:54

コメントしてください




保存しますか? はいいいえ