diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..1ff0c42 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,63 @@ +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### +* text=auto + +############################################################################### +# Set default behavior for command prompt diff. +# +# This is need for earlier builds of msysgit that does not have it on by +# default for csharp files. +# Note: This is only used by command line +############################################################################### +#*.cs diff=csharp + +############################################################################### +# Set the merge driver for project and solution files +# +# Merging from the command prompt will add diff markers to the files if there +# are conflicts (Merging from VS is not affected by the settings below, in VS +# the diff markers are never inserted). Diff markers may cause the following +# file extensions to fail to load in VS. An alternative would be to treat +# these files as binary and thus will always conflict and require user +# intervention with every merge. To do so, just uncomment the entries below +############################################################################### +#*.sln merge=binary +#*.csproj merge=binary +#*.vbproj merge=binary +#*.vcxproj merge=binary +#*.vcproj merge=binary +#*.dbproj merge=binary +#*.fsproj merge=binary +#*.lsproj merge=binary +#*.wixproj merge=binary +#*.modelproj merge=binary +#*.sqlproj merge=binary +#*.wwaproj merge=binary + +############################################################################### +# behavior for image files +# +# image files are treated as binary by default. +############################################################################### +#*.jpg binary +#*.png binary +#*.gif binary + +############################################################################### +# diff behavior for common document formats +# +# Convert binary document formats to text before diffing them. This feature +# is only available from the command line. Turn it on by uncommenting the +# entries below. +############################################################################### +#*.doc diff=astextplain +#*.DOC diff=astextplain +#*.docx diff=astextplain +#*.DOCX diff=astextplain +#*.dot diff=astextplain +#*.DOT diff=astextplain +#*.pdf diff=astextplain +#*.PDF diff=astextplain +#*.rtf diff=astextplain +#*.RTF diff=astextplain diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3c4efe2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,261 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# DNX +project.lock.json +project.fragment.lock.json +artifacts/ + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Comment the next line if you want to checkin your web deploy settings +# but database connection strings (with potential passwords) will be unencrypted +#*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config +# NuGet v3's project.json files produces more ignoreable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +node_modules/ +orleans.codegen.cs + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc \ No newline at end of file diff --git a/License.txt b/License.txt new file mode 100644 index 0000000..6bb8a29 --- /dev/null +++ b/License.txt @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to \ No newline at end of file diff --git a/MSVC Win32 MDI Application.sln b/MSVC Win32 MDI Application.sln new file mode 100644 index 0000000..0a03f0b --- /dev/null +++ b/MSVC Win32 MDI Application.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26430.6 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MSVC Win32 MDI Application", "MSVC Win32 MDI Application\MSVC Win32 MDI Application.vcxproj", "{034B78A2-1C6B-40C9-8822-B1DF413FB9CC}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {034B78A2-1C6B-40C9-8822-B1DF413FB9CC}.Debug|x64.ActiveCfg = Debug|x64 + {034B78A2-1C6B-40C9-8822-B1DF413FB9CC}.Debug|x64.Build.0 = Debug|x64 + {034B78A2-1C6B-40C9-8822-B1DF413FB9CC}.Debug|x86.ActiveCfg = Debug|Win32 + {034B78A2-1C6B-40C9-8822-B1DF413FB9CC}.Debug|x86.Build.0 = Debug|Win32 + {034B78A2-1C6B-40C9-8822-B1DF413FB9CC}.Release|x64.ActiveCfg = Release|x64 + {034B78A2-1C6B-40C9-8822-B1DF413FB9CC}.Release|x64.Build.0 = Release|x64 + {034B78A2-1C6B-40C9-8822-B1DF413FB9CC}.Release|x86.ActiveCfg = Release|Win32 + {034B78A2-1C6B-40C9-8822-B1DF413FB9CC}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/MSVC Win32 MDI Application/AboutDialog.c b/MSVC Win32 MDI Application/AboutDialog.c new file mode 100644 index 0000000..d8dd8d2 --- /dev/null +++ b/MSVC Win32 MDI Application/AboutDialog.c @@ -0,0 +1,40 @@ +#include "stdafx.h" +#include "AboutDialog.h" +#include "Resource.h" +#include "Globals.h" + +/* Dialog procedure for our "about" dialog */ +INT_PTR CALLBACK AboutDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch (uMsg) + { + case WM_COMMAND: + { + WORD id = LOWORD(wParam); + + switch (id) + { + case IDOK: + case IDCANCEL: + { + EndDialog(hwndDlg, (INT_PTR)id); + return (INT_PTR)TRUE; + } + } + break; + } + + case WM_INITDIALOG: + { + return (INT_PTR)TRUE; + } + } + + return (INT_PTR)FALSE; +} + +/* Show our "about" dialog */ +void ShowAboutDialog(HWND owner) +{ + DialogBox(g_hInstance, MAKEINTRESOURCE(IDD_ABOUTDIALOG), owner, &AboutDialogProc); +} diff --git a/MSVC Win32 MDI Application/AboutDialog.h b/MSVC Win32 MDI Application/AboutDialog.h new file mode 100644 index 0000000..1e865fc --- /dev/null +++ b/MSVC Win32 MDI Application/AboutDialog.h @@ -0,0 +1,9 @@ +#pragma once + +#include "stdafx.h" + +/* Dialog procedure for our "about" dialog */ +INT_PTR CALLBACK AboutDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); + +/* Show our "about" dialog */ +void ShowAboutDialog(HWND owner); diff --git a/MSVC Win32 MDI Application/Application.ico b/MSVC Win32 MDI Application/Application.ico new file mode 100644 index 0000000..1073447 Binary files /dev/null and b/MSVC Win32 MDI Application/Application.ico differ diff --git a/MSVC Win32 MDI Application/Application.manifest b/MSVC Win32 MDI Application/Application.manifest new file mode 100644 index 0000000..0b31020 --- /dev/null +++ b/MSVC Win32 MDI Application/Application.manifest @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/MSVC Win32 MDI Application/Globals.h b/MSVC Win32 MDI Application/Globals.h new file mode 100644 index 0000000..d1bc4e9 --- /dev/null +++ b/MSVC Win32 MDI Application/Globals.h @@ -0,0 +1,12 @@ +#pragma once + +#include "stdafx.h" + +/* Global instance handle */ +extern HINSTANCE g_hInstance; + +/* Global main window handle */ +extern HWND g_hMainWindow; + +/* Global MDI client window handle */ +extern HWND g_hMDIClient; diff --git a/MSVC Win32 MDI Application/MDIChildWindow.c b/MSVC Win32 MDI Application/MDIChildWindow.c new file mode 100644 index 0000000..437ec05 --- /dev/null +++ b/MSVC Win32 MDI Application/MDIChildWindow.c @@ -0,0 +1,250 @@ +#include "stdafx.h" +#include "MDIChildWindow.h" +#include "MainWindow.h" +#include "Resource.h" +#include "Globals.h" + +/* MDI child window class and title */ +static LPCTSTR MDIChildWndClass = TEXT("Win32 MDI Example Application - Child"); + +/* Window procedure for our MDI child window */ +LRESULT CALLBACK MDIChildWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) + { + case WM_COMMAND: + { + WORD id = LOWORD(wParam); + + switch (id) + { + case ID_FILE_SAVE: + { + MDIChildSave(hWnd); + return 0; + } + + case ID_FILE_SAVEAS: + { + MDIChildSaveAS(hWnd); + return 0; + } + } + + break; + } + + /* An MDI child window is being activated */ + case WM_MDIACTIVATE: + { + HMENU hParentMenu, hParentFileMenu; + UINT enableMenu; + HWND hActivatedChild = (HWND)lParam; + + /* If this window is the one being activated, enable its menus. */ + if (hWnd == hActivatedChild) + { + enableMenu = MF_ENABLED; + } + else + { + enableMenu = MF_GRAYED; + } + + /* Get menu of MDI frame window */ + hParentMenu = GetMenu(g_hMainWindow); + + /* Enable / disable the "window" menu */ + EnableMenuItem(hParentMenu, 1, MF_BYPOSITION | enableMenu); + + /* Enable / disable the save and close menu items */ + hParentFileMenu = GetSubMenu(hParentMenu, 0); + EnableMenuItem(hParentFileMenu, ID_FILE_SAVE, MF_BYCOMMAND | enableMenu); + EnableMenuItem(hParentFileMenu, ID_FILE_SAVEAS, MF_BYCOMMAND | enableMenu); + EnableMenuItem(hParentFileMenu, ID_FILE_CLOSE, MF_BYCOMMAND | enableMenu); + EnableMenuItem(hParentFileMenu, ID_FILE_CLOSEALL, MF_BYCOMMAND | enableMenu); + + /* Redraw the updated menu */ + DrawMenuBar(g_hMainWindow); + + return 0; + } + + case WM_CREATE: + { + /* Allocate child window data */ + MdiChildData* childData = calloc(1, sizeof(MdiChildData)); + + /* Fail window creation if allocation failed */ + if (!childData) + return -1; + + /* Associate child window data with window */ + SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)childData); + + return 0; + } + + case WM_DESTROY: + { + /* Free child window data */ + MdiChildData* childData = (MdiChildData*)GetWindowLongPtr(hWnd, GWLP_USERDATA); + + if (childData) + free(childData); + + return 0; + } + } + + return DefMDIChildProc(hWnd, msg, wParam, lParam); +} + +/* Register a class for our main window */ +BOOL RegisterMDIChildWindowClass() +{ + WNDCLASSEX wc; + + wc.cbSize = sizeof(wc); + wc.style = 0; + wc.lpfnWndProc = &MDIChildWndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = g_hInstance; + wc.hIcon = (HICON)LoadImage(g_hInstance, MAKEINTRESOURCE(IDI_APPICON), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | + LR_DEFAULTCOLOR | LR_SHARED); + wc.hCursor = (HCURSOR)LoadImage(NULL, IDC_ARROW, IMAGE_CURSOR, 0, 0, LR_SHARED); + wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); + wc.lpszMenuName = MAKEINTRESOURCE(IDR_MAINMENU); + wc.lpszClassName = MDIChildWndClass; + wc.hIconSm = (HICON)LoadImage(g_hInstance, MAKEINTRESOURCE(IDI_APPICON), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR); + + return (RegisterClassEx(&wc)) ? TRUE : FALSE; +} + +/* Create a new MDI child window */ +void MDIChildNew(HWND hMDIClient) +{ + MDICREATESTRUCT mcs; + static unsigned int counter = 0; + TCHAR title[16]; + HWND hWndChild; + MdiChildData* childData; + + /* Increment counter, but ensure it doesn't become longer than the buffer */ + counter = (counter % 9999) + 1; + + /* Create the window title */ + wsprintf(title, TEXT("Untitled - %u"), counter); + + /* Set MDI child properties */ + mcs.szTitle = title; + mcs.szClass = MDIChildWndClass; + mcs.hOwner = g_hInstance; + mcs.x = mcs.cx = CW_USEDEFAULT; + mcs.y = mcs.cy = CW_USEDEFAULT; + mcs.style = MDIS_ALLCHILDSTYLES; + + /* Create the MDI child */ + hWndChild = (HWND)SendMessage(hMDIClient, WM_MDICREATE, 0, (LPARAM)&mcs); + + if (hWndChild) + { + /* Mark document as unsaved */ + childData = (MdiChildData*)GetWindowLongPtr(hWndChild, GWLP_USERDATA); + childData->IsUnSaved = TRUE; + } + else + MessageBox(NULL, TEXT("Error creating new document."), TEXT("Error"), MB_ICONERROR | MB_OK); +} + +/* Open a document in a new MDI child window */ +void MDIChildOpen(HWND hMDIClient) +{ + OPENFILENAME ofn = { 0 }; + TCHAR fileName[MAX_PATH] = TEXT(""); + TCHAR fileTitle[MAX_PATH] = TEXT(""); + MDICREATESTRUCT mcs; + + /* Set open file dialog properties */ + ofn.lStructSize = sizeof(ofn); + ofn.hwndOwner = hMDIClient; + ofn.lpstrFilter = TEXT("Text Documents (*.txt)\0.txt\0All Files (*.*)\0*.*\0"); + ofn.lpstrFile = fileName; + ofn.lpstrFileTitle = fileTitle; + ofn.nMaxFileTitle = MAX_PATH; + ofn.nMaxFile = MAX_PATH; + ofn.Flags = OFN_NOTESTFILECREATE | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; + ofn.lpstrDefExt = TEXT("txt"); + + /* Show open file dialog */ + if (GetOpenFileName(&ofn)) + { + HWND hWndChild; + + /* Set MDI child properties */ + mcs.szTitle = fileTitle; + mcs.szClass = MDIChildWndClass; + mcs.hOwner = g_hInstance; + mcs.x = mcs.cx = CW_USEDEFAULT; + mcs.y = mcs.cy = CW_USEDEFAULT; + mcs.style = MDIS_ALLCHILDSTYLES; + + /* Create the MDI child */ + hWndChild = (HWND)SendMessage(hMDIClient, WM_MDICREATE, 0, (LPARAM)&mcs); + + if (hWndChild) + { + /* TODO: Add file opening code */ + } + else + MessageBox(NULL, TEXT("Error opening document."), TEXT("Error"), MB_ICONERROR | MB_OK); + } +} + +/* Save a document in an MDI child window */ +void MDIChildSave(HWND hMDIChild) +{ + MdiChildData* childData = (MdiChildData*)GetWindowLongPtr(hMDIChild, GWLP_USERDATA); + + /* If this is an unsaved document, do a save as */ + if (childData->IsUnSaved) + { + MDIChildSaveAS(hMDIChild); + } + else + { + /* TODO: Add file saving code */ + } +} + +/* Save a document in an MDI child window with a filename */ +void MDIChildSaveAS(HWND hMDIChild) +{ + OPENFILENAME ofn = { 0 }; + TCHAR fileName[MAX_PATH] = TEXT(""); + TCHAR fileTitle[MAX_PATH] = TEXT(""); + + /* Set save file dialog properties */ + ofn.lStructSize = sizeof(ofn); + ofn.hwndOwner = hMDIChild; + ofn.lpstrFilter = TEXT("Text Documents (*.txt)\0.txt\0All Files (*.*)\0*.*\0"); + ofn.lpstrFile = fileName; + ofn.lpstrFileTitle = fileTitle; + ofn.nMaxFileTitle = MAX_PATH; + ofn.nMaxFile = MAX_PATH; + ofn.Flags = OFN_NOTESTFILECREATE | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT; + ofn.lpstrDefExt = TEXT("txt"); + + if (GetSaveFileName(&ofn)) + { + /* TODO: Add file saving code */ + + /* Update window title with the filename */ + SetWindowText(hMDIChild, ofn.lpstrFileTitle); + + /* Mark document as saved */ + MdiChildData* childData = (MdiChildData*)GetWindowLongPtr(hMDIChild, GWLP_USERDATA); + childData->IsUnSaved = FALSE; + } +} diff --git a/MSVC Win32 MDI Application/MDIChildWindow.h b/MSVC Win32 MDI Application/MDIChildWindow.h new file mode 100644 index 0000000..b32666a --- /dev/null +++ b/MSVC Win32 MDI Application/MDIChildWindow.h @@ -0,0 +1,28 @@ +#pragma once + +#include "stdafx.h" + +/* Window procedure for our main window */ +LRESULT CALLBACK MDIChildWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); + +/* Register a class for our main window */ +BOOL RegisterMDIChildWindowClass(void); + +/* Create a new MDI child window */ +void MDIChildNew(HWND hMDIClient); + +/* Open a document in a new MDI child window */ +void MDIChildOpen(HWND hMDIClient); + +/* Save a document in an MDI child window */ +void MDIChildSave(HWND hMDIChild); + +/* Save a document in an MDI child window with a filename */ +void MDIChildSaveAS(HWND hMDIChild); + +/* Instance data for the MDI child window */ +typedef struct tagMdiChildData +{ + /* Flag to determine whether this is a new document which hasn't been saved */ + BOOL IsUnSaved; +} MdiChildData; diff --git a/MSVC Win32 MDI Application/MSVC Win32 MDI Application.vcxproj b/MSVC Win32 MDI Application/MSVC Win32 MDI Application.vcxproj new file mode 100644 index 0000000..c7b4e51 --- /dev/null +++ b/MSVC Win32 MDI Application/MSVC Win32 MDI Application.vcxproj @@ -0,0 +1,198 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 15.0 + {034B78A2-1C6B-40C9-8822-B1DF413FB9CC} + Win32Proj + MSVCWin32MDIApplication + 10.0.15063.0 + + + + Application + true + v141 + Unicode + + + Application + false + v141 + true + Unicode + + + Application + true + v141 + Unicode + + + Application + false + v141 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + $(SolutionDir)$(Configuration)\$(Platform)\ + $(Configuration)\$(Platform)\ + + + true + $(SolutionDir)$(Configuration)\$(Platform)\ + $(Configuration)\$(Platform)\ + + + false + $(SolutionDir)$(Configuration)\$(Platform)\ + $(Configuration)\$(Platform)\ + + + false + $(SolutionDir)$(Configuration)\$(Platform)\ + $(Configuration)\$(Platform)\ + + + + Use + Level3 + Disabled + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + + + Windows + comctl32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + "type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'" + + + Application.manifest + + + + + Use + Level3 + Disabled + _DEBUG;_WINDOWS;%(PreprocessorDefinitions) + + + Windows + comctl32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + "type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'" + + + Application.manifest + + + + + Level3 + Use + MaxSpeed + true + true + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + + + Windows + true + true + comctl32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + "type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'" + + + Application.manifest + + + + + Level3 + Use + MaxSpeed + true + true + NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + + + Windows + true + true + comctl32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + "type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'" + + + Application.manifest + + + + + + + + + + + + + + + + + Create + Create + Create + Create + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/MSVC Win32 MDI Application/MSVC Win32 MDI Application.vcxproj.filters b/MSVC Win32 MDI Application/MSVC Win32 MDI Application.vcxproj.filters new file mode 100644 index 0000000..ea7fcbc --- /dev/null +++ b/MSVC Win32 MDI Application/MSVC Win32 MDI Application.vcxproj.filters @@ -0,0 +1,72 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Resource Files + + + + + Resource Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/MSVC Win32 MDI Application/MainWindow.c b/MSVC Win32 MDI Application/MainWindow.c new file mode 100644 index 0000000..4b56424 --- /dev/null +++ b/MSVC Win32 MDI Application/MainWindow.c @@ -0,0 +1,238 @@ +#include "stdafx.h" +#include "MainWindow.h" +#include "MDIChildWindow.h" +#include "AboutDialog.h" +#include "Resource.h" +#include "Globals.h" + +/* Main window class and title */ +static LPCTSTR MainWndClass = TEXT("Win32 MDI Example Application"); + +/* Global MDI client window handle */ +HWND g_hMDIClient = NULL; + +/* Window procedure for our main window */ +LRESULT CALLBACK MainWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) + { + case WM_COMMAND: + { + WORD id = LOWORD(wParam); + + switch (id) + { + /* Create new MDI child with an empty document */ + case ID_FILE_NEW: + { + MDIChildNew(g_hMDIClient); + return 0; + } + + /* Create new MDI child with an existing document */ + case ID_FILE_OPEN: + { + MDIChildOpen(g_hMDIClient); + return 0; + } + + /* Send close message to MDI child on close menu item */ + case ID_FILE_CLOSE: + { + HWND hWndChild = (HWND)SendMessage(g_hMDIClient, WM_MDIGETACTIVE, 0, 0); + + if (hWndChild) + { + SendMessage(hWndChild, WM_CLOSE, 0, 0); + return 0; + } + + break; + } + + /* Close all MDI children on close all menu item */ + case ID_FILE_CLOSEALL: + { + EnumChildWindows(g_hMDIClient, &CloseAllProc, 0); + return 0; + } + + /* Show "about" dialog on about menu item */ + case ID_HELP_ABOUT: + { + ShowAboutDialog(hWnd); + return 0; + } + + case ID_FILE_EXIT: + { + DestroyWindow(hWnd); + return 0; + } + + case ID_WINDOW_TILE: + { + SendMessage(g_hMDIClient, WM_MDITILE, 0, 0); + return 0; + } + + case ID_WINDOW_CASCADE: + { + SendMessage(g_hMDIClient, WM_MDICASCADE, 0, 0); + return 0; + } + + case ID_WINDOW_ARRANGE: + { + SendMessage(g_hMDIClient, WM_MDIICONARRANGE, 0, 0); + return 0; + } + + default: + { + /* If the ID is less than ID_MDI_FIRSTCHILD, it's probably a message for a child window's menu */ + if (id < ID_MDI_FIRSTCHILD) + { + HWND hWndChild = (HWND)SendMessage(g_hMDIClient, WM_MDIGETACTIVE, 0, 0); + + if (hWndChild) + { + SendMessage(hWndChild, WM_COMMAND, wParam, lParam); + return 0; + } + } + + break; + } + } + + break; + } + + case WM_GETMINMAXINFO: + { + /* Prevent our window from being sized too small */ + MINMAXINFO *minMax = (MINMAXINFO*)lParam; + minMax->ptMinTrackSize.x = 220; + minMax->ptMinTrackSize.y = 110; + + return 0; + } + + case WM_SIZE: + { + /* Ensure MDI client fills the whole client area */ + RECT rcClient; + + GetClientRect(hWnd, &rcClient); + SetWindowPos(g_hMDIClient, NULL, 0, 0, rcClient.right, rcClient.bottom, SWP_NOZORDER); + + return 0; + } + + /* Item from system menu has been invoked */ + case WM_SYSCOMMAND: + { + WORD id = LOWORD(wParam); + + switch (id) + { + /* Show "about" dialog on about system menu item */ + case ID_HELP_ABOUT: + { + ShowAboutDialog(hWnd); + return 0; + } + } + + break; + } + + case WM_CREATE: + { + /* Create the MDI client window */ + CLIENTCREATESTRUCT ccs; + HWND hMDIClient; + + ccs.hWindowMenu = GetSubMenu(GetMenu(hWnd), 1); + ccs.idFirstChild = ID_MDI_FIRSTCHILD; + + hMDIClient = CreateWindowEx(0, TEXT("MDICLIENT"), NULL, WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL | + WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, hWnd, NULL, + g_hInstance, (LPVOID)&ccs); + + /* Fail the window creation if the MDI client creation failed */ + if (!hMDIClient) + { + MessageBox(NULL, TEXT("Error creating MDI client."), TEXT("Error"), MB_ICONERROR | MB_OK); + return -1; + } + + /* Set global MDI client handle */ + g_hMDIClient = hMDIClient; + + return 0; + } + + case WM_DESTROY: + { + PostQuitMessage(0); + return 0; + } + } + + return DefFrameProc(hWnd, g_hMDIClient, msg, wParam, lParam); +} + +/* Close all child windows */ +BOOL CALLBACK CloseAllProc(HWND hWnd, LPARAM lParam) +{ + if (GetWindow(hWnd, GW_OWNER)) + return TRUE; + + SendMessage(hWnd, WM_CLOSE, 0, 0); + + return TRUE; +} + +/* Register a class for our main window */ +BOOL RegisterMainWindowClass() +{ + WNDCLASSEX wc; + + wc.cbSize = sizeof(wc); + wc.style = 0; + wc.lpfnWndProc = &MainWndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = g_hInstance; + wc.hIcon = (HICON)LoadImage(g_hInstance, MAKEINTRESOURCE(IDI_APPICON), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | + LR_DEFAULTCOLOR | LR_SHARED); + wc.hCursor = (HCURSOR)LoadImage(NULL, IDC_ARROW, IMAGE_CURSOR, 0, 0, LR_SHARED); + wc.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE + 1); + wc.lpszMenuName = MAKEINTRESOURCE(IDR_MAINMENU); + wc.lpszClassName = MainWndClass; + wc.hIconSm = (HICON)LoadImage(g_hInstance, MAKEINTRESOURCE(IDI_APPICON), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR); + + return (RegisterClassEx(&wc)) ? TRUE : FALSE; +} + +/* Create an instance of our main window */ +HWND CreateMainWindow() +{ + HWND hWnd; + HMENU hSysMenu; + + hWnd = CreateWindowEx(WS_EX_CLIENTEDGE, MainWndClass, MainWndClass, WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, + CW_USEDEFAULT, CW_USEDEFAULT, 640, 480, NULL, NULL, g_hInstance, NULL); + + if (hWnd) + { + /* Add "about" to the system menu */ + hSysMenu = GetSystemMenu(hWnd, FALSE); + InsertMenu(hSysMenu, 5, MF_BYPOSITION | MF_SEPARATOR, 0, NULL); + InsertMenu(hSysMenu, 6, MF_BYPOSITION, ID_HELP_ABOUT, TEXT("About")); + } + + return hWnd; +} diff --git a/MSVC Win32 MDI Application/MainWindow.h b/MSVC Win32 MDI Application/MainWindow.h new file mode 100644 index 0000000..8df8c8a --- /dev/null +++ b/MSVC Win32 MDI Application/MainWindow.h @@ -0,0 +1,18 @@ +#pragma once + +#include "stdafx.h" + +/* Window procedure for our main window */ +LRESULT CALLBACK MainWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); + +/* Register a class for our main window */ +BOOL RegisterMainWindowClass(void); + +/* Create an instance of our main window */ +HWND CreateMainWindow(void); + +/* Callback to close all child windows */ +BOOL CALLBACK CloseAllProc(HWND hWnd, LPARAM lParam); + +/* First ID Windows should use for menu items it attaches to the "Window" menu */ +#define ID_MDI_FIRSTCHILD 50000 diff --git a/MSVC Win32 MDI Application/Resource.h b/MSVC Win32 MDI Application/Resource.h new file mode 100644 index 0000000..0df088c --- /dev/null +++ b/MSVC Win32 MDI Application/Resource.h @@ -0,0 +1,33 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by Resource.rc +// +#define IDI_APPICON 101 +#define IDR_MAINMENU 102 +#define IDR_ACCELERATOR 103 +#define IDD_ABOUTDIALOG 104 +#define ID_FILE_NEW 40001 +#define ID_FILE_OPEN 40002 +#define ID_FILE_SAVE 40003 +#define ID_FILE_SAVEAS 40004 +#define ID_FILE_CLOSE 40005 +#define ID_FILE_CLOSEALL 40006 +#define ID_FILE_EXIT 40007 +#define ID_WINDOW_TILE 40008 +#define ID_WINDOW_CASCADE 40009 +#define ID_WINDOW_ARRANGE 40010 +#define ID_HELP_ABOUT 40011 +#ifndef IDC_STATIC +#define IDC_STATIC -1 +#endif + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 105 +#define _APS_NEXT_COMMAND_VALUE 40012 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/MSVC Win32 MDI Application/Resource.rc b/MSVC Win32 MDI Application/Resource.rc new file mode 100644 index 0000000..b50813f Binary files /dev/null and b/MSVC Win32 MDI Application/Resource.rc differ diff --git a/MSVC Win32 MDI Application/WinMain.c b/MSVC Win32 MDI Application/WinMain.c new file mode 100644 index 0000000..2ab35e2 --- /dev/null +++ b/MSVC Win32 MDI Application/WinMain.c @@ -0,0 +1,71 @@ +#include "stdafx.h" +#include "MainWindow.h" +#include "MDIChildWindow.h" +#include "Resource.h" +#include "Globals.h" + +/* Global instance handle */ +HINSTANCE g_hInstance = NULL; + +/* Global main window handle so that child windows can access it */ +HWND g_hMainWindow = NULL; + +/* Our application entry point */ +int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) +{ + INITCOMMONCONTROLSEX icc; + HWND hWnd; + HACCEL hAccelerators; + MSG msg; + + /* Assign global HINSTANCE */ + g_hInstance = hInstance; + + /* Initialise common controls */ + icc.dwSize = sizeof(icc); + icc.dwICC = ICC_WIN95_CLASSES; + InitCommonControlsEx(&icc); + + /* Register our main window class */ + if (!RegisterMainWindowClass()) + { + MessageBox(NULL, TEXT("Error registering main window class."), TEXT("Error"), MB_ICONERROR | MB_OK); + return 0; + } + + /* Register our MDI child window class */ + if (!RegisterMDIChildWindowClass()) + { + MessageBox(NULL, TEXT("Error registering MDI child window class."), TEXT("Error"), MB_ICONERROR | MB_OK); + return 0; + } + + /* Create our main window */ + if (!(hWnd = CreateMainWindow())) + { + MessageBox(NULL, TEXT("Error creating main window."), TEXT("Error"), MB_ICONERROR | MB_OK); + return 0; + } + + /* Set global main window handle */ + g_hMainWindow = hWnd; + + /* Load accelerators */ + hAccelerators = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDR_ACCELERATOR)); + + /* Show main window and force a paint */ + ShowWindow(hWnd, nCmdShow); + UpdateWindow(hWnd); + + /* Main message loop */ + while (GetMessage(&msg, NULL, 0, 0) > 0) + { + if (!TranslateMDISysAccel(g_hMDIClient, &msg) && !TranslateAccelerator(hWnd, hAccelerators, &msg)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + + return (int)msg.wParam; +} diff --git a/MSVC Win32 MDI Application/stdafx.c b/MSVC Win32 MDI Application/stdafx.c new file mode 100644 index 0000000..33d95b6 --- /dev/null +++ b/MSVC Win32 MDI Application/stdafx.c @@ -0,0 +1,5 @@ +// stdafx.c : source file that includes just the standard includes +// MSVC Win32 MDI Application.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" diff --git a/MSVC Win32 MDI Application/stdafx.h b/MSVC Win32 MDI Application/stdafx.h new file mode 100644 index 0000000..4b9be93 --- /dev/null +++ b/MSVC Win32 MDI Application/stdafx.h @@ -0,0 +1,20 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#pragma once + +#include "targetver.h" + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +// Windows Header Files: +#include +#include +#include + +// C RunTime Header Files +#include +#include +#include +#include diff --git a/MSVC Win32 MDI Application/targetver.h b/MSVC Win32 MDI Application/targetver.h new file mode 100644 index 0000000..8014de1 --- /dev/null +++ b/MSVC Win32 MDI Application/targetver.h @@ -0,0 +1,6 @@ +#pragma once + +// Target Windows Vista and later +#define _WIN32_WINNT 0x0600 + +#include diff --git a/Readme.md b/Readme.md new file mode 100644 index 0000000..8a9399f --- /dev/null +++ b/Readme.md @@ -0,0 +1,60 @@ +# MSVC Win32 MDI Application + +## Table of Contents + +- [Introduction](#introduction) +- [Windows Target Version](#windows-target-version) +- [Distributing Your Application](#distributing-your-application) +- [Terms of Use](#terms-of-use) +- [Problems?](#problems) +- [Changelog](#changelog) + +## Introduction + +This application is an example Windows MDI GUI application. The compiled application is a fully functional, with the +exception that opening and saving files does not read or write the files, and the MDI child windows do not have any code +to display documents. However, by adding this functionality you can quickly create a functioning MDI application. + +To build the application, open the solution file in Visual Studio, select the configuration and platform from the +drop-down menu, and use "Build Solution" from the "Build" menu. + +The solution was created in Visual Studio 2017, but it should open in any version of Visual Studio from 2010 SP1 +onwards. + +## Windows Target Version + +The project targets Windows Vista. If you attempt to call Windows API functions in your source code which were +introduced after Windows Vista, you will get a compilation error. If you'd like to use newer API functions (at the +expense of the application not running on older versions of Windows), you will need to change the "_WIN32_WINNT" +preprocessor definition in "targetver.h" to match the version of Windows you are targeting. For example, to target +Windows 7, change it to "0x0601". + +You can also target Windows XP using the above method with the value "0x0501". However, you will also need to go into +your project properties, and set the "Platform Toolset" under "Configuration Properties" to a toolset which supports +Windows XP. + +You can find a complete list of target version numbers in the "SDKDDKVer.h" Windows SDK header file. + +## Distributing Your Application + +The application will depend on the Microsoft Visual C++ Runtime. This will either be in the form of a Visual C++ Runtime +redistributable MSI (or merge module which you can use in your own installer), or DLL(s) which you must redistribute +with the application. Check the product documentation for your version of Visual Studio to see what your options are, +and be careful to ensure that you are allowed to redistribute the DLL(s) if you choose this option. + +## Terms of Use + +Refer to "License.txt" for terms of use. + +## Problems? + +If you have any problems or questions, please ensure you have read this readme. If you are still having trouble, you can +[get in contact](http://www.transmissionzero.co.uk/contact/). + +## Changelog + +1. 2017-08-15: Version 1.0 + - Initial release. + +Transmission Zero +2017-08-15