草庐IT

c# - EnumJobs 返回与 Marshal.SizeOF 不同的 JOB_INFO_1 大小

coder 2024-06-16 原文

我正在从托管代码 (C#) 调用 Win32 函数 EnumJobs ( http://msdn.microsoft.com/en-us/library/windows/desktop/dd162625(v=vs.85).aspx )。

    [DllImport("Winspool.drv", SetLastError = true, EntryPoint = "EnumJobsA")]
    public static extern bool EnumJobs(
       IntPtr hPrinter,                    // handle to printer object
       UInt32 FirstJob,                // index of first job
       UInt32 NoJobs,                // number of jobs to enumerate
       UInt32 Level,                    // information level
       IntPtr pJob,                        // job information buffer
       UInt32 cbBuf,                    // size of job information buffer
       out UInt32 pcbNeeded,    // bytes received or required
       out UInt32 pcReturned    // number of jobs received
    );

EnumJobs(_printerHandle, 0, 99, 1, IntPtr.Zero, 0, out nBytesNeeded, out pcReturned);

我指定级别 1 接收 JOB_INFO_1 但我遇到的问题是上面的函数返回 nBytesNeeded 作为每个结构 240 而 Marshal.SizeOf(typeof(JOB_INFO_1)) 是当我运行 Marshal.PtrToStructure 时,64 字节导致内存异常。手动计算结构的字节数为 64,所以我有点不知所措,为什么我从函数中接收到 240 字节的结构,任何见解都将不胜感激。

[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet=CharSet.Unicode)]
public struct JOB_INFO_1
{
    public UInt32 JobId;
    public string pPrinterName;
    public string pMachineName;
    public string pUserName;
    public string pDocument;
    public string pDatatype;
    public string pStatus;
    public UInt32 Status;
    public UInt32 Priority;
    public UInt32 Position;
    public UInt32 TotalPages;
    public UInt32 PagesPrinted;
    public SYSTEMTIME Submitted;
}

最佳答案

64 的大小对于 JOB_INFO_1 确实是正确的,但如果您仔细查看文档,它会讨论一个结构数组:

pJob [out]
A pointer to a buffer that receives an array of JOB_INFO_1, JOB_INFO_2, or JOB_INFO_3 structures.

另外它是这样写的:

缓冲区必须足够大以接收结构数组以及结构成员指向的任何字符串或其他数据。

所以除了结构本身之外,这里还有用于额外数据的字节。

解决方案:

填充结构,增加下一个结构的指针并忽略剩余字节。

完整示例:

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows;

namespace WpfApplication3
{
    public partial class MainWindow
    {
        public MainWindow()
        {
            InitializeComponent();
            Loaded += MainWindow_Loaded;
        }

        private void MainWindow_Loaded(object sender, RoutedEventArgs e)
        {
            // Get handle to a printer
            var hPrinter = new IntPtr();
            bool open = NativeMethods.OpenPrinterW("Microsoft XPS Document Writer", ref hPrinter, IntPtr.Zero);
            Debug.Assert(open);

            /* Query for 99 jobs */
            const uint firstJob = 0u;
            const uint noJobs = 99u;
            const uint level = 1u;

            // Get byte size required for the function
            uint needed;
            uint returned;
            bool b1 = NativeMethods.EnumJobsW(
                hPrinter, firstJob, noJobs, level, IntPtr.Zero, 0, out needed, out returned);
            Debug.Assert(!b1);
            uint lastError = NativeMethods.GetLastError();
            Debug.Assert(lastError == NativeConstants.ERROR_INSUFFICIENT_BUFFER);

            // Populate the structs
            IntPtr pJob = Marshal.AllocHGlobal((int) needed);
            uint bytesCopied;
            uint structsCopied;
            bool b2 = NativeMethods.EnumJobsW(
                hPrinter, firstJob, noJobs, level, pJob, needed, out bytesCopied, out structsCopied);
            Debug.Assert(b2);

            var jobInfos = new JOB_INFO_1W[structsCopied];
            int sizeOf = Marshal.SizeOf(typeof (JOB_INFO_1W));
            IntPtr pStruct = pJob;
            for (int i = 0; i < structsCopied; i++)
            {
                var jobInfo_1W = (JOB_INFO_1W) Marshal.PtrToStructure(pStruct, typeof (JOB_INFO_1W));
                jobInfos[i] = jobInfo_1W;
                pStruct += sizeOf;
            }
            Marshal.FreeHGlobal(pJob);

            // do something with your structs
        }
    }

