Управление растровым изображением. Структура Windows-приложения. Развитие стартовой заготовки, страница 2

Коротко алгоритм работы WinMain может быть сформулирован так. После выполнения инициализирующих действий (оформления заказа на класс обслуживания) функция WinMain создает окно и входит в цикл обработки сообщений. После выхода из этого цикла работа приложения завершается. Выход происходит, когда придет сообщение WM_QUIT. Обычно его посылает оконная процедура, когда пользователь закрывает главное окно.

#include <windows.h>   // Файл заголовков для Windows приложений

// ======== Оконная процедура

long __stdcall WndProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)

{

switch(msg)             // Переход по сообщению

{

case WM_DESTROY:

  PostQuitMessage(0);    // Сообщаем системе, что поток (thread) требует закрытия

  break;

default:                // Процедура по умолчанию

  return (long)DefWindowProc(hWnd,msg,wParam,lParam);

}

return 0L;

}

//======== Главная функция. С нее начинается выполнение Windows приложения

int WINAPI WinMain (HINSTANCE hInst, HINSTANCE, LPSTR, int nCmdShow)

{

WNDCLASS w;                    // Структура атрибутов класса окна

ZeroMemory(&w,sizeof(w));      // Обнуляем все поля структуры и заполняем их (только самые необходимые)

w.lpszClassName = "My Class";  // Имя класса окна

w.hInstance = hInst;           // Описатель экземпляра приложения

w.lpfnWndProc = WndProc;       // Указатель на оконную процедуру

w.style  = CS_HREDRAW | CS_VREDRAW; // Набор битов, описывающих стиль окна

if (!RegisterClass (&w))       // Попытка зарегистрировать оконный класс

  return FALSE;                 // Уход в случае неудач

//====== Создаем окно и запоминаем его описатель

HWND hWnd = CreateWindow(w.lpszClassName, "Bitmap Manipulations",

   WS_VISIBLE | WS_OVERLAPPEDWINDOW, 0,0,CW_USEDEFAULT,CW_USEDEFAULT,0,0, hInst,0);

MSG msg;                  // Структура для описания сообщений

while (GetMessage (&msg,0,0,0)) // Цикл ожидания сообщений

{                        

  TranslateMessage (&msg); // Преобразование виртуальных кодов клавиш в символы

  DispatchMessage (&msg);    // Пересылка оконной процедуре

}

return 0;

}

Развитие стартовой заготовки

Запустив приложение (Ctrl+F5), вы увидите окно минимального приложения. Заготовку надо развивать, внося требуемую функциональность. Например, задайте цвет фона, форму курсора и введите обработку сообщения о перерисовке. Цвет фона определяется классом окна, то есть структурой типа WNDCLASS. Если вы  заполните ее поле hbrBackground описателем кисти Windows, используемой  при закрашивании клиентской области окна, то система будет знать что делать при обработке сообщения WM_ERASEBKGND (стирание фона окна).

w.hbrBackground = (HBRUSH)GetStockObject (WHITE_BRUSH);

Форму курсора можно задать одним из следующих способов (выберите только один):

w.hCursor = LoadCursor(0, IDC_ARROW);           // Готовый системный курсор

w.hCursor = LoadCursor(hInst, (char*)IDC_MYCUR); // Курсор из ресурсов приложения (его надо создать)

   //===== Курсор из файла текущей папки

char s [MAX_PATH + 10];

GetCurrentDirectory(MAX_PATH, s);

strcat (s, "\\Hand.cur"); // Предполагается, что в папку приложения вы принесли файл с изображением курсора Hand.cur

w.hCursor = (HCURSOR)LoadImage (0,s,IMAGE_CURSOR,0,0,LR_LOADFROMFILE | LR_MONOCHROME);

Для рисования в окне надо в WndProc ввести ветвь, реагирующую на сообщение WM_PAINT. Например:

case WM_PAINT:

{

  PAINTSTRUCT ps;               // Данные для рисования

  HDC hdc = BeginPaint(hWnd, &ps);  // Получаем контекст устройства

  Ellipse (hdc, 20,20,400,200);   // Рисуем эллипс

  EndPaint (hWnd, &ps);       // Завершаем процесс рисования

  break;

}

Если необходимо, чтобы рисунок всегда располагался в центре окна, то следует запоминать размеры окна (которые пользователь периодически изменяет) и использовать эти данные при рисовании. Например, введем в WndProc локальную переменную static POINT ptCenter; которая будет отслеживать изменения размеров окна. Это делается  в ветви обработки сообщения WM_SIZE.

case WM_SIZE:

  ptCenter.x = LOWORD(lParam)/2;  // Распаковываем вспомогательный параметр сообщения