2015-01-08 13 views
6

Tôi đang làm việc trên Ứng dụng Windows Forms mà tôi muốn in tài liệu tùy chỉnh. Tài liệu tùy chỉnh này có kích thước tùy chỉnh và tôi phải đặt kích thước trang in mặc định bằng mã C#.Sử dụng chức năng PrintSpoolerAPI SetForm() trong C#

Tôi đã thực hiện một số tìm kiếm trên google và đã xem qua PrintSpoolerAPI. Mã mà tôi tìm thấy sẽ thêm một biểu mẫu/trang tùy chỉnh sử dụng phương thức AddForm() vào danh sách các trang có sẵn để in. Tôi cũng muốn đặt trang mới được thêm làm trang in mặc định.

Tôi cố gắng viết dòng này trong mã

bool x = SetForm(hPrinter, paperName, 1, ref formInfo); 

Nó trả về một giá trị true nhưng nó không thiết lập trang in mặc định.

dmPaperSize có vai trò gì trong điều này không?

Đây là mã hoàn chỉnh:

using System; 
using System.Text; 
using System.Runtime.InteropServices; 
using System.Security; 
using System.ComponentModel; 
using System.Drawing.Printing; 

namespace WindowsFormsApplication1 
{ 
    public class CustomPrintForm 
    { 
     [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] 
     internal struct structPrinterDefaults 
     { 
      [MarshalAs(UnmanagedType.LPTStr)] 
      public String pDatatype; 
      public IntPtr pDevMode; 
      [MarshalAs(UnmanagedType.I4)] 
      public int DesiredAccess; 
     }; 

    [DllImport("winspool.Drv", EntryPoint = "OpenPrinter", SetLastError = true, 
     CharSet = CharSet.Unicode, ExactSpelling = false, CallingConvention = CallingConvention.StdCall), 
    SuppressUnmanagedCodeSecurityAttribute()] 
    internal static extern bool OpenPrinter([MarshalAs(UnmanagedType.LPTStr)] 
     string printerName, 
     out IntPtr phPrinter, 
     ref structPrinterDefaults pd); 

