代码示例:
// MDIAppDemo.cpp : Defines the entry point for the application.
//
#include "stdafx.h"
#include "MDIAppDemo.h"
#define ID_FIRSTWINDOW 50000
typedef struct tagHELLODATA
{
UINT iColorIndex;
COLORREF clrText;
} HELLODATA, *PHELLODATA;
typedef struct tagRECTDATA
{
short cxClient;
short cyClient;
}RECTDATA, *PRECTDATA;
// 前置函数申明
LRESULT CALLBACK FrameWndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK HelloWndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK RectWndProc(HWND, UINT, WPARAM, LPARAM);
BOOL CALLBACK CloseEnumProc(HWND, LPARAM);
//全局变量
TCHAR szFrameWndClass[] = _T("FrameWndClass");
TCHAR szHelloWndClass[] = _T("HelloWndClass");
TCHAR szRectWndClass[] = _T("RectWndClass");
HMENU hMenuInit;
HMENU hMenuInitWindow;
HMENU hMenuHello;
HMENU hMenuHelloWindow;
HMENU hMenuRect;
HMENU hMenuRectWindow;
HINSTANCE hInst;
int APIENTRY _tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
hInst = hInstance;
WNDCLASS wc;
//注册主框架类
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = FrameWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = sizeof(HANDLE);
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MDIAPPDEMO));
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE+1);
wc.lpszMenuName = NULL;
wc.lpszClassName = szFrameWndClass;
RegisterClass(&wc);
//注册Hello窗口类
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = HelloWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_IBEAM);
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wc.lpszMenuName = NULL;
wc.lpszClassName = szHelloWndClass;
RegisterClass(&wc);
//注册Rect窗口类
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = RectWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = sizeof(HANDLE);
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_CROSS);
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wc.lpszMenuName = NULL;
wc.lpszClassName = szRectWndClass;
RegisterClass(&wc);
//初始化菜单
hMenuInit = LoadMenu(hInstance, MAKEINTRESOURCE(IDR_INIT));
hMenuInitWindow = GetSubMenu(hMenuInit, 0);
hMenuHello = LoadMenu(hInstance, MAKEINTRESOURCE(IDR_HELLO));
hMenuHelloWindow = GetSubMenu(hMenuHello, 2);
hMenuRect = LoadMenu(hInstance, MAKEINTRESOURCE(IDR_RECT));
hMenuRectWindow = GetSubMenu(hMenuRect, 1);
HWND hWndFrame = CreateWindow(szFrameWndClass,
_T("MDIAppDemo"),
WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
hMenuInit,
hInstance,
NULL);
HWND hWndClient = GetWindow(hWndFrame, GW_CHILD);
ShowWindow(hWndFrame, nCmdShow);
UpdateWindow(hWndFrame);
// 主消息循坏
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
//清理工作
DestroyMenu(hMenuHello);
DestroyMenu(hMenuRect);
return (int) msg.wParam;
}
LRESULT CALLBACK FrameWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
static HWND hwndClient;
CLIENTCREATESTRUCT clientCreateStruct;
HWND hwndChild;
MDICREATESTRUCT mdiCreateStruct;
switch(uMsg)
{
case WM_CREATE:
clientCreateStruct.hWindowMenu = hMenuInitWindow;
clientCreateStruct.idFirstChild = ID_FIRSTWINDOW;
hwndClient = CreateWindow(_T("MDIClient"),
NULL,
WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE,
0,0,0,0, //注意:这里都是0!
hwnd,
(HMENU)1,
hInst,
(PSTR)(&clientCreateStruct));
return 0;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case IDM_FILE_NEWHELLO:
mdiCreateStruct.szClass = szHelloWndClass;
mdiCreateStruct.szTitle = _T("Hello Window");
mdiCreateStruct.hOwner = hInst;
mdiCreateStruct.x = CW_USEDEFAULT;
mdiCreateStruct.y = CW_USEDEFAULT;
mdiCreateStruct.cx = CW_USEDEFAULT;
mdiCreateStruct.cy = CW_USEDEFAULT;
mdiCreateStruct.style = 0;
mdiCreateStruct.lParam = 0;
hwndChild = (HWND)SendMessage(hwndClient, WM_MDICREATE, 0, (LPARAM)(LPMDICREATESTRUCT)&mdiCreateStruct);
return 0;
case IDM_FILE_NEWRECT:
mdiCreateStruct.szClass = szRectWndClass;
mdiCreateStruct.szTitle = _T("Rect Window");
mdiCreateStruct.hOwner = hInst;
mdiCreateStruct.x = CW_USEDEFAULT;
mdiCreateStruct.y = CW_USEDEFAULT;
mdiCreateStruct.cx = CW_USEDEFAULT;
mdiCreateStruct.cy = CW_USEDEFAULT;
mdiCreateStruct.style = 0;
mdiCreateStruct.lParam = 0;
hwndChild = (HWND)SendMessage(hwndClient, WM_MDICREATE, 0, (LPARAM)(LPMDICREATESTRUCT)&mdiCreateStruct);
return 0;
case IDM_FILE_CLOSE:
hwndChild = (HWND)SendMessage(hwndClient, WM_MDIGETACTIVE, 0, 0);
if(SendMessage(hwndChild, WM_QUERYENDSESSION, 0, 0))
SendMessage(hwndClient, WM_MDIDESTROY, (WPARAM)hwndChild, 0);
return 0;
case IDM_FILE_EXIT:
SendMessage(hwnd, WM_CLOSE, 0, 0);
return 0;
//窗口布局
case IDM_WINDOW_TILE:
SendMessage(hwndClient, WM_MDITILE, 0, 0);
return 0;
case IDM_WINDOW_CASCADE:
SendMessage(hwndClient, WM_MDICASCADE, 0, 0);
return 0;
case IDM_WINDOW_ARRANGEICONS:
SendMessage(hwndClient, WM_MDIICONARRANGE, 0, 0);
return 0;
case IDM_WINDOW_CLOSEALL:
EnumChildWindows(hwndClient, CloseEnumProc, 0);
return 0;
default:
hwndChild = (HWND)SendMessage(hwndClient, WM_MDIGETACTIVE, 0, 0);
if(IsWindow(hwndChild))
{
SendMessage(hwndChild, WM_COMMAND, wParam, lParam);
}
break;
}// end inner switch
break;
case WM_QUERYENDSESSION:
case WM_CLOSE:
SendMessage(hwnd, WM_COMMAND, IDM_WINDOW_CLOSEALL, 0);
//尝试关闭所有窗口
if(NULL != GetWindow(hwndClient, GW_CHILD))
{
//如果这个if语句体执行了,说明还有子窗口没有被关闭
return 0;
}
break;
case WM_DESTROY:
PostQuitMessage(0);
}// end outer switch
return DefFrameProc(hwnd, hwndClient, uMsg, wParam, lParam);
}
LRESULT CALLBACK HelloWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
static COLORREF clrTextArray[] = { RGB(0, 0, 0),
RGB(255, 0, 0),
RGB(0, 255, 0),
RGB(0, 0, 255),
RGB(255, 255, 255)
};
static HWND hwndClient, hwndFrame;
HMENU hFrameMenu;
PHELLODATA pHelloData;
HDC hdc;
PAINTSTRUCT ps;
RECT rect;
switch(uMsg)
{
case WM_CREATE:
pHelloData = (PHELLODATA)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(HELLODATA));
pHelloData->iColorIndex = IDM_COLOR_BLACK;
pHelloData->clrText = clrTextArray[0];
SetWindowLong(hwnd, GWL_USERDATA, (long)pHelloData);
hwndClient = GetParent(hwnd);
hwndFrame = GetParent(hwndClient);
return 0;
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
pHelloData = (PHELLODATA)GetWindowLong(hwnd, GWL_USERDATA);
SetTextColor(hdc, pHelloData->clrText);
GetClientRect(hwnd, &rect);
DrawText(hdc, _T("Hello World!"), -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
EndPaint(hwnd, &ps);
case WM_COMMAND:
switch(LOWORD(wParam))
{
//从IDM_COLOR_BLACK至IDM_COLOR_WHITE,其ID数值必须是连续的
case IDM_COLOR_BLACK:
case IDM_COLOR_RED:
case IDM_COLOR_GREEN:
case IDM_COLOR_BLUE:
case IDM_COLOR_WHITE:
pHelloData = (PHELLODATA)GetWindowLong(hwnd, GWL_USERDATA);
hFrameMenu = GetMenu(hwndFrame);
CheckMenuItem(hFrameMenu, pHelloData->iColorIndex, MF_UNCHECKED);
//对于菜单的WM_COMMAND消息,wParam高位为0,低位为菜单的ID
//所以此时wParam等于LOWORD(wParam)
pHelloData->iColorIndex = wParam;
CheckMenuItem(hFrameMenu, pHelloData->iColorIndex, MF_CHECKED);
pHelloData->clrText = clrTextArray[wParam - IDM_COLOR_BLACK];
InvalidateRect(hwnd, NULL, FALSE);
}
return 0;
//注意与WM_MDIGETACTIVE区分
case WM_MDIACTIVATE:
if(lParam == (LPARAM)hwnd)
SendMessage(hwndClient, WM_MDISETMENU, (WPARAM)hMenuHello, (LPARAM)hMenuHelloWindow);
pHelloData = (PHELLODATA)GetWindowLong(hwnd, GWL_USERDATA);
CheckMenuItem(hMenuHello, pHelloData->iColorIndex, (lParam == (LPARAM)hwnd) ? MF_CHECKED : MF_UNCHECKED);
//如果当前窗口失去焦点,则将菜单还原成初始菜单
if(lParam != (LPARAM)hwnd)
SendMessage(hwndClient, WM_MDISETMENU, (WPARAM)hMenuInit, (LPARAM)hMenuInitWindow);
DrawMenuBar(hwndFrame);
return 0;
case WM_QUERYENDSESSION:
case WM_CLOSE:
if(IDOK != MessageBox(hwnd,_T("OK to close window?"), _T("Hello"), MB_ICONQUESTION | MB_OKCANCEL))
return 0;
break;
case WM_DESTROY:
pHelloData = (PHELLODATA)GetWindowLong(hwnd, 0);
HeapFree(GetProcessHeap(), 0, pHelloData);
return 0;
}
return DefMDIChildProc(hwnd, uMsg, wParam, lParam);
}
BOOL CALLBACK CloseEnumProc(HWND hwnd, LPARAM lParam)
{
if(GetWindow(hwnd, GW_OWNER))
return TRUE;
SendMessage(GetParent(hwnd), WM_MDIRESTORE, (WPARAM)hwnd, 0);
if(!SendMessage(hwnd, WM_QUERYENDSESSION, 0, 0))
return TRUE;
SendMessage(GetParent(hwnd), WM_MDIDESTROY, (WPARAM)hwnd, 0);
return TRUE;
}
LRESULT CALLBACK RectWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
static HWND hwndClient, hwndFrame;
PRECTDATA pRectData;
int iLeft, iRight, iTop, iBottom;
short nRed, nGreen, nBlue;
HDC hdc;
PAINTSTRUCT ps;
HBRUSH hBrush;
switch(uMsg)
{
case WM_CREATE:
pRectData = (PRECTDATA)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RECTDATA));
SetWindowLong(hwnd, 0, (long)pRectData);
SetTimer(hwnd, 1, 250, NULL);
hwndClient = GetParent(hwnd);
hwndFrame = GetParent(hwndClient);
return 0;
case WM_SIZE:
if(wParam != SIZE_MINIMIZED)
{
pRectData = (PRECTDATA)GetWindowLong(hwnd, 0);
pRectData->cxClient = LOWORD(lParam);
pRectData->cyClient = HIWORD(lParam);
}
break;
case WM_TIMER:
pRectData = (PRECTDATA)GetWindowLong(hwnd, 0);
iLeft = rand() % pRectData->cxClient;
iRight = rand() % pRectData->cxClient;;
iTop = rand() % pRectData->cyClient;
iBottom = rand() % pRectData->cyClient;
nRed = rand() & 255;
nGreen = rand() & 255;
nBlue = rand() & 255;
hdc = GetDC(hwnd);
hBrush = CreateSolidBrush(RGB(nRed, nGreen, nBlue));
SelectObject(hdc, hBrush);
Rectangle(hdc, min(iLeft, iRight), min(iTop, iBottom), max(iLeft, iRight), max(iTop, iBottom));
ReleaseDC(hwnd, hdc);
DeleteObject(hBrush);
return 0;
case WM_PAINT:
InvalidateRect(hwnd, NULL, TRUE);
hdc = BeginPaint(hwnd, &ps);
EndPaint(hwnd, &ps);
return 0;
case WM_MDIACTIVATE:
if(lParam == (LPARAM)hwnd)
SendMessage(hwndClient, WM_MDISETMENU, (WPARAM)hMenuRect, (LPARAM)hMenuRectWindow);
else
SendMessage(hwndClient, WM_MDISETMENU, (WPARAM)hMenuInit, (LPARAM)hMenuInitWindow);
DrawMenuBar(hwndFrame);
return 0;
case WM_DESTROY:
pRectData = (PRECTDATA)GetWindowLong(hwnd, 0);
HeapFree(GetProcessHeap(), 0, pRectData);
KillTimer(hwnd, 1);
//因为子窗口的创建与子窗口本身无关,而是由Client窗口创建的,所以不需要发送PostQuitMessage()
return 0;
}
return DefMDIChildProc(hwnd, uMsg, wParam, lParam);
}