Programming Windows程式开发设计指南 第19章 多重文件介面

19. 多重文件介面 dedecms.com

多重文件介面(MDI)是Microsoft Windows文件处理应用程式的一种规范,该规范描述了视窗结构和允许使用者在单个应用程式中使用多个文件的使用者介面(如文书处理程式中的文字文件和试算表程式中的试算表)。简单地说,就像Windows在一个萤幕上维护多个应用程式视窗一样,MDI应用程式在一个显示区域内维护多个文件视窗。Windows中的第一个MDI应用程式是Windows下的Microsoft Excel的第一个版本。紧接著又出现了许多其他的应用程式。 织梦好,好织梦

MDI概念
 

织梦好,好织梦

尽管MDI规范随著Windows 2.0的推出已经很普及,但在那时,MDI应用程式写起来很困难,并且需要一些非常复杂的程式设计工作。从Windows 3.0起,其中许多工作就都由Windows为您做好了。Windows 95中增强的支援也已经被添加进Windows 98Microsoft Windows NT中。 织梦内容管理系统

MDI的组成
  内容来自dedecms

MDI程式的主应用程式视窗是很普通的:它有一个标题列、一个功能表、一个缩放边框、一个系统功能表图示和最大化/最小化/关闭按钮。显示区域经常被称为「工作空间」,它不直接用於显示程式输出。这个工作空间包括零个或多个子视窗,每个视窗都显示一个文件。 dedecms.com

这些子视窗看起来与通常的应用程式视窗以及MDI程式的主视窗很相似。它们有一个标题列、一个缩放边框、一个系统功能表图示和最大化/最小化/关闭按钮,可能还包括卷动列。但是文件视窗没有功能表,主应用程式视窗上的功能表适用於文件视窗。

织梦好,好织梦

在任何时候都只能有一个文件视窗是活动的(加亮标题列来表示),它出现在其他所有文件视窗之前。所有文件视窗都由工作空间区域加以剪裁,而不会出现在应用程式视窗之外。 织梦内容管理系统

初看起来,对Windows程式写作者来说,MDI似乎是相当简单。需要程式写作者做的工作好像就是为每个文件建立一个WS_CHILD视窗,并使程式的主应用程式视窗成为文件视窗的父视窗。但对现有的MDI应用程式稍加研究,就会发现一些导致程式写作困难的复杂问题。例如: 织梦内容管理系统

  • MDI文件视窗可以最小化。它的图示出现在工作空间的底部。一般来说,MDI应用程式可以将不同的图示分别用於主应用程式视窗和每一类文件应用。
     
  • MDI文件视窗可以最大化。在这种情况下,文件视窗的标题列(一般用来显示视窗中文件的档案名称)消失,档案名称出现在应用程式视窗标题列的应用程式名称之後,文件视窗的系统功能表图示成为应用程式视窗的顶层功能表中的第一项。关闭文件视窗按钮变成顶层功能表中的最後一项,且出现在最右边。
     
  • 用以关闭文件视窗的系统键盘加速键与关闭主视窗的系统键盘加速键一样,只是Ctrl键代替了Alt键。这也就是说,Alt+F4用於关闭应用程式视窗,而Ctrl+F4用於关闭文件视窗。此外,Ctrl+F6可以在活动MDI应用程式的子文件视窗之间切换。与平时一样,Alt+空白键启动主视窗的系统功能表,Alt+-(减号)启动活动子文件视窗的系统功能表。
     
  • 当使用游标键在功能表项间移动时,控制项权通常从系统功能表转到功能表列中的第一项。在MDI应用程式中,控制项权是从应用程式系统功能表转到活动文件系统功能表,然後再转到功能表列中的第一项。 织梦内容管理系统
     
  • 如果应用程式能够支援若干种型态的子视窗(如Microsoft Excel中的工作表和图表文件),那么功能表应能反映出与这种型态的文件有关的操作。这就要求当不同的文字视窗变成活动视窗时,程式能更换功能表。此外,当没有文件视窗存在时,功能表应该被缩减到只剩下与打开新文件有关的操作。
     
  • 顶层功能表上有一个叫做「视窗(Window)」的功能表项。按照习惯,这是顶层功能表上「Help」之前的那一项,即倒数第二项。「视窗」子功能表上通常包含在工作空间内安排文件视窗的选项。文件视窗可以从左上方开始「平铺」或「层叠」。在前一种方式下,可以完整地看到每一个文件视窗。这个子功能表同时也包含所有文件视窗的列表。从中选择一个文件视窗,就可以把此文件视窗移到前景。
     

Windows 98支援MDI的所有这些方面。当然,需要您做一些工作(如下面的范例程式所示),但是,这远不是要您程式写作来直接支援所有这些功能。 本文来自织梦

MDI支援
 

内容来自dedecms

探讨WindowsMDI支援时需要发表一些新术语。主应用程式视窗称为「框架视窗」,就像传统的Windows程式一样,它是WS_OVERLAPPEDWINDOW样式的视窗。

dedecms.com

MDI应用程式还根据预先定义的视窗类别MDICLIENT建立「客户视窗」,这一客户视窗是用这种视窗类别和WS_CHILD样式呼叫CreateWindow来建立的。这一呼叫的最後一个参数是指向一个CLIENTCREATESTRUCT型态的结构的指标。这个客户视窗覆盖框架视窗的显示区域,并提供许多MDI支援。此客户视窗的颜色是系统颜色COLOR_APPWORKSPACEcopyright dedecms

文件视窗被称为「子视窗」。通过初始化一个MDICREATESTRUCT型态的结构,以一个指向此结构的指标为参数将讯息WM_MDICREATE发送给客户视窗,就可以建立这些文件视窗。 织梦好,好织梦

文件视窗是客户视窗的子视窗,而客户视窗又是框架视窗的子视窗。父-子视窗分层结构如图19-1所示。 本文来自织梦


  织梦好,好织梦

copyright dedecms

 

内容来自dedecms

19-1 Windows MDI应用程式的父-子层次图

dedecms.com

 

您需要框架视窗的视窗类别(及视窗讯息处理程式)和一个由应用程式支援的每类子视窗的视窗类别(及视窗讯息处理程式)。由於已经预先注册了视窗类别,所以不需要客户视窗的视窗讯息处理程式。 copyright dedecms

Windows 98MDI支援包括一个视窗类别、五个函式、两个资料结构和12个讯息。前面已经提到了MDI视窗类别,即MDICLIENT,以及资料结构CLIENTCREATESTRUCTMDICREATESTRUCT。在MDI应用程式中,这五个函式中的两个用於取代DefWindowProc:不再将DefWindowProc呼叫用於所有未处理的讯息,而是由框架视窗程序呼叫DefFrameProc,子视窗程序呼叫DefMDIChildProc。另一个MDI特有的函式TranslateMDISysAccel与第十章中讨论的TranslateAccelerator的使用方式相同。MDI支援也包括ArrangeIconicWindows函式,但有一条专用的MDI讯息使得此函式对MDI程式来说不再必要。 内容来自dedecms

第五个MDI函式是CreateMDIWindow,它使得子视窗可以在单独的执行绪中被建立。这个函式不需要在单执行绪的程式中,我会展示这一点。 织梦内容管理系统

在下面的程式中,我将展示12MDI讯息中的9条(其他三个讯息一般不用),这些讯息的字首是WM_MDI。框架视窗向客户视窗发送其中某个讯息,以便在子视窗上完成一项操作或者取得关於子视窗的资讯(例如,框架视窗发送一个WM_MDICREATE讯息给客户视窗,以建立子视窗)。讯息WM_MDIACTIVATE讯息有点特别:框架视窗可以发送这个讯息给客户视窗来启动一个子视窗,而客户视窗也把这个讯息发送给将被启动或者失去活动的子视窗,以便通知它们这一变化。 内容来自dedecms

