I would like to create a DLL which, when loaded into a process, adds an "Always on top" item to the applications Sysmenu. I created a hook trying both SetWindowsHookEx(WH_CALLWNDPROC,...)
and SetWindowsHookEx(WM_GETMESSAGE,...)
, and from there add the menu and check the WM_ messages for click events. WM_SYSCOMMAND is triggered, but without my inserted menu items ID (ALWAYS_ONTOP). Why is my menu item not being processed (or, why can't I capture my inserted menu items click events)?
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.
sidenote: my WndProcCallback() was basically the same as GetMessageCallback(), except that I cast lParam to a PCWPStruct, as per MSDN.