奇趣技术网 收藏本站
设为主页
商务合作
首页 新闻中心 行业动态 软件新闻 安全资讯 病毒预警 漏洞发布 操作系统 Dos Win9x Win2000 WinXP Win2003 WinVista Linux Unix
数据库 DB2 Access MSSQL MySQL Oracle Sybase 编程技术 ASP PHP JSP CGI/Perl XML .Net C/C++/C# VB VC Delphi Java 汇编
安全技术 安全教学 工具介绍 漏洞利用 病毒防范 入侵检测 防火墙 安全防范 汉化破解 攻击实例 加密解密 技术论坛
中华网络安全联盟 >> 程序开发 >> VC >> Visual C++模态对话框消息处理机制的分析
程序开发
Asp
PHP
JSP
CGI/Perl
XML
.Net
C/C++/C#
Visual Basic
Visual C++
Delphi
Java
汇编语言
  • VC中利用多线程技术实

  • 利用OpenGL实现三维绘

  • 基于Visual C++的Wins

  • 基于Visual C++6.0的D

  • Visual C++ MFC 中常用

  • 在MFC下如何定义全局变

  • 使用MFC在应用程序中嵌

  • VC++中进程与多进程管

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

    中华网络安全联盟    作者:佚名    来源:网络转载    时间:2006-3-22

        摘要:消息驱动机制是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编程是很有必要的。

    字体:
     
    设为主页 收藏本站 联系我们 友情连接 商务合作 网友留言
    Copyright©2006-2008 中华网络安全联盟 All rights reserved.