释放 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 时,lpOutBuffe
r 应该是指向 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 分配的内存的主要内容,如果未能解决你的问题,请参考以下文章
C 语言结构体 ( 结构体中嵌套一级指针 | 分配内存时先 为结构体分配内存 然后再为指针分配内存 | 释放内存时先释放 指针成员内存 然后再释放结构头内存 )