| netlib.narod.ru | < Назад | Оглавление | Далее > |
Уверен, вы согласитесь, что необходимость постоянно перепечатывать один и тот же код — код для создания окна, рисования графики, воспроизведения звука и т.д., — каждый раз, когда вы начинаете новый проект очень утомляет. Почему бы не составить библиотеку из тех функций, которые присутствуют в каждом приложении, что избавит вас от рутины и оставит больше времени на разработку самого приложения?
Именно эта идея лежит в основе каркаса приложения (application framework). На базовом уровне каркас должен содержать код для инициализации окна приложения и различных подсистем (графики, ввода, сети и звука), обработки результатов инициализации, выполняемых в каждом кадре процедур и функций для завершения работы приложения. Использование технологии модульного программирования также помогает, поскольку основные компоненты, такие как упомянутые подсистемы, содержатся в отдельных объектах.
На данном этапе цель заключается в разработке простого проекта, который может использоваться в качестве фундамента для остальных ваших приложений. Создайте новый проект и назовите его framework (или как-нибудь иначе, но чтобы название описывало его назначение). В этом проекте создайте файл с именем WinMain.cpp, который будет предсталять точку входа вашего приложения.
Исходный код WinMain.cpp должен быть минимальным и содержать только код, необходимый для инициализации окна. Взгляните на исходный код, находящийся в файле WinMain.cpp, который я обычно использую в каркасе для своих проектов:
// Включаемые файлы
#include <windows.h>
#include <stdio.h>
#include <stdarg.h>
// Экземпляр главного приложения
HINSTANCE g_hInst; // Глобальный дескриптор экземпляра
HWND g_hWnd; // Глобальный дескриптор окна
// Размеры окна приложения, его тип, класс и заголовок
#define WNDWIDTH 400
#define WNDHEIGHT 400
#define WNDTYPE WS_OVERLAPPEDWINDOW
const char g_szClass[] = "FrameClass";
const char g_szCaption[] = "FrameCaption";
// Главные прототипы функци приложения
// Точка входа
int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev,
LPSTR szCmdLine, int nCmdShow);
// Функция для отображения сообщений об ошибках
void AppError(BOOL Fatal, char *Text, ...);
// Процедура обработки ссобщений
long FAR PASCAL WindowProc(HWND hWnd, UINT uMsg,
WPARAM wParam, LPARAM lParam);
// Функции для регистрации и отмены регистрации классов
BOOL RegisterWindowClasses(HINSTANCE hInst);
BOOL UnregisterWindowClasses(HINSTANCE hInst);
// Функция для создания окна приложения
HWND CreateMainWindow(HINSTANCE hInst);
// функции для инициализации, завершения работы и обработки кадров
BOOL DoInit();
BOOL DoShutdown();
BOOL DoPreFrame();
BOOL DoFrame();
BOOL DoPostFrame();
int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev,
LPSTR szCmdLine, int nCmdShow)
{
MSG Msg;
// сохраняем экземпляр приложения
g_hInst = hInst;
// Регистрация класса окна
// Возвращаем управление, если не удалась
if(RegisterWindowClasses(hInst) == FALSE)
return FALSE;
// Создание окна
// Возвращаем управление, если не удалось
if((g_hWnd = CreateMainWindow(hInst)) == NULL)
return FALSE;
// Инициализация приложения
// Возвращаемся в случае ошибки
if(DoInit() == TRUE) {
// Вход в цикл обработки сообщений
ZeroMemory(&Msg, sizeof(MSG));
while(Msg.message != WM_QUIT) {
// Обработка сообщений Windows (если они есть)
if(PeekMessage(&Msg, NULL, 0, 0, PM_REMOVE)) {
TranslateMessage(&Msg);
DispatchMessage(&Msg);
} else {
// Предкадровая обработка,
// прекращаем обработку кадра,
// если вернули FALSE
if(DoPreFrame() == FALSE)
break;
// Обработка кадра,
// прекращаем обработку,
// если вернули FALSE
if(DoFrame() == FALSE)
break;
// Послекадровая обработка,
// прекращаем обработку кадра,
// если вернули FALSE
if(DoPostFrame() == FALSE)
break;
}
}
}
// Функции завершения работы
DoShutdown();
// Отменяем регистрацию класса окна
UnregisterWindowClasses(hInst);
return TRUE;
}
BOOL RegisterWindowClasses(HINSTANCE hInst)
{
WNDCLASSEX wcex;
// Создание и регистрация класса окна
wcex.cbSize = sizeof(wcex);
wcex.style = CS_CLASSDC;
wcex.lpfnWndProc = WindowProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInst;
wcex.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = NULL;
wcex.lpszMenuName = NULL;
wcex.lpszClassName = g_szClass;
wcex.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
if(!RegisterClassEx(&wcex))
return FALSE;
return TRUE;
}
BOOL UnregisterWindowClasses(HINSTANCE hInst)
{
// Отмена регистрации класса окна
UnregisterClass(g_szClass, hInst);
return TRUE;
}
HWND CreateMainWindow(HINSTANCE hInst)
{
HWND hWnd;
// Создание главного окна
hWnd = CreateWindow(g_szClass, g_szCaption,
WNDTYPE, 0, 0, WNDWIDTH, WNDHEIGHT,
NULL, NULL, hInst, NULL);
if(!hWnd)
return NULL;
// Отображение и обновление окна
ShowWindow(hWnd, SW_NORMAL);
UpdateWindow(hWnd);
// Возвращаем дескриптор окна
return hWnd;
}
void AppError(BOOL Fatal, char *Text, ...)
{
char CaptionText[12];
char ErrorText[2048];
va_list valist;
// Создаем заголовок окна сообщения
// на основе флага Fatal
if(Fatal == FALSE)
strcpy(CaptionText, "Error");
else
strcpy(CaptionText, "Fatal Error");
// Создаем текст сообщения
va_start(valist, Text);
vsprintf(ErrorText, Text, valist);
va_end(valist);
// Отображаем окно сообщений
MessageBox(NULL, ErrorText, CaptionText,
MB_OK | MB_ICONEXCLAMATION);
// Отправляем сообщение о завершении работы приложения,
// если ошибка является фатальной
if(Fatal == TRUE)
PostQuitMessage(0);
}
// Процедура обработки сообщений - обрабатывает только
// сообщение о завершении работы приложения
long FAR PASCAL WindowProc(HWND hWnd, UINT uMsg,
WPARAM wParam, LPARAM lParam)
{
switch(uMsg) {
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
BOOL DoInit()
{
// Здесь выполняются функции инициализации приложения,
// такие как инициализация графической системы, сети, звука и т.д.
// Возвращает TRUE в случае успешной инициализации и FALSE при ошибке.
return TRUE;
}
BOOL DoShutdown()
{
// Здесь выполняются действия, завершающие работу приложения,
// такие как отключение график, звука и т.д. Возвращает TRUE
// в случае успешного завершения работы и FALSE при ошибке.
return TRUE;
}
BOOL DoPreFrame()
{
// Выполняет подготовку к формированию кадра, например,
// установку таймера. Возвращает TRUE в случае успешной
// подготовки и FALSE при ошибке.
return TRUE;
}
BOOL DoFrame()
{
// Выполняет операции формирования кадра, такие как визуализация.
// Возвращает TRUE при успехе и FALSE при ошибке.
return TRUE;
}
BOOL DoPostFrame()
{
// Выполняет посткадровую обработку, например,
// синхронизацию со временем и т.д.
// Возвращает TRUE при успехе и FALSE при ошибке.
return TRUE;
}
Представленный выше код каркаса инициализирует окно и запускает цикл обработки сообщений, ожидающий, пока не придет сигнал о завершении программы. Все представленные функции обрабатывают различные моменты инициализации или завершения работы приложения. Обратите внимание, что создаваемое окно приложения не является фоновым — это необходимо для работы с DirectX Graphics, о чем вы узнаете в главе 2 «Рисование с DirectX Graphics».
Чтобы изменить другие параметры окна, такие как высоту, ширину или тип, вы можете отредактировать находящиеся в начале кода определения констант. То же самое справедливо и для класса окна и его заголовка, которые объявлены в двух константах в начале кода.
Обратите внимание, что я добавил функцию, которая нигде не вызывается. Это функция AppError, которую я использую для отображения пользовательских сообщений об ошибках. Если ей в параметре Fatal передать значение TRUE, то работа приложения будет завершена, в то время как значение FALSE позволяет программе продолжать работу.
В каждой функции есть комментарии, объясняющие, что она делает, — ваша задача добавить код, выполняющий инициализацию объектов, загружающий графику, обрабатывающий кадры и т.д.
| netlib.narod.ru | < Назад | Оглавление | Далее > |