Marshal.PtrToStructure() 和结构 DEVMODE 中的字符数组出现问题

2024-06-28

我在使用 Marshal.PtrToStructure() 从指向 DEVMODE 类型结构的指针中提取数据时遇到问题。Here http://msdn.microsoft.com/en-us/library/dd183565%28v=vs.85%29.aspx是指向 DEVMODE 结构上的 MSDN 条目的链接。

我对该结构的 C# 实现如下:

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

    public unsafe fixed char dmDeviceName [CCHDEVICENAME];
    public Int16 dmSpecVersion;
    public Int16 dmDriverVersion;
    public Int16 dmSize;
    public Int16 dmDriverExtra;
    public DM_FIELD_TYPE dmFields;

    public Int16 dmOrientation;
    public Int16 dmPaperSize;
    public Int16 dmPaperLength;
    public Int16 dmPaperWidth;
    public Int16 dmScale;
    public Int16 dmCopies;
    public Int16 dmDefaultSource;
    public Int16 dmPrintQuality;

    public POINTL dmPosition;
    public Int32 dmDisplayOrientation;
    public Int32 dmDisplayFixedOutput;

    public short dmColor;
    public short dmDuplex;
    public short dmYResolution;
    public short dmTTOption;
    public short dmCollate;

    public unsafe fixed char dmFormName [CCHFORMNAME];
    public Int16 dmLogPixels;
    public Int32 dmBitsPerPel;
    public Int32 dmPelsWidth;
    public Int32 dmPelsHeight;
    public Int32 dmDisplayFlags;
    public Int32 dmNup;
    public Int32 dmDisplayFrequency;
    public Int32 dmICMMethod;
    public Int32 dmICMIntent;
    public Int32 dmMediaType;
    public Int32 dmDitherType;
    public Int32 dmReserved1;
    public Int32 dmReserved2;
    public Int32 dmPanningWidth;
    public Int32 dmPanningHeight;

    public DEVMODE(byte[] data)
    {
        unsafe
        {
            fixed (byte* packet = &data[0])
            {
                this = *(DEVMODE*)packet;
            }
        }
    }

}

[Flags()]
public enum DM_FIELD_TYPE : int
{
    /* field selection bits */
    DM_ORIENTATION          = 0x00000001,
    DM_PAPERSIZE            = 0x00000002,
    DM_PAPERLENGTH          = 0x00000004,
    DM_PAPERWIDTH           = 0x00000008,
    DM_SCALE                = 0x00000010,
    DM_POSITION             = 0x00000020,
    DM_NUP                  = 0x00000040,
    DM_DISPLAYORIENTATION   = 0x00000080,
    DM_COPIES               = 0x00000100,
    DM_DEFAULTSOURCE        = 0x00000200,
    DM_PRINTQUALITY         = 0x00000400,
    DM_COLOR                = 0x00000800,
    DM_DUPLEX               = 0x00001000,
    DM_YRESOLUTION          = 0x00002000,
    DM_TTOPTION             = 0x00004000,
    DM_COLLATE              = 0x00008000,
    DM_FORMNAME             = 0x00010000,
    DM_LOGPIXELS            = 0x00020000,
    DM_BITSPERPEL           = 0x00040000,
    DM_PELSWIDTH            = 0x00080000,
    DM_PELSHEIGHT           = 0x00100000,
    DM_DISPLAYFLAGS         = 0x00200000,
    DM_DISPLAYFREQUENCY     = 0x00400000,
    DM_ICMMETHOD            = 0x00800000,
    DM_ICMINTENT            = 0x01000000,
    DM_MEDIATYPE            = 0x02000000,
    DM_DITHERTYPE           = 0x04000000,
    DM_PANNINGWIDTH         = 0x08000000,
    DM_PANNINGHEIGHT        = 0x10000000,
    DM_DISPLAYFIXEDOUTPUT   = 0x20000000
}

public struct POINTL
{
    public Int32 x;
    public Int32 y;
}

在此结构中,有 2 个字符数组“dmDeviceName”和“dmFormName”。两者都是 32 个字符长。问题是,当我尝试从指针编组结构 DEVMODE 时,这些字符数组没有被正确填充。例如,dmDeviceName 将仅包含实际设备名称的第一个字符。数组的其余条目将只是“\0”。我正在执行封送处理的代码行如下:

DEVMODE devMode = (DEVMODE)Marshal.PtrToStructure(aData[i].NotifyData.Data.pBuf, typeof(DEVMODE));

