#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include "resource.h"
#include "filedlg.h"
#define INIT_MENU_POS 0
#define CHILD_MENU_POS 1
#define UNTITLED_FORMAT TEXT ("Untitled%d")
#define IDM_FIRSTCHILD 50000
LRESULT CALLBACK FrameWndProc (HWND, UINT, WPARAM, LPARAM);
BOOL CALLBACK CloseEnumProc (HWND, LPARAM);
LRESULT CALLBACK ChildWndProc (HWND, UINT, WPARAM, LPARAM);
/* structure for storing data unique to each child window */
typedef struct tagDOCDATA
{
TCHAR szFileName[MAX_PATH];
TCHAR szFileTitle[MAX_PATH];
BOOL bNeedSave;
}DOCDATA, *PDOCDATA;
/* global variables */
TCHAR szAppName[] = TEXT ("MDIDemo");
TCHAR szFrameClass[] = TEXT ("MdiFrame");
TCHAR szChildClass[] = TEXT ("MdiChild");
HINSTANCE hInst;
HMENU hMenuInit, hMenuChild;
HMENU hMenuInitWindow, hMenuChildWindow;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
HACCEL hAccel;
HWND hwndFrame, hwndClient;
MSG msg;
WNDCLASS wndclass;
hInst = hInstance;
/* Register the frame window class */
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = FrameWndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH) (COLOR_APPWORKSPACE + 1);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szFrameClass;
if (!RegisterClass (&wndclass))
{
MessageBox (NULL, TEXT ("This program requires Windows NT!"),
szAppName, MB_ICONERROR);
return 0;
}
/* Register the child window class */
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = ChildWndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = sizeof (HANDLE);
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szChildClass;
RegisterClass (&wndclass);
/* Obtain handles to menus & submenus */
hMenuInit = LoadMenu (hInstance, TEXT ("MdiMenuInit"));
hMenuChild = LoadMenu (hInstance, TEXT ("MdiMenuChild"));
hMenuInitWindow = GetSubMenu (hMenuInit, INIT_MENU_POS);
hMenuChildWindow = GetSubMenu (hMenuChild, CHILD_MENU_POS);
/* Load accelerator table */
hAccel = LoadAccelerators (hInstance, szAppName);
/* Create the frame window */
hwndFrame = CreateWindow (szFrameClass, szAppName,
WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, hMenuInit, hInstance, NULL);
hwndClient = GetWindow (hwndFrame, GW_CHILD);
ShowWindow (hwndFrame, iCmdShow);
UpdateWindow (hwndFrame);
/* Enter the modified message loop */
while (GetMessage (&msg, NULL, 0, 0))
{
if (!TranslateMDISysAccel (hwndClient, &msg) &&
!TranslateAccelerator (hwndFrame, hAccel, &msg))
{
TranslateMessage (&msg);
DispatchMessage (&msg);
}
}
/* Clean up by deleting unattached menus */
DestroyMenu (hMenuChild);
return msg.wParam;
}
LRESULT CALLBACK FrameWndProc (HWND hwnd, UINT message,
WPARAM wParam, LPARAM lParam)
{
static HWND hwndClient;
static int iTitleIndex;
CLIENTCREATESTRUCT clientcreate;
HWND hwndChild;
MDICREATESTRUCT mdicreate;
TCHAR szTitle[MAX_PATH] = { 0 };
TCHAR szFileName[MAX_PATH] = { 0 };
PDOCDATA pDocData;
switch (message)
{
case WM_CREATE: /* Create the client window */
clientcreate.hWindowMenu = hMenuInitWindow;
clientcreate.idFirstChild = IDM_FIRSTCHILD;
hwndClient = CreateWindow (TEXT ("MDICLIENT"), NULL,
WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE,
0, 0, 0, 0, hwnd, (HMENU) 1, hInst,
(PSTR) &clientcreate);
/* Init file open/save dialog structure */
FileDlgInit( hwnd );
return 0;
case WM_COMMAND:
switch (LOWORD (wParam))
{
case IDM_FILE_NEW: /* Create/Open a new child window */
case IDM_FILE_OPEN:
if ((LOWORD (wParam) == IDM_FILE_OPEN) )
{
if( !FileOpenDlg (hwnd, szFileName, szTitle) )
return 0;
}
else
_stprintf( szTitle, UNTITLED_FORMAT, ++iTitleIndex );
mdicreate.szClass = szChildClass;
mdicreate.szTitle = szTitle;
mdicreate.hOwner = hInst;
mdicreate.x = CW_USEDEFAULT;
mdicreate.y = CW_USEDEFAULT;
mdicreate.cx = CW_USEDEFAULT;
mdicreate.cy = CW_USEDEFAULT;
mdicreate.style = 0;
mdicreate.lParam = (LPARAM)szFileName;
hwndChild = (HWND) SendMessage (hwndClient,
WM_MDICREATE, 0,
(LPARAM) (LPMDICREATESTRUCT) &mdicreate);
return 0;
case IDM_FILE_SAVE: /* Save the active document */
hwndChild = (HWND) SendMessage (hwndClient,
WM_MDIGETACTIVE, 0, 0);
pDocData = (PDOCDATA)GetWindowLong (hwndChild, 0);
lstrcpy( szTitle, pDocData->szFileTitle );
lstrcpy( szFileName, pDocData->szFileName );
if (FileSaveDlg (hwnd, szFileName, szTitle))
{
}
return 0;
case IDM_FILE_CLOSE: /* Close the active window */
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_APP_EXIT: /* Exit the program */
SendMessage (hwnd, WM_CLOSE, 0, 0);
return 0;
/* messages for arranging windows */
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_ARRANGE:
SendMessage (hwndClient, WM_MDIICONARRANGE, 0, 0);
return 0;
case IDM_WINDOW_CLOSEALL: /* Attempt to close all children */
EnumChildWindows (hwndClient, CloseEnumProc, 0);
return 0;
default: /* Pass to active child... */
hwndChild = (HWND) SendMessage (hwndClient,
WM_MDIGETACTIVE, 0, 0);
if (IsWindow (hwndChild))
SendMessage (hwndChild, WM_COMMAND, wParam, lParam);
break; /* ...and then to DefFrameProc */
}
break;
case WM_QUERYENDSESSION:
case WM_CLOSE: /* Attempt to close all children */
SendMessage (hwnd, WM_COMMAND, IDM_WINDOW_CLOSEALL, 0);
if (NULL != GetWindow (hwndClient, GW_CHILD))
return 0;
break; /* i.e., call DefFrameProc */
case WM_DESTROY:
PostQuitMessage (0);
return 0;
}
/* Pass unprocessed messages to DefFrameProc (not DefWindowProc) */
return DefFrameProc (hwnd, hwndClient, message, wParam, lParam);
}
BOOL CALLBACK CloseEnumProc (HWND hwnd, LPARAM lParam)
{
if (GetWindow (hwnd, GW_OWNER)) /* Check for icon title */
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 ChildWndProc (HWND hwnd, UINT message,
WPARAM wParam, LPARAM lParam)
{
static HWND hwndClient, hwndFrame;
HDC hdc;
HMENU hMenu;
PDOCDATA pDocData;
PAINTSTRUCT ps;
RECT rect;
LPCREATESTRUCT lpcs;
LPMDICREATESTRUCT lpmcs;
switch (message)
{
case WM_CREATE:
lpcs = (LPCREATESTRUCT) lParam; /* structure with creation data */
lpmcs = (LPMDICREATESTRUCT) lpcs->lpCreateParams;
/* Allocate memory for window private data */
pDocData = (PDOCDATA) HeapAlloc (GetProcessHeap (),
HEAP_ZERO_MEMORY, sizeof (DOCDATA));
GetWindowText (hwnd, pDocData->szFileTitle, MAX_PATH);
lstrcpy( pDocData->szFileName, (LPCTSTR)lpmcs->lParam );
SetWindowLong (hwnd, 0, (long) pDocData);
/* Save some window handles */
hwndClient = GetParent (hwnd);
hwndFrame = GetParent (hwndClient);
return 0;
case WM_COMMAND:
switch (LOWORD (wParam))
{
default:
break;
}
return 0;
case WM_PAINT:
/* Paint the window */
hdc = BeginPaint (hwnd, &ps);
pDocData = (PDOCDATA) GetWindowLong (hwnd, 0);
SetTextColor (hdc, RGB(0,0,0));
GetClientRect (hwnd, &rect);
DrawText (hdc, pDocData->szFileTitle, -1, &rect,
DT_SINGLELINE | DT_CENTER | DT_VCENTER);
EndPaint (hwnd, &ps);
return 0;
case WM_MDIACTIVATE:
/* Set the Hello menu if gaining focus */
if (lParam == (LPARAM) hwnd)
SendMessage (hwndClient, WM_MDISETMENU,
(WPARAM) hMenuChild, (LPARAM) hMenuChildWindow);
/* Set the Init menu if losing focus */
if (lParam != (LPARAM) hwnd)
SendMessage (hwndClient, WM_MDISETMENU, (WPARAM) hMenuInit,
(LPARAM) hMenuInitWindow);
DrawMenuBar (hwndFrame);
return 0;
case WM_QUERYENDSESSION:
case WM_CLOSE:
pDocData = (PDOCDATA) GetWindowLong (hwnd, 0);
if (IDOK != MessageBox (hwnd, TEXT ("OK to close window?"),
pDocData->szFileTitle,
MB_ICONQUESTION | MB_OKCANCEL))
return 0;
break; /* i.e., call DefMDIChildProc */
case WM_DESTROY:
pDocData = (PDOCDATA) GetWindowLong (hwnd, 0);
HeapFree (GetProcessHeap (), 0, pDocData);
return 0;
}
/* Pass unprocessed message to DefMDIChildProc */
return DefMDIChildProc (hwnd, message, wParam, lParam);
}