MFC从线程向主界面发送消息(Message)的实现2020-08-04 21:42:54

( 1人已投票,[高质量] )
分享:
31.3K

实现消息的发送主要两种方式,SendMessage 与 PostMessage两种,这两种区别就是前者是阻塞的,后者是异步的,举个例子来说,Post像送报纸,心想一块钱的东西还要包邮,往门前一仍人就跑了,而Send方式是货到付款的,不收到钱他是不会回公司的。两个发送方式的函数原型及调用的方式是一样,传说返回值有点点不同,根据需要选择吧,一般来说,Send很快的,发送个消息又不传对象,都是秒回的,用的很多,Post感觉高大上一点吧,包含进程间传消息都不是事,这里不深入探讨,两种方式等下都发送下给你看,下面开始!


实现消息通信,主要分四步!

1)定义一个宏,

#define  WM_TESTMESSAGE  (WM_USER + 100)

这个宏随便写,只要不重复了就行,值大概 0x0400这样的,为什么我用WM_USER呢,因为这个宏是系统定义了的,而且用的很多,直接加个数就使用了方便,为什么加100呢,因为和你的想法一样,有不少组控件也用它,在后面+N,如果你加1,一不小心就和他们重复了,不过问题一般不大,暂且加100。这个宏放在哪里呢,网上太多人说要放在stdafx.h文件下,这是依赖系统项,谁会去改变不是自己的东西呢,我偏放在我自己的类顶上myDLG2020.cpp,因为我是本界面测试的,没有域限制,如果想多界面甚至多进程通信,只需要解决这个宏的作用域就好了,能调用到它就行

2)定义接收函数

LRESULT myDLG2020::OnReciveMessage(WPARAM wParam, LPARAM lParam)
{
  CString cstr1 = (LPCTSTR)wParam;
  CString cstr2 = (LPCTSTR)lParam;
  TRACE(_T("Got it:wParam is: - %s\n"), cstr1);
  TRACE(_T("Got it:lParam is: - %s\n"), cstr2);
  return 1;
}

看名字就知道,他是一个类内的方法,去.h中也加上声明吧 。

afx_msg LRESULT OnReciveMessage(WPARAM wParam, LPARAM lParam);

这里有个版本兼容的坑,如果你是老版本的vc6.0,这个函数返回值可能是void但是在VS2018 19新版,早就改为LRESULT 了,否则会报后面的参数转换失效。<MFC ON_MESSAGE 类型转换无效 >

3)定义发送函数

UINT myDLG2020::TestingMessage(LPVOID lParam) {
  myDLG2020* pWnd = (myDLG2020*)lParam; //线程内掉用线程外的内容的方式
  //pWnd->KMeansSegment();            //调用外部函数
  //pWnd->myTestParmter123;            //调用外部变量
  //CWnd* pWnd = CWnd::FindWindow(NULL, msg);//已经有句柄了
  int i = 0;
  while (true) {
    if (pWnd->bThread2Stop) break;
    TRACE("Inner thread - %d\n",i);
    CString cstr1;
    cstr1.Format(_T("%d"), i);
    CString cstr2 = _T("Hello Test String!");  
    pWnd->SendMessage(WM_TESTMESSAGE, (WPARAM)(LPCTSTR)cstr1,(LPARAM)(LPCTSTR)cstr2);
    //pWnd->PostMessage(WM_TESTMESSAGE, (WPARAM)(LPCTSTR)cstr1, (LPARAM)(LPCTSTR)cstr2);
    //pWnd->PostMessage(WM_TESTMESSAGE, (WPARAM)(LPCTSTR)cstr1);//传一个值也是可以的,听说甚至可以传结构体或对象。。。
    i++;
    Sleep(1000);
  }
  return 1;
}

我这个函数是一个多线程内的函数,是由另一个button按纽事件下启用

AfxBeginThread(TestingMessage, (LPVOID)this);

一般通信都是在多线程或多进程中,在一个做用域下也不用通信了。我讨厌文章繁琐,一般不相干的,我觉对不往一起掺杂,努力写成模板做到读者copy就能用,因为我以后也直接拷贝,也能给我省不少时间,这块只是单纯为了测试。相信你看到之后,不但会用,还对流程一清二楚,举一返三,就能熟练掌握了。这样说主要是怕我自己以后忘了,好丢人啊。。。

