#Include "windows.bi" #Include "win\commdlg.bi" #Include "win\commctrl.bi" #Include "resource.bi" Const As String g_szClassName = "myWindowClass" Const As String g_szChildClassName = "myMDIChildWindowClass" Dim Shared As HMODULE hInstance Dim Shared As ZString Ptr lpCmdLine #define IDC_MAIN_MDI 101 #define IDC_MAIN_TOOL 102 #define IDC_MAIN_STATUS 103 #define IDC_CHILD_EDIT 101 #define ID_MDI_FIRSTCHILD 50000 Dim Shared As HWND g_hMDIClient = NULL Dim Shared As HWND g_hMainWindow = NULL Function LoadTextFileToEdit(hEdit As HWND, pszFileName As LPCTSTR) As BOOL Dim As HANDLE hFile Dim As BOOL bSuccess = FALSE hFile = CreateFile(pszFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL) If hFile <> INVALID_HANDLE_VALUE Then Dim As Long dwFileSize dwFileSize = GetFileSize(hFile, NULL) If dwFileSize <> &hFFFFFFFF Then Dim As ZString Ptr pszFileText pszFileText = Cast(ZString Ptr, GlobalAlloc(GPTR_, dwFileSize + 1)) If pszFileText <> NULL Then Dim As Long dwRead If ReadFile(hFile, pszFileText, dwFileSize, @dwRead, NULL) Then pszFileText[dwFileSize] = 0 ' Add null terminator If SetWindowText(hEdit, pszFileText) Then bSuccess = TRUE ' It worked! EndIf EndIf GlobalFree(pszFileText) EndIf EndIf CloseHandle(hFile) EndIf Return bSuccess End Function Function SaveTextFileFromEdit(hEdit As HWND, pszFileName As LPCTSTR) As BOOL Dim As HANDLE hFile Dim As BOOL bSuccess = FALSE hFile = CreateFile(pszFileName, GENERIC_WRITE, 0, NULL, _ CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL) If hFile <> INVALID_HANDLE_VALUE Then Dim As Long dwTextLength dwTextLength = GetWindowTextLength(hEdit) ' No need to bother if there's no text. If dwTextLength > 0 Then Dim As ZString Ptr pszText Dim As Long dwBufferSize = dwTextLength + 1 pszText = Cast(ZString Ptr, GlobalAlloc(GPTR_, dwBufferSize)) If pszText <> NULL Then If GetWindowText(hEdit, pszText, dwBufferSize) Then Dim As Long dwWritten If WriteFile(hFile, pszText, dwTextLength, @dwWritten, NULL) Then bSuccess = TRUE EndIf EndIf GlobalFree(pszText) EndIf EndIf CloseHandle(hFile) EndIf Return bSuccess End Function Sub DoFileOpen(hwnd As HWND) Dim As OPENFILENAME ofn Dim As ZString*MAX_PATH szFileName = "" ZeroMemory(@ofn, SizeOf(ofn)) ofn.lStructSize = SizeOf(ofn) ofn.hwndOwner = hwnd ofn.lpstrFilter = @"Text Files (*.txt)\0*.txt\0All Files (*.*)\0*.*\0" ofn.lpstrFile = @szFileName ofn.nMaxFile = MAX_PATH ofn.Flags = OFN_EXPLORER Or OFN_FILEMUSTEXIST Or OFN_HIDEREADONLY ofn.lpstrDefExt = @"txt" If GetOpenFileName(@ofn) Then Dim As HWND hEdit = GetDlgItem(hwnd, IDC_CHILD_EDIT) If LoadTextFileToEdit(hEdit, szFileName) Then SendDlgItemMessage(g_hMainWindow, IDC_MAIN_STATUS, SB_SETTEXT, 0, Cast(LPARAM, @"Opened...")) SendDlgItemMessage(g_hMainWindow, IDC_MAIN_STATUS, SB_SETTEXT, 1, Cast(LPARAM, @szFileName)) SetWindowText(hwnd, @szFileName) EndIf EndIf End Sub Sub DoFileSave(hwnd As HWND) Dim As OPENFILENAME ofn Dim As ZString*MAX_PATH szFileName = "" ZeroMemory(@ofn, SizeOf(ofn)) ofn.lStructSize = SizeOf(ofn) ofn.hwndOwner = hwnd ofn.lpstrFilter = @"Text Files (*.txt)\0*.txt\0All Files (*.*)\0*.*\0" ofn.lpstrFile = @szFileName ofn.nMaxFile = MAX_PATH ofn.lpstrDefExt = @"txt" ofn.Flags = OFN_EXPLORER Or OFN_PATHMUSTEXIST Or OFN_HIDEREADONLY Or OFN_OVERWRITEPROMPT If GetSaveFileName(@ofn) Then Dim As HWND hEdit = GetDlgItem(hwnd, IDC_CHILD_EDIT) If SaveTextFileFromEdit(hEdit, szFileName) Then SendDlgItemMessage(g_hMainWindow, IDC_MAIN_STATUS, SB_SETTEXT, 0, Cast(LPARAM, @"Saved...")) SendDlgItemMessage(g_hMainWindow, IDC_MAIN_STATUS, SB_SETTEXT, 1, Cast(LPARAM, @szFileName)) SetWindowText(hwnd, @szFileName) EndIf EndIf End Sub Function CreateNewMDIChild(hMDIClient As HWND) As HWND Dim As MDICREATESTRUCT mcs Dim As HWND hChild mcs.szTitle = @"[Untitled]" mcs.szClass = @g_szChildClassName mcs.hOwner = GetModuleHandle(NULL) mcs.x = CW_USEDEFAULT mcs.cx = CW_USEDEFAULT mcs.y = CW_USEDEFAULT mcs.cy = CW_USEDEFAULT mcs.style = MDIS_ALLCHILDSTYLES hChild = Cast(HWND, SendMessage(hMDIClient, WM_MDICREATE, 0, Cast(Long, @mcs))) If hChild = 0 Then MessageBox(hMDIClient, "MDI Child creation failed.", "Oh Oh...", MB_ICONEXCLAMATION Or MB_OK) EndIf Return hChild End Function Function WndProc(hwnd As HWND, msg As UINT, wParam As WPARAM, lParam As LPARAM) As LRESULT Select Case msg Case WM_CREATE Dim As HWND hTool Dim As TBBUTTON tbb(2) Dim As TBADDBITMAP tbab Dim As HWND hStatus Dim As Long statwidths(0 To ...) = {100, -1} Dim As CLIENTCREATESTRUCT ccs ' Create MDI Client ' Find window menu where children will be listed ccs.hWindowMenu = GetSubMenu(GetMenu(hwnd), 2) ccs.idFirstChild = ID_MDI_FIRSTCHILD g_hMDIClient = CreateWindowEx(WS_EX_CLIENTEDGE, "mdiclient", NULL, _ WS_CHILD Or WS_CLIPCHILDREN Or WS_VSCROLL Or _ WS_HSCROLL Or WS_VISIBLE, _ CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, _ hwnd, Cast(HMENU, IDC_MAIN_MDI), GetModuleHandle(NULL), _ Cast(LPVOID, @ccs)) If g_hMDIClient = NULL Then MessageBox(hwnd, "Could not create MDI client.", "Error", MB_OK Or MB_ICONERROR) EndIf ' Create Toolbar hTool = CreateWindowEx(0, TOOLBARCLASSNAME, NULL, WS_CHILD Or WS_VISIBLE, 0, 0, 0, 0, _ hwnd, Cast(HMENU, IDC_MAIN_TOOL), GetModuleHandle(NULL), NULL) If hTool = NULL Then MessageBox(hwnd, "Could not create tool bar.", "Error", MB_OK Or MB_ICONERROR) EndIf ' Send the TB_BUTTONSTRUCTSIZE message, which is required for ' backward compatibility. SendMessage(hTool, TB_BUTTONSTRUCTSIZE, Cast(WPARAM, SizeOf(TBBUTTON)), 0) tbab.hInst = HINST_COMMCTRL tbab.nID = IDB_STD_SMALL_COLOR SendMessage(hTool, TB_ADDBITMAP, 0, Cast(LPARAM, @tbab)) ZeroMemory(@tbb(0), SizeOf(tbb) * (UBound(tbb) - LBound(tbb) + 1)) tbb(0).iBitmap = STD_FILENEW tbb(0).fsState = TBSTATE_ENABLED tbb(0).fsStyle = TBSTYLE_BUTTON tbb(0).idCommand = ID_FILE_NEW tbb(1).iBitmap = STD_FILEOPEN tbb(1).fsState = TBSTATE_ENABLED tbb(1).fsStyle = TBSTYLE_BUTTON tbb(1).idCommand = ID_FILE_OPEN tbb(2).iBitmap = STD_FILESAVE tbb(2).fsState = TBSTATE_ENABLED tbb(2).fsStyle = TBSTYLE_BUTTON tbb(2).idCommand = ID_FILE_SAVEAS SendMessage(hTool, TB_ADDBUTTONS, _ (SizeOf(tbb) * (UBound(tbb) - LBound(tbb) + 1)) / SizeOf(TBBUTTON), _ Cast(LPARAM, @tbb(0))) 'Create Status bar hStatus = CreateWindowEx(0, STATUSCLASSNAME, NULL, _ WS_CHILD Or WS_VISIBLE Or SBARS_SIZEGRIP, 0, 0, 0, 0, _ hwnd, Cast(HMENU, IDC_MAIN_STATUS), GetModuleHandle(NULL), NULL) SendMessage(hStatus, SB_SETPARTS, _ (SizeOf(statwidths) * (UBound(statwidths) - LBound(statwidths) + 1)) /SizeOf(Long), _ Cast(LPARAM, @statwidths(0))) SendMessage(hStatus, SB_SETTEXT, 0, Cast(LPARAM, "Hi there :)")) Case WM_SIZE Dim As HWND hTool Dim As RECT rcTool Dim As Long iToolHeight Dim As HWND hStatus Dim As RECT rcStatus Dim As Long iStatusHeight Dim As HWND hMDI Dim As Long iMDIHeight Dim As RECT rcClient ' Size toolbar and get height hTool = GetDlgItem(hwnd, IDC_MAIN_TOOL) SendMessage(hTool, TB_AUTOSIZE, 0, 0) GetWindowRect(hTool, @rcTool) iToolHeight = rcTool.bottom - rcTool.top ' Size status bar and get height hStatus = GetDlgItem(hwnd, IDC_MAIN_STATUS) SendMessage(hStatus, WM_SIZE, 0, 0) GetWindowRect(hStatus, @rcStatus) iStatusHeight = rcStatus.bottom - rcStatus.top ' Calculate remaining height and size edit GetClientRect(hwnd, @rcClient) iMDIHeight = rcClient.bottom - iToolHeight - iStatusHeight hMDI = GetDlgItem(hwnd, IDC_MAIN_MDI) SetWindowPos(hMDI, NULL, 0, iToolHeight, rcClient.right, iMDIHeight, SWP_NOZORDER) Case WM_CLOSE DestroyWindow(hwnd) Case WM_DESTROY PostQuitMessage(0) Case WM_COMMAND Select Case LoWord(wParam) Case ID_FILE_EXIT PostMessage(hwnd, WM_CLOSE, 0, 0) Case ID_FILE_NEW CreateNewMDIChild(g_hMDIClient) Case ID_FILE_OPEN Dim As HWND hChild = CreateNewMDIChild(g_hMDIClient) If hChild Then DoFileOpen(hChild) EndIf Case ID_FILE_CLOSE Dim As HWND hChild = Cast(HWND, SendMessage(g_hMDIClient, WM_MDIGETACTIVE, 0, 0)) If hChild Then SendMessage(hChild, WM_CLOSE, 0, 0) EndIf Case ID_WINDOW_TILE SendMessage(g_hMDIClient, WM_MDITILE, 0, 0) Case ID_WINDOW_CASCADE SendMessage(g_hMDIClient, WM_MDICASCADE, 0, 0) Case Else If LoWord(wParam) >= ID_MDI_FIRSTCHILD Then DefFrameProc(hwnd, g_hMDIClient, WM_COMMAND, wParam, lParam) Else Dim As HWND hChild = Cast(HWND, SendMessage(g_hMDIClient, WM_MDIGETACTIVE, 0, 0)) If hChild Then SendMessage(hChild, WM_COMMAND, wParam, lParam) EndIf EndIf End Select Case Else Return DefFrameProc(hwnd, g_hMDIClient, msg, wParam, lParam) End Select Return 0 End Function Function MDIChildWndProc(hwnd As HWND, msg As UINT, wParam As WPARAM, lParam As LPARAM) As LRESULT Select Case msg Case WM_CREATE Dim As HFONT hfDefault Dim As HWND hEdit ' Create Edit Control hEdit = CreateWindowEx(WS_EX_CLIENTEDGE, "EDIT", "", _ WS_CHILD Or WS_VISIBLE Or WS_VSCROLL Or WS_HSCROLL Or _ ES_MULTILINE Or ES_AUTOVSCROLL Or ES_AUTOHSCROLL, _ 0, 0, 100, 100, hwnd, Cast(HMENU, IDC_CHILD_EDIT), _ GetModuleHandle(NULL), NULL) If hEdit = NULL Then MessageBox(hwnd, "Could not create edit box.", "Error", MB_OK Or MB_ICONERROR) EndIf hfDefault = Cast(HFONT, GetStockObject(DEFAULT_GUI_FONT)) SendMessage(hEdit, WM_SETFONT, Cast(WPARAM, hfDefault), MAKELPARAM(FALSE, 0)) Case WM_MDIACTIVATE Dim As HMENU hMenu, hFileMenu Dim As UINT EnableFlag hMenu = GetMenu(g_hMainWindow) If hwnd = Cast(HWND, lParam) Then EnableFlag = MF_ENABLED 'being activated, enable the menus Else EnableFlag = MF_GRAYED 'being de-activated, gray the menus EndIf EnableMenuItem(hMenu, 1, MF_BYPOSITION Or EnableFlag) EnableMenuItem(hMenu, 2, MF_BYPOSITION Or EnableFlag) hFileMenu = GetSubMenu(hMenu, 0) EnableMenuItem(hFileMenu, ID_FILE_SAVEAS, MF_BYCOMMAND Or EnableFlag) EnableMenuItem(hFileMenu, ID_FILE_CLOSE, MF_BYCOMMAND Or EnableFlag) EnableMenuItem(hFileMenu, ID_FILE_CLOSEALL, MF_BYCOMMAND Or EnableFlag) DrawMenuBar(g_hMainWindow) Case WM_COMMAND Select Case LoWord(wParam) Case ID_FILE_OPEN DoFileOpen(hwnd) Case ID_FILE_SAVEAS DoFileSave(hwnd) Case ID_EDIT_CUT SendDlgItemMessage(hwnd, IDC_CHILD_EDIT, WM_CUT, 0, 0) Case ID_EDIT_COPY SendDlgItemMessage(hwnd, IDC_CHILD_EDIT, WM_COPY, 0, 0) Case ID_EDIT_PASTE SendDlgItemMessage(hwnd, IDC_CHILD_EDIT, WM_PASTE, 0, 0) End Select Case WM_SIZE Dim As HWND hEdit Dim As RECT rcClient ' Calculate remaining height and size edit GetClientRect(hwnd, @rcClient) hEdit = GetDlgItem(hwnd, IDC_CHILD_EDIT) SetWindowPos(hEdit, NULL, 0, 0, rcClient.right, rcClient.bottom, SWP_NOZORDER) Return DefMDIChildProc(hwnd, msg, wParam, lParam) Case Else Return DefMDIChildProc(hwnd, msg, wParam, lParam) End Select Return 0 End Function Function SetUpMDIChildWindowClass(hInstance As HINSTANCE) As BOOL Dim As WNDCLASSEX wc wc.cbSize = SizeOf(WNDCLASSEX) wc.style = CS_HREDRAW Or CS_VREDRAW wc.lpfnWndProc = @MDIChildWndProc wc.cbClsExtra = 0 wc.cbWndExtra = 0 wc.hInstance = hInstance wc.hIcon = LoadIcon(NULL, IDI_APPLICATION) wc.hCursor = LoadCursor(NULL, IDC_ARROW) wc.hbrBackground = Cast(HBRUSH, COLOR_3DFACE + 1) wc.lpszMenuName = NULL wc.lpszClassName = @g_szChildClassName wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION) If RegisterClassEx(@wc) = 0 Then MessageBox(0, "Could Not Register Child Window", "Oh Oh...", MB_ICONEXCLAMATION Or MB_OK) Return FALSE Else Return TRUE EndIf End Function Function WinMain(hInstance As HINSTANCE, hPrevInstance As HINSTANCE, lpCmdLine As ZString Ptr, nCmdShow As Long) As Long Dim As WNDCLASSEX wc Dim As HWND hwnd Dim As MSG Msg InitCommonControls() wc.cbSize = SizeOf(WNDCLASSEX) wc.style = 0 wc.lpfnWndProc = @WndProc wc.cbClsExtra = 0 wc.cbWndExtra = 0 wc.hInstance = hInstance wc.hIcon = LoadIcon(NULL, IDI_APPLICATION) wc.hCursor = LoadCursor(NULL, IDC_ARROW) wc.hbrBackground = Cast(HBRUSH, COLOR_WINDOW + 1) wc.lpszMenuName = MAKEINTRESOURCE(IDR_MAINMENU) wc.lpszClassName = @g_szClassName wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION) If RegisterClassEx(@wc) = 0 Then MessageBox(NULL, "Window Registration Failed!", "Error!", MB_ICONEXCLAMATION Or MB_OK) Return 0 EndIf If SetUpMDIChildWindowClass(hInstance) = 0 Then Return 0 EndIf hwnd = CreateWindowEx(0, _ g_szClassName, _ "theForger's Tutorial Application", _ WS_OVERLAPPEDWINDOW Or WS_CLIPCHILDREN, _ CW_USEDEFAULT, CW_USEDEFAULT, 480, 320, _ NULL, NULL, hInstance, NULL) If hwnd = NULL Then MessageBox(NULL, "Window Creation Failed!", "Error!", MB_ICONEXCLAMATION Or MB_OK) Return 0 EndIf g_hMainWindow = hwnd ShowWindow(hwnd, nCmdShow) UpdateWindow(hwnd) Do While GetMessage(@msg,NULL,0,0) TranslateMessage(@msg) DispatchMessage(@msg) Loop Return msg.wParam End Function ' Program start hInstance = GetModuleHandle(NULL) lpCmdLine = GetCommandLine WinMain(hInstance, NULL, lpCmdLine, SW_SHOWDEFAULT) ExitProcess(0)