Читаем Применение Windows API полностью

 ModalDialog(HINSTANCE hInst, HWND hwnd, int dlgResource, CtrlFactory *ctrlFactory) {

  _result = DialogBoxParam(hInst, MAKEINTRESOURCE(dlgResource), hwnd, (DLGPROC)ModalDialogProc, (LPARAM)ctrlFactory);

 }

 static BOOL CALLBACK ModalDialogProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);

 bool IsOk() const { return (_result == –1) ? false : _result != 0; }

private:

 int _result;

};

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

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

template inline T

GetWinLong(HWND hwnd, int which = GWL_USERDATA) {

 return reinterpret_cast(::GetWindowLong(hwnd, which));

}

template inline void

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

 ::SetWindowLong(hwnd, which, reinterpret_cast(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(hwnd);

 switch (message) {

 case WM_INITDIALOG:

  {

   CtrlFactory *ctrlFactory = reinterpret_cast(lParam);

   ctrl = ctrlFactory->MakeController(hwnd);

   SetWinLong(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(hwnd, 0);

  break;

 }

 return FALSE;

}

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

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

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

Перейти на страницу:

Похожие книги

1С: Бухгалтерия 8 с нуля
1С: Бухгалтерия 8 с нуля

Книга содержит полное описание приемов и методов работы с программой 1С:Бухгалтерия 8. Рассматривается автоматизация всех основных участков бухгалтерии: учет наличных и безналичных денежных средств, основных средств и НМА, прихода и расхода товарно-материальных ценностей, зарплаты, производства. Описано, как вводить исходные данные, заполнять справочники и каталоги, работать с первичными документами, проводить их по учету, формировать разнообразные отчеты, выводить данные на печать, настраивать программу и использовать ее сервисные функции. Каждый урок содержит подробное описание рассматриваемой темы с детальным разбором и иллюстрированием всех этапов.Для широкого круга пользователей.

Алексей Анатольевич Гладкий

Программирование, программы, базы данных / Программное обеспечение / Бухучет и аудит / Финансы и бизнес / Книги по IT / Словари и Энциклопедии
1С: Управление торговлей 8.2
1С: Управление торговлей 8.2

Современные торговые предприятия предлагают своим клиентам широчайший ассортимент товаров, который исчисляется тысячами и десятками тысяч наименований. Причем многие позиции могут реализовываться на разных условиях: предоплата, отсрочка платежи, скидка, наценка, объем партии, и т.д. Клиенты зачастую делятся на категории – VIP-клиент, обычный клиент, постоянный клиент, мелкооптовый клиент, и т.д. Товарные позиции могут комплектоваться и разукомплектовываться, многие товары подлежат обязательной сертификации и гигиеническим исследованиям, некондиционные позиции необходимо списывать, на складах периодически должна проводиться инвентаризация, каждая компания должна иметь свою маркетинговую политику и т.д., вообщем – современное торговое предприятие представляет живой организм, находящийся в постоянном движении.Очевидно, что вся эта кипучая деятельность требует автоматизации. Для решения этой задачи существуют специальные программные средства, и в этой книге мы познакомим вам с самым популярным продуктом, предназначенным для автоматизации деятельности торгового предприятия – «1С Управление торговлей», которое реализовано на новейшей технологической платформе версии 1С 8.2.

Алексей Анатольевич Гладкий

Финансы / Программирование, программы, базы данных