分享懒人张RDLC报表(七、八)-程序员宅基地

技术标签: c#  runtime  

来自懒人张:RDLC报表(七)

        有关LocalReport、DeviceInfo和PrintDocument的内容已经介绍得差不多了,稍后会给出一个继承自 System.Drawing.Printing.PrintDocument的组件EMFStreamPrintDocument。但是现在,来看一下 如何进行自定义纸张票据打印时的页面设置。页面设置窗体如下图所示:

        如何添加、删除自定义大小的纸张、枚举系统的打印机?以前在博客园的一篇随笔中参加过讨论,见http://wormday.cnblogs.com/archive/2005/12/22/302635.aspx。 当然还是使用Win32 API,以下是我封装的一个关于打印机控制的类[以前用VB实现过比这个类还要多的关于打印机控制的功能,但是在C#中感到还是挺困难的,所以这次只给出 了够用的功能:获取当前指定打印机的状态、删除已经存在的自定义纸张、指定的打印机设置以mm为单位的自定义纸张(Form)、获取本地打印机列表、获取 本机的默认打印机名称、设置默认打印机、判断打印机是否在系统可用的打印机列表中、判断表单是否在指定的打印机所支持的纸张列表中、判断指定纸张的宽度和 高度和在文本框中指定的宽度和高度是否匹配、英尺到厘米的转换]:

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

namespace RDLCReport
{

    public class Printer
    {
        private Printer()
        {

        }

        #region 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.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)]
        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 = "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)]
        internal static extern int DocumentProperties(
           IntPtr hwnd,
           IntPtr hPrinter,
           [MarshalAs(UnmanagedType.LPStr)] string pDeviceName,
           IntPtr pDevModeOutput,
           IntPtr pDevModeInput,
           int fMode
           );

        [DllImport("winspool.Drv", EntryPoint = "GetPrinterA", SetLastError = true,
        ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
        internal static extern bool GetPrinter(
           IntPtr hPrinter,
           int dwLevel,
           IntPtr pPrinter,
           int dwBuf,
           out int dwNeeded
           );

        [Flags]
        internal 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)]
        internal static extern IntPtr SendMessageTimeout(
           IntPtr windowHandle,
           uint Msg,
           IntPtr wParam,
           IntPtr lParam,
           SendMessageTimeoutFlags flags,
           uint timeout,
           out IntPtr result
           );

