Модель программирования Component Object Model. Разработка COM-сервера, страница 39

MessageBox (OLE2T(s), _T("Error"), MB_ICONEXCLAMATION);

}

Рассмотрим одну, весьма вероятную, ошибку. Protected-переменные класса CGraphProp нельзя размещать где попало (странно, не правда ли?). Лучше это сделать так, чтобы сразу за ними шло объявление какой-либо из существующих секций public. Если поместить их, например, перед макросом

DECLARE_REGISTRY_RESOURCEID(IDR_GRAPHPROP)

то макрос окажется безоружным против такой атаки, хотя по идее он должен сопротивляться и даже не замечать наскоков подобного рода. Этот феномен не исчез и в новой версии .Net (2003). Многие вопросы подобного рода решаются с помощью запуска в режиме отладки и точек останова. Но тестовый контейнер при этом сообщает, что он не помощник в процессе отладки, так как не содержит отладочной информации. Согласившись с очевидным фактом, не делайте поспешного вывода о том, что невозможно отлаживать COM-серверы. В тот момент, когда вы инициируете страницу свойств, отладчик возьмет управление в свои руки и остановится на нужной строке программы.

В режиме отладки пользуйтесь одним из самых полезных окон Call Stack. В нем вы увидите историю вызова текущей функции, то есть цепочку предыдущих вызовов функций. Такие опыты иллюстрируют, что все необычно в мире ATL. Он устроен совсем не так, как MFC, но стоит признать, что шаблоны классов дают удивительную гибкость всей конструкции и ее способность подстраиваться, приспосабливаться под пользовательские классы.

Сообщение о прокрутке в окне

Сообщение WM_HSCROLL приходит в окно страницы свойств (читайте: объекту диалогового класса, связанного с окном) всякий раз, как пользователь изменяет положение одного из ползунков, расположенных на диалоговой форме. Это довольно удобно, так как мы можем в одной и той же функции обработки (OnHScroll) отследить изменения, произошедшие в любом из 11 регуляторов. Введите коды обработки этого сообщения, которые сходны с кодами, приведенными в приложении на основе MFC, за исключением COM-специфики общения между классами CGraphProp и COpenGL.

LRESULT CGraphProp::OnHScroll (UINT, WPARAM wParam,

LPARAM lParam, BOOL& bHandled)

{

int

nCode = LOWORD(wParam), // Информация о событии запакована в wParam

nPos  = HIWORD(wParam),

delta,  newPos;

HWND hwnd = (HWND) lParam;

UINT nID; // Выясняем номер и идентификатор активного ползунка

int num = GetSliderNum(hwnd, nID);

switch (nCode) // Выясняем суть события

{

case SB_THUMBTRACK:

case SB_THUMBPOSITION:    m_Pos[num] = nPos;   break;

case SB_LEFT:     delta = -100;  goto New_Pos;

case SB_RIGHT:   delta = +100;  goto New_Pos;

case SB_LINELEFT: delta = -1;    goto New_Pos;

case SB_LINERIGHT:delta = +1;     goto New_Pos;

case SB_PAGELEFT: delta = -20;   goto New_Pos;

case SB_PAGERIGHT:delta = +20;   goto New_Pos;

New_Pos:

newPos = m_Pos[num] + delta;

m_Pos[num] = newPos<0 ? 0 : newPos>100 ? 100 : newPos;

break;

case SB_ENDSCROLL:

default: bHandled = TRUE;   return 0;

}

char s[8]; // Готовим текстовое выражение позиции ползунка

sprintf (s,"%d",m_Pos[num]);

SetDlgItemText(nID, (LPCTSTR)s);

for (UINT i = 0; i < m_nObjects; i++)  // Цикл пробега по всем объектам типа CGraphProp

{

CComQIPtr<IOpenGL, &IID_IOpenGL> p(m_ppUnk[i]); // Добываем интерфейсный указатель

if FAILED (p->SetLightParam (num,  m_Pos[num])) // Устанавливаем конкретный параметр

{

ShowError();

return 0;

}

}

bHandled = TRUE;

return 0;

}

Обратите внимание на последний цикл for. Переменная m_nObjects содержит количество объектов, ассоциированных с данной страницей свойств. Цикл учитывает тот факт, что компонентов, то есть объектов класса COpenGL может быть много, ведь многие клиенты могут одновременно использовать наш COM-объект. В данный момент вы можете проверить функционирование ползунков в суровых условиях COM. Они должны работать.

Реакция на выбор в окне выпадающего списка

Теперь введем реакцию на выбор пользователем новой строки в окне выпадающего списка. Для этого выполните следующие действия:

1.  Откройте в окне редактора шаблон окна диалога IDD_PROPDLG.

2.  Поставьте фокус в окно списка IDC_FILLMODE и переведите фокус окно Properties.

3.  Нажмите кнопку Events, расположенную на инструментальной панели окна Properties.