Delphi:系统菜单打开了吗? [英] Delphi: Is system menu opened?

查看:92
本文介绍了Delphi:系统菜单打开了吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在Delphi中,我需要一个函数来确定是否打开了系统菜单(分别是窗口菜​​单,单击图标时出现的菜单)。原因是我正在编写一个反键盘记录器功能,该功能会将垃圾发送到当前的活动editcontrol(这也防止了键盘记录器读取WinAPI消息以读取内容)。但是,如果打开系统菜单,则editcontrol仍然具有焦点,因此垃圾将调用快捷方式。

I Delp 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.

如果我在其中使用消息 WM_INITMENUPOPUP 在我的TForm1上,我可以确定何时打开系统菜单,但是我希望不必更改TForm,因为我想编写一个非可视组件,该组件不需要在TForm派生类本身上进行任何修改。

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()不发送 WM_INITMENUPOPUP 到我的hook函数。

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?

致谢

Daniel Marschall

Regards
Daniel Marschall

推荐答案

如果您不希望对TForm-派生类,为什么不尝试使用纯Windows API方式来实现当前解决方案,即使用 SetWindowLongPtr()拦截 WM_INITMENUPOPUP 消息。实际上,Delphi VCL样式来拦截消息只是此Windows API函数的包装。

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_INITMENUPOPUP message. Delphi VCL style to intercept messages is just a wrapper of this Windows API function actually.

为此,请使用 SetWindowLongPtr()可以为 window过程设置一个新地址,并获得窗口过程的原始地址,两者都是一击。请记住将原始地址存储在 LONG_PTR 变量中。在32位Delphi中, LONG_PTR Longint ;假设将来会发布 64位 Delphi,则 LONG_PTR 应该为 Int64 ;您可以使用 $ IFDEF 指令来区分它们,如下所示:

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 a LONG_PTR variable. In 32-bit Delp LONG_PTR was Longint; supposing 64-bit Delphi will have been released in the future, LONG_PTR should be Int64; you can use $IFDEF directive to distinguish them as follows:

  Type
    {$IFDEF WIN32}
    PtrInt = Longint;
    {$ELSE}
    PtrInt = Int64;
    {$ENDIF}
    LONG_PTR = PtrInt;

要使用的 nIndex 参数的值为此目的是 GWLP_WNDPROC 。另外,将窗口过程的新地址传递给 dwNewLong 参数,例如 LONG_PTR(NewWndProc) NewWndProc 用于处理消息的WindowProc回调函数,您可以在其中放置拦截条件并覆盖要拦截的消息的默认处理方式。回调函数可以是任何名称,但是参数必须遵循 WindowProc 约定。

The value for nIndex parameter to be used for this purpose is GWLP_WNDPROC. Also, pass the new address for the window procedure to dwNewLong parameter, e.g. LONG_PTR(NewWndProc). The NewWndProc is 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.

请注意,您必须调用 CallWindowProc()会将新窗口过程未处理的任何消息传递给原始窗口过程。

Note that you must call CallWindowProc() to pass any messages not processed by the new window procedure to the original window procedure.

最后,您应该在代码中的某处再次调用 SetWindowLongPtr()以设置修改后的/新的窗口过程处理程序的地址回到原始地址。如上所述,原始地址已被保存。

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.

有一个此处是Delphi代码示例。它使用了 SetWindowLong(),但是现在Microsoft建议使用 SetWindowLongPtr()使其与32-位和64位版本的Windows。

There was a Delphi code example here. It used SetWindowLong(), but now Microsoft recommends to use SetWindowLongPtr() instead to make it compatible with both 32-bit and 64-bit versions of Windows.

SetWindowLongPtr() Windows.pas 。如果使用较旧版本的Delphi,则必须自己声明它,或使用 JwaWinUser JEDI API库的单位。

SetWindowLongPtr() didn't exist in Windows.pas of Delphi prior to Delphi 2009. If you use an older version of Delp you must declare it by yourself, or use JwaWinUser unit of JEDI API Library.

这篇关于Delphi:系统菜单打开了吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