【Delphi】中使用消息Messages(五)Windows消息

目录

Windows消息使用流程

Windows消息注意事项

Dispatch消息使用流程

Dispatch消息注意事项:


上一节讲述了RTL消息,本节讲述下Windows消息。首先看下演示程序如下:

对于Windows的消息说明如下:

  1. Windows消息一定是绑定在一个含有窗体句柄的对象上,例如TForm、TButton等;
  2. 如果不使用Windows系统自带的SendMessage和PostMessage发送消息,通过Dispatch分发消息,此时也可以不绑定在窗体对象上,只要是对象就可以;
  3. Demo程序演示了三种方式,其中SendMessage和PostMessage发送消息是使用的Windows的原生API。发送的方式有特别约定;Dispatch使用的是Delphi系统给对象封装的消息分发函数,可以用在任何对象上。
  4. 对于Windows的消息,实际上可以理解为一种有索引号的函数调用,调用参数可以灵活,包括字符串、数字、记录体甚至对象,但需要按照指针方式传递参数;
  5. 对于Dispatch调用,也可以传递任何参数,无需指针方式调用;

Windows消息使用流程

一、首先引用Winapi.Messages消息单元

uses
  ....
  Winapi.Windows,
  ....;

二、定义一个消息ID,整型常数。对于用户自定义消息,该常数必须大于WM_USER

const
  WinMessageID      = WM_USER + 1;   //WM_USER 在Winapi.Messages中定义

三、在对象上定义一个响应消息的方法:

private
    { Private declarations }
    //Winapi.Messages 中的消息响应事件
    procedure OnWinMessage(var Message); message WinMessageID;  //定义一个消息ID对应的消息处理函数过程
   

四、实现消息响应方法对应的函数体:

procedure TForm_Message_VCL.OnWinMessage(var Message);
var
  PStudent : ^TStudent;
begin
  PStudent := Pointer( Winapi.Messages.TMessage(Message).WParam);
  Memo1.Lines.Add('Win消息处理记录消息 姓名: ' + PStudent.Name);
  Memo1.Lines.Add('Win消息处理记录消息 年龄: ' + PStudent.age.ToString);
   if PStudent.Sex then
     Memo1.Lines.Add('Win消息处理记录消息 性别: 男')
  else
     Memo1.Lines.Add('Win消息处理记录消息 性别: 女');

  //如果是SendMessage 可以不释放 PStudent 指针资源,因为SendMessage是同步执行的,发送消息函数应该自己销毁,当然这里销毁也是可以的
  //如果是PostMessage,此时应该销毁这个指针,因为PostMessage是不需要等待结果的,此时如果释放资源就会出现问题。
  Dispose(PStudent);

end;

五、发送消息,可以使用SendMessage或者PostMessage,其区别在于SendMessage需要等待函数执行完成返回结果,而PostMessage无需等待消息结果。

procedure TForm_Message_VCL.Button_SendMessageWinClick(Sender: TObject);
var
  PStudent: ^TStudent; //记录指针
begin
  //申请指针资源
  New(PStudent);
  //构造消息体内容
  PStudent.Name := LabeledEdit_WinName.Text;
  PStudent.age  := SpinEdit_WinAge.Value;
  PStudent.Sex  :=CheckBox_WinSex.Checked;
  //按照 windows 的约定发送消息,必须包含句柄
  SendMessage(Self.Handle,WinMessageID,DWord(PStudent),0);
  //此处是否释放需要根据程序决定,总之上面已经申请了资源,一定要记得在合适的地方释放
  //Dispose(PStudent);
end;

Windows消息注意事项

必须使用SendMessage或者PostMessage,两个函数定义的格式(参见Windows文档)如下:

LRESULT SendMessage(
  [in] HWND   hWnd,
  [in] UINT   Msg,
  [in] WPARAM wParam,
  [in] LPARAM lParam
);

参数说明

hWnd:表示的是窗口对象的句柄,窗口对象必须存在;

Msg:消息ID,整型数。对应Demo中的 WinMessageID

wParam:就是需要发送的消息体指针

IParam:附加的额外消息体指针

对于具体的消息体,可以任意定义,Demo中定义的是一个记录体:

type
  TStudent = record
    Name : string;
    age  : Byte;
    Sex  : Boolean;
  end;

如果不使用Windows消息,而是使用Delphi系统提供的Dispatch机制,也可以实现消息分发。

Dispatch消息使用流程

一、 和Windows消息一样,首先引用Winapi.Messages消息单元

uses
  ....
  Winapi.Windows,
  ....;

二、定义一个消息ID,整型常数。对于用户自定义消息ID,一般不要大于50000,否则会引起编译错误。同时定义一个需要传递的消息结构

const
  DispatchMessageID = WM_USER + 2;   //Dispatch 消息

type
  //Dispatch需要的消息结构,注意增加了一个id字段
  TStudent2 = record
    id   : Word;    //消息ID
    Name : string;
    age  : Byte;
    Sex  : Boolean;
  end;

三、在对象上(注意不一定是窗口对象,也就是说不一定需要有句柄)定义一个消息响应函数过程:

