Чтение онлайн

на главную - закладки

Жанры

Применение Windows API

Легалов А. И.

Шрифт:

private:

 int _result;

};

В заключение отметим, что процедура диалога, общая для всех типов диалогов, реализована так, чтобы ответить на три вида сообщений: WM_INITDIALOG, WM_COMMAND и WM_NOTIFY. Фактически, все они направляют эти сообщения к объекту — контроллеру. Он получает указатель на полиморфный объект контроллера вызывая в начале метод фабрики MakeController.

Обратите внимание, что, из этой точки мы позволяем Windows, отследить указатель на контроллер. Мы сохраняем его как GWL_USERDATA — специальный

длинный, который ассоциируется с каждым окном, в особенности с нашим диалогом, и доступен через его дескриптор окна.

template <class T> inline T

GetWinLong(HWND hwnd, int which = GWL_USERDATA) {

 return reinterpret_cast<T>(::GetWindowLong(hwnd, which));

}

template <class T> inline void

SetWinLong(HWND hwnd, T value, int which = GWL_USERDATA) {

 ::SetWindowLong(hwnd, which, reinterpret_cast<long>(value));

}

Мы должны быть, хотя бы внимательными. Прежде всего мы должны освободить контроллер после того, как использовали его. Мы делаем это при обработке WM_DESTROY.

Во-вторых, Windows имеет неудачную идею (привычку) посылать сообщения WM_COMMAND и WM_NOTIFY перед WM_INITDIALOG и после WM_DESTROY. Что можно здесь сказать? Я бы побил менеджера, который ответствен за эти дела. Но раз это есть, мы должны защитить себя, проверяя, является ли ctrl ненулевым перед вызовом OnCommand и OnNotify.

BOOL CALLBACK ModalDialog::ModalDialogProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {

 DlgController* ctrl = GetWinLong<DlgController *>(hwnd);

 switch (message) {

 case WM_INITDIALOG:

{

CtrlFactory *ctrlFactory = reinterpret_cast<CtrlFactory *>(lParam);

ctrl = ctrlFactory->MakeController(hwnd);

SetWinLong<DlgController *>(hwnd, ctrl);

ctrl->OnInitDialog (hwnd);

}

return TRUE;

 case WM_COMMAND:

if (ctrl && ctrl->OnCommand(hwnd, LOWORD(wParam), HIWORD (wParam))) return TRUE;

break;

 case WM_NOTIFY:

if (ctrl && ctrl->OnNotify(hwnd, wParam, (NMHDR *)lParam))

return TRUE;

break;

 case WM_DESTROY:

delete ctrl;

SetWinLong<DlgController *>(hwnd, 0);

break;

 }

 return FALSE;

}

Здесь

представлена красота полиморфизма в действии. Объект фабрики создан клиентом, использующим шаблонный класс. Этот объект передается конструктору ModalDialog. ModalDialog передает его процедуре диалога как пустой указатель (дело в том, что он должен пройти через Windows). Процедура Диалога получает его внутри сообщения WM_INITDIALOG как LPARAM. После прохождения пищеварительного тракта Windows он должен быть восстановлен к своей первоначальной форме, переводом его обратно к указателю на CtrlFactory — в базовый класс всех фабрик контроллера.

Когда мы вызываем его виртуальный метод MakeController, мы вызываем метод, переопределенный в шаблонном классе ControllerFactory. Он создает новый объект для класса ActualCtrl, определенного клиентом. Но снова, он возвращает этот объект к нам замаскированный как обобщенный указатель на DlgController. Так всякий раз, когда мы вызываем любой из виртуальных методов ctrl, мы выполняем клиентские переопределения, определенные в классе ActualCtrl. Это лучшее проявление полиморфизма: Вы записываете код, используя обобщенные указатели, но когда код выполнен, он вызывается с очень специфическими указателями. Когда Вы вызываете методы через эти указатели, Вы выполняете специфические методы, обеспеченные клиентом вашего кода.