        //EnumPrinters用到的函数和机构体
        [DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern bool EnumPrinters(PrinterEnumFlags Flags, string Name, uint Level,
            IntPtr pPrinterEnum, uint cbBuf,
        ref uint pcbNeeded, ref uint pcReturned);

        [StructLayout(LayoutKind.Sequential)]
        internal struct PRINTER_INFO_2
        {
            public string pServerName;
            public string pPrinterName;
            public string pShareName;
            public string pPortName;
            public string pDriverName;
            public string pComment;
            public string pLocation;
            public IntPtr pDevMode;
            public string pSepFile;
            public string pPrintProcessor;
            public string pDatatype;
            public string pParameters;
            public IntPtr pSecurityDescriptor;
            public uint Attributes;
            public uint Priority;
            public uint DefaultPriority;
            public uint StartTime;
            public uint UntilTime;
            public uint Status;
            public uint cJobs;
            public uint AveragePPM;
        }

        [FlagsAttribute]
        internal enum PrinterEnumFlags
        {
            PRINTER_ENUM_DEFAULT = 0x00000001,
            PRINTER_ENUM_LOCAL = 0x00000002,
            PRINTER_ENUM_CONNECTIONS = 0x00000004,
            PRINTER_ENUM_FAVORITE = 0x00000004,
            PRINTER_ENUM_NAME = 0x00000008,
            PRINTER_ENUM_REMOTE = 0x00000010,
            PRINTER_ENUM_SHARED = 0x00000020,
            PRINTER_ENUM_NETWORK = 0x00000040,
            PRINTER_ENUM_EXPAND = 0x00004000,
            PRINTER_ENUM_CONTAINER = 0x00008000,
            PRINTER_ENUM_ICONMASK = 0x00ff0000,
            PRINTER_ENUM_ICON1 = 0x00010000,
            PRINTER_ENUM_ICON2 = 0x00020000,
            PRINTER_ENUM_ICON3 = 0x00040000,
            PRINTER_ENUM_ICON4 = 0x00080000,
            PRINTER_ENUM_ICON5 = 0x00100000,
            PRINTER_ENUM_ICON6 = 0x00200000,
            PRINTER_ENUM_ICON7 = 0x00400000,
            PRINTER_ENUM_ICON8 = 0x00800000,
            PRINTER_ENUM_HIDE = 0x01000000
        }

        //打印机状态
        [FlagsAttribute]
        internal enum PrinterStatus
        {
            PRINTER_STATUS_BUSY = 0x00000200,
            PRINTER_STATUS_DOOR_OPEN = 0x00400000,
            PRINTER_STATUS_ERROR = 0x00000002,
            PRINTER_STATUS_INITIALIZING = 0x00008000,
            PRINTER_STATUS_IO_ACTIVE = 0x00000100,
            PRINTER_STATUS_MANUAL_FEED = 0x00000020,
            PRINTER_STATUS_NO_TONER = 0x00040000,
            PRINTER_STATUS_NOT_AVAILABLE = 0x00001000,
            PRINTER_STATUS_OFFLINE = 0x00000080,
            PRINTER_STATUS_OUT_OF_MEMORY = 0x00200000,
            PRINTER_STATUS_OUTPUT_BIN_FULL = 0x00000800,
            PRINTER_STATUS_PAGE_PUNT = 0x00080000,
            PRINTER_STATUS_PAPER_JAM = 0x00000008,
            PRINTER_STATUS_PAPER_OUT = 0x00000010,
            PRINTER_STATUS_PAPER_PROBLEM = 0x00000040,
            PRINTER_STATUS_PAUSED = 0x00000001,
            PRINTER_STATUS_PENDING_DELETION = 0x00000004,
            PRINTER_STATUS_PRINTING = 0x00000400,
            PRINTER_STATUS_PROCESSING = 0x00004000,
            PRINTER_STATUS_TONER_LOW = 0x00020000,
            PRINTER_STATUS_USER_INTERVENTION = 0x00100000,
            PRINTER_STATUS_WAITING = 0x20000000,
            PRINTER_STATUS_WARMING_UP = 0x00010000
        }

        //GetDefaultPrinter用到的API函数说明
        [DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)]
        internal static extern bool GetDefaultPrinter(StringBuilder pszBuffer, ref int size);

        //SetDefaultPrinter用到的API函数声明
        [DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)]
        internal static extern bool SetDefaultPrinter(string Name);

        //EnumFormsA用到的函数声明,应该和EnumPrinters类似
        [DllImport("winspool.drv", EntryPoint = "EnumForms")]
        internal static extern int EnumFormsA(IntPtr hPrinter, int Level, ref byte pForm, int cbBuf, ref int pcbNeeded, ref int pcReturned);



        #endregion

        internal static int GetPrinterStatusInt(string PrinterName)
        {
            int intRet = 0;
            IntPtr hPrinter;
            structPrinterDefaults defaults = new structPrinterDefaults();

            if (OpenPrinter(PrinterName, out hPrinter, ref defaults))
            {
                int cbNeeded = 0;
                bool bolRet = GetPrinter(hPrinter, 2, IntPtr.Zero, 0, out cbNeeded);
                if (cbNeeded > 0)
                {
                    IntPtr pAddr = Marshal.AllocHGlobal((int)cbNeeded);
                    bolRet = GetPrinter(hPrinter, 2, pAddr, cbNeeded, out cbNeeded);
                    if (bolRet)
                    {
                        PRINTER_INFO_2 Info2 = new PRINTER_INFO_2();

                        Info2 = (PRINTER_INFO_2)Marshal.PtrToStructure(pAddr, typeof(PRINTER_INFO_2));

                        intRet = System.Convert.ToInt32(Info2.Status);
                    }
                    Marshal.FreeHGlobal(pAddr);
                }
                ClosePrinter(hPrinter);
            }

            return intRet;
        }

