100 lines
3.3 KiB
C#
100 lines
3.3 KiB
C#
|
|
using CloudPrint.Client.Models;
|
||
|
|
using System.Diagnostics;
|
||
|
|
using System.IO;
|
||
|
|
|
||
|
|
namespace CloudPrint.Client.Services.Printing;
|
||
|
|
|
||
|
|
public sealed class PdfPrintJobExecutor : IPrintJobExecutor
|
||
|
|
{
|
||
|
|
private readonly IWindowsPrintQueueService _queueService;
|
||
|
|
|
||
|
|
public PdfPrintJobExecutor(IWindowsPrintQueueService queueService)
|
||
|
|
{
|
||
|
|
_queueService = queueService;
|
||
|
|
}
|
||
|
|
|
||
|
|
public bool CanHandle(PrintJob job)
|
||
|
|
{
|
||
|
|
return string.Equals(Path.GetExtension(job.FilePath), ".pdf", StringComparison.OrdinalIgnoreCase);
|
||
|
|
}
|
||
|
|
|
||
|
|
public async Task ExecuteAsync(PrintJob job, IProgress<int>? progress, CancellationToken cancellationToken = default)
|
||
|
|
{
|
||
|
|
PrintFileGuards.EnsurePrintableFile(job);
|
||
|
|
progress?.Report(10);
|
||
|
|
|
||
|
|
var sumatraPath = FindSumatraPdfExecutable();
|
||
|
|
if (!string.IsNullOrWhiteSpace(sumatraPath))
|
||
|
|
{
|
||
|
|
await PrintWithSumatraAsync(sumatraPath, job, cancellationToken).ConfigureAwait(true);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
await PrintWithShellAsync(job, cancellationToken).ConfigureAwait(true);
|
||
|
|
}
|
||
|
|
|
||
|
|
CaptureWindowsJob(job);
|
||
|
|
|
||
|
|
progress?.Report(100);
|
||
|
|
}
|
||
|
|
|
||
|
|
private void CaptureWindowsJob(PrintJob job)
|
||
|
|
{
|
||
|
|
var documentName = Path.GetFileName(job.FilePath);
|
||
|
|
var queueJob = _queueService.FindLatestJob(job.PrinterName, documentName);
|
||
|
|
if (queueJob is null)
|
||
|
|
{
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
job.WindowsJobId = queueJob.JobId;
|
||
|
|
job.WindowsJobStatus = queueJob.Status;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static async Task PrintWithSumatraAsync(string sumatraPath, PrintJob job, CancellationToken cancellationToken)
|
||
|
|
{
|
||
|
|
var startInfo = new ProcessStartInfo
|
||
|
|
{
|
||
|
|
FileName = sumatraPath,
|
||
|
|
Arguments = $"-print-to \"{job.PrinterName}\" -silent -exit-when-done \"{job.FilePath}\"",
|
||
|
|
CreateNoWindow = true,
|
||
|
|
UseShellExecute = false
|
||
|
|
};
|
||
|
|
|
||
|
|
using var process = Process.Start(startInfo) ?? throw new InvalidOperationException("启动 SumatraPDF 失败");
|
||
|
|
await process.WaitForExitAsync(cancellationToken).ConfigureAwait(true);
|
||
|
|
if (process.ExitCode != 0)
|
||
|
|
{
|
||
|
|
throw new InvalidOperationException($"SumatraPDF 打印失败,退出码:{process.ExitCode}");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private static async Task PrintWithShellAsync(PrintJob job, CancellationToken cancellationToken)
|
||
|
|
{
|
||
|
|
var startInfo = new ProcessStartInfo
|
||
|
|
{
|
||
|
|
FileName = job.FilePath,
|
||
|
|
Verb = "printto",
|
||
|
|
Arguments = $"\"{job.PrinterName}\"",
|
||
|
|
UseShellExecute = true,
|
||
|
|
CreateNoWindow = true,
|
||
|
|
WindowStyle = ProcessWindowStyle.Hidden
|
||
|
|
};
|
||
|
|
|
||
|
|
using var process = Process.Start(startInfo)
|
||
|
|
?? throw new InvalidOperationException("无法调用系统默认 PDF 打印程序,请安装 SumatraPDF 或配置 PDF 默认打印程序");
|
||
|
|
await process.WaitForExitAsync(cancellationToken).ConfigureAwait(true);
|
||
|
|
}
|
||
|
|
|
||
|
|
private static string? FindSumatraPdfExecutable()
|
||
|
|
{
|
||
|
|
var candidates = new[]
|
||
|
|
{
|
||
|
|
Environment.GetEnvironmentVariable("SUMATRA_PDF_PATH"),
|
||
|
|
@"C:\Program Files\SumatraPDF\SumatraPDF.exe",
|
||
|
|
@"C:\Program Files (x86)\SumatraPDF\SumatraPDF.exe"
|
||
|
|
};
|
||
|
|
|
||
|
|
return candidates.FirstOrDefault(path => !string.IsNullOrWhiteSpace(path) && File.Exists(path));
|
||
|
|
}
|
||
|
|
}
|