private
    { Private declarations }
    //Winapi.Messages 中的消息响应事件
    procedure OnWinMessage(var Message); message WinMessageID;  //定义一个消息ID对应的消息处理函数过程
    procedure OnDispatchMessage(var Message); message DispatchMessageID;  //定义一个消息ID对应的消息处理函数过程

四、实现消息响应方法对应的函数体(请注意和Windows消息的实现体的区别):

procedure TForm_Message_VCL.OnDispatchMessage(var Message);
var
  Student2 : TStudent2;
begin
  Student2 := TStudent2(Message);
  Memo1.Lines.Add('Win2消息处理记录消息 姓名: ' + Student2.Name);
  Memo1.Lines.Add('Win消息处理记录消息 年龄: ' + Student2.age.ToString);
   if Student2.Sex then
     Memo1.Lines.Add('Win消息处理记录消息 性别: 男')
  else
     Memo1.Lines.Add('Win消息处理记录消息 性别: 女');
end;

五、发送消息,调用对象上的Dispatch函数(Delphi系统已经在每个对象上都实现了Dispatch)

procedure TForm_Message_VCL.Button_DispatchClick(Sender: TObject);
var
  Student2 : TStudent2;
begin
  Student2.id := DispatchMessageID;
  //构造消息体内容
  Student2.Name := LabeledEdit_WinName.Text;
  Student2.age  := SpinEdit_WinAge.Value;
  Student2.Sex  :=CheckBox_WinSex.Checked;
  //通过对象的Dispatch发送消息,实际上就是调用函数
  Self.Dispatch(Student2);
end;

Dispatch消息注意事项:

Dispatch传递参数不需要指针,但是消息体中增加了一个字段id,是一个Word型的整数。对于Dispatch的定义在Delphi中有如下说明:

Calls message-handling methods for the object, based on the contents of the Message parameter. 

Call Dispatch to automatically pass messages to the appropriate message handler. 

Dispatch determines whether a message is in the list of message handlers declared for the object. If the object does not handle the message, Dispatch then examines the message-handler list of the ancestor class, and continues checking ancestors until it either finds a specific handler or runs out of ancestors, in which case it calls DefaultHandler

The only assumption Dispatch makes about the data in Message is that the first two bytes contain a message ID—that is, an integer that determines which message handler Dispatch calls. Although any kind of data can be passed to Dispatch, most TObject descendants expect a message record such as TMessage or a specific data structure type. 
 

注意红色加粗这句,意思是消息体的前两个字节必须包含一个 message ID。这个就是我们TStudent2中的id字段。

下一节:【Delphi】中使用消息Messages(六)总结及源代码 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Delphi和Python之间通讯可以使用消息队列来实现,具体步骤如下: 1. 在Delphi创建一个消息队列用于接收Python发来的消息。 2. 在Python使用消息队列模块创建一个消息队列,并将需要发送的消息放入队列。 3. Delphi通过轮询消息队列来获取Python发送的消息,并根据消息内容进行相应的处理。 4. Python可以通过轮询消息队列来获取Delphi发送的消息,并根据消息内容进行相应的处理。 下面是一个简单的示例代码: 在Delphi: ```delphi uses Windows, Messages; const WM_PYTHON_MSG = WM_USER + 1; // 定义Python消息ID type TForm1 = class(TForm) private { Private declarations } procedure HandlePythonMsg(var Msg: TMessage); message WM_PYTHON_MSG; public { Public declarations } end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.HandlePythonMsg(var Msg: TMessage); var strMsg: string; begin strMsg := PChar(Msg.LParam); // 获取Python发送的消息 // 根据消息内容进行相应的处理 ShowMessage(strMsg); end; ``` 在Python: ```python import win32api import win32con import win32event import win32file import struct WM_PYTHON_MSG = win32con.WM_USER + 1 # 定义Python消息ID def send_msg_to_delphi(msg): hwnd = win32gui.FindWindow(None, "DelphiForm") # 获取Delphi窗口句柄 if hwnd: win32api.PostMessage(hwnd, WM_PYTHON_MSG, 0, msg) # 发送消息Delphi else: print("Can't find Delphi window") def recv_msg_from_delphi(): handle = win32event.CreateEvent(None, 0, 0, None) # 创建事件 overlapped = win32file.OVERLAPPED() overlapped.hEvent = handle buf = struct.pack("L", WM_PYTHON_MSG) # 构造消息格式 (err, msg) = win32file.ReadFile(handle, buf, overlapped) # 从消息队列获取消息 if err == win32file.ERROR_IO_PENDING: win32event.WaitForSingleObject(handle, 1000) # 等待事件 (err, msg) = win32file.GetOverlappedResult(handle, overlapped, True) if err == 0: print("Error reading from message queue") else: return msg.decode("utf-8") ``` 上述示例代码Delphi的 HandlePythonMsg 过程用于处理接收到的Python消息,Python的 send_msg_to_delphi 函数用于将消息发送给Delphi,recv_msg_from_delphi 函数用于从Delphi接收消息。注意,Delphi消息ID和Python消息ID必须一致。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

海纳老吴

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值