        internal static PRINTER_INFO_2[] EnumPrintersByFlag(PrinterEnumFlags Flags)
        {
            uint cbNeeded = 0;
            uint cReturned = 0;
            bool ret = EnumPrinters(PrinterEnumFlags.PRINTER_ENUM_LOCAL, null, 2, IntPtr.Zero, 0, ref cbNeeded, ref cReturned);

            IntPtr pAddr = Marshal.AllocHGlobal((int)cbNeeded);
            ret = EnumPrinters(PrinterEnumFlags.PRINTER_ENUM_LOCAL, null, 2, pAddr, cbNeeded, ref cbNeeded, ref cReturned);

            if (ret)
            {
                PRINTER_INFO_2[] Info2 = new PRINTER_INFO_2[cReturned];

                int offset = pAddr.ToInt32();

                for (int i = 0; i < cReturned; i++)
                {
                    Info2[i].pServerName = Marshal.PtrToStringAuto(Marshal.ReadIntPtr(new IntPtr(offset)));
                    offset += 4;
                    Info2[i].pPrinterName = Marshal.PtrToStringAuto(Marshal.ReadIntPtr(new IntPtr(offset)));
                    offset += 4;
                    Info2[i].pShareName = Marshal.PtrToStringAuto(Marshal.ReadIntPtr(new IntPtr(offset)));
                    offset += 4;
                    Info2[i].pPortName = Marshal.PtrToStringAuto(Marshal.ReadIntPtr(new IntPtr(offset)));
                    offset += 4;
                    Info2[i].pDriverName = Marshal.PtrToStringAuto(Marshal.ReadIntPtr(new IntPtr(offset)));
                    offset += 4;
                    Info2[i].pComment = Marshal.PtrToStringAuto(Marshal.ReadIntPtr(new IntPtr(offset)));
                    offset += 4;
                    Info2[i].pLocation = Marshal.PtrToStringAuto(Marshal.ReadIntPtr(new IntPtr(offset)));
                    offset += 4;
                    Info2[i].pDevMode = Marshal.ReadIntPtr(new IntPtr(offset));
                    offset += 4;
                    Info2[i].pSepFile = Marshal.PtrToStringAuto(Marshal.ReadIntPtr(new IntPtr(offset)));
                    offset += 4;
                    Info2[i].pPrintProcessor = Marshal.PtrToStringAuto(Marshal.ReadIntPtr(new IntPtr(offset)));
                    offset += 4;
                    Info2[i].pDatatype = Marshal.PtrToStringAuto(Marshal.ReadIntPtr(new IntPtr(offset)));
                    offset += 4;
                    Info2[i].pParameters = Marshal.PtrToStringAuto(Marshal.ReadIntPtr(new IntPtr(offset)));
                    offset += 4;
                    Info2[i].pSecurityDescriptor = Marshal.ReadIntPtr(new IntPtr(offset));
                    offset += 4;
                    Info2[i].Attributes = (uint)Marshal.ReadIntPtr(new IntPtr(offset));
                    offset += 4;
                    Info2[i].Priority = (uint)Marshal.ReadInt32(new IntPtr(offset));
                    offset += 4;
                    Info2[i].DefaultPriority = (uint)Marshal.ReadInt32(new IntPtr(offset));
                    offset += 4;
                    Info2[i].StartTime = (uint)Marshal.ReadInt32(new IntPtr(offset));
                    offset += 4;
                    Info2[i].UntilTime = (uint)Marshal.ReadInt32(new IntPtr(offset));
                    offset += 4;
                    Info2[i].Status = (uint)Marshal.ReadInt32(new IntPtr(offset));
                    offset += 4;
                    Info2[i].cJobs = (uint)Marshal.ReadInt32(new IntPtr(offset));
                    offset += 4;
                    Info2[i].AveragePPM = (uint)Marshal.ReadInt32(new IntPtr(offset));
                    offset += 4;

                }

                Marshal.FreeHGlobal(pAddr);

                return Info2;

            }
            else
            {
                return new PRINTER_INFO_2[0];
            }
        }

