C#之Windows自帶打印功能的實(shí)現(xiàn)
接著上回說(shuō),在使用打印機(jī)自帶的SDK開(kāi)發(fā)失利只后,經(jīng)過(guò)一系列的實(shí)驗(yàn),發(fā)現(xiàn),這個(gè)打印機(jī)可以直接用我安裝好的驅(qū)動(dòng)直接進(jìn)行打印操作,用word直接調(diào)整好字體之后打印是完全沒(méi)有問(wèn)題的,所以,推測(cè),應(yīng)該可以直接調(diào)用人家封裝好的一些驅(qū)動(dòng)進(jìn)行打印,但是要怎么連接這些驅(qū)動(dòng)呢?
一、打印控件
首先我們要提到的就是在C#中的一個(gè)關(guān)于打印的控件了,叫:PrintDocument,說(shuō)他是一個(gè)控件,其實(shí)也就是一個(gè)關(guān)于windows打印的屬性和代碼的集合而已,但是結(jié)合著windows自帶的一些對(duì)話框窗體,我們可以輕而易舉的做一個(gè)打印的小程序。
我們要做的是,首先建立一個(gè)窗體,然后從工具箱中找到PrintDocument這個(gè)控件,然后添加上就可以了,可以看到控件的屬性是這樣的:
并沒(méi)有什么特殊的地方,但是在方法里面卻有一個(gè)很重要的方法,那就是他的printPage這個(gè)方法,這個(gè)就是每次觸發(fā)這個(gè)控件的打印的內(nèi)容核心,先貼上如下代碼:
private void pd1_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e) { Graphics g = e.Graphics; //獲得繪圖對(duì)象 float linesPerPage = 0; //頁(yè)面的行號(hào) float yPosition = 0; //繪制字符串的縱向位置 int count = 0; //行計(jì)數(shù)器 float leftMargin = 1; //左邊距 float topMargin = 1; //上邊距 string line = ""; //行字符串 Font printFont = this.textBox1.Font; //當(dāng)前的打印字體 SolidBrush myBrush = new SolidBrush(Color.Black);//刷子 linesPerPage = e.MarginBounds.Height / printFont.GetHeight(g);//每頁(yè)可打印的行數(shù) //逐行的循環(huán)打印一頁(yè) while (count < linesPerPage && ((line = lineReader.ReadLine()) != null)) { yPosition = topMargin + (count * printFont.GetHeight(g)); g.DrawString(line, printFont, myBrush, leftMargin, yPosition, new StringFormat()); count++; } // 注意:使用本段代碼前,要在該窗體的類中定義lineReader對(duì)象: // StringReader lineReader = null; //如果本頁(yè)打印完成而line不為空,說(shuō)明還有沒(méi)完成的頁(yè)面,這將觸發(fā)下一次的打印事件。在下一次的打印中l(wèi)ineReader會(huì) //自動(dòng)讀取上次沒(méi)有打印完的內(nèi)容,因?yàn)閘ineReader是這個(gè)打印方法外的類的成員,它可以記錄當(dāng)前讀取的位置 if (line != null) e.HasMorePages = true; else { e.HasMorePages = false; // 重新初始化lineReader對(duì)象,不然使用打印預(yù)覽中的打印按鈕打印出來(lái)是空白頁(yè) lineReader = new StringReader(textBox1.Text); // textBox是你要打印的文本框的內(nèi)容 } }
這里需要注意的是,使用了lineReader這個(gè)類的對(duì)象,這個(gè)對(duì)象的特點(diǎn)就是可以把對(duì)象中賦值的字符串按照行(以\r\n為準(zhǔn)的換行)來(lái)進(jìn)行字符串的獲取,上面代碼中的line就是指的獲得的一行的數(shù)據(jù)。
我們用system.draw的Graphics里面的繪圖對(duì)象來(lái)進(jìn)行基本的字符繪圖,最后把繪圖對(duì)象打印到我們紙上,就是這個(gè)打印里面的內(nèi)容。
所以,我們這個(gè)里面需要引入的一個(gè)引用就是using System.Drawing.Printing; 這樣整個(gè)控件加代碼就可以運(yùn)行了,說(shuō)明一下,這個(gè)打印的調(diào)用需要觸發(fā),使用的是如下代碼:
lineReader = new StringReader(stb.ToString()); // 獲取要打印的字符串 pd1.Print(); //執(zhí)行打印方法
另外說(shuō)明一下,這里執(zhí)行的時(shí)候,有一些輔助設(shè)置,比如打印預(yù)覽,打印機(jī)使用的默認(rèn)的,還有頁(yè)面的配置等都是有專門的對(duì)話框,我把他們都放在了菜單里面,
如圖:
下面我們來(lái)說(shuō)一下他們的實(shí)現(xiàn),其實(shí)很是簡(jiǎn)單:
打印設(shè)置:
private void FileMenuItem_PrintSet_Click(object sender, EventArgs e) { PrintDialog printDialog = new PrintDialog(); printDialog.Document = pd1; printDialog.ShowDialog(); }
頁(yè)面設(shè)置:
private void FileMenuItem_PageSet_Click(object sender, EventArgs e) { PageSetupDialog pageSetupDialog = new PageSetupDialog(); pageSetupDialog.Document = pd1; pageSetupDialog.ShowDialog(); }
打印預(yù)覽:
private void FileMenuItem_PrintView_Click(object sender, EventArgs e) { PrintPreviewDialog printPreviewDialog = new PrintPreviewDialog(); printPreviewDialog.Document = pd1; lineReader = new StringReader(stb.ToString()); try { printPreviewDialog.ShowDialog(); } catch(Exception excep) { MessageBox.Show(excep.Message, "打印出錯(cuò)", MessageBoxButtons.OK, MessageBoxIcon.Error); } }
這些頁(yè)面里面的設(shè)置在選擇保存的時(shí)候會(huì)自動(dòng)存儲(chǔ)到Graphic對(duì)象當(dāng)中,因此,可以配置之后使用。
二、系統(tǒng)API接口
既然有系統(tǒng)定制的控件,那么系統(tǒng)的接入API肯定也少不了,不過(guò),我目前從網(wǎng)絡(luò)上找到的只有一小部分而已,并且都是一些獲取配置,設(shè)置默認(rèn)等一些列的代碼,在此分享給大家
using System; using System.Text; using System.Runtime.InteropServices; using System.Security; using System.ComponentModel; using System.IO; namespace WindowsFormsApplication1 { public class PrinterHelper { private PrinterHelper(){ } #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); [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用到的函數(shù)和結(jié)構(gòu)體 [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 } //打印機(jī)狀態(tài) [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函數(shù)說(shuō)明 [DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)] internal static extern bool GetDefaultPrinter(StringBuilder pszBuffer, ref int size); //SetDefaultPrinter用到的API函數(shù)聲明 [DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)] internal static extern bool SetDefaultPrinter(string Name); //EnumFormsA用到的函數(shù)聲明,應(yīng)該和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 API聲明 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]; } } #region 獲取當(dāng)前指定打印機(jī)的狀態(tài) /// </summary> /// 獲取當(dāng)前指定打印機(jī)的狀態(tài) /// </summary> /// <param name="PrinterName">打印機(jī)名稱</param> /// <returns>打印機(jī)狀態(tài)描述</returns> public static string GetPrinterStatus(string PrinterName) { int intValue = GetPrinterStatusInt(PrinterName); string strRet = string.Empty; switch (intValue) { case 0: strRet = "準(zhǔn)備就緒(Ready)"; break; case 0x00000200: strRet = "忙(Busy)"; break; case 0x00400000: strRet = "門被打開(kāi)(Printer Door Open)"; break; case 0x00000002: strRet = "錯(cuò)誤(Printer Error)"; break; case 0x0008000: strRet = "正在初始化(Initializing)"; break; case 0x00000100: strRet = "正在輸入或輸出(I/O Active)"; break; case 0x00000020: strRet = "手工送紙(Manual Feed)"; break; case 0x00040000: strRet = "無(wú)墨粉(No Toner)"; break; case 0x00001000: strRet = "不可用(Not Available)"; break; case 0x00000080: strRet = "脫機(jī)(Off Line)"; break; case 0x00200000: strRet = "內(nèi)存溢出(Out of Memory)"; break; case 0x00000800: strRet = "輸出口已滿(Output Bin Full)"; break; case 0x00080000: strRet = "當(dāng)前頁(yè)無(wú)法打?。≒age Punt)"; break; case 0x00000008: strRet = "塞紙(Paper Jam)"; break; case 0x00000010: strRet = "打印紙用完(Paper Out)"; break; case 0x00000040: strRet = "紙張問(wèn)題(Page Problem)"; break; case 0x00000001: strRet = "暫停(Paused)"; break; case 0x00000004: strRet = "正在刪除(Pending Deletion)"; break; case 0x00000400: strRet = "正在打?。≒rinting)"; break; case 0x00004000: strRet = "正在處理(Processing)"; break; case 0x00020000: strRet = "墨粉不足(Toner Low)"; break; case 0x00100000: strRet = "需要用戶干預(yù)(User Intervention)"; break; case 0x20000000: strRet = "等待(Waiting)"; break; case 0x00010000: strRet = "正在準(zhǔn)備(Warming Up)"; break; default: strRet = "未知狀態(tài)(Unknown Status)"; break; } return strRet; } #endregion 獲取當(dāng)前指定打印機(jī)的狀態(tài) #region 刪除已經(jīng)存在的自定義紙張 /**/ /// <summary> /// 刪除已經(jīng)存在的自定義紙張 /// </summary> /// <param name="PrinterName">打印機(jī)名稱</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; //打開(kāi)打印機(jī) if (OpenPrinter(PrinterName, out hPrinter, ref defaults)) { try { DeleteForm(hPrinter, PaperName); ClosePrinter(hPrinter); } catch { } } } #endregion 刪除已經(jīng)存在的自定義紙張 #region 指定的打印機(jī)設(shè)置以mm為單位的自定義紙張(Form) /**/ /// <summary> /// 指定的打印機(jī)設(shè)置以mm為單位的自定義紙張(Form) /// </summary> /// <param name="PrinterName">打印機(jī)名稱</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; structPrinterDefaults defaults = new structPrinterDefaults(); defaults.pDatatype = null; defaults.pDevMode = IntPtr.Zero; defaults.DesiredAccess = PRINTER_ACCESS_ADMINISTER | PRINTER_ACCESS_USE; IntPtr hPrinter = IntPtr.Zero; //打開(kāi)打印機(jī) if (OpenPrinter(PrinterName, out hPrinter, ref defaults)) { try { //如果Form存在刪除之 DeleteForm(hPrinter, PaperName); //創(chuàng)建并初始化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("向打印機(jī) {1} 添加自定義紙張 {0} 失?。″e(cuò)誤代號(hào):{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("無(wú)法取得DEVMODE結(jié)構(gòu)的大??!"); //分配緩沖 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("無(wú)法獲得DEVMODE結(jié)構(gòu)!"); //填充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("無(wú)法為打印機(jī)設(shè)定打印方向!"); GetPrinter(hPrinter, 9, IntPtr.Zero, 0, out iPrinterInfoSize); if (iPrinterInfoSize == 0) throw new ApplicationException("調(diào)用GetPrinter方法失敗!"); hPrinterInfo = Marshal.AllocCoTaskMem(iPrinterInfoSize + 100); bool bSuccess = GetPrinter(hPrinter, 9, hPrinterInfo, iPrinterInfoSize, out iDummyInt); if (!bSuccess) throw new ApplicationException("調(diào)用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(), "調(diào)用SetPrinter方法失敗,無(wú)法進(jìn)行打印機(jī)設(shè)置!"); SendMessageTimeout( new IntPtr(HWND_BROADCAST), WM_SETTINGCHANGE, IntPtr.Zero, IntPtr.Zero, PrinterHelper.SendMessageTimeoutFlags.SMTO_NORMAL, 1000, out hDummy); } finally { ClosePrinter(hPrinter); } } else { StringBuilder strBuilder = new StringBuilder(); strBuilder.AppendFormat("無(wú)法打開(kāi)打印機(jī){0}, 錯(cuò)誤代號(hào): {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); } } } #endregion 指定的打印機(jī)設(shè)置以mm為單位的自定義紙張(Form) #region 獲取本地打印機(jī)列表 /**/ /// <summary> /// 獲取本地打印機(jī)列表 /// 可以通過(guò)制定參數(shù)獲取網(wǎng)絡(luò)打印機(jī) /// </summary> /// <returns>打印機(jī)列表</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; } #endregion 獲取本地打印機(jī)列表 #region 獲取本機(jī)的默認(rèn)打印機(jī)名稱 /**/ /// <summary> /// 獲取本機(jī)的默認(rèn)打印機(jī)名稱 /// </summary> /// <returns>默認(rèn)打印機(jī)名稱</returns> public static string GetDeaultPrinterName() { StringBuilder dp = new StringBuilder(256); int size = dp.Capacity; if (GetDefaultPrinter(dp, ref size)) { return dp.ToString(); } else { return string.Empty; } } #endregion 獲取本機(jī)的默認(rèn)打印機(jī)名稱 #region 設(shè)置默認(rèn)打印機(jī) /**/ /// <summary> /// 設(shè)置默認(rèn)打印機(jī) /// </summary> /// <param name="PrinterName">可用的打印機(jī)名稱</param> public static void SetPrinterToDefault(string PrinterName) { SetDefaultPrinter(PrinterName); } #endregion 設(shè)置默認(rèn)打印機(jī) #region 判斷打印機(jī)是否在系統(tǒng)可用的打印機(jī)列表中 /**/ / <summary> / 判斷打印機(jī)是否在系統(tǒng)可用的打印機(jī)列表中 / </summary> / <param name="PrinterName">打印機(jī)名稱</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; } #endregion 判斷打印機(jī)是否在系統(tǒng)可用的打印機(jī)列表中 #region 判斷表單是否在指定的打印機(jī)所支持的紙張列表中 /**/ / <summary> / 判斷表單是否在指定的打印機(jī)所支持的紙張列表中,表單就是我們平常所說(shuō)的紙張 / </summary> / <param name="PrinterName">打印機(jī)名稱</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; } #endregion 判斷表單是否在指定的打印機(jī)所支持的紙張列表中 #region 判斷指定紙張的寬度和高度和與打印內(nèi)容指定的寬度和高度是否匹配 /**/ /// <summary> /// 判斷指定紙張的寬度和高度和與打印內(nèi)容指定的寬度和高度是否匹配 /// </summary> /// <param name="PrinterName">打印機(jī)名稱</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)); //只要整數(shù)位相同即認(rèn)為是同一紙張,畢竟inch到cm的轉(zhuǎn)換并不能整除 if (Math.Round(decWidth, 0) == Math.Round(Width, 0) && Math.Round(decHeight, 0) == Math.Round(Height, 0)) bolRet = true; break; } } pd.Dispose(); return bolRet; } #endregion 判斷指定紙張的寬度和高度和與打印內(nèi)容指定的寬度和高度是否匹配 #region 英寸到厘米的轉(zhuǎn)換 /**/ /// <summary> /// 英寸到厘米的轉(zhuǎn)換 /// /* = = = = = = = = = = = = = = = = *\ /// | 換算一下計(jì)量單位,將其換算成厘米 | /// | 厘米 像素 英寸 | /// | 1 38 0.395 | /// | 0.026 1 0.01 | /// | 2.54 96 1 | /// \* = = = = = = = = = = = = = = = = */ /// </summary> /// <param name="inch">英寸數(shù)</param> /// <returns>厘米數(shù),兩位小數(shù)</returns> /// public static decimal FromInchToCM(decimal inch) { return Math.Round((System.Convert.ToDecimal((inch / 100)) * System.Convert.ToDecimal(2.5400)), 2); } #endregion 英寸到厘米的轉(zhuǎn)換 [DllImport("winspool.Drv", EntryPoint = "OpenPrinterA", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)] public static extern bool OpenPrinter([MarshalAs(UnmanagedType.LPStr)] string szPrinter, out IntPtr hPrinter, IntPtr pd); //[DllImport("winspool.Drv", EntryPoint = "ClosePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)] //public static extern bool ClosePrinter(IntPtr hPrinter); [DllImport("winspool.Drv", EntryPoint = "StartDocPrinterA", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)] public static extern bool StartDocPrinter(IntPtr hPrinter, Int32 level, [In, MarshalAs(UnmanagedType.LPStruct)] DOCINFOA di); [DllImport("winspool.Drv", EntryPoint = "EndDocPrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)] public static extern bool EndDocPrinter(IntPtr hPrinter); [DllImport("winspool.Drv", EntryPoint = "StartPagePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)] public static extern bool StartPagePrinter(IntPtr hPrinter); [DllImport("winspool.Drv", EntryPoint = "EndPagePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)] public static extern bool EndPagePrinter(IntPtr hPrinter); [DllImport("winspool.Drv", EntryPoint = "WritePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)] public static extern bool WritePrinter(IntPtr hPrinter, IntPtr pBytes, Int32 dwCount, out Int32 dwWritten); /// <summary> /// 該方法把非托管內(nèi)存中的字節(jié)數(shù)組發(fā)送到打印機(jī)的打印隊(duì)列 /// </summary> /// <param name="szPrinterName">打印機(jī)名稱</param> /// <param name="pBytes">非托管內(nèi)存指針</param> /// <param name="dwCount">字節(jié)數(shù)</param> /// <returns>成功返回true,失敗時(shí)為false</returns> public static bool SendBytesToPrinter(string szPrinterName, IntPtr pBytes, Int32 dwCount) { Int32 dwError = 0, dwWritten = 0; IntPtr hPrinter = new IntPtr(0); DOCINFOA di = new DOCINFOA(); bool bSuccess = false; di.pDocName = "My C#.NET RAW Document"; di.pDataType = "RAW"; try { // 打開(kāi)打印機(jī) if (OpenPrinter(szPrinterName.Normalize(), out hPrinter, IntPtr.Zero)) { // 啟動(dòng)文檔打印 if (StartDocPrinter(hPrinter, 1, di)) { // 開(kāi)始打印 if (StartPagePrinter(hPrinter)) { // 向打印機(jī)輸出字節(jié) bSuccess = WritePrinter(hPrinter, pBytes, dwCount, out dwWritten); EndPagePrinter(hPrinter); } EndDocPrinter(hPrinter); } ClosePrinter(hPrinter); } if (bSuccess == false) { dwError = Marshal.GetLastWin32Error(); } } catch (Win32Exception ex) { WriteLog(ex.Message); bSuccess = false; } return bSuccess; } /// <summary> /// 發(fā)送文件到打印機(jī)方法 /// </summary> /// <param name="szPrinterName">打印機(jī)名稱</param> /// <param name="szFileName">打印文件的路徑</param> /// <returns></returns> public static bool SendFileToPrinter(string szPrinterName, string szFileName) { bool bSuccess = false; try { // 打開(kāi)文件 FileStream fs = new FileStream(szFileName, FileMode.Open); // 將文件內(nèi)容讀作二進(jìn)制 BinaryReader br = new BinaryReader(fs); // 定義字節(jié)數(shù)組 Byte[] bytes = new Byte[fs.Length]; // 非托管指針 IntPtr pUnmanagedBytes = new IntPtr(0); int nLength; nLength = Convert.ToInt32(fs.Length); // 讀取文件內(nèi)容到字節(jié)數(shù)組 bytes = br.ReadBytes(nLength); // 為這些字節(jié)分配一些非托管內(nèi)存 pUnmanagedBytes = Marshal.AllocCoTaskMem(nLength); // 將托管字節(jié)數(shù)組復(fù)制到非托管內(nèi)存指針 Marshal.Copy(bytes, 0, pUnmanagedBytes, nLength); // 將非托管字節(jié)發(fā)送到打印機(jī) bSuccess = SendBytesToPrinter(szPrinterName, pUnmanagedBytes, nLength); // 釋放先前分配的非托管內(nèi)存 Marshal.FreeCoTaskMem(pUnmanagedBytes); fs.Close(); fs.Dispose(); } catch (Win32Exception ex) { WriteLog(ex.Message); bSuccess = false; } return bSuccess; } /// <summary> /// 將字符串發(fā)送到打印機(jī)方法 /// </summary> /// <param name="szPrinterName">打印機(jī)名稱</param> /// <param name="szString">打印的字符串</param> /// <returns></returns> public static bool SendStringToPrinter(string szPrinterName, string szString) { bool flag = false; try { IntPtr pBytes; Int32 dwCount; // 獲取字符串長(zhǎng)度 dwCount = szString.Length; // 將字符串復(fù)制到非托管 COM 任務(wù)分配的內(nèi)存非托管內(nèi)存塊,并轉(zhuǎn)換為 ANSI 文本 pBytes = Marshal.StringToCoTaskMemAnsi(szString); // 將已轉(zhuǎn)換的 ANSI 字符串發(fā)送到打印機(jī) flag = SendBytesToPrinter(szPrinterName, pBytes, dwCount); // 釋放先前分配的非托管內(nèi)存 Marshal.FreeCoTaskMem(pBytes); } catch (Win32Exception ex) { WriteLog(ex.Message); flag = false; } return flag; } /// <summary> /// 寫(xiě)入日志方法 /// </summary> /// <param name="msg">記錄信息</param> public static void WriteLog(string msg) { string str = string.Empty; string path = AppDomain.CurrentDomain.BaseDirectory + "log\\" + DateTime.Now.ToString("yyyy-MM-dd") + ".txt"; FileStream filestream = new FileStream(path, FileMode.OpenOrCreate); str += "************" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "************\r\n"; str += msg; str += "************" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "************\r\n"; FileStream fs = new FileStream(path, FileMode.Append); StreamWriter sw = new StreamWriter(fs, System.Text.Encoding.Default); sw.WriteLine(str); sw.Flush(); sw.Close(); sw.Dispose(); fs.Close(); fs.Dispose(); } } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] public class DOCINFOA { [MarshalAs(UnmanagedType.LPStr)] public string pDocName; [MarshalAs(UnmanagedType.LPStr)] public string pOutputFile; [MarshalAs(UnmanagedType.LPStr)] public string pDataType; } }
我們可以看到,這些函數(shù)都是調(diào)用的winspool.drv 這個(gè)windows的驅(qū)動(dòng)來(lái)實(shí)現(xiàn)API調(diào)用的,這里我們還真應(yīng)該好好琢磨琢磨。
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
C#實(shí)現(xiàn)讀取DataSet數(shù)據(jù)并顯示在ListView控件中的方法
這篇文章主要介紹了C#實(shí)現(xiàn)讀取DataSet數(shù)據(jù)并顯示在ListView控件中的方法,涉及C#操作DataSet及ListView控件的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-10-10C#用websocket實(shí)現(xiàn)簡(jiǎn)易聊天功能(服務(wù)端)
這篇文章主要為大家詳細(xì)介紹了C#用websocket實(shí)現(xiàn)簡(jiǎn)易聊天功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-02-02c# 實(shí)現(xiàn)圓形的進(jìn)度條(ProgressBar)
這篇文章主要介紹了c# 如何實(shí)現(xiàn)圓形的進(jìn)度條(ProgressBar),幫助大家更好的理解和學(xué)習(xí)使用c#,感興趣的朋友可以了解下2021-03-03C#實(shí)現(xiàn)多線程編程的簡(jiǎn)單案例
這篇文章介紹了C#實(shí)現(xiàn)多線程編程的簡(jiǎn)單案例,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-04-04WCF分布式開(kāi)發(fā)之MSMQ消息隊(duì)列
這篇文章介紹了WCF分布式開(kāi)發(fā)之MSMQ消息隊(duì)列,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-05-05