    public class NativeConstants
    {
        public const int ERROR_INSUFFICIENT_BUFFER = 122;
    }

    public partial class NativeMethods
    {
        [DllImport("kernel32.dll", EntryPoint = "GetLastError")]
        public static extern uint GetLastError();
    }

    public partial class NativeMethods
    {
        [DllImport("Winspool.drv", EntryPoint = "OpenPrinterW")]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool OpenPrinterW([In] [MarshalAs(UnmanagedType.LPWStr)] string pPrinterName,
            ref IntPtr phPrinter, [In] IntPtr pDefault);

        [DllImport("Winspool.drv", EntryPoint = "EnumJobsW")]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool EnumJobsW([In] IntPtr hPrinter, uint FirstJob, uint NoJobs, uint Level, IntPtr pJob,
            uint cbBuf, [Out] out uint pcbNeeded, [Out] out uint pcReturned);
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct JOB_INFO_1W
    {
        public uint JobId;
        [MarshalAs(UnmanagedType.LPWStr)] public string pPrinterName;
        [MarshalAs(UnmanagedType.LPWStr)] public string pMachineName;
        [MarshalAs(UnmanagedType.LPWStr)] public string pUserName;
        [MarshalAs(UnmanagedType.LPWStr)] public string pDocument;
        [MarshalAs(UnmanagedType.LPWStr)] public string pDatatype;
        [MarshalAs(UnmanagedType.LPWStr)] public string pStatus;
        public uint Status;
        public uint Priority;
        public uint Position;
        public uint TotalPages;
        public uint PagesPrinted;
        public SYSTEMTIME Submitted;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct SYSTEMTIME
    {
        public ushort wYear;
        public ushort wMonth;
        public ushort wDayOfWeek;
        public ushort wDay;
        public ushort wHour;
        public ushort wMinute;
        public ushort wSecond;
        public ushort wMilliseconds;
    }
}

结果:

工作 1:

工作 2:

编辑

看来您必须进行比我做的更可靠的检查,因为 EnumJobs 似乎在队列中没有作业时返回 true。在我的示例中,断言会失败,但这并不意味着代码是错误的;只需确保队列中有一些作业用于测试功能即可。

关于c# - EnumJobs 返回与 Marshal.SizeOF 不同的 JOB_INFO_1 大小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26857875/

有关c# - EnumJobs 返回与 Marshal.SizeOF 不同的 JOB_INFO_1 大小的更多相关文章

  1. ruby-on-rails - 在 Rails 中将文件大小字符串转换为等效千字节 - 2

    我的目标是转换表单输入,例如“100兆字节”或“1GB”,并将其转换为我可以存储在数据库中的文件大小(以千字节为单位)。目前,我有这个:defquota_convert@regex=/([0-9]+)(.*)s/@sizes=%w{kilobytemegabytegigabyte}m=self.quota.match(@regex)if@sizes.include?m[2]eval("self.quota=#{m[1]}.#{m[2]}")endend这有效,但前提是输入是倍数(“gigabytes”,而不是“gigabyte”)并且由于使用了eval看起来疯狂不安全。所以,功能正常,

  2. ruby - 为什么 4.1%2 使用 Ruby 返回 0.0999999999999996?但是 4.2%2==0.2 - 2

    为什么4.1%2返回0.0999999999999996?但是4.2%2==0.2。 最佳答案 参见此处:WhatEveryProgrammerShouldKnowAboutFloating-PointArithmetic实数是无限的。计算机使用的位数有限(今天是32位、64位)。因此计算机进行的浮点运算不能代表所有的实数。0.1是这些数字之一。请注意,这不是与Ruby相关的问题,而是与所有编程语言相关的问题,因为它来自计算机表示实数的方式。 关于ruby-为什么4.1%2使用Ruby返