“aData[i].NotifyData.Data.pBuf”是指向 DEVMODE 类型结构的有效指针。我知道这一点有两个原因。

  1. 此结构是从名为 FindNextPrinterChangeNotification() 的打印机驱动程序调用返回的信息的子集。我使用它来捕获打印作业信息,当我捕获打印作业并使用上面的代码封送 DEVMODE 对象时,“dmCopies”字段始终与该作业中打印的份数完全正确。因此,结构中的第 12 个成员如何正确编组,而它之前的一些成员似乎没有正确编组,这有点奇怪。

  2. 我使用 Marshal.ReadByte() 强制读取 aData[i].NotifyData.Data.pBuf 指向的前 100 个字节,果然,第一个字节集合是打印机设备的完整名称。所以我知道信息就在那里。

无论出于何种原因,当我使用 Marshal.PtrToStructure() 时,它似乎无法正确填充字符数组。我很确定大多数其他变量都是正确的,但由于数组问题,我有疑问。有谁知道这里发生了什么事。

- 编辑 - 根据要求,以下是填充 aData[] 数组的代码:

private PRINTER_NOTIFY_INFO_DATA[] MarshalOutPrinterNotifyInfoDataArray(IntPtr ppPrinterNotifyInfo)
{
    //Dereferencing ppPrinterNotifyInfo and setting NotifyInfoStruct to it.
    PRINTER_NOTIFY_INFO NotifyInfoStruct = (PRINTER_NOTIFY_INFO)Marshal.PtrToStructure(ppPrinterNotifyInfo, typeof(PRINTER_NOTIFY_INFO));

    //Creating a point to point to the PRINTER_NOTIFY_INFO and then moving it to the end of the structure where the
    //aData[] member would begin.
    int paData = (int)ppPrinterNotifyInfo + Marshal.SizeOf(typeof(PRINTER_NOTIFY_INFO));

    //Creating an array to hold all the elements of our aData array.
    PRINTER_NOTIFY_INFO_DATA[] data = new PRINTER_NOTIFY_INFO_DATA[NotifyInfoStruct.Count];

    //looping through all the PRINTER_NOTIFY_INFO_DATA elments in the aData member and adding them to our local array.
    for (uint i = 0; i < NotifyInfoStruct.Count; i++)
    {
        //extracting out a single PRINTER_NOTIFY_INFO_DATA item and storing it in our local array
        data[i] = (PRINTER_NOTIFY_INFO_DATA)Marshal.PtrToStructure((IntPtr)paData, typeof(PRINTER_NOTIFY_INFO_DATA));

        //moving our pointer to the next PRINTER_NOTIFY_INFO_DATA item
        paData += Marshal.SizeOf(typeof(PRINTER_NOTIFY_INFO_DATA));
    }

    return data;
}



private void SomeRoutine()
{
    //////////////////
    /// some code here
    //////////////////

    //retrieving information about the most recent change notification for a change notification object associated with the printer
    FindNextPrinterChangeNotification(m_ManualResetEvent.SafeWaitHandle.DangerousGetHandle(), out pdwChangeFlags, null, out ppPrinterNotifyInfo);

    //Need to extract our PRINTER_NOTIFY_INFO_DATA array out of the PRINTER_NOTIFY_INFO structure
    PRINTER_NOTIFY_INFO_DATA[] aData = MarshalOutPrinterNotifyInfoDataArray(ppPrinterNotifyInfo);

    //////////////////
    /// some code here
    //////////////////
}

使用字符串:

[MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCHDEVICENAME)]
public string dmDeviceName;

See: http://pinvoke.net/default.aspx/Structures/DEVMODE.html http://pinvoke.net/default.aspx/Structures/DEVMODE.html

EDIT:我在发布快速回复时没有注意到,因为我专注于字符串(并且结构的最开始有一个字符串,这意味着其余的结构元素不会影响事物),但正如其他人指出的那样DEVMODE 结构中的联合有一个大问题。联合中的元素不是按顺序排列的,而是在内存中占据相同的空间:一次只能使用其中一个联合元素。例如:

union {
    DWORD dmDisplayFlags;
    DWORD dmNup;
};

意味着 dmDisplayFlags 和 dmNup 本质上是同一内存块的不同名称。 IE。 dmDisplayFlags 和 dmNup 都存储在距结构开头 116 字节的偏移处。更改 dmNup 会导致 dmDisplayFlags 的值也发生更改,反之亦然。使用 C# 代码,例如:

public Int32 dmDisplayFlags;
public Int32 dmNup;

