终于懂了:Delphi消息的Result完全是生造出来的,不是Windows消息自带的(Delphi对Windows编程体系的改造越大,学习收获就越大)——消息是否继续传递就看这个Result

Windows中,消息使用统一的结构体(MSG)来存放信息,其中message表明消息的具体的类型,

而wParam,lParam是其最灵活的两个变量,为不同的消息类型时,存放数据的含义也不一样。

time表示产生消息的时间,pt表示产生消息时鼠标的位置。

终于懂了:Delphi消息的Result完全是生造出来的,不是Windows消息自带的(Delphi对Windows编程体系的改造越大,学习收获就越大)——消息是否继续传递就看这个Result

里面没有Result的选项。然后我用VC2008实测MSG结构的大小:

#include <afx.h>

void Cxe111Dlg::OnBnClickedButton1()
{
    CString m_Str;
    int ddd = sizeof(MSG);
    m_Str.Format(_T("%d"), ddd);
    AfxMessageBox(m_Str);
}

结果等于28

void Cxe111Dlg::OnBnClickedButton1()
{
    CString m_Str;
    int ddd = sizeof(WM_SIZE);
    m_Str.Format(_T("%d"), ddd);
    AfxMessageBox(m_Str);
}

结果等于4

void Cxe111Dlg::OnBnClickedButton1()
{
    CString m_Str;
    int ddd = sizeof(WM_CHAR);
    m_Str.Format(_T("%d"), ddd);
    AfxMessageBox(m_Str);
}

结果等于4

-------------------------------------------------------------

再来看Delphi里的定义,它也有原模原样的定义,只不过一般情况下用不到:

  PMsg = ^TMsg;
  tagMSG = packed record
    hwnd: HWND;
    message: UINT;
    wParam: WPARAM;
    lParam: LPARAM;
    time: DWORD;
    pt: TPoint;
  end;

  TMsg = tagMSG;
  MSG = tagMSG;

经过测试,它的大小当然也是28:

procedure TForm1.Button3Click(Sender: TObject);
begin
  ShowMessage(IntToStr(sizeof(tagMSG)));
end;

再看Delphi真正使用的消息结构,注意它包括了Result:

  PMessage = ^TMessage;
  TMessage = packed record
    Msg: Cardinal;
    case Integer of
      0: (
        WParam: Longint;
        LParam: Longint;
        Result: Longint);
      1: (
        WParamLo: Word;
        WParamHi: Word;
        LParamLo: Word;
        LParamHi: Word;
        ResultLo: Word;
        ResultHi: Word);
  end;

测试它的大小:

procedure TForm1.Button3Click(Sender: TObject);
begin
  ShowMessage(IntToStr(sizeof(TMessage)));
end;

结果等于16

-------------------------------------------------------------

再测试消息本身的大小:

procedure TForm1.Button3Click(Sender: TObject);
begin
  ShowMessage(IntToStr(sizeof(WM_CHAR)));
end;

结果等于2

procedure TForm1.Button3Click(Sender: TObject);
begin
  ShowMessage(IntToStr(sizeof(WM_SIZE)));
end;

结果等于1

-------------------------------------------------------------

再来看Delphi定义的消息结构体:

  TWMSize = packed record
    Msg: Cardinal;
    SizeType: Longint; { SIZE_MAXIMIZED, SIZE_MINIMIZED, SIZE_RESTORED,
                         SIZE_MAXHIDE, SIZE_MAXSHOW }
    Width: Word;
    Height: Word;
    Result: Longint;
  end;

  TWMKey = packed record
    Msg: Cardinal;
    CharCode: Word;
    Unused: Word;
    KeyData: Longint;
    Result: Longint;
  end;

  TWMChar = TWMKey;

  TWMPaint = packed record
    Msg: Cardinal;
    DC: HDC;
    Unused: Longint;
    Result: Longint;
  end;

  TWMCommand = packed record
    Msg: Cardinal;
    ItemID: Word;
    NotifyCode: Word;
    Ctl: HWND;
    Result: Longint;
  end;

  TWMNotify = packed record
    Msg: Cardinal;
    IDCtrl: Longint;
    NMHdr: PNMHdr;
    Result: Longint;
  end;

测试Delphi消息结构体的大小:

procedure TForm1.Button3Click(Sender: TObject);
begin
  ShowMessage(IntToStr(sizeof(TWMSize)));
  ShowMessage(IntToStr(sizeof(TWMChar)));
  ShowMessage(IntToStr(sizeof(TWMPaint)));
  ShowMessage(IntToStr(sizeof(TWMCommand)));
  ShowMessage(IntToStr(sizeof(TWMNotify)));
end;

怎么测都是16字节大小。。。

------------------------------------------------------------------------

一个使用例子:

  TWMContextMenu = packed record
    Msg: Cardinal;
    hWnd: HWND;
    case Integer of
      0: (
        XPos: Smallint;
        YPos: Smallint);
      1: (
        Pos: TSmallPoint;
        Result: Longint);
  end;

procedure TControl.WMContextMenu(var Message: TWMContextMenu);
var
  Pt, Temp: TPoint;
  Handled: Boolean;
  PopupMenu: TPopupMenu;
begin
  if Message.Result <> 0 then Exit;
  if csDesigning in ComponentState then
  begin
    inherited;
    Exit;
  end;

  Pt := SmallPointToPoint(Message.Pos);
  if InvalidPoint(Pt) then
    Temp := Pt
  else
  begin
    Temp := ScreenToClient(Pt);
    if not PtInRect(ClientRect, Temp) then
    begin
      inherited;
      Exit;
    end;
  end;

  Handled := False;
  DoContextPopup(Temp, Handled);
  Message.Result := Ord(Handled);
  if Handled then Exit;

  PopupMenu := GetPopupMenu;
  if (PopupMenu <> nil) and PopupMenu.AutoPopup then
  begin
    SendCancelMode(nil);
    PopupMenu.PopupComponent := Self;
    if InvalidPoint(Pt) then
      Pt := ClientToScreen(Point(0, 0));
    PopupMenu.Popup(Pt.X, Pt.Y);
    Message.Result := 1;
  end;

  if Message.Result = 0 then
    inherited;
end;