  3. ruby - 检查字符串是否包含散列中的任何键并返回它包含的键的值 - 2

    我有一个包含多个键的散列和一个字符串,该字符串不包含散列中的任何键或包含一个键。h={"k1"=>"v1","k2"=>"v2","k3"=>"v3"}s="thisisanexamplestringthatmightoccurwithakeysomewhereinthestringk1(withspecialcharacterslike(^&*$#@!^&&*))"检查s是否包含h中的任何键的最佳方法是什么,如果包含,则返回它包含的键的值?例如,对于上面的h和s的例子,输出应该是v1。编辑:只有字符串是用户定义的。哈希将始终相同。 最佳答案

  4. c# - 如何在 ruby​​ 中调用 C# dll? - 2

    如何在ruby​​中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL

  5. ruby - Ruby 中的隐式返回值是怎么回事? - 2

    所以我开始关注ruby​​,很多东西看起来不错,但我对隐式return语句很反感。我理解默认情况下让所有内容返回self或nil但不是语句的最后一个值。对我来说,它看起来非常脆弱(尤其是)如果你正在使用一个不打算返回某些东西的方法(尤其是一个改变状态/破坏性方法的函数!),其他人可能最终依赖于一个返回对方法的目的并不重要,并且有很大的改变机会。隐式返回有什么意义?有没有办法让事情变得更简单?总是有返回以防止隐含返回被认为是好的做法吗?我是不是太担心这个了?附言当人们想要从方法中返回特定的东西时,他们是否经常使用隐式返回,这不是让你组中的其他人更容易破坏彼此的代码吗?当然,记录一切并给出

  6. C# 到 Ruby sha1 base64 编码 - 2

    我正在尝试在Ruby中复制Convert.ToBase64String()行为。这是我的C#代码:varsha1=newSHA1CryptoServiceProvider();varpasswordBytes=Encoding.UTF8.GetBytes("password");varpasswordHash=sha1.ComputeHash(passwordBytes);returnConvert.ToBase64String(passwordHash);//returns"W6ph5Mm5Pz8GgiULbPgzG37mj9g="当我在Ruby中尝试同样的事情时,我得到了相同sha

  7. ruby-on-rails - ruby 日期方程不返回预期的真值 - 2

    为什么以下不同?Time.now.end_of_day==Time.now.end_of_day-0.days#falseTime.now.end_of_day.to_s==Time.now.end_of_day-0.days.to_s#true 最佳答案 因为纳秒数不同:ruby-1.9.2-p180:014>(Time.now.end_of_day-0.days).nsec=>999999000ruby-1.9.2-p180:015>Time.now.end_of_day.nsec=>999999998

  8. ruby - 从 String#split 返回的零长度字符串 - 2

    在Ruby1.9.3(可能还有更早的版本,不确定)中,我试图弄清楚为什么Ruby的String#split方法会给我某些结果。我得到的结果似乎与我的预期相反。这是一个例子:"abcabc".split("b")#=>["a","ca","c"]"abcabc".split("a")#=>["","bc","bc"]"abcabc".split("c")#=>["ab","ab"]在这里,第一个示例返回的正是我所期望的。但在第二个示例中,我很困惑为什么#split返回零长度字符串作为返回数组的第一个值。这是什么原因呢?这是我所期望的:"abcabc".split("a")#=>["bc"

  9. 基于C#实现简易绘图工具【100010177】 - 2

    C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.

  10. HBase Region 简介和建议数量&大小 - 2

    Region是HBase数据管理的基本单位,region有一点像关系型数据的分区。region中存储这用户的真实数据,而为了管理这些数据,HBase使用了RegionSever来管理region。Region的结构hbaseregion的大小设置默认情况下,每个Table起初只有一个Region,随着数据的不断写入,Region会自动进行拆分。刚拆分时,两个子Region都位于当前的RegionServer,但处于负载均衡的考虑,HMaster有可能会将某个Region转移给其他的RegionServer。RegionSplit时机:当1个region中的某个Store下所有StoreFile

随机推荐