完整的极简(非工作)代码: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
,那么这到底意味着什么呢?
2条答案
按热度按时间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)]公共单元保留;//乌隆
}
ruoxqz4g2#
问题是并集从8开始(由于对齐),因此您应该将结构更改为:
作为一种替代方法,您还可以将联合的所有项放入主结构中,所有项都具有
[FieldOffset(8)]
而不是[FieldOffset(0)]