Создание DLL- и ЕХЕ-файлов сообщений
октября 12 2009 by admin in АдминистрированиеУ нас осталось еще несколько вопросов:
как текст в файлах сообщений связан с событием?
как используется параметр ppszStrings функции ReportEvent?
как создается DLL-файл сообщений?
В этом разделе я на них отвечу. Взгляните на архитектуру регистрации событий, в том числе и этапы создания DLL-файла сообщений.
Первый этап разработки DLL-файла сообщений — создание текстового файла для источника сообщений. Этот источник обычно называют МС-файлом. Он может называться как угодно, но должен иметь расширение .тс, например MyMsg.mc.
Этот .тс-файл состоит из набора сообщений, записанных в любом порядке. Его синтаксис подробно описан в документации Platform SDK.
Messageld — идентификатор, связанный с текстом. Значение этого поля можно явно не указывать. При этом компилятор сгенерирует идентификатор, превышающий на единицу идентификатор предыдущего сообщения. В поле SymbolicName указывается название, присваиваемое макросу, который будет определен в сгенерированном компилятором заголовочном файле. Включение такого заголовочного файла в код позволит вам использовать для идентификации сообщения макросы, определенные в поле SymbolicName. В строке Language определяется язык сообщения. Она позволяет создать единственный ресурс, поддерживающий несколько языков для одного идентификатора сообщения. Так как сообщение может занимать несколько строк, для обозначения его конца применяется точка. Заметьте: точка должна быть в строке одна, поэтому за точкой, обозначающей конец последней записи, должен следовать символ возврата каретки.
При регистрации события с помощью RcportEvent параметр dwEventID обозначает идентификатор события. Именно его значение используется при поиске компонентом Event Viewer текста в файле сообщений о событиях. Подобным образом и параметр wCategory этой функции связан с имеющим такой же идентификатор сообщением из файла сообщений о категории.
Как видите, синтаксис файла сообщений довольно прост, однако некоторые связанные с ним вопросы требуют дополнительного описания. Я уже говорил, что одна из главных целей регистрации событий — независимость от языка. Она реализуется в строке Language, за которой идет сообщение на соответствующем языке. Файлы на разных языках обычно компилируются в отдельные DLL. Например, ваш проект может включать MsgEnglish.dll и MsgFrench.dll. Если обе эти библиотеки указаны в значении реестра, отвечающем за файлы сообщений, Event Viewer сможет найти сообщение на нужном языке.
Сейчас вы, наверное, считаете, что для каждого идентификатора события Event Viewer отображает одинаковые сообщения. Если вы думаете, что механизм регистрации событий, основанный на статических строках, не очень удобен, вы правы. Нам хочется сообщать о событиях с одинаковым идентификатором, отображая разный текст в зависимости от ситуации. Например, если ваше приложение сообщает, что не может открыть файл, неплохо было бы включить в описание события название виновного в этом файла. Вы, конечно, уже догадались, что решение такой задачи — в параметре ppszString функции ReportEvent.
В сообщение вы можете поместить специальные последовательности символов, указывающие на место вставки специфичных для события строк. Например, п следующем сообщении находятся две строки:
"Файл Х1 заменен на файл Х2"
Если с помощью параметра ppszStrings вы передадите в функцию ReportEvent массив из двух строк, Event Viewer заменит «%1» на первую из них, а «%2» — на вторую.
Как правило, вы должны передавать строковые значения, не зависимые от языка, например, числа, названия файлов и других ресурсов. Конечно, можно передать любой текст, и Event Viewer вставит его в сообщение, однако при передаче, например, фразы на английском языке будет нарушена языковая независимость механизма регистрации событий.
Такой подход позволяет заменять параметры, что необходимо для включения в сообщения строк из файлов сообщений-параметров. Заменяемый параметр обозначается номером, которому предшествуют символы «%%*. Например, в следующей строке есть один заменяемый параметр:
"Это пример 501237"
При преобразовании этой строки Event Viewer найдет в таблице сообщений файла сообщений-параметров строку с идентификатором 237 и заменит на нее символы «%%237».
Кроме того, параметры заменяются после анализа строки, что позволяет проводить сложные преобразования. Допустим, у нас есть строка сообщения «Замена на динамический параметр %%%!», а в функцию ReportEvent передано значение «237». В этом случае Event Viewer сначала заменит «%1» на «237», а потом вместо получившейся строки «?6%237» вставит параметр с идентификатором 237 из файла сообщений-параметров.
Если значение реестра ParameterMessageFile источника сообщений установить в Kcrncl32.dll, можно будет динамически вставлять текстовые сообщения об ошибках, используя значения, возвращаемые GetLastError. Допустим, вы объявили файлом сообщений-параметров Kemel32.dll, а ваше сообщение выглядит так: «GetLastErrorQ вернула ошибку %%%1». При этом вы можете передать в ReportEvent, например, одну строку «5», указывающую на запрещение доступа. В результате вы получите такое сообщение о событии:
"GetLastErrorO вернула ошибку Access is denied".
Как видите, вставка текстового сообщения о последней ошибке в описание события — очень полезная функция.