意味着它们按顺序存储,即在偏移量 116 和 120 处。这会打乱整个结构的布局。要解决这个问题,您需要使用显式布局并手动定义字段偏移量。请查看我之前在 pinvoke.net 上提供的链接,了解如何在此特定结构上执行此操作的示例。注意 dmDisplayFlags 和 dmNup 如何具有same场偏移。由于 C# 本身不支持联合,因此对于像这样需要它的特殊互操作场景,这是一种处理联合的有点笨拙的方法。

我建议修复您的联合问题,然后按照最初的建议使用带有 ByValTStr 的字符串(总之,使用 pinvoke.net 上的内容)。看看它是否会给你带来更好的结果。

其他人认为这是 Unicode 问题,但我认为事实并非如此。文档说 FindNextPrinterChangeNotification 在 Unicode 中不可用。如果您检查了字节级别的结构并说它不是 Unicode - 我绝对相信您。

来自文档:

"由ValTStr:用于出现在结构中的内联固定长度字符数组。 ByValTStr 使用的字符类型由应用于包含结构的 System.Runtime.InteropServices.StructLayoutAttribute 的 System.Runtime.InteropServices.CharSet 参数确定。始终使用 MarshalAsAttribute.SizeConst 字段来指示数组的大小。

.NET Framework ByValTStr 类型的行为类似于结构内的 C 风格固定大小字符串(例如 char s[5])。托管代码中的行为与 Microsoft Visual Basic 6.0 行为不同,后者不是以 null 终止的(例如,MyString As String * 5)。

