I Delphi, I need a function which determinates if the system menu (resp. window menu, the menu that appears when the icon is clicked) is opened. The reason is that I am writing a anti-keylogger functionality which sends garbage to the current active editcontrol (this also prevents keylogger which read WinAPI messages to read the content). But if system-menu is opened, the editcontrol STILL has the focus, so the garbage will invoke shortcuts.
If I use message WM_INITMENUPOPUP in my TForm1, I can determinate when the system menu opens, but I wish that I do not have to change the TForm, since I want to write a non visual component, which does not need any modifications at the TForm-derivate-class itself.
//I do not want that solution since I have to modify TForm1 for that!
procedure TForm1.WMInitMenuPopup(var Message: TWMInitMenuPopup);
begin
if message.MenuPopup=getsystemmenu(Handle, False) then
begin
SystemMenuIsOpened := true;
end;
end;
TApplicaton.HookMainWindow() does not send the WM_INITMENUPOPUP to my hook function.
function TForm1.MessageHook(var Msg: TMessage): Boolean;
begin
Result := False;
if (Msg.Msg = WM_INITMENUPOPUP) then
begin
// Msg.Msg IS NEVER WM_INITMENUPOPUP!
if LongBool(msg.LParamHi) then
begin
SystemMenuIsOpened := true;
end;
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
Application.HookMainWindow(MessageHook);
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
Application.UnhookMainWindow(MessageHook);
end;
Even after very long research I did not found any information about how to query if the system-menu is opened or not. I do not find any way to determinate the opening+closing of that menu.
Has someone a solution for me please?
Regards
Daniel Marschall
If you don’t want any modifications to TForm-derivate-class, why don’t try pure Windows API way to implement your current solution, that is, use SetWindowLongPtr() to intercept the
WM_INITMENUPOPUPmessage. Delphi VCL style to intercept messages is just a wrapper of this Windows API function actually.For that purpose, use
SetWindowLongPtr()to set a new address for the window procedure and to get the original address of the window procedure, both at one blow. Remember to store the original address in aLONG_PTRvariable. In 32-bit Delphi,LONG_PTRwasLongint; supposing 64-bit Delphi will have been released in the future,LONG_PTRshould beInt64; you can use$IFDEFdirective to distinguish them as follows:The value for
nIndexparameter to be used for this purpose isGWLP_WNDPROC. Also, pass the new address for the window procedure todwNewLongparameter, e.g.LONG_PTR(NewWndProc). TheNewWndProcis a WindowProc Callback Function that processes messages, it is where your put your intercept criteria and override the default handling of the message you are going to intercept. The callback function can be any name, but the parameters must follow the WindowProc convention.Note that you must call CallWindowProc() to pass any messages not processed by the new window procedure to the original window procedure.
Finally, you should call
SetWindowLongPtr()again somewhere in your code to set the address of modified/new window procedure handler back to the original address. The original address has been saved before as mentioned above.There was a Delphi code example here. It used
SetWindowLong(), but now Microsoft recommends to useSetWindowLongPtr()instead to make it compatible with both 32-bit and 64-bit versions of Windows.SetWindowLongPtr()didn’t exist inWindows.pasof Delphi prior to Delphi 2009. If you use an older version of Delphi, you must declare it by yourself, or useJwaWinUserunit of JEDI API Library.