C#打印机监控程序

news/2024/11/28 13:54:45/


一、需求

      由于公司打印纸张浪费比较严重,领导要求对所有的打印进行记录。对比了几款商业软件有的功能比较强大但是价格比较贵而且好多功能并不需要,而有的功能又过于简单。我需要的只是对打印进行记录并不需要计费等功能,而且考虑最好可以和公司现有的OA系统整合在一起,让领导在OA的界面中就可以查询到打印记录,最后决定尝试自己动手进行开发。

二、查找资料

      由于平时用C#比较多一些所以首先查找了一些用C#写的开源程序,但是由于版本都比较老了根本无法运行。又找到一个C++写的可以运行但是C++实在是搞不定,也不是一两天能学会的所以放弃。虽然找了两天没有找到可以运行的完整的程序,但是确定了一个方向,就是调用Windows API函数Enumjobs来获得打印记录。并且还搜到了一份现成的用C#调用Enumjobs的代码,虽然不完整但是确实可以用。

三、规划

     1、首先程序需要安装到打印服务器所以最好是以服务的方式运行

     2、需要通过配置文件来确定需要监控的打印机

四、开始动手

     1、新建一个服务

          (1)首先打开Visual studio 2008,新建一个windows service

          (2)在Service1上点右键选Add Installer

image

        (3)在ProjectInstaller中设置好服务的运行账号和相关设置

            serviceProcessInstaller1 设置属性account为LocalSystem

            serviceInstaller1 设置属性starttype为Automatic

        (4)添加一个timer

            注意这里不能添加工具栏那个,要添加System.timer命名空间下的

       (5)设置服务运行时启动timer

 

 
  1. protected override void OnStart(string[] args) 
  2.     timer1.Enabled = true

(6)定时调用监控程序

 

 
  1. private void timer1_Elapsed(object sender, System.Timers.ElapsedEventArgs e) 
  2.     pm.peekPrinterJobs(config.GetPrinterName()); 

