Delphi SetWindowsHookEx钩子中未处理消息
我想创建一个DLL,当加载到进程中时,它会在应用程序菜单中添加一个“始终在顶部”项。我创建了一个钩子,尝试了Delphi SetWindowsHookEx钩子中未处理消息,delphi,hook,message-queue,delphi-xe,Delphi,Hook,Message Queue,Delphi Xe,我想创建一个DLL,当加载到进程中时,它会在应用程序菜单中添加一个“始终在顶部”项。我创建了一个钩子,尝试了SetWindowsHookEx(WH_CALLWNDPROC,…)和SetWindowsHookEx(WM_GETMESSAGE,…),然后从那里添加菜单并检查WM_u消息中的点击事件。WM_SYSCOMMAND被触发,但没有我插入的菜单项ID(始终\u ONTOP)。为什么我的菜单项没有被处理(或者,为什么我不能捕获插入的菜单项单击事件) 库dlltest; 使用 窗口、消息、系统工具
SetWindowsHookEx(WH_CALLWNDPROC,…)
和SetWindowsHookEx(WM_GETMESSAGE,…)
,然后从那里添加菜单并检查WM_u消息中的点击事件。WM_SYSCOMMAND被触发,但没有我插入的菜单项ID(始终\u ONTOP)。为什么我的菜单项没有被处理(或者,为什么我不能捕获插入的菜单项单击事件)
库dlltest;
使用
窗口、消息、系统工具;
变量
钩子:HHOOK;
启用:布尔值;
常数
始终p=100;
函数GetMessageCallback(代码:整数;wParam:wParam;lParam:lParam):LRESULT;stdcall;
变量
uMsg:TMSG;
汉努:唐德尔;
开始
如果(代码=HC\U动作),则
开始
//--
//--插入菜单项
如果(Enabled=False),则
开始
humenu:=GetSystemMenu(umsg.hwnd,FALSE);
如果(hMenu 0)那么
开始
{Enabled:=}附加菜单(menu,MF_分隔符,0,”);
已启用:=附录菜单(hMenu、MF_字符串、始终在顶部、“始终在顶部”);
End//Else writetext('hMenu=0!');
结束;
//--
//--处理消息
uMsg:=PMSG(lParam)^;
案例(uMsg.消息)
WM_SYSCOMMAND:
开始
案例loword(uMsg.信息)
始终坚持:
开始
//切换复选标记
MessageBoxA(0,'你好世界','测试',0);
结束;
结束//案例
结束//WM_SYSCOMMAND:
WM_初始化菜单:
开始
//GetSystemMenu返回0?,嗯
//writetext('WM_INITMENU');
结束//WM_初始化菜单:
结束//案例uMsg
结束//如果(HC_行动)
结果:=CallNextHookEx(Hook、Code、wParam、lParam);
结束;
开始
已启用:=假;
Hook:=SetWindowsHookEx(WH_GETMESSAGE{WH_CALLWNDPROC},@GetMessageCallback{@WndProcCallback},0,GetCurrentThreadId());
如果(Hook=0),则
开始
消息框(0,'无挂钩','失败',0);
结束;
结束。
旁注:我的WndProcCallback()与GetMessageCallback()基本相同,只是我根据MSDN将lParam强制转换为PCWPStruct。嗯,刚刚意识到我的标题有误导性,我如何更改它?阅读帮助,点击标签下面的链接(在本例中,就在
delphi
和hook
之间)。。请仅使用适用于您的问题的标签。Delphi不是Pascal。泛型Pascal标记用于传统Pascal语言。Delphi可能起源于turbopascal,但它已经演变成自己的语言。谢谢。为什么在测试时总是使用loword(uMsg.message)
?至此,您已经知道uMsg.message
本身就是WM\u SYSCOMMAND
。它的位中不包含始终\u ONTOP
值。您应该测试uMsg.wParam和$FFF0
。话虽如此,您是否考虑过使用WH\u CBT
hook?尝试在HCBT_CREATEWND
、HCBT_ACTIVATE
或HCBT_SETFOCUS
通知中添加菜单项,然后在HCBT_SYSCOMMAND
通知中处理菜单项。WM_SYSCOMMAND
保留wParam
的低位4位供内部使用(这就是为什么在测试值时必须使用wParam和$FFF0
)。二进制中的100是01100100
,而二进制中的96是01100000
。看起来很熟悉吗?96是100,其低位4位设置为0(在本例中,100-4=96).So 100作为菜单项ID与WM\u SYSCOMMAND
不兼容。请使用不使用低位4位的其他值,或与现有SC\u…
定义的ID冲突。
library dlltest;
uses
Windows, messages, sysutils;
var
Hook : HHOOK;
Enabled : boolean;
Const
ALWAYS_ONTOP = 100;
Function GetMessageCallback(code: integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
Var
uMsg : TMSG;
hMenu : Thandle;
Begin
IF(Code = HC_ACTION)Then
Begin
//--
//-- Insert Menu Item
IF (Enabled = False) then
Begin
hMenu := GetSystemMenu(umsg.hwnd, FALSE);
IF (hMenu <> 0) Then
Begin
{Enabled :=}AppendMenu(hMenu, MF_SEPARATOR, 0, '');
Enabled := AppendMenu(hMenu, MF_STRING, ALWAYS_ONTOP, 'Always On Top');
End //Else writetext('hMenu=0!');
End;
//--
//-- Process message(s)
uMsg := PMSG(lParam)^;
case (uMsg.message) of
WM_SYSCOMMAND:
Begin
case loword(uMsg.message) of
ALWAYS_ONTOP:
Begin
//toggle checkmark
MessageBoxA(0, 'Hello World', 'test', 0);
End;
End;//Case
End;//WM_SYSCOMMAND:
WM_INITMENU:
Begin
//GetSystemMenu returns 0?, hmm
//writetext('WM_INITMENU');
End;//WM_INITMENU:
end;//case uMsg
end;//IF (HC_ACTION)
Result := CallNextHookEx(Hook, Code, wParam, lParam);
End;
begin
enabled := False;
Hook := SetWindowsHookEx(WH_GETMESSAGE{WH_CALLWNDPROC}, @GetMessageCallback {@WndProcCallback}, 0, GetCurrentThreadId());
IF(Hook = 0)Then
Begin
messagebox(0, 'no hook', 'fail', 0);
End;
end.