    [DllImport("winspool.Drv", EntryPoint = "ClosePrinter", SetLastError = true, 
     CharSet = CharSet.Unicode, ExactSpelling = false, 
     CallingConvention = CallingConvention.StdCall), SuppressUnmanagedCodeSecurityAttribute()] 
    internal static extern bool ClosePrinter(IntPtr phPrinter); 

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] 
    internal struct structSize 
    { 
     public Int32 width; 
     public Int32 height; 
    } 

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] 
    internal struct structRect 
    { 
     public Int32 left; 
     public Int32 top; 
     public Int32 right; 
     public Int32 bottom; 
    } 

    [StructLayout(LayoutKind.Explicit, CharSet = CharSet.Unicode)] 
    internal struct FormInfo1 
    { 
     [FieldOffset(0), MarshalAs(UnmanagedType.I4)] 
     public uint Flags; 
     [FieldOffset(4), MarshalAs(UnmanagedType.LPWStr)] 
     public String pName; 
     [FieldOffset(8)] 
     public structSize Size; 
     [FieldOffset(16)] 
     public structRect ImageableArea; 
    }; 

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi/* changed from CharSet=CharSet.Auto */)] 
    internal struct structDevMode 
    { 
     [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] 
     public String 
      dmDeviceName; 
     [MarshalAs(UnmanagedType.U2)] 
     public short dmSpecVersion; 
     [MarshalAs(UnmanagedType.U2)] 
     public short dmDriverVersion; 
     [MarshalAs(UnmanagedType.U2)] 
     public short dmSize; 
     [MarshalAs(UnmanagedType.U2)] 
     public short dmDriverExtra; 
     [MarshalAs(UnmanagedType.U4)] 
     public int dmFields; 
     [MarshalAs(UnmanagedType.I2)] 
     public short dmOrientation; 
     [MarshalAs(UnmanagedType.I2)] 
     public short dmPaperSize; 
     [MarshalAs(UnmanagedType.I2)] 
     public short dmPaperLength; 
     [MarshalAs(UnmanagedType.I2)] 
     public short dmPaperWidth; 
     [MarshalAs(UnmanagedType.I2)] 
     public short dmScale; 
     [MarshalAs(UnmanagedType.I2)] 
     public short dmCopies; 
     [MarshalAs(UnmanagedType.I2)] 
     public short dmDefaultSource; 
     [MarshalAs(UnmanagedType.I2)] 
     public short dmPrintQuality; 
     [MarshalAs(UnmanagedType.I2)] 
     public short dmColor; 
     [MarshalAs(UnmanagedType.I2)] 
     public short dmDuplex; 
     [MarshalAs(UnmanagedType.I2)] 
     public short dmYResolution; 
     [MarshalAs(UnmanagedType.I2)] 
     public short dmTTOption; 
     [MarshalAs(UnmanagedType.I2)] 
     public short dmCollate; 
     [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] 
     public String dmFormName; 
     [MarshalAs(UnmanagedType.U2)] 
     public short dmLogPixels; 
     [MarshalAs(UnmanagedType.U4)] 
     public int dmBitsPerPel; 
     [MarshalAs(UnmanagedType.U4)] 
     public int dmPelsWidth; 
     [MarshalAs(UnmanagedType.U4)] 
     public int dmPelsHeight; 
     [MarshalAs(UnmanagedType.U4)] 
     public int dmNup; 
     [MarshalAs(UnmanagedType.U4)] 
     public int dmDisplayFrequency; 
     [MarshalAs(UnmanagedType.U4)] 
     public int dmICMMethod; 
     [MarshalAs(UnmanagedType.U4)] 
     public int dmICMIntent; 
     [MarshalAs(UnmanagedType.U4)] 
     public int dmMediaType; 
     [MarshalAs(UnmanagedType.U4)] 
     public int dmDitherType; 
     [MarshalAs(UnmanagedType.U4)] 
     public int dmReserved1; 
     [MarshalAs(UnmanagedType.U4)] 
     public int dmReserved2; 
    } 

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] 
    internal struct PRINTER_INFO_9 
    { 
     public IntPtr pDevMode; 
    } 

    [DllImport("winspool.Drv", EntryPoint = "AddFormW", SetLastError = true, 
     CharSet = CharSet.Unicode, ExactSpelling = true, 
     CallingConvention = CallingConvention.StdCall), SuppressUnmanagedCodeSecurityAttribute()] 
    internal static extern bool AddForm(
    IntPtr phPrinter, 
     [MarshalAs(UnmanagedType.I4)] int level, 
    ref FormInfo1 form); 

    [DllImport("winspool.Drv", EntryPoint = "SetForm", SetLastError = true, 
     CharSet = CharSet.Unicode, ExactSpelling = false, 
     CallingConvention = CallingConvention.StdCall), SuppressUnmanagedCodeSecurityAttribute()] 
    internal static extern bool SetForm(IntPtr phPrinter, string paperName, 
     [MarshalAs(UnmanagedType.I4)] int level, ref FormInfo1 form); 

    [DllImport("winspool.Drv", EntryPoint = "DeleteForm", SetLastError = true, 
     CharSet = CharSet.Unicode, ExactSpelling = false, CallingConvention = CallingConvention.StdCall), 
    SuppressUnmanagedCodeSecurityAttribute()] 
    internal static extern bool DeleteForm(
    IntPtr phPrinter, 
     [MarshalAs(UnmanagedType.LPTStr)] string pName); 

    [DllImport("kernel32.dll", EntryPoint = "GetLastError", SetLastError = false, 
     ExactSpelling = true, CallingConvention = CallingConvention.StdCall), 
    SuppressUnmanagedCodeSecurityAttribute()] 
    internal static extern Int32 GetLastError(); 

    [DllImport("GDI32.dll", EntryPoint = "CreateDC", SetLastError = true, 
     CharSet = CharSet.Unicode, ExactSpelling = false, 
     CallingConvention = CallingConvention.StdCall), 
    SuppressUnmanagedCodeSecurityAttribute()] 
    internal static extern IntPtr CreateDC([MarshalAs(UnmanagedType.LPTStr)] 
     string pDrive, 
     [MarshalAs(UnmanagedType.LPTStr)] string pName, 
     [MarshalAs(UnmanagedType.LPTStr)] string pOutput, 
     ref structDevMode pDevMode); 

    [DllImport("GDI32.dll", EntryPoint = "ResetDC", SetLastError = true, 
     CharSet = CharSet.Unicode, ExactSpelling = false, 
     CallingConvention = CallingConvention.StdCall), 
    SuppressUnmanagedCodeSecurityAttribute()] 
    internal static extern IntPtr ResetDC(
    IntPtr hDC, 
    ref structDevMode 
     pDevMode); 

    [DllImport("GDI32.dll", EntryPoint = "DeleteDC", SetLastError = true, 
     CharSet = CharSet.Unicode, ExactSpelling = false, 
     CallingConvention = CallingConvention.StdCall), 
    SuppressUnmanagedCodeSecurityAttribute()] 
    internal static extern bool DeleteDC(IntPtr hDC); 

    [DllImport("winspool.Drv", EntryPoint = "SetPrinterA", SetLastError = true, 
     CharSet = CharSet.Auto, ExactSpelling = true, 
     CallingConvention = CallingConvention.StdCall), SuppressUnmanagedCodeSecurityAttribute()] 
    internal static extern bool SetPrinter(
     IntPtr hPrinter, 
     [MarshalAs(UnmanagedType.I4)] int level, 
     IntPtr pPrinter, 
     [MarshalAs(UnmanagedType.I4)] int command); 

    /* 
    LONG DocumentProperties(
     HWND hWnd,    // handle to parent window 
     HANDLE hPrinter,   // handle to printer object 
     LPTSTR pDeviceName,  // device name 
     PDEVMODE pDevModeOutput, // modified device mode 
     PDEVMODE pDevModeInput, // original device mode 
     DWORD fMode    // mode options 
     ); 
    */ 
    [DllImport("winspool.Drv", EntryPoint = "DocumentPropertiesA", SetLastError = true, 
    ExactSpelling = true, CallingConvention = CallingConvention.StdCall)] 
    public static extern int DocumentProperties(
     IntPtr hwnd, 
     IntPtr hPrinter, 
     [MarshalAs(UnmanagedType.LPStr)] string pDeviceName /* changed from String to string */, 
     IntPtr pDevModeOutput, 
     IntPtr pDevModeInput, 
     int fMode 
     ); 

    [DllImport("winspool.Drv", EntryPoint = "GetPrinterA", SetLastError = true, 
    ExactSpelling = true, CallingConvention = CallingConvention.StdCall)] 
    public static extern bool GetPrinter(
     IntPtr hPrinter, 
     int dwLevel /* changed type from Int32 */, 
     IntPtr pPrinter, 
     int dwBuf /* chagned from Int32*/, 
     out int dwNeeded /* changed from Int32*/ 
     ); 

    // SendMessageTimeout tools 
    [Flags] 
    public enum SendMessageTimeoutFlags : uint 
    { 
     SMTO_NORMAL = 0x0000, 
     SMTO_BLOCK = 0x0001, 
     SMTO_ABORTIFHUNG = 0x0002, 
     SMTO_NOTIMEOUTIFNOTHUNG = 0x0008 
    } 
    const int WM_SETTINGCHANGE = 0x001A; 
    const int HWND_BROADCAST = 0xffff; 

    [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] 
    public static extern IntPtr SendMessageTimeout(
     IntPtr windowHandle, 
     uint Msg, 
     IntPtr wParam, 
     IntPtr lParam, 
     SendMessageTimeoutFlags flags, 
     uint timeout, 
     out IntPtr result 
     ); 

    public static void AddMjm80MmPaperSizeToDefaultPrinter() 
    { 
     AddCustomPaperSizeToDefaultPrinter("MJM 80mm * Receipt Length", 80.1f, 4003.9f); 
    } 

    public static void AddMjm104MmPaperSizeToDefaultPrinter() 
    { 
     AddCustomPaperSizeToDefaultPrinter("MJM 104mm * Receipt Length", 104.1f, 4003.9f); 
    } 

    /// <summary> 
    /// Adds the printer form to the default printer 
    /// </summary> 
    /// <param name="paperName">Name of the printer form</param> 
    /// <param name="widthMm">Width given in millimeters</param> 
    /// <param name="heightMm">Height given in millimeters</param> 
    public static void AddCustomPaperSizeToDefaultPrinter(string paperName, float widthMm, float heightMm) 
    { 
     PrintDocument pd = new PrintDocument(); 
     string sPrinterName = pd.PrinterSettings.PrinterName; 
     AddCustomPaperSize(sPrinterName, paperName, widthMm, heightMm); 
    } 

    /// <summary> 
    /// Add the printer form to a printer 
    /// </summary> 
    /// <param name="printerName">The printer name</param> 
    /// <param name="paperName">Name of the printer form</param> 
    /// <param name="widthMm">Width given in millimeters</param> 
    /// <param name="heightMm">Height given in millimeters</param> 
    public static void AddCustomPaperSize(string printerName, string paperName, float 
     widthMm, float heightMm) 
    { 
     if (PlatformID.Win32NT == Environment.OSVersion.Platform) 
     { 
      // The code to add a custom paper size is different for Windows NT then it is 
      // for previous versions of windows 

      const int PRINTER_ACCESS_USE = 0x00000008; 
      const int PRINTER_ACCESS_ADMINISTER = 0x00000004; 
      const int FORM_PRINTER = 0x00000002; 

      structPrinterDefaults defaults = new structPrinterDefaults(); 
      defaults.pDatatype = null; 
      defaults.pDevMode = IntPtr.Zero; 
      defaults.DesiredAccess = PRINTER_ACCESS_ADMINISTER | PRINTER_ACCESS_USE; 

      IntPtr hPrinter = IntPtr.Zero; 

      // Open the printer. 
      if (OpenPrinter(printerName, out hPrinter, ref defaults)) 
      { 
       try 
       { 
        // delete the form incase it already exists 
        DeleteForm(hPrinter, paperName); 
        // create and initialize the FORM_INFO_1 structure 
        FormInfo1 formInfo = new FormInfo1(); 
        formInfo.Flags = 0; 
        formInfo.pName = paperName; 
        // all sizes in 1000ths of millimeters 
        formInfo.Size.width = (int)(widthMm * 1000.0); 
        formInfo.Size.height = (int)(heightMm * 1000.0); 
        formInfo.ImageableArea.left = 0; 
        formInfo.ImageableArea.right = formInfo.Size.width; 
        formInfo.ImageableArea.top = 0; 
        formInfo.ImageableArea.bottom = formInfo.Size.height; 
        if (!AddForm(hPrinter, 1, ref formInfo)) 
        { 
         StringBuilder strBuilder = new StringBuilder(); 
         strBuilder.AppendFormat("Failed to add the custom paper size {0} to the printer {1}, System error number: {2}", 
          paperName, printerName, GetLastError()); 
         throw new ApplicationException(strBuilder.ToString()); 
        } 
        else 
        { 
         bool x = SetForm(hPrinter, paperName, 1, ref formInfo); 
        } 

        // INIT 
        const int DM_OUT_BUFFER = 2; 
        const int DM_IN_BUFFER = 8; 
        structDevMode devMode = new structDevMode(); 
        IntPtr hPrinterInfo, hDummy; 
        PRINTER_INFO_9 printerInfo; 
        printerInfo.pDevMode = IntPtr.Zero; 
        int iPrinterInfoSize, iDummyInt; 


        // GET THE SIZE OF THE DEV_MODE BUFFER 
        int iDevModeSize = DocumentProperties(IntPtr.Zero, hPrinter, printerName, IntPtr.Zero, IntPtr.Zero, 0); 

        if (iDevModeSize < 0) 
         throw new ApplicationException("Cannot get the size of the DEVMODE structure."); 

        // ALLOCATE THE BUFFER 
        IntPtr hDevMode = Marshal.AllocCoTaskMem(iDevModeSize + 100); 

        // GET A POINTER TO THE DEV_MODE BUFFER 
        int iRet = DocumentProperties(IntPtr.Zero, hPrinter, printerName, hDevMode, IntPtr.Zero, DM_OUT_BUFFER); 

        if (iRet < 0) 
         throw new ApplicationException("Cannot get the DEVMODE structure."); 

        // FILL THE DEV_MODE STRUCTURE 
        devMode = (structDevMode)Marshal.PtrToStructure(hDevMode, devMode.GetType()); 

        // SET THE FORM NAME FIELDS TO INDICATE THAT THIS FIELD WILL BE MODIFIED 
        devMode.dmFields = 0x10000; // DM_FORMNAME 
        // SET THE FORM NAME 
        devMode.dmFormName = paperName; 

        // PUT THE DEV_MODE STRUCTURE BACK INTO THE POINTER 
        Marshal.StructureToPtr(devMode, hDevMode, true); 

        // MERGE THE NEW CHAGES WITH THE OLD 
        iRet = DocumentProperties(IntPtr.Zero, hPrinter, printerName, 
          printerInfo.pDevMode, printerInfo.pDevMode, DM_IN_BUFFER | DM_OUT_BUFFER); 

        if (iRet < 0) 
         throw new ApplicationException("Unable to set the orientation setting for this printer."); 

        // GET THE PRINTER INFO SIZE 
        GetPrinter(hPrinter, 9, IntPtr.Zero, 0, out iPrinterInfoSize); 
        if (iPrinterInfoSize == 0) 
         throw new ApplicationException("GetPrinter failed. Couldn't get the # bytes needed for shared PRINTER_INFO_9 structure"); 

        // ALLOCATE THE BUFFER 
        hPrinterInfo = Marshal.AllocCoTaskMem(iPrinterInfoSize + 100); 

        // GET A POINTER TO THE PRINTER INFO BUFFER 
        bool bSuccess = GetPrinter(hPrinter, 9, hPrinterInfo, iPrinterInfoSize, out iDummyInt); 

        if (!bSuccess) 
         throw new ApplicationException("GetPrinter failed. Couldn't get the shared PRINTER_INFO_9 structure"); 

        // FILL THE PRINTER INFO STRUCTURE 
        printerInfo = (PRINTER_INFO_9)Marshal.PtrToStructure(hPrinterInfo, printerInfo.GetType()); 
        printerInfo.pDevMode = hDevMode; 

        // GET A POINTER TO THE PRINTER INFO STRUCTURE 
        Marshal.StructureToPtr(printerInfo, hPrinterInfo, true); 

        // SET THE PRINTER SETTINGS 
        bSuccess = SetPrinter(hPrinter, 9, hPrinterInfo, 0); 

        if (!bSuccess) 
         throw new Win32Exception(Marshal.GetLastWin32Error(), "SetPrinter() failed. Couldn't set the printer settings"); 

        // Tell all open programs that this change occurred. 
        SendMessageTimeout(new IntPtr(HWND_BROADCAST), WM_SETTINGCHANGE, IntPtr.Zero, IntPtr.Zero, CustomPrintForm.SendMessageTimeoutFlags.SMTO_NORMAL, 1000, out hDummy); 


       } 
       finally 
       { 
        ClosePrinter(hPrinter); 
       } 
      } 
      else 
      { 
       StringBuilder strBuilder = new StringBuilder(); 
       strBuilder.AppendFormat("Failed to open the {0} printer, System error number: {1}", 
        printerName, GetLastError()); 
       throw new ApplicationException(strBuilder.ToString()); 
      } 
     } 
     else 
     { 
      structDevMode pDevMode = new structDevMode(); 
      IntPtr hDC = CreateDC(null, printerName, null, ref pDevMode); 
      if (hDC != IntPtr.Zero) 
      { 
       const long DM_PAPERSIZE = 0x00000002L; 
       const long DM_PAPERLENGTH = 0x00000004L; 
       const long DM_PAPERWIDTH = 0x00000008L; 
       pDevMode.dmFields = (int)(DM_PAPERSIZE | DM_PAPERWIDTH | DM_PAPERLENGTH); 
       pDevMode.dmPaperSize = 256; 
       pDevMode.dmPaperWidth = (short)(widthMm * 1000.0); 
       pDevMode.dmPaperLength = (short)(heightMm * 1000.0); 
       ResetDC(hDC, ref pDevMode); 
       DeleteDC(hDC); 
      } 
     } 
    } 
} 

}

