Работая с классом, производным от класса MFC,
разработчик не только вводит в него реакции на
сообщения и переопределяет виртуальные функции.
Он также вносит в класс свою собственную
функциональность, вводя в него вспомогательные
методы (helper functions). Сейчас мы создадим
несколько таких функций. Новый метод ReadErrors
будет заниматься поиском, чтением и анализом
файла WinError.h.
-
Переведите фокус мыши на узел CLookDlg в
дереве классов Class View, вызовите
контекстное меню и дайте команду Add > Add
Function.
-
В окне мастера Add Member Function Wizard
заполните следующие поля:
Return type:
bool,
Function name:
ReadErrors.
-
В поле Access: задайте тип доступа — public.
-
В поле Comment: введите комментарий Search
and read errors (моя версия Studio.Net не
позволяет пользоваться русским языком в этом
диалоге).
Просмотрите изменения в классе CLookDlg, которые
произвел мастер. Комментарий он помещает в файл
заголовков (интерфейс класса). Введите следующий
код в тело новой функции:
bool
CLookDlg: :ReadErrors ()
{
//==== Поиск и чтение информации об ошибках
//==== Пытаемся найти путь в реестре
string sPath =
GetPathFromRegistry ( ) ;
//==== В случае неудачи пытаемся узнать у
пользователя
if
(sPath. empty () )
sPath =
GetPathFromUser
О
; if (sPath.emptyO)
return false;
// При отказе уходим
//==== Пытаемся открыть файл
if
stream is (sPath. c_str () ) ;
if
(!is) {
MessageBox ("He
могу найти
WinError.h", "Выход")
;
return false;
//====== Последовательно ищем все ошибки
while
(GetNextErrorCode (is) )
{
//====
Создаем новый объект типа
ErrorType
и
//====
помещаем его в контейнер
m_Vector.push_back
(ErrorType (gCode, gsID, gsMsg) ) ;
}
is. closet);
// Закрываем файл
//====== Запоминаем размер контейнера
m_nltems = m_Vector
. size () ;
return
bool (m_nltems != 0) ;
}
Здесь мы вызываем функции (Getxxx), которых еще
нет. Это является типичной практикой разработки
многомодульных приложений. Мы определяем
прототипы функций так, как того требует логика
алгоритма, а тела будут созданы позже. Вы должны
обратить внимание на объявление объекта is
класса ifstream, который определен в STL.
Поставьте курсор на имя класса ifstream и
воспользуйтесь окном Dynamic Help, для того
чтобы получить справку об этом классе. Из нее вы
мало что узнаете, так как, к сожалению, все
справки по библиотеке STL в разделе Reference
слишком краткие, но если использовать поиск, то
в MSDN можно получить достаточно подробную
информацию о потоковом вводе-выводе.
В рассматриваемом коде мы вызываем конструктор
класса ifstream, который создает поток ввода,
связывает его с буфером и пытается открыть файл,
путь к которому задан в параметре (sPath.c_str()).
Вы помните, что вызов c_str() дает возможность
пользоваться строкой в стиле языка с (то есть
const char*), которая прячется в строке типа
string. Операция "!", переопределенная в классе
ifstream, сообщает нам о неудаче при открытии
файла. Переменные gCode, gsio, gsMsg — это
глобальные переменные, которые мы собираемся
завести для временного хранения параметров
ошибки (кода, индекса и сообщения).
Примечание
Работая с объектами классов, вы можете создавать
глобальные данные и функции. Это оправдано,
когда надо расширить область видимости каких-то
данных или когда функция имеет универсальный
характер, например ищет в файле строку текста.
Если вы знаете или вам кажется, что создаваемую
функцию можно использовать и вне контекста
класса, то ее целесообразно объявить глобальной.
В начало файла LookDlg.cpp (после директивы #endif)
введите определения глобальных данных, которые
будут использованы как в методах класса, так и в
глобальных функциях:
//=== Текущие значения кода, индекса и текста
сообщения
string gCode, gsID,
gsMsg;
//====== Количество категорий (групп) ошибок
const int
N_FACILITIES = 23;
//======
Имена категорий ошибок
TCHAR *gsFacilities[N_FACILITIES
+ 1] = {
"NULL", "RFC", "Dispatch",
"Storage", "Interface", "Unknown",
"Unknown", "Win32", "Windows",
"SSPI", "Control", "Cert",
"Internet", "MediaServer", "MSMQ",
"SetupAPI", "Smart Card", "COM+",
"AAF", "URT", "ACS",
"DPlay", "UMI", "SXS" };
Категории ошибок принято обозначать
аббревиатурами, смысл которых можно выяснить в
разделе Glossary MSDN. Например, аббревиатура
RFC (Remote Procedure Call) обозначает категорию
ошибок, связанных с обращением к процедурам,
которые размещены на других процессорах сети.
Повторите последовательность действий по
введению в класс вспомогательной функции и
создайте функцию Getlnfo. Она выбирает из
контейнера структуру, которая соответствует
ошибке с индексом nPos, и присваивает
переменным, связанным с элементами управления в
окне диалога, значения, которые характеризуют
ошибку (атрибуты ошибки). После такой операции
можно проводить обмен данными (UpdateData(FALSE))
с дочерними окнами диалога и они
«высветят» ошибку.
-
Переведите фокус мыши на узел CLookDlg в
дереве классов Class View, вызовите
контекстное меню и дайте команду Add > Add
Function.
-
В окне мастера
Add Member Function Wizard
заполните
следующие поля:
Return type: void, Function name: Getlnfo,
Parameter type: int, Parameter name: nPos.
-
Нажмите кнопку Add.
-
В поле Access: задайте тип доступа public:
void
CLookDlg::GetInfo(int nPos)
{
// =======
Текущая позиция
m_CurPos.Format("%d",nPos);
if
(nPos >= m_nltems)
return;
//======= Выбираем поля структуры
m_Code = m_Vector[nPos].Code.c_str();
m_Msg =
m_Vector[nPos].Message.c_str() ;
m_ID=
m_Vector[nPos].Identifier.c_str();
//====== Преобразование кода в целое число
DWORD dw = strtoul(LPCTSTR(m_Code),0,0);
//======
Выделяем старший бит
(Severity)
m_Severity = dw &
0x80000000 ?
"Fail" : "Success";
//=== СОМ-коды это НЕХ-коды, длина которых > 8
символов
//=== В этой ветви мы обрабатываем Win32-ошибки
if
(m_Code.GetLength() < 8)
{
if
(dw)
{
//======
Вставляем поля
facility
и
severity
dw = 0x80000000 |
(0x7 << 16) | (dw f, OxFFFF) ;
m_Severity =
"Error";
}
}
//======
Выделяем поле
facility
UINT f = (dw»16) &
0xlFFF;
//====== Выбираем нужную аббревиатуру
m_Facility = f <=
N_FACILITIES |gsFacilities[f) :
"Unknown";
}
Так как коды \Ут32-ошибок не имеют полей
facility и severity (эти атрибуты появились
позже), то их надо синтезировать. Таким же
образом поступает макроподстановка
HRESULT_FROM_wiN32, и ее можно использовать в
этом месте, но мы (с учебной целью) вставили ее
код. Если вы хотите опробовать макрос, то
замените строку
dw = 0x80000000 |
(0x7 << 16) | (dw & 0xFFFF);
на
dw =
HRESULT_FROM_WIN32(dw);
Далее мы выделяем поле facility и выбираем из
массива gsFacilities аббревиатуру, которая более
информативна, чем число f, кодирующее facility. |