zoukankan      html  css  js  c++  java
  • Winform 打印PDF顺序混乱,获取打印队列

    工作中PDF打印顺序混乱着实让我疼痛了好久,其实决绝方法非常简单,但没有想到这个点子的时候确实让我走了很多弯路

    这里文章写出来并不是为了炫耀什么,只是觉得发现些好东西就分享出来而已,同时也做个记录,方便以后查找

    开始正文

    既然要解决打印顺序混乱,那么必须先要实现打印PDF功能,实现PDF打印的方法很多,网上随便一搜就可以找到,这里我贴上自己的打印方法,其实也是网上找到的,稍稍做了修改

    复制代码
    Process proc = new Process();
    proc.StartInfo.CreateNoWindow = false;
    proc.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
    proc.StartInfo.UseShellExecute = true;
    proc.StartInfo.FileName = itemPath;//打印文件路径(本地完整路径包括文件名和后缀名)
    proc.StartInfo.Verb = "print";
    proc.Start();
    proc.Close();
    复制代码

    这个打印方法非常方便,只要你的电脑安装了可以阅读PDF文档的软件,都可以打印,不用特定的软件Adobe Reader、Adobe Acrobat XI等。

    但是 当你连续打印多个PDF文档的时候就出现打印顺序混乱的问题,

    经调试发现,我发送打印请求的顺和打印机接收到的请求的顺序是不一致的

    我的解决方法是当前一个文档打印完成后,再发送下一个打印请求,为此我想到如下方法:

    就是在上面的进程打印中添加阻塞;proc.WaitForExit();注释说名的很清楚,等待关联进程退出

    代码如下:

    复制代码
                        foreach (var itemPath in filePathList)
                        {
                            if (File.Exists(itemPath))
                            {
                                Process proc = new Process();
                                proc.StartInfo.CreateNoWindow = false;
                                proc.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
                                proc.StartInfo.UseShellExecute = true;
                                proc.StartInfo.FileName = itemPath;//打印文件路径(本地完整路径包括文件名和后缀名)
                                proc.StartInfo.Verb = "print";
                                proc.Start();
                                proc.WaitForExit();
                                proc.Close();
                            }
                        }
    复制代码

    因为PDF打印会关联你的阅读PDF文档软件,因此没打印一个PDF文档就会打开关联软件,这样你必须关掉关联软件才会进入下个打印,这样就很蛋疼了,为此我又做了个线程,这个线程就是实现自动关闭关联软件的功能,但是在使用过程中会发现卡主的现象,这样用户体验不好

    因此我想到第二种实现方式:在一个打印请求发送给打印机后,就判断打印机的打印队列中是存在我发送的打印文档,如果没有,则一直等到队列中已存在打印文档后,再发送下一个打印请求,要实现这个功能,你必须要先获取到打印机的打印队列,

    首先要获得打印机的名称,我这里使用的是默认打印,为此要获得默认打印机的名称(注:必须是本机的,局域网的没时间研究,等有空了再看看)

    复制代码
            //引入命名空间:using System.Runtime.InteropServices;
            [DllImport("Winspool.drv", CharSet = CharSet.Auto, SetLastError = true)]
            private static extern bool SetDefaultPrinter(string printerName);
    
            [DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)]
            private static extern bool GetDefaultPrinter(StringBuilder pszBuffer, ref int pcchBuffer);
    
            /// <summary>
            /// 获取默认打印机 
            /// </summary>
            /// <returns></returns>
            public static string GetDefaultPrinter()
            {
                const int ERROR_FILE_NOT_FOUND = 2;
    
                const int ERROR_INSUFFICIENT_BUFFER = 122;
    
                int pcchBuffer = 0;
    
                if (GetDefaultPrinter(null, ref pcchBuffer))
                {
                    return "";
                }
    
                int lastWin32Error = Marshal.GetLastWin32Error();
    
                if (lastWin32Error == ERROR_INSUFFICIENT_BUFFER)
                {
                    StringBuilder pszBuffer = new StringBuilder(pcchBuffer);
                    if (GetDefaultPrinter(pszBuffer, ref pcchBuffer))
                    {
                        return pszBuffer.ToString();
                    }
    
                    lastWin32Error = Marshal.GetLastWin32Error();
                }
                if (lastWin32Error == ERROR_FILE_NOT_FOUND)
                {
                    return "";
                }
                return "";
            }
    复制代码

    然后根据打印机的名称获取本地打印机的打印队列

    复制代码
    /// <summary>
            /// 获取打印机的打印列表
            /// </summary>
            /// <param name="printName">打印机名称,本地</param>
            /// <returns>返回打印队列中文档名称字符串,多个之间用逗号连接</returns>
            public static string GetPrintJobs(string printName)
            {
                StringBuilder result = new StringBuilder();
    
                IntPtr handle;
                int FirstJob = 0;
                int NumJobs = 127;
                int pcbNeeded;
                int pcReturned;
    
                // open printer 
                OpenPrinter(printName, out handle, IntPtr.Zero);
    
                // get num bytes required, here we assume the maxt job for the printer quest is 128 (0..127) 
                EnumJobs(handle, FirstJob, NumJobs, 1, IntPtr.Zero, 0, out pcbNeeded, out pcReturned);
    
                // allocate unmanaged memory 
                IntPtr pData = Marshal.AllocHGlobal(pcbNeeded);
    
                // get structs 
                EnumJobs(handle, FirstJob, NumJobs, 1, pData, pcbNeeded, out pcbNeeded, out pcReturned);
    
                // create array of managed job structs 
                JOB_INFO_1[] jobs = new JOB_INFO_1[pcReturned];
    
                // marshal struct to managed 
                int pTemp = pData.ToInt32(); //start pointer 
                for (int i = 0; i < pcReturned; ++i)
                {
                    jobs[i] = (JOB_INFO_1)Marshal.PtrToStructure(new IntPtr(pTemp), typeof(JOB_INFO_1));
                    result.Append(jobs[i].pDocument);
                    result.Append(",");
                    pTemp += Marshal.SizeOf(typeof(JOB_INFO_1));
                }
    
                // cleanup unmanaged memory 
                Marshal.FreeHGlobal(pData);
    
                // close printer 
                ClosePrinter(handle);
    
                return result.ToString();
            }
    复制代码

    最后在上面的循环打印的方法里加上判断,同时去掉proc.WaitForExit();

    复制代码
                        foreach (string pdfPath in paths)
                        {
                            Process proc = new Process();
                            proc.StartInfo.CreateNoWindow = false;
                            proc.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
                            proc.StartInfo.UseShellExecute = true;
                            proc.StartInfo.FileName = pdfPath;
                            proc.StartInfo.Verb = "print";
                            proc.Start();
                            //proc.WaitForExit();
                            proc.Close();
                            string pdfFileName = Path.GetFileName(pdfPath);
                            strPrintName.Append(pdfFileName);
                            strPrintName.Append("
    ");
                            bool isOk = true;
                            while (isOk)
                            {
                                string strJob =GetPrintJobs(defaultPrintName);
                                if (strJob.Contains(pdfFileName))
                                {
                                    isOk = false;
                                }
                            }
    
                        }
    复制代码

    另外一种解决方法请看 这里

  • 相关阅读:
    大学那点破事
    我是计算机专业的学生
    acm 血泪教训
    汉诺塔问题(竟然还与Sierpiński三角形分形有关)
    证明:log(n!)与nlogn是等价无穷大
    priority_queue POJ 3253 Fence Repair
    插入排序之直接插入排序
    对Huffman编码的思考,熵
    Sudan Function
    给力小程序
  • 原文地址:https://www.cnblogs.com/Alex80/p/8835009.html
Copyright © 2011-2022 走看看