В этой статье речь пойдёт о буфере и о таймере отсчёта.
Для начала убедитесь, что Вы разбираетесь в выделении памяти с помощью функции alloc (malloc), free, с помощью операторов new, delete и понимаете функцию преобразованию itoa().
Рассмотрим листинг, представленный ниже:
LRESULT CALLBACK WindowProcess(HWND hWindow, UINT uMessage,
WPARAM wParameter, LPARAM lParameter)
{
HDC hDeviceContext;
PAINTSTRUCT paintStruct;
RECT rectPlace;
HFONT hFont;
static PTCHAR text;
static int size = 0;
switch (uMessage)
{
case WM_CREATE:
text=(PTCHAR)GlobalAlloc(GPTR,50000*sizeof(TCHAR));
break;
case WM_PAINT:
hDeviceContext = BeginPaint(hWindow, &paintStruct);
GetClientRect(hWindow, &rectPlace);
SetTextColor(hDeviceContext, NULL);
hFont=CreateFont(50,0,0,0,0,0,0,0,
DEFAULT_CHARSET,
0,0,0,VARIABLE_PITCH,
"Arial Bold");
SelectObject(hDeviceContext,hFont);
if(wParameter != VK_RETURN)
DrawText(hDeviceContext,
(LPCSTR)text,
size, &rectPlace,
DT_SINGLELINE|DT_CENTER|DT_VCENTER);
EndPaint(hWindow, &paintStruct);
break;
case WM_CHAR:
switch(wParameter)
{
case VK_RETURN:
size=0;
break;
default:
text[size]=(char)wParameter;
size++;
break;
}
InvalidateRect(hWindow, NULL, TRUE);
break;
case WM_DESTROY:
PostQuitMessage(NULL);
GlobalFree((HGLOBAL)text);
break;
default:
return DefWindowProc(hWindow, uMessage, wParameter, lParameter);
}
return NULL;
}
Результат после ввода CppStudio.com будет таким:
Код для функции WinMain не приводится, так как он не менялся с предыдущих уроков.
Данная программа позволяет вводить текст по мере возможности и стирать его клавишей ENTER.
Наверное, Вы заметили, что в программе в предыдущем уроке для считывания нажатой клавиши мы использовали message WM_KEYDOWN, а здесь что-то новое — WM_CHAR.
Отличительная особенность в том, что WM_KEYDOWNнужен для обработки специальных клавиш типа shift, ctrl и т.п., а WM_CHAR– отвечает за обработку символов. Обычно они работают вместе для комбинаций клавиш и вызывают друг друга. В этом Вы убедитесь, когда мы будем разбирать работу текстового редактора.
По умолчанию в MVS используется Юникод. Его отключение производится следующим образом: заходим в свойства проекта

и отключаем Юникод, нажав «Использовать многобайтовую кодировку».

После того, как Вы это сделаете, перед строками не нужно будет писать L, и представленный код не будет иметь ошибок. По этой причине в программе прошлого урока было не правильное отображение некоторых символов.
Теперь второе отличие: мы можем вводить текст (примерно до 50 кБ), который сохранится в буфере.
Конструкция создания, использования, удаления буфера выглядит так:
static PTCHAR text;
text=(PTCHAR)GlobalAlloc(GPTR,50000*sizeof(TCHAR));
if()
{
//....
// заполняем буфер информацией, используем её, где нам нужно
//.....
GlobalFree((HGLOBAL)text);
}
Она аналогична alloc() и free() и её смысл абсолютно такой же.
PTCHAR — указатель на тип TCHAR.
GPTR — режим выделения памяти (в данном случае фиксированное)
HGLOBAL — тип возвращаемого значения функции GlobalAlloc()
Третье достоинство нашей программы — возможность стирать текст (строки 36-38).
В случае нажатия клавиши ENTER – мы делаем окно не действительным с помощью функции InvalidateRect() (строка 44), тем самым вызываем сообщение WM_PAINT. В нём прописано, что если параметр wParameter был равен VK_RETURN (то есть ENTER), то мы перерисовываем окно и не вызываем функцию DrawText().
И, как и обещалось ранее, добавим в функцию таймер и некоторые другие особенности.
static int sec = 0;
TCHAR workTime[10];
//...
switch (wParameter)
{
case WM_CREATE:
SetTimer(hWindow, 1, 1000, NULL);
//...
SetForegroundWindow(hWindow);
break;
case WM_CHAR:
//...
case VK_BACK:
if(size!=0)
size--;
break;
case WM_TIMER:
sec++;
break;
case WM_DESTROY:
KillTimer(hWindow, 1);
_itoa(sec, workTime, 10); MessageBox(NULL, (LPCSTR)workTime, "Время работы программы (сек.):", MB_ICONASTERISK|MB_OK);
//...
break;
}
Добавьте в соответствующие места программы выше представленный код.
Функция SetTimer() создаёт таймер. Первый параметр — дескриптор окна, третий — интервал срабатывания WM_TIMER в миллисекундах, второй — количество вызовов WM_TIMER в заданный интервал времени. Четвёртый параметр — нам не нужен.
В сообщении WM_TIMER мы увеличиваем sec на единицу.
Функция KillTimer() — удаляет таймер. Параметры те же, что и в SetTimer().
Чтобы отобразить время работы программы, в WM_DESTROYмы преобразовываем int в TCHAR массив при помощи функции _itoa, выводим строку на экран, удаляем таймер и освобождаем память, выделенную под буфер.
Функция SetForegroundWindow(HWND) – делает окно активным. Например, если Вы находитесь на сайте CppStudio.com и при этом идёт компиляция данной программы, это окно появится поверх браузера с фокусом для ввода.
Для возможности удаления одного или нескольких символов добавлен обработчик VK_BACK– нажатие клавиши backspace. Если size не равен нулю (то есть не был нажат ENTER), мы уменьшаем его на единицу и последний элемент при обновлении окна не отображается.
В результате, при закрытии окна, мы получим такое сообщение:

До встречи в следующем уроке!

Комментарии
Achez
Нужно хорошо разобраться в исходнике, чтобы понять, куда что добавлять. Однако же у меня получилось.
Elz
Будет ли продолжение?
Очень интересные и простые в понимании статьи! Спасибо!
Gosha
Надо так делать:
Иначе утечка памяти будет. И в предыдущей статье тоже.