MFC子线程访问/控制对话框程序控件

  MFC窗口程序,如果不把具体的流程在子线程中运行,碰到Sleep()函数时程序窗口就会呈现一种未响应的状
态,不美观,所以一般都会把具体的流程放到一个子线程中去,这样通常情况下就不会出现“未响应”状态了。
但是微软出于安全考虑不允许子线程直接访问窗口程序中的例如按钮、编辑框、静态文本框一类的控件,原因是
这样会容易导致访问异常消息混乱造成程序卡死崩溃,MSDN 中也有说明,子线程直接访问主线程的控件对象是
不安全的。为此,微软也提供了相应的解决方案:
  
  1、通过传递控件句柄 HWND 给子线程,来对控件进行访问;
  
  2、通过消息传送机制,也就是通过在子线程里给主线程传递访问控件对象的消息,然后在主线程的消息响
应函数里面对控件对象进行操作。
  
  以上两步都需要完成才能成功访问主线程上的控件。
  
  下面是具体的操作步骤:
  
  1.创建一个自定义消息
  
  
  在×××Dlg.cpp开头写入

  #define UM_OPENPOWER    WM_USER+100    //自定义一个消息

  因为消息有很多,为了不与系统定义的消息冲突所以定义到100以后。
  
  然后在×××Dlg.cpp文件里的默认BEGIN_MESSAGE_MAP消息映射函数中加上我们自定义的消息:

  ON_MESSAGE(UM_OPENPOWER,&C×××Dlg::OnOpenPower)

  参数1:消息名称;参数2:消息的回调函数地址
  
  也就是这样:

  BEGIN_MESSAGE_MAP(C×××Dlg, CDialogEx)
  ON_WM_SYSCOMMAND()
  ON_WM_PAINT()
  ON_WM_QUERYDRAGICON()
  ON_BN_CLICKED(IDOK, &C×××Dlg::OnBnClickedOk)
  ON_MESSAGE(UM_OPENPOWER,&C×××Dlg::OnOpenPower)
  END_MESSAGE_MAP()

然后在C×××Dlg类中添加消息回调函数声明:

afx_msg LRESULT OnOpenPower(WPARAM WParam, LPARAM LParam);

函数实现:

  LRESULT C×××Dlg::OnOpenPower(WPARAM WParam, LPARAM LParam)
  {
  
  BSTR b = (BSTR)WParam;  //把WParam转换成BSTR类型
  CString s(b);  //把BSTR转换成CString类型
  SysFreeString(b);
  
  GetDlgItem(IDC_EDIT1)->SetWindowTextW(s); //编辑框控件内容
  
  return 1;
  
  }
  

  2.重载WindowProc虚函数
  
  
  我们调用上面的回调函数给主线程发送消息后就完事了,需要等待系统调用WindowProc()函数处理我们的消
息,所以可能会出现消息无法及时处理的情况,我们可以重载一下WindowProc()函数:
  
  

  LRESULT C×××Dlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
  {
  // TODO: 在此添加专用代码和/或调用基类
  
  
  if(message==UM_OPENPOWER) //先处理我们的消息,如果没有就走默认流程
  {
  
  OnOpenPower(wParam,lParam);
  return 1;
  
  }
  else
  {
  return CDialogEx::WindowProc(message, wParam, lParam);
  }
  
  
  }

  这一步不是必要的,如果程序复杂程度比较低,基本上还是会实时处理我们的自定义消息的。
  
  
  
  3.把消息发送封装成一个函数,方便我们在程序的任何位置调用

        为了方便我们在程序任何位置发送消息访问/控制控件,就需要先获取窗口的对象指针。

C×××Dlg *cums;  //建立一个对象指针

       然后我们在OnInitDialog()函数中获取主窗口对象指针:

  cums=(C×××Dlg*)AfxGetMainWnd(); //获取程序主窗口对象指针
  
  
  
  void C×××Dlg::hungry()//测试函数
  {
  
  
  C×××Dlg* pDlg = cums; //主窗口对象指针
  
  CString diffe=L"春哥纯爷们!";
  
  //将要执行的命令发送出去
  ::PostMessageW(pDlg -> m_hWnd, UM_OPENPOWER, (WPARAM)diffe.AllocSysString(), (LPARAM)

(LPCTSTR)_T("Put on power...") );
  
  
  }

  PostMessageW()函数的参数3、参数4可以向回调函数传递我们自定义的内容,在这里可以把需要显示到控件
上的字符串添加到参数中。
  
  
  然后在子线程回调函数的任何位置调用void C×××Dlg::hungry()函数,都可以向编辑框控件发送字符串
了。
  
  另外,需要注意在子线程的入口函数里进行消息传送时,使用的是 PostMessageW()函数,而不是
SendMessage() 函数,这里说明一下,这里需要用到的就是PostMessageW()函数,要是用SendMessage()函数的
话,会发生阻塞的现象。这两个函数的主要区别就是,前者将消息发送出去后就会立即返回,后者需要等相应的
消息映射函数处理完成后才能返回,所以会一直阻塞在那个地方。具体说明还请读者自己百度或 MSDN 一下。
  
  
  
  示例工程:https://download.csdn.net/download/l198738655/10821760
  参考文献:https://blog.csdn.net/xbmoxia/article/details/16981243

猜你喜欢

转载自blog.csdn.net/l198738655/article/details/84678111
今日推荐