MDI的范例程式
  dedecms.com

程式19-1 MDIDEMO程式说明了编写MDI应用程式的基本方法。

内容来自dedecms

 程式19-1  MDIDEMO 

织梦好,好织梦

MDIDEMO.C 
copyright dedecms
/*--------------------------------------------------------------------------- 

织梦好,好织梦

        MDIDEMO.C -- Multiple-Document Interface Demonstration 本文来自织梦 
                                                             (c) Charles Petzold, 1998 织梦内容管理系统 
---------------------------------------------------------------------------*/ copyright dedecms 
  dedecms.com 
#include <windows.h> 
内容来自dedecms
#include "resource.h" 织梦内容管理系统 
  织梦好,好织梦 
#define INIT_MENU_POS                         0 dedecms.com 
#define HELLO_MENU_POS                    2 
织梦好,好织梦
#define RECT_MENU_POS                         1 copyright dedecms 
  
内容来自dedecms
#define IDM_FIRSTCHILD                50000 

织梦好,好织梦

  
dedecms.com
LRESULT        CALLBACK FrameWndProc                         (HWND, UINT, WPARAM, LPARAM) ; 
本文来自织梦
BOOL                   CALLBACK CloseEnumProc                (HWND, LPARAM) ; copyright dedecms 
LRESULT        CALLBACK HelloWndProc                         (HWND, UINT, WPARAM, LPARAM) ; 

本文来自织梦

LRESULT        CALLBACK RectWndProc                          (HWND, UINT, WPARAM, LPARAM) ; 织梦好,好织梦 
  织梦内容管理系统 
        // structure for storing data unique to each Hello child window dedecms.com 
  织梦内容管理系统 
typedef struct tagHELLODATA 
本文来自织梦
{ 

copyright dedecms

        UINT                           iColor ; 
织梦好,好织梦
        COLORREF               clrText ; 
内容来自dedecms
} 织梦内容管理系统 
HELLODATA, * PHELLODATA ; dedecms.com 
        // structure for storing data unique to each Rect child window 

织梦内容管理系统

typedef struct tagRECTDATA 织梦好,好织梦 
{ 内容来自dedecms 
        short           cxClient ; 
内容来自dedecms
        short          cyClient ; 

dedecms.com

} 
织梦内容管理系统
RECTDATA, * PRECTDATA ; 
本文来自织梦
        // global variables 织梦内容管理系统 
TCHAR                                 szAppName[]            = TEXT ("MDIDemo") ; 

内容来自dedecms

TCHAR                                 szFrameClass[]         = TEXT ("MdiFrame") ; 内容来自dedecms 
TCHAR                                 szHelloClass[]         = TEXT ("MdiHelloChild") ; 

织梦内容管理系统

TCHAR                                 szRectClass[]          = TEXT ("MdiRectChild") ; 

dedecms.com

HINSTANCE              hInst ; 

dedecms.com

HMENU                                 hMenuInit, hMenuHello, hMenuRect ; dedecms.com 
HMENU                                 hMenuInitWindow, hMenuHelloWindow, hMenuRectWindow ; 
copyright dedecms
  dedecms.com 
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, dedecms.com 
                                                                     PSTR szCmdLine, int iCmdShow) 本文来自织梦 
{ 

织梦内容管理系统

        HACCEL                         hAccel ; 
本文来自织梦
        HWND                                  hwndFrame, hwndClient ; 本文来自织梦 
        MSG                                   msg ; 
copyright dedecms
        WNDCLASS                       wndclass ; 
dedecms.com
      
dedecms.com
        hInst = hInstance ; 织梦内容管理系统 
                               // Register the frame window class 织梦内容管理系统 
        wndclass.style                                = CS_HREDRAW | CS_VREDRAW ; 

内容来自dedecms

        wndclass.lpfnWndProc                          = FrameWndProc ; 
织梦内容管理系统
        wndclass.cbClsExtra                           = 0 ; 内容来自dedecms 
        wndclass.cbWndExtra                           = 0 ; 
内容来自dedecms
        wndclass.hInstance                            = hInstance ; 本文来自织梦 
        wndclass.hIcon                                = LoadIcon (NULL, IDI_APPLICATION) ; 织梦内容管理系统 
        wndclass.hCursor                              = LoadCursor (NULL, IDC_ARROW) ; 织梦好,好织梦 
        wndclass.hbrBackground                = (HBRUSH) (COLOR_APPWORKSPACE + 1) ; dedecms.com 
        wndclass.lpszMenuName                 = NULL ; 
本文来自织梦
        wndclass.lpszClassName                = szFrameClass ; 
织梦内容管理系统
      内容来自dedecms 
        if (!RegisterClass (&wndclass)) copyright dedecms 
        { 织梦内容管理系统 
                               MessageBox (   NULL, TEXT ("This program requires Windows NT!"), 

内容来自dedecms

                                                                            szAppName, MB_ICONERROR) ; 本文来自织梦 
                               return 0 ; 本文来自织梦 
       } 织梦好,好织梦 
         本文来自织梦 
                               // Register the Hello child window class 织梦内容管理系统 
        wndclass.style                                               = CS_HREDRAW | CS_VREDRAW ; 
内容来自dedecms
        wndclass.lpfnWndProc                          = HelloWndProc ; 
织梦好,好织梦
        wndclass.cbClsExtra                           = 0 ; 
dedecms.com
        wndclass.cbWndExtra                           = sizeof (HANDLE) ; 织梦内容管理系统 
        wndclass.hInstance                            = hInstance ; 
内容来自dedecms
        wndclass.hIcon                                = LoadIcon (NULL, IDI_APPLICATION) ; 
本文来自织梦
        wndclass.hCursor                              = LoadCursor (NULL, IDC_ARROW) ; 
织梦内容管理系统
        wndclass.hbrBackground                = (HBRUSH) GetStockObject (WHITE_BRUSH) ; 织梦好,好织梦 
        wndclass.lpszMenuName                 = NULL ; 
织梦内容管理系统
        wndclass.lpszClassName                = szHelloClass ; 
织梦好,好织梦
           
dedecms.com
        RegisterClass (&wndclass) ; 织梦好,好织梦 
                               // Register the Rect child window class 本文来自织梦 
        wndclass.style                                = CS_HREDRAW | CS_VREDRAW ; 织梦内容管理系统 
        wndclass.lpfnWndProc                          = RectWndProc ; 

内容来自dedecms

        wndclass.cbClsExtra                           = 0 ; 

织梦好,好织梦

        wndclass.cbWndExtra                           = sizeof (HANDLE) ; 内容来自dedecms 
        wndclass.hInstance                            = hInstance ; 
织梦内容管理系统
        wndclass.hIcon                                = LoadIcon (NULL, IDI_APPLICATION) ; 内容来自dedecms 
        wndclass.hCursor                              = LoadCursor (NULL, IDC_ARROW) ; 内容来自dedecms 
        wndclass.hbrBackground                = (HBRUSH) GetStockObject (WHITE_BRUSH) ; dedecms.com 
        wndclass.lpszMenuName                 = NULL ; 

织梦内容管理系统

        wndclass.lpszClassName                = szRectClass ; 

dedecms.com

           本文来自织梦 
        RegisterClass (&wndclass) ; 织梦内容管理系统 
                               // Obtain handles to three possible menus & submenus dedecms.com 
        hMenuInit              = LoadMenu     (hInstance, TEXT ("MdiMenuInit")) ; copyright dedecms 
        hMenuHello             = LoadMenu     (hInstance, TEXT ("MdiMenuHello")) ; 
织梦好,好织梦
        hMenuRect              = LoadMenu     (hInstance, TEXT ("MdiMenuRect")) ; 本文来自织梦 
     织梦内容管理系统 
        hMenuInitWindow                = GetSubMenu   (hMenuInit,   INIT_MENU_POS)   ; 内容来自dedecms 
        hMenuHelloWindow               = GetSubMenu   (hMenuHello, HELLO_MENU_POS)   ; 内容来自dedecms 
        hMenuRectWindow                = GetSubMenu   (hMenuRect,   RECT_MENU_POS)   ; 织梦内容管理系统 
  

内容来自dedecms

                               // Load accelerator table 织梦好,好织梦 
      

织梦内容管理系统

        hAccel = LoadAccelerators (hInstance, szAppName) ; 
织梦好,好织梦
                               // Create the frame window 织梦好,好织梦 
        hwndFrame      = CreateWindow (szFrameClass, TEXT ("MDI Demonstration"), 
织梦内容管理系统
                      WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, 织梦内容管理系统 
                      CW_USEDEFAULT, CW_USEDEFAULT, 
织梦好,好织梦
                      CW_USEDEFAULT, CW_USEDEFAULT, 

织梦内容管理系统

                      NULL, hMenuInit, hInstance, NULL) ; 内容来自dedecms 
        hwndClient = GetWindow (hwndFrame, GW_CHILD) ; dedecms.com 
        ShowWindow (hwndFrame, iCmdShow) ; 本文来自织梦 
        UpdateWindow (hwndFrame) ; 

织梦内容管理系统

      
内容来自dedecms
                               // Enter the modified message loop 
织梦内容管理系统
        while (GetMessage (&msg, NULL, 0, 0)) 织梦内容管理系统 
        { 内容来自dedecms 
                       if (    !TranslateMDISysAccel (hwndClient, &msg) && 内容来自dedecms 
                                      !TranslateAccelerator (hwndFrame, hAccel, &msg)) 
copyright dedecms
                               { 

copyright dedecms

                                      TranslateMessage (&msg) ; 

copyright dedecms

                                      DispatchMessage (&msg) ; 本文来自织梦 
                               } 
织梦好,好织梦
        } copyright dedecms 
                               // Clean up by deleting unattached menus dedecms.com 
        DestroyMenu (hMenuHello) ; 

织梦好,好织梦

        DestroyMenu (hMenuRect) ; 织梦内容管理系统 
      copyright dedecms 
        return msg.wParam ; 织梦内容管理系统 
        } copyright dedecms 
      内容来自dedecms 