        /// <summary>
        /// 获取当前指定打印机的状态
        /// </summary>
        /// <param name="PrinterName">打印机名称</param>
        /// <returns>打印机状态描述</returns>
        public static string GetPrinterStatus(string PrinterName)
        {
            int intValue = GetPrinterStatusInt(PrinterName);
            string strRet = string.Empty;
            switch (intValue)
            {
                case 0:
                    strRet = "准备就绪(Ready)";
                    break;
                case 0x00000200:
                    strRet = "忙(Busy)";
                    break;
                case 0x00400000:
                    strRet = "门被打开(Printer Door Open)";
                    break;
                case 0x00000002:
                    strRet = "错误(Printer Error)";
                    break;
                case 0x0008000:
                    strRet = "正在初始化(Initializing)";
                    break;
                case 0x00000100:
                    strRet = "正在输入或输出(I/O Active)";
                    break;
                case 0x00000020:
                    strRet = "手工送纸(Manual Feed)";
                    break;
                case 0x00040000:
                    strRet = "无墨粉(No Toner)";
                    break;
                case 0x00001000:
                    strRet = "不可用(Not Available)";
                    break;
                case 0x00000080:
                    strRet = "脱机(Off Line)";
                    break;
                case 0x00200000:
                    strRet = "内存溢出(Out of Memory)";
                    break;
                case 0x00000800:
                    strRet = "输出口已满(Output Bin Full)";
                    break;
                case 0x00080000:
                    strRet = "当前页无法打印(Page Punt)";
                    break;
                case 0x00000008:
                    strRet = "塞纸(Paper Jam)";
                    break;
                case 0x00000010:
                    strRet = "打印纸用完(Paper Out)";
                    break;
                case 0x00000040:
                    strRet = "纸张问题(Page Problem)";
                    break;
                case 0x00000001:
                    strRet = "暂停(Paused)";
                    break;
                case 0x00000004:
                    strRet = "正在删除(Pending Deletion)";
                    break;
                case 0x00000400:
                    strRet = "正在打印(Printing)";
                    break;
                case 0x00004000:
                    strRet = "正在处理(Processing)";
                    break;
                case 0x00020000:
                    strRet = "墨粉不足(Toner Low)";
                    break;
                case 0x00100000:
                    strRet = "需要用户干预(User Intervention)";
                    break;
                case 0x20000000:
                    strRet = "等待(Waiting)";
                    break;
                case 0x00010000:
                    strRet = "正在准备(Warming Up)";
                    break;
                default:
                    strRet = "未知状态(Unknown Status)";
                    break;
            }
            return strRet;
        }

        /// <summary>
        /// 删除已经存在的自定义纸张
        /// </summary>
        /// <param name="PrinterName">打印机名称</param>
        /// <param name="PaperName">纸张名称</param>
        public static void DeleteCustomPaperSize(string PrinterName, string PaperName)
        {
            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;

            IntPtr hPrinter = IntPtr.Zero;

            //打开打印机
            if (OpenPrinter(PrinterName, out hPrinter, ref defaults))
            {
                try
                {
                    DeleteForm(hPrinter, PaperName);
                    ClosePrinter(hPrinter);
                }
                catch
                {
                    Pub.WinForm.Msg.Warning("删除自定义纸张时发生错误!");
                }
            }
        }

