├── archive ├── www.winprog.org.zip └── README.md ├── revised-code ├── 04_menu_two │ ├── menu_two.ico │ ├── menu_two_minimal.c │ └── menu_two_modern.c ├── 00_test │ ├── HelloWorld.cpp │ ├── test_minimal.c │ ├── test_MFC.cpp │ ├── test_modern.c │ └── README.md ├── 03_menu_one │ ├── menu_one_modern │ │ ├── menu_one.ico │ │ ├── resource.h │ │ ├── menu_one.rc │ │ └── menu_one_modern.c │ ├── menu_one_minimal │ │ ├── menu_one.ico │ │ ├── resource.h │ │ ├── menu_one_minimal.c │ │ └── menu_one.rc │ └── README.md ├── README.md ├── 01_simple_window │ ├── simple_window_MFC.cpp │ ├── sized_window_MFC.cpp │ ├── README.md │ ├── simple_window_minimal.c │ └── simple_window_modern.c └── 02_window_click │ ├── window_click_minimal.c │ └── window_click_modern.c ├── .gitignore ├── LICENSE └── README.md /archive/www.winprog.org.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GeorgePimpleton/theForger-winapi-tutorial/HEAD/archive/www.winprog.org.zip -------------------------------------------------------------------------------- /revised-code/04_menu_two/menu_two.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GeorgePimpleton/theForger-winapi-tutorial/HEAD/revised-code/04_menu_two/menu_two.ico -------------------------------------------------------------------------------- /revised-code/00_test/HelloWorld.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main( ) 4 | { 5 | std::cout << "Hello World!" << std::endl; 6 | 7 | return 0; 8 | } -------------------------------------------------------------------------------- /revised-code/03_menu_one/menu_one_modern/menu_one.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GeorgePimpleton/theForger-winapi-tutorial/HEAD/revised-code/03_menu_one/menu_one_modern/menu_one.ico -------------------------------------------------------------------------------- /revised-code/03_menu_one/menu_one_minimal/menu_one.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GeorgePimpleton/theForger-winapi-tutorial/HEAD/revised-code/03_menu_one/menu_one_minimal/menu_one.ico -------------------------------------------------------------------------------- /revised-code/00_test/test_minimal.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int WINAPI 4 | WinMain( HINSTANCE inst, HINSTANCE prevInst, LPSTR CmdLine, int cmdShow ) 5 | { 6 | MessageBox( NULL, TEXT( "Narf!" ), TEXT( "Pinky says..." ), MB_OK | MB_ICONEXCLAMATION ); 7 | return 0; 8 | } -------------------------------------------------------------------------------- /revised-code/03_menu_one/menu_one_modern/resource.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define IDR_MYMENU 101 4 | #define IDI_MYICON 102 5 | #define ID_FILE_EXIT 40001 6 | #define ID_STUFF_GO 40002 7 | #define ID_STUFF_GOSOMEWHEREELSE 40003 8 | -------------------------------------------------------------------------------- /revised-code/00_test/test_MFC.cpp: -------------------------------------------------------------------------------- 1 | // when using MFC stops Visual Studio from whinging the windows version isn't set 2 | #include 3 | 4 | // the MFC equivalent for windows.h 5 | #include 6 | 7 | int result = AfxMessageBox( L"Hello MFC!", MB_OK | MB_ICONASTERISK ); 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Unwanted folders 2 | Debug/ 3 | Release/ 4 | x64/ 5 | .vs/ 6 | 7 | # Unwanted compile & misc files 8 | *.exe 9 | *.aps 10 | *.obj 11 | *.lib 12 | *.log 13 | *.tlog 14 | *.VC.db 15 | *.cache 16 | *.pdb 17 | *.pch 18 | *.sln 19 | *.slnx 20 | *.user 21 | *.vcxproj 22 | *.filter 23 | revised-code.rar 24 | 25 | # MacOS-specific to ignore 26 | .DS_Store 27 | -------------------------------------------------------------------------------- /revised-code/03_menu_one/menu_one_modern/menu_one.rc: -------------------------------------------------------------------------------- 1 | #include "windows.h" 2 | 3 | #include "resource.h" 4 | 5 | IDR_MYMENU MENU DISCARDABLE 6 | { 7 | POPUP "&File" 8 | { 9 | MENUITEM "E&xit", ID_FILE_EXIT 10 | } 11 | 12 | POPUP "&Stuff" 13 | { 14 | MENUITEM "&Go", ID_STUFF_GO 15 | MENUITEM "Go &Somewhere Else", ID_STUFF_GOSOMEWHEREELSE, GRAYED 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /revised-code/00_test/test_modern.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int WINAPI wWinMain( _In_ HINSTANCE inst, 4 | _In_opt_ HINSTANCE prevInst, 5 | _In_ PWSTR cmdLine, 6 | _In_ int cmdShow ) 7 | { 8 | UNREFERENCED_PARAMETER( inst ); 9 | UNREFERENCED_PARAMETER( prevInst ); 10 | UNREFERENCED_PARAMETER( cmdLine ); 11 | UNREFERENCED_PARAMETER( cmdShow ); 12 | 13 | MessageBoxW( NULL, L"Narf!", L"Pinky says...", MB_OK | MB_ICONEXCLAMATION ); 14 | 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /archive/README.md: -------------------------------------------------------------------------------- 1 | # theForger's Win32 API tutorial archive 2 | [![Language](https://img.shields.io/badge/Language%20-C-blue.svg)](https://github.com/GeorgePimpleton/theForger-winapi-tutorial/) 3 | [![Platform](https://img.shields.io/badge/Platform%20-Win32-blue.svg)](https://github.com/GeorgePimpleton/theForger-winapi-tutorial/) 4 | 5 | An archive of [theForger's Win32 API Programming Tutorial](http://www.winprog.org/tutorial/) site in zip format. For reference purposes as comparison with my updated code, as well as a backup in case one day the site "goes dark." 6 | 7 | ### Notes 8 | I archived the site using WinHTTrack. https://www.httrack.com/ 9 | -------------------------------------------------------------------------------- /revised-code/03_menu_one/README.md: -------------------------------------------------------------------------------- 1 | # theForger's Win32 API tutorial, revised and updated code 2 | [![Language](https://img.shields.io/badge/Language%20-C-blue.svg)](https://github.com/GeorgePimpleton/theForger-winapi-tutorial/) 3 | [![Platform](https://img.shields.io/badge/Platform%20-Win32-blue.svg)](https://github.com/GeorgePimpleton/theForger-winapi-tutorial/) 4 | 5 | ### Notes 6 | There are two separate directories for the sources because of how Visual Studio creates resource script files (.rc and resource.h). There's a lot of excessive text used for the visual resource editor in the VS IDE. Text that can be stripped out. The trimmed down resource files can still be opened for visual inspection in the IDE. 7 | -------------------------------------------------------------------------------- /revised-code/03_menu_one/menu_one_minimal/resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Developer Studio generated include file. 3 | // Used by menu_one.rc 4 | // 5 | #define IDR_MYMENU 101 6 | #define IDI_MYICON 102 7 | #define ID_FILE_EXIT 40001 8 | #define ID_STUFF_GO 40002 9 | #define ID_STUFF_GOSOMEWHEREELSE 40003 10 | 11 | // Next default values for new objects 12 | // 13 | #ifdef APSTUDIO_INVOKED 14 | #ifndef APSTUDIO_READONLY_SYMBOLS 15 | #define _APS_NEXT_RESOURCE_VALUE 103 16 | #define _APS_NEXT_COMMAND_VALUE 40004 17 | #define _APS_NEXT_CONTROL_VALUE 1000 18 | #define _APS_NEXT_SYMED_VALUE 101 19 | #endif 20 | #endif 21 | -------------------------------------------------------------------------------- /revised-code/README.md: -------------------------------------------------------------------------------- 1 | # theForger's Win32 API tutorial, revised and update code 2 | [![Language](https://img.shields.io/badge/Language%20-C-blue.svg)](https://github.com/GeorgePimpleton/theForger-winapi-tutorial/) 3 | [![Platform](https://img.shields.io/badge/Platform%20-Win32-blue.svg)](https://github.com/GeorgePimpleton/theForger-winapi-tutorial/) 4 | 5 | My updated code for the tutorial. Download and unpack the archived website to follow the lessons in your browser. 6 | 7 | For most of the examples there are two different updates to the code. 8 | 9 | 1. The minimum needed for modern Windows systems. 10 | 2. Using modern WinAPI features. 11 | 12 | Enjoy! 13 | 14 | ### Notes 15 | The first two examples have additional code samples using the Microsoft Foundation Classes (MFC), to show the differences between writing code using the C-based Desktop WinAPI and the C++-based MFC framework. 16 | -------------------------------------------------------------------------------- /revised-code/01_simple_window/simple_window_MFC.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | // application class 5 | class CTheApp : public CWinApp 6 | { 7 | public: 8 | BOOL InitInstance( ); 9 | }; 10 | 11 | // main window class 12 | class CMainWnd : public CFrameWnd 13 | { 14 | public: 15 | CMainWnd( ); 16 | 17 | protected: 18 | DECLARE_MESSAGE_MAP( ) 19 | }; 20 | 21 | // instantiate the application 22 | CTheApp theApp; 23 | 24 | // construct a window 25 | CMainWnd::CMainWnd( ) 26 | { 27 | Create(NULL, L"The title of my window"); 28 | } 29 | 30 | // initalize the application 31 | BOOL CTheApp::InitInstance( ) 32 | { 33 | m_pMainWnd = new CMainWnd; 34 | 35 | m_pMainWnd->ShowWindow(m_nCmdShow); 36 | m_pMainWnd->UpdateWindow( ); 37 | 38 | return TRUE; 39 | } 40 | 41 | // application's message map 42 | BEGIN_MESSAGE_MAP(CMainWnd, CFrameWnd) 43 | END_MESSAGE_MAP( ) 44 | -------------------------------------------------------------------------------- /revised-code/01_simple_window/sized_window_MFC.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | class CMainWin : public CFrameWnd 5 | { 6 | public: 7 | CMainWin( ); 8 | 9 | DECLARE_MESSAGE_MAP( ) 10 | }; 11 | 12 | CMainWin::CMainWin( ) 13 | { 14 | CreateEx(WS_EX_CLIENTEDGE, 15 | AfxRegisterWndClass(NULL, 16 | (HCURSOR) ::LoadCursorW(NULL, IDC_ARROW), 17 | (HBRUSH) (COLOR_WINDOW + 1), 18 | (HICON) ::LoadIconW(NULL, IDI_APPLICATION)), 19 | L"MFC Small Window", 20 | WS_OVERLAPPEDWINDOW, 21 | CW_USEDEFAULT, CW_USEDEFAULT, 22 | 480, 240, 23 | NULL, NULL, 0); 24 | } 25 | 26 | class CApp : public CWinApp 27 | { 28 | public: 29 | BOOL InitInstance( ); 30 | }; 31 | 32 | BOOL CApp::InitInstance( ) 33 | { 34 | m_pMainWnd = new CMainWin; 35 | m_pMainWnd->ShowWindow(m_nCmdShow); 36 | m_pMainWnd->UpdateWindow( ); 37 | 38 | return TRUE; 39 | } 40 | 41 | BEGIN_MESSAGE_MAP(CMainWin, CFrameWnd) 42 | END_MESSAGE_MAP( ) 43 | 44 | CApp App; 45 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) theForger 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /revised-code/01_simple_window/README.md: -------------------------------------------------------------------------------- 1 | # theForger's Win32 API tutorial, revised and updated code 2 | [![Language](https://img.shields.io/badge/Language%20-C-blue.svg)](https://github.com/GeorgePimpleton/theForger-winapi-tutorial/) 3 | [![Platform](https://img.shields.io/badge/Platform%20-Win32-blue.svg)](https://github.com/GeorgePimpleton/theForger-winapi-tutorial/) 4 | 5 | ### A simple window using MFC 6 | Creating a custom sized window using MFC is more complicated than using the WinAPI. ~~The code would have to call the CWnd::PreCreateWindow() function and specify the size of the window. Setting the location of the window when creating the window in the WinAPI doesn't look to be possible. So....even more code needed for a simple "how to program" example. **\*ouch!\***~~ 7 | 8 | Well, there are several ways to create a sized window with MFC, sadly they bloat up the code. One approach, the one shown here doesn't use the PreCreateWindow() method, reveals how MFC encapsulates the underlying WinAPI. 9 | 10 | To be honest I don't know where to call the PreCreateWindow() function for this small sized window example. Apparently that is the preferred method vs. the method I used. I don't know all that much about MFC. 11 | -------------------------------------------------------------------------------- /revised-code/00_test/README.md: -------------------------------------------------------------------------------- 1 | # theForger's Win32 API tutorial, revised and updated code 2 | [![Language](https://img.shields.io/badge/Language%20-C-blue.svg)](https://github.com/GeorgePimpleton/theForger-winapi-tutorial/) 3 | [![Platform](https://img.shields.io/badge/Platform%20-Win32-blue.svg)](https://github.com/GeorgePimpleton/theForger-winapi-tutorial/) 4 | This example is not a numbered part of the lessons, it shows the simplest possible Win32/Desktop WinAPI app possible. Similar to the beginner's "Hello World!" example for C/C++ code. Also included. 5 | 6 | If someone wants to learn C\++ there's a free online tutorial site available: Learn C++. https://www.learncpp.com/ 7 | 8 | ### The initial test application created with MFC 9 | I wondered if a simple app that displays just a message box was possible using MFC. Well, it is. test_MFC.cpp shows how. 10 | 11 | This example shows that MFC is not as feature rich as the Windows Desktop WinAPI in some aspects when creating minimal apps, using Message boxes, for example. Being unable to easily specify a window title is not good, doing so requires more code. 12 | 13 | This minimal MFC example also causes an app crash on exit that goes unnoticed executing the app without debugging. \*\****OUCH***\*\* 14 | 15 | The rest of the code examples (except for the next one) will NOT be redone using MFC. Doing it yourself would be a learning experience after learning C++ and the WinAPI. 16 | -------------------------------------------------------------------------------- /revised-code/01_simple_window/simple_window_minimal.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | const TCHAR g_szClassName[ ] = TEXT( "myWindowClass" ); 4 | 5 | // Step 4: the Window Procedure 6 | LRESULT CALLBACK WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam ) 7 | { 8 | switch ( msg ) 9 | { 10 | case WM_CLOSE: 11 | DestroyWindow( hwnd ); 12 | break; 13 | case WM_DESTROY: 14 | PostQuitMessage( 0 ); 15 | break; 16 | default: 17 | return DefWindowProc( hwnd, msg, wParam, lParam ); 18 | } 19 | return 0; 20 | } 21 | 22 | int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, 23 | PSTR lpCmdLine, int nCmdShow ) 24 | { 25 | WNDCLASSEX wc; 26 | HWND hwnd; 27 | MSG Msg; 28 | 29 | //Step 1: Registering the Window Class 30 | wc.cbSize = sizeof( WNDCLASSEX ); 31 | wc.style = 0; 32 | wc.lpfnWndProc = WndProc; 33 | wc.cbClsExtra = 0; 34 | wc.cbWndExtra = 0; 35 | wc.hInstance = hInstance; 36 | wc.hIcon = LoadIcon( NULL, IDI_APPLICATION ); 37 | wc.hCursor = LoadCursor( NULL, IDC_ARROW ); 38 | wc.hbrBackground = ( HBRUSH ) ( COLOR_WINDOW + 1 ); 39 | wc.lpszMenuName = NULL; 40 | wc.lpszClassName = g_szClassName; 41 | wc.hIconSm = LoadIcon( NULL, IDI_APPLICATION ); 42 | 43 | if ( !RegisterClassEx( &wc ) ) 44 | { 45 | MessageBox( NULL, TEXT( "Window Registration Failed!" ), TEXT( "Error!" ), 46 | MB_ICONEXCLAMATION | MB_OK ); 47 | return 0; 48 | } 49 | 50 | // Step 2: Creating the Window 51 | hwnd = CreateWindowEx( 52 | WS_EX_CLIENTEDGE, 53 | g_szClassName, 54 | TEXT( "The title of my window" ), 55 | WS_OVERLAPPEDWINDOW, 56 | CW_USEDEFAULT, CW_USEDEFAULT, 240, 120, 57 | NULL, NULL, hInstance, NULL ); 58 | 59 | if ( hwnd == NULL ) 60 | { 61 | MessageBox( NULL, TEXT( "Window Creation Failed!" ), TEXT( "Error!" ), 62 | MB_ICONEXCLAMATION | MB_OK ); 63 | return 0; 64 | } 65 | 66 | ShowWindow( hwnd, nCmdShow ); 67 | UpdateWindow( hwnd ); 68 | 69 | // Step 3: The Message Loop 70 | while ( GetMessage( &Msg, NULL, 0, 0 ) > 0 ) 71 | { 72 | TranslateMessage( &Msg ); 73 | DispatchMessage( &Msg ); 74 | } 75 | return Msg.wParam; 76 | } 77 | -------------------------------------------------------------------------------- /revised-code/02_window_click/window_click_minimal.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | const TCHAR g_szClassName[ ] = TEXT( "myWindowClass" ); 4 | 5 | LRESULT CALLBACK WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam ) 6 | { 7 | switch ( msg ) 8 | { 9 | case WM_LBUTTONDOWN: 10 | { 11 | TCHAR szFileName[MAX_PATH]; 12 | HINSTANCE hInstance = GetModuleHandle( NULL ); 13 | 14 | GetModuleFileName( hInstance, szFileName, MAX_PATH ); 15 | MessageBox( hwnd, szFileName, TEXT( "This program is:" ), MB_OK | MB_ICONINFORMATION ); 16 | } 17 | break; 18 | case WM_CLOSE: 19 | DestroyWindow( hwnd ); 20 | break; 21 | case WM_DESTROY: 22 | PostQuitMessage( 0 ); 23 | break; 24 | default: 25 | return DefWindowProc( hwnd, msg, wParam, lParam ); 26 | } 27 | return 0; 28 | } 29 | 30 | int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, 31 | LPSTR lpCmdLine, int nCmdShow ) 32 | { 33 | WNDCLASSEX wc; 34 | HWND hwnd; 35 | MSG Msg; 36 | 37 | wc.cbSize = sizeof( WNDCLASSEX ); 38 | wc.style = 0; 39 | wc.lpfnWndProc = WndProc; 40 | wc.cbClsExtra = 0; 41 | wc.cbWndExtra = 0; 42 | wc.hInstance = hInstance; 43 | wc.hIcon = LoadIcon( NULL, IDI_APPLICATION ); 44 | wc.hCursor = LoadCursor( NULL, IDC_ARROW ); 45 | wc.hbrBackground = ( HBRUSH ) ( COLOR_WINDOW + 1 ); 46 | wc.lpszMenuName = NULL; 47 | wc.lpszClassName = g_szClassName; 48 | wc.hIconSm = LoadIcon( NULL, IDI_APPLICATION ); 49 | 50 | if ( !RegisterClassEx( &wc ) ) 51 | { 52 | MessageBox( NULL, TEXT( "Window Registration Failed!" ), TEXT( "Error!" ), 53 | MB_ICONEXCLAMATION | MB_OK ); 54 | return 0; 55 | } 56 | 57 | hwnd = CreateWindowEx( 58 | WS_EX_CLIENTEDGE, 59 | g_szClassName, 60 | TEXT( "The title of my window" ), 61 | WS_OVERLAPPEDWINDOW, 62 | CW_USEDEFAULT, CW_USEDEFAULT, 240, 120, 63 | NULL, NULL, hInstance, NULL ); 64 | 65 | if ( hwnd == NULL ) 66 | { 67 | MessageBox( NULL, TEXT( "Window Creation Failed!" ), TEXT( "Error!" ), 68 | MB_ICONEXCLAMATION | MB_OK ); 69 | return 0; 70 | } 71 | 72 | ShowWindow( hwnd, nCmdShow ); 73 | UpdateWindow( hwnd ); 74 | 75 | while ( GetMessage( &Msg, NULL, 0, 0 ) > 0 ) 76 | { 77 | TranslateMessage( &Msg ); 78 | DispatchMessage( &Msg ); 79 | } 80 | return Msg.wParam; 81 | } 82 | -------------------------------------------------------------------------------- /revised-code/03_menu_one/menu_one_minimal/menu_one_minimal.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "resource.h" 4 | 5 | const TCHAR g_szClassName[ ] = TEXT( "myWindowClass" ); 6 | 7 | LRESULT CALLBACK WndProc( HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam ) 8 | { 9 | switch ( Message ) 10 | { 11 | case WM_COMMAND: 12 | switch ( LOWORD( wParam ) ) 13 | { 14 | case ID_FILE_EXIT: 15 | PostMessage( hwnd, WM_CLOSE, 0, 0 ); 16 | break; 17 | case ID_STUFF_GO: 18 | MessageBox( hwnd, TEXT( "You clicked Go!" ), TEXT( "Woo!" ), MB_OK ); 19 | break; 20 | } 21 | break; 22 | case WM_CLOSE: 23 | DestroyWindow( hwnd ); 24 | break; 25 | case WM_DESTROY: 26 | PostQuitMessage( 0 ); 27 | break; 28 | default: 29 | return DefWindowProc( hwnd, Message, wParam, lParam ); 30 | } 31 | return 0; 32 | } 33 | 34 | int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, 35 | LPSTR lpCmdLine, int nCmdShow ) 36 | { 37 | WNDCLASSEX wc; 38 | HWND hwnd; 39 | MSG Msg; 40 | 41 | wc.cbSize = sizeof( WNDCLASSEX ); 42 | wc.style = 0; 43 | wc.lpfnWndProc = WndProc; 44 | wc.cbClsExtra = 0; 45 | wc.cbWndExtra = 0; 46 | wc.hInstance = hInstance; 47 | wc.hIcon = LoadIcon( GetModuleHandle( NULL ), MAKEINTRESOURCE( IDI_MYICON ) ); 48 | wc.hCursor = LoadCursor( NULL, IDC_ARROW ); 49 | wc.hbrBackground = ( HBRUSH ) ( COLOR_WINDOW + 1 ); 50 | wc.lpszMenuName = MAKEINTRESOURCE( IDR_MYMENU ); 51 | wc.lpszClassName = g_szClassName; 52 | wc.hIconSm = ( HICON ) LoadImage( GetModuleHandle( NULL ), MAKEINTRESOURCE( IDI_MYICON ), IMAGE_ICON, 16, 16, 0 ); 53 | 54 | if ( !RegisterClassEx( &wc ) ) 55 | { 56 | MessageBox( NULL, TEXT( "Window Registration Failed!" ), TEXT( "Error!" ), 57 | MB_ICONEXCLAMATION | MB_OK ); 58 | return 0; 59 | } 60 | 61 | hwnd = CreateWindowEx( 62 | WS_EX_CLIENTEDGE, 63 | g_szClassName, 64 | TEXT( "A Menu" ), 65 | WS_OVERLAPPEDWINDOW, 66 | CW_USEDEFAULT, CW_USEDEFAULT, 240, 120, 67 | NULL, NULL, hInstance, NULL ); 68 | 69 | if ( hwnd == NULL ) 70 | { 71 | MessageBox( NULL, TEXT( "Window Creation Failed!" ), TEXT( "Error!" ), 72 | MB_ICONEXCLAMATION | MB_OK ); 73 | return 0; 74 | } 75 | 76 | ShowWindow( hwnd, nCmdShow ); 77 | UpdateWindow( hwnd ); 78 | 79 | while ( GetMessage( &Msg, NULL, 0, 0 ) > 0 ) 80 | { 81 | TranslateMessage( &Msg ); 82 | DispatchMessage( &Msg ); 83 | } 84 | return Msg.wParam; 85 | } 86 | -------------------------------------------------------------------------------- /revised-code/03_menu_one/menu_one_minimal/menu_one.rc: -------------------------------------------------------------------------------- 1 | //Microsoft Developer Studio generated resource script. 2 | // 3 | #include "resource.h" 4 | 5 | #define APSTUDIO_READONLY_SYMBOLS 6 | ///////////////////////////////////////////////////////////////////////////// 7 | // 8 | // Generated from the TEXTINCLUDE 2 resource. 9 | // 10 | #define APSTUDIO_HIDDEN_SYMBOLS 11 | #include "windows.h" 12 | #undef APSTUDIO_HIDDEN_SYMBOLS 13 | 14 | 15 | ///////////////////////////////////////////////////////////////////////////// 16 | #undef APSTUDIO_READONLY_SYMBOLS 17 | 18 | ///////////////////////////////////////////////////////////////////////////// 19 | // English (Canada) resources 20 | 21 | #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENC) 22 | #ifdef _WIN32 23 | LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_CAN 24 | #pragma code_page(1252) 25 | #endif //_WIN32 26 | 27 | ///////////////////////////////////////////////////////////////////////////// 28 | // 29 | // Menu 30 | // 31 | 32 | IDR_MYMENU MENU DISCARDABLE 33 | BEGIN 34 | POPUP "&File" 35 | BEGIN 36 | MENUITEM "E&xit", ID_FILE_EXIT 37 | END 38 | POPUP "&Stuff" 39 | BEGIN 40 | MENUITEM "&Go", ID_STUFF_GO 41 | MENUITEM "Go &Somewhere Else", ID_STUFF_GOSOMEWHEREELSE 42 | , GRAYED 43 | END 44 | END 45 | 46 | 47 | #ifdef APSTUDIO_INVOKED 48 | ///////////////////////////////////////////////////////////////////////////// 49 | // 50 | // TEXTINCLUDE 51 | // 52 | 53 | 1 TEXTINCLUDE DISCARDABLE 54 | BEGIN 55 | "resource.h\0" 56 | END 57 | 58 | 2 TEXTINCLUDE DISCARDABLE 59 | BEGIN 60 | "#define APSTUDIO_HIDDEN_SYMBOLS\r\n" 61 | "#include ""windows.h""\r\n" 62 | "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n" 63 | "\0" 64 | END 65 | 66 | 3 TEXTINCLUDE DISCARDABLE 67 | BEGIN 68 | "\r\n" 69 | "\0" 70 | END 71 | 72 | #endif // APSTUDIO_INVOKED 73 | 74 | 75 | ///////////////////////////////////////////////////////////////////////////// 76 | // 77 | // Icon 78 | // 79 | 80 | // Icon with lowest ID value placed first to ensure application icon 81 | // remains consistent on all systems. 82 | IDI_MYICON ICON DISCARDABLE "menu_one.ico" 83 | #endif // English (Canada) resources 84 | ///////////////////////////////////////////////////////////////////////////// 85 | 86 | 87 | 88 | #ifndef APSTUDIO_INVOKED 89 | ///////////////////////////////////////////////////////////////////////////// 90 | // 91 | // Generated from the TEXTINCLUDE 3 resource. 92 | // 93 | 94 | 95 | ///////////////////////////////////////////////////////////////////////////// 96 | #endif // not APSTUDIO_INVOKED 97 | 98 | -------------------------------------------------------------------------------- /revised-code/02_window_click/window_click_modern.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | PCWSTR g_className = L"myWindowClass"; 5 | 6 | LRESULT CALLBACK WndProc( HWND, UINT, WPARAM, LPARAM ); 7 | 8 | int WINAPI wWinMain( _In_ HINSTANCE inst, 9 | _In_opt_ HINSTANCE prevInst, 10 | _In_ PWSTR cmdLine, 11 | _In_ int cmdShow ) 12 | { 13 | UNREFERENCED_PARAMETER( prevInst ); 14 | UNREFERENCED_PARAMETER( cmdLine ); 15 | 16 | WNDCLASSEXW wc = { 0 }; 17 | HWND wnd; 18 | MSG msg; 19 | 20 | wc.cbSize = sizeof( WNDCLASSEXW ); 21 | wc.style = 0; 22 | wc.lpfnWndProc = WndProc; 23 | wc.cbClsExtra = 0; 24 | wc.cbWndExtra = 0; 25 | wc.hInstance = inst; 26 | wc.hIcon = ( HICON ) LoadImageW( NULL, IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR ); 27 | wc.hIconSm = ( HICON ) LoadImageW( NULL, IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR ); 28 | wc.hCursor = ( HCURSOR ) LoadImageW( NULL, IDC_ARROW, IMAGE_CURSOR, 0, 0, LR_SHARED ); 29 | wc.hbrBackground = ( HBRUSH ) ( COLOR_WINDOW + 1 ); 30 | wc.lpszMenuName = NULL; 31 | wc.lpszClassName = g_className; 32 | 33 | if ( !RegisterClassExW( &wc ) ) 34 | { 35 | MessageBoxW( NULL, L"Window Registration Failed!", L"Error!", MB_ICONEXCLAMATION | MB_OK ); 36 | return 0; 37 | } 38 | 39 | wnd = CreateWindowExW( WS_EX_CLIENTEDGE, g_className, L"The title of my window", 40 | WS_OVERLAPPEDWINDOW, 41 | CW_USEDEFAULT, CW_USEDEFAULT, 240, 120, 42 | NULL, NULL, inst, NULL ); 43 | 44 | if ( wnd == NULL ) 45 | { 46 | MessageBoxW( NULL, L"Window Creation Failed!", L"Error!", MB_ICONEXCLAMATION | MB_OK ); 47 | return 0; 48 | } 49 | 50 | ShowWindow( wnd, cmdShow ); 51 | UpdateWindow( wnd ); 52 | 53 | while ( GetMessageW( &msg, NULL, 0, 0 ) > 0 ) 54 | { 55 | TranslateMessage( &msg ); 56 | DispatchMessageW( &msg ); 57 | } 58 | return ( int ) msg.wParam; 59 | } 60 | 61 | LRESULT CALLBACK WndProc( HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam ) 62 | { 63 | switch ( msg ) 64 | { 65 | case WM_LBUTTONDOWN: 66 | { 67 | WCHAR fileName[MAX_PATH]; 68 | HINSTANCE inst = GetWindowInstance( wnd ); 69 | 70 | GetModuleFileNameW( inst, fileName, MAX_PATH ); 71 | MessageBoxW( wnd, fileName, L"This program is:", MB_OK | MB_ICONINFORMATION ); 72 | } 73 | break; 74 | 75 | case WM_CLOSE: 76 | DestroyWindow( wnd ); 77 | break; 78 | 79 | case WM_DESTROY: 80 | PostQuitMessage( 0 ); 81 | break; 82 | 83 | default: 84 | return DefWindowProcW( wnd, msg, wParam, lParam ); 85 | } 86 | return 0; 87 | } 88 | -------------------------------------------------------------------------------- /revised-code/03_menu_one/menu_one_modern/menu_one_modern.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "resource.h" 3 | 4 | PCWSTR g_className = L"myWindowClass"; 5 | 6 | LRESULT CALLBACK WndProc( HWND, UINT, WPARAM, LPARAM ); 7 | 8 | int WINAPI wWinMain( _In_ HINSTANCE hInstance, 9 | _In_opt_ HINSTANCE prevInst, 10 | _In_ PWSTR cmdLine, 11 | _In_ int cmdShow ) 12 | { 13 | UNREFERENCED_PARAMETER( prevInst ); 14 | UNREFERENCED_PARAMETER( cmdLine ); 15 | 16 | WNDCLASSEXW wc = { 0 }; 17 | HWND wnd; 18 | MSG msg; 19 | 20 | wc.cbSize = sizeof( WNDCLASSEXW ); 21 | wc.style = 0; 22 | wc.lpfnWndProc = WndProc; 23 | wc.cbClsExtra = 0; 24 | wc.cbWndExtra = 0; 25 | wc.hInstance = hInstance; 26 | wc.hIcon = ( HICON ) LoadImageW( GetModuleHandleW( NULL ), MAKEINTRESOURCEW( IDI_MYICON ), IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR ); 27 | wc.hIconSm = ( HICON ) LoadImageW( GetModuleHandleW( NULL ), MAKEINTRESOURCEW( IDI_MYICON ), IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR ); 28 | wc.hCursor = ( HCURSOR ) LoadImageW( NULL, IDC_ARROW, IMAGE_CURSOR, 0, 0, LR_SHARED ); 29 | wc.hbrBackground = ( HBRUSH ) ( COLOR_WINDOW + 1 ); 30 | wc.lpszMenuName = MAKEINTRESOURCE( IDR_MYMENU ); 31 | wc.lpszClassName = g_className; 32 | 33 | if ( !RegisterClassExW( &wc ) ) 34 | { 35 | MessageBoxW( NULL, L"Window Registration Failed!", L"Error!", MB_ICONEXCLAMATION | MB_OK ); 36 | return 0; 37 | } 38 | 39 | wnd = CreateWindowExW( WS_EX_CLIENTEDGE, 40 | g_className, 41 | L"A Menu", 42 | WS_OVERLAPPEDWINDOW, 43 | CW_USEDEFAULT, CW_USEDEFAULT, 240, 120, 44 | NULL, NULL, hInstance, NULL ); 45 | 46 | if ( wnd == NULL ) 47 | { 48 | MessageBoxW( NULL, L"Window Creation Failed!", L"Error!", MB_ICONEXCLAMATION | MB_OK ); 49 | return 0; 50 | } 51 | 52 | ShowWindow( wnd, cmdShow ); 53 | UpdateWindow( wnd ); 54 | 55 | while ( GetMessageW( &msg, NULL, 0, 0 ) > 0 ) 56 | { 57 | TranslateMessage( &msg ); 58 | DispatchMessageW( &msg ); 59 | } 60 | 61 | return ( int ) msg.wParam; 62 | } 63 | 64 | LRESULT CALLBACK WndProc( HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam ) 65 | { 66 | switch ( msg ) 67 | { 68 | case WM_COMMAND: 69 | switch ( LOWORD( wParam ) ) 70 | { 71 | 72 | case ID_FILE_EXIT: 73 | PostMessageW( wnd, WM_CLOSE, 0, 0 ); 74 | break; 75 | 76 | case ID_STUFF_GO: 77 | MessageBoxW( wnd, L"You clicked Go!", L"Woo!", MB_ICONINFORMATION | MB_OK ); 78 | break; 79 | } 80 | break; 81 | 82 | case WM_CLOSE: 83 | DestroyWindow( wnd ); 84 | break; 85 | 86 | case WM_DESTROY: 87 | PostQuitMessage( 0 ); 88 | break; 89 | } 90 | 91 | return DefWindowProcW( wnd, msg, wParam, lParam ); 92 | } 93 | -------------------------------------------------------------------------------- /revised-code/01_simple_window/simple_window_modern.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // Step 5: the Window Procedure 4 | LRESULT CALLBACK WndProc( HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam ); 5 | 6 | // Step 1: Desktop WinAPI app entry point 7 | // added SAL (source-code annotation language) to WinMain 8 | // https://learn.microsoft.com/en-us/cpp/code-quality/understanding-sal?view=msvc-170 9 | int WINAPI wWinMain( _In_ HINSTANCE inst, 10 | _In_opt_ HINSTANCE prevInst, 11 | _In_ PWSTR cmdLine, 12 | _In_ int cmdShow ) 13 | { 14 | UNREFERENCED_PARAMETER( prevInst ); 15 | 16 | // WinAPI has several pointer to string data types 17 | // this type is a constant ptr-to-str 18 | // https://learn.microsoft.com/en-us/windows/win32/winprog/windows-data-types 19 | PCWSTR className = L"myWindowClass"; // <-- no need for this to be a global 20 | 21 | WNDCLASSEXW wc = { 0 }; 22 | HWND wnd; 23 | MSG msg; 24 | 25 | // Step 2: Registering the Window Class 26 | wc.cbSize = sizeof( WNDCLASSEXW ); 27 | wc.style = 0; 28 | wc.lpfnWndProc = WndProc; 29 | wc.cbClsExtra = 0; 30 | wc.cbWndExtra = 0; 31 | wc.hInstance = inst; 32 | wc.hIcon = ( HICON ) LoadImageW( NULL, IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR ); 33 | wc.hCursor = ( HCURSOR ) LoadImageW( NULL, IDC_ARROW, IMAGE_CURSOR, 0, 0, LR_SHARED ); 34 | wc.hbrBackground = ( HBRUSH ) ( COLOR_WINDOW + 1 ); 35 | wc.lpszMenuName = NULL; 36 | wc.lpszClassName = className; 37 | wc.hIconSm = ( HICON ) LoadImageW( NULL, IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR ); 38 | 39 | if ( !RegisterClassExW( &wc ) ) 40 | { 41 | MessageBoxW( NULL, L"Window Registration Failed!", L"Critical Error", MB_OK | MB_ICONERROR ); 42 | return 0; 43 | } 44 | 45 | // Step 3: Creating (and showing) the Window 46 | wnd = CreateWindowExW( WS_EX_CLIENTEDGE, 47 | className, 48 | L"The title of my window", 49 | WS_OVERLAPPEDWINDOW, 50 | CW_USEDEFAULT, CW_USEDEFAULT, 51 | 240, 120, 52 | NULL, NULL, inst, NULL ); 53 | 54 | if ( wnd == NULL ) 55 | { 56 | MessageBoxW( NULL, L"Window Creation Failed!", L"Critical Error", MB_OK | MB_ICONERROR ); 57 | return 0; 58 | } 59 | 60 | ShowWindow( wnd, cmdShow ); 61 | UpdateWindow( wnd ); 62 | 63 | // Step 4: The Message Loop 64 | while ( GetMessageW( &msg, NULL, 0, 0 ) > 0 ) 65 | { 66 | TranslateMessage( &msg ); 67 | DispatchMessageW( &msg ); 68 | } 69 | 70 | // needed to stop VS from whinging about possible loss of data 71 | return ( int ) msg.wParam; 72 | } 73 | 74 | // Step 5: the Window Procedure 75 | LRESULT CALLBACK WndProc( HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam ) 76 | { 77 | switch ( msg ) 78 | { 79 | case WM_CLOSE: 80 | DestroyWindow( wnd ); 81 | break; 82 | 83 | case WM_DESTROY: 84 | PostQuitMessage( 0 ); 85 | break; 86 | } 87 | 88 | return DefWindowProcW( wnd, msg, wParam, lParam ); 89 | } 90 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # theForger's Win32 API tutorial 2 | [![Language](https://img.shields.io/badge/Language%20-C-blue.svg)](https://github.com/GeorgePimpleton/theForger-winapi-tutorial/) 3 | [![Platform](https://img.shields.io/badge/Platform%20-Win32-blue.svg)](https://github.com/GeorgePimpleton/theForger-winapi-tutorial/) 4 | 5 | An unofficial repo of theForger's Win32 API tutorial as well as an archive of [theForger's Win32 API Programming Tutorial](http://www.winprog.org/tutorial/) site. 6 | 7 | ### Background 8 | Win9X/Me is officially dead! Windows API ANSI encoding is dead! Windows XP and later now use Unicode! 9 | 10 | Windows and C/C++ have changed since Win9X/Me was Windows. Programmers need to adapt. 11 | 12 | ### Why this repository exists 13 | theForger's Win32 API tutorial is one of the better non-MS affiliated free online resources for learning the basics of Win32 API programming, but the code is IMO hopelessly out-dated. Written when Win9X was the main OS the Windows API has changed since then. Windows is no longer a hybrid 16/32 bit hybrid operating system. The core of the operating system is all 32-bit or 64-bit. 64-bit CPUs are now common and Microsoft has kept up by releasing x64 Windows with a resulting change to the Windows API. 14 | 15 | Multi-core CPUs are also common, but the lessons won't be using more than one core. 16 | 17 | Rewriting the code to work with modern Windows systems is the goal. The goal of having theForger's Win32 API sources compile and work on a modern system whether it is x86 or x64. 18 | 19 | ### Notes 20 | I changed the directory structure to better reflect the tutorial's flow. 21 | 22 | I used Visual Studio 2022 Community edition to rework and modernize the code as made sense to me. The changes aren't the only way to go. 23 | 24 | For most of the examples there are two different sets of code. The first is the bare minimum needed to modify the code to work using the TEXT macro and character data type of TCHAR. This approach allows flexibility when compiling Unicode or ANSI (wide character set). 25 | 26 | The changes for the second examples are (not a complete list): 27 | 28 | 1. Explictly used the Unicode version of WinAPI functions, objects and data types. wWinMain vs. WinMain, for example. WCHAR vs. TCHAR. And so on. 29 | 2. Add/changed some casts so the code would work with both x86 & x64 Windows. 30 | 3. Used SAL on wWinMain to stop Visual Studio whinging about "inconsistent annotations". 31 | 32 | Compare theForger's orginal code and my versions to see what I consider to be necessary or required modifications. It isn't the only way to modify the code. 33 | 34 | Why don't I simply repo the entire solution instead of just the individual source files? My layout might not work for you. I also like being able to compile and test any code for x86 & x64. 35 | 36 | The source files don't require using Visual Studio. As long as you use a Windows compliant compiler the sources should build runnable executables. 37 | 38 | ### Post-script 39 | The code as written by theForger ***is*** compileable as written as long as the code isn't compiled using the Unicode/wide character set. If someone wanted to compile using the Multi-byte character set the code needs zero modification. There will be at least two warnings compiling the unmodified code this way, there should be no errors. 40 | 41 | --- 42 | 43 | ### Update 44 | Real life decided to get nasty and intrude. I also discovered there were some insidious bugs burrowed deep in my revised code. Being a self-taught programming hobbyist I needed (and need) some time to investigate what is wrong. I can't say when I will get back to reworking this code. 45 | -------------------------------------------------------------------------------- /revised-code/04_menu_two/menu_two_minimal.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define ID_FILE_EXIT 9001 4 | #define ID_STUFF_GO 9002 5 | 6 | const TCHAR g_szClassName[ ] = TEXT( "myWindowClass" ); 7 | 8 | LRESULT CALLBACK WndProc( HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam ) 9 | { 10 | switch ( Message ) 11 | { 12 | case WM_CREATE: 13 | { 14 | HMENU hMenu, hSubMenu; 15 | HICON hIcon, hIconSm; 16 | 17 | hMenu = CreateMenu( ); 18 | 19 | hSubMenu = CreatePopupMenu( ); 20 | AppendMenu( hSubMenu, MF_STRING, ID_FILE_EXIT, TEXT( "E&xit" ) ); 21 | AppendMenu( hMenu, MF_STRING | MF_POPUP, ( UINT ) hSubMenu, TEXT( "&File" ) ); 22 | 23 | hSubMenu = CreatePopupMenu( ); 24 | AppendMenu( hSubMenu, MF_STRING, ID_STUFF_GO, TEXT( "&Go" ) ); 25 | AppendMenu( hMenu, MF_STRING | MF_POPUP, ( UINT ) hSubMenu, TEXT( "&Stuff" ) ); 26 | 27 | SetMenu( hwnd, hMenu ); 28 | 29 | hIcon = ( HICON ) LoadImage( NULL, TEXT( "menu_two.ico" ), IMAGE_ICON, 32, 32, LR_LOADFROMFILE ); 30 | if ( hIcon ) 31 | { 32 | SendMessage( hwnd, WM_SETICON, ICON_BIG, ( LPARAM ) hIcon ); 33 | } 34 | else 35 | { 36 | MessageBox( hwnd, TEXT( "Could not load large icon! Is it in the current working directory?" ), TEXT( "Error" ), MB_OK | MB_ICONERROR ); 37 | } 38 | 39 | hIconSm = ( HICON ) LoadImage( NULL, TEXT( "menu_two.ico" ), IMAGE_ICON, 16, 16, LR_LOADFROMFILE ); 40 | if ( hIconSm ) 41 | { 42 | SendMessage( hwnd, WM_SETICON, ICON_SMALL, ( LPARAM ) hIconSm ); 43 | } 44 | else 45 | { 46 | MessageBox( hwnd, TEXT( "Could not load small icon! Is it in the current working directory?" ), TEXT( "Error" ), MB_OK | MB_ICONERROR ); 47 | } 48 | } 49 | break; 50 | case WM_COMMAND: 51 | switch ( LOWORD( wParam ) ) 52 | { 53 | case ID_FILE_EXIT: 54 | PostMessage( hwnd, WM_CLOSE, 0, 0 ); 55 | break; 56 | case ID_STUFF_GO: 57 | MessageBox( hwnd, TEXT( "You clicked Go!" ), TEXT( "Woo!" ), MB_OK ); 58 | break; 59 | } 60 | break; 61 | case WM_CLOSE: 62 | DestroyWindow( hwnd ); 63 | break; 64 | case WM_DESTROY: 65 | PostQuitMessage( 0 ); 66 | break; 67 | default: 68 | return DefWindowProc( hwnd, Message, wParam, lParam ); 69 | } 70 | return 0; 71 | } 72 | 73 | int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, 74 | LPSTR lpCmdLine, int nCmdShow ) 75 | { 76 | WNDCLASSEX wc; 77 | HWND hwnd; 78 | MSG Msg; 79 | 80 | wc.cbSize = sizeof( WNDCLASSEX ); 81 | wc.style = 0; 82 | wc.lpfnWndProc = WndProc; 83 | wc.cbClsExtra = 0; 84 | wc.cbWndExtra = 0; 85 | wc.hInstance = hInstance; 86 | wc.hIcon = NULL; 87 | wc.hCursor = LoadCursor( NULL, IDC_ARROW ); 88 | wc.hbrBackground = ( HBRUSH ) ( COLOR_WINDOW + 1 ); 89 | wc.lpszMenuName = NULL; 90 | wc.lpszClassName = g_szClassName; 91 | wc.hIconSm = NULL; 92 | 93 | if ( !RegisterClassEx( &wc ) ) 94 | { 95 | MessageBox( NULL, TEXT( "Window Registration Failed!" ), TEXT( "Error!" ), 96 | MB_ICONEXCLAMATION | MB_OK ); 97 | return 0; 98 | } 99 | 100 | hwnd = CreateWindowEx( 101 | WS_EX_CLIENTEDGE, 102 | g_szClassName, 103 | TEXT( "A Menu #2" ), 104 | WS_OVERLAPPEDWINDOW, 105 | CW_USEDEFAULT, CW_USEDEFAULT, 240, 120, 106 | NULL, NULL, hInstance, NULL ); 107 | 108 | if ( hwnd == NULL ) 109 | { 110 | MessageBox( NULL, TEXT( "Window Creation Failed!" ), TEXT( "Error!" ), 111 | MB_ICONEXCLAMATION | MB_OK ); 112 | return 0; 113 | } 114 | 115 | ShowWindow( hwnd, nCmdShow ); 116 | UpdateWindow( hwnd ); 117 | 118 | while ( GetMessage( &Msg, NULL, 0, 0 ) > 0 ) 119 | { 120 | TranslateMessage( &Msg ); 121 | DispatchMessage( &Msg ); 122 | } 123 | return Msg.wParam; 124 | } 125 | -------------------------------------------------------------------------------- /revised-code/04_menu_two/menu_two_modern.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define ID_FILE_EXIT 9001 4 | #define ID_STUFF_GO 9002 5 | 6 | PCWSTR g_className = L"myWindowClass"; 7 | 8 | LRESULT CALLBACK WndProc( HWND, UINT, WPARAM, LPARAM ); 9 | 10 | int WINAPI wWinMain( _In_ HINSTANCE inst, 11 | _In_opt_ HINSTANCE prevInst, 12 | _In_ PWSTR cmdLine, 13 | _In_ int cmdShow ) 14 | { 15 | UNREFERENCED_PARAMETER( prevInst ); 16 | UNREFERENCED_PARAMETER( cmdLine ); 17 | 18 | WNDCLASSEXW wc = { 0 }; 19 | HWND wnd; 20 | MSG msg; 21 | 22 | wc.cbSize = sizeof( WNDCLASSEXW ); 23 | wc.style = 0; 24 | wc.lpfnWndProc = WndProc; 25 | wc.cbClsExtra = 0; 26 | wc.cbWndExtra = 0; 27 | wc.hInstance = inst; 28 | wc.hIcon = NULL; 29 | wc.hIconSm = NULL; 30 | wc.hCursor = ( HCURSOR ) LoadImageW( NULL, IDC_ARROW, IMAGE_CURSOR, 0, 0, LR_SHARED ); 31 | wc.hbrBackground = ( HBRUSH ) ( COLOR_WINDOW + 1 ); 32 | wc.lpszMenuName = NULL; 33 | wc.lpszClassName = g_className; 34 | 35 | if ( !RegisterClassExW( &wc ) ) 36 | { 37 | MessageBoxW( NULL, L"Window Registration Failed!", L"Error!", 38 | MB_ICONEXCLAMATION | MB_OK ); 39 | return 0; 40 | } 41 | 42 | wnd = CreateWindowExW( WS_EX_CLIENTEDGE, 43 | g_className, 44 | L"A Menu #2", 45 | WS_OVERLAPPEDWINDOW, 46 | CW_USEDEFAULT, CW_USEDEFAULT, 240, 120, 47 | NULL, NULL, inst, NULL ); 48 | 49 | if ( wnd == NULL ) 50 | { 51 | MessageBoxW( NULL, L"Window Creation Failed!", L"Error!", 52 | MB_ICONEXCLAMATION | MB_OK ); 53 | return 0; 54 | } 55 | 56 | ShowWindow( wnd, cmdShow ); 57 | UpdateWindow( wnd ); 58 | 59 | while ( GetMessageW( &msg, NULL, 0, 0 ) > 0 ) 60 | { 61 | TranslateMessage( &msg ); 62 | DispatchMessageW( &msg ); 63 | } 64 | 65 | return ( int ) msg.wParam; 66 | } 67 | 68 | LRESULT CALLBACK WndProc( HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam ) 69 | { 70 | switch ( msg ) 71 | { 72 | case WM_CREATE: 73 | { 74 | HMENU hMenu; 75 | HMENU hSubMenu; 76 | HICON hIcon; 77 | HICON hIconSm; 78 | 79 | hMenu = CreateMenu( ); 80 | 81 | hSubMenu = CreatePopupMenu( ); 82 | AppendMenuW( hSubMenu, MF_STRING, ID_FILE_EXIT, L"E&xit" ); 83 | AppendMenuW( hMenu, MF_STRING | MF_POPUP, ( UINT_PTR ) hSubMenu, L"&File" ); 84 | 85 | hSubMenu = CreatePopupMenu( ); 86 | AppendMenuW( hSubMenu, MF_STRING, ID_STUFF_GO, L"&Go" ); 87 | AppendMenuW( hMenu, MF_STRING | MF_POPUP, ( UINT_PTR ) hSubMenu, L"&Stuff" ); 88 | 89 | SetMenu( wnd, hMenu ); 90 | 91 | hIcon = ( HICON ) LoadImageW( NULL, L"menu_two.ico", IMAGE_ICON, 32, 32, LR_LOADFROMFILE ); 92 | 93 | if ( hIcon ) 94 | { 95 | SendMessageW( wnd, WM_SETICON, ICON_BIG, ( LPARAM ) hIcon ); 96 | } 97 | else 98 | { 99 | MessageBoxW( wnd, L"Could not load large icon! Is it in the current working directory?", L"Error", MB_OK | MB_ICONERROR ); 100 | } 101 | 102 | hIconSm = ( HICON ) LoadImageW( NULL, L"menu_two.ico", IMAGE_ICON, 16, 16, LR_LOADFROMFILE ); 103 | 104 | if ( hIconSm ) 105 | { 106 | SendMessageW( wnd, WM_SETICON, ICON_SMALL, ( LPARAM ) hIconSm ); 107 | } 108 | else 109 | { 110 | MessageBoxW( wnd, L"Could not load small icon! Is it in the current working directory?", L"Error", MB_OK | MB_ICONERROR ); 111 | } 112 | } 113 | break; 114 | 115 | case WM_COMMAND: 116 | switch ( LOWORD( wParam ) ) 117 | { 118 | case ID_FILE_EXIT: 119 | PostMessageW( wnd, WM_CLOSE, 0, 0 ); 120 | break; 121 | 122 | case ID_STUFF_GO: 123 | MessageBoxW( wnd, L"You clicked Go!", L"Woo!", MB_ICONINFORMATION | MB_OK ); 124 | break; 125 | } 126 | break; 127 | 128 | case WM_CLOSE: 129 | DestroyWindow( wnd ); 130 | break; 131 | 132 | case WM_DESTROY: 133 | PostQuitMessage( 0 ); 134 | break; 135 | } 136 | 137 | return DefWindowProcW( wnd, msg, wParam, lParam ); 138 | } 139 | --------------------------------------------------------------------------------