1.1.6      内核的内存操作

    Windows驱动程序使用的内存资源非常珍贵,分配内存时要尽量节约。和应用程序一样,局部变量是存放在栈( Stack)空间中的。但栈空间不会像应用程序那么大,所以驱动程序不适台递归调用或者局部变量是大型结构体。如果需要大型结构体,请在堆( Heap)中申请。
    堆中申请内存的函数有以下几个,原型如下:
PVOID   
ExAllocatePool(
IN POOL_TYPE  PoolType,
IN SIZE_T  NumberOfBytes
 );
PVOID   
ExAllocatePoolWithTag(
IN POOL_TYPE  PoolType,
IN SIZE_T  NumberOfBytes,
IN ULONG  Tag
 );
PVOID   
ExAllocatePoolWithQuota(
IN POOL_TYPE  PoolType,
IN SIZE_T  NumberOfBytes
 );
PVOID   
ExAllocatePoolWithQuotaTag(
IN POOL_TYPE  PoolType,
IN SIZE_T  NumberOfBytes,
IN ULONG  Tag 
);
参数PooIType是个枚举变量,如果此值为NonPagedPool,则分配非分页内存。如果此值为PagedPool,则分配内存为分页内存。Windows规定有些虚拟内存页面是可以交换到文件中的,这类内存被称为分页内存。而有些虚拟内存页永远不会交换到文件中,这些内存被称为非分页内存。
参数NumbelofBytes是分配内存的大小,注意最好是4的倍数。
函数返回分配的内存地址,一定是内核模式地址。如果返回NULL,则代表分配失败。
    以上四个函数功能类似,函数以WithQuota结尾的代表分配的时候按配额分配。函数以WithTag结尾的函数,和ExAllocatePool功能类似,唯一不同的是多了一个Tag参数,系统在要求的内存外又额外地多分配了4个字节的标签。在调试的时候,可以找出是否有标有这个标签的内存没有被释放。
将分配的内存,进行回收的函数是ExFreePoolExFreePoolWithTag,它们的原型是:
VOID
ExFreePool(
 IN PVOID  P
 );
VOID
ExFreePoolWithTag(
IN PVOID  P,
IN ULONG  Tag
); 
参数P就是要释放的地址。
下面的代码为WinPcap中使用内核内存操作的实例:
PWCHAR getAdaptersList(void)
{
   
    PWCHAR DeviceNames = (PWCHAR) ExAllocatePoolWithTag(PagedPool, BufLen,
 '0PWA');
ExFreePool(DeviceNames);
}
 

1.1.7       内存操作的运行时函数

运行时函数是程序运行时必不可少的,由编译器提供。针对不同的操作系统,运行时函数的实现方法不同,但接口基本保持一致。例如,malloc函数就是典型的运行时函数,所有编译器厂商都必须提供这个函数,但在不同操作系统上的实现方法就不尽相同了。

1.1.7.1     内存间复制(非重叠的情况)

在驱动程序开发中,经常用到内存的复制。DDK为程序员提供了RtlCopyMemory函数。
VOID
RtlCopyMemory(
    IN VOID UNALIGNED  *Destination,
    IN CONST VOID UNALIGNED  *Source,
    IN SIZE_T  Length
);
参数Destination表示要复制内存的目标地址。参数Source表示要复制内存的源地址。参数Length表示要复制的内存的长度,单位是字节。

1.1.7.2    内存间复制(可重叠的情况)

RtICopyMemory可以复制内存,但其内部没有考虑目标内存与源内存重叠的情况。对可重叠的情况DDK提供了RtIMoveMemory函数。
VOID
RtlMoveMemory(
    IN VOID UNALIGNED  *Destination,
    IN CONST VOID UNALIGNED  *Source,
    IN SIZE_T  Length
);
参数Destination表示要复制内存的目标地址。参数Source表示要复制内存的源地址。参数Length表示要复制的内存的长度,单位是字节。

1.1.7.3    填充内存

驱动程序开发中,迹经常用到对某段内存区域用固定字节填充。DDK为程序员提供了RtIFillMemory函数。
VOID
RtlFillMemory(
    IN VOID UNALIGNED  *Destination,
    IN SIZE_T  Length,
    IN UCHAR  Fill
);
参数Destination为目标内存的地址。参数Length为待填的长度。参数Fill为需要填充的字节。
在驱动程序开发中,还经常要对某段内存填零,DDK提供了RtlZeroMemory函数。
VOID
RtlZeroMemory(
           IN VOID UNALIGNED  *Destination,
            IN SIZE_T  Length
    );
参数Destination为目标内存的地址。参数Length为待填的长度。

1.1.7.4   内存比较

驱动程序开发中,还会用到比较两块内存是否一致,可采用RtICompareMemory函数。
SIZE_T
RtlCompareMemory(
    IN CONST VOID  *Source1,
    IN CONST VOID  *Source2,
    IN SIZE_T  Length
);
参数Sourcel为比较的第一个内存地址。参数Sou:rce2为比较的第二个内存地址。参数Length为比较的长度,单位为字节。
函数返回相等的字节数。
函数RtIEquaIMemory通过判断返回值和Length是否相等,来判断两块内存是否完全一致。同时DDK还提供了RtlEqualMemory函数,直接判断两块内存是否一致。
LOGICAL
RtlEqualMemory(
    CONST VOID  *Source1,
    CONST VOID  *Source2,
    SIZE_T  Length
);
函数RtlEquaIMemory在两块内存一致的情况下返回非零值,在不一致的情况下返回零。

本文出自 “千江月” 博客,请务必保留此出处http://eslxf.blog.51cto.com/918801/196914