xref: /reactos/modules/rostests/tests/mdi/mdi.c (revision 40462c92)
1 /*
2   Thanks to theForger from winprog.org
3 */
4 #include <windows.h>
5 #include <commctrl.h>
6 
7 #include <string.h>
8 #include "resource.h"
9 
10 const char g_szClassName[] = "myWindowClass";
11 const char g_szChildClassName[] = "myMDIChildWindowClass";
12 
13 #define IDC_MAIN_MDI	101
14 #define IDC_MAIN_TOOL	102
15 #define IDC_MAIN_STATUS	103
16 
17 #define IDC_CHILD_EDIT	101
18 
19 #define ID_MDI_FIRSTCHILD 50000
20 
21 HWND g_hMDIClient = NULL;
22 HWND g_hMainWindow = NULL;
23 
24 BOOL LoadTextFileToEdit(HWND hEdit, LPCTSTR pszFileName)
25 {
26 	HANDLE hFile;
27 	BOOL bSuccess = FALSE;
28 
29 	hFile = CreateFile(pszFileName, GENERIC_READ, FILE_SHARE_READ, NULL,
30 		OPEN_EXISTING, 0, NULL);
31 	if(hFile != INVALID_HANDLE_VALUE)
32 	{
33 		DWORD dwFileSize;
34 
35 		dwFileSize = GetFileSize(hFile, NULL);
36 		if(dwFileSize != 0xFFFFFFFF)
37 		{
38 			LPSTR pszFileText;
39 
40 			pszFileText = GlobalAlloc(GPTR, dwFileSize + 1);
41 			if(pszFileText != NULL)
42 			{
43 				DWORD dwRead;
44 
45 				if(ReadFile(hFile, pszFileText, dwFileSize, &dwRead, NULL))
46 				{
47 					pszFileText[dwFileSize] = 0; // Add null terminator
48 					if(SetWindowText(hEdit, pszFileText))
49 						bSuccess = TRUE; // It worked!
50 				}
51 				GlobalFree(pszFileText);
52 			}
53 		}
54 		CloseHandle(hFile);
55 	}
56 	return bSuccess;
57 }
58 
59 BOOL SaveTextFileFromEdit(HWND hEdit, LPCTSTR pszFileName)
60 {
61 	HANDLE hFile;
62 	BOOL bSuccess = FALSE;
63 
64 	hFile = CreateFile(pszFileName, GENERIC_WRITE, 0, NULL,
65 		CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
66 	if(hFile != INVALID_HANDLE_VALUE)
67 	{
68 		DWORD dwTextLength;
69 
70 		dwTextLength = GetWindowTextLength(hEdit);
71 		// No need to bother if there's no text.
72 		if(dwTextLength > 0)
73 		{
74 			LPSTR pszText;
75 			DWORD dwBufferSize = dwTextLength + 1;
76 
77 			pszText = GlobalAlloc(GPTR, dwBufferSize);
78 			if(pszText != NULL)
79 			{
80 				if(GetWindowText(hEdit, pszText, dwBufferSize))
81 				{
82 					DWORD dwWritten;
83 
84 					if(WriteFile(hFile, pszText, dwTextLength, &dwWritten, NULL))
85 						bSuccess = TRUE;
86 				}
87 				GlobalFree(pszText);
88 			}
89 		}
90 		CloseHandle(hFile);
91 	}
92 	return bSuccess;
93 }
94 
95 void DoFileOpen(HWND hwnd)
96 {
97 	OPENFILENAME ofn;
98 	char szFileName[MAX_PATH] = "";
99 
100 	ZeroMemory(&ofn, sizeof(ofn));
101 
102 	ofn.lStructSize = sizeof(ofn);
103 	ofn.hwndOwner = hwnd;
104 	ofn.lpstrFilter = "Text Files (*.txt)\0*.txt\0All Files (*.*)\0*.*\0";
105 	ofn.lpstrFile = szFileName;
106 	ofn.nMaxFile = MAX_PATH;
107 	ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
108 	ofn.lpstrDefExt = "txt";
109 
110 	if(GetOpenFileName(&ofn))
111 	{
112 		HWND hEdit = GetDlgItem(hwnd, IDC_CHILD_EDIT);
113 		if(LoadTextFileToEdit(hEdit, szFileName))
114 		{
115 			SendDlgItemMessage(g_hMainWindow, IDC_MAIN_STATUS, SB_SETTEXT, 0, (LPARAM)"Opened...");
116 			SendDlgItemMessage(g_hMainWindow, IDC_MAIN_STATUS, SB_SETTEXT, 1, (LPARAM)szFileName);
117 
118 			SetWindowText(hwnd, szFileName);
119 		}
120 	}
121 }
122 
123 void DoFileSave(HWND hwnd)
124 {
125 	OPENFILENAME ofn;
126 	char szFileName[MAX_PATH] = "";
127 
128 	ZeroMemory(&ofn, sizeof(ofn));
129 
130 	ofn.lStructSize = sizeof(ofn);
131 	ofn.hwndOwner = hwnd;
132 	ofn.lpstrFilter = "Text Files (*.txt)\0*.txt\0All Files (*.*)\0*.*\0";
133 	ofn.lpstrFile = szFileName;
134 	ofn.nMaxFile = MAX_PATH;
135 	ofn.lpstrDefExt = "txt";
136 	ofn.Flags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
137 
138 	if(GetSaveFileName(&ofn))
139 	{
140 		HWND hEdit = GetDlgItem(hwnd, IDC_CHILD_EDIT);
141 		if(SaveTextFileFromEdit(hEdit, szFileName))
142 		{
143 			SendDlgItemMessage(g_hMainWindow, IDC_MAIN_STATUS, SB_SETTEXT, 0, (LPARAM)"Saved...");
144 			SendDlgItemMessage(g_hMainWindow, IDC_MAIN_STATUS, SB_SETTEXT, 1, (LPARAM)szFileName);
145 
146 			SetWindowText(hwnd, szFileName);
147 		}
148 	}
149 }
150 
151 HWND CreateNewMDIChild(HWND hMDIClient)
152 {
153 	MDICREATESTRUCT mcs;
154 	HWND hChild;
155 
156 	mcs.szTitle = "[Untitled]";
157 	mcs.szClass = g_szChildClassName;
158 	mcs.hOwner  = GetModuleHandle(NULL);
159 	mcs.x = mcs.cx = CW_USEDEFAULT;
160 	mcs.y = mcs.cy = CW_USEDEFAULT;
161 	mcs.style = MDIS_ALLCHILDSTYLES;
162 
163 	hChild = (HWND)SendMessage(hMDIClient, WM_MDICREATE, 0, (LPARAM)&mcs);
164 	if(!hChild)
165 	{
166 		MessageBox(hMDIClient, "MDI Child creation failed.", "Oh Oh...",
167 			MB_ICONEXCLAMATION | MB_OK);
168 	}
169 	return hChild;
170 }
171 
172 LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
173 {
174 	switch(msg)
175 	{
176 		case WM_CREATE:
177 		{
178 			HWND hTool;
179 			TBBUTTON tbb[3];
180 			TBADDBITMAP tbab;
181 
182 			HWND hStatus;
183 			int statwidths[] = {100, -1};
184 
185 			CLIENTCREATESTRUCT ccs;
186 
187 			// Create MDI Client
188 
189 			// Find window menu where children will be listed
190 			ccs.hWindowMenu  = GetSubMenu(GetMenu(hwnd), 2);
191 			ccs.idFirstChild = ID_MDI_FIRSTCHILD;
192 
193 			g_hMDIClient = CreateWindowEx(WS_EX_CLIENTEDGE, "mdiclient", NULL,
194 				WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL | WS_VISIBLE,
195 				CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
196 				hwnd, (HMENU)IDC_MAIN_MDI, GetModuleHandle(NULL), (LPVOID)&ccs);
197 
198 			if(g_hMDIClient == NULL)
199 				MessageBox(hwnd, "Could not create MDI client.", "Error", MB_OK | MB_ICONERROR);
200 
201 			// Create Toolbar
202 
203 			hTool = CreateWindowEx(0, TOOLBARCLASSNAME, NULL, WS_CHILD | WS_VISIBLE, 0, 0, 0, 0,
204 				hwnd, (HMENU)IDC_MAIN_TOOL, GetModuleHandle(NULL), NULL);
205 			if(hTool == NULL)
206 				MessageBox(hwnd, "Could not create tool bar.", "Error", MB_OK | MB_ICONERROR);
207 
208 			// Send the TB_BUTTONSTRUCTSIZE message, which is required for
209 			// backward compatibility.
210 			SendMessage(hTool, TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0);
211 
212 			tbab.hInst = HINST_COMMCTRL;
213 			tbab.nID = IDB_STD_SMALL_COLOR;
214 			SendMessage(hTool, TB_ADDBITMAP, 0, (LPARAM)&tbab);
215 
216 			ZeroMemory(tbb, sizeof(tbb));
217 			tbb[0].iBitmap = STD_FILENEW;
218 			tbb[0].fsState = TBSTATE_ENABLED;
219 			tbb[0].fsStyle = TBSTYLE_BUTTON;
220 			tbb[0].idCommand = ID_FILE_NEW;
221 
222 			tbb[1].iBitmap = STD_FILEOPEN;
223 			tbb[1].fsState = TBSTATE_ENABLED;
224 			tbb[1].fsStyle = TBSTYLE_BUTTON;
225 			tbb[1].idCommand = ID_FILE_OPEN;
226 
227 			tbb[2].iBitmap = STD_FILESAVE;
228 			tbb[2].fsState = TBSTATE_ENABLED;
229 			tbb[2].fsStyle = TBSTYLE_BUTTON;
230 			tbb[2].idCommand = ID_FILE_SAVEAS;
231 
232 			SendMessage(hTool, TB_ADDBUTTONS, sizeof(tbb)/sizeof(TBBUTTON), (LPARAM)&tbb);
233 
234 			// Create Status bar
235 
236 			hStatus = CreateWindowEx(0, STATUSCLASSNAME, NULL,
237 				WS_CHILD | WS_VISIBLE | SBARS_SIZEGRIP, 0, 0, 0, 0,
238 				hwnd, (HMENU)IDC_MAIN_STATUS, GetModuleHandle(NULL), NULL);
239 
240 			SendMessage(hStatus, SB_SETPARTS, sizeof(statwidths)/sizeof(int), (LPARAM)statwidths);
241 			SendMessage(hStatus, SB_SETTEXT, 0, (LPARAM)"Hi there :)");
242 		}
243 		break;
244 		case WM_SIZE:
245 		{
246 			HWND hTool;
247 			RECT rcTool;
248 			int iToolHeight;
249 
250 			HWND hStatus;
251 			RECT rcStatus;
252 			int iStatusHeight;
253 
254 			HWND hMDI;
255 			int iMDIHeight;
256 			RECT rcClient;
257 
258 			// Size toolbar and get height
259 
260 			hTool = GetDlgItem(hwnd, IDC_MAIN_TOOL);
261 			SendMessage(hTool, TB_AUTOSIZE, 0, 0);
262 
263 			GetWindowRect(hTool, &rcTool);
264 			iToolHeight = rcTool.bottom - rcTool.top;
265 
266 			// Size status bar and get height
267 
268 			hStatus = GetDlgItem(hwnd, IDC_MAIN_STATUS);
269 			SendMessage(hStatus, WM_SIZE, 0, 0);
270 
271 			GetWindowRect(hStatus, &rcStatus);
272 			iStatusHeight = rcStatus.bottom - rcStatus.top;
273 
274 			// Calculate remaining height and size edit
275 
276 			GetClientRect(hwnd, &rcClient);
277 
278 			iMDIHeight = rcClient.bottom - iToolHeight - iStatusHeight;
279 
280 			hMDI = GetDlgItem(hwnd, IDC_MAIN_MDI);
281 			SetWindowPos(hMDI, NULL, 0, iToolHeight, rcClient.right, iMDIHeight, SWP_NOZORDER);
282 		}
283 		break;
284 		case WM_CLOSE:
285 			DestroyWindow(hwnd);
286 		break;
287 		case WM_DESTROY:
288 			PostQuitMessage(0);
289 		break;
290 		case WM_COMMAND:
291 			switch(LOWORD(wParam))
292 			{
293 				case ID_FILE_EXIT:
294 					PostMessage(hwnd, WM_CLOSE, 0, 0);
295 				break;
296 				case ID_FILE_NEW:
297 					CreateNewMDIChild(g_hMDIClient);
298 				break;
299 				case ID_FILE_OPEN:
300 				{
301 					HWND hChild = CreateNewMDIChild(g_hMDIClient);
302 					if(hChild)
303 					{
304 						DoFileOpen(hChild);
305 					}
306 				}
307 				break;
308 				case ID_FILE_CLOSE:
309 				{
310 					HWND hChild = (HWND)SendMessage(g_hMDIClient, WM_MDIGETACTIVE,0,0);
311 					if(hChild)
312 					{
313 						SendMessage(hChild, WM_CLOSE, 0, 0);
314 					}
315 				}
316 				break;
317 				case ID_WINDOW_TILE:
318 					SendMessage(g_hMDIClient, WM_MDITILE, 0, 0);
319 				break;
320 				case ID_WINDOW_CASCADE:
321 					SendMessage(g_hMDIClient, WM_MDICASCADE, 0, 0);
322 				break;
323 				default:
324 				{
325 					if(LOWORD(wParam) >= ID_MDI_FIRSTCHILD)
326 					{
327 						DefFrameProc(hwnd, g_hMDIClient, WM_COMMAND, wParam, lParam);
328 					}
329 					else
330 					{
331 						HWND hChild = (HWND)SendMessage(g_hMDIClient, WM_MDIGETACTIVE,0,0);
332 						if(hChild)
333 						{
334 							SendMessage(hChild, WM_COMMAND, wParam, lParam);
335 						}
336 					}
337 				}
338 			}
339 		break;
340 		default:
341 			return DefFrameProc(hwnd, g_hMDIClient, msg, wParam, lParam);
342 	}
343 	return 0;
344 }
345 
346 LRESULT CALLBACK MDIChildWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
347 {
348 	switch(msg)
349 	{
350 		case WM_CREATE:
351 		{
352 			HFONT hfDefault;
353 			HWND hEdit;
354 
355 			// Create Edit Control
356 
357 			hEdit = CreateWindowEx(WS_EX_CLIENTEDGE, "EDIT", "",
358 				WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_HSCROLL | ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL,
359 				0, 0, 100, 100, hwnd, (HMENU)IDC_CHILD_EDIT, GetModuleHandle(NULL), NULL);
360 			if(hEdit == NULL)
361 				MessageBox(hwnd, "Could not create edit box.", "Error", MB_OK | MB_ICONERROR);
362 
363 			hfDefault = GetStockObject(DEFAULT_GUI_FONT);
364 			SendMessage(hEdit, WM_SETFONT, (WPARAM)hfDefault, MAKELPARAM(FALSE, 0));
365 		}
366 		break;
367 		case WM_MDIACTIVATE:
368 		{
369 			HMENU hMenu, hFileMenu;
370 			UINT EnableFlag;
371 
372 			hMenu = GetMenu(g_hMainWindow);
373 			if(hwnd == (HWND)lParam)
374 			{	   //being activated, enable the menus
375 				EnableFlag = MF_ENABLED;
376 			}
377 			else
378 			{						   //being de-activated, gray the menus
379 				EnableFlag = MF_GRAYED;
380 			}
381 
382 			EnableMenuItem(hMenu, 1, MF_BYPOSITION | EnableFlag);
383 			EnableMenuItem(hMenu, 2, MF_BYPOSITION | EnableFlag);
384 
385 			hFileMenu = GetSubMenu(hMenu, 0);
386 			EnableMenuItem(hFileMenu, ID_FILE_SAVEAS, MF_BYCOMMAND | EnableFlag);
387 
388 			EnableMenuItem(hFileMenu, ID_FILE_CLOSE, MF_BYCOMMAND | EnableFlag);
389 			EnableMenuItem(hFileMenu, ID_FILE_CLOSEALL, MF_BYCOMMAND | EnableFlag);
390 
391 			DrawMenuBar(g_hMainWindow);
392 		}
393 		break;
394 		case WM_COMMAND:
395 			switch(LOWORD(wParam))
396 			{
397 				case ID_FILE_OPEN:
398 					DoFileOpen(hwnd);
399 				break;
400 				case ID_FILE_SAVEAS:
401 					DoFileSave(hwnd);
402 				break;
403 				case ID_EDIT_CUT:
404 					SendDlgItemMessage(hwnd, IDC_CHILD_EDIT, WM_CUT, 0, 0);
405 				break;
406 				case ID_EDIT_COPY:
407 					SendDlgItemMessage(hwnd, IDC_CHILD_EDIT, WM_COPY, 0, 0);
408 				break;
409 				case ID_EDIT_PASTE:
410 					SendDlgItemMessage(hwnd, IDC_CHILD_EDIT, WM_PASTE, 0, 0);
411 				break;
412 			}
413 		break;
414 		case WM_SIZE:
415 		{
416 			HWND hEdit;
417 			RECT rcClient;
418 
419 			// Calculate remaining height and size edit
420 
421 			GetClientRect(hwnd, &rcClient);
422 
423 			hEdit = GetDlgItem(hwnd, IDC_CHILD_EDIT);
424 			SetWindowPos(hEdit, NULL, 0, 0, rcClient.right, rcClient.bottom, SWP_NOZORDER);
425 		}
426 		return DefMDIChildProc(hwnd, msg, wParam, lParam);
427 		default:
428 			return DefMDIChildProc(hwnd, msg, wParam, lParam);
429 
430 	}
431 	return 0;
432 }
433 
434 BOOL SetUpMDIChildWindowClass(HINSTANCE hInstance)
435 {
436 	WNDCLASSEX wc;
437 
438 	wc.cbSize		 = sizeof(WNDCLASSEX);
439 	wc.style		 = CS_HREDRAW | CS_VREDRAW;
440 	wc.lpfnWndProc	 = MDIChildWndProc;
441 	wc.cbClsExtra	 = 0;
442 	wc.cbWndExtra	 = 0;
443 	wc.hInstance	 = hInstance;
444 	wc.hIcon		 = LoadIcon(NULL, (LPCTSTR)IDI_APPLICATION);
445 	wc.hCursor		 = LoadCursor(NULL, (LPCTSTR)IDC_ARROW);
446 	wc.hbrBackground = (HBRUSH)(COLOR_3DFACE+1);
447 	wc.lpszMenuName  = NULL;
448 	wc.lpszClassName = g_szChildClassName;
449 	wc.hIconSm		 = LoadIcon(NULL, (LPCTSTR)IDI_APPLICATION);
450 
451 	if(!RegisterClassEx(&wc))
452 	{
453 		MessageBox(0, "Could Not Register Child Window", "Oh Oh...",
454 			MB_ICONEXCLAMATION | MB_OK);
455 		return FALSE;
456 	}
457 	else
458 		return TRUE;
459 }
460 
461 
462 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
463 	LPSTR lpCmdLine, int nCmdShow)
464 {
465 	WNDCLASSEX wc;
466 	HWND hwnd;
467 	MSG Msg;
468 
469 	InitCommonControls();
470 
471 	wc.cbSize		 = sizeof(WNDCLASSEX);
472 	wc.style		 = 0;
473 	wc.lpfnWndProc	 = WndProc;
474 	wc.cbClsExtra	 = 0;
475 	wc.cbWndExtra	 = 0;
476 	wc.hInstance	 = hInstance;
477 	wc.hIcon		 = LoadIcon(NULL, (LPCTSTR)IDI_APPLICATION);
478 	wc.hCursor		 = LoadCursor(NULL, (LPCTSTR)IDC_ARROW);
479 	wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
480 	wc.lpszMenuName  = MAKEINTRESOURCE(IDR_MAINMENU);
481 	wc.lpszClassName = g_szClassName;
482 	wc.hIconSm		 = LoadIcon(NULL, (LPCTSTR)IDI_APPLICATION);
483 
484 	if(!RegisterClassEx(&wc))
485 	{
486 		MessageBox(NULL, "Window Registration Failed!", "Error!",
487 			MB_ICONEXCLAMATION | MB_OK);
488 		return 0;
489 	}
490 
491 	if(!SetUpMDIChildWindowClass(hInstance))
492 		return 0;
493 
494 	hwnd = CreateWindowEx(
495 		0,
496 		g_szClassName,
497 		"MDI Test Application",
498 		WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
499 		CW_USEDEFAULT, CW_USEDEFAULT, 480, 320,
500 		NULL, NULL, hInstance, NULL);
501 
502 	if(hwnd == NULL)
503 	{
504 		MessageBox(NULL, "Window Creation Failed!", "Error!",
505 			MB_ICONEXCLAMATION | MB_OK);
506 		return 0;
507 	}
508 
509 	g_hMainWindow = hwnd;
510 
511 	ShowWindow(hwnd, nCmdShow);
512 	UpdateWindow(hwnd);
513 
514 	while(GetMessage(&Msg, NULL, 0, 0) > 0)
515 	{
516 		if (!TranslateMDISysAccel(g_hMDIClient, &Msg))
517 		{
518 			TranslateMessage(&Msg);
519 			DispatchMessage(&Msg);
520 		}
521 	}
522 	return Msg.wParam;
523 }
524