微软MFC技术中的消息循环

这篇具有很好参考价值的文章主要介绍了微软MFC技术中的消息循环。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

微软MFC技术中的消息循环,Visual Studio技术,microsoft,mfc,c++,windows,开发语言

 我是荔园微风,作为一名在IT界整整25年的老兵,今天来聊聊微软MFC技术中的消息循环。

在很多windows程序中,都有如下代码:

//Win32应用程序入口函数WinMain()
int WINAPI WinMain(
  HINSTANCE hInstance,      //指向当前实例的句柄
  HINSTANCE hPrevInstance,      //指向先前实例的句柄
  LPSTR lpCmdLine,      //命令行
  int nCmdShow         //显示状态
)
{
  WNDCLASS wndclass;      //创建一个窗口类 
  wndclass. cbClsExtra=0;     //窗口类无扩展
  wndclass. cbWndExtra=0;    //窗口实例无扩展
  wndclass. hbrBackground=(HBRUSH)GetStockObject (BLACK_BRUSH);  //窗口背景为黑
  wndclass.hCursor=LoadCursor(NULL,IDC_ARROW);    //窗口采用箭头光标
   wndclass. hIcon=LoadIcon(NULL, IDI_APPLICATION);  //窗口的最小化图标为缺省
  wndclass. hInstance=hInstance:  //当前实例句柄
  wndclass. lpfnWndProc=WinHouProc    //定义窗口处理函数
  wndclass.lpszClassName="VC++";      //窗口类为“VC++”
  wndclass.lpszMenuName=NULL;        //窗口无菜单
  wndclass.style=CS_HREDRAW|CS_PARENTDC;          //设置窗口类型
  RegisterClass(&wndclass);        //注册窗口类
 
  HWND hwnd;
  hwnd=CreateWindow("VC++","消息机制",WS_OVERLAPPEDWINDOW,0,0, 600, 400, NULL, NULL, hInstance, NULL);       //创建窗口
 
  ShowWindow(hwnd, SW_SHOWNORMAL);         //显示窗口
  UpdateWindow(hwnd);                 //更新窗口
 
  MSG msg;
  while(GetMessage 6msg, NULL,0,0))       //获取消息
  {
      TranslateMessage (&msg);
      DispatchMessage (&msg);
   }
  return 0;
}

在上面代码的第30行中,提到了循环。只有消息不断地被循环。才会实时得到窗口的当前状态。否则按照程序的顺序执行结构,此窗口只会闪下就被关闭,根本不会等待用户输入的任何命令。因此消息循环非常必要,即使窗口不会闪一下就关,它的状态也一直是初始状态,因为没有消息的循环,窗口的当前状态没法被线程捕获。首先从设置断点、函数传递角度来看下MFC程序启动时是如何进入消息循环。

下面就分两种情况介绍消息循环机制。

非对话框程序的消息循环机制

打开我之前帖子中所建的单文档 MFC程序,名字为Message。在源文件 Message.cpp中找到下面这一行代码,并在此处设置断点。

CMessageApp theApp;

按F11键单步执行后,会发现非对话框程序的运行点进入函数顺序为如下。

第一步  CMessageApp theApp;

第二步  _tWinMain()

第三步  Afx WinMain

第四步  CMessageApp::Initlnstance()

第五步  CWinThread::Run()    而非对话框程序的消息循环是从 CWinThread::Run()开始。来看下 MFC自带的thrdcore.cpp源文件中包含 CWinThread::Run()函数的部分代码如下。

MFC自带程序 CWinThread::Run()函数示例:thrdcore.cpp

int CWinThread::Run ()
{
  ASSERT_VALID(this)

   BOOL bIdle=TRUE;    //空闲状态标志量
  LONG lIdleCount=0;

  for (;;)  //无限循环,一直获取和发送消息,直到接收到WM_QUIT消息
   {
      //阶段1:检查看是否可以做空闲工作
      while (bIdle && !::PeekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE))
       {
         //如果空闲则呼叫OnIdle()函数
        if (!OnIdle(lIdleCount++))
            bIdle=FALSE;
       }
       //阶段2:启动消息处理
      do
       {
         //当接收WM_QUIT,则退出
         if (!PumpMessage())
             return ExitInstance();

         //当获取"正常"消息时,重新设置空闲状态量
        if (IsIdleMessage(&m_msgCur))
         {
             bIdle=TRUE;
              lIdleCount=0;
           }
       }while ( ::PeekMessage (&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE));
  }
  ASSERT (FALSE);
}

大家可以从自己VC++平台安装路径下找到thrdcore.cpp源文件。如“C:\ProgramFiles\Microsoft Visual Studio\VC98\MFC\SRC"

在上面代码中,第8行表示这是一个无限循环,程序会一直处于获取和发送消息的处理状态中,除非接收到WM_QUIT消息。如第22行所示。for循环中有两个阶段,下面就这两个阶段进行分析。这2个阶段是顺序执行的,总是先执行阶段1后阶段2。

