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