`
happmaoo
  • 浏览: 4333391 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

Visual C++模态对话框消息处理机制的分析

阅读更多
摘要:消息驱动机制是Windows操作系统的根本,模态对话框消息处理又是不同于一般消息处理的特殊形式。通过分析这种消息机制的原理,可用来处理类似的程序设计要求。

  在Windows操作系统中,面向用户的GUI基本上可分为对话框形式和文档/视图两种表现形式。对话框的显示方式又可分为模态对话框和非模态对话框,以适应不同的用户交互需求。由于对话框和文档/视图框架结构各有特色,能不能将文档/视图框架结构当作一对话框来使用,或在对话框中实现文档/视图框架结构内的特色功能呢,答案是肯定的。

  下面,从Windows 操作系统消息驱动机制开始,进而探讨模态对话框实现过程的消息封装、传递和处理机制,最后以模态的形式显示应用到文档/视图框架结构中的实例作为对所讲内容的验证和实践。

  一、Windows消息机制

  Windows是一种面向对象的体系结构,Windows环境和应用程序都是通过消息来交互的。Windows应用程序开始执行后,Windows为该程序创建一个"消息队列(message queue)",用以存放邮寄给该程序可能创建的各种不同窗口的消息。消息队列中消息的结构(MSG)为:

typedef struct tagMSG{
 HWND hwnd;
 UINT message;
 WPARAM wParam;
 LPARAM lParam;
 DWORD time;
 POINT pt;
}MSG;

  其中第一个成员变量是用来标识接收消息的窗口句柄;第二个参数便是消息标识号,如WM_PAINT;第三个和第四个参数的具体意义同message值有关,均为消息参数。前四个参数是非常重要和经常用到的,至于后两个参数则分别表示邮寄消息的时间和光标位置(屏幕坐标)。把消息传送到应用程序有两种方法:一种是由系统将消息"邮寄(post)"到应用程序的"消息队列"这是"进队消息"Win32 API有对应的函数: PostMessage(),此函数不等待该消息处理完就返回;而另一种则是由系统在直接调用窗口函数时将消息"发送(send)"给应用程序的窗口函数,属于"不进队消息"对应的函数是SendMessage()其必须等待该消息处理完后方可返回。

  对于每一个正在执行的Windows应用程序,系统为其建立一个"消息队列",即应用程序队列,用来存放该程序可能创建的各种窗口的消息。应用程序中含有一段称作"消息循环"的代码,用来从消息队列中检索这些消息并把它们分发到相应的窗口函数中。

  消息循环代码是应用程序中主函数winmain ( )中类似如下的程序段:

  while(GetMessage(&&msg,NULL,NULL,NULL))
  { file://从消息队列中取得消息
   TranslateMessage(&&msg);
   file://检索并生成字符消息WM_CHAR
   DispatchMessage(&&msg);
   file://将消息发送给相应的窗口函数
   }

  由此可见,所谓"消息循环",实际是程序循环。

  Windows 应用程序创建的每个窗口都在系统核心注册一个相应的窗口函数,窗口函数程序代码形式上是一个巨大的switch 语句,用以处理由消息循环发送到该窗口的消息,窗口函数由Windows 采用消息驱动的形式直接调用,而不是由应用程序显示调用的,窗口函数处理完消息后又将控制权返回给Windows。
二、模态对话框的消息处理

  由上面我们看到,Windows是一个巨大的消息驱动结构,由用户发出消息,系统响应处理。非模态对话框是响应一个消息,系统处理一个消息,处理完毕后返回控制权给Windows。文档/视图框架结构与其类似。模态对话框在对话框创建后,挂起外部的消息,只是响应对话框内部的消息,而外部消息则全部"过滤"掉了,直到系统接收到WM_DESTROY或WM_CLOSE后,系统返回控制权给模态对话框创建前的线程,继续模态对话框创建前的线程将执行下面的代码。

  让我们看看下面的对话框DoModal实现代码:

{
 … …
 // Disable 父窗口 (在创建对话框前)
 HWND hWndParent = PreModal();
 AfxUnhookWindowCreate();
 BOOL bEnableParent = FALSE;
 if (hWndParent != NULL && ::IsWindowEnabled(hWndParent))
 {
  ::EnableWindow(hWndParent, FALSE);
  bEnableParent = TRUE;
 }
 TRY
 {
  // 创建模态对话框
  AfxHookWindowCreate(this);
  if (CreateDlgIndirect(lpDialogTemplate,CWnd::FromHandle(hWndParent), hInst))
  {
   if (m_nFlags & WF_CONTINUEMODAL)
   {
    // 进入模式循环
    DWORD dwFlags = MLF_SHOWONIDLE;
    if (GetStyle() & DS_NOIDLEMSG) dwFlags |= MLF_NOIDLEMSG;
      VERIFY(RunModalLoop(dwFlags) == m_nModalResult);
   }
  }
 }
 CATCH_ALL(e)
 {
  DELETE_EXCEPTION(e);
  m_nModalResult = -1;
 }
 END_CATCH_ALL
 file://Enable 父窗口
 if (bEnableParent)
  ::EnableWindow(hWndParent, TRUE);
  if (hWndParent != NULL && ::GetActiveWindow() == m_hWnd)
   ::SetActiveWindow(hWndParent);
   // 删除对话框
   DestroyWindow();
   PostModal();
   … …
 }

  可以看到,在此实现代码中,并没有开辟新的线程。系统是在RunModalLoop()中进行消息循环。当 m_nFlags 为 WF_CONTINUEMODAL时,系统继续模式状态。RunModalLoop()函数实际上也是一for(;;)循环,控制重新分派Windows消息。直到ContinueModal()返回FALSE,而当调用EndModalLoop()时,ContinueModal()返回FALSE。此时,标志着模态显示的结束。因此,实现模态对话框消息处理的核心部分为RunModalLoop()和EndModalLoop()函数。

  三、以模态的形式显示应用到文档/视图框架结构实例

  (1)新建一工程文件:ModeFrame,选取MFC AppWizard(exe)。

  (2)第二步选取Single document(单文档)。

  (3)其余几步均为缺省值。

  (4)用ClassWizard添加一新类CSubModeFrame,以CFrameWnd为基类。

  (5)添加CsubModeFrame的实现函数DoMode();

int CsubModeFrame::DoModal()
{
 HWND hWndParent = m_hWndPrt;
 CRect rc(0,0,400,400);
 CWnd *pParent = CWnd::FromHandle(hWndParent);
 DWORD dwStyle=WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_THICKFRAME |  WS_VISIBLE | WS_SYSMENU | WS_CAPTION;
 if(!Create(NULL,"模态文档/试图框架 ",dwStyle,rc,pParent,NULL)) return FALSE;
  BOOL bEnableParent = FALSE;
  if (hWndParent != NULL && ::IsWindowEnabled(hWndParent))
  {
   ::EnableWindow(hWndParent,FALSE);
   ::EnableWindow(m_hWnd,TRUE);
   bEnableParent = TRUE;
  }
  CenterWindow();
  TRY
  {
   // enter modal loop
   DWORD dwFlags = MLF_SHOWONIDLE;
   if (GetStyle() & DS_NOIDLEMSG) dwFlags |= MLF_NOIDLEMSG;
    VERIFY(RunModalLoop(dwFlags) == m_nModalResult);
  }
  CATCH_ALL(e)
  {
   DELETE_EXCEPTION(e);
   m_nModalResult = -1;
  }
  END_CATCH_ALL
 
 if (bEnableParent)
  ::EnableWindow(hWndParent, TRUE);
  if (hWndParent != NULL && ::GetActiveWindow() == m_hWnd)
   ::SetActiveWindow(hWndParent);
   // destroy modal window
   DestroyWindow();
   return m_nModalResult;
 }

  (6)添加CsubModeFrame的实现函数EndMode()

void CSubFrame::EndModal(){
 ASSERT(::IsWindow(m_hWnd));
 if (m_nFlags & (WF_MODALLOOP|WF_CONTINUEMODAL)) {
  EndModalLoop(1);
 }
}

  (7)添加CModeFrameView的实现函数OnLButtonDblClk()

  在此函数的消息处理中:可以象显示对话框一样处理CsubModeFrame类。

CSubModeFrame SubModeFrame;
If(SubModeFrame.DoMode()){ MessageBox("Mode Ok");}

  (8)编译运行工程,双击视图,就会弹出模态的子文档/视图框架结构

  结论: 通过上面的分析和实例可以看出,深入研究了解Windows的消息处理机制,可利用消息对Windows的事件进行任意的定制和处理,不用拘泥于系统原有的模式。对进行深入Windows编程是很有必要的。
分享到:
评论

相关推荐

    Visual C++ 开发技术 通用对话框编程 文件打开对话框例程

    Visual C++ 开发技术 通用对话框编程 文件打开对话框例程,例程来自《Visual C++ 开发技术大全》,全部打包下载可点击http://download.csdn.net/detail/zhou625315237/5103878

    MFC按钮触发模态对话框窗口和非模态对话框窗口

    MFC开发的窗口程序,实现了模态model dialog window和非模态窗口modelles dialog window的创建,可以下载下来,做逆向分析用。 详细的IDA和X64dbg分析见这篇文章: ...代码是基于Visual Studio 2022版本的,配图详细,...

    visual c++创建无模式对话框

    vc创建非模态对话框

    Visual C++从初学到精通 吕兵 高清PDF带书签

    《Visual C++从初学到精通》涵盖内容:控制台应用程序、基于对话框的应用程序、单文档应用程序、多文档应用程序、异常处理机制、 Windows应用程序运行机;WinMain()函数、MFC消息映射机制、API文件操作、MFC文件...

    VC++ 对话框的使用

    对话框分为两类,一是模态对话框,二是非模态对话框;另外还可以直接建立基于对话框的应用程序。 Visual C++6.0提供的对话框编辑器能“可视”地进行设计、编辑对话框,并可用ClassWizard为对话框从CDialog基类中派生...

    Visual C++2010开发权威指南(共三部分).part1.rar

    7.5.2 鼠标的消息处理机制 373 7.5.3 示例 374 7.6 创建启动界面 376 7.7 创建特效窗口启动应用程序 378 7.8 创建特效窗口关闭应用程序 378 7.9 小结 383 第8章 Visual C++ 2010 MFC文本与字体 384 8.1 CFont字体类...

    《Visual C++范例大全》随书光盘 第六章

    实例116——创建模态对话框 实例117——创建非模态对话框 实例118——模态对话框与应用程序之间的数据交换 实例119——非模态对话框与应用程序之间的数据交换 实例120——使用MessageBox消息对话框 实例121...

    Visual C++2010开发权威指南.part02

    4.2.1 模态对话框 153 4.2.2 非模式对话框 159 4.2.3 属性页对话框 163 4.3 消息对话框 173 4.4 通用对话框 175 4.4.1 文件打开对话框 176 4.4.2 文件保存对话框 178 4.4.3 颜色对话框 179 4.4.4 字体对话框 181 ...

    Visual C++从初学到精通 吕兵 源代码+电子教案

    《Visual C++从初学到精通》涵盖内容:控制台应用程序、基于对话框的应用程序、单文档应用程序、多文档应用程序、异常处理机制、 Windows应用程序运行机;WinMain()函数、MFC消息映射机制、API文件操作、MFC文件操作...

    visual c++6.0技术内幕 带有NLC的文件查看器

     第6章 模态对话框和windows通用控件  第7章 非模态对话框和Windows通用对话框  第8章 使用ActiveX控件  第9章 Internet Explorer 4通用控件  第10章 win32内存管理  第11章 位图  第12章 windows消息处理和...

    Visual C++ 2005入门经典.part08.rar (整理并添加所有书签)

    16.4.2 模态和非模态对话框 16.4.3 显示对话框 16.5 支持对话框控件 16.5.1 初始化控件 16.5.2 处理单选按钮消息 16.6 完成对话框的操作 16.6.1 给文档类添加存储线宽的成员 16.6.2 给元素添加线宽 16.6.3 在视图中...

    Visual C++ 2005入门经典.part04.rar (整理并添加所有书签)

    16.4.2 模态和非模态对话框 16.4.3 显示对话框 16.5 支持对话框控件 16.5.1 初始化控件 16.5.2 处理单选按钮消息 16.6 完成对话框的操作 16.6.1 给文档类添加存储线宽的成员 16.6.2 给元素添加线宽 16.6.3 在视图中...

    Visual C++ 2005入门经典.part05.rar (整理并添加所有书签)

    16.4.2 模态和非模态对话框 16.4.3 显示对话框 16.5 支持对话框控件 16.5.1 初始化控件 16.5.2 处理单选按钮消息 16.6 完成对话框的操作 16.6.1 给文档类添加存储线宽的成员 16.6.2 给元素添加线宽 16.6.3 在视图中...

    Microsoft visual c++ 6.0 programmer's Guide 程序员指南

    例2:简单的非模态对话框 例3:向AppWizard程序添加对话 基于对话的应用程序 第三部分 编程帮助工具 第6章 ClassWizard(类向导) 访问ClassWizard ClassWizard对话 WizardBar(向导栏) ClassWizard如何识别类 用...

    模式对话框和通用控件示例程序

    完全按照VisualC++6.0实例精通pdf编写的示例程序,编译通过,但遇到一个很奇怪的问题,当双击鼠标左键时无法弹出对话框?

    Visual c++源代码

    实例2-2:Visual C++语言基本元素介绍。源代码在光盘中“\02\secondcpp”目录下。 实例2-3:cout流控制符setw的使用。源代码在光盘中“\02\thirdcpp”目录下。 实例2-4:增加域内填充字符。源代码在光盘中“\02\...

Global site tag (gtag.js) - Google Analytics