使用Win32 API 实现MDI程序

http://www.codeproject.com/KB/winsdk/Sigma.aspx 

使用Win32 API 实现MDI程序


 介绍

    这篇文章讲解了如何使用Win32 API创建一个基本的MDI程序。在这个例子中,被创建的MDI子窗体显示了如下

操作系统信息:计算机名、操作系统版本、补丁版本,CPU个数。

    此外,这篇文章还包括:

    *当打开子窗体时,更新菜单。

    *创建多分割区域的状态栏。

    *添加、移除托盘。

    *使用邮槽在进程间通讯。

基于Win32 API 创建MDI程序

    在WinMain()函数中,创建MDI框架窗体。在WM_CREATE处理代码中,创建了MDI的客户区。所有的子窗体

在客户区中浮动。

CLIENTCREATESTRUCT MDIClientCreateStruct;
// Structure to be used for MDI client area
switch(message)
{
    case WM_CREATE:
    // On creation of main frame, create the MDI client area
        MDIClientCreateStruct.hWindowMenu = NULL; 
        MDIClientCreateStruct.idFirstChild = IDM_FIRSTCHILD; 
        ghMDIClientArea = CreateWindow(TEXT("MDICLIENT"), // predefined value for
                                                          // MDI client area
                                  NULL, // no caption required
                                   WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE, 
                                   0, // No need to give any x/y or height/width.
                                   0,
                                   0,
                                   0,
                                   hwnd, 
                                   NULL,
                                   ghInstance,
                                   (void*) &MDIClientCreateStruct);

MDICLIENT 是第一个参数,预先被Windows定义。CreateWindow的最后一个参数是CLIENTCREATESTRUCT类型

的变量的指针。CLIENTCREATESTRUCT有两个成员:一个是程序窗体的菜单句柄,另一个是第一个子窗体的标识符。

当得到了命令消息ID_INFORMATION_SYSTEMINFORMATION 后,,创建显示系统信息的MDI子窗体。在堆上创

CSystemInfo对象。G_pSystemInfo对象被用来创建窗体和填充树控件。CSystemInfo::CreateSystemInfoWindow()

注册了子窗体并创建了MDI子窗体。

MDICREATESTRUCT MDIChildCreateStruct;
MDIChildCreateStruct.szClass = TEXT("SigmaSystemInfoWnd");
MDIChildCreateStruct.szTitle = TEXT("System Information");
MDIChildCreateStruct.hOwner = ghInstance;
MDIChildCreateStruct.x = CW_USEDEFAULT;
MDIChildCreateStruct.y = CW_USEDEFAULT;
MDIChildCreateStruct.cx = CW_USEDEFAULT;
MDIChildCreateStruct.cy = CW_USEDEFAULT;
MDIChildCreateStruct.style = 0;
MDIChildCreateStruct.lParam = 0;
//
m_hwndSystemInformation = (HWND) SendMessage(ghMDIClientArea,
                                   WM_MDICREATE, 
                                   0,
                                   (LPARAM) (LPMDICREATESTRUCT) &MDIChildCreateStruct);
// return if its not possible to create the child window
if(NULL == m_hwndSystemInformation)
{
    return 0;
}

MDICREATESTRUCT用来设置子窗体参数。SendMessage最后一个参数是它的指针。SendMessage发送WM_MDICREATE消息到主框架窗体的客户区。

一些类的功能

CSystemInfo:这个类有两个成员:CSystemInfoData成员,CSystemInfoView成员。在这个类中,创建了这个子窗体。

CSystemInfoData;这个类储存了树控件要显示的数据。

CSystemInfoView:这个类初始化了树控件,然后将CSystemInfoData中的数据填充到Tree中。

当子窗体被激活时,创建并改变菜单

框架窗体的菜单的资源是IDR_MAINFRAME_MENU.这个菜单在WinMain中加载。

ghMainFrameMenu  = LoadMenu(hInstance, MAKEINTRESOURCE(IDR_MAINFRAME_MENU));
ghSysInfoMenu    = LoadMenu(hInstance, MAKEINTRESOURCE(IDR_SYSINFO_MENU));
DWORD derror     = GetLastError();
//Create the main MDI frame window
ghwndMainFrame = CreateWindow(gszSigmaFrameClassName, 
                          gszAppName, 
                          WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
                          CW_USEDEFAULT,   // allows system choose an x position
                          CW_USEDEFAULT,   // allows system choose a y position
                          CW_USEDEFAULT,   // width, CW_USEDEFAULT allows system to
                                           // choose height and width
                          CW_USEDEFAULT,   // height, CW_USEDEFAULT ignores heights
                                           // as this is set by setting
                                            // CW_USEDEFAULT in width above.
                          NULL,                     // handle to parent window
                          ghMainFrameMenu, // handle to menu
                          hInstance,       // handle to the instance of module
                          NULL);           // Long pointer to a value to be passed
                                           // to the window through the
                                           // CREATESTRUCT structure passed in the
                                           // lParam parameter the WM_CREATE message


子窗口菜单是IDR_SYSINFO_MENU。在子窗体的窗口函数中(SigmaSystemInfoWndProc)中有WM_MDIACTIVATE,此段代码用来修改子窗的菜单,

名为Window的菜单被添加。当子窗体失去焦点时,它将设置而框架窗体的菜单。DrawMenuBar()需要调用SendMessage发送WM_MDISETMENU

消息。一旦子窗体被打开,它的菜单由于调用EnableMenuItem而变灰。

case WM_MDIACTIVATE:
{
HWND hwndClient = GetParent(hWnd);
HWND hwndFrame  = GetParent(hwndClient);
HMENU hSysInfoWindowMenu = GetSubMenu(ghSysInfoMenu, SIGMA_SYSINFO_WINDOW_MENU_POS) ;
                           
// Set the system info menu when getting activated
if (lParam == (LPARAM) hWnd)
{
         SendMessage(hwndClient, 
                 WM_MDISETMENU,
                 (WPARAM) ghSysInfoMenu, 
                 (LPARAM) hSysInfoWindowMenu);
         //Gray out the system information menu item
         EnableMenuItem(ghSysInfoMenu, ID_INFORMATION_SYSTEMINFORMATION, MF_GRAYED);
}
                           
// Set the frame window menu when losing focus
if (lParam != (LPARAM) hWnd)
{
          SendMessage(hwndClient, 
                 WM_MDISETMENU, 
                 (WPARAM) ghMainFrameMenu,
                 (LPARAM) NULL) ;
}
                           
// call DrawMenuBar after the menu items are set
DrawMenuBar(hwndFrame);

状态栏和重排列的MDI客户区

WinMain函数中,CreateStatusBar函数创建了状态栏。CreateWindowEx使用STATUSCLASSNAME创建了状态栏,如下所示

//Create the status bar
ghwndStatusBar = CreateWindowEx(0, // extended not required
                          STATUSCLASSNAME, // status bar class name, equivalent to
                                           // "msctls_statusbar32"
                          "", //caption not required
                          WS_CHILD | WS_VISIBLE,
                          -100, // x
                          -100, // y
                          10, // width
                          10, // height
                          ghwndMainFrame,
                          NULL,
                          (HINSTANCE) GetWindowLong (ghwndMainFrame, GWL_HINSTANCE),
                          NULL);

调用SendMessage(ghwndStatusBar, SB_SETPARTS, (WPARAM)nParts, (LPARAM)lpParts).详细过程如下:

//Create parts to the status bar
RECT rcClient;
LPINT lpParts = NULL;
int nWidth = 0;
int nParts = SIGMA_STATUSBAR_PARTS;
         
// Get the coordinates of the parent window's client area.
GetClientRect(ghwndMainFrame, &rcClient);
         
// Allocate an array for holding the right edge coordinates.
HLOCAL hloc = NULL;
hloc = LocalAlloc(LHND, sizeof(int) * nParts);
lpParts = (int *)LocalLock(hloc);
         
// Calculate the right edge coordinate for each part, and
// copy the coordinates to the array.
nWidth = rcClient.right / nParts;
for (int i = 0; i < nParts; i++) 
{ 
         lpParts[i] = nWidth;
         nWidth += nWidth;
}
         
// Create status bar parts.
SendMessage(ghwndStatusBar, SB_SETPARTS, (WPARAM)nParts, (LPARAM)lpParts);
         
// Free the array
LocalUnlock(hloc);
LocalFree(hloc);

添加系统托盘

WinMain函数中,调用AddSysTrayIcon函数创建系统托盘。Shell_NotifyIcon添加了系统托盘的图标。

NOTIFYICONDATA nid = {0};
nid.cbSize = sizeof(nid);
nid.uID = SIGMA_SYSTRAY_ICON_ID;      // 0 to 12 are reserved and should not be used.
nid.uFlags = NIF_ICON | NIF_TIP | NIF_MESSAGE;
nid.hIcon = LoadIcon(ghInstance, MAKEINTRESOURCE(IDI_SIGMA_MAIN_ICON));
                  strcpy(nid.szTip, "Sigma");
                  nid.hWnd = ghwndMainFrame;
                  nid.uCallbackMessage = WM_SIGMA_SYSTRAY_MSG;
//Add the notification to the tray
Shell_NotifyIcon(NIM_ADD, &nid);

当关闭程序时,调用Shell_Notify(NIM_DELETE,&nid)移除托盘图标。

使用邮槽进行进程间通讯(IPC with Mailslot IPC = inter-process communication)

Me:MDI窗体没有关系,不翻译了。

额外信息

*调用InitCommonControlsEx()函数初始化通用控件。这里创建了tree控件。

*框架窗体WM_SIZE的消息处理,不能调用DefFrameProc。因为调用DefFrameProc函数将引起MDI客户

区改变大小且重写状态栏。

*程序仅在XP SP3下通过测试。

你可能感兴趣的:(使用Win32 API 实现MDI程序)