Мне нужно знать, нажата ли F11, когда PopupMenu TrayIcon открыт и завершает программу. Не хочу RegisterHotKey. В документации указано, что «PopupList.Window предоставляет доступ к дескриптору окна скрытого окна, которое обрабатывает сообщения всплывающего меню». Итак, мой план состоит в том, чтобы перехватывать сообщения клавиатуры в этом окне, но вместо этого происходит следующее:
Project Project2.exe поднял класс исключений $C0000005 с сообщением «нарушение доступа по адресу 0x00020003: запись адреса 0x2014fd38».
unit Unit2;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ImgList, Vcl.Menus, Vcl.ExtCtrls;
type
TForm2 = class(TForm)
TrayIcon1: TTrayIcon;
PopupMenu1: TPopupMenu;
N11: TMenuItem;
N21: TMenuItem;
ImageList1: TImageList;
procedure PopupMenu1Popup(Sender: TObject);
private
function hook(code: Integer; w: WPARAM; p : LPARAM): Lresult stdcall;
public
{ Public declarations }
end;
var
Form2: TForm2;
HookID: hhook;
implementation
{$R *.dfm}
function TForm2.hook(code: Integer; w: WPARAM; p: LPARAM): Lresult stdcall;
begin
if code < 0 then
begin
Result := CallNextHookEx(0, code, w, p);
Exit;
end;
Result := CallNextHookEx(0, code, w, p);
end;
procedure TForm2.PopupMenu1Popup(Sender: TObject);
begin
HookID := SetWindowsHookEx(WH_KEYBOARD, @TForm2.hook, 0,
GetWindowThreadProcessId(PopupList.Window, nil));
end;
end.
SetWindowsHookEx()
— не лучший способ перехватывать сообщения клавиатуры, отправляемые во всплывающее меню. Просто создайте подкласс самого PopupList.Window
, используя SetWindowSubclass()
или SetWindowLongPtr()
. Или лучше просто замените объект PopupList
на пользовательский объект, который переопределяет метод TPopupList.WndProc()
.
Ваша функция ловушки является методом TForm2 и поэтому имеет дополнительный (скрытый) параметр self. Вы должны разместить функцию вне TForm2:
TForm2 = class(TForm)
TrayIcon1: TTrayIcon;
PopupMenu1: TPopupMenu;
N11: TMenuItem;
N21: TMenuItem;
ImageList1: TImageList;
procedure PopupMenu1Popup(Sender: TObject);
private
public
{ Public declarations }
end;
function hook(code: Integer; w: WPARAM; p : LPARAM): Lresult stdcall;
implementation
function hook(code: Integer; w: WPARAM; p: LPARAM): Lresult stdcall;
begin
if code < 0 then
begin
Result := CallNextHookEx(0, code, w, p);
Exit;
end;
Result := CallNextHookEx(0, code, w, p);
end;
Или вы можете превратить его в статическую функцию класса: private class function hook(code: Integer; w: WPARAM; p : LPARAM): Lresult stdcall; static;
А также удалите лишние строки кода: просто всегда вызывайте CallNextHookEx().
Тело вашего крючка можно упростить до Result := CallNextHookEx(0, code, w, p);