Как я могу получить марку и модель принтера на Java?
На самом деле я работаю над приложением Java, которое использует принтеры на сервере, и мне нужно это приложение, чтобы узнать марку и модель принтеров, которые он использует.
Я знаю, что этот вопрос задавался три или четыре раза, но никто, кажется, не нашел ответа.
Я пробовал этот код:
PrintService[] printServices = PrintServiceLookup.lookupPrintServices(null, null);
for (PrintService printer : printServices){
System.out.println(printer.getDefaultAttributeValue(PrinterMakeAndModel.class));
System.out.println(printer.getAttribute(PrinterURI.class));
}
первая печать всегда возвращает пустую строку, а вторая получает исключение NullPointerException.
Некоторые исследования приводят меня на эту страницу: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4673400
Кажется, что это "ошибка", и я не совсем понимаю оценку.
Я думаю, что в качестве обходного пути можно было бы получить марку и модель, отправив запрос SNMP на принтеры, но я ничего не знаю о SNMP и не уверен, что есть одна команда SNMP для получения марки и модели. любого принтера.
Если у кого-то есть идеи о том, как этого добиться, используя метод Java или отправляя команды SNMP или что-либо еще, что можно сделать в любой ОС, ваша помощь будет принята с благодарностью.
РЕДАКТИРОВАТЬ:
Вот ссылка на тему, где задавался тот же вопрос:
РЕДАКТИРОВАТЬ 2:
Решение:
Как я сказал в комментарии, я попытался получить марку и модель через SNMP, отправив OID "1.3.6.1.2.1.25.3.2.1.3.1" на принтер. Кажется, что это работает, но я не уверен, что он работает на любом принтере, использующем тот же OID, и может произойти сбой, если SNMP отключен на целевом принтере.
Поэтому я, наконец, решил получить имя драйвера, используя JNA и Winspool.drv. Часть этого уже была реализована в JNA, но мне пришлось добавить некоторые структуры и функции.
Вот ссылка на существующие классы WinspoolUtil.java и Winspool.java в JNA.
А вот код с моим личным обновлением этих двух классов.
Уинспул:
import java.util.Arrays;
import java.util.List;
import com.sun.jna.Memory;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.Structure;
import com.sun.jna.platform.win32.WinDef.DWORD;
import com.sun.jna.platform.win32.WinDef.INT_PTR;
import com.sun.jna.platform.win32.WinNT.HANDLE;
import com.sun.jna.platform.win32.WinNT.HANDLEByReference;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.win32.StdCallLibrary;
import com.sun.jna.win32.W32APIOptions;
public class WinspoolUpdate {
public interface WinspoolLib extends StdCallLibrary {
WinspoolLib INSTANCE = (WinspoolLib) Native.loadLibrary("Winspool.drv", WinspoolLib.class,
W32APIOptions.UNICODE_OPTIONS);
boolean EnumPrinters(int Flags, String Name, int Level, Pointer pPrinterEnum,
int cbBuf, IntByReference pcbNeeded, IntByReference pcReturned);
boolean GetPrinter(HANDLE hPrinter, int Level, Pointer pPrinter, int cbBuf, IntByReference pcbNeeded);
boolean OpenPrinter(String pPrinterName, HANDLEByReference phPrinter, Pointer pDefault);
public static class PRINTER_INFO_1 extends Structure {
public int Flags;
public String pDescription;
public String pName;
public String pComment;
protected List<String> getFieldOrder() {
return Arrays.asList(new String[] { "Flags", "pDescription", "pName", "pComment" });
}
public PRINTER_INFO_1() {
}
public PRINTER_INFO_1(int size) {
super(new Memory(size));
}
}
public static class PRINTER_INFO_2 extends Structure {
public String pServerName;
public String pPrinterName;
public String pShareName;
public String pPortName;
public String pDriverName;
public String pComment;
public String pLocation;
public INT_PTR pDevMode;
public String pSepFile;
public String pPrintProcessor;
public String pDatatype;
public String pParameters;
public INT_PTR pSecurityDescriptor;
public int Attributes;
public int Priority;
public int DefaultPriority;
public int StartTime;
public int UntilTime;
public int Status;
public int cJobs;
public int AveragePPM;
protected List<String> getFieldOrder() {
return Arrays.asList(new String[] { "pServerName", "pPrinterName", "pShareName", "pPortName",
"pDriverName", "pComment", "pLocation", "pDevMode", "pSepFile", "pPrintProcessor",
"pDatatype", "pParameters", "pSecurityDescriptor", "Attributes", "Priority", "DefaultPriority",
"StartTime", "UntilTime", "Status", "cJobs", "AveragePPM" });
}
public PRINTER_INFO_2() {
}
public PRINTER_INFO_2(int size) {
super(new Memory(size));
}
}
public static class PRINTER_INFO_4 extends Structure {
public String pPrinterName;
public String pServerName;
public DWORD Attributes;
protected List<String> getFieldOrder() {
return Arrays.asList(new String[] { "pPrinterName", "pServerName", "Attributes" });
}
public PRINTER_INFO_4() {
}
public PRINTER_INFO_4(int size) {
super(new Memory(size));
}
}
int PRINTER_ENUM_DEFAULT = 0x00000001;
int PRINTER_ENUM_LOCAL = 0x00000002;
int PRINTER_ENUM_CONNECTIONS = 0x00000004;
int PRINTER_ENUM_FAVORITE = 0x00000004;
int PRINTER_ENUM_NAME = 0x00000008;
int PRINTER_ENUM_REMOTE = 0x00000010;
int PRINTER_ENUM_SHARED = 0x00000020;
int PRINTER_ENUM_NETWORK = 0x00000040;
int PRINTER_ENUM_EXPAND = 0x00004000;
int PRINTER_ENUM_CONTAINER = 0x00008000;
int PRINTER_ENUM_ICONMASK = 0x00ff0000;
int PRINTER_ENUM_ICON1 = 0x00010000;
int PRINTER_ENUM_ICON2 = 0x00020000;
int PRINTER_ENUM_ICON3 = 0x00040000;
int PRINTER_ENUM_ICON4 = 0x00080000;
int PRINTER_ENUM_ICON5 = 0x00100000;
int PRINTER_ENUM_ICON6 = 0x00200000;
int PRINTER_ENUM_ICON7 = 0x00400000;
int PRINTER_ENUM_ICON8 = 0x00800000;
int PRINTER_ENUM_HIDE = 0x01000000;
}
}
WinspoolUtil:
import Model.WinspoolUpdate.WinspoolLib;
import Model.WinspoolUpdate.WinspoolLib.PRINTER_INFO_2;
import com.sun.jna.platform.win32.Kernel32;
import com.sun.jna.platform.win32.Win32Exception;
import com.sun.jna.platform.win32.WinNT.HANDLEByReference;
import com.sun.jna.platform.win32.Winspool.PRINTER_INFO_1;
import com.sun.jna.platform.win32.Winspool.PRINTER_INFO_4;
import com.sun.jna.ptr.IntByReference;
public class WinspoolUtils2 {
public static PRINTER_INFO_1[] getPrinterInfo1() {
IntByReference pcbNeeded = new IntByReference();
IntByReference pcReturned = new IntByReference();
WinspoolLib.INSTANCE.EnumPrinters(WinspoolLib.PRINTER_ENUM_LOCAL,
null, 1, null, 0, pcbNeeded, pcReturned);
if (pcbNeeded.getValue() <= 0) {
return new PRINTER_INFO_1[0];
}
PRINTER_INFO_1 pPrinterEnum = new PRINTER_INFO_1(pcbNeeded.getValue());
if (!WinspoolLib.INSTANCE.EnumPrinters(WinspoolLib.PRINTER_ENUM_LOCAL,
null, 1, pPrinterEnum.getPointer(), pcbNeeded.getValue(), pcbNeeded, pcReturned)) {
throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
}
pPrinterEnum.read();
return (PRINTER_INFO_1[]) pPrinterEnum.toArray(pcReturned.getValue());
}
public static PRINTER_INFO_2[] getPrinterInfo2() {
IntByReference pcbNeeded = new IntByReference();
IntByReference pcReturned = new IntByReference();
WinspoolLib.INSTANCE.EnumPrinters(WinspoolLib.PRINTER_ENUM_LOCAL,
null, 2, null, 0, pcbNeeded, pcReturned);
if (pcbNeeded.getValue() <= 0) {
return new PRINTER_INFO_2[0];
}
PRINTER_INFO_2 pPrinterEnum = new PRINTER_INFO_2(pcbNeeded.getValue());
if (!WinspoolLib.INSTANCE.EnumPrinters(WinspoolLib.PRINTER_ENUM_LOCAL,
null, 2, pPrinterEnum.getPointer(), pcbNeeded.getValue(), pcbNeeded, pcReturned)) {
throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
}
pPrinterEnum.read();
return (PRINTER_INFO_2[]) pPrinterEnum.toArray(pcReturned.getValue());
}
public static PRINTER_INFO_4[] getPrinterInfo4() {
IntByReference pcbNeeded = new IntByReference();
IntByReference pcReturned = new IntByReference();
WinspoolLib.INSTANCE.EnumPrinters(WinspoolLib.PRINTER_ENUM_LOCAL,
null, 4, null, 0, pcbNeeded, pcReturned);
if (pcbNeeded.getValue() <= 0) {
return new PRINTER_INFO_4[0];
}
PRINTER_INFO_4 pPrinterEnum = new PRINTER_INFO_4(pcbNeeded.getValue());
if (!WinspoolLib.INSTANCE.EnumPrinters(WinspoolLib.PRINTER_ENUM_LOCAL,
null, 4, pPrinterEnum.getPointer(), pcbNeeded.getValue(), pcbNeeded, pcReturned)) {
throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
}
pPrinterEnum.read();
return (PRINTER_INFO_4[]) pPrinterEnum.toArray(pcReturned.getValue());
}
public static PRINTER_INFO_2 getPrinterInfo2(String printerName) {
IntByReference pcbNeeded = new IntByReference();
IntByReference pcReturned = new IntByReference();
HANDLEByReference pHandle = new HANDLEByReference();
WinspoolLib.INSTANCE.OpenPrinter(printerName, pHandle, null);
WinspoolLib.INSTANCE.GetPrinter(pHandle.getValue(), 2, null, 0, pcbNeeded);
if (pcbNeeded.getValue() <= 0) {
return new PRINTER_INFO_2();
}
PRINTER_INFO_2 pinfo2 = new PRINTER_INFO_2(pcbNeeded.getValue());
WinspoolLib.INSTANCE.GetPrinter(pHandle.getValue(), 2, pinfo2.getPointer(), pcbNeeded.getValue(), pcReturned);
pinfo2.read();
return (PRINTER_INFO_2) pinfo2;
}
}
Основной класс, вызывающий три реализованные функции и отображающий результат:
public static void main(String[] args) {
for(PRINTER_INFO_1 printerInfo : WinspoolUtils2.getPrinterInfo1()) {
System.out.println(printerInfo.pName + ": " + printerInfo.pDescription);
}
for(PRINTER_INFO_2 printerInfo : WinspoolUtils2.getPrinterInfo2()) {
System.out.println(printerInfo.pPrinterName + ": " + printerInfo.pDriverName);
}
PRINTER_INFO_2 printerInfo = WinspoolUtils2.getPrinterInfo2("Canon iR-ADV C7000s GX300 V2.0");
System.out.println(printerInfo.pPrinterName + ": " + printerInfo.pDriverName);
}
Я изо всех сил пытался, наконец, заставить его работать, поэтому я надеюсь, что это поможет.
Если вы хотите добавить некоторые другие функции API диспетчера очереди печати, здесь вы можете найти ссылки на этот API.
Примечание: проблема все еще существует, потому что я хотел бы, чтобы это приложение было мультиплатформенным, и это решение работает только для Windows. Поэтому в будущем мне нужно будет найти решение, чтобы получить имя драйвера принтера для ОС Linux и Mac OS X. Я буду держать вас в курсе, если что-нибудь найду.
3 ответа
Для тех, кто интересуется этой темой, я продолжал искать решение, которое использовало бы базовые библиотеки Java, но когда я начал искать исходный код этих библиотек, я обнаружил, что большинство методов, которые должны возвращать атрибуты принтера никогда не были реализованы, они всегда возвращают нулевое значение. Так что на данный момент нет способа сделать это в Java.
Есть два обходных пути, которые я разместил во втором редактировании моего исходного вопроса:
- Получите эту информацию через вызовы SNMP.
- Используйте библиотеку диспетчера очереди печати Windows и получите эту информацию из драйвера.
(Вишня выбирает некоторые части вопроса, которые отвечают.)
Кажется, что это "ошибка", и я не совсем понимаю оценку.
На самом деле, это запрос на улучшение (RFE), а не ошибка.
Оценка просто показывает, что рецензент думает, что он нашел способ, которым они могли бы реализовать это в Windows ... если и когда они дойдут до этого. Это не обходной путь для вас.
Этот связанный вопрос говорит о получении модели принтера с использованием SNMP
Вы должны быть в состоянии сопоставить это с решением, используя библиотеку Java SNMP. Этот подход предполагает, что принтер подключен к сети и поддерживает SNMP... но я думаю, вы уже поняли это.
Используя JNA, правильная версия для решения OP (без дублированного кода) выглядит так:
WinspoolExt
import java.util.Arrays;
import java.util.List;
import com.sun.jna.Memory;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.Structure;
import com.sun.jna.platform.win32.Winspool;
import com.sun.jna.platform.win32.WinDef.INT_PTR;
import com.sun.jna.platform.win32.WinNT.HANDLE;
import com.sun.jna.platform.win32.WinNT.HANDLEByReference;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.win32.W32APIOptions;
public interface WinspoolExt extends Winspool {
WinspoolExt INSTANCE = (WinspoolExt) Native.loadLibrary("Winspool.drv", WinspoolExt.class,
W32APIOptions.UNICODE_OPTIONS);
boolean GetPrinter(HANDLE hPrinter, int Level, Pointer pPrinter, int cbBuf, IntByReference pcbNeeded);
boolean OpenPrinter(String pPrinterName, HANDLEByReference phPrinter, Pointer pDefault);
public static class PRINTER_INFO_2 extends Structure {
public String pServerName;
public String pPrinterName;
public String pShareName;
public String pPortName;
public String pDriverName;
public String pComment;
public String pLocation;
public INT_PTR pDevMode;
public String pSepFile;
public String pPrintProcessor;
public String pDatatype;
public String pParameters;
public INT_PTR pSecurityDescriptor;
public int Attributes;
public int Priority;
public int DefaultPriority;
public int StartTime;
public int UntilTime;
public int Status;
public int cJobs;
public int AveragePPM;
protected List<String> getFieldOrder() {
return Arrays.asList(new String[] { "pServerName", "pPrinterName", "pShareName", "pPortName",
"pDriverName", "pComment", "pLocation", "pDevMode", "pSepFile", "pPrintProcessor", "pDatatype",
"pParameters", "pSecurityDescriptor", "Attributes", "Priority", "DefaultPriority", "StartTime",
"UntilTime", "Status", "cJobs", "AveragePPM" });
}
public PRINTER_INFO_2() {
}
public PRINTER_INFO_2(int size) {
super(new Memory(size));
}
}
}
WinspoolUtilExt
import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.Kernel32;
import com.sun.jna.platform.win32.Win32Exception;
import com.sun.jna.platform.win32.WinNT.HANDLEByReference;
import com.sun.jna.platform.win32.WinspoolUtil;
import com.sun.jna.ptr.IntByReference;
import WinspoolExt.PRINTER_INFO_2;
public class WinspoolUtilExt extends WinspoolUtil {
public static PRINTER_INFO_2[] getPrinterInfo2() {
IntByReference pcbNeeded = new IntByReference();
IntByReference pcReturned = new IntByReference();
WinspoolExt.INSTANCE.EnumPrinters(WinspoolExt.PRINTER_ENUM_LOCAL, null, 2, null, 0, pcbNeeded, pcReturned);
if (pcbNeeded.getValue() <= 0) {
return new PRINTER_INFO_2[0];
}
PRINTER_INFO_2 pPrinterEnum = new PRINTER_INFO_2(pcbNeeded.getValue());
if (!WinspoolExt.INSTANCE.EnumPrinters(WinspoolExt.PRINTER_ENUM_LOCAL, null, 2, pPrinterEnum.getPointer(),
pcbNeeded.getValue(), pcbNeeded, pcReturned)) {
throw new Win32Exception(Kernel32.INSTANCE.GetLastError());
}
pPrinterEnum.read();
return (PRINTER_INFO_2[]) pPrinterEnum.toArray(pcReturned.getValue());
}
public static PRINTER_INFO_2 getPrinterInfo2(String printerName) {
IntByReference pcbNeeded = new IntByReference();
IntByReference pcReturned = new IntByReference();
HANDLEByReference pHandle = new HANDLEByReference();
WinspoolExt.INSTANCE.OpenPrinter(printerName, pHandle, (Pointer) null);
WinspoolExt.INSTANCE.GetPrinter(pHandle.getValue(), 2, null, 0, pcbNeeded);
if (pcbNeeded.getValue() <= 0) {
return new PRINTER_INFO_2();
}
PRINTER_INFO_2 pinfo2 = new PRINTER_INFO_2(pcbNeeded.getValue());
WinspoolExt.INSTANCE.GetPrinter(pHandle.getValue(), 2, pinfo2.getPointer(), pcbNeeded.getValue(), pcReturned);
pinfo2.read();
return (PRINTER_INFO_2) pinfo2;
}
}
По сути, он добавляет поддержку PRINTER_INFO_2.