LRESULT CALLBACK FrameWndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) 
织梦好,好织梦
{ 本文来自织梦 
        static HWND                    hwndClient ; 内容来自dedecms 
        CLIENTCREATESTRUCT             clientcreate ; 内容来自dedecms 
        HWND                           hwndChild ; 
织梦好,好织梦
        MDICREATESTRUCT                mdicreate ; 

织梦好,好织梦

           本文来自织梦 
        switch (message) dedecms.com 
        { 织梦好,好织梦 
        case    WM_CREATE:                                    // Create the client window 
dedecms.com
           
织梦好,好织梦
        clientcreate.hWindowMenu              = hMenuInitWindow ; dedecms.com 
               clientcreate.idFirstChild             = IDM_FIRSTCHILD ; 

内容来自dedecms

           copyright dedecms 
        hwndClient = CreateWindow     (       TEXT ("MDICLIENT"), NULL, 
copyright dedecms
                                     WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE,    

织梦内容管理系统

                                     0, 0, 0, 0, hwnd, (HMENU) 1, hInst, 内容来自dedecms 
                                     (PSTR) &clientcreate) ; 
织梦内容管理系统
                       return 0 ; 
织梦内容管理系统
        case    WM_COMMAND: 内容来自dedecms 
                               switch (LOWORD (wParam)) 
dedecms.com
                               { 织梦好,好织梦 
                               case    IDM_FILE_NEWHELLO:  // Create a Hello child window 织梦内容管理系统 
                            mdicreate.szClass                = szHelloClass ; 内容来自dedecms 
                                      mdicreate.szTitle              = TEXT ("Hello") ; 

内容来自dedecms

                                      mdicreate.hOwner               = hInst ; 内容来自dedecms 
                                      mdicreate.x                                   = CW_USEDEFAULT ; 内容来自dedecms 
                                      mdicreate.y                                   = CW_USEDEFAULT ; 

织梦好,好织梦

                                      mdicreate.cx                          = CW_USEDEFAULT ; 本文来自织梦 
                                      mdicreate.cy                          = CW_USEDEFAULT ; 内容来自dedecms 
                                      mdicreate.style                = 0 ; 
copyright dedecms
                                      mdicreate.lParam               = 0 ; 

织梦好,好织梦

                

dedecms.com

               hwndChild = (HWND) SendMessage (hwndClient, 织梦内容管理系统 
               WM_MDICREATE, 0, (LPARAM) (LPMDICREATESTRUCT) &mdicreate) ; 
织梦内容管理系统
               return 0 ; 

织梦好,好织梦

                

内容来自dedecms

                               case    IDM_FILE_NEWRECT:      // Create a Rect child window 织梦内容管理系统 
                copyright dedecms 
                       mdicreate.szClass                  = szRectClass ; 

织梦内容管理系统

                       mdicreate.szTitle                  = TEXT ("Rectangles") ; 

织梦好,好织梦

                       mdicreate.hOwner                   = hInst ; dedecms.com 
                       mdicreate.x                           = CW_USEDEFAULT ; dedecms.com 
                       mdicreate.y                           = CW_USEDEFAULT ; 
dedecms.com
                       mdicreate.cx                          = CW_USEDEFAULT ; dedecms.com 
                       mdicreate.cy                          = CW_USEDEFAULT ; 
dedecms.com
                       mdicreate.style                    = 0 ; 织梦好,好织梦 
                       mdicreate.lParam                   = 0 ; 

本文来自织梦

                本文来自织梦 
                       hwndChild = (HWND) SendMessage (hwndClient, copyright dedecms 
                              WM_MDICREATE, 0, copyright dedecms 
                                (LPARAM) (LPMDICREATESTRUCT) &mdicreate) ; 

织梦好,好织梦

                                              return 0 ; copyright dedecms 
                织梦内容管理系统 
                               case    IDM_FILE_CLOSE:        // Close the active window 
本文来自织梦
                

本文来自织梦

                       hwndChild = (HWND) SendMessage (hwndClient, dedecms.com 
                                WM_MDIGETACTIVE, 0, 0) ; copyright dedecms 
                copyright dedecms 
                       if (SendMessage (hwndChild, WM_QUERYENDSESSION, 0, 0)) 
copyright dedecms
                               SendMessage (hwndClient, WM_MDIDESTROY, dedecms.com 
                        (WPARAM) hwndChild, 0) ; 
本文来自织梦
                               return 0 ; copyright dedecms 
  织梦好,好织梦 
                               case    IDM_APP_EXIT:  // Exit the program 织梦好,好织梦 
                
dedecms.com
                       SendMessage (hwnd, WM_CLOSE, 0, 0) ; 本文来自织梦 
                       return 0 ; 织梦内容管理系统 
                copyright dedecms 
                       // messages for arranging windows 织梦内容管理系统 
  

本文来自织梦

                               case    IDM_WINDOW_TILE: 织梦好,好织梦 
                                      SendMessage (hwndClient, WM_MDITILE, 0, 0) ; 

本文来自织梦

                                      return 0 ; 
织梦好,好织梦
                

copyright dedecms

                               case    IDM_WINDOW_CASCADE: 
织梦好,好织梦
                                      SendMessage (hwndClient, WM_MDICASCADE, 0, 0) ; dedecms.com 
                                      return 0 ; 

本文来自织梦

                内容来自dedecms 
                               case    IDM_WINDOW_ARRANGE: 

织梦内容管理系统

                                      SendMessage (hwndClient, WM_MDIICONARRANGE, 0, 0) ; 本文来自织梦 
                                      return 0 ; 
本文来自织梦
                copyright dedecms 
                               case    IDM_WINDOW_CLOSEALL:  // Attempt to close all children 

织梦内容管理系统

                

copyright dedecms

                                      EnumChildWindows (hwndClient, CloseEnumProc, 0) ; 

内容来自dedecms

                                      return 0 ; 本文来自织梦 
                织梦好,好织梦 
                               default:                       // Pass to active child... 

内容来自dedecms

  

copyright dedecms

                                      hwndChild = (HWND) SendMessage (hwndClient, 织梦内容管理系统 
                                         WM_MDIGETACTIVE, 0, 0) ; 织梦好,好织梦 
                                      if (IsWindow (hwndChild)) 

本文来自织梦

                               SendMessage (hwndChild, WM_COMMAND, wParam, lParam) ; 织梦好,好织梦 
                copyright dedecms 
                               break ;    // ...and then to DefFrameProc dedecms.com 
                               } 织梦内容管理系统 
                               break ; 

织梦好,好织梦

           织梦好,好织梦 
        case    WM_QUERYENDSESSION: 
copyright dedecms
        case    WM_CLOSE:      // Attempt to close all children dedecms.com 
                织梦好,好织梦 
                       SendMessage (hwnd, WM_COMMAND, IDM_WINDOW_CLOSEALL, 0) ; dedecms.com 
                

dedecms.com

                   if (NULL != GetWindow (hwndClient, GW_CHILD)) copyright dedecms 
               return 0 ; copyright dedecms 
                
织梦内容管理系统
                               break ;        // i.e., call DefFrameProc  copyright dedecms 
        case    WM_DESTROY: 

dedecms.com

                               PostQuitMessage (0) ; 

内容来自dedecms

                               return 0 ; 

dedecms.com

        } 
本文来自织梦
        // Pass unprocessed messages to DefFrameProc (not DefWindowProc) 

织梦好,好织梦

      织梦内容管理系统 
        return DefFrameProc (hwnd, hwndClient, message, wParam, lParam) ; 内容来自dedecms 
} 
织梦好,好织梦
  织梦内容管理系统 