(7)读取配置文件

 

 
  1. private static string ReadXml(string nodeName, string attr) 
  2.     XmlDocument xml = new XmlDocument(); 
  3.     xml.Load("config.xml"); 
  4.     return xml.SelectSingleNode("config/" + nodeName).Attributes[attr].Value; 
  5.  
  6. public static string GetPrinterName() 
  7.     return ReadXml("printer""name"); 
  8. }        public static string GetOutputPath() 
  9.     return ReadXml("output""path"); 
  10.  

    配置文件

 

 
  1. <?xml version="1.0" encoding="utf-8" ?> 
  2. <config> 
  3. <output path="c:\\monitor.log"></output> 
  4. <printer name="HP5100"></printer> 
  5. </config> 

      (8)新建一个类,核心的监控代码,主要就是通过调用peekPrinterJobs这个函数返回打印的记录

 

 
  1. public static int oldPrintId = 0; 
  2.  
  3.        [StructLayout(LayoutKind.Sequential)] 
  4.        public struct SYSTEMTIME 
  5.        { 
  6.            public short wYear; 
  7.            public short wMonth; 
  8.            public short wDayOfWeek; 
  9.            public short wDay; 
  10.            public short wHour; 
  11.            public short wMinute; 
  12.            public short wSecond; 
  13.            public short wMilliseconds; 
  14.        } 
  15.  
  16.        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] 
  17.        public struct JOB_INFO_1 
  18.        { 
  19.            public int JobId; 
  20.            public string pPrinterName; 
  21.            public string pMachineName; 
  22.            public string pUserName; 
  23.            public string pDocument; 
  24.            public string pDatatype; 
  25.            public string pStatus; 
  26.            public int Status; 
  27.            public int Priority; 
  28.            public int Position; 
  29.            public int TotalPages; 
  30.            public int PagesPrinted; 
  31.            public SYSTEMTIME Submitted; 
  32.        } 
  33.  
  34.        [DllImport("winspool.drv", CharSet = CharSet.Auto)] 
  35.        public static extern bool OpenPrinter(string pPrinterName, out IntPtr phPrinter, IntPtr pDefault); 
  36.  
  37.        [DllImport("winspool.drv", CharSet = CharSet.Auto)] 
  38.        public static extern bool ClosePrinter(IntPtr hPrinter); 
  39.  
  40.        [DllImport("winspool.drv", CharSet = CharSet.Auto)] 
  41.        public static extern int EnumJobs(IntPtr hPrinter, int FirstJob, int NoJobs, int Level, IntPtr pInfo, int cdBuf, 
  42.                                          out int pcbNeeded, out int pcReturned); 
  43.  
  44.        public static void peekPrinterJobs(string printerToPeek) 
  45.        { 
  46.            IntPtr handle; 
  47.            int FirstJob = 0; 
  48.            int NumJobs = 127; 
  49.            int pcbNeeded; 
  50.            int pcReturned; 
  51.  
  52.            // open printer  
  53.            OpenPrinter(printerToPeek, out handle, IntPtr.Zero); 
  54.  
  55.            // get num bytes required, here we assume the maxt job for the printer quest is 128 (0..127)  
  56.            EnumJobs(handle, FirstJob, NumJobs, 1, IntPtr.Zero, 0, out pcbNeeded, out pcReturned); 
  57.  
  58.            // allocate unmanaged memory  
  59.            IntPtr pData = Marshal.AllocHGlobal(pcbNeeded); 
  60.  
  61.            // get structs  
  62.            EnumJobs(handle, FirstJob, NumJobs, 1, pData, pcbNeeded, out pcbNeeded, out pcReturned); 
  63.  
  64.            // create array of managed job structs  
  65.            JOB_INFO_1[] jobs = new JOB_INFO_1[pcReturned]; 
  66.  
  67.            // marshal struct to managed  
  68.            int pTemp = pData.ToInt32(); //start pointer  
  69.            for (int i = 0; i < pcReturned; ++i) 
  70.            { 
  71.                jobs[i] = (JOB_INFO_1)Marshal.PtrToStructure(new IntPtr(pTemp), typeof(JOB_INFO_1)); 
  72.                if (jobs[i].Status != 16) break
  73.                if (jobs[i].JobId == oldPrintId) 
  74.                { 
  75.                    break
  76.                } 
  77.                else 
  78.                { 
  79.                    pTemp += Marshal.SizeOf(typeof(JOB_INFO_1)); 
  80.                                        //记录到日志,可以自己写方法写到数据库或者其他地方 
  81.                    RecordJobToLog(jobs[i]); 
  82.                    oldPrintId = jobs[i].JobId; 
  83.                } 
  84.  
  85.            } 
  86.  
  87.            Marshal.FreeHGlobal(pData); 
  88.  
  89.            ClosePrinter(handle); 
  90.  
  91.        } 
  92.  
  93.        private static void RecordJobToLog(JOB_INFO_1 job) 
  94.        { 
  95.            string logText = job.JobId + "-" + job.pMachineName + "-" + job.pUserName + "-" + job.pDocument + "-" + job.PagesPrinted + "-" + job.TotalPages + "-" + job.Status + "-" + DateTime.Now.ToString("yyyy-MM-dd HH:mm"); 
  96.            WriteToLog(logText); 
  97.        } 

3、安装部署

 

           编译程序,把程序拷到服务器

           然后运行c:\Windows\Microsoft.NET\Framework\v2.0.50727\installutil.exe installutil yourproject.exe 安装服务

           卸载服务c:\Windows\Microsoft.NET\Framework\v2.0.50727\installutil.exe /u yourproject.exe

           打印一份文件,然后就可以到指定目录查看打印日志了

           服务的配置文件一定要拷贝到c:\windows\system32中

五、总结

      通过这个程序学习了服务的开发、读取xml和C#调用api函数,自己开发的优势是可以把日志存已自己需要的格式存放在需要的地方,比如配置文件或者数据库方便和现有平台的整合。JOB_INFO_1所得到的数据比较有限,比如无法取得打印份数等等,通过JOB_INFO_2可以取得更多的打印信息,原理都是一样的先能用慢慢在修改完善。

六、参考链接

