C# 实现虚拟打印机 HP Color LaserJet 4500 1
无聊了研究了下PCL和HPGL两种语言。如果要实现虚拟打印机只使用.NET来做,驱动是最大的问题。其实我们可以使用已经写好的打印机驱动来实现。只是让驱动最终生成的打印语言输出到我们想要的位置。并且我们对打印语言进行模拟显示就可以。经过几天的研究发现HP Color LaserJet 4500 打印出的图形为PCL和HPGL的混合体。那就写个控制HP Color LaserJet 4500的程序进行控制并且把打印出的打印语言输出到我们想要的位置。
首先 先给系统添加打印机 HP Color LaserJet 4500
其他的设置不用管。用程序来控制把,免得配置复杂以后我自己都忘了怎么配置的。
思路 先给打印机更换端口 使用写注册表 把临时目录放做为打印端口 然后设置打印后保留文档 通过API EnumJobs 获取打印任务 重新执行打印后获取临时文件 ,这里临时文件就是我们需要的PCL/HPGL文件( ImagePRN 这个类 我暂时不贴出来) 因为包含两种打印语言所以这个东西的类我还的找个时间再整理下,到目前为止就10来个类了贴出来太累了。等整理后、成一个类后我会帖出来。
效果图
不说了 先看代码把
测试使用代码
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using System.ComponentModel;
- using System.Data;
- using System.Drawing;
- using System.Drawing.Imaging;
- using System.Text;
- using System.Windows.Forms;
-
- using Zgke.Code;
-
-
- namespace WindowsApplication1
- {
-
-
- public partial class Form1 : Form
- {
-
- public Form1()
- {
- InitializeComponent();
-
- }
-
- /// <summary>
- /// 最终保存PCL文件的路径
- /// </summary>
- private string p_FileDir = @"D:/temp/PCL/";
-
- /// <summary>
- /// 打印控制器
- /// </summary>
- private PrintControlSet m_SetControl;
-
- /// <summary>
- /// PCL文件里的文档
- /// </summary>
- private IList<Image> m_PrintImageList;
-
- private void Form1_Load(object sender, EventArgs e)
- {
- string[] _Filelist = System.IO.Directory.GetFiles(p_FileDir, "*.PCL");
- for (int i = 0; i != _Filelist.Length; i++)
- {
- listBox1.Items.Add(_Filelist[i]);
- }
-
- m_SetControl = new PrintControlSet("Zgke PrintOK", @"C:/1.PRN");
- m_SetControl.PrintJobLoad += new PrintControlSet.PrintJobFile(_SetControl_PrintJobLoad);
- m_SetControl.SaveFileOver += new PrintControlSet.SaveOver(_SetControl_SaveFileOver);
- m_SetControl.StarMonitor();
- }
-
- /// <summary>
- /// 文件复制完成后触发
- /// </summary>
- /// <param name="p_FileName"></param>
- void _SetControl_SaveFileOver(string p_FileName)
- {
- this.Invoke((MethodInvoker)delegate { listBox1.Items.Add(p_FileName); });
- }
-
- /// <summary>
- /// 需要处理时触发 这里可以根据需要写到数据库里。 我只用了日期 并没有使用档名 这个名字可能文件不能创建
- /// </summary>
- /// <param name="p_Document"></param>
- /// <param name="p_PrintDateTime"></param>
- /// <param name="p_MachineName"></param>
- /// <param name="p_UserName"></param>
- /// <param name="p_PageCount"></param>
- /// <param name="p_PrintOK"></param>
- /// <param name="p_SaveFileName"></param>
- void _SetControl_PrintJobLoad(string p_Document, DateTime p_PrintDateTime, string p_MachineName, string p_UserName, int p_PageCount, out bool p_PrintOK, out string p_SaveFileName)
- {
- p_PrintOK = true;
- p_SaveFileName = p_FileDir +p_PrintDateTime.ToString("yyyyMMddHHmmssffff")+".PCL";
- }
-
- private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
- {
- pictureBox1.Image = m_PrintImageList[comboBox1.SelectedIndex];
- }
-
- private void listBox1_DoubleClick(object sender, EventArgs e)
- {
- if (listBox1.SelectedItem == null) return;
- comboBox1.Items.Clear();
- ImagePRN _HPGL = new ImagePRN(listBox1.SelectedItem.ToString());
- m_PrintImageList = _HPGL.PrintBitmap;
- for (int i = 0; i != m_PrintImageList.Count; i++)
- {
- comboBox1.Items.Add(i.ToString());
- }
- if (m_PrintImageList.Count != 0) comboBox1.SelectedIndex = 0;
- }
-
-
-
- }
- }
下面是打印控制的类
- using System;
- using System.Collections.Generic;
- using System.Text;
- using System.Drawing.Printing;
- using System.Threading;
- using System.Runtime.InteropServices;
-
-
-
- namespace Zgke.Code
- {
- /// <summary>
- /// zgke@sina.com
- /// qq:116149
- /// 虚拟打印机控制器
- /// </summary>
- public class PrintControlSet
- {
- // <summary>
- /// 保存文件
- /// </summary>
- /// <param name="p_Document">文档名称</param>
- /// <param name="p_PrintDateTime">打印日期</param>
- /// <param name="p_MachineName">计算机名</param>
- /// <param name="p_UserName">用户名</param>
- /// <param name="p_PageCount">用户名</param>
- /// <param name="m_PrintOK">是否处理完成 如果为false 那下次监控还会触发这个</param>
- /// <param name="p_SaveFileName">保存PRN文件到指定的位置</param>
- public delegate void PrintJobFile(string p_Document,DateTime p_PrintDateTime,string p_MachineName,string p_UserName,int p_PageCount, out bool m_PrintOK,out string p_SaveFileName);
- /// <summary>
- /// 获取打印事件
- /// </summary>
- public event PrintJobFile PrintJobLoad;
-
- /// <summary>
- /// 保存完成
- /// </summary>
- /// <param name="p_FileName">复制完成后的文件位置</param>
- public delegate void SaveOver(string p_FileName);
- /// <summary>
- /// 保存完成
- /// </summary>
- public event SaveOver SaveFileOver;
-
- /// <summary>
- /// 监视线程
- /// </summary>
- private System.Timers.Timer m_Timer;
-
- /// <summary>
- /// 设置时间间隔
- /// </summary>
- public double Interval { get { return m_Timer.Interval; } set { m_Timer.Interval = value; } }
-
- /// <summary>
- /// 打印器名称
- /// </summary>
- private string m_PrintName = "";
-
- /// <summary>
- /// 打印临时目录
- /// </summary>
- private string m_TempFile = "";
-
- /// <summary>
- /// 打印设置器 先去安装 HP Color LaserJet 4500 打印机
- /// </summary>
- /// <param name="p_PrintName"></param>
- public PrintControlSet(string p_PrintName,string p_TempFile)
- {
- if (p_PrintName.Length == 0) throw new Exception("必须指定打印机名称!");
- m_PrintName = p_PrintName;
- m_TempFile = p_TempFile;
- m_Timer = new System.Timers.Timer();
- m_Timer.Interval = 1000;
- m_Timer.Elapsed += new System.Timers.ElapsedEventHandler(m_Timer_Elapsed);
- Microsoft.Win32.RegistryKey _Regisity = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(@"SOFTWARE/Microsoft/Windows NT/CurrentVersion/Print/Printers");
-
- string[] _PrintName =_Regisity.GetSubKeyNames();
- for (int i = 0; i != _PrintName.Length; i++)
- {
- if (_PrintName[i] == m_PrintName)
- {
- AddPort();
- SetPrintAttrib();
- RestSpooler();
- return;
- }
- }
- throw new Exception("无法找到对应的打印机!");
- }
-
- /// <summary>
- /// 监控打印缓冲区
- /// </summary>
- /// <param name="sender"></param>
- /// <param name="e"></param>
- void m_Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
- {
- m_Timer.Stop();
- IntPtr _PrintIntPtr = IntPtr.Zero;
- IntPtr _PrintDefault = IntPtr.Zero;
-
- bool A = Win32API.OpenPrinter("Zgke PrintOK", out _PrintIntPtr, _PrintDefault);
-
- uint _dwNeeded;
- uint _dwReturned;
-
- for (int i = 0; i != 65535; i++)
- {
- IntPtr _JobIntPtr = Marshal.AllocHGlobal(1000);
- Win32API.EnumJobs(_PrintIntPtr, (uint)i, 1, 1, _JobIntPtr, 1000, out _dwNeeded, out _dwReturned);
- if (_dwReturned == 0)
- {
- Marshal.FreeHGlobal(_JobIntPtr);
- break;
- }
-
- JOB_INFO_1 _JobInfo = (JOB_INFO_1)Marshal.PtrToStructure(_JobIntPtr, typeof(JOB_INFO_1));
-
- if (_JobInfo.Status != 128)
- {
- Marshal.FreeHGlobal(_JobIntPtr);
- continue;
- }
- DateTime _PrintTime = new DateTime(_JobInfo.Submitted.wYear, _JobInfo.Submitted.wMonth, _JobInfo.Submitted.wDay, _JobInfo.Submitted.wHour, _JobInfo.Submitted.wMinute, _JobInfo.Submitted.wSecond, _JobInfo.Submitted.wMilliseconds);
- if (PrintJobLoad != null)
- {
- bool _PrintOK = false;
- string _SaveFile = "";
- PrintJobLoad(_JobInfo.pDocument, _PrintTime, _JobInfo.pMachineName, _JobInfo.pUserName, _JobInfo.TotalPages, out _PrintOK, out _SaveFile);
- if (_PrintOK)
- {
- int _State = Win32API.SetJob(_PrintIntPtr, _JobInfo.JobId, 0, IntPtr.Zero, JOB_CONTROL.JOB_CONTROL_RESTART);
- WaitForPrintOver(_PrintIntPtr, i);
- if (_SaveFile.Length != 0)System.IO.File.Copy(m_TempFile, _SaveFile, true);
- _State = Win32API.SetJob(_PrintIntPtr, _JobInfo.JobId, 0, IntPtr.Zero, JOB_CONTROL.JOB_CONTROL_CANCEL);
- if (SaveFileOver != null) SaveFileOver(_SaveFile);
- }
- Marshal.FreeHGlobal(_JobIntPtr);
- }
- }
- Win32API.ClosePrinter(_PrintIntPtr);
- m_Timer.Start();
- }
-
- /// <summary>
- /// 等待打印完成
- /// </summary>
- /// <param name="p_JobId">任务ID</param>
- public void WaitForPrintOver(IntPtr p_PrintIntPtr, int p_JobId)
- {
- while (true)
- {
- uint _dwNeeded;
- uint _dwReturned;
- IntPtr _JobIntPtr = Marshal.AllocHGlobal(1000);
- Win32API.EnumJobs(p_PrintIntPtr, (uint)p_JobId, 1, 1, _JobIntPtr, 1000, out _dwNeeded, out _dwReturned);
- if (_dwReturned != 0)
- {
- JOB_INFO_1 _JobInfo = (JOB_INFO_1)Marshal.PtrToStructure(_JobIntPtr, typeof(JOB_INFO_1));
- if (_JobInfo.Status == 128) return;
- }
- System.Windows.Forms.Application.DoEvents();
- Marshal.FreeHGlobal(_JobIntPtr);
- }
- }
-
- /// <summary>
- /// 添加一个端口
- /// </summary>
- private void AddPort()
- {
- Microsoft.Win32.RegistryKey _Regisity = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(@"SOFTWARE/Microsoft/Windows NT/CurrentVersion/Ports",true);
- string[] _ValueName = _Regisity.GetValueNames();
- for (int i = 0; i != _ValueName.Length; i++)
- {
- if (_ValueName[i] == m_TempFile) return;
- }
- _Regisity.SetValue(m_TempFile, "", Microsoft.Win32.RegistryValueKind.String);
- }
-
- /// <summary>
- /// 设置打印机属性
- /// </summary>
- private void SetPrintAttrib()
- {
- Microsoft.Win32.RegistryKey _Regisity = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(@"SOFTWARE/Microsoft/Windows NT/CurrentVersion/Print/Printers/"+m_PrintName,true);
- int _Attrib = (int)_Regisity.GetValue("Attributes");
- _Attrib |= 0x100;
- _Regisity.SetValue("Attributes", _Attrib);
- _Regisity.SetValue("Port", m_TempFile);
- }
-
- /// <summary>
- /// 重新启动服务
- /// </summary>
- private void RestSpooler()
- {
- System.ServiceProcess.ServiceController[] _Spooler = System.ServiceProcess.ServiceController.GetServices();
- for (int i = 0; i != _Spooler.Length; i++)
- {
- if (_Spooler[i].ServiceName == "Spooler")
- {
- if (_Spooler[i].Status != System.ServiceProcess.ServiceControllerStatus.Stopped)
- {
- _Spooler[i].Stop();
- _Spooler[i].WaitForStatus(System.ServiceProcess.ServiceControllerStatus.Stopped);
- }
- _Spooler[i].Start();
- _Spooler[i].WaitForStatus(System.ServiceProcess.ServiceControllerStatus.Running);
- }
- }
-
- }
-
- /// <summary>
- /// 开始监控
- /// </summary>
- public void StarMonitor()
- {
- m_Timer.Start();
- }
-
- /// <summary>
- /// 停止监控
- /// </summary>
- public void StopMonitor()
- {
- m_Timer.Stop();
- }
-
- }
-
-
- public class Win32API
- {
-
- [DllImport("winspool.drv", EntryPoint = "EnumJobsA")]
- public static extern bool EnumJobs(IntPtr hPrinter, uint FirstJob, uint NoJobs, uint Level, IntPtr pJob, uint cdBuf, out uint pcbNeeded, out uint pcReturned);
-
- [DllImport("winspool.drv", EntryPoint = "SetJob")]
- public static extern int SetJob(IntPtr hPrinter, int JobId, int Level, IntPtr pJob, JOB_CONTROL Command);
-
-
- [DllImport("winspool.drv", CharSet = CharSet.Auto)]
- public static extern bool OpenPrinter(string pPrinterName, out IntPtr phPrinter, IntPtr pDefault);
-
- [DllImport("winspool.drv", CharSet = CharSet.Auto)]
- public static extern bool ClosePrinter(IntPtr ptrPrinter);
- }
-
- public enum JOB_CONTROL
- {
- JOB_CONTROL_PAUSE = 1,
- JOB_CONTROL_RESUME = 2,
- JOB_CONTROL_CANCEL = 3,
- JOB_CONTROL_RESTART = 4
- }
-
- [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
- public struct JOB_INFO_1
- {
- public int JobId;
- [MarshalAs(UnmanagedType.LPStr)]
- public string pPrinterName;
- [MarshalAs(UnmanagedType.LPStr)]
- public string pMachineName;
- [MarshalAs(UnmanagedType.LPStr)]
- public string pUserName;
- [MarshalAs(UnmanagedType.LPStr)]
- public string pDocument;
- [MarshalAs(UnmanagedType.LPStr)]
- public string pDatatype;
- [MarshalAs(UnmanagedType.LPStr)]
- public string pStatus;
- public int Status;
- public int Priority;
- public int Position;
- public int TotalPages;
- public int PagesPrinted;
- public SYSTEMTIME Submitted;
- }
-
- [StructLayout(LayoutKind.Sequential)]
- public struct SYSTEMTIME
- {
- public short wYear;
- public short wMonth;
- public short wDayOfWeek;
- public short wDay;
- public short wHour;
- public short wMinute;
- public short wSecond;
- public short wMilliseconds;
- }
-
- }
下一篇 我会把PCL/HPGL的类贴出来。
|