Программирование драйверов Windows

       

Операции над строками 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 &#62 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 &#8212 локальная переменная.

Прототип вызова функции 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 &#8212 выделить память под буфер строки ANSI_STRING
Возвращаемое значение STATUS_SUCCESS или код ошибки
Работа с текстом в драйверах случается нечасто, но, тем не менее, следует быть к ней готовым. Например, при работе с файлами.


Содержание раздела