释放 DeviceIoControl 分配的内存

Posted

技术标签:

【中文标题】释放 DeviceIoControl 分配的内存【英文标题】:Free the memory allocated by DeviceIoControl 【发布时间】:2015-02-16 22:30:08 【问题描述】:

当用IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS 调用DeviceIoControl 时,它用指向某些数据(Extents 数组)的指针填充VOLUME_DISK_EXTENTS 结构。虽然在我的代码中创建的结构已被我解除分配,但指针数组似乎令人不安。

我应该释放那段内存吗? 如何释放它?

【问题讨论】:

嗯,不,Extents 数组不包含指针。 【参考方案1】:

唯一涉及的指针是指向缓冲区的指针,该指针传递给DeviceIoControl() 以填充VOLUME_DISK_EXTENTS 结构的内容。 VOLUME_DISK_EXTENTS 内部没有指针,它的 Extents 成员是一个平面结构数组,而不是一个指针数组。这些结构完全包含在您分配的缓冲区中。所以唯一需要释放的是你的缓冲区,没有别的。

【讨论】:

调用 DeviceIoControl 时,lpOutBuffer 应该是指向 VOLUME_DISK_EXTENTS 结构的指针,nOutBufferSize 应该是 sizeof(VOLUME_DISK_EXTENTS @TonyJiang: 你传入一个指向单个VOLUME_DISK_EXTENTS 的指针,但是Extents 被声明为DISK_EXTENT Extents[ANYSIZE_ARRAY] NOT DISK_EXTENT* Extents[ANYSIZE_ARRAY],所以它是一个数组结构,NOT 指向结构的指针数组。文档说:“一个范围是一个磁盘上连续运行的扇区。当返回的范围数大于一 (1) 时,返回错误代码 ERROR_MORE_DATA。您应该再次调用 DeviceIoControl,分配足够的缓冲区空间基于第一次 DeviceIoControl 调用后 NumberOfDiskExtents 的值。" @RemyLebeau 根据我朋友的回答,我已经回答了自己的问题。无论如何感谢您的支持。 因此必须分配足够大的缓冲区以在单个内存块中容纳 X 个扩展区。【参考方案2】:

其实VOLUME_DISK_EXTENTS被定义为存储1个项目。

typedef struct _VOLUME_DISK_EXTENTS 
    DWORD       NumberOfDiskExtents;
    DISK_EXTENT Extents[ANYSIZE_ARRAY]; // ANYSIZE_ARRAY == 1
 VOLUME_DISK_EXTENTS, *PVOLUME_DISK_EXTENTS;

如果我们通过以下方式调用DeviceIoControl

VOLUME_DISK_EXTENTS vde;
ret = DeviceIoControl(
    h, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,
    NULL, 0, &vde, sizeof(vde), &bytesReturned, NULL
);

我们将得到ERROR_MORE_DATA 返回码,因为该结构中没有足够的空间。 Extents 数组的大小定义为 1,如果您尝试访问 1 及以上的元素,您将进入 VOLUME_DISK_EXTENTS 结构之后的缓冲区空间。所以我们真正需要的不是创建一个VOLUME_DISK_EXTENTS,而是一个大小的缓冲区

sizeof(DISK_EXTENT) * (nextents - 1) + sizeof(VOLUME_DISK_EXTENTS)

其中nextents 是我们从上一次调用中获得的VOLUME_DISK_EXTENTS::NumberOfDiskExtents 值。那么我们应该使用

VOLUME_DISK_EXTENTS *ext = (VOLUME_DISK_EXTENTS*) buff;

并使用此结构,假设 Extents 数组具有 nextents 元素。

不需要额外的 API 调用来释放内存。所有被释放的都是一个缓冲区。

【讨论】:

您所描述的在VOLUME_DISK_EXTENTS documentation on MSDN中进行了解释:“一个盘区是一个磁盘上连续运行的扇区。当返回的盘区数大于一(1)时,错误代码返回 ERROR_MORE_DATA。您应该再次调用 DeviceIoControl,在第一次 DeviceIoControl 调用后根据 NumberOfDiskExtents 的值分配足够的缓冲区空间。" 因此,您分配一个VOLUME_DISK_EXTENTS 缓冲区,其初始大小是您选择的(必须是>= sizeof(VOLUME_DISK_EXTENTS)),然后继续重新分配它以增加其大小,直到DeviceIoControl() 停止返回@ 987654340@,然后根据需要处理缓冲区并在完成后释放它。 @RemyLebeau 谢谢。我在 SO 上找到了一个不正确的示例,并且在那之后根本不理解该行。当你看到的只是&vde, sizeof(vde)时,它所讲述的缓冲区是非常违反直觉的。 @RemyLebeau 为什么要编辑 C++ 风格的对 C 风格指针的引用? :) 因为您不能传递对DeviceIoControl() 的引用,也不能通过引用释放缓冲区。分配缓冲区(这意味着您有一个开始的指针),将其转换为引用,然后再次将其转换回指针是没有意义的(没有双关语的意思)。您应该按原样使用指针。但无论哪种方式,使用引用和指针访问结构的成员没有区别,编译的机器代码是相同的。

以上是关于释放 DeviceIoControl 分配的内存的主要内容,如果未能解决你的问题,请参考以下文章

d 对象的动态建立和释放

C++二维数组内存分配

C 语言结构体 ( 结构体中嵌套一级指针 | 分配内存时先 为结构体分配内存 然后再为指针分配内存 | 释放内存时先释放 指针成员内存 然后再释放结构头内存 )

linux采用啥方法实现内存的分配和释放

解析PHP中的内存管理,PHP动态分配和释放内存

在 C++ 中的 2D 动态内存分配数组中释放分配的内存