首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >DEVMODE结构中C# StructLayout.Explicit的对准误差

DEVMODE结构中C# StructLayout.Explicit的对准误差
EN

Stack Overflow用户
提问于 2017-04-21 15:09:53
回答 1查看 896关注 0票数 1

我正在尝试使用EnumDisplaySettings,它使用DEVMODE结构作为结果结构。DEVMODE结构在内部使用几个联合,这使得它在C#中的使用更加复杂。联合用于计算显示器或打印机。StructLayout.Explicit中的FieldOffsets应该可以使用联合。

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

抛出的异常发生在字段偏移量70上,这表明字段不是没有对齐,就是被另一个字段重叠。这就是我不明白的,当然,字段可以与使用的显式布局重叠,而且在字段偏移68处的字段是短的,不能重叠到场域70。这就是Microsoft定义的结构的工作方式。当运动场从70移到72时,它可以工作。

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

代码语言:javascript
复制
[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;
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-04-21 15:49:31

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

问题是代码不必要地使用了FieldOffset。这不仅设置了封送结构中字段的偏移量,而且还降低了托管结构中字段的偏移量。

这是一个大问题,70是无效的,因为这错误地对齐了内存中的字符串。.NET内存模型要求,在32位模式下,引用类型引用需要对齐到4倍的地址。垃圾收集器确实讨厌对齐字段,对象引用需要原子更新,而对错对齐的引用不能有这种保证。它们可以跨L1缓存行,这需要两个内存总线周期来设置值。导致撕裂,只看到更新的一部分,这是一个无法调试的问题。

删除所有FieldOffset属性或从参考源复制/粘贴。另一个优势是,如果你的程序以64位模式运行,你会觉得它还能正常工作。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/43546187

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档