Cần giúp đỡ trong việc giải quyết vấn đề này.

Trả lời

4

Mã của bạn là rất gần như hoàn hảo (nhu cầu làm việc trong chế độ 64-bit) và những gì nó có ý định làm:

enter image description here

Đó là tuy nhiên nơi những tin tức tốt kết thúc. Api bạn đang sử dụng các cuộc đàm phán trực tiếp với trình điều khiển máy in và nó chịu trách nhiệm đảm bảo rằng các thay đổi của DEVMODE của bạn trở nên hiệu quả. Điều đó làm việc tốt cho trình điều khiển máy in XPS, không tốt cho nhiều loại trình điều khiển khác. Giống như trình điều khiển Hewlett Packard tôi cũng đã thử.

Mọi thứ bạn làm đều có tác dụng phụ có thể nhìn thấy ngay trong sổ đăng ký. Bạn có thể thấy nó với Regedit.exe. Cách tốt nhất để kiểm tra lại mã của bạn là gì. Và để thấy rằng bạn cần dừng thử vì trình điều khiển máy in sẽ không hoạt động. Các phím bạn muốn xem:

  • HKEY_LOCAL_MACHINE \ SYSTEM \ CurrentControlSet \ Control \ Print \ Forms. Phím này liệt kê biểu mẫu bạn thêm. Bạn không nên có vấn đề với cái đó.

  • HKEY_LOCAL_MACHINE \ SYSTEM \ CurrentControlSet \ Control \ Print \ Forms \ MJM 80mm * Thời lượng nhận, "Giá trị biểu mẫu". Viết xuống, đó là "từ khóa" mà biểu mẫu của bạn được chọn bởi máy in.

  • HKEY_LOCAL_MACHINE \ SYSTEM \ CurrentControlSet \ Control \ Print \ Máy in \ printername, "Giá trị mặc định DevMode". Điều này được viết khi bạn gọi SetPrinter(). Bạn có thể nhìn vào giá trị hex của giá trị. Từ khóa FormKeyword bạn đã viết ở bước trước được hiển thị tại offset 0x348

  • HKEY_LOCAL_MACHINE \ SYSTEM \ CurrentControlSet \ Control \ Print \ Printers \ printername \ DsDriver, printMediaGiá trị được hỗ trợ. Không hoàn toàn chắc chắn về điều này, nhưng nên hiển thị một danh sách các kích cỡ giấy và hình thức tùy chỉnh của bạn nên được hiển thị ở đó.

