Создание эффективных WIN32-приложений с учетом специфики 64-разрядной версии Windows

         

Программа-пример ErrorShow


Эта программа, «01 ErrorShow.exe» (см. листинг на рис. 1 -2), демонстрирует, как получить текстовое описание ошибки no ee коду. Файлы исходного кода и ресурсов программы находятся в каталоге Ol-ErrorShow на компакт-диске, прилагаемом к книге.

Программа ErrorShow в основном предназначена для того, чтобы Вы увидели, как работают окно Watch отладчика и утилита Error Lookup. После запуска ErrorShow открывается следующее окно.

В поле Error можно ввести любой код ошибки. Когда Вы щелкнете кнопку Look Up, внизу, в прокручиваемом окне появится текст с описанием данной ошибки. Единственная интересная особенность программы заключается в том, как она обращается к функции FormatMessage. Я использую эту функцию так:

// получаем код ошибки
DWORD dwError = GetDlgItemInt(hwnd, IDC_ERRORCODE, NULL, FALSE);

HLOCAL hlocal = NULL; // буфер для строки с описанием ошибки

// получаем текстовое описание ошибки
BOOL fOk = FormatMessage(
FORMAT_MESSAGE_FROM_SYSTFM | FORMAT_MESSAGE_ALLOCATC_BUFFER,
NULL, dwError, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US).
(LPTSTR) &hlocal, 0, NULL);

if (hlocal != NULL) {
SetDlgItemText(hwnd, IDC_ERRORTEXT, (PCTSTR) LocalLock(hlocal));
LocalFree(hlocal);
} else {
SetDlgItemText(hwnd, IDC ERRORTEXT, TEXT("Error number not found "));
}

Первая строка считывает код ошибки из текстового поля. Далее я создаю экземпляр описателя (handle) блока памяти и инициализирую его значением NULL. Функция FormatMessage сама выделяет нужный блок памяти и возвращает нам его описатель.

Вызывая FormatMessage, я передаю флаг FORMAT_MESSAGE_FROM_SYSTEM Он сообщает функции, что мне нужна строка, соответствующая коду ошибки, определенному в системе. Кроме того, я передаю флаг FORMAT_MESSAGE_ALLOCATE_BUFFER, чтобы функция выделила соответствующий блок памяти для хранения текста Описатель этого блока будет возвращен в переменной hlocal. Третий параметр указывает код интересующей нас ошибки, а четвертый — язык, на котором мы хотим увидеть ее описание.

Если выполнение FormatMessage заканчивается успешно, описание ошибки помещается в блок памяти, и я копирую его в прокручиваемое окно, расположенное в нижней части окна программы. А если вызов FormatMessage оказывается неудачным,

я пытаюсь найти код сообщения в модуле NetMsg.dll, чтобы выяснить не связана ли ошибка с сетью Используя описатель NetMsg.dll, я вновь вызываю FormatMessage. Дело в том, что у каждого DLL или ЕХЬ-модуля может быть собственный набор кодов ошибок, который включается в модуль с помощью Message Compiler (MC.exe) Как раз это и позволяет делать утилита Error Lookup через свое диалоговое окно Modules



Вы тоже можете это сделать


О'кэй, я показал, как функции Windows сообщают об ошибках. Microsoft позволяет Вам использовать этот механизм и в собственных функциях. Допустим, Вы пишете функцию, к которой будут обращаться другие программы. Вызов этой функции может по какой-либо причине завершиться неудачно, и Вам тоже нужно сообщать об ошибках. С этой целью Вы просто устанавливаете код последней ошибки в потоке и возвращаете значение FALSE, INVALID_HANDLE_VALUE, NULL или что-то другое, более подходящее в Вашем случае. Чтобы установить код последней ошибки в потоке, Вы вызываете SetLastErro

VOID SetLastError(DWORD dwErrCode);

и передаете ей нужное 32-битное число. Я стараюсь использовать коды, уже определенные в WinError.h, — при условии, что они подходят под те ошибки, о которых могут сообщать мои функции Если Вы считаете, что ни один из кодов в WinError.h не годится для ошибки, возможной в Вашей функции, определите свой код. Он представляет собой 32-битное значение, которое разбито па поля, показанные в следующей
таблице.



Биты

31-30

29

28

27-16

15-0

Содержимое

Код степени "тяжести" (severity)

Кем определен
— Microsoft
или
пользователем

Зарезервирован

Код
подсистемы
(facility code)

Код
исключения

Значение

0 = успех
1 = информация
2 = предупреждение
3 = ошибка

0 = Microsoft
1 = пользователь

Должен
быть 0

Определяется
Microsoft

Определяет-
ся Microsoft
или пользователем

Подробнее об этих полях я рассказываю в главе 24. На данный момент единственное важное для Вас поле — бит 29- Microsoft обещает, что все коды ошибок, генерируемые ее функциями, будут содержать 0 в этом бите. Если Вы определяете собственный код ошибки, запишите сюда 1. Тогда у Вас будет гарантия, что Ваш код ошибки не войдет в конфликт с кодом, определенным Microsoft, — ни сейчас, ни в будущем.