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
LoadTextFileToEdit(HWND hEdit,LPCTSTR pszFileName)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
SaveTextFileFromEdit(HWND hEdit,LPCTSTR pszFileName)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
DoFileOpen(HWND hwnd)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
DoFileSave(HWND hwnd)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
CreateNewMDIChild(HWND hMDIClient)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
WndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)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
MDIChildWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)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
SetUpMDIChildWindowClass(HINSTANCE hInstance)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
WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)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