BOOL CALLBACK CloseEnumProc (HWND hwnd, LPARAM lParam) 
copyright dedecms
{ 

本文来自织梦

        if (GetWindow (hwnd, GW_OWNER)) // Check for icon title 织梦内容管理系统 
                               return TRUE ; 

dedecms.com

      copyright dedecms 
        SendMessage (GetParent (hwnd), WM_MDIRESTORE, (WPARAM) hwnd, 0) ; 本文来自织梦 
        if (!SendMessage (hwnd, WM_QUERYENDSESSION, 0, 0)) 
dedecms.com
        return TRUE ; copyright dedecms 
        SendMessage (GetParent (hwnd), WM_MDIDESTROY, (WPARAM) hwnd, 0) ; 本文来自织梦 
        return TRUE ; 

内容来自dedecms

} 
dedecms.com
  
内容来自dedecms
LRESULT CALLBACK HelloWndProc (HWND hwnd, UINT message,  
dedecms.com
WPARAM wParam, LPARAM lParam) 织梦好,好织梦 
{ 内容来自dedecms 
        static COLORREF clrTextArray[] = {    RGB (0,   0, 0), RGB (255, 0,   0), 
copyright dedecms
        RGB (0, 255, 0), RGB (  0, 0, 255), 

copyright dedecms

        RGB (255, 255, 255) } ; 本文来自织梦 
        static HWND                    hwndClient, hwndFrame ; 内容来自dedecms 
        HDC                            hdc ; 

本文来自织梦

        HMENU                          hMenu ; 织梦好,好织梦 
        PHELLODATA                     pHelloData ; 
织梦好,好织梦
        PAINTSTRUCT                    ps ; 

本文来自织梦

        RECT                           rect ; 内容来自dedecms 
      
本文来自织梦
        switch (message) 
copyright dedecms
        { copyright dedecms 
        case    WM_CREATE: 内容来自dedecms 
                // Allocate memory for window private data 

dedecms.com

           本文来自织梦 
                               pHelloData = (PHELLODATA) HeapAlloc (GetProcessHeap (), 
织梦内容管理系统
                                HEAP_ZERO_MEMORY, sizeof (HELLODATA)) ; 
copyright dedecms
                               pHelloData->iColor  = IDM_COLOR_BLACK ; copyright dedecms 
                               pHelloData->clrText = RGB (0, 0, 0) ; 
本文来自织梦
                               SetWindowLong (hwnd, 0, (long) pHelloData) ; 

本文来自织梦

           

copyright dedecms

                                      // Save some window handles 织梦内容管理系统 
           
织梦好,好织梦
                               hwndClient = GetParent (hwnd) ; 

本文来自织梦

                               hwndFrame  = GetParent (hwndClient) ; 
copyright dedecms
                               return 0 ; 织梦内容管理系统 
           
copyright dedecms
        case    WM_COMMAND: 织梦内容管理系统 
                               switch (LOWORD (wParam)) 本文来自织梦 
                               { 织梦内容管理系统 
                                      case IDM_COLOR_BLACK: 

织梦内容管理系统

                                      case IDM_COLOR_RED: 

dedecms.com

                                      case IDM_COLOR_GREEN: copyright dedecms 
                                      case IDM_COLOR_BLUE: 织梦好,好织梦 
                                      case IDM_COLOR_WHITE: copyright dedecms 
                       // Change the text color 内容来自dedecms 
                
本文来自织梦
               pHelloData = (PHELLODATA) GetWindowLong (hwnd, 0) ; 内容来自dedecms 
                
内容来自dedecms
               hMenu = GetMenu (hwndFrame) ; 内容来自dedecms 
                织梦好,好织梦 
               CheckMenuItem (hMenu, pHelloData->iColor, MF_UNCHECKED) ; dedecms.com 
               pHelloData->iColor = wParam ; 内容来自dedecms 
               CheckMenuItem (hMenu, pHelloData->iColor, MF_CHECKED) ; 

织梦内容管理系统

                
copyright dedecms
               pHelloData->clrText = clrTextArray[wParam - IDM_COLOR_BLACK] ; 

dedecms.com

                

copyright dedecms

               InvalidateRect (hwnd, NULL, FALSE) ; 本文来自织梦 
                  } 

copyright dedecms

                  return 0 ; 本文来自织梦 
           织梦好,好织梦 
        case    WM_PAINT: 织梦内容管理系统 
               // Paint the window 
copyright dedecms
                织梦内容管理系统 
                               hdc = BeginPaint (hwnd, &ps) ; 织梦内容管理系统 
                内容来自dedecms 
                               pHelloData = (PHELLODATA) GetWindowLong (hwnd, 0) ; 织梦内容管理系统 
                               SetTextColor (hdc, pHelloData->clrText) ; 
内容来自dedecms
                

内容来自dedecms

                               GetClientRect (hwnd, &rect) ; 
dedecms.com
                

织梦内容管理系统

                               DrawText (hdc, TEXT ("Hello, World!"), -1, &rect, dedecms.com 
                    DT_SINGLELINE | DT_CENTER | DT_VCENTER) ; 

本文来自织梦

                               EndPaint (hwnd, &ps) ; 本文来自织梦 
                               return 0 ; 织梦内容管理系统 
                dedecms.com 
        case    WM_MDIACTIVATE: 内容来自dedecms 
               // Set the Hello menu if gaining focus 

copyright dedecms

                

本文来自织梦

                               if (lParam == (LPARAM) hwnd) 织梦内容管理系统 
               SendMessage (hwndClient, WM_MDISETMENU,(WPARAM) 

copyright dedecms

hMenuHello, (LPARAM) hMenuHelloWindow) ; copyright dedecms 
                内容来自dedecms 
                                              // Check or uncheck menu item 织梦好,好织梦 
                

本文来自织梦

                               pHelloData = (PHELLODATA) GetWindowLong (hwnd, 0) ; 织梦内容管理系统 
                               CheckMenuItem (hMenuHello, pHelloData->iColor, 

内容来自dedecms

                                              (lParam == (LPARAM) hwnd) ? MF_CHECKED : MF_UNCHECKED) ; copyright dedecms 
                
织梦内容管理系统
                                              // Set the Init menu if losing focus 

织梦好,好织梦

                织梦好,好织梦 
                               if (lParam != (LPARAM) hwnd) 
内容来自dedecms
                                              SendMessage (hwndClient, WM_MDISETMENU, (WPARAM)  copyright dedecms 
hMenuInit,(LPARAM) hMenuInitWindow) ; 

织梦好,好织梦

                

copyright dedecms

                               DrawMenuBar (hwndFrame) ; 
织梦内容管理系统
                               return 0 ; 

织梦好,好织梦

  本文来自织梦 
        case    WM_QUERYENDSESSION: 

织梦内容管理系统

        case    WM_CLOSE: 

dedecms.com

        if (IDOK != MessageBox (hwnd, TEXT ("OK to close window?"), 
copyright dedecms
                                        TEXT ("Hello"),  本文来自织梦 
                    MB_ICONQUESTION | MB_OKCANCEL)) dedecms.com 
                       return 0 ; 

本文来自织梦

                
内容来自dedecms
                               break ;                // i.e., call DefMDIChildProc 
内容来自dedecms
                
内容来自dedecms
        case    WM_DESTROY: 织梦好,好织梦 
                               pHelloData = (PHELLODATA) GetWindowLong (hwnd, 0) ; 内容来自dedecms 
                               HeapFree (GetProcessHeap (), 0, pHelloData) ; 

内容来自dedecms

                               return 0 ; 内容来自dedecms 
        } 

织梦好,好织梦

                                      // Pass unprocessed message to DefMDIChildProc 
本文来自织梦
      
本文来自织梦
        return DefMDIChildProc (hwnd, message, wParam, lParam) ; 
本文来自织梦
} 本文来自织梦 
LRESULT CALLBACK RectWndProc (HWND hwnd, UINT message,WPARAM wParam, LPARAM lParam) 
织梦内容管理系统
{ 
织梦好,好织梦
        static HWND    hwndClient, hwndFrame ; copyright dedecms 
        HBRUSH         hBrush ; copyright dedecms 
        HDC            hdc ; 

内容来自dedecms

        PRECTDATA      pRectData ; 

copyright dedecms

        PAINTSTRUCT    ps ; 织梦好,好织梦 
        int                                   xLeft, xRight, yTop, yBottom ; 
内容来自dedecms
        short                                         nRed, nGreen, nBlue ; dedecms.com 
      内容来自dedecms 
        switch (message) dedecms.com 
     { dedecms.com 
        case    WM_CREATE: 
内容来自dedecms
                                      // Allocate memory for window private data 织梦好,好织梦 
           
织梦内容管理系统
                               pRectData = (PRECTDATA) HeapAlloc (GetProcessHeap (), 

织梦内容管理系统

                                HEAP_ZERO_MEMORY, sizeof (RECTDATA)) ; 织梦内容管理系统 
           
内容来自dedecms
                               SetWindowLong (hwnd, 0, (long) pRectData) ; 
dedecms.com
           内容来自dedecms 
                                                                     // Start the timer going 

dedecms.com

           织梦内容管理系统 
                               SetTimer (hwnd, 1, 250, NULL) ; 本文来自织梦 
           织梦好,好织梦 
                                                                     // Save some window handles copyright dedecms 
                               hwndClient     = GetParent (hwnd) ; copyright dedecms 
                               hwndFrame      = GetParent (hwndClient) ; 
本文来自织梦
                               return 0 ; 

内容来自dedecms

           

本文来自织梦

        case    WM_SIZE:    // If not minimized, save the window size 

织梦内容管理系统

           内容来自dedecms 
                               if (wParam != SIZE_MINIMIZED) 
织梦好,好织梦
                               { 内容来自dedecms 
                                              pRectData = (PRECTDATA) GetWindowLong (hwnd, 0) ; 内容来自dedecms 
                
织梦内容管理系统
                                              pRectData->cxClient = LOWORD (lParam) ; 

dedecms.com

                                              pRectData->cyClient = HIWORD (lParam) ; dedecms.com 
                               } 织梦内容管理系统 
           
copyright dedecms
                               break ;                        // WM_SIZE must be processed by DefMDIChildProc dedecms.com 
           
织梦内容管理系统
        case    WM_TIMER:                      // Display a random rectangle 

dedecms.com

           织梦内容管理系统 
                               pRectData      = (PRECTDATA) GetWindowLong (hwnd, 0) ; 
copyright dedecms
                               xLeft                          = rand () % pRectData->cxClient ; 织梦内容管理系统 
                               xRight                 = rand () % pRectData->cxClient ; 

织梦好,好织梦

                               yTop                           = rand () % pRectData->cyClient ; 
copyright dedecms
                               yBottom                = rand () % pRectData->cyClient ; 

本文来自织梦

                               nRed                           = rand () & 255 ; 织梦好,好织梦 
                               nGreen                 = rand () & 255 ; 

织梦内容管理系统

                               nBlue                          = rand () & 255 ; 

dedecms.com

           

织梦好,好织梦

                               hdc = GetDC (hwnd) ; 织梦内容管理系统 
                               hBrush = CreateSolidBrush (RGB (nRed, nGreen, nBlue)) ; 

本文来自织梦

                               SelectObject (hdc, hBrush) ; 内容来自dedecms 
           

内容来自dedecms

                               Rectangle (hdc, min (xLeft, xRight), min (yTop, yBottom), copyright dedecms 
                                                                     max (xLeft, xRight), max (yTop, yBottom)) ; 
copyright dedecms
           dedecms.com 
                               ReleaseDC (hwnd, hdc) ; 

copyright dedecms

                               DeleteObject (hBrush) ; 
织梦好,好织梦
                               return 0 ; 

dedecms.com

           织梦内容管理系统 
        case    WM_PAINT:                                             // Clear the window 织梦内容管理系统 
           

copyright dedecms

                               InvalidateRect (hwnd, NULL, TRUE) ; copyright dedecms 
                               hdc = BeginPaint (hwnd, &ps) ; 
织梦好,好织梦
                               EndPaint (hwnd, &ps) ; 织梦好,好织梦 
                               return 0 ; 
织梦好,好织梦
           织梦内容管理系统 
        case    WM_MDIACTIVATE:                       // Set the appropriate menu dedecms.com 
                               if (lParam == (LPARAM) hwnd) 

本文来自织梦

               SendMessage (hwndClient, WM_MDISETMENU, (WPARAM) hMenuRect, (LPARAM) hMenuRectWindow) ; 

dedecms.com

                               else 内容来自dedecms 
               SendMessage (hwndClient, WM_MDISETMENU, (WPARAM) hMenuInit, (LPARAM) hMenuInitWindow) ; 

copyright dedecms

           
织梦好,好织梦
                                      DrawMenuBar (hwndFrame) ; 

copyright dedecms

                                      return 0 ; 本文来自织梦 
           copyright dedecms 
        case    WM_DESTROY: 

本文来自织梦

                               pRectData = (PRECTDATA) GetWindowLong (hwnd, 0) ; 
dedecms.com
                               HeapFree (GetProcessHeap (), 0, pRectData) ; 

织梦内容管理系统

                               KillTimer (hwnd, 1) ; 
织梦好,好织梦
                               return 0 ; 
copyright dedecms
     } dedecms.com 
          // Pass unprocessed message to DefMDIChildProc 本文来自织梦 
     return DefMDIChildProc (hwnd, message, wParam, lParam) ; copyright dedecms 
} 

