2012-06-21 145 views
0

我有一個打印多頁文檔的程序。第一頁是預先打印好的紙張,所以應該在第一面打印,其餘頁面應該雙面打印。如何從.NET打印作業中更換雙面打印件

我最初的解決方案是在第一頁後面打印一張空白紙,但很多(或者全部)打印機會使用預打印紙的不同面作爲前面(非常糟糕),這取決於是否它設置爲雙面打印或不打印。

因此,我試圖說服打印機在打印作業中更改雙面打印。我一直沒有任何運氣的戰鬥,並使用各種代碼示例,這應該在理論上工作,但事實並非如此。

在每次EndPage調用後,如果雙面打印需要更改,它將從打印機獲取設備上下文(使用內部類的專用字段上的反射,yuck),它使用數組填充DEVMODE結構中的值,然後用設備上下文和DEVMODE指針調用ResetDC()。

我從指針中檢索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

我認爲這將是最後的手段,這些確實是一個單一的打印工作,並試圖分裂它將意味着完全改變它們的構建和處理方式。此外,我有Delphi代碼這樣做,所以我知道Windows可以處理它,但問題是如何從.NET做到這一點。 –

+2

可以從StandardPrintController下降並通過調用base.OnEndPrint()/ base.OnStartPrint()在PrintDocument中間啓動新的打印作業,因此我不必在創建多個PrintDocuments時進行分解(這是我害怕不得不這樣做)。 –

相關問題