Читать «Применение Windows API» онлайн - страница 11
А. И. Легалов
Если, как это часто бывает, ваше приложение имеет только одно окно верхнего уровня, Вы можете непосредственно включать модель в ее контроллер. Это упрощает управление ресурсами, но ценой усиления связи контроллера с моделью. В больших проектах нужно избегать таких связей. Предпочтительнее использовать внутри контроллера "интеллектуальный" указатель на модель.
Большинство методов контроллера требует дескриптора окна, с которым они взаимодействуют. Этот дескриптор передается с каждым сообщением Windows, но проще сохранить его один раз внутри контроллера и использовать всякий раз, когда он необходим. Помните — имеется взаимно однозначное соответствие между контроллерами и экземплярами окон (а следовательно, и их дескрипторами).
class Controller {
public:
Controller(HWND hwnd, CREATESTRUCT * pCreate);
~Controller();
void Size(int x, int y);
void Paint();
void Command(int cmd);
private:
HWND _hwnd;
Model _model;
View _view;
};
Оконная процедура — основной коммутационный узел Windows приложения. Вы не вызываете ее из вашей программы — ее вызывает Windows! Каждый раз когда случается что-то интересное, Windows посылает вашей программе сообщение. Это сообщение передается оконной процедуре. Вы можете обработать его, или передать оконной процедуре, заданной по умолчанию.
Оконная процедура вызывается с указанием дескриптора к окна, к которому направлено данное сообщение. Этот дескриптор однозначно идентифицирует внутреннюю структуру данных Windows, которая соответствует экземпляру окна. Это так часто случОконная процедура вызывается с указанием дескриптора к окна, к которому направлено данное сообщение. Этот дескриптор однозначно идентифицирует внутреннюю структуру данных Windows, которая соответствует экземпляру окна. Это так часто случается, что мы можем обращаться к этой структуре данных и использовать ее, чтобы сохранить некоторые специфические для экземпляра данные. Имеется типовой безопасный способ доступа к этой структуре. Между прочим, элемент GWL_USERDATA этой структуры гарантированно присутствует во всех окнах, включая окна сообщения, диалоговые окна и даже кнопки.
template <class T> inline T
WinGetLong(hwnd hwnd, int which = gwl_userdata) {
return reinterpret_cast<T>(::GetWindowLong (hwnd, which));
}
template <class T> inline void
WinSetLong(hwnd hwnd, t value, int which = gwl_userdata) {
::SetWindowLong(hwnd, which, reinterpret_cast<long>(value));
}
Каждый раз, когда Windows вызывает нашу оконную процедуру, мы хотим сначала восстановить ее контроллер. Вспомните, что может быть несколько окон, совместно использующих ту же самую оконную процедуру, и мы хотим иметь отдельный контроллер для каждого окна. Как мы узнаем, какой из контроллеров используетсять, когда произходит обратный вызов оконной процедуры? Мы можем выяснить это, рассмотрев дескриптор окна. В этом дескрипторе мы сохраняем указатель на контроллер данного окна, используя функцию Win[Set/Get]Long.
Оконная процедура сначала вызывается с сообщением WM_CREATE. В этот момент мы создаем экземпляр контроллера, нициализируем его дескриптором окна и специальной структурой данных по имени CREATESTRUCT, которая передана нам от Windows. Если же мы уже имеем контроллер, то сохраняем указатель на его в соответствующей внутренней Windows-структуре данных помеченной текущим hwnd. В следующий раз оконная процедура вызывается с сообщением, отличным от WM_CREATE, и мы просто восстанавливаем (отыскиваем) указатель на наш контроллер, используя hwnd.