Xin lỗi vì tin xấu, máy in hút.

+0

yêu cầu thay đổi bổ sung để làm cho nó hoạt động ở chế độ 64 bit? –

+0

Dễ dàng dùng thử. Bạn sẽ thấy rằng [FieldOffset] là sai, con trỏ mất 8 byte. –

+0

sẽ dùng thử. Nhưng chắc chắn máy in hút !! –

1

cho x64 sử dụng

[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Unicode)] 
     internal struct FormInfo1 
     { 
      [FieldOffset(0), MarshalAs(UnmanagedType.I4)] 
      public uint Flags; 
      [FieldOffset(8), MarshalAs(UnmanagedType.LPWStr)] 
      public String pName; 
      [FieldOffset(16)] 
      public structSize Size; 
      [FieldOffset(24)] 
      public structRect ImageableArea; 
     }; 
0

Nhờ mã Nilesh và thông tin đăng ký Hans', yêu cầu của tôi là thiết lập các pagesize mặc định cho máy in cụ thể bằng C# chương trình, sau đó trình duyệt mở web để in một trang web cụ thể.

Lúc này tôi đã cố gắng thêm biểu mẫu trang tùy chỉnh của mình và đặt dmFormName với nó làm mặc định. Sau đó, tôi lấy lại cấu trúc devmode, dmFormName là những gì tôi đã thay đổi, nhưng khi tôi mở notepad hoặc ứng dụng khác và cố gắng in một cái gì đó, tôi thấy các trang mặc định không phải là những gì tôi thiết lập.

