首页 文章

如何在.NET中更改打印作业中的双面打印

提问于
浏览
0

我有一个打印多页文档的程序 . 第一页是预先打印的纸张,因此应在第一面打印,其余页面应双面打印 .

我最初的解决方案是在第一页后打印一张空白纸,但是很多(或者全部)打印机将使用预打印纸的另一面作为前面(非常糟糕),这取决于它是否设置为是否双工 .

因此,我试图说服打印机在打印作业中间更改双面打印 . 我一直在努力与此作斗争,并且使用各种代码示例,理论上这应该可行,但事实并非如此 .

在每次EndPage调用之后,如果需要更改双工,它将从打印机获取设备上下文(使用内部类的私有字段上的反射,yuck),它使用Marshal填充DEVMODE结构上的值,然后调用ResetDC()带有设备上下文和DEVMODE指针 .

我从指针检索DEVMODE结构仅用于验证目的,我想确保我正在设置正确的字段 . DEVMODE正确填充并发送到ResetDC()和PrinterSettings.SetHdevmode(),但是当我重新检索PrinterSettings.GetHdevmode()时,我刚才所做的更改就消失了 . 打印机保持旧的双面打印设置 .

编辑:我发现之前发布的代码存在一些问题,例如OnStartPage调用ResetDC . 所以我需要修改StandardPrintController持有的DEVMODE结构 . 但它仍然没有处理这些变化:

public class PrinterDuplexController : StandardPrintController
{
    public PrinterDuplexController()
    {
    }

    private static FieldInfo dcField = typeof(StandardPrintController)
        .GetField("dc",
        BindingFlags.GetField | BindingFlags.Instance | BindingFlags.NonPublic);
    private static FieldInfo modeHandleField = typeof(StandardPrintController)
        .GetField("modeHandle",
        BindingFlags.GetField | BindingFlags.Instance | BindingFlags.NonPublic);

    protected object dc
    {
        get
        {
            return dcField.GetValue(this);
        }
    }

    protected IntPtr Hdc
    {
        get
        {
            var dc = this.dc;
            return (IntPtr)(dc.GetType().GetProperty("Hdc").GetValue(dc, null));
        }
    }
    protected IntPtr modeHandle
    {
        get
        {
            object result = modeHandleField.GetValue(this);
            var field = result.GetType().GetField("handle", BindingFlags.GetField | BindingFlags.Instance | BindingFlags.NonPublic);
            return (IntPtr)field.GetValue(result);
        }
    }

    public override void OnEndPage(PrintDocument document, PrintPageEventArgs e)
    {
        base.OnEndPage(document, e);
        IntPtr pDEVMODE = GlobalLock(modeHandle);
        try
        {
            int[] flags = new int[1];
            Marshal.Copy(
                new IntPtr(40 + pDEVMODE.ToInt64()),
                flags,
                0,
                1);
            flags[0] |= (int)DM.Duplex;
            Marshal.Copy(
                flags,
                0,
                new IntPtr(40 + pDEVMODE.ToInt64()),
                1);



            Marshal.Copy(
                new short[] { (short)e.PageSettings.PrinterSettings.Duplex },
                0,
                new IntPtr(62 + pDEVMODE.ToInt64()),
                1);

            var debugDevMode = (DEVMODE)Marshal.PtrToStructure(pDEVMODE, typeof(DEVMODE));

            ResetDC(Hdc, pDEVMODE);
        }
        finally
        {
            GlobalUnlock(modeHandle);
        }
    }

    [DllImport("gdi32.dll")]
    //private static extern IntPtr ResetDC(IntPtr hdc, [In] ref DEVMODE lpInitData);
    private static extern int ResetDC(IntPtr hdc, IntPtr DevMode);

    [DllImport("gdi32.dll")]
    public static extern int StartPage(IntPtr hdc);

    [DllImport("gdi32.dll")]
    public static extern int EndPage(IntPtr hdc);

    [DllImport("kernel32.dll", ExactSpelling = true)]
    private static extern IntPtr GlobalFree(IntPtr handle);

    [DllImport("kernel32.dll", ExactSpelling = true)]
    private static extern IntPtr GlobalLock(IntPtr handle);

    [DllImport("kernel32.dll", ExactSpelling = true)]
    private static extern IntPtr GlobalUnlock(IntPtr handle);

    [Flags()]
    internal enum DM : int
    {
        Orientation = 0x1,
        PaperSize = 0x2,
        PaperLength = 0x4,
        PaperWidth = 0x8,
        Scale = 0x10,
        Position = 0x20,
        NUP = 0x40,
        DisplayOrientation = 0x80,
        Copies = 0x100,
        DefaultSource = 0x200,
        PrintQuality = 0x400,
        Color = 0x800,
        Duplex = 0x1000,
        YResolution = 0x2000,
        TTOption = 0x4000,
        Collate = 0x8000,
        FormName = 0x10000,
        LogPixels = 0x20000,
        BitsPerPixel = 0x40000,
        PelsWidth = 0x80000,
        PelsHeight = 0x100000,
        DisplayFlags = 0x200000,
        DisplayFrequency = 0x400000,
        ICMMethod = 0x800000,
        ICMIntent = 0x1000000,
        MediaType = 0x2000000,
        DitherType = 0x4000000,
        PanningWidth = 0x8000000,
        PanningHeight = 0x10000000,
        DisplayFixedOutput = 0x20000000
    }

    internal struct POINTL
    {
        public int x;
        public int y;
    }


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

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

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

        [FieldOffset(44)]
        public POINTL dmPosition;
        [FieldOffset(52)]
        public Int32 dmDisplayOrientation;
        [FieldOffset(56)]
        public Int32 dmDisplayFixedOutput;

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

1 回答

  • 1

    尝试制作两个打印作业,每个作业具有不同的双面设置 . 弄清楚工作的优先级,以使他们井然有序,而不是在内部领域进行黑客攻击 .

相关问题