Вот, что случается с фабрикой объектов, чей фактический класс

ControllerFactory <EditorCtrl, EditorData>

Передается конструктору ModalDialog как void*
Передаётся от Windows к ModalDialogProcedure как LPARAM
Приведение в ModalDialogProcedure к CtrlFactory*

А вот, что случается с объектными данными, чьим фактическим классом является EditorData.

Передается конструктору фабрики как void*
Приведение в методе AcquireController класса ControllerFactory<EditorCtrl, EditorData> к EditorData*
Переданный конструктору EditCtrl как EditotData*

Объект класса EditCtrl, созданный в методе MakeController класса ControllerFactory<EditorCtrl, EditorData> возвращается из него как DlgController* и сохраняется в этой форме как статический член данных ModalDialog.

Если Вы имеете проблемы после моего объяснения, не отчаивайтесь. Объектно ориентированные методы, которые я только описал, трудны, но необходимы. Они названы образцами проектирования. Я настоятельно рекомендую читать книгу: Gamma, Helm, Johnson and Vlissides — Design Patterns, Elements of Reusable Object-Oriented Software или посмотреть Patterns Home Page (домашнюю страницу образцов). Там описано много творческих способов использования полиморфизма, наследования и шаблонизации, чтобы делать программное обеспечение более пригодным для многократного использования.

Поделиться:
Популярные книги

Мастер...

Чащин Валерий
1. Мастер
Фантастика:
героическая фантастика
попаданцы
аниме
6.50
рейтинг книги
Мастер...

Жених из гроба

Сотис Майя
1. Гробокопательница
Фантастика:
юмористическое фэнтези
сказочная фантастика
фэнтези
5.00
рейтинг книги
Жених из гроба

Ищу жену с прицепом

Рам Янка
2. Спасатели
Любовные романы:
современные любовные романы
6.25
рейтинг книги
Ищу жену с прицепом

Гримуар тёмного лорда I

Грехов Тимофей
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Гримуар тёмного лорда I

Заклятие предков

Прозоров Александр Дмитриевич
3. Ведун
Фантастика:
фэнтези
альтернативная история
8.49
рейтинг книги
Заклятие предков

Крепость над бездной

Лисина Александра
4. Гибрид
Фантастика:
боевая фантастика
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Крепость над бездной

Рота Его Величества

Дроздов Анатолий Федорович
Новые герои
Фантастика:
боевая фантастика
8.55
рейтинг книги
Рота Его Величества

Экспансия: Сотрудничество. Том 5

Белов Артем
5. Планетарный десант
Фантастика:
боевая фантастика
аниме
5.00
рейтинг книги
Экспансия: Сотрудничество. Том 5

Отверженный III: Вызов

Опсокополос Алексис
3. Отверженный
Фантастика:
фэнтези
альтернативная история
7.73
рейтинг книги
Отверженный III: Вызов

Князь Серединного мира

Земляной Андрей Борисович
4. Страж
Фантастика:
фэнтези
попаданцы
5.00
рейтинг книги
Князь Серединного мира

Возвышение Меркурия. Книга 8

Кронос Александр
8. Меркурий
Фантастика:
героическая фантастика
попаданцы
аниме
5.00
рейтинг книги
Возвышение Меркурия. Книга 8

Эволюционер из трущоб. Том 5

Панарин Антон
5. Эволюционер из трущоб
Фантастика:
попаданцы
аниме
фэнтези
фантастика: прочее
5.00
рейтинг книги
Эволюционер из трущоб. Том 5

Локки 7. Потомок бога

Решетов Евгений Валерьевич
7. Локки
Фантастика:
аниме
эпическая фантастика
фэнтези
5.00
рейтинг книги
Локки 7. Потомок бога

Черный Маг Императора 4

Герда Александр
4. Черный маг императора
Фантастика:
юмористическое фэнтези
попаданцы
аниме
5.00
рейтинг книги
Черный Маг Императора 4