Ngoài ra, tôi đã cố gắng xóa tất cả các trang không sử dụng để chỉ có một trang mặc định, nhưng chỉ một trang được thêm vào bản thân tôi mới có thể bị xóa.

PS: Tôi làm một số mã refactoring như sau:

internal class PrinterPagaSize 
{ 
    public void DeleteAllPrintForm(string printerName) 
    { 
     structPrinterDefaults defaults = InitPrinterDefaults(); 
     IntPtr hPrinter = IntPtr.Zero; 
     if (OpenPrinter(printerName, out hPrinter, ref defaults)) 
     { 
      try 
      { 
       var printerSettings = PrinterSelector.DefaultPrinterSettings; 
       foreach (PaperSize ps in printerSettings.PaperSizes) 
       { 
        bool ret = DeleteForm(hPrinter, ps.PaperName); 
        Debug.WriteLine("delete ret:" + ret.ToString()); 
       } 
      } 
      finally 
      { 
       ClosePrinter(hPrinter); 
      } 
     } 
    } 

    public PaperSize GetPrintForm(string printerName, string paperName) 
    { 
     PaperSize paper = null; 
     //var printer = new System.Drawing.Printing.PrinterSettings {PrinterName = printerName}; 
     var printer = PrinterSelector.DefaultPrinterSettings; 
     foreach (PaperSize ps in printer.PaperSizes) 
     { 
      if (ps.PaperName.ToLower() == paperName.ToLower()) 
      { 
       paper = ps; 
       break; 
      } 
     } 
     return paper; 
    } 

    /// <summary> 
    /// Add the printer form to a printer 
    /// </summary> 
    /// <param name="printerName">The printer name</param> 
    /// <param name="paperName">Name of the printer form</param> 
    /// <param name="widthMm">Width given in millimeters</param> 
    /// <param name="heightMm">Height given in millimeters</param> 
    public void AddCustomPaperSize(string printerName, string paperName, float 
     width, float height) 
    { 
     if (PlatformID.Win32NT == Environment.OSVersion.Platform) 
     { 
      // The code to add a custom paper size is different for Windows NT then it is 
      // for previous versions of windows 
      structPrinterDefaults defaults = InitPrinterDefaults(); 
      IntPtr hPrinter = IntPtr.Zero; 

      // Open the printer. 
      if (OpenPrinter(printerName, out hPrinter, ref defaults)) 
      { 
       try 
       { 
        // delete the form incase it already exists 
        DeleteForm(hPrinter, paperName); 
        // create and initialize the FORM_INFO_1 structure 
        FormInfo1 formInfo = new FormInfo1(); 
        formInfo.Flags = 0; 
        formInfo.pName = paperName; 
        // all sizes in 1000ths of millimeters 
        formInfo.Size.width = (int)(width * 100.0); 
        formInfo.Size.height = (int)(height * 100.0); 
        formInfo.ImageableArea.left = 0; 
        formInfo.ImageableArea.right = formInfo.Size.width; 
        formInfo.ImageableArea.top = 0; 
        formInfo.ImageableArea.bottom = formInfo.Size.height; 
        if (!AddForm(hPrinter, 1, ref formInfo)) 
        { 
         StringBuilder strBuilder = new StringBuilder(); 
         strBuilder.AppendFormat(
          "Failed to add the custom paper size {0} to the printer {1}, System error number: {2}", 
          paperName, printerName, GetLastError()); 
         throw new ApplicationException(strBuilder.ToString()); 
        } 
        else 
        { 
         SetForm(hPrinter, paperName, 1, ref formInfo); 
        } 

        SetPrinterDevMode(hPrinter, printerName, paperName); 
       } 
       finally 
       { 
        ClosePrinter(hPrinter); 
       } 
      } 
      else 
      { 
       StringBuilder strBuilder = new StringBuilder(); 
       strBuilder.AppendFormat("Failed to open the {0} printer, System error number: {1}", 
        printerName, GetLastError()); 
       throw new ApplicationException(strBuilder.ToString()); 
      } 
     } 
     else 
     { 
      structDevMode pDevMode = new structDevMode(); 
      IntPtr hDC = CreateDC(null, printerName, null, ref pDevMode); 
      if (hDC != IntPtr.Zero) 
      { 
       const long DM_PAPERSIZE = 0x00000002L; 
       const long DM_PAPERLENGTH = 0x00000004L; 
       const long DM_PAPERWIDTH = 0x00000008L; 
       pDevMode.dmFields = (int)(DM_PAPERSIZE | DM_PAPERWIDTH | DM_PAPERLENGTH); 
       pDevMode.dmPaperSize = 256; 
       pDevMode.dmPaperWidth = (short)(width * 1000.0); 
       pDevMode.dmPaperLength = (short)(height * 1000.0); 
       ResetDC(hDC, ref pDevMode); 
       DeleteDC(hDC); 
      } 
     } 
    } 

