94 lines
3.1 KiB
C#
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);
|
|
}
|
|
} |