dedecms.com

 MDIDEMO.RC (摘录) 
织梦好,好织梦
//Microsoft Developer Studio generated resource script. 
dedecms.com
#include "resource.h" 

本文来自织梦

#include "afxres.h" 

织梦内容管理系统

  

织梦好,好织梦

///////////////////////////////////////////////////////////////////////////// 

内容来自dedecms

// Menu 

本文来自织梦

MDIMENUINIT MENU DISCARDABLE  织梦好,好织梦 
BEGIN 
本文来自织梦
        POPUP "&File" 

内容来自dedecms

        BEGIN 本文来自织梦 
                               MENUITEM "New &Hello",                        IDM_FILE_NEWHELLO 织梦内容管理系统 
                               MENUITEM "New &Rectangle",                    IDM_FILE_NEWRECT 
内容来自dedecms
                               MENUITEM SEPARATOR 
copyright dedecms
                               MENUITEM "E&xit", IDM_APP_EXIT 

织梦内容管理系统

        END 织梦内容管理系统 
END 织梦内容管理系统 
MDIMENUHELLO MENU DISCARDABLE  
织梦好,好织梦
BEGIN 织梦好,好织梦 
        POPUP "&File" 
本文来自织梦
        BEGIN 本文来自织梦 
MENUITEM "New &Hello",                IDM_FILE_NEWHELLO 

