.NET Drawing.Printing中自定义PaperSize的问题

2023-12-17 07:18

本文主要是介绍.NET Drawing.Printing中自定义PaperSize的问题,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

以前在做一个项目,需要很多报表,而且报表的格式各不相同,重点是这些格式都是需要自定义的。但是这就碰到一个比较棘手的问题了,用过.net的朋友应该知道,PaperSize的自定义用起来有点问题,反正设置来设置去都实现不了,后来没办法客户催的紧,而且公司也要赶进度,因为客户只需要在两台机子上安装这个报表系统,所以用了一个最笨的方法,在两台机子上先设好需要的报表格式,这样系统才可以顺利使用。其实我分析以后知道如果利用WINDOWS的API在系统中进行设定,应该可以解决这个问题,不过后来转去做其他项目就没时间再考虑如何实现的问题。后来一次在网上看到和我思路一样的一种解决方法,当时就保存下来了。具体的代码如下:
using System;
using System.Text;
using System.Runtime.InteropServices;
using System.Security;
using System.ComponentModel;
using System.Drawing.Printing;

namespace MJMCustomPrintForm
{
    /// <summary>
    /// Summary description for MJMCustomPrintForm.
    /// </summary>
    public class MJMCustomPrintForm
    {
        // Make a static class
        private MJMCustomPrintForm()
        {
        }
   
        [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);

/*    This method is not used
        [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());
                        }

                  // 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,
                     MJMCustomPrintForm.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);
                }
            }
        }
    }
}

 不过具体在哪里找到的就不记得了。我自己其实还没试过。先记下来以后再用。 

这篇关于.NET Drawing.Printing中自定义PaperSize的问题的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/503545

相关文章

IDEA和GIT关于文件中LF和CRLF问题及解决

《IDEA和GIT关于文件中LF和CRLF问题及解决》文章总结:因IDEA默认使用CRLF换行符导致Shell脚本在Linux运行报错,需在编辑器和Git中统一为LF,通过调整Git的core.aut... 目录问题描述问题思考解决过程总结问题描述项目软件安装shell脚本上git仓库管理,但拉取后,上l

idea npm install很慢问题及解决(nodejs)

《ideanpminstall很慢问题及解决(nodejs)》npm安装速度慢可通过配置国内镜像源(如淘宝)、清理缓存及切换工具解决,建议设置全局镜像(npmconfigsetregistryht... 目录idea npm install很慢(nodejs)配置国内镜像源清理缓存总结idea npm in

pycharm跑python项目易出错的问题总结

《pycharm跑python项目易出错的问题总结》:本文主要介绍pycharm跑python项目易出错问题的相关资料,当你在PyCharm中运行Python程序时遇到报错,可以按照以下步骤进行排... 1. 一定不要在pycharm终端里面创建环境安装别人的项目子模块等,有可能出现的问题就是你不报错都安装

idea突然报错Malformed \uxxxx encoding问题及解决

《idea突然报错Malformeduxxxxencoding问题及解决》Maven项目在切换Git分支时报错,提示project元素为描述符根元素,解决方法:删除Maven仓库中的resolv... 目www.chinasem.cn录问题解决方式总结问题idea 上的 maven China编程项目突然报错,是

Python爬虫HTTPS使用requests,httpx,aiohttp实战中的证书异步等问题

《Python爬虫HTTPS使用requests,httpx,aiohttp实战中的证书异步等问题》在爬虫工程里,“HTTPS”是绕不开的话题,HTTPS为传输加密提供保护,同时也给爬虫带来证书校验、... 目录一、核心问题与优先级检查(先问三件事)二、基础示例:requests 与证书处理三、高并发选型:

前端导出Excel文件出现乱码或文件损坏问题的解决办法

《前端导出Excel文件出现乱码或文件损坏问题的解决办法》在现代网页应用程序中,前端有时需要与后端进行数据交互,包括下载文件,:本文主要介绍前端导出Excel文件出现乱码或文件损坏问题的解决办法,... 目录1. 检查后端返回的数据格式2. 前端正确处理二进制数据方案 1:直接下载(推荐)方案 2:手动构造

C#利用Free Spire.XLS for .NET复制Excel工作表

《C#利用FreeSpire.XLSfor.NET复制Excel工作表》在日常的.NET开发中,我们经常需要操作Excel文件,本文将详细介绍C#如何使用FreeSpire.XLSfor.NET... 目录1. 环境准备2. 核心功能3. android示例代码3.1 在同一工作簿内复制工作表3.2 在不同

Python绘制TSP、VRP问题求解结果图全过程

《Python绘制TSP、VRP问题求解结果图全过程》本文介绍用Python绘制TSP和VRP问题的静态与动态结果图,静态图展示路径,动态图通过matplotlib.animation模块实现动画效果... 目录一、静态图二、动态图总结【代码】python绘制TSP、VRP问题求解结果图(包含静态图与动态图

C#中通过Response.Headers设置自定义参数的代码示例

《C#中通过Response.Headers设置自定义参数的代码示例》:本文主要介绍C#中通过Response.Headers设置自定义响应头的方法,涵盖基础添加、安全校验、生产实践及调试技巧,强... 目录一、基础设置方法1. 直接添加自定义头2. 批量设置模式二、高级配置技巧1. 安全校验机制2. 类型

MyBatis/MyBatis-Plus同事务循环调用存储过程获取主键重复问题分析及解决

《MyBatis/MyBatis-Plus同事务循环调用存储过程获取主键重复问题分析及解决》MyBatis默认开启一级缓存,同一事务中循环调用查询方法时会重复使用缓存数据,导致获取的序列主键值均为1,... 目录问题原因解决办法如果是存储过程总结问题myBATis有如下代码获取序列作为主键IdMappe