Вот что я сделал на данный момент:
- Открыл принтер и настроил уведомления об изменениях:
Код: Выделить всё
IntPtr hPrinter;
if (!OpenPrinter(printerName, out hPrinter, IntPtr.Zero))
{
int errorCode = Marshal.GetLastWin32Error();
Log($"Failed to open printer: {printerName}. Error code: {errorCode}");
return;
}
IntPtr hChange = FindFirstPrinterChangeNotification(hPrinter, PRINTER_CHANGE_ADD_JOB | PRINTER_CHANGE_WRITE_JOB | PRINTER_CHANGE_SET_JOB, 0, IntPtr.Zero);
if (hChange == IntPtr.Zero)
{
int errorCode = Marshal.GetLastWin32Error();
Log($"Failed to create change notification for printer: {printerName}. Error code: {errorCode}");
ClosePrinter(hPrinter);
return;
}
- Отслеживание изменений принтера:
Код: Выделить всё
while (bKeepMonitoring && !cancellationToken.IsCancellationRequested)
{
uint waitResult = WaitForSingleObject(hChange, 1000);
if (waitResult == WAIT_OBJECT_0)
{
int pdwChange;
IntPtr lppPrinterNotifyInfo;
bool fcnreturn = FindNextPrinterChangeNotification(hChange, out pdwChange, IntPtr.Zero, out lppPrinterNotifyInfo);
if (fcnreturn)
{
if ((pdwChange & PRINTER_CHANGE_ADD_JOB) != 0)
{
Log($"A new print job was added to printer: {printerName}");
JOB_INFO_1? jobInfo = PausePrintJob(hPrinter);
if (jobInfo != null)
{
Log($"Job paused: {jobInfo.Value.JobId}, Document: {jobInfo.Value.pDocument}");
}
}
// Additional handling for other events
}
else
{
int errorCode = Marshal.GetLastWin32Error();
Log($"Failed to get next printer change notification for printer: {printerName}. Error code: {errorCode}");
bKeepMonitoring = false;
}
}
else if (waitResult == WAIT_TIMEOUT)
{
Log("Timeout...");
}
else
{
int errorCode = Marshal.GetLastWin32Error();
Log($"WaitForSingleObject failed for printer: {printerName}. Error code: {errorCode}");
bKeepMonitoring = false;
}
}
- Приостановка задания печати:
Код: Выделить всё
private static JOB_INFO_1? PausePrintJob(IntPtr hPrinter)
{
uint needed = 0, returned = 0;
IntPtr buffer = IntPtr.Zero;
try
{
EnumJobs(hPrinter, 0, 1, 1, buffer, 0, out needed, out returned);
if (needed == 0)
{
Log("No job to pause.");
return null;
}
buffer = Marshal.AllocHGlobal((int)needed);
if (EnumJobs(hPrinter, 0, 1, 1, buffer, needed, out needed, out returned) && returned > 0)
{
JOB_INFO_1 jobInfo = (JOB_INFO_1)Marshal.PtrToStructure(buffer, typeof(JOB_INFO_1));
Log($"Pausing job: {jobInfo.JobId}, Document: {jobInfo.pDocument}");
if (!SetJob(hPrinter, jobInfo.JobId, 0, IntPtr.Zero, JOB_CONTROL_PAUSE))
{
int errorCode = Marshal.GetLastWin32Error();
Log($"Failed to pause job: {jobInfo.JobId}. Error code: {errorCode}");
}
else
{
return jobInfo;
}
}
}
finally
{
if (buffer != IntPtr.Zero)
{
Marshal.FreeHGlobal(buffer);
}
}
return null;
}
Несмотря на установку малого интервала опроса и обработку различных событий уведомлений, все же бывают случаи, когда задание на печать начинает печатать до того, как оно будет приостановлено, особенно с некоторыми драйверами принтера или большие объемы печати. Иногда я получаю статус «Приостановлено — печать» вместо статуса «Приостановлено».
Вопросы:
Что можно сделать, чтобы гарантировать, что задание приостанавливается сразу после добавления в очередь?
Существуют ли определенные драйверы или конфигурации принтера, которые лучше подходят для такого типа управления заданиями?
Как я могу улучшить время и надежность обнаружения и приостановки печати задание до начала печати?
Дополнительная информация:
Для тестирования я использую драйвер принтера «Общий/Только текст».
Я пробовал другой таймаут. значения для WaitForSingleObject.
Приложение работает с правами администратора.
Будем очень признательны за любые идеи и предложения!
Подробнее здесь: https://stackoverflow.com/questions/786 ... in-c-sharp