织梦好,好织梦

MENUITEM "New &Rectangle",     IDM_FILE_NEWRECT 织梦好,好织梦 
MENUITEM "&Close",             IDM_FILE_CLOSE 内容来自dedecms 
MENUITEM SEPARATOR 

织梦内容管理系统

MENUITEM "E&xit",                     IDM_APP_EXIT 内容来自dedecms 
END 织梦内容管理系统 
        POPUP "&Color" 

dedecms.com

        BEGIN 

织梦内容管理系统

        MENUITEM "&Black",                    IDM_COLOR_BLACK 
织梦好,好织梦
        MENUITEM "&Red",                  IDM_COLOR_RED dedecms.com 
        MENUITEM "&Green",            IDM_COLOR_GREEN 

织梦好,好织梦

        MENUITEM "B&lue",             IDM_COLOR_BLUE 内容来自dedecms 
        MENUITEM "&White",                    IDM_COLOR_WHITE 内容来自dedecms 
        END 本文来自织梦 
        POPUP "&Window" copyright dedecms 
        BEGIN 织梦好,好织梦 
        MENUITEM "&Cascade\tShift+F5",                IDM_WINDOW_CASCADE 

dedecms.com

        MENUITEM "&Tile\tShift+F4",                   IDM_WINDOW_TILE 内容来自dedecms 
        MENUITEM "Arrange &Icons",                    IDM_WINDOW_ARRANGE 

内容来自dedecms

        MENUITEM "Close &All",                               IDM_WINDOW_CLOSEALL 
本文来自织梦
        END dedecms.com 
END 
织梦内容管理系统
MDIMENURECT MENU DISCARDABLE  本文来自织梦 
BEGIN 

织梦好,好织梦

        POPUP "&File" 本文来自织梦 
        BEGIN 
dedecms.com
        MENUITEM "New &Hello",                               IDM_FILE_NEWHELLO 内容来自dedecms 
        MENUITEM "New &Rectangle",                   IDM_FILE_NEWRECT dedecms.com 
        MENUITEM "&Close",                    IDM_FILE_CLOSE 织梦内容管理系统 
        MENUITEM SEPARATOR 

织梦内容管理系统

        MENUITEM "E&xit",                                    IDM_APP_EXIT copyright dedecms 
        END 
内容来自dedecms
        POPUP "&Window" copyright dedecms 
        BEGIN 

本文来自织梦

        MENUITEM "&Cascade\tShift+F5",                IDM_WINDOW_CASCADE 

织梦内容管理系统

        MENUITEM "&Tile\tShift+F4",                   IDM_WINDOW_TILE 

织梦好,好织梦

        MENUITEM "Arrange &Icons",                    IDM_WINDOW_ARRANGE 
dedecms.com
        MENUITEM "Close &All",                    IDM_WINDOW_CLOSEALL 织梦内容管理系统 
        END 

织梦内容管理系统

END 
dedecms.com
  dedecms.com 
///////////////////////////////////////////////////////////////////////////// 
织梦好,好织梦
// Accelerator 
织梦内容管理系统
MDIDEMO ACCELERATORS DISCARDABLE  
织梦内容管理系统
BEGIN 本文来自织梦 
    VK_F4,    IDM_WINDOW_TILE,     VIRTKEY, SHIFT, NOINVERT 
本文来自织梦
    VK_F5,    IDM_WINDOW_CASCADE,  VIRTKEY, SHIFT, NOINVERT 

本文来自织梦

END 
copyright dedecms
 RESOURCE.H (摘录) 织梦内容管理系统 
// Microsoft Developer Studio generated include file. 织梦内容管理系统 
// Used by MDIDemo.rc 织梦好,好织梦 
  

织梦好,好织梦

#define IDM_FILE_NEWHELLO                                                           40001 copyright dedecms 
#define IDM_FILE_NEWRECT                                                            40002 
内容来自dedecms
#define IDM_APP_EXIT                                                                40003 
织梦好,好织梦
#define IDM_FILE_CLOSE                                                              40004 
内容来自dedecms
#define IDM_COLOR_BLACK                                                             40005 
dedecms.com
#define IDM_COLOR_RED                                                               40006 copyright dedecms 
#define IDM_COLOR_GREEN                                                             40007 

织梦内容管理系统

#define IDM_COLOR_BLUE                                                              40008 dedecms.com 
#define IDM_COLOR_WHITE                                                             40009 dedecms.com 
#define IDM_WINDOW_CASCADE                                                      40010 内容来自dedecms 
#define IDM_WINDOW_TILE                                                             40011 dedecms.com 
#define IDM_WINDOW_ARRANGE                                                      40012 

内容来自dedecms

#define IDM_WINDOW_CLOSEALL                                                     40013 
本文来自织梦

MDIDEMO支援两种型态的非常简单的文件视窗:第一种视窗在它的显示区域中央显示"Hello, World!",另一种视窗显示一系列随机矩形(在原始码列表和识别字名中,它们分别叫做「Hello」文件和「Rect」文件)。这两类文件视窗的功能表不同,显示"Hello, World!"的文件视窗有一个允许使用者修改文字颜色的功能表。 copyright dedecms

三个功能表
 

copyright dedecms

现在让我们先看看MDIDEMO.RC资源描述档,它定义了程式所使用的三个功能表模板。 copyright dedecms

当文件视窗不存在时,程式显示MdiMenuInit功能表,这个功能表只允许使用者建立新文件或退出程式。 copyright dedecms

MdiMenuHello功能表与显示「Hello, World!」的文件视窗相关联。「File」子功能表允许使用者打开任何一类新文件、关闭活动文件或退出程式。「Color」子功能表允许使用者设定文字颜色。Window子功能表包括以平铺或者重叠的方式安排文件视窗、安排文件图示或关闭所有视窗等选项,这个子功能表也列出了它们建立的所有文件视窗。

dedecms.com

MdiMenuRect功能表与随机矩形文件相关联。除了不包含「Color」子功能表外,它与MdiMenuHello功能表一样。 织梦好,好织梦

RESOURCE.H表头档案定义所有的功能表识别字。另外,以下三个常数定义在MDIDEMO.C中:

