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

Мы выберем более традиционный для COM способ, когда проверяется HRESULT и вызывается метод ShowError, который предстоит создать.

LRESULT CGraphProp::OnInitDialog (UINT msg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)

{

CComQIPtr<IOpenGL> p(m_ppUnk[0]); // Кроим умный указатель по шаблону IOpenGL

//=== Пытаемся связаться с классом COpenGL и выяснить значение переменной m_FillMode, В случае неудачи сообщаем об ошибке

DWORD mode;

if FAILED (p->GetFillMode(&mode))

{

ShowError();

return 0;

}

HWND hwnd = GetDlgItem (IDC_FILLMODE); // Работа с combobox по правилам API

//=== Наполняем список строками текста

SendMessage (hwnd, CB_ADDSTRING, 0,  (LPARAM)(LPCTSTR)"Points");

SendMessage (hwnd, CB_ADDSTRING, 0,  (LPARAM)(LPCTSTR)"Lines");

SendMessage (hwnd, CB_ADDSTRING, 0,  (LPARAM)(LPCTSTR)"Fill");

//=== Выбираем текущую позицию списка в соответствии со значением, полученным из COpenGL

WPARAM w = mode == GL_POINT ? 0 : mode == GL_LINE ? 1 : 2;

SendMessage(hwnd, CB_SETCURSEL, w, 0);

if FAILED (p->GetLightParams(m_Pos)) // Повторяем сеанс связи, выясняя позиции ползунков

{

ShowError();

return 0;

}

// Мы не надеемся на упорядоченность идентификаторов элементов и поэтому заводим массив отображений

UINT IDs[] =

{

IDC_XPOS, IDC_YPOS, IDC_ZPOS, IDC_AMBIENT, IDC_DIFFUSE, IDC_SPECULAR,

IDC_AMBMAT, IDC_DIFFMAT, IDC_SPECMAT, IDC_SHINE, IDC_EMISSION

};

for (int i=0; i<sizeof(IDs)/sizeof(IDs[0]); i++)// Установка позиций регуляторов

{

hwnd = GetDlgItem (IDs[i]); // Получаем описатель окна

UINT nID;

int num = GetSliderNum (hwnd, nID); // Узнаем идентификатор элемента

SendMessage (hwnd, TBM_SETPOS, TRUE, (LPARAM)m_Pos[i]); // Выставляем позицию

char s[8]; // Приводим в соответствие текстовый ярлык

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

SetDlgItemText (nID, s);

}

if FAILED (p->GetQuad(&m_bQuad)) // Выясняем состояние режима изображения полигонов

{

ShowError();

return 0;

}

SetDlgItemText (IDC_QUADS,m_bQuad ? "Quads" : "Strips");  // Устанавливаем текст

return TRUE;

}

Обратите внимание на вызов SendMessage при управлении combo-box. Этот способ характерен для Win32 API. В процессе обработки сообщения нам понадобились вспомогательные функции GetSliderNum и ShowError. Первая функция уже участвовала в проекте на основе MFC, поэтому мы лишь напомним, что она позволяет по известному Windows-описателю окна элемента управления получить его порядковый номер в массиве позиций регуляторов. Кроме этого, функция позволяет получить идентификатор элемента nID, который нужен для управления им (например, при вызове SetDlgItemText).

int CGraphProp::GetSliderNum (HWND hwnd, UINT& nID)

{

switch (::GetDlgCtrlID(hwnd)) // Получаем ID по известному описателю окна

{

case IDC_XPOS:     nID = IDC_XPOS_TEXT;     return 0;

case IDC_YPOS:     nID = IDC_YPOS_TEXT;     return 1;

case IDC_ZPOS:     nID = IDC_ZPOS_TEXT;     return 2;

case IDC_AMBIENT:   nID = IDC_AMB_TEXT;      return 3;

case IDC_DIFFUSE:   nID = IDC_DIFFUSE_TEXT;    return 4;

case IDC_SPECULAR:  nID = IDC_SPECULAR_TEXT; return 5;

case IDC_AMBMAT:    nID = IDC_AMBMAT_TEXT;   return 6;

case IDC_DIFFMAT:   nID = IDC_DIFFMAT_TEXT;    return 7;

case IDC_SPECMAT:   nID = IDC_SPECMAT_TEXT;    return 8;

case IDC_SHINE:     nID = IDC_SHINE_TEXT;      return 9;

case IDC_EMISSION:  nID = IDC_EMISSION_TEXT; return 10;

}

return 0;

}

Функция ShowError демонстрирует, как в условиях COM можно обработать исключительную ситуацию. Если мы хотим выявить причину ошибки, спрятанную в HRESULT, то следует воспользоваться методом GetDescription интерфейса IErrorInfo. Сначала мы получаем указатель на него с помощью объекта класса CComPtr. Этот класс, так же как и CComQIPtr, автоматизирует работу с методами главного интерфейса IUnknown, за исключением метода QueryInterface.

void CGraphProp::ShowError()

{

USES_CONVERSION;

CComPtr<IErrorInfo> p; // Создаем инерфейсный указатель

GetErrorInfo (0, &p); // Выясняем причину отказа

CComBSTR s;    // Класс для работы с Unicode-строками

p->GetDescription (&s);

//=== Преобразуем тип строкового объекта для вывода в окно