1) ASCII string and wide string
Use two types of Characters in the application:
A) Char stringRecords the ANSI character set. It is a pointer to a char array. The size of each char variable is a byte, and the string ends with a string of 0;
B) wchar_t type wide stringDescription of the Unicode character set, which is a pointer to a wchar_t array. The size of the wchar_t character is two bytes, and the string ends with a 0 Sign string.
Example:
ANSI character structure: char * str1 = "asce ";
Unicode character structure: wchar_t * str2 = l "asce"; Note: When constructing a string using the keyword "L", the compiler automatically generates the required wide character
In driver development, DDK replaces char and wchar_t with Char and wchar.
Use the kdprint macro in the driver to print the ASCII string and width string:
Example:
Char * string1 = "asce"; kdprint ("% s \ n", string1); // note that it is lower case % s wchar * string2 = l "asce "; kdprint ("% s \ n", string2 ));
2) ansi_string and unicode_string
DDK does not encourage programmers to use C-language strings, mainly because the standard C string processing functions can easily cause errors such as buffer overflow. The custom string of DDK should be used:
This structure encapsulates ASCII strings:
Typedef struct _ string {ushort length; // character length, in bytes ushort maximumlength; // Maximum length of the entire string buffer pchar buffer; // buffer pointer} ansi_string, * pansi_string;
In the standard C string, if the buffer length is N, it can only hold the string of N-1 characters, the last byte stores NULL;
In string strings, the buffer size is maximumlength, and the maximum string length can be maximumlength, rather than MaximumLength-1.
DDK encapsulates the wide string into the unicode_string data structure:
Typedef struct _ unicode_string {ushort length; // The length of the character, in bytes. If it is n characters, the length is equal to 2 times that of N. ushort maximumlength; // the maximum length of the entire string buffer, in the unit of byte pwstr buffer; // buffer pointer} unicode_string, * punicode_string;
Like ansi_string, The unicode_string string does not end with null.
The following describes how to print the two strings:
Ansi_string ansistring; // The initialization kdprint ("% Z \ n", & ansistring) of ansistring is omitted here; // note that it is % Z unicode_string unistring; // The initialization kdprint ("% WZ \ n", & unistring) of unistring is omitted here ));
3) character initialization and destruction
The ansi_string and unicode_string strings must be initialized before use. There are two methods to construct the data structure:
(1) Use the functions provided by DDK:
The advantage of this initialization is that the operation is simple and the memory does not need to be cleared after use. However, if you modify sourcestring, The destinationstring character changes:
Initialize ansi_string: void rtlinitansistring (_ out pansi_string destinationstring, // The ansi_string to be initialized _ in_opt pcsz sourcestring // the content of the string); initialize the unicode_string: void rtlinitunicodestring (_ out punicode_string destinationstring, // the content of the unicode_string _ in_opt pcwstr sourcestring // string to be initialized); ansi_string ansistring; char * string = "asce "; // initialize ansi_string rtlinitansistring (& ansistring, string); kdprint ("ansistring: % Z \ n", & ansistring )); // change string [0] = 'a'; string [1] = 's'; string [2] = 'C'; string [3] = 'E '; // while changing the string, ansistring also changes kdprint ("ansistring: % Z \ n", & ansistring ));
(2) The programmer applies for memory and initializes the memory. When no string is needed, the memory occupied by the string must be recycled:
# Define buffer_size 1024 unicode_string unicodestring = {0}; // set the buffer size unicodestring. maximumlength = buffer_size; // allocate memory unicodestring. buffer = (pwstr) exallocatepool (pagedpool, buffer_size); wchar * widestring = l "asce"; // set the string length. Because it is a wide character, it is twice the length of the character unicodestring. length = 2 * wcslen (widestring); // ensure that the buffer is large enough; otherwise, the program terminates assert (unicodestring. maximumlength> = unicodestring. length); // copy rtlcopystring (unicodest Ring. buffer, widestring, unicodestring. length); kdprint ("unicodestring: % WZ \ n", & unicodestring); // clear the memory exfreepool (unicodestring. buffer); unicodestring. buffer = NULL; unicodestring. length = unicodestring. maximumlength = 0; for memory cleanup in the last step, DDK provides the simplified functions rtlfreeansistring and rtlfreeunicodestring, which call exfreepool internally to recycle the memory.
4) string Replication
DDK provides a copy string function for ansi_string and unicode_string:
Void rtlcopystring (_ out pstring destinationstring, // destination string _ in_opt const string * sourcestring // source string); void rtlcopyunicodestring (_ inout punicode_string destinationstring, // destination string _ in_opt pcunicode_string sourcestring // source string );
The following code illustrates the use of the rtlcopyunicodestring function:
# Define buffer_size 1024 // initialize unicodestring1 unicode_string unicodestring1; initialize (& unicodestring1, l "asce"); // initialize unicodestring2 unicode_string unicodestring2 = {0}; Forward = (pwstr) exallocatepool (pagedpool, buffer_size); bytes = buffer_size; // copy the initialization unicodestring1 to unicodestring2 values (& found, & found); // unicodestring1 and javaskdprint ("unicodestring1: % WZ \ n ", & unicodestring1); kdprint (" unicodestring2: % WZ \ n ", & unicodestring2); // destroy unicodestring2. Note: unicodestring1 does not need to destroy rtlfreeunicodestring (& unicodestring2 );
5) string comparison
DDK provides a comparison function for the ansi_string and unicode_string strings:
Long rtlcomparestring (_ in const string * string1, // The first string to be compared _ in const string * string2, // The second string to be compared: _ in Boolean caseinsensitive // case sensitive); long rtlcompareunicodestring (_ in pcunicode_string string1, // The first string to be compared _ in pcunicode_string string2, // The second string to be compared _ in Boolean caseinsensitive // whether it is case sensitive );
DDK also provides the rtlequalstring and rtlequalunicodestring functions. If the return value is non-zero, the return value is equal. If the return value is zero, the return value is not equal:
BOOLEAN RtlEqualString( __in const STRING *String1, __in const STRING *String2, __in BOOLEAN CaseInSensitive ); BOOLEAN RtlEqualUnicodeString( __in PCUNICODE_STRING String1, __in PCUNICODE_STRING String2, __in BOOLEAN CaseInSensitive );
Function example:
// Initialize unicodestring1 unicode_string unicodestring1; initialize (& unicodestring1, l "asce"); // initialize unicodestring2 unicode_string unicodestring2; initialize (& unicodestring2, l "asce boy "); // judge whether the string is equal if (rtlequalunicodestring (& unicodestring1, & unicodestring2, true) {kdprint ("unicodestring1 and unicodestring2 are equal \ n "));} else {kdprint ("unicodestring1 and unicodestring2 are not euqal \ n "));}
6) convert the string to uppercase.
The function provided by DDK to convert ansi_string and unicode_string to uppercase is as follows:
Void rtlupperstring (_ inout pstring destinationstring, // destination string _ in const string * sourcestring // source string); ntstatus rtlupcaseunicodestring (_ inout punicode_string destinationstring, // destination string _ in pcunicode_string sourcestring, // source string _ in Boolean allocatedestinationstring // whether to allocate memory for the destination string, // The target string and source string can be the same string );
Instance code:
// Initialize unicodestring1 unicode_string unicodestring; rtlinitunicodestring (& unicodestring, l "asce boy"); // before change kdprint ("unicodestring: % WZ \ n", & unicodestring )); // convert it to rtlupcaseunicodestring (& unicodestring, & unicodestring, false); // after the change, kdprint ("unicodestring: % WZ \ n", & unicodestring ));
7) string and Integer Conversion
Convert a unicode_string to an integer:
Ntstatus rtlunicodestringtointeger (_ in pcunicode_string string, // the string to be converted _ in_opt ulong base, // The number of converted values (such as 2, 8, 10, 16) _ out Pulong value // number to be converted); converts an integer to a unicode_string: ntstatus rtlintegertounicodestring (_ in ulong value, // number _ in_opt ulong base to be converted, // The hexadecimal format of the number to be converted (2, 8, 10, 16) _ inout punicode_string string // the string to be converted );
The instance code is as follows:
# Define buffer_size 1024 // the string is converted to the numeric unicode_string unicodestring; rtlinitunicodestring (& unicodestring, l "-100"); ulong lnumber; ntstatus nstatus = rtlunicodestringtointeger (& unicodestring, 10, & lnumber); If (nt_success (nstatus) {kdprint ("conver to integer successfully \ n"); kdprint ("Result: % d \ n ", lnumber);} else {kdprint ("conver to integer failed \ n");} // converts a number to a string unicode_string unicodestringsec = {0}; unicodestringsec. buffer = (pwstr) exallocatepool (pagedpool, buffer_size); unicodestringsec. maximumlength = buffer_size; nstatus = rtlintegertounicodestring (200, 10, & unicodestringsec); If (nt_success (nstatus) {kdprint ("cover to string successfully \ n ")); kdprint ("Result: % WZ \ n", & unicodestringsec);} else {kdprint ("conver to string failed \ n");} // destroy unicodestringsec, note: unicodestring does not need to destroy rtlfreeunicodestring (& unicodestringsec );
8) ansi_string and unicode_string Conversion
Convert a unicode_string to an ansi_string:
Ntstatus rtlunicodestringtoansistring (_ inout pansi_string destinationstring, // string to be converted _ in pcunicode_string sourcestring, // source string to be converted _ in Boolean allocatedestinationstring // whether to allocate memory to the converted string); Convert ansi_string to unicode_string: ntstatus rtlansistringtounicodestring (_ inout punicode_string destinationstring, // string to be converted _ in pcansi_string sourcestring, // source string to be converted _ in Boolean allocatedestinationstring // whether to allocate memory to the converted string );
The instance code is as follows:
// Convert the unicode_string to the ansi_string unicode_string unicodestring; rtlinitunicodestring (& unicodestring, l "asce boy"); ansi_string ansistring; ntstatus nstatus = running (& ansistring, & unicodestring, true); If (nt_success (nstatus) {kdprint ("conver successfully \ n"); kdprint ("Result: % Z \ n ", & ansistring);} else {kdprint ("conver failed \ n");} // destroy ansistring rtlfreeansistring (& ansistring ); // convert ansi_string to unicode_string ansi_string ansistringsec; rtlinitstring (& signature, "asce boy"); unicode_string unicodestringsec; nstatus = require (& unicodestringsec, & signature, true ); if (nt_success (nstatus) {kdprint ("conver successfully \ n"); kdprint ("Result: % WZ \ n", & unicodestringsec ));} else {kdprint ("conver failed \ n");} // destroy unicodestringsec rtlfreeunicodestring (& unicodestringsec );