http://msdn.microsoft.com/en-us/library/dd162861(v=VS.85).aspx
http://msdn.microsoft.com/en-us/library/dd162625(VS.85).aspx
http://msdn.microsoft.com/en-us/library/dd145020(v=VS.85).aspx
http://support.microsoft.com/kb/160129http://msdn.microsoft.com/en-us/library/ff556443.aspx
http://msdn.microsoft.com/en-us/library/dd183565(v=VS.85).aspx

http://www.cnblogs.com/waxic/archive/2009/05/07/1451952.html

http://www.cnblogs.com/caca/archive/2005/02/25/109028.html


转自:http://dqw3721.blog.51cto.com/112726/411682


http://www.ppmy.cn/news/259536.html

相关文章

惠普打印机驱动服务器系统,在打印机服务器(系统WIN2003)上安装了HP5100 打印机,客户机系统WIN7 64位,现没法添加HP5100的驱动...

windows 开机出现 „ 应用程序正常初始化 (0xc0000044) 失败 ‟ 进不了系统 在前两天的工作中&#xff0c;客户那边的服务器 winows2003 出现了进不了桌面的问题&#xff0c;当输入用户名 和密码后&#xff0c;跳出警告对话框&#xff1a;应用程序正常初始化 (0xc0000044) 失败…

vue完美模拟快手实现短视频,含短视频详情播放

目录 一、预览 二、效果图 项目实现的demo效果图&#xff1a; 三、项目细节说明 1.项目结构、设计说明 2.项目可拓展能力题外话&#xff08;看不懂可以忽略&#xff09; 3.项目路由配置 4.框架布局页面源码 5.首页实现 四、总结 一、预览 本作品demo预览地址&#xff1…

【STM32CubeMX项目】DHT11模块

前言 在我的另一篇里文章里已经介绍过DHT11的时序理论了&#xff0c;这里介绍下&#xff0c;我写DHT11的数据获取的思路和调用。程序验证后&#xff0c;发现下述问题&#xff0c;暂时解决不了&#xff0c;但是还是会把个人的代码流程&#xff0c;函数的编写思路和工程写下&…

电脑 机带RAM 16G(可用2G),可用内存远低于实际内存问题解决

一通搜索操作后发现&#xff0c;电脑操作系统过期了&#xff0c;激活或者重装即可

电脑内存占用狂飙到90%

如果你感觉电脑啥也没干&#xff0c;但是电脑内存动不动狂飙到70%以上。 如果你用的刚好是联想拯救者系列的电脑&#xff1a; 1、直接把联想电脑管家、联系应用商店全删了。 再重启电脑&#xff0c;Win X &#xff0c;输入 regedit打开注册表&#xff0c;在计算机HKEY_LOCA…

8g内存的计算机专业可以吗,电脑内存4G和8G差距能有多大?

如今内存的价格昂贵&#xff0c;好多人都看着500元左右的DDR4 8G内存不忍下手&#xff0c;虽然4G内存将近便宜一半&#xff0c;但是担心性能不够用&#xff0c;因此非常纠结&#xff0c;在这个情况下&#xff0c;到底是省钱买4G还是咬牙上8G成为大多数人的选择难题。 其实4G内存…

java用4g内存够么,不玩游戏4g运存够用吗

智能手机如今飞速发展&#xff0c;手机性能也在突飞猛进&#xff0c;除了CPU的性能越来越强&#xff0c;内存空间也从原本的256KB上升到目前4GB、6GB&#xff0c;甚至在某些旗舰机器上已经使用上了12GB的超大运存。那么现在选择手机不玩游戏4g运存够用吗&#xff1f;下面就为您…

8g内存学习计算机专业够吗,电脑内存4G和8G差距能有多大?电脑装机内存多大合适?...

原标题&#xff1a;电脑内存4G和8G差距能有多大&#xff1f;电脑装机内存多大合适&#xff1f; 如今内存的价格昂贵&#xff0c;好多人都看着500元左右的DDR4 8G内存不忍下手&#xff0c;虽然4G内存将近便宜一半&#xff0c;但是担心性能不够用&#xff0c;因此非常纠结&#x…