        /// <summary>
        /// 指定的打印机设置以mm为单位的自定义纸张(Form)
        /// </summary>
        /// <param name="PrinterName">打印机名称</param>
        /// <param name="PaperName">Form名称</param>
        /// <param name="WidthInMm">以mm为单位的宽度</param>
        /// <param name="HeightInMm">以mm为单位的高度</param>
        public static void AddCustomPaperSize(string PrinterName, string PaperName, float WidthInMm, float HeightInMm)
        {
            if (PlatformID.Win32NT == Environment.OSVersion.Platform)
            {
                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;

                //打开打印机
                if (OpenPrinter(PrinterName, out hPrinter, ref defaults))
                {
                    try
                    {
                        //如果Form存在删除之
                        DeleteForm(hPrinter, PaperName);
                        //创建并初始化FORM_INFO_1
                        FormInfo1 formInfo = new FormInfo1();
                        formInfo.Flags = 0;
                        formInfo.pName = PaperName;
                        formInfo.Size.width = (int)(WidthInMm * 1000.0);
                        formInfo.Size.height = (int)(HeightInMm * 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("向打印机 {1} 添加自定义纸张 {0} 失败!错误代号:{2}",
                                PaperName, PrinterName, GetLastError());
                            throw new ApplicationException(strBuilder.ToString());
                        }

                        //初始化
                        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;


                        int iDevModeSize = DocumentProperties(IntPtr.Zero, hPrinter, PrinterName, IntPtr.Zero, IntPtr.Zero, 0);

                        if (iDevModeSize < 0)
                            throw new ApplicationException("无法取得DEVMODE结构的大小!");

                        //分配缓冲
                        IntPtr hDevMode = Marshal.AllocCoTaskMem(iDevModeSize + 100);

                        //获取DEV_MODE指针
                        int iRet = DocumentProperties(IntPtr.Zero, hPrinter, PrinterName, hDevMode, IntPtr.Zero, DM_OUT_BUFFER);

                        if (iRet < 0)
                            throw new ApplicationException("无法获得DEVMODE结构!");

                        //填充DEV_MODE
                        devMode = (structDevMode)Marshal.PtrToStructure(hDevMode, devMode.GetType());


                        devMode.dmFields = 0x10000;

                        //FORM名称
                        devMode.dmFormName = PaperName;

                        Marshal.StructureToPtr(devMode, hDevMode, true);

                        iRet = DocumentProperties(IntPtr.Zero, hPrinter, PrinterName,
                                 printerInfo.pDevMode, printerInfo.pDevMode, DM_IN_BUFFER | DM_OUT_BUFFER);

                        if (iRet < 0)
                            throw new ApplicationException("无法为打印机设定打印方向!");

                        GetPrinter(hPrinter, 9, IntPtr.Zero, 0, out iPrinterInfoSize);
                        if (iPrinterInfoSize == 0)
                            throw new ApplicationException("调用GetPrinter方法失败!");

                        hPrinterInfo = Marshal.AllocCoTaskMem(iPrinterInfoSize + 100);

                        bool bSuccess = GetPrinter(hPrinter, 9, hPrinterInfo, iPrinterInfoSize, out iDummyInt);

                        if (!bSuccess)
                            throw new ApplicationException("调用GetPrinter方法失败!");

                        printerInfo = (PRINTER_INFO_9)Marshal.PtrToStructure(hPrinterInfo, printerInfo.GetType());
                        printerInfo.pDevMode = hDevMode;

                        Marshal.StructureToPtr(printerInfo, hPrinterInfo, true);

                        bSuccess = SetPrinter(hPrinter, 9, hPrinterInfo, 0);

                        if (!bSuccess)
                            throw new Win32Exception(Marshal.GetLastWin32Error(), "调用SetPrinter方法失败,无法进行打印机设置!");

                        SendMessageTimeout(
                           new IntPtr(HWND_BROADCAST),
                           WM_SETTINGCHANGE,
                           IntPtr.Zero,
                           IntPtr.Zero,
                           Printer.SendMessageTimeoutFlags.SMTO_NORMAL,
                           1000,
                           out hDummy);
                    }
                    finally
                    {
                        ClosePrinter(hPrinter);
                    }
                }
                else
                {
                    StringBuilder strBuilder = new StringBuilder();
                    strBuilder.AppendFormat("无法打开打印机{0}, 错误代号: {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)(WidthInMm * 1000.0);
                    pDevMode.dmPaperLength = (short)(HeightInMm * 1000.0);
                    ResetDC(hDC, ref pDevMode);
                    DeleteDC(hDC);
                }
            }
        }

        /// <summary>
        /// 获取本地打印机列表
        /// 可以通过制定参数获取网络打印机
        /// </summary>
        /// <returns>打印机列表</returns>
        public static System.Collections.ArrayList GetPrinterList()
        {
            System.Collections.ArrayList alRet = new System.Collections.ArrayList();
            PRINTER_INFO_2[] Info2 = EnumPrintersByFlag(PrinterEnumFlags.PRINTER_ENUM_LOCAL);
            for (int i = 0; i < Info2.Length; i++)
            {
                alRet.Add(Info2[i].pPrinterName);
            }
            return alRet;
        }

        /// <summary>
        /// 获取本机的默认打印机名称
        /// </summary>
        /// <returns>默认打印机名称</returns>
        public static string GetDeaultPrinterName()
        {
            StringBuilder dp = new StringBuilder(256);
            int size = dp.Capacity;
            if (GetDefaultPrinter(dp, ref size))
            {
                return dp.ToString();
            }
            else
            {
                int rc = GetLastError();
                Pub.WinForm.Msg.Warning("获取默认打印机失败!错误代号:" + rc.ToString());
                return string.Empty;
            }
        }

        /// <summary>
        /// 设置默认打印机
        /// </summary>
        /// <param name="PrinterName">可用的打印机名称</param>
        public static void SetPrinterToDefault(string PrinterName)
        {
            SetDefaultPrinter(PrinterName);
        }

        ///// <summary>
        ///// 判断打印机是否在系统可用的打印机列表中
        ///// </summary>
        ///// <param name="PrinterName">打印机名称</param>
        ///// <returns>是:在;否:不在</returns>
        public static bool PrinterInList(string PrinterName)
        {
            bool bolRet = false;

            System.Collections.ArrayList alPrinters = GetPrinterList();

            for (int i = 0; i < alPrinters.Count; i++)
            {
                if (PrinterName == alPrinters[i].ToString())
                {
                    bolRet = true;
                    break;
                }
            }

            alPrinters.Clear();
            alPrinters = null;

            return bolRet;
        }

        ///// <summary>
        ///// 判断表单是否在指定的打印机所支持的纸张列表中
        ///// </summary>
        ///// <param name="PrinterName">打印机名称</param>
        ///// <param name="PaperName">纸张名称</param>
        ///// <returns>是:在;否:不在</returns>
        public static bool FormInPrinter(string PrinterName, string PaperName)
        {
            bool bolRet = false;

            System.Drawing.Printing.PrintDocument pd = new System.Drawing.Printing.PrintDocument();

            pd.PrinterSettings.PrinterName = PrinterName;

            foreach (System.Drawing.Printing.PaperSize ps in pd.PrinterSettings.PaperSizes)
            {
                if (ps.PaperName == PaperName)
                {
                    bolRet = true;
                    break;
                }
            }

            pd.Dispose();

            return bolRet;
        }

        /// <summary>
        /// 判断指定纸张的宽度和高度和在文本框中指定的宽度和高度是否匹配
        /// </summary>
        /// <param name="PrinterName">打印机名称</param>
        /// <param name="FormName">表单名称</param>
        /// <param name="Width">宽度</param>
        /// <param name="Height">高度</param>
        /// <returns></returns>
        public static bool FormSameSize(string PrinterName, string FormName, decimal Width, decimal Height)
        {
            bool bolRet = false;

            System.Drawing.Printing.PrintDocument pd = new System.Drawing.Printing.PrintDocument();

            pd.PrinterSettings.PrinterName = PrinterName;

            foreach (System.Drawing.Printing.PaperSize ps in pd.PrinterSettings.PaperSizes)
            {
                if (ps.PaperName == FormName)
                {
                    decimal decWidth = FromInchToCM(System.Convert.ToDecimal(ps.Width));
                    decimal decHeight = FromInchToCM(System.Convert.ToDecimal(ps.Height));
                    //只要整数位相同即认为是同一纸张,毕竟inch到cm的转换并不能整除
                    if (Pub.MathEx.Round(decWidth, 0) == Pub.MathEx.Round(Width, 0) && Pub.MathEx.Round(decHeight, 0) == Pub.MathEx.Round(Height, 0))
                        bolRet = true;
                    break;
                }
            }

            pd.Dispose();

            return bolRet;
        }

        /// <summary>
        /// 英尺到厘米的转换
        /// 米国人用的是英尺,中国人用的是厘米
        /// 1 inch = 2.5400 cm
        /// </summary>
        /// <param name="inch">英尺数</param>
        /// <returns>厘米数,两位小数</returns>
        public static decimal FromInchToCM(decimal inch)
        {
            return Math.Round((System.Convert.ToDecimal((inch / 100)) * System.Convert.ToDecimal(2.5400)), 2);
        }
    }
}

        页面设置窗体由报表浏览器窗体ReportViewer调用,使用以下结构的XML文件存储针对每个报表的页面设置:

