お世話になります。
前回作成したグローバルフックをVK_CANCEL(Ctrl+Break)で終了させたいのですが、どう記述すればいいのでしょうか?Mr.XRAYさんのサイトを参考にさせてもらったのですが、よくわかりません。
//-----------------------------
//------------------------------------------------------------------
// キーフックのコールバック関数
//------------------------------------------------------------------
function LowLevelKeyProc(nCode: Integer; wPar: WPARAM; lPar: LPARAM):
LRESULT; stdcall;
var
Lkbdll : PKBDLLHOOKSTRUCT;
LScanCode : Integer;
pEvent: pEVENTMSG;
begin
if nCode < 0 then begin
Result := CallNextHookEx(KeyHookHandle, nCode, wPar, lPar);
exit;
end;
if nCode = HC_ACTION then begin
pEvent := pEVENTMSG(lParam);//<<<<<コンパイル時ここでエラー!
if (wPar=WM_KEYDOWN) and (Lo(pEvent.paramL)=VK_CANCEL) then begin
UnhookWindowsHookEx(KeyHookHandle);
end;
end;
Result := CallNextHookEx(KeyHookHandle, nCode, wPar, lPar);
end;
//------------------------------
なお、前回のマウスフックのコールバック関数は以下のようにマウスの右ボタンを離したときにチェックするように統一してあります。
//-----------------------------------------------------------------
// マウスフックのコールバック関数
//-----------------------------------------------------------------
function LowLevelMouseProc(nCode:integer; wPar: WPARAM; lPar: LPARAM): LRESULT; stdcall;
var
IsCtrl:Integer;
Label _NextProc;
begin
if nCode < 0 then begin
Result := CallNextHookEx(MouseHookHandle, nCode, wPar, lPar);
exit;
end;
if nCode = HC_ACTION then begin
IsCtrl := (GetKeyState(VK_CONTROL) and $8000);
if (WPar = WM_RBUTTONUP) and(IsCtrl = 0 ) then begin
goto _NextProc;
end;
if (WPar = WM_RBUTTONUP) and(IsCtrl <> 0 ) then begin
keybd_event(VK_Control, 0, 0, 0); //押した状態にする
keybd_event(VK_NUMPAD5, 0, 0, 0); //押した状態にする
keybd_event(VK_NUMPAD5, 0, KEYEVENTF_KEYUP, 0); //放した状態にする
keybd_event(VK_Control, 0, KEYEVENTF_KEYUP, 0); //放した状態にする
Result := 3;
exit;
end;
end;
_NextProc:
Result := CallNextHookEx(MouseHookHandle, nCode, wPar, lPar);
end;
エラーメッセージを書きましょう
エラーは次の通りです。
[dcc32 エラー] : E2029 '(' が必要な場所に ')' があります
[dcc32 エラー] : E2066 演算子またはセミコロン (';') が必要です
[dcc32 エラー] : E2029 ')' が必要な場所に ';' があります
[dcc32 致命的エラー] : F2063 'Unit1.pas' ユニットはコンパイルできませんでした
>エラーメッセージを書きましょう
ですね.
それとですね.コールバック関数内で受けたメッセージに対して処理をする場合,
できる限り,コールバック関数内ではなく,呼び出し側のスレッド
(新規に作成したプロジェクトの場合は Form1)
に PostMesssage して,そこで処理するようにした方がいいです.
そうしないと思わぬ結果になることがあります.
フックの詳しい説明は英文しかないので難しいのですが...
処理を分けることで,問題が発生したときの切り分けにもなります.
SendMessage を使用してしまうと,フックの性質からして,
コールバック関数内での処理と同じになってしまいます.
>[dcc32 エラー] : E2029 '(' が必要な場所に ')' があります
> pEvent := pEVENTMSG(lParam);//<<<<<コンパイル時ここでエラー!
lParam という変数はどこで定義しているのですか ?
これだと,コールバック関数の引数の型名と同じになってしまいます.
Delphi は大文字と小文字を区別しません.これが便利なこともあるわけです.
>これだと,コールバック関数の引数の型名と同じになってしまいます.
これは型変換 (型キャスト) を要求することになるわけです.
つまり,以下のように,キャストには () が必要ということです.
型名 (変数名)
TBitmap(LBitmap)
>エラーメッセージを書きましょう
>ですね.
さらにですね.
どかこのサイトの記事やサンプルを参考にした時は,その URL を示すといいのです.
そうすれば,他の方も参考になるし,気が付いてレスしてくれるかも知れません.
今回の質問の文章の場合,私の名前がでているのですが,私自身も「どれかな ?」と探してしまいます.
自分のサイトの記事のどこに何があるか,全てを把握できるほどの頭脳は持っていません (キッパリ !!)
>どこかのサイトの記事やサンプルを参考にした時は,その URL を示すといいのです.
すみません、参考にしたのは次の部分です。
ぴったりのがなくてつぎはぎしましたけど...
http://mrxray.on.coocan.jp/Delphi/plSamples/260_HookKeyMouseEvent.htmの
リスト1
DLL を使用しないマウスとキーのグローバルフック
リスト6
低レベルのマウスフック WH_MOUSE_LL とキーフック WH_KEYBORD_LL を使用したコード
コンパイルは通ったんですが、Ctrl+ScrollLockまたはCtrl+Pauseでフックを終了できません。
次のようにShowMessageで値を表示したところ、VK_CANCELの値(仮想キーコードの値)3とは異なります)
調べてみるとIParではなくwParが仮想キーコードの値を格納しているようですが、どのようにしてVK_CANCELと比較すればいいのでしょうか?
//-----------------------------------------------------------------------------
// キーフックのコールバック関数
//-----------------------------------------------------------------------------
function LowLevelKeyProc(nCode: Integer; wPar: WPARAM; lPar: LPARAM):
LRESULT; stdcall;
var
Lkbdll : PKBDLLHOOKSTRUCT;
LScanCode : Integer;
pEvent: pEVENTMSG;
begin
if nCode < 0 then begin
Result := CallNextHookEx(KeyHookHandle, nCode, wPar, lPar);
exit;
end;
if nCode = HC_ACTION then begin
pEvent := pEVENTMSG(wPar);//ここをIParからwParに変えただけでは次のエラーが出る
ShowMessage(IntToStr(Lo(pEvent.paramL)));//ここでaccess violation at 0x005c6365
if (wPar=WM_KEYDOWN) and (Lo(pEvent.paramL)=VK_CANCEL) then begin
UnhookWindowsHookEx(KeyHookHandle);
Form1.Caption := 'No Hook!';
KeyHookHandle := 0;
end;
end;
Result := CallNextHookEx(KeyHookHandle, nCode, wPar, lPar);
end;
//---------------------------
>それとですね.コールバック関数内で受けたメッセージに対して処理をする場合,
できる限り,コールバック関数内ではなく,呼び出し側のスレッド
(新規に作成したプロジェクトの場合は Form1)
に PostMesssage して,そこで処理するようにした方がいいです.
そうしないと思わぬ結果になることがあります.
ごめんなさい、どのように変えればいいのでしょうか?
上で提示しているコードは,フックのコールバック関数内でフック終了のコードがあります.
そういうことはできません.
フックの終了コードは,コールバック関数以外で実行する必要があります.
そのためにも,メッセージを PostMessage で送って処理する方がいいのです.
>ごめんなさい、どのように変えればいいのでしょうか?
参考にされたのは,
http://mrxray.on.coocan.jp/Delphi/plSamples/260_HookKeyMouseEvent.htm#04
http://mrxray.on.coocan.jp/Delphi/plSamples/260_HookKeyMouseEvent.htm#list2
ですよね.
そうなると,そこに掲載していコードを参考にしてください.
というよりは他にないのですが....
私のサンプルコードでは PostMessage を使用していますよね ?
掲載しているサンプルコードは,ページの最初に書いてある環境では間違いなく動作します.
フックを使用するプログラムは,コーディングとしては難しい部類だと,個人的には思っています.
基本的には PostMessage を使用する必要があります.
その PostMessage の引数を処理しなければなりません.
しかも,情報を取得するには型キャストも必要です.
しかし,フック処理のプログラムが書けるようになると,結構いろいろいな応用が可能です.
是非頑張ってください.
それからプログラムをテストする時は注意が必要です.
Delphi の IDE からコンパイルして実行するのではなく,
作成した EXE を起動してテストしてみてください.
これは,IDE の設定にもよりますが,その方が確実です.
面倒ですか.
>それからプログラムをテストする時は注意が必要です.
Delphi の IDE からコンパイルして実行するのではなく,
作成した EXE を起動してテストしてみてください.
これは,IDE の設定にもよりますが,その方が確実です.
回答ありがとうございます。
そうなんですか?
知りませんでした。
でも、今日は夕食(+晩酌)も済んでいい気分ですので明日試してみます。
ツイート | ![]() |