WinspoolUtil
и другие сопоставления API Windows, предоставляемые JNA, можно найти в артефакте jna-platform
.
Может показаться, что у JNA нет готового сопоставления для получения информации уровня 2 о задании на печать. Вы можете использовать WinspoolUtil#getJobInfo1
, если вам не нужна подробная информация, которую предоставляет структура уровня 2. Эта функция использует функцию Winspool.drv
EnumJobs
, документация которой гласит:
Структура JOB_INFO_1
содержит общую информацию о задании на печать; структура JOB_INFO_2
содержит гораздо более подробную информацию. Структура JOB_INFO_3
содержит информацию о том, как связаны задания.
Что касается того, как получить ручку к принтеру, вам сначала нужно перечислить принтеры , затем открыть принтер , затем перечислить задания .
Перечень принтеров
Если вы знаете точное имя принтера, вы можете полностью пропустить этот шаг.
Перечень принтеров зависит от того, как подключен нужный принтер (локальный / удаленный / доменный) и какой уровень детализации вам необходим (см. Замечания ) .
Если вы просто хотите получить быстрый и простой способ получения минимальной информации (атрибуты, имя принтера, имя сервера) локально и удаленно подключенных принтеров из реестра, используйте WinspoolUtil.getAllPrinterInfo4()
.
Если вы хотите получить подробную информацию обо всех подключенных принтерах и / или хотите также проверить их статусы, вы можете использовать WinspoolUtil.getAllPrinterInfo2()
. Обратите внимание, что это может занять некоторое время ; документация EnumPrinters гласит, что при уровне 2 он будет вызывать OpenPrinter на каждом удаленном принтере, и ему придется подождать время, чтобы сообщить, что принтер не доступен ,
В качестве альтернативы, если вам нужна информация уровня 2, но только для локально подключенных принтеров , используйте WinspoolUtil.getPrinterInfo2()
.
Кроме того, есть getPrinterInfo1()
, но JNA, кажется, получает только локальные принтеры - я не уверен, как его производительность или детали сравниваются с getPrinterInfo4()
.
Пример: распечатать имена всех принтеров, найденных в реестре
Winspool.PRINTER_INFO_4[] printers = WinspoolUtil.getPrinterInfo4();
System.out.println("Printers:");
for (Winspool.PRINTER_INFO_4 printer : printers) {
System.out.println(" Name: " + printer.pPrinterName + ", server: " + printer.pServerName);
}
Открытие принтера
Как только вы перечислили принтеры и определили принтер, с которым вы хотите работать, вы можете использовать Winspool#OpenPrinter
, чтобы открыть дескриптор принтера. Этот вызов может завершиться ошибкой, если у вас нет прав доступа к принтеру.
Всегда не забывайте звонить Winspool#ClosePrinter
, когда закончите с принтером.
Пример: открыть ручку для принтера
Winspool.PRINTER_INFO_4[] printers = WinspoolUtil.getPrinterInfo4();
System.out.println("Opening printer \"" + printers[0].pPrinterName + "\".");
WinNT.HANDLEByReference phPrinter = new WinNT.HANDLEByReference();
boolean ok = Winspool.INSTANCE.OpenPrinter(printers[0].pPrinterName, phPrinter, null);
System.out.println("ok = " + ok);
Winspool.INSTANCE.ClosePrinter(phPrinter.getValue());
Перечень работ
Теперь, когда у вас есть ручка для принтера, вы можете использовать WinspoolUtil#getJobInfo1
для получения заданий. Однако это даст вам только общую информацию о задании на печать, которую вы можете прочитать в разделе «Примечания» функции EnumJobs
.
Пример: печать всех заданий принтера
Winspool.PRINTER_INFO_4[] printers = WinspoolUtil.getPrinterInfo4();
// Just an example - get the first printer from the list
Winspool.PRINTER_INFO_4 printer = printers[4];
WinNT.HANDLEByReference phPrinter = new WinNT.HANDLEByReference();
boolean opened = Winspool.INSTANCE.OpenPrinter(
printer.pPrinterName,
phPrinter,
null
);
if (!opened) {
System.err.printf("Failed to open printer \"%s\"!", printer.pPrinterName);
return;
}
Winspool.JOB_INFO_1[] jobs = WinspoolUtil.getJobInfo1(phPrinter);
System.out.printf("Printer \"%s\" has %d jobs\n", printer.pPrinterName, jobs.length);
for (Winspool.JOB_INFO_1 job : jobs) {
System.out.printf(
" Document: \"%s\", owner: %s, status: %s, total pages: %d, pages printed: %d ...\n",
job.pDocument,
job.pUserName,
job.pStatus != null ? job.pStatus : job.Status,
job.TotalPages,
job.PagesPrinted
);
}
Winspool.INSTANCE.ClosePrinter(phPrinter.getValue());
Этот пример производит для меня следующий вывод:
Принтер "EPSONA78A80 (серия L355)" имеет 1 задание
Документ: "java - Как заставить GetLastError надежно работать с JNA? - Переполнение стека", владелец: pc, статус: 0, всего страниц: 1, напечатанных страниц: 0 ...
В заключение, Windows API имеет целый ряд способов перечислять принтеры и задания в зависимости от того, какой уровень информации вам нужен и от каких принтеров. JNA имеет сопоставления только для некоторых методов, но я думаю, что если вам действительно нужны эти сведения о работе уровня 2, вы можете просто взглянуть на источник WinspoolUtil#getJobInfo1
и документацию EnumJobs
чтобы понять это.
Кроме того, если вы заинтересованы в отслеживании изменений в определенной катушке принтера, взгляните на пример "w32printer" в репозитории JNA Github.