Как получить JobInfo2 из WinspoolUtil и Winspool с использованием JNA (принтеры и рабочие места)? - PullRequest
0 голосов
/ 14 мая 2018

Я думаю, что могу использовать что-то вроде этого:

for(JOB_INFO_2 ji2: WinspoolUtil.getJobInfo2(phPrinter)){
// ... 

}

API JNA, который использует Winspool.drv для получения такой информации, здесь . Но это неполно.

Например, там я не могу найти этот метод: WinspoolUtil.getJobInfo2(?) где "?" это то, чего я не знаю.

1 Ответ

0 голосов
/ 20 мая 2018

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.

...