核心模式下的字串操作
1)ASCII字串和寬字串
在應用程式中使用兩種字元:
a) char型字串,負責記錄ANSI字符集,它是指向一個char陣列的指標,每個char型變數大小是一個位元組,字串是以0標誌字串結束的;
b) wchar_t型的寬字串,負責描述unicode字符集,它是指向一個wchar_t陣列的指標,wchar_t字元大小為兩個位元組,字串以0標誌字串結束。
例:
ANSI字元構造如下: char *str1 = "ASCE";
UNICODE字元構造如下:wchar_t *str2 = L"ASCE";
注:在構造字串時使用關鍵字“L”,編譯器會自動生成所需要的寬字元
在驅動開發中,DDK將char和wchar_t替換成CHAR和WCHAR。
驅動程式中使用KdPrint巨集列印ASCII字串和寬字串: 在驅動開發中,DDK將char和wchar_t替換成CHAR和WCHAR。
例:
CHAR *string1 = "ASCE";
KdPrint(("%s\n", string1)); //注意是小寫%s
WCHAR *string2 = L"ASCE";
KdPrint(("%S\n", string2));
2)ANSI_STRING字串與UNICODE_STRING字串
DDK不鼓勵程式設計師使用C語言的字串,主要是因為標準C字串處理函式容易導致緩衝區溢位等錯誤。應該使用DDK自定義的字串:
這個結構對ASCII字串進行封裝:
typedef struct _STRING {
USHORT Length; //字元的長度,單位是位元組
USHORT MaximumLength; //整個字串緩衝區的最大長度
PCHAR Buffer; //緩衝區的指標
} ANSI_STRING, *PANSI_STRING;
標準C字串中,如果緩衝區長度是N,則只能容納N-1個字元的字串,最後一個位元組儲存NULL;而在STRING字串中,緩衝區大小是MaximumLength,最大字串長度可以是MaximumLength,而不是MaximumLength-1。
DDK將寬字串封裝成UNICODE_STRING資料結構:
typedef struct _UNICODE_STRING {
USHORT Length; //字元的長度,單位是位元組。如果是N個字元,那麼Length等於N的2倍
USHORT MaximumLength; //整個字串緩衝區的最大長度,單位是位元組
PWSTR Buffer; //緩衝區的指標
} UNICODE_STRING, *PUNICODE_STRING;
與ANSI_STRING一樣,UNICODE_STRING字串不是以NULL為結束標誌的。 列印這兩種字串方法如下:
ANSI_STRING ansiString;
//此處略去對ansiString的初始化
KdPrint(("%Z\n", &ansiString)); //注意是%Z
UNICODE_STRING uniString;
//此處略去對uniString的初始化
KdPrint(("%wZ\n", &uniString));
3)字元的初始化和銷燬
ANSI_STRING字串和UNICODE_STRING字串使用前需要進行初始化,有兩種方法構造這個資料結構:
(1)使用DDK提供的函式:
這種初始化的優點是操作簡單,用完後不用清理記憶體。但有一個問題,就是如果修改SourceString,同時會導致DestinationString字元發生變化:
初始化ANSI_STRING字串:
VOID RtlInitAnsiString(
__out PANSI_STRING DestinationString, //要初始化的ANSI_STRING字串
__in_opt PCSZ SourceString //字串的內容
);
初始化UNICODE_STRING字串:
VOID RtlInitUnicodeString(
__out PUNICODE_STRING DestinationString, //要初始化的UNICODE_STRING字串
__in_opt PCWSTR SourceString //字串的內容
);
ANSI_STRING ansiString;
CHAR *string = "asce";
//初始化ANSI_STRING字串
RtlInitAnsiString(&ansiString, string);
KdPrint(("ansiString: %Z\n", &ansiString));
//改變string
string[0] = 'a';
string[1] = 's';
string[2] = 'c';
string[3] = 'e';
//改變string的同時ansiString也改變了
KdPrint(("ansiString: %Z\n", &ansiString));
(2)程式設計師自己申請記憶體,並初始化記憶體,當不用字串時,需要回收字串佔用的記憶體:
#define BUFFER_SIZE 1024
UNICODE_STRING UnicodeString = {0};
//設定緩衝區大小
UnicodeString.MaximumLength = BUFFER_SIZE;
//分配記憶體
UnicodeString.Buffer = (PWSTR)ExAllocatePool(PagedPool, BUFFER_SIZE);
WCHAR *wideString = L"ASCE";
//設定字串長度,因為是寬字元,所以是字元長度的倍
UnicodeString.Length = 2*wcslen(wideString);
//保證緩衝區足夠大,否則程式終止
ASSERT(UnicodeString.MaximumLength >= UnicodeString.Length);
//記憶體複製
RtlCopyString(UnicodeString.Buffer, wideString, UnicodeString.Length);
KdPrint(("UnicodeString: %wZ\n", &UnicodeString));
//清理記憶體
ExFreePool(UnicodeString.Buffer);
UnicodeString.Buffer = NULL;
UnicodeString.Length = UnicodeString.MaximumLength = 0;
對於最後一步清理記憶體,DDK給出了簡化函式,分別是RtlFreeAnsiString和RtlFreeUnicodeString,這兩個函式內部呼叫了ExFreePool去回收記憶體的。
4)字串複製
DDK提供針對ANSI_STRING字串和UNICODE_STRING字串的複製字串函式:
VOID RtlCopyString(
__out PSTRING DestinationString, //目的字串
__in_opt const STRING *SourceString //源字串
);
VOID RtlCopyUnicodeString(
__inout PUNICODE_STRING DestinationString, //目的字串
__in_opt PCUNICODE_STRING SourceString //源字串
);
下面程式碼說明了RtlCopyUnicodeString函式的使用:
#define BUFFER_SIZE 1024
//初始化UnicodeString1
UNICODE_STRING UnicodeString1;
RtlInitUnicodeString(&UnicodeString1, L"ASCE");
//初始化UnicodeString2
UNICODE_STRING UnicodeString2 = {0};
UnicodeString2.Buffer = (PWSTR)ExAllocatePool(PagedPool, BUFFER_SIZE);
UnicodeString2.MaximumLength = BUFFER_SIZE;
//將初始化UnicodeString1複製到UnicodeString2
RtlCopyUnicodeString(&UnicodeString2, &UnicodeString1);
//分別顯示UnicodeString1和UnicodeString2
KdPrint(("UnicodeString1: %wZ\n", &UnicodeString1));
KdPrint(("UnicodeString2: %wZ\n", &UnicodeString2));
//銷燬UnicodeString2,注意:UnicodeString1不用銷燬
RtlFreeUnicodeString(&UnicodeString2);
5)字串比較
DDK提供了對ANSI_STRING字串和UNICODE_STRING字串的相關比較函式:
LONG RtlCompareString(
__in const STRING *String1, //要比較的第一個字串
__in const STRING *String2, //要比較的第二個字串
__in BOOLEAN CaseInSensitive //是否對大小寫敏感
);
LONG RtlCompareUnicodeString(
__in PCUNICODE_STRING String1, //要比較的第一個字串
__in PCUNICODE_STRING String2, //要比較的第二個字串
__in BOOLEAN CaseInSensitive //是否對大小寫敏感
);
DDK同時提供了RtlEqualString和RtlEqualUnicodeString函式,返回為非零代表相等,零代表不相等: 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
);
函式例項:
//初始化UnicodeString1
UNICODE_STRING UnicodeString1;
RtlInitUnicodeString(&UnicodeString1, L"ASCE");
//初始化UnicodeString2
UNICODE_STRING UnicodeString2;
RtlnitUnicodeString(&UnicodeString2, L"ASCE BOY");
//判斷字串是否相等
if(RtlEqualUnicodeString(&UnicodeString1, &UnicodeString2, TRUE))
{
KdPrint(("UnicodeString1 and UnicodeString2 are equal\n"));
}
else
{
KdPrint(("UnicodeString1 and UnicodeString2 are not euqal\n"));
}
6)字串轉化成大寫
DDK提供的將ANSI_STRING字串和UNICODE_STRING字串轉換成大寫的函式如下:
VOID RtlUpperString(
__inout PSTRING DestinationString, //目的字串
__in const STRING *SourceString //源字串
);
NTSTATUS RtlUpcaseUnicodeString(
__inout PUNICODE_STRING DestinationString, //目的字串
__in PCUNICODE_STRING SourceString, //源字串
__in BOOLEAN AllocateDestinationString //是否為目的字串分配記憶體,
//目的字串和源字串可以是同一個字串
);
例項程式碼:
//初始化UnicodeString1
UNICODE_STRING UnicodeString;
RtlInitUnicodeString(&UnicodeString, L"ASCE BOY");
//變化前
KdPrint(("UnicodeString: %wZ\n", &UnicodeString));
//轉化成大寫
RtlUpcaseUnicodeString(&UnicodeString, &UnicodeString, FALSE);
//變化後
KdPrint(("UnicodeString: %wZ\n", &UnicodeString));
7)字串與整型數字相互轉換
將UNICODE_STRING字串轉換成整數:
NTSTATUS RtlUnicodeStringToInteger(
__in PCUNICODE_STRING String, //需要轉換的字串
__in_opt ULONG Base, //轉換的數的進位制(如2、8、10、16)
__out PULONG Value //需要轉換的數字
);
將整數轉換成UNICODE_STRING字串:
NTSTATUS RtlIntegerToUnicodeString(
__in ULONG Value, //需要轉換的數字
__in_opt ULONG Base, //轉換的數的進位制(2、8、10、16)
__inout PUNICODE_STRING String //需要轉換的字串
);
例項程式碼如下:
#define BUFFER_SIZE 1024
//字串轉換成數字
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"));
}
//將數字轉換成字串
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"));
}
//銷燬UnicodeStringSec,注意:UnicodeString不用銷燬
RtlFreeUnicodeString(&UnicodeStringSec);
8)ANSI_STRING字串與UNICODE_STRING字串的轉換
將UNICODE_STRING字串轉換成ANSI_STRING字串:
NTSTATUS RtlUnicodeStringToAnsiString(
__inout PANSI_STRING DestinationString, //需要被轉換的字串
__in PCUNICODE_STRING SourceString, //需要轉換的源字串
__in BOOLEAN AllocateDestinationString //是否需要對被轉換字串分配記憶體
);
將ANSI_STRING字串轉換成UNICODE_STRING字串:
NTSTATUS RtlAnsiStringToUnicodeString(
__inout PUNICODE_STRING DestinationString, //需要被轉換的字串
__in PCANSI_STRING SourceString, //需要轉換的源字串
__in BOOLEAN AllocateDestinationString //是否需要對被轉換字串分配記憶體
);
例項程式碼如下:
//將UNICODE_STRING字串轉換成ANSI_STRING字串
UNICODE_STRING UnicodeString;
RtlInitUnicodeString(&UnicodeString, L"ASCE BOY");
ANSI_STRING AnsiString;
NTSTATUS nStatus = RtlUnicodeStringToAnsiString(&AnsiString, &UnicodeString, TRUE);
if(NT_SUCCESS(nStatus))
{
KdPrint(("Conver successfully\n"));
KdPrint(("Result:%Z\n", &AnsiString));
}
else
{
KdPrint(("Conver failed\n"));
}
//銷燬AnsiString
RtlFreeAnsiString(&AnsiString);
//將ANSI_STRING字串轉換成UNICODE_STRING字串
ANSI_STRING AnsiStringSec;
RtlInitString(&AnsiStringSec, "ASCE BOY");
UNICODE_STRING UnicodeStringSec;
nStatus = RtlAnsiStringToUnicodeString(&UnicodeStringSec, &AnsiStringSec, TRUE);
if(NT_SUCCESS(nStatus))
{
KdPrint(("Conver successfully\n"));
KdPrint(("Result: %wZ\n", &UnicodeStringSec));
}
else
{
KdPrint(("Conver failed\n"));
}
//銷燬UnicodeStringSec
RtlFreeUnicodeString(&UnicodeStringSec);
相關文章
- 字串的操作字串
- 部分liunx下字串操作函式(轉載)字串函式
- 字串操作字串
- 字串和字元的操作字串字元
- shell下數字和字串比較操作命令字串
- 07字串操作字串
- ABAP字串操作字串
- shell 字串操作字串
- JS常見的字串操作JS字串
- Python中字串的操作Python字串
- Python字串操作Python字串
- Laravel str 字串操作Laravel字串
- python 字串操作Python字串
- 字串操作函式字串函式
- C# 字串操作C#字串
- python 之 字串的所有操作Python字串
- IOS 常用字串的操作iOS字串
- delphi中關於字串的操作字串
- openCV入門 核心操作 1 影像的基礎操作OpenCV
- [C#]C#中字串的操作C#字串
- 高效操作字串的String Reference類字串
- 操作型別之字串型別字串
- ES6操作字串字串
- 字串操作 localeCompare()方法字串
- shell中字串操作【轉】字串
- golang 字串操作例項Golang字串
- Sql字串操作函式SQL字串函式
- Delphi字串指標操作字串指標
- SQL字串操作彙總SQL字串
- 字串的一個操作(替換類似陣列字串中的項)字串陣列
- Awk 字串連線操作(字串轉數字,數字轉字串)字串
- shell 下的字串比較字串
- 字串匹配模式問題字串匹配模式
- 1-python 字串的相關操作Python字串
- JavaScript中對字串常用的操作方法JavaScript字串
- 103-字串的定義和操作字串
- Js字串操作函式大全JS字串函式
- 手撕字串操作函式字串函式