c# winproc重写-消息机制使用-SendMessage和PostMessage的区别
SendMessage和PostMessage的区别
SendMessage是将消息发送到窗口函数,在窗口函数处理完消息后才返回。
PostMessage 是将消息发送到窗口的消息队列中,然后立即返回
SendMessage是同步处理
PostMessage是异步处理
BOOL PostMessage(
HWND hWnd, // handle of destination window
UINT Msg, // message to post
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
);
消息就是发到hWnd这个窗口
----------------------------------------------------------------------------------------------------------------------------------------------------
PostMessage 和SendMessage的区别主要在于是否等待其他程序消息处理。PostMessage只是把消息放入队列,不管其他程序是否处理都返回,然后继续执行;而SendMessage必须等待其他程序处理消息后才返回,继续执行。这两个函数的返回值也不同,PostMessage的返回值表示PostMessage函数执行是否正确,而SendMessage的返回值表示其他程序处理消息后的返回值。
---------------------------------------------------------------------------------------------
前者需要马上返回
后者要阻塞等待
凡是由你设计而却由Windows系统调用的函数,统称callback函数。这些函数都有一定的类型,以配合Windows的调用操作
---------------------------------------------------------------------------------------------
注意在实际使用中才有可能体会异同点,
以前我写程序的时候发现post到消息队列的消息可能会丢失,
尤其你的消息特别多,例如用timer发送的时候容易出错
仅供参考!
---------------------------------------------------------------------------------------------
1 对于消息映射机制的理解。表面上看是A发消息到B,然后B收到消息执行相应的操作。实际上呢?消息映射的原理是:B预先设定,假如A执行了发某个消息的过程,那么B就做某一个操作。可以看出,实际上并没有什么“消息”在传递,消息映射的实质是A对B的一种函数调用。
2 进一步理解消息映射,A调用B的函数,那么A要不要等到B的过程执行完再继续呢?这就是消息队列机制了。PostMessage只是把调用要求放进一个等待队列里(消息队列),而SendMessage一定要等到B执行完消息映射函数才能继续,这就是两个函数的本质区别。
补充一下: 很多人会被“消息”的假象迷惑,一定要记住,其实并不存在什么消息,消息映射机制只不过是一种跨对象的函数调用,不是A“发消息”让B做什么,而是B“自己决定”在A“执行发消息函数”的时候做什么!
---------------------------------------------------------------------------------------------
CALLBACK是回调的意思,即由应用程序定义,供系统调用的函数.
就实质而言,CALLBACK是一种调用方式,即__stdcall
而C/C++的默认调用方式是__cdecl
子线程向主线程窗口发消息
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; namespace SendPostMessageTest { public partial class Form1 : Form { [DllImport("user32.dll", EntryPoint = "SendMessage")] public static extern int SendMessage(int hWnd, int Msg,int wParam,ref COPYDATASTRUCT lParam); [DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)] public static extern int FindWindow(string lpClassName, string lpWindowName); private static int WM_COPYDATA = 0x004A; //固定值 public Form1() { InitializeComponent(); } public struct COPYDATASTRUCT { public IntPtr dwData; public int cbData; [MarshalAs(UnmanagedType.LPStr)] public string lpData; } protected override void DefWndProc(ref Message m) { if(m.Msg== WM_COPYDATA) { COPYDATASTRUCT cds = new COPYDATASTRUCT(); Type t = cds.GetType(); cds = (COPYDATASTRUCT)m.GetLParam(t); string receiveInfo = cds.lpData; } else { base.DefWndProc(ref m); } } protected override void WndProc(ref Message m) { if (m.Msg == WM_COPYDATA) { COPYDATASTRUCT cds = new COPYDATASTRUCT(); Type t = cds.GetType(); cds = (COPYDATASTRUCT)m.GetLParam(t); string receiveInfo = cds.lpData; MessageBox.Show(receiveInfo); } //const int WM_SYSCOMMAND = 0x0112; //const int SC_CLOSE = 0xF060; //if (m.Msg == WM_SYSCOMMAND && (int)m.WParam == SC_CLOSE) //{ // // 屏蔽传入的消息事件 // this.WindowState = FormWindowState.Minimized; // return; //} base.WndProc(ref m); } private void button1_Click(object sender, EventArgs e) { Thread thead_test = new Thread(test_show); thead_test.IsBackground = true; thead_test.Start(); } private void test_show() { //OQA测试接收消息窗口 while(true) { int hWnd = FindWindow(null, "OQA测试接收消息窗口"); if (hWnd == 0) { MessageBox.Show("未找到:OQA测试接收消息窗口"); } else { string sendMsg = "子线程发送数据到指定窗口"; byte[] str_array = System.Text.Encoding.Default.GetBytes(sendMsg); int length = str_array.Length; COPYDATASTRUCT cds; cds.dwData = (IntPtr)0; cds.cbData = length + 1; cds.lpData = sendMsg; SendMessage(hWnd, WM_COPYDATA, 0, ref cds); } Thread.Sleep(3000); } } } }