Собственные
методы класса
Работая с классом,
производным от класса 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.