gpt4 book ai didi

c# - C# StructLayout.Explicit 在 DEVMODE 结构中的对齐错误

转载 作者:太空宇宙 更新时间:2023-11-03 19:47:32 26 4
gpt4 key购买 nike

我正在尝试使用 EnumDisplaySettings,它使用 DEVMODE 结构作为结果结构。 DEVMODE 结构在内部使用了一些联合,这使得它在 C# 中的使用稍微复杂一些。并集用于对显示器或打印机进行编号。 StructLayout.Explicit 中的 FieldOffsets 应该可以使用联合。

下面是从 pinvoke.net 复制的结构。显然,其他一些人也遇到了这种结构的问题,并通过简单地使它们 StructLayout.Sequential 解决了联合问题,并创建了两个结构,一个用于显示,一个用于打印机。

抛出的异常发生在字段偏移量 70 上,这表明该字段未对齐或与另一个字段重叠。这是我不明白的,当然字段可以与使用的显式布局重叠,而且字段偏移 68 之前的字段很短,不能重叠到 fieldoffset 70。这就是 Microsoft 定义的结构的工作方式。当将 fieldoffset 从 70 移动到 72 时,它起作用了

所以我真的不想解决我的问题,但我对这里发生的事情的背景很感兴趣。

[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi)]
public struct DEVMODE3
{
public const int CCHDEVICENAME = 32;
public const int CCHFORMNAME = 32;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCHDEVICENAME)]
[System.Runtime.InteropServices.FieldOffset(0)]
public string dmDeviceName;
[System.Runtime.InteropServices.FieldOffset(32)]
public Int16 dmSpecVersion;
[System.Runtime.InteropServices.FieldOffset(34)]
public Int16 dmDriverVersion;
[System.Runtime.InteropServices.FieldOffset(36)]
public Int16 dmSize;
[System.Runtime.InteropServices.FieldOffset(38)]
public Int16 dmDriverExtra;
[System.Runtime.InteropServices.FieldOffset(40)]
public uint dmFields;

[System.Runtime.InteropServices.FieldOffset(44)]
Int16 dmOrientation;
[System.Runtime.InteropServices.FieldOffset(46)]
Int16 dmPaperSize;
[System.Runtime.InteropServices.FieldOffset(48)]
Int16 dmPaperLength;
[System.Runtime.InteropServices.FieldOffset(50)]
Int16 dmPaperWidth;
[System.Runtime.InteropServices.FieldOffset(52)]
Int16 dmScale;
[System.Runtime.InteropServices.FieldOffset(54)]
Int16 dmCopies;
[System.Runtime.InteropServices.FieldOffset(56)]
Int16 dmDefaultSource;
[System.Runtime.InteropServices.FieldOffset(58)]
Int16 dmPrintQuality;

[System.Runtime.InteropServices.FieldOffset(44)]
public POINTL dmPosition;
[System.Runtime.InteropServices.FieldOffset(52)]
public Int32 dmDisplayOrientation;
[System.Runtime.InteropServices.FieldOffset(56)]
public Int32 dmDisplayFixedOutput;

[System.Runtime.InteropServices.FieldOffset(60)]
public short dmColor; // See note below!
[System.Runtime.InteropServices.FieldOffset(62)]
public short dmDuplex; // See note below!
[System.Runtime.InteropServices.FieldOffset(64)]
public short dmYResolution;
[System.Runtime.InteropServices.FieldOffset(66)]
public short dmTTOption;
[System.Runtime.InteropServices.FieldOffset(68)]
public short dmCollate; // See note below!
[System.Runtime.InteropServices.FieldOffset(70)]
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCHFORMNAME)]
public string dmFormName;
[System.Runtime.InteropServices.FieldOffset(102)]
public Int16 dmLogPixels;
[System.Runtime.InteropServices.FieldOffset(104)]
public Int32 dmBitsPerPel;
[System.Runtime.InteropServices.FieldOffset(108)]
public Int32 dmPelsWidth;
[System.Runtime.InteropServices.FieldOffset(112)]
public Int32 dmPelsHeight;
[System.Runtime.InteropServices.FieldOffset(116)]
public Int32 dmDisplayFlags;
[System.Runtime.InteropServices.FieldOffset(116)]
public Int32 dmNup;
[System.Runtime.InteropServices.FieldOffset(120)]
public Int32 dmDisplayFrequency;
}

最佳答案

70 是正确的偏移量。对于 CharSet = CharSet.Auto,它是 102,您应该始终喜欢它。

问题在于代码不必要地使用了 [FieldOffset]。这不仅会在编码结构中设置字段的偏移量,还会降低托管结构中字段的偏移量。

这是个大问题,70 无效,因为它在内存中未对齐字符串。 .NET 内存模型要求在 32 位模式下,引用类型引用需要对齐到 4 的倍数的地址。垃圾收集器非常讨厌未对齐的字段,对象引用需要能够自动更新和未对齐引用文献不能保证。它们可能跨越 L1 高速缓存线,这需要两个内存总线周期来设置值。导致撕裂,只能看到更新的一部分,这是一个无法调试的问题。

删除所有 [FieldOffset] 属性或从 Reference Source 复制/粘贴.另一个优点是,如果您的程序在 64 位模式下运行,您会感觉它仍然可以正常工作。

关于c# - C# StructLayout.Explicit 在 DEVMODE 结构中的对齐错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43546187/

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