内容来自dedecms

#define INIT_MENU_POS                 0 
dedecms.com
#define HELLO_MENU_POS                2 
dedecms.com
#define RECT_MENU_POS                 1 copyright dedecms 

这些识别字说明每个功能表模板中Windows子功能表的位置。程式需要这些资讯来通知客户视窗文件列表应出现在哪里。当然,MdiMenuInit功能表没有Windows子功能表,所以如前所述,文件列表应附加在第一个子功能表中(位置0)。不过,实际上永远不会在此看到文件列表(在後面讨论此程式时,您可以发现这样做的原因)。 copyright dedecms

定义在MDIDEMO.C中的IDM_FIRSTCHILD识别字不对应於功能表项,它与出现在Windows子功能表上的文件列表中的第一个文件视窗相关联。这个识别字的值应当大於所有其他功能表ID的值。 copyright dedecms

程式初始化
 

织梦好,好织梦

MDIDEMO.C中,WinMain是从注册框架视窗和两个子视窗的视窗类别开始的。视窗讯息处理程式是FrameWndProcHelloWndProcRectWndProc。一般来说,这些视窗类别应该与不同的图示相关联。为了简单起见,我们将标准IDI_APPLICATION图示用於框架视窗和子视窗。 dedecms.com

注意,我们已经定义了框架视窗类别的WNDCLASS结构的hbrBackground栏位为COLOR_APPWORKSPACE系统颜色。由於框架视窗的显示区域被客户视窗所覆盖并且客户视窗具有这种颜色,所以上面的定义不是绝对必要的。但是,在最初显示框架视窗时,使用这种颜色似乎要好一些。

dedecms.com

这三种视窗类别中的lpszMenuName栏位都设定为NULL。对「Hello」和「Rect」子视窗类别来说,这是很自然的。对於框架视窗类别,我在建立框架视窗时在CreateWindow函式中给出功能表代号。 内容来自dedecms

Hello」和「Rect」子视窗的视窗类别将WNDCLASS结构中的cbWndExtra栏位设为非零值来为每个视窗配置额外空间,这个空间将用於储存指向一个记忆体块的指标(HELLODATARECTDATA结构的大小定义在MDIDEMO.C的开始处),这个记忆体块被用於储存每个文件视窗特有的资讯。

本文来自织梦

下一步,WinMainLoadMenu载入三个功能表,并把它们的代号储存到整体变数中。呼叫三次GetSubMenu函式可获得Windows子功能表(文件列表将加在它上面)的代号,同样也把它们储存到整体变数中。LoadAccelerators函式载入加速键表。

dedecms.com

WinMain中呼叫CreateWindow建立框架视窗。在FrameWndProcWM_CREATE讯息处理期间,框架视窗建立客户视窗。这项操作涉及到再一次呼叫函式CreateWindow。视窗类别被设定为MDICLIENT,它是预先注册的MDI显示区域视窗类别。在Windows中许多对MDI的支援被放入了MDICLIENT视窗类别中。显示区域视窗讯息处理程式作为框架视窗和不同文件视窗的中间层。当呼叫CreateWindow建立显示区域视窗时,最後一个参数必须被设定为指向CLIENTCREATESTRUCT型态结构的指标。这个结构有两个栏位: 织梦好,好织梦

  • hWindowMenu是要加入文件列表的子功能表的代号。在MDIDEMO中,它是hMenuInitWindow,是在WinMain期间获得的。後面将看到如何修改此功能表。
     
  • idFirstChild是与文件列表中的第一个文件视窗相关联的功能表ID。它就是IDM_FIRSTCHILD.
     

再让我们回过头来看看WinMainMDIDEMO显示新建立的框架视窗并进入讯息回圈。讯息回圈与正常的回圈稍有不同:在呼叫GetMessage从讯息伫列中获得讯息之後,MDI程式把这个讯息传送给了TranslateMDISysAccel(以及TranslateAccelerator,如果像MDIDEMO程式一样,程式本身也有功能表加速键的话)。 织梦内容管理系统

TranslateMDISysAccel函式把可能对应特定MDI加速键(例如Ctrl-F6)的按键转换成WM_SYSCOMMAND讯息。如果TranslateMDISysAccelTranslateAccelerator都传回TRUE(表示某个讯息已被这些函式之一转换),就不能呼叫TranslateMessageDispatchMessage织梦内容管理系统

注意传递到TranslateMDISysAccelTranslateAccelerator的两个视窗代号:hwndClienthwndFrameWinMain函式通过用GW_CHILD参数呼叫GetWindow获得hwndClient视窗代号。 copyright dedecms

建立子视窗
 

dedecms.com

FrameWndProc的大部分工作是用於处理通知功能表选择的WM_COMMAND讯息。与平时一样,FrameWndProcwParam参数的低字组包含著功能表ID

copyright dedecms

在功能表ID的值为IDM_FILE_NEWHELLOIDM_FILE_NEWRECT的情况下,FrameWndProc必须建立一个新的文件视窗。这涉及到初始化MDICREATESTRUCT结构中的栏位(大多数栏位对应於CreateWindow的参数),并将讯息WM_MDICREATE发送给客户视窗,讯息的lParam参数设定为指向这个结构的指标。然後由客户视窗建立子文件视窗。(也可以使用CreateMDIWindow函式。)

dedecms.com

MDICREATESTRUCT结构中的szTitle栏位一般是对应於文件的档案名称。样式栏位设定为视窗样式WS_HSCROLLWS_VSCROLL或这两者的组合,以便在文件视窗中包括卷动列。样式栏位也可以包括WS_MINIMIZEWS_MAXIMIZE,以便在最初时以最小化或最大化状态显示文件视窗。

copyright dedecms

MDICREATESTRUCT结构的lParam栏位为框架视窗和子视窗共用某些变数提供了一种方法。这个栏位可以设定为含有一个结构的记忆体块的记忆体代号。在子文件视窗的WM_CREATE讯息处理期间,lParam是一个指向CREATESTRUCT结构的指标,这个结构的lpCreateParams栏位是一个指向用於建立视窗的MDICREATESTRUCT结构的指标。 织梦好,好织梦

客户视窗一旦接收到WM_MDICREATE讯息就建立一个子文件视窗,并把视窗标题加到用於建立客户视窗的MDICLIENTSTRUCT结构中所指定的子功能表的底部。当MDIDEMO程式建立它的第一个文件视窗时,这个子功能表就是「MdiMenuInit」功能表中的「File」子功能表。後面将看到这个文件列表将如何移到「MdiMenuHello」和「MdiMenuRect」功能表的「Windows」子功能表中。 dedecms.com

功能表上可以列出9个文件,每个文件的前面是带有底线的数字19。如果建立的文件视窗多於9个,则这个清单後跟有「More Windows」功能表项。该项启动带有清单方块的对话方块,清单方块列出了所有文件。这种文件列表的维护是Windows MDI支援的最好特性之一。 copyright dedecms

关於框架视窗的讯息处理
  本文来自织梦

在把注意力转移到子文件视窗之前,我们先继续讨论FrameWndProc的讯息处理。

织梦好,好织梦

当从「File」功能表中选择「Close」时,MDIDEMO关闭活动子视窗。它通过把WM_MDIGETACTIVE讯息发送给客户视窗,而获得活动子视窗的代号。如果子视窗以WM_QUERYENDSESSION讯息来回应,那么MDIDEMOWM_MDIDESTROY讯息发送给客户视窗,从而关闭子视窗。

织梦内容管理系统

处理「File」功能表中的「Exit」选项只需要框架视窗讯息处理程式给自己发送一个WM_CLOSE讯息。 dedecms.com

处理Window子功能表的「Tile」、「Cascade」和「Arrange」选项是极容易的,只需把讯息WM_MDITILEWM_MDICASCADEWM_MDIICONARRANGE发送给客户视窗。 织梦好,好织梦

