gpt4 book ai didi

c# - 带有 IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS 的 DeviceIoControl - C#

转载 作者:行者123 更新时间:2023-11-30 16:48:52 27 4
gpt4 key购买 nike

我的 C++ 代码使用 IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS 调用 DeviceIoControl,我需要将其转换为 C#。
我发现了许多 DeviceIoControl p\invoke 示例,但没有针对此特定标志的示例。我试过使用以下 extern:

[DllImport("kernel32", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool DeviceIoControl(SafeFileHandle hVol, int controlCode, IntPtr inBuffer, int inBufferSize, ref DiskExtents outBuffer, int outBufferSize, ref int bytesReturned, IntPtr overlapped);

结构:

[StructLayout(LayoutKind.Sequential)]
public struct DiskExtent
{
public uint DiskNumber;
public long StartingOffset;
public long ExtentLength;
}

[StructLayout(LayoutKind.Sequential)]
public struct DiskExtents
{
public int numberOfExtents;
public DiskExtent[] first;
}

以及以下调用代码:

int bytesReturned = 0;
DiskExtents diskExtents = new DiskExtents();
bool res = DeviceIoControl(hVol, 5636096, IntPtr.Zero, 0, ref diskExtents, Marshal.SizeOf(diskExtents), ref bytesReturned, IntPtr.Zero);

但调用返回 false,数据结构始终为空。任何帮助都会很棒!

最佳答案

您的代码的问题在于,除非数组的大小已知,否则无法编码数组。这意味着在进行 DeviceIoControl 调用时,您的 DiskExtents 结构无法正确编码。

以下代码适用于我(出于互操作目的,我更喜欢明确大小的类型,并且更喜欢坚持使用 Win32 header 中的名称,因为我已经知道它们的含义并且可以轻松地通过 Google 搜索它们):

internal static class NativeMethods
{
internal const UInt32 IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS = 0x00560000;

[StructLayout(LayoutKind.Sequential)]
internal class DISK_EXTENT
{
public UInt32 DiskNumber;
public Int64 StartingOffset;
public Int64 ExtentLength;
}

[StructLayout(LayoutKind.Sequential)]
internal class VOLUME_DISK_EXTENTS
{
public UInt32 NumberOfDiskExtents;
public DISK_EXTENT Extents;
}

[DllImport("kernel32", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool DeviceIoControl(SafeFileHandle hDevice,
UInt32 ioControlCode,
IntPtr inBuffer,
UInt32 inBufferSize,
IntPtr outBuffer,
UInt32 outBufferSize,
out UInt32 bytesReturned,
IntPtr overlapped);
}
class Program
{
static void Main(string[] args)
{
// Open the volume handle using CreateFile()
SafeFileHandle sfh = ...

// Prepare to obtain disk extents.
// NOTE: This code assumes you only have one disk!
NativeMethods.VOLUME_DISK_EXTENTS vde = new NativeMethods.VOLUME_DISK_EXTENTS();
UInt32 outBufferSize = (UInt32)Marshal.SizeOf(vde);
IntPtr outBuffer = Marshal.AllocHGlobal((int)outBufferSize);
UInt32 bytesReturned = 0;
if (NativeMethods.DeviceIoControl(sfh,
NativeMethods.IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,
IntPtr.Zero,
0,
outBuffer,
outBufferSize,
out bytesReturned,
IntPtr.Zero))
{
// The call succeeded, so marshal the data back to a
// form usable from managed code.
Marshal.PtrToStructure(outBuffer, vde);

// Do something with vde.Extents here...e.g.
Console.WriteLine("DiskNumber: {0}\nStartingOffset: {1}\nExtentLength: {2}",
vde.Extents.DiskNumber,
vde.Extents.StartingOffset,
vde.Extents.ExtentLength);
}
Marshal.FreeHGlobal(outBuffer);
}
}

当然,这假设您只需要获取有关单个磁盘的信息。如果您需要 DeviceIoControl 函数将有关多个 磁盘的信息填充到VOLUME_DISK_EXTENTS 结构中,您将不得不更加努力。

问题是直到运行时你才能知道究竟有多少磁盘。 DeviceIoControl 将返回 ERROR_MORE_DATA 以通知您表中还有更多信息,您需要使用更大的缓冲区再次调用。您将按照与上面相同的方式执行此操作,但会出现一些额外的复杂情况。您将需要使用类似 Marshal.ReAllocHGlobal 的东西来扩展缓冲区的大小以容纳额外的 DISK_EXTENT 结构。在第一次调用 DeviceIoControl 失败后,所需的数字将在 VOLUME_DISK_EXTENTS.NumberOfDiskExtents 成员中返回。 This C# code显示了类似的实现。

花时间编写像这样令人讨厌的代码是我基本上放弃使用 C# 开发 Windows 应用程序的原因。它造成了一个不可避免的悖论,即 C++ 本来应该更简洁、更优雅、更易于编写并且不易出错。 (你确定我没有在上面的代码中泄露任何句柄吗?我不是。)

关于c# - 带有 IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS 的 DeviceIoControl - C#,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37532548/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com