Кстати, отладчик в Microsoft Visual Studio позволяет настраивать
окно Watch так, чтобы оно всегда показывало код и описание последней ошибки в
текущем потоке. Теперь посмотрите на рис. 1-1. Видите, я вызвал функцию
CreateFile. Она вернула значение INVALID_HANDLE_VALUE (-1) типа
HANDLE, свидетельствующее о том, что ей не удалось открыть заданный файл. Но окно Watch показывает нам код последней ошибки (который вернула бы
функция GetLastError, если бы я ее вызвал), равный 0x00000002, и описание «The
system cannot find the file specified» («Система не может найти указанный файл»). Именно эта строка и определена в заголовочном файле WinError. h для ошибки с
кодом 2. Рис. 1-1. Если приложение обнаруживает какую-нибудь ошибку, то, как правило, сооб-
щает о ней пользователю, выводя на экран ее описание. В Windows для этого есть
специальная функция, которая «конвертирует» код ошибки в ее описание, —
FormatMessage:
6 Часть I. Материалы для обязательного чтения
DWORD FormatMessage(
DWORD dwFlags,
LPCVOID pSource,
DWORD dwMessageId,
DWORD dwLanguageId,
PTSTR pszBuffer,
DWORD nSize,
va_list *Arguments);
FormatMessage — весьма богатая по своим возможностям функция, и именно
ее желательно применять при формировании всех строк, показываемых пользова-
телю. Дело в том, что она позволяет легко работать с множеством языков.
FormatMessage определяет, какой язык выбран в системе в качестве основного
(этот параметр задается через апплет Regional Settings в Control Panel), и возвра-
щает текст на соответствующем языке. Разумеется, сначала вы должны перевести
строки на нужные языки и встроить этот ресурс в свой EXE- или DLL-модуль, за-
то потом функция будет автоматически выбирать требуемый язык. Программа-
пример ErrorShow, приведенная в конце главы, демонстрирует, как вызывать эту
функцию для получения текстового описания ошибки по ее коду, определенному
Майкрософт. Время от времени меня кто-нибудь да спрашивает, составит ли Майкрософт
полный список кодов всех ошибок, возможных в каждой функции Windows. От-
вет: увы, нет. Скажу больше, такого списка никогда не будет — слишком уж
сложно его составлять и поддерживать для всё новых и новых версий системы. Проблема с подобным списком еще и в том, что вы вызываете одну API-
функцию, а она может обратиться к другой, та — к третьей и т. д. Любая из этих
функций может завершиться неудачно (и по самым разным причинам). Иногда
функция более высокого уровня сама справляется с ошибкой в одной из вызван-
ных ею функций и в конечном счете выполняет то, что вы от нее хотели. В об-
щем, для создания такого списка Майкрософт пришлось бы проследить цепочки
вызовов в каждой функции, что очень трудно. А с появлением новой версии сис-
темы эти цепочки нужно было бы пересматривать заново.