В статье рассказывается как создать Win32 приложение сложения двух чисел в Visual Studio 2015 на С++.
Статья из цикла «Сложение двух чисел». Для меня минимальное освоение любой системы программирования начинается с возможности создания такой программы. Если можно написать приложение, в которой пользователь может ввести два числа, считать их, провести с ними какие-то действия, а потом вывести результат, то, значит, базовое владение имеется. И много задач именно из области программирования, алгоритмики можно будет решать, зная, как в конкретной системе программирования запрограммировать такую программу.
Содержание
Чтоб я еще когда-нибудь связался с этим Win32 приложениями! После опыта написания приложения прекрасно понимаю, почему никто не любит так программировать. Использовал в частности материал статей этой и этой.
Создание проекта
Создадим пустой проект.
Добавление файла
Мы создали пустой проект, поэтому нужно самим добавить файл cpp.
Написание кода основной программы
Вначале подключим инклуды и пропишем главную функцию:
1 2 3 4 5 6 7 8 9 10 |
#include <windows.h> #include <tchar.h> //Главная функция int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { } |
Нам потребуются глобальные переменные:
1 2 3 |
//Глобальные переменные static TCHAR szWindowClass[] = _T("win32app");//Имя класса главного окна static TCHAR szTitle[] = _T("Сложение двух чисел");//Заголовок окна |
Теперь в функции можем прописать описание нашего окна.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
//Определим внешний вид окна WNDCLASSEX wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = WndProc;//Тут прописана та функция, в которой прописан главный функционал wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION)); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wcex.lpszMenuName = NULL; wcex.lpszClassName = szWindowClass; wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_APPLICATION)); |
Обратите внимание на строчку wcex.lpfnWndProc = WndProc;. Тут прописана функция, в которой мы пропишем основной функционал. Её пропишем далее.
Далее можем зарегистрировать класс нашего окна:
1 2 3 4 5 6 7 8 9 10 |
//Зарегистрируем наше окно if (!RegisterClassEx(&wcex)) { MessageBox(NULL, _T("Call to RegisterClassEx failed!"), _T("Win32 Guided Tour"), NULL); return 1; } |
Теперь создадим наше окно:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
//Создадим окно HWND hWnd = CreateWindow( szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 200, 200,//Размеры окна NULL, NULL, hInstance, NULL ); if (!hWnd) { MessageBox(NULL, _T("Создать окно не получилось"), _T("Ошибка"), NULL); return 1; } |
И запустим его:
1 2 3 4 |
// Теперь можем запустить наше окно ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); |
Жесть! Сколько уже кода написано!
Ну, а потом начнем слушать сообщения от операционной системы Windows.
1 2 3 4 5 6 7 8 9 |
// Слушаем сообщения от ОС MSG msg; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return (int)msg.wParam; |
Пропишем болванку функции WndProc, о которой мы уже говорили выше:
1 2 3 4 5 |
//Главный функционал LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { return 0; } |
Сейчас код программы выглядит так:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
#include <windows.h> #include <tchar.h> //Глобальные переменные static TCHAR szWindowClass[] = _T("win32app");//Имя класса главного окна static TCHAR szTitle[] = _T("Сложение двух чисел");//Заголовок окна // Список функций LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); //Главная функция int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { //Определим внешний вид окна WNDCLASSEX wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = WndProc;//Тут прописана та функция, в которой прописан главный функционал wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION)); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wcex.lpszMenuName = NULL; wcex.lpszClassName = szWindowClass; wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_APPLICATION)); //Зарегистрируем наше окно if (!RegisterClassEx(&wcex)) { MessageBox(NULL, _T("Call to RegisterClassEx failed!"), _T("Win32 Guided Tour"), NULL); return 1; } //Создадим окно HWND hWnd = CreateWindow( szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 200, 200,//Размеры окна NULL, NULL, hInstance, NULL ); if (!hWnd) { MessageBox(NULL, _T("Создать окно не получилось"), _T("Ошибка"), NULL); return 1; } // Теперь можем запустить наше окно ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); // Слушаем сообщения от ОС MSG msg; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return (int)msg.wParam; } LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { return 0; } |
У нас будет два поля для ввода текста, одно поле для вывода и кнопка. Для каждого контрола создадим свой индентификатор уникальный. По нему потом будем искать нужен контрол.
1 2 3 4 5 |
//Идентификаторы наших контролов: полей ввода и кнопки #define EDIT1 110 #define EDIT2 111 #define EDIT3 112 #define BUTTON 113 |
Теперь в функции WndProc создадим нужные контролы.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_CREATE: //Первое число CreateWindowEx(WS_EX_CLIENTEDGE, TEXT("EDIT"), TEXT("0"), WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL | WS_TABSTOP, 20, 10, 85, 25, hWnd, HMENU(EDIT1), GetModuleHandle(NULL), NULL); //Второе число CreateWindowEx(WS_EX_CLIENTEDGE, TEXT("EDIT"), TEXT("0"), WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL | WS_TABSTOP, 20, 45, 85, 25, hWnd, HMENU(EDIT2), GetModuleHandle(NULL), NULL); //Сюда будем выводить результат CreateWindowEx(WS_EX_CLIENTEDGE, TEXT("EDIT"), TEXT("0"), WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL | WS_TABSTOP, 20, 85, 85, 25, hWnd, HMENU(EDIT3), GetModuleHandle(NULL), NULL); //Кнопка сложения CreateWindowEx(NULL, TEXT("BUTTON"), TEXT("+"), WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON | WS_TABSTOP, 115, 45, 30, 25, hWnd, HMENU(BUTTON), GetModuleHandle(NULL), NULL); break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); break; } return 0; } |
Обратите внимание, где мы используем идентификаторы вроде такого HMENU(EDIT1).
При запуске программы мы увидим вот такое приложение:
Но пока кнопка не работает. В нашу функцию WndProc добавим отслеживание нажатия на кнопку.
1 2 3 4 5 6 7 8 |
case WM_COMMAND: switch (LOWORD(wParam)) { case BUTTON: //Тут наш код return 1; } break; |
Функция примет вид:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_CREATE: //Первое число CreateWindowEx(WS_EX_CLIENTEDGE, TEXT("EDIT"), TEXT("0"), WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL | WS_TABSTOP, 20, 10, 85, 25, hWnd, HMENU(EDIT1), GetModuleHandle(NULL), NULL); //Второе число CreateWindowEx(WS_EX_CLIENTEDGE, TEXT("EDIT"), TEXT("0"), WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL | WS_TABSTOP, 20, 45, 85, 25, hWnd, HMENU(EDIT2), GetModuleHandle(NULL), NULL); //Сюда будем выводить результат CreateWindowEx(WS_EX_CLIENTEDGE, TEXT("EDIT"), TEXT("0"), WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL | WS_TABSTOP, 20, 85, 85, 25, hWnd, HMENU(EDIT3), GetModuleHandle(NULL), NULL); //Кнопка сложения CreateWindowEx(NULL, TEXT("BUTTON"), TEXT("+"), WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON | WS_TABSTOP, 115, 45, 30, 25, hWnd, HMENU(BUTTON), GetModuleHandle(NULL), NULL); break; case WM_DESTROY: PostQuitMessage(0); break; case WM_COMMAND: switch (LOWORD(wParam)) { case BUTTON: //Тут наш код return 1; } break; default: return DefWindowProc(hWnd, message, wParam, lParam); break; } return 0; } |
Чтобы не захламлять код вынесем обработку клика кнопки в отдельную функцию:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
//Функция сложения двух чисел void Addition(HWND hWnd) { BOOL success = false; int a = GetDlgItemInt(hWnd, EDIT1, &success, true); if (!success) { MessageBox(hWnd, TEXT("В первом поле не целое число"), TEXT("Ошибка"), MB_OK); } int b = GetDlgItemInt(hWnd, EDIT2, &success, true); if (!success) { MessageBox(hWnd, TEXT("Во втором поле не целое число"), TEXT("Ошибка"), MB_OK); } int c = a + b; SetDlgItemInt(hWnd, EDIT3, c, true); } |
И в итоге получим вот такой полный код нашего приложения:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 |
#include <windows.h> #include <tchar.h> //Идентификаторы наших контролов: полей ввода и кнопки #define EDIT1 110 #define EDIT2 111 #define EDIT3 112 #define BUTTON 113 //Глобальные переменные static TCHAR szWindowClass[] = _T("win32app");//Имя класса главного окна static TCHAR szTitle[] = _T("Сложение двух чисел");//Заголовок окна // Список функций LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); void Addition(HWND hWnd); //Главная функция int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { //Определим внешний вид окна WNDCLASSEX wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = WndProc;//Тут прописана та функция, в которой прописан главный функционал wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION)); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wcex.lpszMenuName = NULL; wcex.lpszClassName = szWindowClass; wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_APPLICATION)); //Зарегистрируем наше окно if (!RegisterClassEx(&wcex)) { MessageBox(NULL, _T("Call to RegisterClassEx failed!"), _T("Win32 Guided Tour"), NULL); return 1; } //Создадим окно HWND hWnd = CreateWindow( szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 200, 200,//Размеры окна NULL, NULL, hInstance, NULL ); if (!hWnd) { MessageBox(NULL, _T("Создать окно не получилось"), _T("Ошибка"), NULL); return 1; } // Теперь можем запустить наше окно ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); // Слушаем сообщения от ОС MSG msg; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return (int)msg.wParam; } //Функция сложения двух чисел void Addition(HWND hWnd) { BOOL success = false; int a = GetDlgItemInt(hWnd, EDIT1, &success, true); if (!success) { MessageBox(hWnd, TEXT("В первом поле не целое число"), TEXT("Ошибка"), MB_OK); } int b = GetDlgItemInt(hWnd, EDIT2, &success, true); if (!success) { MessageBox(hWnd, TEXT("Во втором поле не целое число"), TEXT("Ошибка"), MB_OK); } int c = a + b; SetDlgItemInt(hWnd, EDIT3, c, true); } LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_CREATE: //Первое число CreateWindowEx(WS_EX_CLIENTEDGE, TEXT("EDIT"), TEXT("0"), WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL | WS_TABSTOP, 20, 10, 85, 25, hWnd, HMENU(EDIT1), GetModuleHandle(NULL), NULL); //Второе число CreateWindowEx(WS_EX_CLIENTEDGE, TEXT("EDIT"), TEXT("0"), WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL | WS_TABSTOP, 20, 45, 85, 25, hWnd, HMENU(EDIT2), GetModuleHandle(NULL), NULL); //Сюда будем выводить результат CreateWindowEx(WS_EX_CLIENTEDGE, TEXT("EDIT"), TEXT("0"), WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL | WS_TABSTOP, 20, 85, 85, 25, hWnd, HMENU(EDIT3), GetModuleHandle(NULL), NULL); //Кнопка сложения CreateWindowEx(NULL, TEXT("BUTTON"), TEXT("+"), WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON | WS_TABSTOP, 115, 45, 30, 25, hWnd, HMENU(BUTTON), GetModuleHandle(NULL), NULL); break; case WM_DESTROY: PostQuitMessage(0); break; case WM_COMMAND: switch (LOWORD(wParam)) { case BUTTON: Addition(hWnd); return 1; } break; default: return DefWindowProc(hWnd, message, wParam, lParam); break; } return 0; } |
Ну, и монстр получился! Зато теперь всё работает:
Вот наше приложение и написано. Пока всё)
P.S. До этого WinAPI я никогда не занимался, и надеюсь, что в дальнейшим не придется! Так что помочь в каких-нибудь вопросах не смогу.