【讲解】本篇文章看到myDLG2020就是我主界面类,用的时候就改为你自己的,函数内部前三行,我上一篇文章讲过了,多线程获取主界面句柄,调用外部函数与变量更容易,这三行很不简单,打通了一个通道。其实用这个方法就可以降低message的依赖性了,但是message很强大,不但能传各种对象甚至能发送一个消息给“按纽”,对于程序逻辑精简至关重要!

接下来的是一个while循环,是测试占用时间的,再怎么费时的工作也不会阻塞主线程。bThread2Stop是一个外部的公共bool变量,是用来防止程序退出了,循环还在转,在结束的时候,将他设为true,这个逻辑是解决无限死循环的一个重要方法。

下一行是TRACE("Inner thread - %d\n",i);,TRACE是MFC调试利器,这个函数只在debug时输出到底部的“输出”窗口,很是直观,还带变量转换,很方便。

下面搞了两个变量,一个来源是一直在变的int型的参数,另一个是字符串,cstr1,cstr2。

下面调用发送消息函数,你看我写了三条,其实任意解开一条,都有效果,我只是想展现send与post与单、双参数的方法,需要说明的是,由于我给线程传送了pWnd这个句柄指针的,所以我直接用它发送了,但是函数原型中的第一个参数就是句柄,也就是说如果你要这样发送也是一回事SendMessage(hwnd,WM_TESTMESSAGE,...。这里的WM_TESTMESSAGE就是我们第一步定义的宏,大家都被穿在这一条线上了,举一返三,是不是可以定义多个宏,同时送三个不同的快递呢,由其在很拥挤的时候,这可能很有用。。。

Sleep因为里面没有耗时,输出会很快的,故做了个延迟。

4)绑定收发函数

BEGIN_MESSAGE_MAP(myDLG2020, CDialogEx)
  ON_WM_SYSCOMMAND()
  ON_WM_PAINT()
    。。。。。。
  ON_MESSAGE(WM_TESTMESSAGE, OnReciveMessage)//绑定
END_MESSAGE_MAP()

这几句话,不要看多,其实只要写一句话(就是注释//绑定那一行),其他内容方便定位位置用的,不要放错地方了,而是在cpp文件中 BEGIN_MESSAGE_MAP的尾部加上这么一行ON_MESSAGE,这些代码是新建MFC应用时默认就有的。如果你不是对话框模式或者没有这些代码,那可能需要再去头文件里定义一下。值得一提的是,对话框模式下默认还有下BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx),这是“关于对话框”那个绑定,不是这里不要搞错了,第一个参数应该是你的类名,对于初学者来说确实都是坑,比尔,你变了。。。


至此,一个完整精简的线程向主界面发送的消息就规划好了,我们运行一下,上面说了,我是在按纽事件中启动了线程,所以,点击了按纽后,每隔1秒就发送了一个消息到主界面,说明流程已经通了,说句实在话,这个收发过程与java中很类似,java中就是不用绑定而已。


最后上一张鼓舞图,按我说的来,能避开不少坑,而且如果够聪明,消息这块从此都不是事。想发啥就去查原型函数,看参数说明,想实现啥就改啥,你就比我厉害了。


MFC从线程向主界面发送消息(Message)的实现




话太多了,如果你是高手,肯定觉得繁琐,这还用说,多此一举,我也讨厌文章太长。。。下不为例。。。祝你成功!

MFC从线程向主界面发送消息(Message)的实现






头像

snowcoal
  • MFC
  • vs2019
  • 多线程
  • 收发消息

收藏到我的私密空间

标题:MFC从线程向主界面发送消息(Message)的实现

作者:花花世界

你暂未登录,请登录后才可收藏至您的私密空间 确认取消
雪炭网

键盘操作 更便捷 -雪炭网雪中送炭-乐趣无限

如果本站的内容有幸帮助到了您,建议您了解一下当页的广告内容哦,我们的进步离不开您的支持,Thank you~