Завершение приложения
Завершить работу DirectInput несложно — для этого достаточно освободить все интерфейсы DirectInput. В нашей программе это происходит в функции OnDestroy():
void QwertyWin::OnDestroy() { DirectDrawWin::OnDestroy();
if (dinput) dinput->Release(), dinput=0; if (keyboard) { keyboard->Unacquire(); keyboard->Release(), keyboard=0; } } |
Перед завершением приложения MFC вызывает функцию OnDestroy(); мы воспользуемся ею для освобождения объектов DirectInput. Функция OnDestroy() выглядит так:
void SmearWin::OnDestroy() { DirectDrawWin::OnDestroy(); if (dinput) dinput->Release(), dinput=0; if (keyboard) { keyboard->Unacquire(); keyboard->Release(), keyboard=0; }
if (mouse) { mouse->Unacquire(); mouse->Release(), mouse=0; } } |
Функция OnDestroy() просто освобождает каждый объект DirectInput (и вызывает одноименную функцию базового класса).
Осталось лишь поговорить о том, как завершается работа приложения. Эта тема неоднократно рассматривалась, и ее можно было бы пропустить, но для программы Cursor она важна из-за наличия дополнительного потока. Мы должны не только послать потоку ввода сигнал о завершении, но и проследить за тем, чтобы поток завершился до уничтожения объекта устройства мыши и поверхностей DirectDraw. В противном случае он может попытаться обратиться к мыши или обновить первичную поверхность после того, как соответствующие объекты перестанут существовать. Функция OnDestroy() выглядит так:
void CursorWin::OnDestroy() { critsection.Lock();
DirectDrawWin::OnDestroy(); if (mouse) { TRACE("mouse->Unacquire()\n"); mouse->Unacquire(); TRACE("sending mouse quit message...\n"); mouse_event[quit_event_index]->SetEvent(); Sleep(100); // дать потоку мыши возможность ответить TRACE("Releasing mouse pointer...\n"); mouse->Release(), mouse=0; delete mouse_event[mouse_event_index]; delete mouse_event[quit_event_index]; } if (keyboard) keyboard->Release(), keyboard=0; if (dinput) dinput->Release(), dinput=0; critsection.Unlock(); } |
Когда MFC вызывает функцию OnDestroy(), основной поток заведомо не обновляет экран, потому что он занят выполнением этой функции. Тем не менее мы не знаем, не обновляется ли экран потоком ввода. Чтобы поток ввода закончил последнее обновление, мы блокируем критическую секцию.
Далее мы уступаем мышь. Устройство перестает генерировать новые события, которые заставили бы поток ввода попытаться снова обновить экран. Затем функция CEvent::SetEvent() посылает потоку ввода сигнал о завершении.
Нам осталось лишь освободить объекты DirectInput. Но перед тем, как это делать, мы вызываем функцию Sleep(), чтобы ненадолго приостановить основной поток. Поток ввода получает возможность обработать событие и завершиться. Наконец, мы освобождаем критическую секцию, и функция завершается— на этом работа приложения заканчивается.