打印系统开发(62)——C# 实现虚拟打印机 HP Color LaserJet 4500 (1)

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的类贴出来。

  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值