.net 如何在C#中调用GetVirtualDiskInformation

x759pob2  于 2023-03-20  发布在  .NET
关注(0)|答案(2)|浏览(125)

完整的极简(非工作)代码http://pastebin.com/GPdSxyrt

我正在尝试PInvoke GetVirtualDiskInformation(https://msdn.microsoft.com/en-us/library/windows/desktop/dd323670(v=vs.85).aspx),并将代码设置为:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct GetVirtualDiskInfo
{
    public GetVirtualDiskInfoVersion Version; //GET_VIRTUAL_DISK_INFO_VERSION
    public GetVirtualDiskInfoUnion Union;
}

[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Unicode)]
public struct GetVirtualDiskInfoUnion
{
    [FieldOffset(0)] public GetVirtualDiskInfoSize Size;
    [FieldOffset(0)] public Guid Identifier; //GUID
    [FieldOffset(0)] public GetVirtualDiskInfoParentLocation ParentLocation;
    [FieldOffset(0)] public Guid ParentIdentifier; //GUID
    [FieldOffset(0)] public uint ParentTimestamp; //ULONG
    [FieldOffset(0)] public VirtualStorageType VirtualStorageType; //VIRTUAL_STORAGE_TYPE
    [FieldOffset(0)] public uint ProviderSubtype; //ULONG
    [FieldOffset(0)] public bool Is4kAligned; //BOOL
    [FieldOffset(0)] public bool IsLoaded; //BOOL
    [FieldOffset(0)] public GetVirtualDiskInfoPhysicalDisk PhysicalDisk;
    [FieldOffset(0)] public uint VhdPhysicalSectorSize; //ULONG
    [FieldOffset(0)] public ulong SmallestSafeVirtualSize; //ULONGLONG
    [FieldOffset(0)] public uint FragmentationPercentage; //ULONG
    [FieldOffset(0)] public Guid VirtualDiskId; //GUID
    [FieldOffset(0)] public GetVirtualDiskInfoChangeTrackingState ChangeTrackingState;
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct GetVirtualDiskInfoSize
{
    public ulong VirtualSize; //ULONGLONG
    public ulong PhysicalSize; //ULONGLONG
    public uint BlockSize; //ULONG
    public uint SectorSize; //ULONG
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct GetVirtualDiskInfoParentLocation
{
    public bool ParentResolved; //BOOL
    public char ParentLocationBuffer; //WCHAR[1] //TODO
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct GetVirtualDiskInfoPhysicalDisk
{
    public uint LogicalSectorSize; //ULONG
    public uint PhysicalSectorSize; //ULONG
    public bool IsRemote; //BOOL
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct GetVirtualDiskInfoChangeTrackingState
{
    public bool Enabled; //BOOL
    public bool NewerChanges; //BOOL
    public char MostRecentId; //WCHAR[1] //TODO
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct VirtualStorageType
{
    public VirtualStorageDeviceType DeviceId; //ULONG
    public Guid VendorId; //GUID
}

public enum GetVirtualDiskInfoVersion
{
    Unspecified = 0,
    Size = 1,
    Identifier = 2,
    ParentLocation = 3,
    ParentIdentifier = 4,
    ParentTimestamp = 5,
    VirtualStorageType = 6,
    ProviderSubtype = 7,
    Is4KAligned = 8,
    PhysicalDisk = 9,
    VhdPhysicalSectorSize = 10,
    SmallestSafeVirtualSize = 11,
    Fragmentation = 12,
    IsLoaded = 13,
    VirtualDiskId = 14,
    ChangeTrackingState = 15
}

public enum VirtualStorageDeviceType
{
    Unknown = 0,
    Iso = 1,
    Vhd = 2,
    Vhdx = 3,
    Vhdset = 4
}

[DllImport("virtdisk.dll", CharSet = CharSet.Unicode)]
public static extern uint GetVirtualDiskInformation
(
    [In]            VirtualDiskSafeHandle virtualDiskHandle,
    [In, Out]   ref uint virtualDiskInfoSize,
    [In, Out]   ref GetVirtualDiskInfo virtualDiskInfo,
    [In, Out]   ref uint sizeUsed
);

我调用GetVirtualDiskInformation,如下所示:

var info = new GetVirtualDiskInfo {Version = infoVersion};
infoSize = (uint) Marshal.SizeOf(info);
var result = NativeMethods.GetVirtualDiskInformation(handle, ref infoSize, ref info, ref sizeUsed);

显然,handle在这里确实包含有效的VirtualDiskSafeHandle
问题是我的out结构体完全搞砸了,数据到处都是,根据它,VHD的LogicalSectorSize是257,例如,它有一个负的VirtualSize
我做错了什么?怎样才能让它正常工作?

编辑

以下是一个具体的错误例子:
我创建了一个全新的VHDX作为差分(无父,无源),设置它的最大大小为50MB,LogicalSectorSize为512,PhysicalSectorSize为4096,BlockSize为2MB,它的VendorId(GUID)为new Guid("EC984AEC-A0F9-47e9-901F-71415A66345B")
我希望在表演时:

var info = new GetVirtualDiskInfo {Version = GetVirtualDiskInfoVersion.Size};
infoSize = (uint) Marshal.SizeOf(info);
var result = NativeMethods.GetVirtualDiskInformation(handle, ref infoSize, ref info, ref sizeUsed);

info.Union.Size将返回:

VirtualSize = 52428800
PhysicalSize = 4194304
BlockSize = 2097152
SectorSize = 512

我得到的结果是“足够接近”。除了VirtualSize返回52428801之外,所有值都是正确的。现在,多出的一个字节可能是预期的,但我对此表示怀疑。不管怎样,接下来的两个示例产生了更糟糕的结果:

var info = new GetVirtualDiskInfo {Version = GetVirtualDiskInfoVersion.VirtualStorageType};
infoSize = (uint) Marshal.SizeOf(info);
var result = NativeMethods.GetVirtualDiskInformation(handle, ref infoSize, ref info, ref sizeUsed);

info.Union.VirtualStorageType的预期结果:

DeviceId = 2 //2 Symbolizes VHDX, which is how I created it
VendorId = "EC984AEC-A0F9-47e9-901F-71415A66345B" //As a GUID

实际结果:

DeviceId = 257
VendorId = "EC984AEC-A0F9-47e9-901F-71415A66345B" //As a GUID

换句话说,GUID是好的,DeviceId不是。257甚至不是一个有效值。
最后一个例子:

var info = new GetVirtualDiskInfo {Version = GetVirtualDiskInfoVersion.PhysicalDisk};
infoSize = (uint) Marshal.SizeOf(info);
var result = NativeMethods.GetVirtualDiskInformation(handle, ref infoSize, ref info, ref sizeUsed);

应返回info.Union.PhysicalDisk

LogicalSectorSize = 512
PhysicalSectorSize = 4096
IsRemote = false

实际结果:

LogicalSectorSize  = 257
PhysicalSectorSize = 512
IsRemote = false

所以第一个值又是完全错误的,257不是一个可接受的值,第二个值也是错误的,我认为是4096。

EDIT2已将虚拟存储设备类型添加到初始代码中。
EDIT3完整示例如下:http://pastebin.com/GPdSxyrt
编辑4

我发现问题出在C语言中的WCHAR[1]字段上,如果我注解掉结构体GetVirtualDiskInfoUnion中的ChangeTrackingState,那么一切都很好。
尽管如此,我还是不确定在C#中如何设置它们,从我尝试的Angular 来看,它们似乎既不是char,也不是IntPtr,那么这到底意味着什么呢?

yiytaume

yiytaume1#

我没有解决方案,但注意到如果您添加任何uint字段作为结构中的最后一个,它也可以正常工作。我的定义是:
公共结构获取虚拟磁盘信息联合
{
[字段偏移量(0)]公共获取虚拟磁盘信息大小大小;
[字段偏移量(0)]公共GUID标识符;//用户名
[字段偏移量(0)] public获取虚拟磁盘信息父位置父位置;
[字段偏移量(0)]公共GUID父标识符;//用户名
[字段偏移量(0)]公共uint父时间戳;//乌隆
[字段偏移量(0)]公共虚拟存储类型虚拟存储类型;//虚拟存储类型
[字段偏移量(0)]公共uint提供者子类型;//乌隆
[字段偏移量(0)]公共布尔值是4k对齐;//布尔值
[字段偏移量(0)]公共布尔值已加载;//布尔值
[字段偏移量(0)] public获取虚拟磁盘信息物理磁盘物理磁盘;
[字段偏移量(0)]公共单元VhdPhysicalSectorSize;//乌隆
[字段偏移量(0)]公共ulong最小安全虚拟大小;//乌隆隆
[字段偏移量(0)]公共单元分片百分比;//乌隆
[字段偏移量(0)]公共GUID虚拟磁盘ID;//用户名
[字段偏移量(0)] public获取虚拟磁盘信息更改跟踪状态更改跟踪状态;
[字段偏移量(0)]公共单元保留;//乌隆
}

ruoxqz4g

ruoxqz4g2#

问题是并集从8开始(由于对齐),因此您应该将结构更改为:

[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Unicode)]
public struct GetVirtualDiskInfo
{
    [FieldOffset(0)] public GetVirtualDiskInfoVersion Version; //GET_VIRTUAL_DISK_INFO_VERSION
    [FieldOffset(8)] public GetVirtualDiskInfoUnion Union;
}

作为一种替代方法,您还可以将联合的所有项放入主结构中,所有项都具有[FieldOffset(8)]而不是[FieldOffset(0)]

相关问题