<? xml version="1.0" standalone="yes" ?>  
< ReportSettings >  
    
< 采购订单 >  
        
< ReportName > 采购订单 </ ReportName >  
        
< PrinterName > EPSON LQ-1600KIII </ PrinterName >  
        
< PaperName > Test </ PaperName >  
        
< PageWidth > 8.00 </ PageWidth >  
        
< PageHeight > 8.00 </ PageHeight >  
        
< MarginTop > 0.2 </ MarginTop >  
        
< MarginBottom > 0.2 </ MarginBottom >  
        
< MarginLeft > 0.2 </ MarginLeft >  
        
< MarginRight > 0.2 </ MarginRight >  
        
< Orientation > 横向 </ Orientation >  
    
</ 采购订单 >  
</ ReportSettings >

        当然,这种格式的XML配置文件是用DataSet来读写更新的,因为这种方法比较简单。

        页面设置窗体上有一个关于打印方向的设置,在(六)中有一个问题忘记阐述了,就是关于打印方向的。因为DeviceInfo结构中并没有打印方向的设置, 所以在生成DeviceInfo结构的字符串时,应该根据打印方向来设置DeviceInfo结构的页高和页宽,见(五)中给出的 EMFDeviceInfo类的属性DeviceInfoString。放在这里补充说一下。

        完整的页面设置窗体的代码下载

