Files
client/Services/Printing/RawPrintJobExecutor.cs
2026-05-23 18:16:50 +08:00

94 lines
3.1 KiB
C#

using CloudPrint.Client.Helpers;
using CloudPrint.Client.Models;
using System.IO;
namespace CloudPrint.Client.Services.Printing;
public sealed class RawPrintJobExecutor : IPrintJobExecutor
{
public bool CanHandle(PrintJob job) => true;
public async Task ExecuteAsync(PrintJob job, IProgress<int>? progress, CancellationToken cancellationToken = default)
{
PrintFileGuards.EnsurePrintableFile(job);
if (!WindowsPrintApi.OpenPrinter(job.PrinterName, out var printerHandle, IntPtr.Zero))
{
throw new InvalidOperationException($"打开打印机失败:{job.PrinterName}");
}
try
{
var docInfo = new WindowsPrintApi.DocInfo
{
DocumentName = string.IsNullOrWhiteSpace(job.FileName) ? job.JobNo : job.FileName,
DataType = "RAW"
};
var windowsJobId = WindowsPrintApi.StartDocPrinter(printerHandle, 1, docInfo);
if (windowsJobId == 0)
{
throw new InvalidOperationException("启动打印文档失败");
}
job.WindowsJobId = windowsJobId;
job.WindowsJobStatus = "已提交到 Windows 打印队列";
try
{
if (!WindowsPrintApi.StartPagePrinter(printerHandle))
{
throw new InvalidOperationException("启动打印页面失败");
}
try
{
await WriteFileToPrinterAsync(printerHandle, job.FilePath, progress, cancellationToken).ConfigureAwait(true);
}
finally
{
WindowsPrintApi.EndPagePrinter(printerHandle);
}
}
finally
{
WindowsPrintApi.EndDocPrinter(printerHandle);
}
}
finally
{
WindowsPrintApi.ClosePrinter(printerHandle);
}
}
private static async Task WriteFileToPrinterAsync(IntPtr printerHandle, string filePath, IProgress<int>? progress, CancellationToken cancellationToken)
{
const int bufferSize = 64 * 1024;
var buffer = new byte[bufferSize];
var fileInfo = new FileInfo(filePath);
long totalWritten = 0;
await using var stream = File.OpenRead(filePath);
while (true)
{
cancellationToken.ThrowIfCancellationRequested();
var read = await stream.ReadAsync(buffer.AsMemory(0, buffer.Length), cancellationToken).ConfigureAwait(true);
if (read == 0)
{
break;
}
var chunk = read == buffer.Length ? buffer : buffer[..read];
if (!WindowsPrintApi.WritePrinter(printerHandle, chunk, read, out var written) || written != read)
{
throw new InvalidOperationException("写入打印机失败");
}
totalWritten += written;
var percent = fileInfo.Length == 0 ? 100 : (int)Math.Min(99, totalWritten * 100 / fileInfo.Length);
progress?.Report(percent);
}
progress?.Report(100);
}
}