    const int DM_OUT_BUFFER = 2; 
    const int DM_IN_BUFFER = 8; 
    private void SetPrinterDevMode(IntPtr hPrinter, string printerName, string paperName) 
    { 
     // INIT 
     structDevMode devMode = new structDevMode(); 

     PRINTER_INFO_9 printerInfo = new PRINTER_INFO_9(); 
     printerInfo.pDevMode = IntPtr.Zero; 


     IntPtr hDevMode = GetDevMode(hPrinter, printerName, ref devMode); 
     // SET THE FORM NAME FIELDS TO INDICATE THAT THIS FIELD WILL BE MODIFIED 
     devMode.dmFields = 0x10000; // DM_FORMNAME 
     // SET THE FORM NAME 
     devMode.dmFormName = paperName; 
     ChangeDevMode(hPrinter, printerName, paperName, devMode, hDevMode, ref printerInfo); 

     IntPtr hPrinterInfo = GetPrinterInfo(hPrinter); 

     // FILL THE PRINTER INFO STRUCTURE 
     printerInfo = (PRINTER_INFO_9)Marshal.PtrToStructure(hPrinterInfo, printerInfo.GetType()); 
     printerInfo.pDevMode = hDevMode; 

     // GET A POINTER TO THE PRINTER INFO STRUCTURE 
     Marshal.StructureToPtr(printerInfo, hPrinterInfo, true); 

     // SET THE PRINTER SETTINGS 
     bool bSuccess = SetPrinter(hPrinter, 9, hPrinterInfo, 0); 

     if (!bSuccess) 
      throw new Exception("Set printer failed!"); 
    } 

    private static IntPtr GetPrinterInfo(IntPtr hPrinter) 
    { 
     IntPtr hPrinterInfo; 
     bool bSuccess = false; 

     int iPrinterInfoSize, iDummyInt; 
     // GET THE PRINTER INFO SIZE 
     GetPrinter(hPrinter, 9, IntPtr.Zero, 0, out iPrinterInfoSize); 
     if (iPrinterInfoSize == 0) 
      throw new ApplicationException(
       "GetPrinter failed. Couldn't get the # bytes needed for shared PRINTER_INFO_9 structure"); 

     // ALLOCATE THE BUFFER 
     hPrinterInfo = Marshal.AllocCoTaskMem(iPrinterInfoSize + 100); 

     // GET A POINTER TO THE PRINTER INFO BUFFER 
     bSuccess = GetPrinter(hPrinter, 9, hPrinterInfo, iPrinterInfoSize, out iDummyInt); 

     if (!bSuccess) 
      throw new ApplicationException(
       "GetPrinter failed. Couldn't get the shared PRINTER_INFO_9 structure"); 

     return hPrinterInfo; 
    } 

    private static void ChangeDevMode(IntPtr hPrinter, string printerName, string paperName, structDevMode devMode, IntPtr hDevMode, ref PRINTER_INFO_9 printerInfo) 
    { 
     // PUT THE DEV_MODE STRUCTURE BACK INTO THE POINTER 
     Marshal.StructureToPtr(devMode, hDevMode, true); 

     // MERGE THE NEW CHAGES WITH THE OLD 
     int iRet = DocumentProperties(IntPtr.Zero, hPrinter, printerName, 
      printerInfo.pDevMode, printerInfo.pDevMode, DM_IN_BUFFER | DM_OUT_BUFFER); 

     if (iRet < 0) 
      throw new ApplicationException("Unable to set the orientation setting for this printer."); 
    } 

    private static IntPtr GetDevMode(IntPtr hPrinter, string printerName, ref structDevMode devMode) 
    { 
     // GET THE SIZE OF THE DEV_MODE BUFFER 
     int iDevModeSize = DocumentProperties(IntPtr.Zero, hPrinter, printerName, IntPtr.Zero, 
      IntPtr.Zero, 0); 

     if (iDevModeSize < 0) 
      throw new ApplicationException("Cannot get the size of the DEVMODE structure."); 

     // ALLOCATE THE BUFFER 
     IntPtr hDevMode = Marshal.AllocCoTaskMem(iDevModeSize + 100); 

     // GET A POINTER TO THE DEV_MODE BUFFER 
     int iRet = DocumentProperties(IntPtr.Zero, hPrinter, printerName, hDevMode, IntPtr.Zero, 
      DM_OUT_BUFFER); 

     if (iRet < 0) 
      throw new ApplicationException("Cannot get the DEVMODE structure."); 

     // FILL THE DEV_MODE STRUCTURE 
     devMode = (structDevMode)Marshal.PtrToStructure(hDevMode, devMode.GetType()); 
     return hDevMode; 
    } 

    private static structPrinterDefaults InitPrinterDefaults() 
    { 
     const int PRINTER_ACCESS_USE = 0x00000008; 
     const int PRINTER_ACCESS_ADMINISTER = 0x00000004; 
     structPrinterDefaults defaults = new structPrinterDefaults(); 
     defaults.pDatatype = null; 
     defaults.pDevMode = IntPtr.Zero; 
     defaults.DesiredAccess = PRINTER_ACCESS_ADMINISTER | PRINTER_ACCESS_USE; 
     return defaults; 
    } 

