Наше приложение благополучно инициализируется и выводит графические данные. Теперь необходимо справиться с возможной потерей поверхностей. При рассмотрении функции DirectDrawWin::PreDrawScene мы видели, что DirectDrawWin вызывает виртуальную функцию RestoreSurfaces(), чтобы производный класс получил возможность восстановить потерянные поверхности. Функция RestoreSurfaces() отвечает за восстановление как потерянной памяти поверхности, так и ее содержимого. Функция BounceWin::RestoreSurfaces() выглядит так:
void BounceWin::RestoreSurfaces() {
if (surf1->IsLost()==FALSE) return;
CString filename;
if (GetCurDisplayDepth()==8) filename="tri08.bmp";
else filename="tri24.bmp";
surf1->Restore();
LoadSurface(surf1, filename);
}
DirectDraw может отнимать у неактивного приложения только поверхности, находящиеся в видеопамяти, так что нет смысла в восстановлении поверхностей из системной памяти. Поэтому RestoreSurfaces() сначала проверяет, была ли потеряна единственная вспомогательная поверхность нашего приложения, и если нет — функция прекращает работу. Если же поверхность была потеряна, мы восстанавливаем ее память функцией Restore(), а содержимое — функцией LoadSurface().
ЗавершениеКак бы ни была хороша программа Bounce, рано или поздно вам захочется убрать ее с экрана. Нажатие клавиши Escape завершает работу программы. Это происходит в обработчике OnKeyDown():
void bounceWin::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) {
if (nChar==VK_ESCAPE) PostMessage(WM_CLOSE);
DirectDrawWin::OnKeyDown(nChar, nRepCnt, nFlags);
}
Приложение завершает работу, отправляя сообщение WM_CLOSE. В нашем приложении на это сообщение реагирует и класс окна, и класс приложения. Класс окна отвечает сообщением WM_DESTROY, для которого в DirectDrawWin предусмотрен обработчик OnDestroy(). Класс DirectDrawWin в данном обработчике освобождает объекты DirectDraw и всю память, занимаемую приложением. Функция OnDestroy() выглядит так:
void DirectDrawWin::OnDestroy() {
if (primsurf) primsurf->Release(), primsurf=0;
if (palette) palette->Release(), palette=0;
if (ddraw2) ddraw2->Release(), ddraw2=0;
for (int i=0;i<totaldrivers;i++) {
if (driver[i].guid) delete[] driver[i].guid;
free(driver[i].desc);
free(driver[i].name);
}
}
}
Каждый из указателей на интерфейсы DirectDraw сначала освобождается, а затем обнуляется. Затем мы освобождаем память, занятую информацией о драйверах DirectDraw.
Класс приложения обрабатывает завершение в функции ExitInstance(), в которой удаляется класс окна:
int DirectDrawApp::ExitInstance() {
delete ddwin;
return CWinApp::ExitInstance();
}
На этом наше знакомство с программой Bounce заканчивается. Однако до сих пор речь шла только о полноэкранных приложениях. Оставшаяся часть этой главы посвящена оконным приложениям.
Оконные приложения
Наверное, вы уже поняли, что полноэкранным приложениям в этой книге уделяется особое внимание. Все программы на CD-ROM работают в полноэкранном режиме, и в этой главе до настоящего момента все внимание было сосредоточено исключительно на полноэкранных приложениях.
Дело в том, что книга посвящена быстродействующим графическим Windows-приложениям, а оконные приложения не обеспечивают оптимального быстродействия. Для полноты картины мы рассмотрим оконные приложения, но не так подробно, как полноэкранные. Впрочем, если вы захотите поддерживать оконный режим в своих приложениях, не все потеряно. Многие описанные приемы, реализованные в полноэкранных приложениях, в равной степени относятся и к оконным.
В начале этой главы мы воспользовались DirectDraw AppWizard и создали приложение Bounce. При этом мы указали, что создаваемая программа должна быть полноэкранной. Чтобы получить рассматриваемый ниже код, следует снова запустить AppWizard и выбрать оконное приложение.
Структура приложенияПо своей структуре оконная версия приложения Bounce почти не отличается от полноэкранной. Как и прежде, классы DirectDrawWin и DirectDrawApp организуют поддержку DirectDraw и используются в качестве базовых для классов, относящихся к конкретным приложениям.
ИнициализацияВ полноэкранном варианте класса DirectDrawWin функция OnCreate() инициализирует DirectDraw за несколько этапов. Оконный вариант выглядит проще, потому что ему не приходится перечислять драйверы DirectDraw или видеорежимы. Оконная версия функции OnCreate() выглядит так:
int DirectDrawWin::OnCreate(LPCREATESTRUCT) {
LPDIRECTDRAW ddraw1;
DirectDrawCreate(0, &ddraw1, 0);
ddraw1->QueryInterface(IID_IDirectDraw2, (void**)&ddraw2); ddraw1->Release(), ddraw1=0; ddraw2->SetCooperativeLevel(GetSafeHwnd(), DDSCL_NORMAL);
DetectDisplayMode();
if (CreateFlippingSurfaces()==FALSE) {