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

       

Операции над строками UNICODE_STRING


Операционная система Windows NT издавна ориентирована на использование так называемых "широких" символов (занимающих два байта), что, в отличие от символов ASCII, o которых будет сказано ниже, без особых затруднений обеспечивает поддержку всех типов алфавитов, включая поддержку языков Юго-Восточной Азии.

Собственно тип данных UNICODE_STRING описывается в пакете DDK следующим образом (см. заголовочный файл ntdef.h):

typedef struct _UNICODE_STRING { USHORT Length; // Длина строки (в двухбайтных символах) USHORT MaximumLength; // Максимально возможная длина строки PWSTR Buffer; // указатель на буфер с двухбайтными символами } UNICODE_STRING, *PUNICODE_STRING;

Иногда UNICODE_STRING определяется выражением "counted string", что довольно точно передает сущность этого типа данных, то есть &#8212 "счетная строка", строка, где поддерживается учет действующих символов.

Нетрудно догадаться, что у программистов, долгое время привыкавших к простым ASCII кодировкам и столь же несложным функциям, оперирующим ASCIIZ строками, переход к использованию кодировки Юникод не вызовет энтузиазма.

Тем не менее, при работе в режиме ядра Windows NT это совершенно необходимый инструмент. (Правда, функции отладочной диагностики типа DbgPrint

позволяют пользоваться строками в прежней манере.)

Работа с типом UNICODE_STRING покажется менее сложной, если смириться с тем, что не следует "трогать его руками" (примерно, как CString в MFC), и научиться использовать набор системных функций, предназначенный для работы с ним.

Прежде всего, простая буква 'L', примененная перед строкой символов, дает указание препроцессору, трактовать эту строку как строку "широких" символов (строку WCHAR, но еще &#8212 не UNICODE_STRING). Соответственно, перейти от обычного текста, набираемого на клавиатуре компьютера, к строке UNICODE_STRING можно так:

UNICODE_STRING myNewUString; RtlInitUnicodeString( &myNewUString, L"My Unicode text example." );


В следующем примере посредником при инициализации UNICODE_STRING выступает тип данных ANSI_STRING (счетная строка однобайтных символов):

ANSI_STRING myNewANSIString; UNICODE_STRING myNewUString; RtlInitAnsiString( &myNewUString, "My second text example." ); RtlAnsiStringToUnicodeString(&myNewUString, &myNewANSIString, TRUE);



Третий параметр, указанный как TRUE, заставляет данную функцию выделять память под буфер двухбайтных символов. Соответственно, по окончании работы с UNICODE_STRING (а в данном случае &#8212 при выходе из текущей функции, поскольку myNewUString определена как локальная переменная) следует выполнить освобождение буфера двухбайтных символов вызовом RtlFreeUnicodeString. To же необходимо проделать и в первом примере. Более того, аналогичное требование и к типу данных ANSI_STRING, для которого следует использовать RtlFreeAnsiString.

Сам тип ANSI_STRING определяется следующим образом (см. ntdef.h):

typedef struct _STRING { USHORT Length; USHORT MaximumLength; PCHAR Buffer; // Здесь 'PCHAR' - просто 'char' указатель } STRING, *PSTRING; typedef STRING ANSI_STRING;

Очевидно, второй способ более трудоемкий, и им редко кто пользуется.

После того как экземпляр UNICODE_STRING получен, над ним можно выполнять разнообразные операции. Предназначенные для этого системные функции описываются ниже.

Таблица 7.33. Прототип вызова RtlAppendUnicodeStringToString

NTSTATUS RtlAppendUnicodeStringToString IRQL &#8212 любой (если это допускает тип памяти буферов двухбайтных символов)
Параметры Объединяет строки UNICODE_STRING
IN OUT PUNICODE_STRING Destination Указатель на строку-получатель
IN OUT PUNICODE_STRING AppendString Указатель на присоединяемую строку
Возвращаемое значение STATUS_SUCCESS &#8212 строка присоединена и длина строки получателя обновлена

STATUS_BUFFER_TOO_SMALL &#8212 слишком мал размер буфера двухбайтных символов строки-получателя
При анализе приведенного выше описания возникает правомерный вопрос: что предпринимать, если объединение строк завершилось неудачей по причине недостаточно большого буфера принимающей строки UNICODE_STRING? Достойного ответа в пакете DDK на этот вопрос просто нет.


Если требуемый размер буфера не составит труда вычислить как

(Destination-&#62Length + AppendString-&#62Length) * sizeof(WCHAR)

то расширение буфера строки-получателя &#8212 задача несколько более сложная. Хотя логично было бы иметь соответствующую системную функцию, однако в документации DDK o подобном вызове нет никакого упоминания.

Таблица 7.34. Прототип вызова RtlCompareUnicodeString

LONG RtlCompareUnicodeString IRQL == PASSIVE_LEVEL
Параметры Выполняет сравнение строк UNICODE_STRING
IN PUNICODE_STRING pString1 Указатель на первую строку
IN PUNICODE_STRING pString2 Указатель на вторую строку
BOOLEAN CaseInSensitive TRUE &#8212 игнорировать регистр (верхний/нижний)
Возвращаемое значение 0 &#8212 строки идентичны

&#60 0 &#8212 строка 1 меньше строки 2
Таблица 7.35. Прототип вызова RtlEqualUnicodeString

BOOLEAN RtlEqualUnicodeString IRQL == PASSIVE_LEVEL
Параметры Выполняет сравнение строк UNICODE_STRING
IN PUNICODE_STRING pString1 Указатель на первую строку
IN PUNICODE_STRING pString2 Указатель на вторую строку
BOOLEAN CaseInSensitive TRUE &#8212 игнорировать регистр (верхний/нижний)
Возвращаемое значение TRUE &#8212 строки идентичны

FALSE &#8212 строки различаются
Таблица 7.36. Прототип вызова RtlInt64ToUnicodeString

NTSTATUS RtlInt64ToUnicodeString IRQL == PASSIVE_LEVEL
Параметры Преобразует число int64 в UNICODE_STRING
IN ULONGLONG Value Исходное число
IN ULONG Base Формат: 16 &#8212 шестнадцатеричный, 8 &#8212 октавный, 2 &#8212 двоичный, 0 или 10 &#8212 десятичный.
IN OUT PUNICODE_STRING s Строка UNICODE_STRING
Возвращаемое значение STATUS_SUCCESS

STATUS_BUFFER_OVERFLOW &#8212 слишком мал размер буфера UNICODE_STRING

STATUS_INVALID_PARAMETER &#8212 ошибочен параметр Base
Аналогичный прототип вызова имеют также функции преобразования целых чисел без знака и указателей в строку UNICODE_STRING &#8212 RtlIntegerToUnicodeString



и RtlIntPtrToUnicodeString, соответственно.

Таблица 7.37. Прототип вызова RtlUpcaseUnicodeString

NTSTATUS RtlUpcaseUnicodeString IRQL == PASSIVE_LEVEL
Параметры Преобразует все символы строки src в символы верхнего регистра
IN OUT OPTIONAL PUNICODE_STRING dest Указатель на строку с буфером, подготовленным для приема преобразованной строки или NULL (в последнем случае преобразование происходит по месту)
IN OUT PUNICODE_STRING src Исходная строка
IN BOOLEAN AllocateDstStringBuff Если TRUE &#8212 выделить буфер под результат преобразования (в этом случае его следует освободить вызовом RtlFreeUnicodeString

по окончании работы с этой строкой)
Возвращаемое значение STATUS_SUCCESS

STATUS_BUFFER_OVERFLOW &#8212 слишком мал размер буфера UNICODE_STRING

STATUS_INVALID_PARAMETER &#8212 ошибочен параметр Base

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