    #region Win API 
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] 
    internal struct structPrinterDefaults 
    { 
     [MarshalAs(UnmanagedType.LPTStr)] 
     public String pDatatype; 
     public IntPtr pDevMode; 
     [MarshalAs(UnmanagedType.I4)] 
     public int DesiredAccess; 
    }; 

    [DllImport("winspool.Drv", EntryPoint = "OpenPrinter", SetLastError = true, 
     CharSet = CharSet.Unicode, ExactSpelling = false, CallingConvention = CallingConvention.StdCall), 
    SuppressUnmanagedCodeSecurityAttribute()] 
    internal static extern bool OpenPrinter([MarshalAs(UnmanagedType.LPTStr)] string printerName, 
     out IntPtr phPrinter, 
     ref structPrinterDefaults pd); 

    [DllImport("winspool.Drv", EntryPoint = "ClosePrinter", SetLastError = true, 
     CharSet = CharSet.Unicode, ExactSpelling = false, 
     CallingConvention = CallingConvention.StdCall), SuppressUnmanagedCodeSecurityAttribute()] 
    internal static extern bool ClosePrinter(IntPtr phPrinter); 

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] 
    internal struct structSize 
    { 
     public Int32 width; 
     public Int32 height; 
    } 

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] 
    internal struct structRect 
    { 
     public Int32 left; 
     public Int32 top; 
     public Int32 right; 
     public Int32 bottom; 
    } 

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] 
    internal struct FormInfo1 
    { 
     [MarshalAs(UnmanagedType.I4)] 
     public int Flags; 
     [MarshalAs(UnmanagedType.LPTStr)] 
     public String pName; 
     public structSize Size; 
     public structRect ImageableArea; 
    }; 

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi /* changed from CharSet=CharSet.Auto */)] 
    internal struct structDevMode 
    { 
     [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] 
     public String 
      dmDeviceName; 

     [MarshalAs(UnmanagedType.U2)] 
     public short dmSpecVersion; 
     [MarshalAs(UnmanagedType.U2)] 
     public short dmDriverVersion; 
     [MarshalAs(UnmanagedType.U2)] 
     public short dmSize; 
     [MarshalAs(UnmanagedType.U2)] 
     public short dmDriverExtra; 
     [MarshalAs(UnmanagedType.U4)] 
     public int dmFields; 
     [MarshalAs(UnmanagedType.I2)] 
     public short dmOrientation; 
     [MarshalAs(UnmanagedType.I2)] 
     public short dmPaperSize; 
     [MarshalAs(UnmanagedType.I2)] 
     public short dmPaperLength; 
     [MarshalAs(UnmanagedType.I2)] 
     public short dmPaperWidth; 
     [MarshalAs(UnmanagedType.I2)] 
     public short dmScale; 
     [MarshalAs(UnmanagedType.I2)] 
     public short dmCopies; 
     [MarshalAs(UnmanagedType.I2)] 
     public short dmDefaultSource; 
     [MarshalAs(UnmanagedType.I2)] 
     public short dmPrintQuality; 
     [MarshalAs(UnmanagedType.I2)] 
     public short dmColor; 
     [MarshalAs(UnmanagedType.I2)] 
     public short dmDuplex; 
     [MarshalAs(UnmanagedType.I2)] 
     public short dmYResolution; 
     [MarshalAs(UnmanagedType.I2)] 
     public short dmTTOption; 
     [MarshalAs(UnmanagedType.I2)] 
     public short dmCollate; 
     [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] 
     public String dmFormName; 
     [MarshalAs(UnmanagedType.U2)] 
     public short dmLogPixels; 
     [MarshalAs(UnmanagedType.U4)] 
     public int dmBitsPerPel; 
     [MarshalAs(UnmanagedType.U4)] 
     public int dmPelsWidth; 
     [MarshalAs(UnmanagedType.U4)] 
     public int dmPelsHeight; 
     [MarshalAs(UnmanagedType.U4)] 
     public int dmNup; 
     [MarshalAs(UnmanagedType.U4)] 
     public int dmDisplayFrequency; 
     [MarshalAs(UnmanagedType.U4)] 
     public int dmICMMethod; 
     [MarshalAs(UnmanagedType.U4)] 
     public int dmICMIntent; 
     [MarshalAs(UnmanagedType.U4)] 
     public int dmMediaType; 
     [MarshalAs(UnmanagedType.U4)] 
     public int dmDitherType; 
     [MarshalAs(UnmanagedType.U4)] 
     public int dmReserved1; 
     [MarshalAs(UnmanagedType.U4)] 
     public int dmReserved2; 
    } 

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] 
    internal struct PRINTER_INFO_9 
    { 
     public IntPtr pDevMode; 
    } 

    [DllImport("winspool.Drv", EntryPoint = "AddFormW", SetLastError = true, 
     CharSet = CharSet.Unicode, ExactSpelling = true, 
     CallingConvention = CallingConvention.StdCall), SuppressUnmanagedCodeSecurityAttribute()] 
    internal static extern bool AddForm(
     IntPtr phPrinter, 
     [MarshalAs(UnmanagedType.I4)] int level, 
     ref FormInfo1 form); 

    [DllImport("winspool.Drv", EntryPoint = "SetForm", SetLastError = true, 
     CharSet = CharSet.Unicode, ExactSpelling = false, 
     CallingConvention = CallingConvention.StdCall), SuppressUnmanagedCodeSecurityAttribute()] 
    internal static extern bool SetForm(IntPtr phPrinter, string paperName, 
     [MarshalAs(UnmanagedType.I4)] int level, ref FormInfo1 form); 

    [DllImport("winspool.Drv", EntryPoint = "DeleteForm", SetLastError = true, 
     CharSet = CharSet.Unicode, ExactSpelling = false, CallingConvention = CallingConvention.StdCall), 
    SuppressUnmanagedCodeSecurityAttribute()] 
    internal static extern bool DeleteForm(
     IntPtr phPrinter, 
     [MarshalAs(UnmanagedType.LPTStr)] string pName); 

    [DllImport("kernel32.dll", EntryPoint = "GetLastError", SetLastError = false, 
     ExactSpelling = true, CallingConvention = CallingConvention.StdCall), 
    SuppressUnmanagedCodeSecurityAttribute()] 
    internal static extern Int32 GetLastError(); 

    [DllImport("GDI32.dll", EntryPoint = "CreateDC", SetLastError = true, 
     CharSet = CharSet.Unicode, ExactSpelling = false, 
     CallingConvention = CallingConvention.StdCall), 
    SuppressUnmanagedCodeSecurityAttribute()] 
    internal static extern IntPtr CreateDC([MarshalAs(UnmanagedType.LPTStr)] string pDrive, 
     [MarshalAs(UnmanagedType.LPTStr)] string pName, 
     [MarshalAs(UnmanagedType.LPTStr)] string pOutput, 
     ref structDevMode pDevMode); 

    [DllImport("GDI32.dll", EntryPoint = "ResetDC", SetLastError = true, 
     CharSet = CharSet.Unicode, ExactSpelling = false, 
     CallingConvention = CallingConvention.StdCall), 
    SuppressUnmanagedCodeSecurityAttribute()] 
    internal static extern IntPtr ResetDC(
     IntPtr hDC, 
     ref structDevMode 
      pDevMode); 

    [DllImport("GDI32.dll", EntryPoint = "DeleteDC", SetLastError = true, 
     CharSet = CharSet.Unicode, ExactSpelling = false, 
     CallingConvention = CallingConvention.StdCall), 
    SuppressUnmanagedCodeSecurityAttribute()] 
    internal static extern bool DeleteDC(IntPtr hDC); 

    [DllImport("winspool.Drv", EntryPoint = "SetPrinterA", SetLastError = true, 
     CharSet = CharSet.Auto, ExactSpelling = true, 
     CallingConvention = CallingConvention.StdCall), SuppressUnmanagedCodeSecurityAttribute()] 
    internal static extern bool SetPrinter(
     IntPtr hPrinter, 
     [MarshalAs(UnmanagedType.I4)] int level, 
     IntPtr pPrinter, 
     [MarshalAs(UnmanagedType.I4)] int command); 

    /* 
LONG DocumentProperties(
    HWND hWnd,    // handle to parent window 
    HANDLE hPrinter,   // handle to printer object 
    LPTSTR pDeviceName,  // device name 
    PDEVMODE pDevModeOutput, // modified device mode 
    PDEVMODE pDevModeInput, // original device mode 
    DWORD fMode    // mode options 
    ); 
*/ 

    [DllImport("winspool.Drv", EntryPoint = "DocumentPropertiesA", SetLastError = true, 
     ExactSpelling = true, CallingConvention = CallingConvention.StdCall)] 
    public static extern int DocumentProperties(
     IntPtr hwnd, 
     IntPtr hPrinter, 
     [MarshalAs(UnmanagedType.LPStr)] string pDeviceName /* changed from String to string */, 
     IntPtr pDevModeOutput, 
     IntPtr pDevModeInput, 
     int fMode 
     ); 

    [DllImport("winspool.Drv", EntryPoint = "GetPrinterA", SetLastError = true, 
     ExactSpelling = true, CallingConvention = CallingConvention.StdCall)] 
    public static extern bool GetPrinter(
     IntPtr hPrinter, 
     int dwLevel /* changed type from Int32 */, 
     IntPtr pPrinter, 
     int dwBuf /* chagned from Int32*/, 
     out int dwNeeded /* changed from Int32*/ 
     ); 

    // SendMessageTimeout tools 
    [Flags] 
    public enum SendMessageTimeoutFlags : uint 
    { 
     SMTO_NORMAL = 0x0000, 
     SMTO_BLOCK = 0x0001, 
     SMTO_ABORTIFHUNG = 0x0002, 
     SMTO_NOTIMEOUTIFNOTHUNG = 0x0008 
    } 

    private const int WM_SETTINGCHANGE = 0x001A; 
    private const int HWND_BROADCAST = 0xffff; 

    [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] 
    public static extern IntPtr SendMessageTimeout(
     IntPtr windowHandle, 
     uint Msg, 
     IntPtr wParam, 
     IntPtr lParam, 
     SendMessageTimeoutFlags flags, 
     uint timeout, 
     out IntPtr result 
     ); 
    #endregion 
} 
0

tôi chỉ sử dụng một mã số tương tự để thêm một khổ giấy đặc biệt để điều khiển cửa sổ tùy chỉnh máy in CỦA CHÚNG TÔI. Dường như đôi khi nó không hoạt động nhưng lý do là trình điều khiển GPD của máy in. Nếu trong tập tin này không tồn tại phần đặc biệt CUSTOMIZE rằng máy in sẽ không bao giờ chấp nhận bất kỳ kích cỡ giấy TÙY CHỈNH nào. Bạn có thể dễ dàng kiểm tra bằng cách sử dụng quy trình cửa sổ chuẩn để thêm giấy tùy chỉnh vào bất kỳ máy in nào.

*Option: CUSTOMSIZE 
{ 
    *rcNameID: =USER_DEFINED_SIZE_DISPLAY 
    *MinSize: PAIR(100, 100) 
    *MaxSize: PAIR(4026, 11340) 
    *TopMargin: 0 
    *BottomMargin: 0 
    *MaxPrintableWidth: 4026 
    *MinLeftMargin: 0 
    *CenterPrintable?: FALSE 
    *Command: CmdSelect 
    { 
     *Order: DOC_SETUP.10 
     *Cmd: "" 
    } 
} 
Các vấn đề liên quan