Файл edit\edit.cpp
// ---------------------------------------- // Редактор текста // ----------------------------------------
#define STRICT #include <windows.h>
#include <mem.h>
// Идентификатор редактора текста #define ID_EDIT 1
// Идентификатор кнопки #define ID_BUTTON 2
// Прототипы функций BOOL InitApp(HINSTANCE);
LRESULT CALLBACK _export WndProc(HWND, UINT, WPARAM, LPARAM);
// Имя класса окна char const szClassName[] = "EditAppClass";
// Заголовок окна char const szWindowTitle[] = "Edit Demo";
// Идентификатор копии приложения HINSTANCE hInst;
// ===================================== // Функция WinMain // ===================================== #pragma argsused
int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow) { MSG msg; // структура для работы с сообщениями HWND hwnd; // идентификатор главного окна приложения
// Инициализируем приложение if(!InitApp(hInstance)) return FALSE;
// Сохраняем идентификатор копии приложения // в глобальной переменной hInst = hInstance;
// После успешной инициализации приложения создаем // главное окно приложения hwnd = CreateWindow( szClassName, // имя класса окна szWindowTitle, // заголовок окна WS_OVERLAPPEDWINDOW, // стиль окна CW_USEDEFAULT, // задаем расположение и размеры CW_USEDEFAULT, // окна, принятые по умолчанию CW_USEDEFAULT, // CW_USEDEFAULT, // 0, // идентификатор родительского окна 0, // идентификатор меню hInstance, // идентификатор приложения NULL);
// указатель на дополнительные // параметры // Если создать окно не удалось, завершаем приложение if(!hwnd) return FALSE;
// Рисуем главное окно ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
// Запускаем цикл обработки сообщений while(GetMessage(&msg, 0, 0, 0)) { // Создаем символьные сообщения TranslateMessage(&msg);
DispatchMessage(&msg);
} return msg.wParam; }
// ===================================== // Функция InitApp // Выполняет регистрацию класса окна // =====================================
BOOL InitApp(HINSTANCE hInstance) { ATOM aWndClass; // атом для кода возврата WNDCLASS wc; // структура для регистрации // класса окна
memset(&wc, 0, sizeof(wc));
wc.style = 0; wc.lpfnWndProc = (WNDPROC) WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszMenuName = (LPSTR)NULL; wc.lpszClassName = (LPSTR)szClassName;
// Регистрация класса aWndClass = RegisterClass(&wc);
return (aWndClass != 0);
}
// ===================================== // Функция WndProc // =====================================
LRESULT CALLBACK _export WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { // Идентификатор редактора текста static HWND hEdit;
// Идентификатор кнопки static HWND hButton;
switch (msg) { case WM_CREATE: { // Создаем редактор текста hEdit = CreateWindow("edit", NULL, WS_CHILD | WS_VISIBLE | WS_BORDER | ES_LEFT, 30, 30, 300, 30, hwnd, (HMENU) ID_EDIT, hInst, NULL);
// Создаем кнопку hButton = CreateWindow("button", "OK", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 30, 80, 100, 30, hwnd, (HMENU) ID_BUTTON, hInst, NULL);
return 0; }
// Когда главное окно приложения получает // фокус ввода, отдаем фокус редактору текста case WM_SETFOCUS: { SetFocus(hEdit);
return 0; }
case WM_COMMAND: { // Обработка извещения текстового редактора // об ошибке if(wParam == ID_EDIT) { if(HIWORD(lParam) == EN_ERRSPACE) { MessageBox(hwnd, "Мало памяти", szWindowTitle, MB_OK);
} }
// Сообщение от кнопки else if(wParam == ID_BUTTON) { BYTE chBuff[80]; WORD cbText;
// Записываем в первое слово буфера // значение размера буфера в байтах * (WORD *) chBuff = sizeof (chBuff) - 1;
// Получаем от редактора текста содержимое // первой строки. Функция возвращает количество // байт, скопированных в буфер cbText = SendMessage(hEdit, EM_GETLINE, 0, (LPARAM)(LPSTR)chBuff);
// Закрываем буфер двоичным нулем chBuff[cbText] = '\0';
// Выводим содержимое буфера на экран MessageBox(hwnd, chBuff, szWindowTitle, MB_OK);
} return 0; }
case WM_PAINT: { HDC hdc; PAINTSTRUCT ps;
// Получаем индекс контекста устройства hdc = BeginPaint(hwnd, &ps);
// Выводим текстовую строку TextOut(hdc, 30, 10, "Введите строку и нажмите кнопку 'OK'", 36);
// Отдаем индекс контекста устройства EndPaint(hwnd, &ps);
return 0; }
case WM_DESTROY: { PostQuitMessage(0);
return 0; } } return DefWindowProc(hwnd, msg, wParam, lParam);
}
В начале исходного текста определены идентификаторы редактора текста и кнопки:
#define ID_EDIT 1 #define ID_BUTTON 2
Функция WinMain приложения EDIT не имеет никаких особенностей. Она создает одно главное окно и организует цикл обработки сообщений. Так как текстовый редактор работает с символьными сообщениями, в цикле обработки сообщений вызывается функция TranslateMessage:
while(GetMessage(&msg, 0, 0, 0)) { TranslateMessage(&msg);
DispatchMessage(&msg);
}
В функции главного окна приложения определены две статические переменные для хранения идентификаторов созданных органов управления - редактора текста и кнопки:
static HWND hEdit; static HWND hButton;
По сообщению WM_CREATE функция окна создает редактор текста и кнопку, вызывая функцию CreateWindow. При создании текстового редактора используется комбинация стилей WS_CHILD | WS_VISIBLE | WS_BORDER | ES_LEFT. При этом создается дочернее окно, которое изначально является видимым и имеет рамку. Для текста задается выравнивание по левой границе:
hEdit = CreateWindow("edit", NULL, WS_CHILD | WS_VISIBLE | WS_BORDER | ES_LEFT, 30, 30, 300, 30, hwnd, (HMENU) ID_EDIT, hInst, NULL);
Когда главное окно приложения получает фокус ввода, в его функцию передается сообщение WM_SETFOCUS. Но нам нужно, чтобы фокус ввода получил редактор текста, так как именно он будет обрабатывать символьные сообщения, поступающие от клавиатуры. Поэтому в ответ на сообщение WM_SETFOCUS функция главного окна отдает фокус ввода текстовому редактору, вызывая функцию SetFocus:
case WM_SETFOCUS: { SetFocus(hEdit);
return 0; }
Сообщение WM_COMMAND может приходить в функцию главного окна от текстового редактора или от кнопки.
Если сообщение пришло от текстового редактора, параметр wParam этого сообщения содержит идентификатор редактора ID_EDIT. В этом случае обработчик сообщения получает код извещения из старшего байта параметра lParam. Обрабатывается только одно извещение с кодом EN_ERRSPACE (мало памяти).
Если же сообщение WM_COMMAND пришло от кнопки, параметр wParam этого сообщения содержит идентификатор кнопки ID_BUTTON. Обработчик такого сообщения читает содержимое первой (и единственной) строки текстового редактора в специальным образом подготовленный буфер и выводит строку на экран, вызывая функцию MessageBox.
Подготовка буфера заключается в том, что в его первое слово записывается размер буфера в байтах:
* (WORD *) chBuff = sizeof (chBuff) - 1;
Затем текстовому редактору посылается сообщение EM_GETLINE:
cbText = SendMessage(hEdit, EM_GETLINE, 0, (LPARAM)(LPSTR)chBuff);
В качестве парамера lParam используется адрес подготовленного буфера.
После посылки сообщения функция SendMessage возвращает количество скопированных в буфер символов, причем буфер нулем не закрывается. Далее обработчик сообщения закрывает буфер нулем и выводит содержимое буфера на экран:
chBuff[cbText] = '\0'; MessageBox(hwnd, chBuff, szWindowTitle, MB_OK);
Обработчик сообщения WM_PAINT выводит в окно приглашение для ввода текста, вызывая функцию TextOut:
TextOut(hdc, 30, 10, "Введите строку и нажмите кнопку 'OK'", 36);
Файл определения модуля для приложения EDIT приведен в листинге 2.23.