9

我有一个 Delphi 2007 项目,它在 Windos XP、Vista 和“7”上运行良好多年。它是 Delphi 5 的升级版,因此默认情况下“MainFormOnTaskBar”为“false”(我从未在 DPR 中更改过它)。在这种情况下,系统范围的热键在主窗体的 OnCreate 事件处理程序中使用以下代码在“系统范围内”工作。

HotKey_xyz := GlobalAddAtom('Hotkey_xyz');
if NOT RegisterHotKey(Self.Handle, HotKey_xyz, MOD_CONTROL, VK_F12) then
    ShowMessage('Unable to register Control-F12 as system-wide hot key') ;

(I have GlobalDeleteAtom() and UnregisterHotKey() in Form.OnDestroy as expected.)

现在,我需要一个表单来在任务栏上显示它自己的按钮,所以我在 DPR 中设置了“Application.MainFormOnTaskBar := True”。这按预期工作。但是,这具有 Control-F12 在系统范围内不起作用的副作用,它仅在我的应用程序具有焦点时才起作用(因此,它不再是“系统范围的”。)

我在网上广泛搜索了很多关于“MainFormOnTaskBar”如何/为什么影响某些子表单/模态表单行为的文章。但是,我没有发现它对我上面描述的“系统范围的热键”问题的影响。我已经测试并重新测试了我的应用程序,并将 MainFormOnTaskBar 设置为 true 和 false,而其他所有内容都保持不变。我可以肯定地验证上述系统范围热键的问题与 MainFormOnTaskBar 标志有关。

我将非常感谢有关解决方法的任何指导。我确实需要 - 一个系统范围的热键和一个在任务栏上有自己的按钮的表单。

非常感谢您。

4

1 回答 1

15

TApplication.MainFormOnTaskbar对系统范围的热键完全没有影响。我可以肯定地证实这一点。无论设置为什么,无论应用程序是否聚焦等,我都能够接收WM_HOTKEY消息。因此,无论您看到什么,都不是您认为正在发生的事情。MainFormOnTaskbar

最有可能的Handle是,表单只是在您调用后在您背后重新创建RegisterHotKey(),因此您丢失了HWND将接收WM_HOTKEY消息的表单。除了使用OnCreate事件,您应该覆盖表单的CreateWindowHandle()和方法,以确保无论发生什么情况,DestroyWindowHandle()始终为表单的当前注册热键(每当您将任何类型的数据绑定到表单时,您都应该这样做),例如:HWNDHandle

type
  TForm1 = class(TForm)
  private
    HotKey_xyz: WORD;
    procedure WMHotKey(var Message: TMessage); message WM_HOTKEY;
  protected
    procedure CreateWindowHandle(const Params: TCreateParams); override;
    procedure DestroyWindowHandle; override;
  end;

procedure TForm1.CreateWindowHandle(const Params: TCreateParams);
begin
  inherited;
  HotKey_xyz := GlobalAddAtom('Hotkey_xyz'); 
  if HotKey_xyz <> 0 then
    RegisterHotKey(Self.Handle, HotKey_xyz, MOD_CONTROL, VK_F12);
end;

procedure TForm1.DestroyWindowHandle(const Params: TCreateParams);
begin
  if HotKey_xyz <> 0 then
  begin
    UnregisterHotKey(Self.Handle, HotKey_xyz);
    GlobalDeleteAtom(HotKey_xyz);
    HotKey_xyz := 0;
  end;
  inherited;
end;

procedure TForm1.WMHotKey(var Message: TMessage);
begin
  ...
end;

更好的选择是使用AllocateHWnd()分配一个单独的专用HWND仅用于处理热键消息(然后您可以再次使用OnCreateandOnDestroy事件),例如:

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    HotKey_xyz: WORD;
    HotKeyWnd: HWND;
    procedure HotKeyWndProc(var Message: TMessage);
  end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  HotKeyWnd := AllocateHwnd(HotKeyWndProc);
  HotKey_xyz := GlobalAddAtom('Hotkey_xyz'); 
  if HotKey_xyz <> 0 then
    RegisterHotKey(HotKeyWnd, HotKey_xyz, MOD_CONTROL, VK_F12);
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  if HotKey_xyz <> 0 then
  begin
    UnregisterHotKey(HotKeyWnd, HotKey_xyz);
    GlobalDeleteAtom(HotKey_xyz);
    HotKey_xyz := 0;
  end;
  if HotKeyWnd <> 0 then
  begin
    DeallocateHWnd(HotKeyWnd);
    HotKeyWnd := 0;
  end;
end;

procedure TForm1.HotKeyWndProc(var Message: TMessage);
begin
  if Message.Msg = WM_HOTKEY then
  begin
    ...
  end else
    Message.Result := DefWindowProc(HotKeyWnd, Message.Msg, Message.WParam, Message.LParam);
end;
于 2012-04-19T01:15:54.087 回答