WM_APPCOMMANDをグローバルフックしてブロックするには?

解決


パルプンテ  2006-06-13 10:55:53  No: 22159

USBマウスについている"戻る"・"進む"のボタンが押されたときに、
"戻る"・"進む"の動作(APPCOMMAND_BROWSER_BACKWARD、APPCOMMAND_BROWSER_FORWARD)ではなく
設定したプログラムを実行するようにしたいと考えているのですが、
なぜか、他のプログラムが受け取る WM_APPCOMMAND をグローバルフックすることができません。
どこが、おかしいのでしょうか?


パルプンテ  2006-06-13 10:56:22  No: 22160

------------------------------------------------------------------------------
library HookDLL;

uses
  Windows,
  Messages,
  SysUtils,
  Unit1 in 'Unit1.pas' {Form1},

const
  MY_HOOK_MESSAGE = WM_USER + $1006;

var
  DestWndHandle : HWND  = 0;
  HookHandle    : HHOOK = 0;

function OnHookProc(nCode: Integer; aWParam: WPARAM; aLParam: LPARAM): LRESULT; stdcall;
begin
  if nCode < 0 then
  begin
    Result := CallNextHookEx(HookHandle, nCode, aWParam, aLParam);
  end
  else
  if nCode = HSHELL_APPCOMMAND then
  begin
    // メッセージをアプリケーションに送る
    PostMessage(DestWndHandle, MY_HOOK_MESSAGE, aWParam, aLParam);
    Result := 1;
  end
  else
  begin
    Result := CallNextHookEx(HookHandle, nCode, aWParam, aLParam);
  end;
end;

function SetHookDLL: HHOOK; export;
begin
  Result := 0;

  if HookHandle <> 0 then
  begin
    Exit;
  end;

  HookHandle := SetWindowsHookEx(WH_SHELL , @OnHookProc, HInstance, 0);
  Result := HookHandle;
end;

procedure UnHookDLL; export;
begin
  if HookHandle = 0 then
  begin
    Exit;
  end;

  if UnhookWindowsHookEx(HookHandle) then
  begin
    HookHandle := 0;
  end;
end;

procedure SetHandleToHookDLL(hWnd: HWND); export;
begin
  DestWndHandle := hWnd;
end;

exports
  SetHandleToHookDLL,
  SetHookDLL,
  UnHookDLL;

begin
//
end.

------------------------------------------------------------------------------

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

const
  DLL_NAME        = 'HookDLL.dll';
  MY_HOOK_MESSAGE = WM_USER + $1006;  //適当

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Memo1: TMemo;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    procedure OnDLLHookMessage(var Msg: TMessage); message MY_HOOK_MESSAGE;
  public
  end;

var
  Form1: TForm1;

procedure SetHandleToHookDLL(hWnd: HWND); external DLL_NAME;
function  SetHookDLL: HHOOK; external DLL_NAME;
procedure UnHookDLL; external DLL_NAME;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
  SetHandleToHookDLL(Handle);
  SetHookDLL;
end;

procedure TForm1.OnDLLHookMessage(var Msg: TMessage);
begin
  // フックされたことを確認表示
  Memo1.Lines.Add( IntToHex(Msg.WParam, 8) + '_' + IntToHex(Msg.LParam, 8) );
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  UnHookDLL;
end;

end.

------------------------------------------------------------------------------


カレーライズ  2006-06-14 04:41:42  No: 22161

SetHandleToHookDLL()  で  呼び出し側のハンドルをDestWndHandleに代入してして、そのハンドルの先に PostMessage()でメッセージをしたいのですよね??
  SetWindowHookEx()でグローバルフックを行う際には DestWndHandle のように事前に呼び出し側のハンドルを保持していてもフックプロシージャで利用できません。
( たしか SetWindowHookEx()はOSにしかける関数なのですべてのメッセージを拾い処理していきますのでウィンドウハンドルを区別できないような感じだったと思います。)
  こういうときは DestWndHandleの値を 共有メモリで保持しておくときちんと取得することができますよ。呼び出し側で  アプリのハンドルを取得して
共有メモリに保持する。 DLL側でその値を読み込んで指定したウィンドウハンドルにメッセージを送るという風にすれば問題ないはず・・・現状だと呼び出し側のアプリ上ではフック(ローカル)できているのではないでしょうか??


パルプンテ  2006-06-14 08:07:01  No: 22162

確かに、共有メモリにハンドルを保存すれば、
グローバルフックできました。
参考 http://www.q3.nu/trucomania/truco.cgi?409&ing
カレーライズ さん、ありがとうございます。

しかし、IEやエクスプローラなど"戻る"・"進む"メッセージに
反応するように作られているプログラムがアクティブのときはフックできませんでした。
なぜでしょうか?

しかたないので、
WH_SHELLでWM_APPCOMMANDをフックするのではなく、
キーボード・マウスのフックでどうにかできないか考えてみようと思います。


パルプンテ  2006-06-14 08:07:01  No: 22163

確かに、共有メモリにハンドルを保存すれば、
グローバルフックできました。
参考 http://www.q3.nu/trucomania/truco.cgi?409&ing
カレーライズ さん、ありがとうございます。

しかし、IEやエクスプローラなど"戻る"・"進む"メッセージに
反応するように作られているプログラムがアクティブのときはフックできませんでした。
なぜでしょうか?

しかたないので、
WH_SHELLでWM_APPCOMMANDをフックするのではなく、
キーボード・マウスのフックでどうにかできないか考えてみようと思います。


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

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






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