グローバルフックをVK_CANCELで終了させたいのですが


いつもここから  2017-08-24 00:20:37  No: 48747

お世話になります。
前回作成したグローバルフックを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;


通りすがり  2017-08-24 00:49:20  No: 48748

エラーメッセージを書きましょう


いつもここから  2017-08-24 01:41:36  No: 48749

エラーは次の通りです。
[dcc32 エラー] : E2029 '(' が必要な場所に ')' があります
[dcc32 エラー] : E2066 演算子またはセミコロン (';') が必要です
[dcc32 エラー] : E2029 ')' が必要な場所に ';' があります
[dcc32 致命的エラー] : F2063 'Unit1.pas' ユニットはコンパイルできませんでした


Mr.XRAY  2017-08-24 02:25:55  No: 48750

>エラーメッセージを書きましょう 

ですね.

それとですね.コールバック関数内で受けたメッセージに対して処理をする場合,
できる限り,コールバック関数内ではなく,呼び出し側のスレッド
 (新規に作成したプロジェクトの場合は Form1)
に PostMesssage して,そこで処理するようにした方がいいです.
そうしないと思わぬ結果になることがあります.

フックの詳しい説明は英文しかないので難しいのですが...
処理を分けることで,問題が発生したときの切り分けにもなります.

SendMessage を使用してしまうと,フックの性質からして,
コールバック関数内での処理と同じになってしまいます.

>[dcc32 エラー] : E2029 '(' が必要な場所に ')' があります 
>     pEvent := pEVENTMSG(lParam);//<<<<<コンパイル時ここでエラー! 

lParam という変数はどこで定義しているのですか ?
これだと,コールバック関数の引数の型名と同じになってしまいます.
Delphi は大文字と小文字を区別しません.これが便利なこともあるわけです.


Mr.XRAY  2017-08-24 02:53:23  No: 48751

>これだと,コールバック関数の引数の型名と同じになってしまいます. 

これは型変換 (型キャスト) を要求することになるわけです.
つまり,以下のように,キャストには () が必要ということです.

  型名 (変数名)
  TBitmap(LBitmap)


Mr.XRAY  2017-08-24 03:00:06  No: 48752

>エラーメッセージを書きましょう 

>ですね. 

さらにですね.
どかこのサイトの記事やサンプルを参考にした時は,その URL を示すといいのです.
そうすれば,他の方も参考になるし,気が付いてレスしてくれるかも知れません.
今回の質問の文章の場合,私の名前がでているのですが,私自身も「どれかな ?」と探してしまいます.
自分のサイトの記事のどこに何があるか,全てを把握できるほどの頭脳は持っていません (キッパリ !!)


いつもここから  2017-08-24 23:45:02  No: 48753

>どこかのサイトの記事やサンプルを参考にした時は,その&nbsp;URL&nbsp;を示すといいのです.

すみません、参考にしたのは次の部分です。
ぴったりのがなくてつぎはぎしましたけど...
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;

//---------------------------

>それとですね.コールバック関数内で受けたメッセージに対して処理をする場合,&nbsp;
できる限り,コールバック関数内ではなく,呼び出し側のスレッド&nbsp;
&nbsp;(新規に作成したプロジェクトの場合は&nbsp;Form1)&nbsp;
に&nbsp;PostMesssage&nbsp;して,そこで処理するようにした方がいいです.&nbsp;
そうしないと思わぬ結果になることがあります.

ごめんなさい、どのように変えればいいのでしょうか?


Mr.XRAY  2017-08-25 01:38:23  No: 48754

上で提示しているコードは,フックのコールバック関数内でフック終了のコードがあります.
そういうことはできません.
フックの終了コードは,コールバック関数以外で実行する必要があります.
そのためにも,メッセージを PostMessage で送って処理する方がいいのです.

>ごめんなさい、どのように変えればいいのでしょうか? 

参考にされたのは,

http://mrxray.on.coocan.jp/Delphi/plSamples/260_HookKeyMouseEvent.htm#04
http://mrxray.on.coocan.jp/Delphi/plSamples/260_HookKeyMouseEvent.htm#list2

ですよね.
そうなると,そこに掲載していコードを参考にしてください.
というよりは他にないのですが....
私のサンプルコードでは PostMessage を使用していますよね ?
掲載しているサンプルコードは,ページの最初に書いてある環境では間違いなく動作します.


Mr.XRAY  2017-08-25 01:51:31  No: 48755

フックを使用するプログラムは,コーディングとしては難しい部類だと,個人的には思っています.
基本的には PostMessage を使用する必要があります.
その PostMessage の引数を処理しなければなりません.
しかも,情報を取得するには型キャストも必要です.

しかし,フック処理のプログラムが書けるようになると,結構いろいろいな応用が可能です.
是非頑張ってください.


Mr.XRAY  2017-08-25 02:02:12  No: 48756

それからプログラムをテストする時は注意が必要です.
Delphi の IDE からコンパイルして実行するのではなく,
作成した EXE を起動してテストしてみてください.
これは,IDE の設定にもよりますが,その方が確実です.

面倒ですか.


いつもここから  2017-08-25 04:10:31  No: 48757

>それからプログラムをテストする時は注意が必要です.&nbsp;
Delphi&nbsp;の&nbsp;IDE&nbsp;からコンパイルして実行するのではなく,&nbsp;
作成した&nbsp;EXE&nbsp;を起動してテストしてみてください.&nbsp;
これは,IDE&nbsp;の設定にもよりますが,その方が確実です.&nbsp;

回答ありがとうございます。
そうなんですか?
知りませんでした。

でも、今日は夕食(+晩酌)も済んでいい気分ですので明日試してみます。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加