(1)阶段1的while循环是判断当前线程是否空闲并且消息队列中是否有消息需要处理,如果线程当前空闲且无消息可处理,则处于空闲状态,并一直判断;否则直接进入阶段2,进行消息处理。

(2)阶段2是判断是否收到消息,如果获取消息,继续执行;否则,退出循环。而此do-while 循环中首先判断 PumpMessage()的返回值,如果获取到 WM_QUIT消息,退出程序,否则向下执行,当设置断点调试一个非对话框程序时,单步执行第22行时,会进入PumpMessage()函数体中。如下所示:

BOOL CWinThread::PumpMessage()
{
  return AfxInternalPumpMessage ();
  //此函数内容相当于老版本的PumpMessage()内容
}

单步执行到此函数体时,再按F5键继续运行程序,运行点会一直停留在此处。因此,非对话框的消息机制就是在一个无限循环中不断从消息队列中获取消息、窗口消息被发送到相应的窗口处理过程。

对话框程序的消息循环机制

同上面所讲,打开名为MFC_Message的基于对话框程序。在源文件MFC_Message.cpp中找到下面这一行代码,并在此处设置断点。

CMFC_MessageApp theApp;

单步调试该程序后,会发现对话框程序的运行点进入函数顺序与非对话框程序的不同。非对话框程序的消息循环是从CWinThread::Run()开始,而对话框程序根本不会进入CWinThread::Run()函数。因此对话框程序的运行点进入函数顺序如下。

第一步  CMFC_MessageApp    theApp;

第二步  CMFC_MessageApp:: InitInstance()

第三步  CMFC_MessageDlg dlg;

第四步  dlg.DoModal()

因为它们的应用程序对象的InitInstance()不一样。可以通过下面两段代码进行比较。

非对话框MFC程序InitInstance()函数示例:Message.cpp

BOOL CMessageApp::InitInstance()
{
  ......
  CSingleDocTemplate* pDocTemplate;     //定义一个单文档模板
  pDocTemplate=new CSingleDocTemplate(  //定义模板的各种属性
    IDR_MAINFRAME,     //菜单
     RUNTIME_CLASS (CMessageDoc),  //文档类
    RUNTIME_CLASS(CMainFrame),  //框架类
     RUNTIME_CLASS(CMessageView));  //视图类

  if( !pDocTemplate)
      return FALSE;  //如果创建不成功返回FALSE
  AddDocTemplate (pDocTemplate);      //将此模板对象加入模板中
 
  CCommandLineInfo cmdInfo;
  ParseCommandLine(cmdInfo);
 
  if ( !ProcessShellCommand (cmdInfo))
  return FALSE;      //程序启动时创建新文档失败返回FALSE
 
   m_pMainWnd->Showwindow (SW_SHOW);  //显示窗口
  m_pMainWnd->Updatewindow ();     //更新窗口
  return TRUE:
}

对话框MFC程序 Initinstance()函数例: MFC_Message.cpp

BOOL CMFC_MessageApp::InitInstance()
{
   ......
  CMEC_MessageDlg dlg;  //声明一个对话框类对象
  m_pMainWnd =&dlg;  //将其指针赋给窗口类对象
  INT_PTR nResponse =dlg.DoModal     //延模对话框,消息循环在这里开始
   ......
 
  return FALSE;
}


非对话框MFC程序InitInstance()函数示例代码中,执行完CMessageApp::InitInstance()函数,其第22行为返回正确;而对话框MFC程序InitInstance()函数示例代码执行完CMFC_MessageApp::InitInstance()函数,其第10行为返回错误。同时,设置断点进行单步调试,会发现对话框程序的消息循环发生在DoModal()函数里,如对话框MFC程序InitInstance()函数示例代码的第07行所示。而此函数中有一个RunModalLoop()函数用于消息循环。

总结

前面分别讲解了非对话框和对话框程序的消息循环,接下来总结一下消息循环是什么。下面分2个方面来对对话框和非对话MF程序进行对比分析:

(一)发生消息循环的函数位置。

非对话框MFC程序的消息循环发生在CWinThread::Run()中,而对话框MFC程序的消息循环则发生在DoModal()中。

(二)接收消息的对象。

非对话框MFC程序的消息是与窗口交换的,而对话框MFC程序的消息则是与对话框进行交互的。

提示:因为对话框不是严格意义上的窗口,所以对话框MFC程序运行时不会进入_tWinMain()函数。

作者简介:荔园微风,1981年生,高级工程师,浙大工学硕士,软件工程项目主管,做过程序员、软件设计师、系统架构师,早期的Windows程序员,Visual Studio忠实用户,C/C++使用者,是一位在计算机界学习、拼搏、奋斗了25年的老将,经历了UNIX时代、桌面WIN32时代、Web应用时代、云计算时代、手机安卓时代、大数据时代、ICT时代、AI深度学习时代、智能机器时代,我不知道未来还会有什么时代,只记得这一路走来,充满着艰辛与收获,愿同大家一起走下去,充满希望的走下去。文章来源地址https://www.toymoban.com/news/detail-549040.html

