Операции над строками ANSI символов
Работа со строками символов ANSI (8-битными) более привычна для программистов. Такие средства тоже присутствуют в наборе встроенных функций пакета и в наборе системных вызовов RtlXxx.
Строками простых 8-битных символов, в которых окончание обозначено нулем (так называемые строки SZ, String, Zero end), можно манипулировать при помощи уцелевших встроенных функций strlen, memcpy, strcpy, strncpy, strcat и даже strstr. Набор функций, которыми можно попытаться воспользоваться, приведен в файле DDK XP в заголовочном файле inc\crt\string.h, хотя в официальной документации DDK они не упоминаются вовсе, так что к ним следует применять правила использования по-умолчанию. Например, не обращаться к строкам, размещенным в страничной памяти, на высоких уровнях IRQL и т.п. Другие функции, например, мощную sprintf или хотя бы atoi, компилятор DDK не предоставляет.
Вариант счетной строки обычных 8-битных символов вводится в пакете DDK как тип данных ANSI_STRING. Это аналогичная UNICODE_STRING структура данных, в которой собственно строка хранится по адресу, указанному в поле Buffer, как уже было показано выше. Длину строки можно взять из поля Length. Хотя в большинстве случаев вполне успешно проходит обращение со строкой по адресу Buffer, как если бы она была строкой SZ (заканчивающейся нулем), однако, строго говоря, надеяться на это не следует, поскольку документация DDK не указывает, что на это можно вполне рассчитывать.
Можно ли перейти от строки UNICODE_STRING к обычной строке 8-битных символов? Можно, но при этом произойдет потеря информации о языковой локализации. Ниже показан несложный способ, как перейти к счетной строке ANSI, а затем и к обычной строке SZ.
// Полагаем, что уже существует счетная строка UNICODE_STRING // по адресу ptrToUNICODE_STRING ANSI_STRING ansiStr; // стековая переменная (не инициализирована) char str[100];// стековая переменная
NTSTATUS stat = // инициализируем строку ANSI RtlUnicodeStringToAnsiString( &ansiStr, ptrToUNICODE_STRING, TRUE );
if(NT_SUCCESS(stat)) { // Теперь поле ansiString. Buffer указывает на выделенный буфер, // куда помещена строка ANSI символов, полученная из строки // UNICODE_STRING, изначально находившейся по адресу, куда // указывает переменная ptrToUNICODE_STRING. // Поле ansiStr.Length уже содержит информацию о длине строки. int len= (ansiStr.Length > 99? 99: ansiStr.Length); strncpy(str, ansiStr.Buffer, len); str[len+1]=0;
DbgPrint("SZ string = %s(len=%d).", str, len);
// Освобождаем буфер, выделенный под хранение ANSI строки: RtlFreeAnsiString(&ansiStr); }
Заметим, что переменная str будет хранить строку 8-битных символов до выхода из данного программного модуля, поскольку str — локальная переменная.
Прототип вызова функции RtlUnicodeStringToAnsiString описан в таблице ниже. В том случае, если третий параметр указан как TRUE, то будет выполнено выделение памяти для хранения строки, полученной из строки UNICODE_STRING. Соответственно, по окончании использования строки ANSI_STRING следует освободить числящуюся за драйвером область памяти, что выполняется вызовом RtlFreeAnsiString.
Таблица 7.38. Прототип вызова RtlUnicodeStringToAnsiString
NTSTATUS RtlUnicodeStringToAnsiString | IRQL == PASSIVE_LEVEL |
Параметры | Преобразует информацию строки UNICODE_STRING в строку ANSI_STRING |
IN OUT PANSI_STRING ansiStringPtr | Указатель на строку ANSI_STRING, которая должна быть получена в результате вызова |
IN PUNICODE_STRING Source | Указатель на исходную строку UNICODE_STRING |
BOOLEAN AllocFlag | TRUE — выделить память под буфер строки ANSI_STRING |
Возвращаемое значение | STATUS_SUCCESS или код ошибки |