You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

189 lines
5.9 KiB

using System;
using System.Collections.Generic;
using System.Linq;
using System.Printing;
using System.Threading;
using System.Threading.Tasks;
public class PrintMonitor
{
public async Task<string> CheckPrintStatusAsync(
string printerName,
string targetJobName,
CancellationToken cancellationToken,
TimeSpan? timeout = null)
{
var timeoutValue = timeout ?? TimeSpan.FromSeconds(60);
using (var timeoutCts = new CancellationTokenSource(timeoutValue))
using (var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(
cancellationToken,
timeoutCts.Token))
{
try
{
while (!linkedCts.IsCancellationRequested)
{
var isCompleted = await Task.Run(() =>
{
// 关键修改:每个操作线程创建自己的PrintServer
using (var printServer = new LocalPrintServer())
{
var printQueue = GetPrintQueue(printServer, printerName);
return CheckJobs(printQueue, targetJobName);
}
}, linkedCts.Token);
if (isCompleted) return "Success";
await Task.Delay(1000, linkedCts.Token);
}
}
catch (OperationCanceledException ex)
{
HandleCancellation(timeoutCts, cancellationToken, timeoutValue);
throw;
}
}
//throw new OperationCanceledException();
return "Success";
}
private PrintQueue GetPrintQueue(LocalPrintServer server, string printerName)
{
try
{
return string.IsNullOrEmpty(printerName)
? server.DefaultPrintQueue
: server.GetPrintQueue(printerName);
}
catch (Exception ex)
{
throw new InvalidOperationException($"获取打印机队列失败: {ex.Message}");
}
}
private bool CheckJobs(PrintQueue queue, string targetJobName)
{
queue.Refresh();
var jobs = queue.GetPrintJobInfoCollection()
?? throw new Exception("无法获取打印任务列表");
foreach (PrintSystemJobInfo job in jobs)
{
if (job.Name.Contains(targetJobName))
{
try
{
CheckJobStatus(job);
return job.JobStatus.HasFlag(PrintJobStatus.Completed);
}
catch (Exception ex)
{
// 仅传播需要处理的异常
if (!IsExpectedStatus(job.JobStatus))
throw new Exception("关键打印错误", ex);
}
}
}
return false;
}
private bool IsExpectedStatus(PrintJobStatus status)
{
// 定义可忽略的临时状态
var ignorableStatuses = new[]
{
PrintJobStatus.Printing,
PrintJobStatus.Spooling,
PrintJobStatus.Retained
};
return ignorableStatuses.Any(s => status.HasFlag(s));
}
private void CheckJobStatus(PrintSystemJobInfo job)
{
// 成功状态直接返回
if (job.JobStatus.HasFlag(PrintJobStatus.Completed))
return;
// 状态分类配置
var ignorableStatuses = new[]
{
PrintJobStatus.Printing, // 正在打印
PrintJobStatus.Retained, // 任务保留
PrintJobStatus.Spooling, // 后台处理
PrintJobStatus.Paused // 用户主动暂停
};
var criticalStatuses = new[]
{
PrintJobStatus.Error, // 通用错误
PrintJobStatus.PaperOut, // 缺纸
//PrintJobStatus.PaperJam, // 卡纸
PrintJobStatus.Offline // 脱机
};
// 第一步:检查可忽略的中间状态
if (ignorableStatuses.Any(s => job.JobStatus.HasFlag(s)))
{
return; // 静默继续等待
}
// 第二步:检测关键错误状态
var criticalStatus = criticalStatuses.FirstOrDefault(s =>
job.JobStatus.HasFlag(s));
if (criticalStatus != default)
{
throw new Exception($"打印错误: {GetStatusDescription(criticalStatus)}");
}
// 第三步:处理未知状态
throw new Exception($"无法处理的打印状态: {FormatCompositeStatus(job.JobStatus)}");
}
// 辅助方法:获取状态描述
private string GetStatusDescription(PrintJobStatus status)
{
// 优先处理复合状态
if ((status & (PrintJobStatus.Error | PrintJobStatus.Offline)) != 0)
{
return "设备故障";
}
// 处理单一状态
switch (status)
{
case PrintJobStatus.PaperOut:
return "缺纸";
case PrintJobStatus.Spooling:
return "后台处理中";
default:
return status.ToString();
}
}
// 辅助方法:格式化复合状态
private string FormatCompositeStatus(PrintJobStatus status)
{
var activeFlags = Enum.GetValues(typeof(PrintJobStatus))
.Cast<PrintJobStatus>()
.Where(s => s != PrintJobStatus.None && status.HasFlag(s))
.Select(s => s.ToString());
return string.Join(" | ", activeFlags);
}
private void HandleCancellation(
CancellationTokenSource timeoutCts,
CancellationToken originalToken,
TimeSpan timeout)
{
if (timeoutCts.IsCancellationRequested)
throw new TimeoutException($"操作超时 ({timeout.TotalMinutes}分钟)");
if (originalToken.IsCancellationRequested)
throw new OperationCanceledException("用户取消操作");
}
}