RDLC报表(八)

        代码的主要内容是如何对RDLC报表进行自定义纸张单据打印

        下载内容包括:

        在其它窗体调用报表浏览器的代码如下:

// 创建报表浏览器对象
RDLCReport.ReportViewer frmRPT  =   new  RDLCReport.ReportViewer();
// 指定列表报表显示的数据源,这个例子写的比较死,建议修改MainDataSet和DrillDataSet为System.Data.DataTable类型,这样可以更方便的调用
frmRPT.MainDataSet  =   this .dsMain;
// 为列表报表设置数据源名称,这必须和报表中的数据区域的数据源名称相同
frmRPT.MainDataSourceName  =   " DataSet_Main " ;
// 报表名称,这是用来存储报表页面设置的标识
frmRPT.ReportName  =   " DataList " ;
// 指定钻取报表的数据源
frmRPT.DrillDataSet  =   this .dsDrill;
// 指定钻取报表的数据源名称
frmRPT.DrillDataSourceName  =   " DataSet_Drill " ;
// 指定报表路径
frmRPT.ReportPath  =  System.Windows.Forms.Application.StartupPath  +   @" \Reports\rptReport.rdlc " ;
// 显示报表浏览器
frmRPT.ShowDialog();

        
        相关随笔:
            RDLC报表(一) 
            RDLC报表(二) 
            RDLC报表(三) 
            RDLC报表(四) 
            RDLC报表(五) 
            RDLC报表(六)  

 

转载于:https://www.cnblogs.com/JuneZhang/archive/2013/01/11/2855762.html

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/diaoshanwai2368/article/details/102220603

智能推荐

Eclipse 插件精选介绍 -程序员宅基地

文章浏览阅读91次。Eclipse插件之EasyExplorer http://dev2dev.bea.com.cn/bbsdoc/20060124184.html&nbsp;能够在 Eclipse 里面打开资源管理器来浏览当前选中的文件.可以在选项里面输入命令:explorer.exe /n,/e,{0}来打开一个显示树和文件夹内容的浏览窗口. 通过对以上explorer.exe的参数分析,我们可能会有个希..._eclipse插件介绍

牛客真题(35)-青草游戏_给出m个草的点燃位置,在第c秒点燃,最后有几种食物烤熟-程序员宅基地

文章浏览阅读155次。今天继续刷牛客真题,青草游戏分析:找规律,通过规律,判断游戏的输赢。问题:1、Python中if else 的简写方式;方式C++代码:#include<iostream>using namespace std;int main(){ int n; cin>>n; int a[n]; for(int i=0;i<n;i..._给出m个草的点燃位置,在第c秒点燃,最后有几种食物烤熟

ASP.NET MVC Model验证(一)_asp.net viewmodel 验证-程序员宅基地

文章浏览阅读1.2k次。前面对于Model绑定部分作了大概的介绍,从这章开始就进入Model验证部分了,这个实际上是一个系列的Model的绑定往往都是伴随着验证的。也会在后面的篇幅中讲解MVC框架中Model验证的机制,以及一些Model验证的方式讲解,本章只是一个简单的示例篇幅,对于有基础的朋友可以直接跳过了(不能耽误大家时间)。_asp.net viewmodel 验证

内核驱动 (五)看门狗_ida_simple_get-程序员宅基地

文章浏览阅读1.6k次。尽管在linux系统中,对于S3C2440开发板来说,默认是已经配置了看门狗定时器,如:Device Drivers ---&gt; [*] Watchdog Timer Support ---&gt; [*] Disable watchdog shutdown on close (NEW) //如果选中, 用户一旦 open 看门狗..._ida_simple_get

iPhone/iOS图片相关(读取、保存、绘制、其它相关)_ios cglayergetcontext-程序员宅基地

文章浏览阅读3.2w次,点赞3次,收藏26次。一.读取图片1.从资源(resource)读取UIImage* image=[UIImage imageNamed:@"1.jpg"];2.从网络读取NSURL *url=[NSURL URLWithString:@"http://www.sinaimg.cn/qc/photo_auto/chezhan/2012/50/00/15/80046_950.jpg"];UIImag_ios cglayergetcontext