对我来说,这似乎很清楚,这应该是普遍接受的“正确”方法。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Marshal.PtrToStructure() 和结构 DEVMODE 中的字符数组出现问题 的相关文章

  • pop() 期间提升 Fibonacci 堆访问冲突

    Context 我目前正在实现某种形式的 A 算法 我决定使用 boost 的斐波那契堆作为底层优先级队列 我的图表是在算法运行时构建的 作为我使用的顶点对象 class Vertex public Vertex double double
  • 如何在 Multiline 属性设置为 true 的文本框中将空格替换为换行符?

    假设我有这个字符串 string str The quick brown fox jumps over the lazy dog 如何替换或忽略字符串中的空格并在多行文本框中输入每个单词 预期输出 The quick brown fox j
  • 错误:调用 Configuration.BuildSessionFactory() 时“无法同时获取多个包”;

    升级到 NHibernate 2 1 后 我们收到此错误 QueryException Cannot simultaneously fetch multiple bags NHibernate Loader BasicLoader Post
  • 如何向 Iron Python 添加模块?

    我一直在尝试使用 C Visual Studio 执行以下 Python 代码 graphcreater py 我通过 NuGet 包管理器添加了 IronPyton 2 7 7 和 IronPython StdLib 2 7 7 一旦我运
  • C++ 局部变量销毁顺序

    C 11 中是否存在局部变量释放的定义顺序 更简洁地说 同一作用域中两个局部变量的析构函数的副作用将以什么顺序变得可见 e g struct X X do something int main X x1 X x2 return 0 Is x
  • main() 是用户定义函数吗? [复制]

    这个问题在这里已经有答案了 程序员does定义内部发生的事情main 毕竟 那么 它应该被视为用户定义的函数吗 C 标准没有用户定义函数的概念 相反 它有一个概念库函数 main 不是库函数 但是 该标准还对其签名提出了一些要求 并且不得重
  • 创建一个从用户机密获取连接字符串的 DbContextFactory

    使用 DotNetCore 解决方案WebApi项目和一个单独的Data包含实体框架实现的项目 我们一直在升级库 因此我们使用所有最新的核心内容 In the Data项目 我们创建了一个ApplicationDbContextFactor
  • 处理可选依赖项 (C#)

    我们有一个可以选择与 TFS 集成的应用程序 但是由于集成是可选的 所以我显然不希望所有机器都需要 TFS 程序集作为要求 我应该怎么办 我是否可以在主程序集中引用 TFS 库 并确保在使用 TFS 集成时仅引用 TFS 相关对象 或者 更
  • 如何重命名 MacOS/X 程序中的程序名称菜单标签?

    我有一个在 MacOS X 下运行的基于 Qt 的 GUI 程序 我希望能够更改该程序的第一个菜单标题的标签 即此屏幕截图中用红色圈出的标签 有没有一种编程方法可以做到这一点 假设不存在基于 Qt 的解决方案 则 Objective C 本
  • “#include ”导致“错误:asm/io.h:没有这样的文件或目录”

    我正在使用 gentoo 并尝试编译一个程序来控制并行端口上的位 它的顶部附近有这一行 include
  • WCF:通用接口的序列化可能吗?

    我正在尝试实现一个服务契约 其中包含一个采用通用接口的方法 并且该通用接口本身被赋予一个接口参数 我用 ServiceKnownType 装饰了服务接口 用常规 KnownType 装饰了服务实现 并用常规 KnownType 装饰了数据契
  • 开始学习 C# 的最佳方式是什么?

    我对 vb 6 有一点编程经验 而 vb net 则不多 请告诉我成为专家 C 程序员的最佳方法 我知道这需要很长时间 想想你如何学习人类语言 阅读 写作 口语和听力 阅读代码 阅读文章 阅读示例 当您更有经验时 请查看您使用的一些项目的源
  • Linux 相当于 GetCommandLine 和 CommandLineToArgv?

    我想知道是否有一些 API 可以在 Linux 上获取当前进程的命令行参数 我想我是非常不清楚的 该问题的真正目的是通过命令行参数传递 unicode 文件名 从文件中读取 proc self cmdline 例如 wallyk zf od
  • 像 MS Excel 一样在 C++ 中舍入双精度值

    我在网上进行了搜索 但找不到解决我的问题的方法 我只是想要一个像 MS Excel 那样对双精度值进行舍入的函数 这是我的代码 include
  • 检测非 DPI 感知应用程序是否已扩展/虚拟化

    我正在尝试在 WinForms 应用程序中检测它是否由于操作系统具有高 DPI 而以缩放 虚拟化模式启动 目前 在以 3840x2400 缩放 200 缩放运行的系统中 应用程序将分辨率视为 1920x1200 DPI 为 96 缩放因子为
  • Microsoft Build Tools 2013 缺少 v120 目录

    我们已经安装了 Microsoft Build Tools 2013 从http www microsoft com en us download details aspx id 40760 http www microsoft com e
  • 如何在 JSON 输出上强制采用 ISO 格式“YYYY-MM-DDThh:mm:ss.sss”?

    我有一个 ASP NET WebApi2 api 它返回一些 JSON 格式的时间戳 时间戳具有毫秒分辨率 通常我会得到这种格式的时间戳 这很好 YYYY MM DDThh mm ss sss 不幸的是 如果时间戳恰好用整秒对日期进行编码
  • C# 固定长度的字符串对象

    我有一堂课 我想使用固定大小的字符串 固定大小的原因是该类 序列化 为文本文件 具有固定长度的值 我想避免为每个值编写一个保护子句 而是让类处理它 所以我有大约 30 个属性 看起来像这样 public String CompanyNumb
  • C++ 中的 golang 风格“延迟”[重复]

    这个问题在这里已经有答案了 我正在阅读有关 go 语言的defer http blog golang org defer panic and recover陈述 它允许您指定函数结束时要执行的操作 例如 如果您有一个文件指针或资源 则只需指
  • 使用 CRTP 模式时继承中的不明确方法

    我正在定义一个DoubleWrapper类继承自两个 CRTP 基类 Ratioable and Divable 两者都定义operator 具有不同的签名 T operator double const scalar const retu

随机推荐

  • PrimeFaces 3.0.M3 单元编辑器不更新值

    我读过了there https stackoverflow com questions 6365877 cell edit in primefaces is not updating the value 6487361 6487361 但我
  • div 宽度,单位:厘米(英寸)

    我需要在每个显示器中放入宽度为 25 厘米 10 英寸 的站点 div 我怎样才能做到呢 您可以简单地使用cmCSS 中的单位 mydiv width 25cm 请注意 正如其他人指出的那样 结果仍然取决于操作系统对显示器尺寸的正确读取 S
  • 剥掉所有的身体标签而不毁掉他们的孩子

    此 Ruby 代码使用Nokogiri http nokogiri org doc xpath tbody remove 删除 的子项 tbody 以及 tbody 他们自己 我只想删除所有 tbody 文档中的标签 将其子项留在原处 我怎
  • HTML输入日期,如何减少日期和图标之间的间距?

    我需要压缩输入类型日期 所以我尝试将宽度设置为 120px 问题是有一个space日期数字和输入日期图标之间 我需要减少或删除该空间 有没有办法做到这一点 我的代码 顺便说一句 我正在使用 bootstrap 4
  • 你可以在 Android 中有意打开多个文件吗?

    我正在尝试在 Android Studio 中编写一个应用程序来打开多个音乐文件并存储它们的路径 目前我所做的只是一次加载一个文件 这不会出现任何问题 例如 下面的代码显示了我的加载按钮的 onclicklister 和相关代码 本示例的一
  • Java字符串对象的创建

    我一直在阅读 Java String 对象 并且有这个问题 String x a String y b 它在Java中创建两个对象吗 这两行代码不会创建任何对象 字符串文字 例如 a 被放入字符串池 https stackoverflow
  • enableHiveSupport 在 java Spark 代码中引发错误[重复]

    这个问题在这里已经有答案了 我有一个非常简单的应用程序 尝试使用 Spark 从 src main resources 读取 orc 文件 我不断收到此错误 无法实例化具有 Hive 支持的 SparkSession 因为找不到 Hive
  • 通过绑定启用 TabItem

    我想在不同页面是 TabItem 的应用程序中使用 MVVM 为此 我使用视图模型 项目 的可观察集合并将其绑定到选项卡控件 ItemSource 对于每个视图模型 我创建了一个单独的数据模板来呈现正确的视图 如下所示
  • 如何用惰性传播实现线段树?

    我在互联网上搜索了有关线段树的实现的信息 但在惰性传播方面却一无所获 之前有一些关于堆栈溢出的问题 但它们专注于解决 SPOJ 的一些特定问题 虽然我认为这是用伪代码对线段树的最好解释 但我需要用惰性传播来实现它 我发现以下链接 除了上面的
  • 用于 GNU C++ 的 SSE SSE2 和 SSE3 [关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 有没有一个简单的教程可以帮助我快速掌握 GNU C 中的 SSE SSE2 和 SSE3 如何在SSE中
  • 使用 Mathematica 在定义位置的左侧或右侧“StringCut”

    论读书这个问题 https stackoverflow com q 6052211 499167 我认为使用下面的问题会很简单StringSplit 给定以下字符串 我想将其 剪切 到每个 D 的左侧 以便 I get a List片段数
  • Google AppEngine Python 3.7 上的自定义库

    我正在尝试在 Google AppEngine Python 3 7 标准环境上部署一项服务 该环境需要一组库作为依赖项 无法部署依赖项之一 GDAL 2 2 2 并返回错误消息 File upload done Updating serv
  • 调用异步方法和 Task.Run 异步方法之间的区别

    我的视图模型中有一个方法 private async void SyncData SyncMessage syncMessage if syncMessage State SyncState SyncContacts this SyncCo
  • Django:如何从模型中验证 unique_together

    我有以下内容 class AccountAdmin models Model account models ForeignKey Account is master models BooleanField name models CharF
  • 如何从不同的进程关闭窗口

    我有一个 C 应用程序 我想指示它从不同的进程中很好地关闭 我还希望能够要求它打开主窗口 我有一个对其主窗口句柄的引用 我知道我可以使用远程处理或 WCF 等复杂的方案来做到这一点 问题是我可以使用更简单的机制 例如窗口消息 或 c 应用程
  • .htaccess RewriteRule 中的单个点有什么作用?

    使用 Wordpress 作为 CMS htaccess 文件如下所示 RewriteEngine On 1 ok enables engine RewriteBase blog 2 sets blog directory as base
  • 我可以添加编译时检查以确保这是合法的处理程序函数吗? (受限通用)

    查看评论 我希望第二个 MapPost 调用在编译时失败 我只是在尝试使用 asp net 最小管道 我认为这需要受限泛型 但我是 C 新手 所以认为有人可以快速回答这个问题 希望如此 var router new ExampleRoute
  • 我可以使用独立签名作为 Perl 6 中的签名吗?

    我正在尝试使用 Perl 6 实现一个命令行程序 该程序需要进行多次切换 签名至MAIN非常复杂而且有点混乱 我想知道是否有一种方法可以在其他地方定义签名并告诉子例程使用什么 possibly big and messy signature
  • AWS S3 保存和加载项目需要多长时间?

    S3 常见问题解答提到 所有区域中的 Amazon S3 存储桶为新对象的 PUTS 提供写后读一致性 并为覆盖 PUTS 和 DELETES 提供最终一致性 但是 我不知道需要多长时间才能获得最终一致性 我尝试搜索此内容 但在 S3 文档
  • Marshal.PtrToStructure() 和结构 DEVMODE 中的字符数组出现问题

    我在使用 Marshal PtrToStructure 从指向 DEVMODE 类型结构的指针中提取数据时遇到问题 Here http msdn microsoft com en us library dd183565 28v vs 85