处理「Close All」选项要稍微复杂一些。FrameWndProc呼叫EnumChildWindows,传送一个引用CloseEnumProc函式的指标。此函式把WM_MDIRESTORE讯息发送给每个子视窗,紧跟著发出WM_QUERYENDSESSIONWM_MDIDESTROY。对图示平铺视窗来说并不就此结束,用GW_OWNER参数呼叫GetWindow时,传回的非NULL值可以显示出这一点。

dedecms.com

FrameWndProc没有处理任何由「Color」功能表中对颜色的选择所导致的WM_COMMAND讯息,这些讯息应该由文件视窗负责处理。因此,FrameWndProc把所有未经处理的WM_COMMAND讯息发送到活动子视窗,以便子视窗可以处理那些与它们有关的讯息。

织梦好,好织梦

框架视窗讯息处理程式不予处理的所有讯息都要送到DefFrameProc,它在框架视窗讯息处理程式中取代了DefWindowProc。即使框架视窗讯息处理程式拦截了WM_MENUCHARWM_SETFOCUSWM_SIZE讯息,这些讯息也要被送到DefFrameProc中。

dedecms.com

所有未经处理的WM_COMMAND讯息也必须送给DefFrameProc。具体地说,FrameWndProc并不处理任何WM_COMMAND讯息,即使这些讯息是使用者在Windows子功能表的文件列表中选择文件时产生的(这些选项的wParam值是以IDM_FIRSTCHILD开始的)。这些讯息要传送到DefFrameProc,并在那里进行处理。 织梦内容管理系统

注意框架视窗并不需要维护它所建立的所有文件视窗的视窗代号清单。如果需要这些视窗代号(如处理功能表上的「Close All」选项时),可以使用EnumChildWindows得到它们。 本文来自织梦

子文件视窗
  内容来自dedecms

现在看一下HelloWndProc,它是用於显示「Hello, World!」的子文件视窗的视窗讯息处理程式。

内容来自dedecms

与用於多个视窗的视窗类别一样,所有在视窗讯息处理程式(或从该视窗讯息处理程式中呼叫的任何函式)中定义的静态变数由依据该视窗类别建立的所有视窗共用。 copyright dedecms

只有对於每个唯一於视窗的资料才必须采用非静态变数的方法来储存。这样的技术要用到视窗属性。另一种方法(我使用的方法)是使用预留的记忆体空间;可以在注册视窗类别时将WNDCLASS结构的cbWndExtra栏位设定为非零值以便预留这部分记忆体空间。

dedecms.com

MDIDEMO程式使用这个记忆体空间来储存一个指标,这个指标指向一块与HELLODATA结构大小相同的记忆体块。在处理WM_CREATE讯息时,HelloWndProc配置这块记忆体,初始化它的两个栏位(它们用於指定目前选中的功能表项和文字颜色),并用SetWindowLong将记忆体指标储存到预留的空间中。 dedecms.com

当处理改变文字颜色的WM_COMMAND讯息(回忆一下,这些讯息来自框架视窗讯息处理程式)时,HelloWndProc使用GetWindowLong获得包含HELLODATA结构的记忆体块的指标。利用这个结构,HelloWndProc清除原来对功能表项的选择,设定所选功能表项为选中状态,并储存新的颜色。

织梦内容管理系统

当视窗变成活动视窗或不活动的时候,文件视窗讯息处理程式都会收到WM_MDIACTIVATE讯息(lParam的值是否为这个视窗的代号表示了该视窗是活动的还是不活动的)。您也许还能记起MDIDEMO程式中有三个不同的功能表:当无文件时为MdiMenuInit;当「Hello」文件视窗是活动视窗时为MdiMenuHello;当「Rect」文件视窗为活动视窗时为MdiMenuRect

copyright dedecms

WM_MDIACTIVATE讯息为文件视窗提供了一个修改功能表的机会。如果lParam中含有本视窗的代号(意味著本视窗将变成活动的),那么HelloWndProc就将功能表改为MdiMenuHello。如果lParam中包含另一个视窗的代号,那么HelloWndProc将功能表改为MdiMenuInit本文来自织梦

HelloWndProc经由把WM_MDISETMENU讯息发送给客户视窗来修改功能表,客户视窗透过从目前功能表上删除文件列表并把它添加到一个新的功能表上来处理这个讯息。这就是文件列表从MdiMenuInit功能表(它在建立第一个文件时有效)传送到MdiMenuHello功能表中的方法。在MDI应用程式中不要用SetMenu函式改变功能表。 copyright dedecms

另一项工作涉及到「Color」子功能表上的选中旗标。像这样的程式选项对每个文件来说都是不同的,例如,可以在一个视窗中设定黑色文字,在另一个视窗中设定红色文字。功能表选中旗标应能反映出活动视窗中选择的选项。由於这种原因,HelloWndProc在视窗变成非活动视窗时清除选中功能表项的选中旗标,而当视窗变成活动视窗时设定适当功能表项的选中旗标。

织梦内容管理系统

WM_MDIACTIVATEwParamlParam值分别是失去活动和被启动视窗的代号。视窗讯息处理程式得到的第一个WM_MDIACTIVATE讯息的lParam参数被设定为目前视窗的代号。而当视窗被消除时,视窗讯息处理程式得到的最後一个讯息的lParam参数被设定为另一个值。当使用者从一个文件切换到另一个文件时,前一个文件视窗收到一个WM_MDIACTIVATE讯息,其lParam参数为第一个视窗的代号(此时,视窗讯息处理程式将功能表设定为MdiMenuInit);後一个文件视窗收到一个WM_MDIACTIVATE讯息,其lParam参数是第二个视窗的代号(此时,视窗讯息处理程式将功能表设定为MdiMenuHelloMdiMenuRect中适当的那个)。如果所有的视窗都关闭了,剩下的功能表就是MdiMenuInit本文来自织梦

当使用者从功能表中选择「Close」或「Close All」时,FrameWndProc给子视窗发送一个WM_QUERYENDSESSION讯息。HelloWndProc将显示一个讯息方块并询问使用者是否要关闭视窗,以此来处理WM_QUERYENDSESSIONWM_CLOSE讯息(在真实的应用程式中,讯息方块会询问是否需要储存档案)。如果使用者表示不能关闭视窗,那么视窗讯息处理程式传回0dedecms.com

WM_DESTROY讯息处理期间,HelloWndProc释放在WM_CREATE期间配置的记忆体块。

织梦内容管理系统

所有未经处理的讯息必须传送到用於内定处理的DefMDIChildProc(不是DefWindowProc)。不论子视窗讯息处理程式是否使用了这些讯息,有几个讯息必须被传送给DefMDIChildProc。这些讯息是:WM_CHILDACTIVATEWM_GETMINMAXINFOWM_MENUCHARWM_MOVEWM_SETFOCUSWM_SIZEWM_SYSCOMMANDcopyright dedecms

RectWndProcHelloWndProc非常相似,但是它比HelloWndProc要简单一些(不含功能表选项并且无需使用者确认是否关闭视窗),所以这里不对它进行讨论了。但应该注意到,在处理WM_SIZE之後RectWndProc使用了「break」叙述,所以WM_SIZE讯息被传给DefMDIChildProccopyright dedecms

结束处理
  copyright dedecms

WinMain中,MDIDEMO使用LoadMenu载入资源描述档中定义的三个功能表。一般说来,当功能表所在的视窗被清除时,Windows也要清除与之关联的功能表。对於Init功能表,应该清除那些没有联系到视窗的功能表。由於这个原因,MDIDEMOWinMain的末尾呼叫了两次DestroyMenu来清除「Hello」和「Rect」功能表。

copyright dedecms