摘要:消息驱动机制是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++ 开发技术大全》,全部打包下载可点击http://download.csdn.net/detail/zhou625315237/5103878
MFC开发的窗口程序,实现了模态model dialog window和非模态窗口modelles dialog window的创建,可以下载下来,做逆向分析用。 详细的IDA和X64dbg分析见这篇文章: ...代码是基于Visual Studio 2022版本的,配图详细,...
vc创建非模态对话框
《Visual C++从初学到精通》涵盖内容:控制台应用程序、基于对话框的应用程序、单文档应用程序、多文档应用程序、异常处理机制、 Windows应用程序运行机;WinMain()函数、MFC消息映射机制、API文件操作、MFC文件...
对话框分为两类,一是模态对话框,二是非模态对话框;另外还可以直接建立基于对话框的应用程序。 Visual C++6.0提供的对话框编辑器能“可视”地进行设计、编辑对话框,并可用ClassWizard为对话框从CDialog基类中派生...
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字体类...
实例116——创建模态对话框 实例117——创建非模态对话框 实例118——模态对话框与应用程序之间的数据交换 实例119——非模态对话框与应用程序之间的数据交换 实例120——使用MessageBox消息对话框 实例121...
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++从初学到精通》涵盖内容:控制台应用程序、基于对话框的应用程序、单文档应用程序、多文档应用程序、异常处理机制、 Windows应用程序运行机;WinMain()函数、MFC消息映射机制、API文件操作、MFC文件操作...
第6章 模态对话框和windows通用控件 第7章 非模态对话框和Windows通用对话框 第8章 使用ActiveX控件 第9章 Internet Explorer 4通用控件 第10章 win32内存管理 第11章 位图 第12章 windows消息处理和...
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 在视图中...
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 在视图中...
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 在视图中...
例2:简单的非模态对话框 例3:向AppWizard程序添加对话 基于对话的应用程序 第三部分 编程帮助工具 第6章 ClassWizard(类向导) 访问ClassWizard ClassWizard对话 WizardBar(向导栏) ClassWizard如何识别类 用...
完全按照VisualC++6.0实例精通pdf编写的示例程序,编译通过,但遇到一个很奇怪的问题,当双击鼠标左键时无法弹出对话框?
实例2-2:Visual C++语言基本元素介绍。源代码在光盘中“\02\secondcpp”目录下。 实例2-3:cout流控制符setw的使用。源代码在光盘中“\02\thirdcpp”目录下。 实例2-4:增加域内填充字符。源代码在光盘中“\02\...