Простейшая программа
В первых частях книги мы достаточно часто будем использовать шаблон Win32 Application , который создает нам Visual C++. Поэтому сейчас необходимо подробнее рассмотреть некоторые вещи, которые нам пригодятся уже в ближайшем будущем. В специализированной литературе по Visual C++ вы сможете найти более детальное описание, а сейчас мы поговорим о самом необходимом.
Код программы
Листинг 1.1. Исходный код файла ctest.cpp |
#include "stdafx.h"
#include "ctest.h"
#define MAX_LOADSTRING 100
// Global Variables:
// (Глобальные переменные):
HINSTANCE hInst; // current instance
// (текущий интерфейс)
TCHAR szTitle[MAX_LOADSTRING]; // The title bar text
// (Заголовок окна)
TCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name
// (Имя класса главного окна)
// Forward declarations of functions included in this code module:
// Описание процедур, используемых в этом модуле:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK About(HWND, UINT, WPARAM, LPARAM);
int APIENTRY _tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
// TODO: Place code here.
//(Поместите свой код здесь)
MSG msg;
HACCEL hAccelTable;
// Initialize global strings
// (Инициализация глобальных строк)
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_CTEST, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// Perform application initialization:
// (Инициализация приложения:)
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_CTEST);
// Main message loop:
//(Главный цикл обработки сообщений:)
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int) msg.wParam;
}
// FUNCTION (Функция): MyRegisterClass()
// PURPOSE (Предназначение): Registers the window class
// (Регистрация класса окна)
// COMMENTS (Комментарии):
// This function and its usage are only necessary if you want this code
// to be compatible with Win32 systems prior to the 'RegisterClassEx'
// function that was added to Windows 95.
// It is important to call this function so that the application
// will get 'well formed' small icons associated with it.
// (Эта функция и ее использование необходимы, только если вы хотите,
// чтобы этот код был совместим с системой Win32 до функции
// 'RegisterClassEx', которая была добавлена в Windows 95.
// Это важно, вызвать эту функцию так, чтобы приложение получило
// 'хорошо отфарматированную' маленькую иконку, ассоциированную с ним.)
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = (WNDPROC)WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_CTEST);
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = (LPCTSTR)IDC_CTEST;
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);
return RegisterClassEx(&wcex);
}
// FUNCTION (Функция): InitInstance(HANDLE, int)
// PURPOSE (Предназначение): Saves instance handle and creates main
// window
// (Функция сохраняет указатель экземпляра и создает окно)
// COMMENTS (Комментарии):
// In this function, we save the instance handle in a global variable
// and create and display the main program window.
// (В этой функции мы сохраняем указатель экземпляра в глобальной
// переменной, создаем и отобажаем главное окно.)
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd;
hInst = hInstance; // Store instance handle in our global variable
// (Сохраняем указатель экземпляра в глобальной переменной)
hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
// FUNCTION (Функция): WndProc(HWND, unsigned, WORD, LONG)
// PURPOSE (Предназначение): Processes messages for the main window
// (Обработка сообщений главного окна)
// WM_COMMAND — process the application menu
// (обработка меню приложения)
// WM_PAINT - Paint the main window
// (Прорисовка окна)
// WM_DESTROY — post a quit message and return
// (отправка сообщения о выходе из программы)
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
switch (message)
{
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
// Проверка выбранного меню:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code here...
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
// Message handler for about box
// (Обработчик сообщения для окна "О программе")
// Мы окно о программе удалили, поэтому следующий код можно удалять
LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_INITDIALOG:
return TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return TRUE;
}
break;
}
return FALSE;
}
// Мы окно о программе удалили, поэтому следующий код можно удалять
Этот код отображает окно О программе, и его можно удалять полностью.
case IDM_ABOUT:
DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About);
break;
case Идентификатор
Действия
break;
Здесь Идентификатор — это константа, которая назначена элементу управления (например, пункту меню). Оператор case проверяет, если пришло событие от элемента управления с указанным идентификатором, то выполняется последующий код до оператора break. Чуть позже мы познакомимся с событиями на практике.
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
Эти строки находятся в процедуре InitInstance, которая предназначена для создания и отображения окна на рабочем столе. Создание окна можно и не убирать, а вот для того, чтобы программа стала невидимой, отображать ничего не надо.
Листинг 1.2. Стартовая функция |
int APIENTRY _tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
// Дальше идет объявление двух переменных
MSG msg;
HACCEL hAccelTable;
// Инициализация строковых переменных
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hlnstance, IDC_CTEST, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// Выполнение инициализации приложения
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_CTEST);
// Главный цикл обработки сообщений Windows
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int) msg.wParam;
}
Все функции в C++ объявляются следующим образом:
Тип Имя (Параметры)
{
}
У нашей главной функции после возвращаемого типа стоит ключевое слово APIENTRY, которое указывает на точку входа программы.
В самом начале функции объявляются две переменные:
MSG msg;
HACCEL hAccelTable ;
При объявлении указывают Тип и Имя. По типу программа определяет количество памяти, которое надо выделить под хранение значения переменной. К этой памяти можно обратиться с помощью указанного имени. В C++ достаточно много типов переменных, и с основными из них мы познакомимся в процессе изучения примеров.
После объявления переменных идут следующие две строки:
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_CTEST, szWindowClass, MAX_LOADSTRING);
После этого идет вызов функции MyRegisterClass(hInstance). В ней происходит заполнение структуры WNDCLASSEX. Что такое структура? Это особая переменная, которая хранит в себе набор переменных любого типа. Например, структура может хранить одну переменную с именем Age числового типа и одну строкового — с именем Name. Чтобы прочитать или изменить значение этих переменных, нужно написать Структура.Переменная. Структура — это имя структурной переменной, а переменная — это имя переменной.
WNDCLASSEX — это структура, которая используется при создании нового класса окна. Для минимального приложения нам понадобится заполнить следующие поля (основные):
- style — стиль окна;
- Lpfnwndproc — указатель на процедуру, которая будет вызываться на все пользовательские или системные события;
- Hinstance — манипулятор, который мы получили при запуске программы в процедуре _tWinMain;
- HbrBackground — цвет фона (в принципе, он необязателен, но по умолчанию используется цвет окна);
- LpszClassName — имя создаваемого класса;
- Hcursor — курсор. Сюда загружается стандартный курсор-стрелка.
hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
У нее достаточно много параметров, и давайте посмотрим на них внимательнее.
И последняя подготовительная функция — UpdateWindow. Это просто отрисовка созданного окна.
Чуть позже мы еще встретимся с процедурой ShowWindow, и не один раз.