feat: 初始功能

This commit is contained in:
Shiqvlizi Name
2026-05-23 18:16:50 +08:00
parent a5bfd8792e
commit 9a51259e9e
63 changed files with 5377 additions and 1 deletions

View File

@@ -0,0 +1,100 @@
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));
}
}