某城市电话号码由三部分组成,分别是:      地区码—— 空白或三位数字;      前缀—— 非‘0’或‘1’开头的三位数字;      后缀—— 4位数字。_某城市电话号码由三部分组成,分别是: 地区码:空白或3位数字; 前缀:非0或1开头的3-程序员宅基地

文章浏览阅读1.3w次,点赞6次,收藏42次。软件测试技术(第二版)题目:某城市电话号码由三部分组成,分别是:地区码——空白或三位数字;前缀——非‘0’或‘1’开头的三位数字;后缀—— 4位数字。假定被测程序能接受一切符合上述规定的电话号码, 拒绝所有不符合规定的电话号码。要求:(1)请选择适当的黑盒测试方法,写出选择该方法的原因,并使用该方法的步骤,给出测试用例表。(2)如果所生成的测试用例不够全面,请考虑用别的测试方法生成一些补充的测试用例。..._某城市电话号码由三部分组成,分别是: 地区码:空白或3位数字; 前缀:非0或1开头的3

随便推点

【抽象代数概念速查】magic square-幻方_magic square线性代数-程序员宅基地

文章浏览阅读240次。如果对角线和反对角线的数加和也都等于magic number_magic square线性代数

CGLIB原理及实现机制学习_cglib methoddelegate-程序员宅基地

文章浏览阅读330次。什么是CGLIBCGLIB(Code Generator Library)是一个强大的、高性能的代码生成库。其被广泛应用于AOP框架(Spring、dynaop)中,用以提供方法拦截操作。Hibernate作为一个比较受欢迎的ORM框架,同样使用CGLIB来代理单端(多对一和一对一)关联(延迟提取集合使用的另一种机制)。为什么使用CGLIBCGLIB代理主要通过对字节码的操作,为对象引入间接级别,以控制对象的访问。我们知道Java中有一个动态代理也是做这个事情的,那我们为什么不直接使用Java动态_cglib methoddelegate

感恩过去,憧憬未来 | 数图2023年成长回顾-程序员宅基地

文章浏览阅读349次,点赞5次,收藏7次。龙腾千里,不忘初心,展望2024年,我们将继续秉持以客户为中心的服务理念,进一步提升产品质量,加大技术创新力度,以满足市场的不断变化和客户的需求,致力于为合作客户企业达成降本增效的良好成果。我们坚信,在全体员工的共同努力下,我们将在新的一年里取得更加丰硕的成果,为公司的未来发展奠定更加坚实的基础,也为我们在零售业和服务领域的广阔前景描绘更加美好的蓝图。数图在2023年取得了丰硕的成果,不仅在合作企业、荣誉奖项、员工规模等方面有了显著提升,还在质量管理、技术创新等方面展现了卓越的实力。岁月不居,时节如流。

JSON详解_json(json(appendix)->0)-程序员宅基地

文章浏览阅读294次。JSON的全称是”JavaScript Object Notation”,意思是JavaScript对象表示法,它是一种基于文本,独立于语言的轻量级数据交换格式。XML也是一种数据交换格式,为什么没有选择XML呢?因为XML虽然可以作为跨平台的数据交换格式,但是在JS(JavaScript的简写)中处理XML非常不方便,同时XML标记比数据多,增加了交换产生的流量,而JSON没有附加的任何标记,在_json(json(appendix)->0)

numpy 找到矩阵中值为nan的元素 numpy.isnan_numpy找出矩阵中nan值-程序员宅基地

文章浏览阅读4.4k次。numpy.isnan(a,axis=None,keepdims=no value)官方文档Test element-wise for NaN and return result as a boolean array.示例import numpy as npa = np.array([[1, 2], [3, np.nan]])print(np.isnan(a))结果[[False False] [False True]]_numpy找出矩阵中nan值

如何防止用一用户同时登陆-程序员宅基地

文章浏览阅读63次。记录用户登陆信息[登陆时间,用户ID]每隔一段时间(如5秒怎么样?)检查存储的登陆信息。如果发现多个,则比较各个的登陆时间,如果自己用的登陆时间比其他的早,则提示并注销。实现:1.把所有登陆用户存在这个全局Application中(建议把这个Application放在基类,方便调用):protected IList<IList> LoginInfo..._如何保证一个账号不允许同时登录