总版主
|
阅读:4663回复:8
Windows驱动编程基础教程(连载2)
本文作者为楚狂人。有问题请联系QQ 16191935,msn walled_river@hotmail.com
Windows驱动编程基础教程(1.4-2.1) 1.4 字符串的连接 UNICODE_STRING不再是简单的字符串。操作这个数据结构往往需要更多的耐心。读者会常常碰到这样的需求:要把两个字符串连接到一起。简单的追加一个字符串并不困难。重要的依然是保证目标字符串的空间大小。下面是范例: NTSTATUS status; UNICODE_STRING dst; // 目标字符串 WCHAR dst_buf[256]; // 我们现在还不会分配内存,所以先定义缓冲区 UNICODE_STRING src = RTL_CONST_STRING(L”My source string!”); // 把目标字符串初始化为拥有缓冲区长度为256的UNICODE_STRING空串 RtlInitEmptyString(dst,dst_buf,256*sizeof(WCHAR)); RtlCopyUnicodeString(&dst,&src); // 字符串拷贝! status = RtlAppendUnicodeToString( &dst,L”my second string!”); if(status != STATUS_SUCCESS) { …… } NTSTATUS是常见的返回值类型。如果函数成功,返回STATUS_SUCCESS。否则的话,是一个错误码。RtlAppendUnicodeToString在目标字符串空间不足的时候依然可以连接字符串,但是会返回一个警告性的错误STATUS_BUFFER_TOO_SMALL。 另外一种情况是希望连接两个UNICODE_STRING,这种情况请调用RtlAppendUnicodeStringToString。这个函数的第二个参数也是一个UNICODE_STRING的指针。 1.5 字符串的打印 字符串的连接另一种常见的情况是字符串和数字的组合。有时数字需要被转换为字符串。有时需要把若干个数字和字符串混合组合起来。这往往用于打印日志的时候。日志中可能含有文件名、时间、和行号,以及其他的信息。 熟悉C语言的读者会使用sprintf。这个函数的宽字符版本为swprintf。该函数在驱动开发中依然可以使用,但是不安全。微软建议使用RtlStringCbPrintfW来代替它。RtlStringCbPrintfW需要包含头文件ntstrsafe.h。在连接的时候,还需要连接库ntsafestr.lib。 下面的代码生成一个字符串,字符串中包含文件的路径,和这个文件的大小。 #include <ntstrsafe.h> // 任何时候,假设文件路径的长度为有限的都是不对的。应该动态的分配 // 内存。但是动态分配内存的方法还没有讲述,所以这里再次把内存空间 // 定义在局部变量中,也就是所谓的“在栈中” WCHAR buf[512] = { 0 }; UNICODE_STRING dst; NTSTATUS status; …… // 字符串初始化为空串。缓冲区长度为512*sizeof(WCHAR) RtlInitEmptyString(dst,dst_buf,512*sizeof(WCHAR)); // 调用RtlStringCbPrintfW来进行打印 status = RtlStringCbPrintfW( dst->Buffer,L”file path = %wZ file size = %d \r\n”, &file_path,file_size); // 这里调用wcslen没问题,这是因为RtlStringCbPrintfW打印的 // 字符串是以空结束的。 dst->Length = wcslen(dst->Buffer) * sizeof(WCHAR); RtlStringCbPrintfW在目标缓冲区内存不足的时候依然可以打印,但是多余的部分被截去了。返回的status值为STATUS_BUFFER_OVERFLOW。调用这个函数之前很难知道究竟需要多长的缓冲区。一般都采取倍增尝试。每次都传入一个为前次尝试长度为2倍长度的新缓冲区,直到这个函数返回STATUS_SUCCESS为止。 值得注意的是UNICODE_STRING类型的指针,用%wZ打印可以打印出字符串。在不能保证字符串为空结束的时候,必须避免使用%ws或者%s。其他的打印格式字符串与传统C语言中的printf函数完全相同。可以尽情使用。 另外就是常见的输出打印。printf函数只有在有控制台输出的情况下才有意义。在驱动中没有控制台。但是Windows内核中拥有调试信息输出机制。可以使用特殊的工具查看打印的调试信息(请参阅附录1“WDK的安装与驱动开发的环境配置”)。 驱动中可以调用DbgPrint()函数来打印调试信息。这个函数的使用和printf基本相同。但是格式字符串要使用宽字符。DbgPrint()的一个缺点在于,发行版本的驱动程序往往不希望附带任何输出信息,只有调试版本才需要调试信息。但是DbgPrint()无论是发行版本还是调试版本编译都会有效。为此可以自己定义一个宏: #if DBG KdPrint(a) DbgPrint##a #else KdPrint (a) #endif 不过这样的后果是,由于KdPrint (a)只支持1个参数,因此必须把DbgPrint的所有参数都括起来当作一个参数传入。导致KdPrint看起来很奇特的用了双重括弧: // 调用KdPrint来进行输出调试信息 status = KdPrint (( L”file path = %wZ file size = %d \r\n”, &file_path,file_size)); 这个宏没有必要自己定义,WDK包中已有。所以可以直接使用KdPrint来代替DbgPrint取得更方便的效果。 2.1内存的分配与释放 内存泄漏是C语言中一个臭名昭著的问题。但是作为内核开发者,读者将有必要自己来面对它。在传统的C语言中,分配内存常常使用的函数是malloc。这个函数的使用非常简单,传入长度参数就得到内存空间。在驱动中使用内存分配,这个函数不再有效。驱动中分配内存,最常用的是调用ExAllocatePoolWithTag。其他的方法在本章范围内全部忽略。回忆前一小节关于字符串的处理的情况。一个字符串被复制到另一个字符串的时候,最好根据源字符串的空间长度来分配目标字符串的长度。下面的举例,是把一个字符串src拷贝到字符串dst。 // 定义一个内存分配标记 #define MEM_TAG ‘MyTt’ // 目标字符串,接下来它需要分配空间。 UNICODE_STRING dst = { 0 }; // 分配空间给目标字符串。根据源字符串的长度。 dst.Buffer = (PWCHAR)ExAllocatePoolWithTag(NonpagedPool,src->Length,MEM_TAG); if(dst.Buffer == NULL) { // 错误处理 status = STATUS_INSUFFICIENT_RESOUCRES; …… } dst.Length = dst.MaximumLength = src->Length; status = RtlCopyUnicodeString(&dst,&src); ASSERT(status == STATUS_SUCCESS); ExAllocatePoolWithTag的第一个参数NonpagedPool表明分配的内存是锁定内存。这些内存永远真实存在于物理内存上。不会被分页交换到硬盘上去。第二个参数是长度。第三个参数是一个所谓的“内存分配标记”。 内存分配标记用于检测内存泄漏。想象一下,我们根据占用越来越多的内存的分配标记,就能大概知道泄漏的来源。一般每个驱动程序定义一个自己的内存标记。也可以在每个模块中定义单独的内存标记。内存标记是随意的32位数字。即使冲突也不会有什么问题。 此外也可以分配可分页内存,使用PagedPool即可。 ExAllocatePoolWithTag分配的内存可以使用ExFreePool来释放。如果不释放,则永远泄漏。并不像用户进程关闭后自动释放所有分配的空间。即使驱动程序动态卸载,也不能释放空间。唯一的办法是重启计算机。 ExFreePool只需要提供需要释放的指针即可。举例如下: ExFreePool(dst.Buffer); dst.Buffer = NULL; dst.Length = dst.MaximumLength = 0; ExFreePool不能用来释放一个栈空间的指针。否则系统立刻崩溃。像以下的代码: UNICODE_STRING src = RTL_CONST_STRING(L”My source string!”); ExFreePool(src.Buffer); 会招来立刻蓝屏。所以请务必保持ExAllocatePoolWithTag和ExFreePool的成对关系。 |
沙发#
发布于:2008-05-23 08:39
我每篇都要顶!
|
|
板凳#
发布于:2008-05-23 11:10
顶 顶 顶
|
|
地板#
发布于:2008-05-23 14:20
强烈支持!!!!!!!
|
|
地下室#
发布于:2008-05-30 15:12
我收藏了.....
|
|
驱动小牛
|
5楼#
发布于:2008-06-24 17:39
RTL_CONST_STRING不能用,请问楼主需要什么头文件么?
|
6楼#
发布于:2008-06-29 00:17
定顶
|
|
7楼#
发布于:2008-07-02 16:41
基础的东西,就是好,学习
|
|
8楼#
发布于:2011-04-06 23:23
太感谢了 我每篇都收藏
|
|