Delphi:自定义 window 菜单:Msg.CmdType 和 $FFF0 需要说明

Delphi: custom window menu: Msg.CmdType and $FFF0 clarification needed

我正在对我在 Delphi XE6 中开发的 Windows 应用程序做最后的润色。

目前,我对 window 系统菜单感到困惑,我指的是当您单击左侧标题栏中的图标时出现的菜单。

我定义了两个程序:

// this inserts one additional command into the menu
procedure InsertCommand(Sender: TObject);

// this is obviously a handler of mouse clicks on that menu
procedure OnSysCommand(var Msg: TWMSysCommand); message WM_SYSCOMMAND;

定义如下:

const
  ALWAYS_ON_TOP_ID = 1000;

var
  HandleMenu: THandle;
  sAlwaysOnTop: string;

procedure TFormMain.InsertCommand(Sender: TObject);
begin
  // get the system menu handle and store it into form-level defined variable
  HandleMenu := GetSystemMenu(Handle, False);

  // just to make it nicer, I add a separator line
  AppendMenu(HandleMenu, MF_SEPARATOR, 0, '');

  // append "Always on Top" language localized string at the end of the menu
  AppendMenu(HandleMenu, MF_STRING, ALWAYS_ON_TOP_ID, PChar(sAlwaysOnTop));
end;


procedure TFormMain.OnSysCommand(var Msg: TWMSysCommand);
begin

  if Msg.CmdType = ALWAYS_ON_TOP_ID then
    if GetMenuState(HandleMenu, ALWAYS_ON_TOP_ID, MF_BYCOMMAND) and MF_CHECKED = MF_CHECKED
      then begin
        FormStyle := fsNormal;
        CheckMenuItem(HandleMenu, ALWAYS_ON_TOP_ID, MF_UNCHECKED);
      end else begin
        FormStyle := fsStayOnTop;
        CheckMenuItem(HandleMenu, ALWAYS_ON_TOP_ID, MF_CHECKED);
      end;

  inherited;
end;

我现在读到正确的用法是:

Msg.CmdType and $FFF0

但如果我使用它,我的代码将停止工作。

来自官方MSDN source,本人引用:

In WM_SYSCOMMAND messages, the four low-order bits of the wParam parameter are used internally by the system. To obtain the correct result when testing the value of wParam, an application must combine the value 0xFFF0 with the wParam value by using the bitwise AND operator.

问题是,我是否必须避开 $FFF0 掩码,还是有更合适的方法?

文档是准确的,你的代码停止工作的原因当你测试按位 AND 使用 $FFF0 是你定义的常量是不好的。

const
  ALWAYS_ON_TOP_ID = 1000;

1000的十六进制是3E8,最低位的十六进制数应该是0,最低四位为0。IOW,二进制1111是十六进制的F,所以你应该把最后一位留给系统。

将常量设置为十六进制,这样就不会出错。在定义常量时,请小心远离 SC_... 范围(即 $F000 ... $F###)。例如:

const
  ALWAYS_ON_TOP_ID = 0; {256}

所以现在你可以安全地测试了

  if Msg.CmdType and $FFF0 = ALWAYS_ON_TOP_ID then
    ...