到了这里,关于微软MFC技术中的消息循环的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Visual Studio中C++部分的官方文档链接【微软(Microsoft)所有产品的官方文档链接】

    目前(2022年07月),微软官方网站上关于Visual Studio的文档,最老的版本也是VS2015了,如下图所示: 微软所有产品的文档目录: 中文版:https://docs.microsoft.com/zh-CN/documentation/ 英文版:https://docs.microsoft.com/en-us/documentation/ Visual Studio中C++部分的官方文档: 中文版:https://docs.microso

    2024年02月07日
    浏览(54)
  • Visual Studio 2022的MFC框架——theApp全局对象

      我是荔园微风,作为一名在IT界整整25年的老兵,今天我们来重新审视一下Visual Studio 2022下开发工具的MFC框架知识。  MFC中的WinMain函数是如何与MFC程序中的各个类组织在一起的呢?MFC程序中的类是如何与WinMain函数关联起来的呢? 面对这个问题,我们来分析一下。 双击我在

    2024年02月11日
    浏览(19)
  • 微软MFC技术简明介绍

    我是荔园微风,作为一名在IT界整整25年的老兵,今天来看一下微软MFC技术简明介绍 微软公司于1992年上半年推出了C/C++ 7.0 产品时初次向世人介绍了MFC 1.0,这个产品包含了20,000行C++原始代码,60个以上的Windows相关类,以及其它的一般类如时间、数据处理、文件、内存、诊断、

    2024年02月11日
    浏览(30)
  • 微软MFC技术运行机制

    我是荔园微风,作为一名在IT界整整25年的老兵,今天总结一下微软MFC技术运行机制。 很多初学者误以为VC++开发必须使用MFC,其实不一定的。MFC的使用只能是提高程序在某些情况下的开发效率,而不能替代整个Win32程序设计。我认为我们有必要再来好好讲讲MFC的本质、MFC中的

    2024年02月08日
    浏览(32)
  • Microsoft Visual Studio 和 Visual Studio Code区别

    都是 Microsoft 的产品。 Microsoft Visual Studio(简称VS)是一款 开发工具 ,可以系统的开发软件。类似Java开发工具IDEA。 Visual Studio Code 是一款 代码编辑器 ,不能单独的用来软件的开发。比普通的编辑器(类似notepad++)功能多 VS VSCode 概述 开发工具 代码编辑器 平台 只能在 windo

    2024年02月05日
    浏览(35)
  • 找不到mfc140u.dll或者Microsoft Visual C++ 2017 Redistributable一直安装失败解决

    安装后提示这个问题,我将xshell卸载重新安装后发现安装过程中提示Microsoft Visual C++ 2017 Redistributable一直安装失败,所以问题出在Microsoft Visual C++ 2017 Redistributable上 首先查看日志文件 说明有更高的版本 控制面板–》卸载程序 发现比自己版本高的,卸载掉 下载Microsoft Visual C

    2024年02月12日
    浏览(36)
  • Visual Studio 2022的MFC框架——AfxWinMain全局对象和InitInstance函数

    我是荔园微风,作为一名在IT界整整25年的老兵,今天我们来重新审视一下Visual Studio 2022下开发工具的MFC框架知识。  在看这篇帖子前,请先看我的另一篇帖子《Visual Studio 2022的MFC框架——应用程序向导》。 当程序调用了CWinApp类的构造函数,并执行了CMfcApp类的构造函数,且产

    2024年02月10日
    浏览(22)
  • Microsoft Message Queue(MSMQ:微软消息队列)简介

    最近在安装公司的一个产品时,接触到了MSMQ,在此对MSMQ做一个简单的介绍,以便各位能对它有一个快速、直观的认识。本文针对于Microsoft Message Queue,以下提到的消息队列均指代Microsoft Message Queue。 2.1、消息队列是什么 MSMQ是一个Windows上的功能。主要用于多个应用之间实现相

    2024年02月09日
    浏览(43)
  • Microsoft微软官方Win10 visual c++(vc++2019)运行库下载

    最新支持Visual C++ 可再发行程序包下载 | Microsoft Docs 本文列出了最新版本的包的下载Visual C++ 可再发行程序包链接。 https://support.microsoft.com/zh-cn/help/2977003/the-latest-supported-visual-c-downloads 安装后可以解决某些软件(如QQ)运行时 .dll 文件报错问题

    2024年02月16日
    浏览(46)
  • Microsoft Visual Studio—常用快捷键

    1 Ctrl+W,W: 浏览器窗口 2 Ctrl+W,S: 解决方案管理器 (Solution) 3 Ctrl+W,C: 类视图 (Class) 4 Ctrl+W,E: 错误列表 (Error) 5 Ctrl+W,O: 输出窗口(Output) 6 Ctrl+W,P: 属性窗口 (Property) 7 Ctrl+W,T: 任务列表 (Task) 8 Ctrl+W,X: 工具箱 (Tool,t已被任务列表占用) 9 Ctrl+W,B: 书签窗口 (Bookmark,方便

    2024年02月06日
    浏览(49)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包