在 Delphi 中,我需要一个函数来确定系统菜单(分别是窗口菜单,单击图标时出现的菜单)是否打开。原因是我正在编写一个反键盘记录器功能,它将垃圾发送到当前活动的编辑控件(这也阻止了键盘记录器读取 WinAPI 消息来读取内容)。但是,如果打开系统菜单,编辑控件仍然具有焦点,因此垃圾将调用快捷方式。
如果我使用消息WM_INITMENUPOPUP在我的 TForm1 中,我可以确定系统菜单何时打开,但我希望不必更改 TForm,因为我想编写一个非可视组件,它不需要对 TForm 派生类本身进行任何修改。
//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
到我的钩子函数。
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;
即使经过很长时间的研究,我也没有找到任何有关如何查询系统菜单是否打开的信息。我没有找到任何方法来确定该菜单的打开+关闭。
有人可以帮我解决吗?
Regards
丹尼尔·马歇尔
Application.HookMainWindow
并没有按照你的想法去做。它挂钩隐藏的应用程序窗口,而不是主窗体。拦截WM_INITMENUPOPUP
正如您所看到的,在特定的表单上,您所需要做的就是为其编写一个处理程序。
要为组件的任何所有者形式执行此操作,您可以指定WindowProc
用于放置挂钩的表单属性:
unit FormHook;
interface
uses
Windows, Classes, SysUtils, Messages, Controls, Forms;
type
TFormMessageEvent = procedure(var Message: TMessage; var Handled: Boolean) of object;
TFormHook = class(TComponent)
private
FForm: TCustomForm;
FFormWindowProc: TWndMethod;
FOnFormMessage: TFormMessageEvent;
protected
procedure FormWindowProc(var Message: TMessage); virtual;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
published
property OnFormMessage: TFormMessageEvent read FOnFormMessage write FOnFormMessage;
end;
procedure Register;
implementation
procedure Register;
begin
RegisterComponents('Test', [TFormHook]);
end;
procedure TFormHook.FormWindowProc(var Message: TMessage);
var
Handled: Boolean;
begin
if Assigned(FFormWindowProc) then
begin
Handled := False;
if Assigned(FOnFormMessage) then
FOnFormMessage(Message, Handled);
if not Handled then
FFormWindowProc(Message);
end;
end;
constructor TFormHook.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FFormWindowProc := nil;
FForm := nil;
while Assigned(AOwner) do
begin
if AOwner is TCustomForm then
begin
FForm := TCustomForm(AOwner);
FFormWindowProc := FForm.WindowProc;
FForm.WindowProc := FormWindowProc;
Break;
end;
AOwner := AOwner.Owner;
end;
end;
destructor TFormHook.Destroy;
begin
if Assigned(FForm) and Assigned(FFormWindowProc) then
begin
FForm.WindowProc := FFormWindowProc;
FFormWindowProc := nil;
FForm := nil;
end;
inherited Destroy;
end;
end.
然后您可以在表单上使用此组件:
procedure TForm1.FormHook1FormMessage(var Message: TMessage; var Handled: Boolean);
begin
case Message.Msg of
WM_INITMENUPOPUP:
...
end;
end;
问题可能是,如果表单有任何其他组件执行相同的操作,那么您需要确保以相反的顺序取消挂钩(最后挂钩,首先取消挂钩)。上面的示例在构造函数中挂钩并在析构函数中取消挂钩;即使对于同一表单上的多个实例,这似乎也适用。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)