MFC自定义消息发送机制及CString对象作为消息发送(我误认为PostMessage发了多次,其实没有)

595 阅读4分钟

bitwjg.wordpress.com/2011/07/17/…

MFC编程中经常需要在不同的对话框(类)之间发送消息以实现数据共享或流程控制,最简单的方法当然是使用全局变量在不同的类之间共享数据,但如果数据量很大的话,这种方法显得不是那么高效;特别是当我们需要在不同的对话框之间实现逻辑流程控制的时候,首选的方法应该是发送自定义消息。这周的项目里用到了这部分知识,做个总结。

MFC中使用自定义消息需要经过以下步骤;

  1. 在B类的头文件(B.h)中定义消息

    1#define WM_MY_UPDATE WM_USER+100

    网上的帖子说自定义消息至少是WM_USER+100,因为100以内可能是VC中很多控件的消息使用。

  2.  在B的实现文件(B.cpp)中实现消息处理函数

    1234567891011121314151617LRESULT CShowResult::OnMyUpdate(WPARAM wParam, LPARAM lParam) { CString strUpdate = _T(""); wchar_t * pChar = (wchar_t*)wParam; strUpdate = CString(pChar); m_ListBox.AddString(strUpdate); UpdateData(false); return 0; }

    其中CShowResult就是B的类名。

  3. 在类头文件的AFX_MSG块中声明消息处理函数

    1afx_msg LRESULT OnMyUpdate(WPARAM wParam, LPARAM lParam);
  4. 在用户类的消息块中,使用ON_MESSAGE宏指令将消息映射到消息处理函数中。

    12345BEGIN_MESSAGE_MAP(CShowResult, CDialog) ON_MESSAGE(WM_MY_UPDATE, OnMyUpdate) END_MESSAGE_MAP()

完成以上步骤之后,就可以在A.cpp中给B.cpp发送消息了,需要注意的是,消息发送函数是作为B的成员函数出现的。需要在A中定义B类对象的指针,代码如下。

1pShowRst->SendMessageW(WM_MY_UPDATE,(WPARAM)strRst.GetBuffer(0), 0);

MFC中消息发送函数有两个,SendMessage和PostMessage函数。最好是使用SendMessage函数。

因为PostMessage函数是在发送完消息后立刻返回的,而SendMessage是等待接收消息的窗口处理玩消息后才返回。

如果自定义消息不发送数据,只作为控制指令的话,使用两者没有区别,但是如果通过消息共享数据的话,最好使用

SendMessage函数。因为通过消息机制共享数据的实质是共享某块内存,将内存的指针作为SendMessage函数的参数

进行发送。因此如果使用PostMessage函数,消息发送完毕后函数立即返回,等到消息得到处理时,指针所指的内容

可能已经发生变化,使用SendMessage函数则不会有此问题。

还有一点需要注意的是,如何得到CString对象的指针?需要使用CString对象的GetBuffer函数。

网上讲解该函数的帖子很多,比如blog.pfan.cn/xman/43212.…

GetBuffer()主要作用是将字符串的缓冲区长度锁定,releaseBuffer则是解除锁定,使得CString对象在以后的代码中继续可以实现长度自适应增长的功能。

是否需要在GetBufer后面调用ReleaseBuffer(),是根据你的后面的程序是否需要继续使用该字符串变量,并且是否动态改变其长度而定的。不是什么好地编程习惯,之类的原因。
如果你GetBuffer以后程序自函数就退出,局部变量都不存在了,调用不掉用ReleaseBuffer没什么意义了。

对一个CString变量,你可以使用的唯一合法转换符是LPCTSTR,直接转换成非常量指针(LPTSTR-[const] char*)是错误的。正确的得到一个指向缓冲区的非常量指针的方法是调用GetBuffer()方法。

应用程序里有两个对话框A和B,B是A的非模态子对话框,当A中满足特定条件(比如按下某一按钮)时,弹出对话框B,那么在B的实现类中需要使用A中定义的一些数据。以下是写的代码,A中完成对数据库的查询,B中将查询到的数据进行显示。

123456789101112131415while(!con.pRst->adoEOF) { CString strRst = (_bstr_t)con.pRst->GetCollect("GZFS"); //给子对话框发送消息用于显示查询结果 pShowRst->SendMessageW(WM_MY_UPDATE,(WPARAM)strRst.GetBuffer(0), 0); strRst.ReleaseBuffer(); con.pRst->MoveNext(); }

firecat注:

本人在项目实践中,采取PostMessage发送CString,后来发现很多重复的数据,一开始误认为是MFC的bug,PostMessage多发了几次,其实不是的,是因为CString覆盖了前面消息的CString,导致listctrl控件栏显示的数据出现重复的现象。