代码示例:
// 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); }