USBマウスについている"戻る"・"進む"のボタンが押されたときに、
"戻る"・"進む"の動作(APPCOMMAND_BROWSER_BACKWARD、APPCOMMAND_BROWSER_FORWARD)ではなく
設定したプログラムを実行するようにしたいと考えているのですが、
なぜか、他のプログラムが受け取る WM_APPCOMMAND をグローバルフックすることができません。
どこが、おかしいのでしょうか?
------------------------------------------------------------------------------
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.
------------------------------------------------------------------------------
SetHandleToHookDLL() で 呼び出し側のハンドルをDestWndHandleに代入してして、そのハンドルの先に PostMessage()でメッセージをしたいのですよね??
SetWindowHookEx()でグローバルフックを行う際には DestWndHandle のように事前に呼び出し側のハンドルを保持していてもフックプロシージャで利用できません。
( たしか SetWindowHookEx()はOSにしかける関数なのですべてのメッセージを拾い処理していきますのでウィンドウハンドルを区別できないような感じだったと思います。)
こういうときは DestWndHandleの値を 共有メモリで保持しておくときちんと取得することができますよ。呼び出し側で アプリのハンドルを取得して
共有メモリに保持する。 DLL側でその値を読み込んで指定したウィンドウハンドルにメッセージを送るという風にすれば問題ないはず・・・現状だと呼び出し側のアプリ上ではフック(ローカル)できているのではないでしょうか??
確かに、共有メモリにハンドルを保存すれば、
グローバルフックできました。
参考 http://www.q3.nu/trucomania/truco.cgi?409&ing
カレーライズ さん、ありがとうございます。
しかし、IEやエクスプローラなど"戻る"・"進む"メッセージに
反応するように作られているプログラムがアクティブのときはフックできませんでした。
なぜでしょうか?
しかたないので、
WH_SHELLでWM_APPCOMMANDをフックするのではなく、
キーボード・マウスのフックでどうにかできないか考えてみようと思います。
確かに、共有メモリにハンドルを保存すれば、
グローバルフックできました。
参考 http://www.q3.nu/trucomania/truco.cgi?409&ing
カレーライズ さん、ありがとうございます。
しかし、IEやエクスプローラなど"戻る"・"進む"メッセージに
反応するように作られているプログラムがアクティブのときはフックできませんでした。
なぜでしょうか?
しかたないので、
WH_SHELLでWM_APPCOMMANDをフックするのではなく、
キーボード・マウスのフックでどうにかできないか考えてみようと思います。
ツイート | ![]() |