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;
    }
}
4

1 回答 1

1

尝试制作两个打印作业,每个都具有不同的双面设置。摆弄工作的优先级以使它们井井有条,而不是围绕内部领域进行黑客攻击。

于 2012-06-21T16:14:48.043 回答