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 "";
            }
    View Code

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

    /// <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();
            }
    View Code

    最后在上面的循环打印的方法里加上判断,同时去掉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;
                                }
                            }
    
                        }

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

  • 相关阅读:
    【故障处理】ORA-12162: TNS:net service name is incorrectly specified (转)
    android studio 编程中用到的快捷键
    java时间格式串
    android Error occurred during initialization of VM Could not reserve enough space for object heap Could not create the Java virtual machine.
    linux安装vmware
    x1c 2017 安装mint18的坑——grub2
    x1c2017 8G版 win linux的取舍纠结记录
    python的try finally (还真不简单)
    kafka+docker+python
    json文件不能有注释
  • 原文地址:https://www.cnblogs.com/springSky/p/3227285.html
Copyright © 2011-2022 走看看