java - 我如何在 Java 中获取打印机的品牌和型号?

标签 java printing driver snmp jna

我实际上正在开发一个将打印机共享到服务器的 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));
        }

第一次打印总是返回一个null 字符串,第二次打印得到一个NullPointerException

一些研究将我带到了这个页面:http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4673400

好像是know“bug”,没看懂评价。

我在想一个解决方法是通过向打印机发送 SNMP 请求来获取品牌和型号,但我对 SNMP 一无所知,而且我不确定是否有单个 SNMP 命令可以获取任何打印机的品牌和型号。

如果有人知道如何通过使用 Java 方法或通过发送 SNMP 命令或任何其他可以在任何操作系统上完成的操作来实现这一点,我们将不胜感激。

编辑:

这是一个主题的链接,其中提出了相同的问题:

编辑 2:

解决方案:

正如我在评论中所说,我试图通过向打印机发送 OID“1.3.6.1.2.1.25.3.2.1.3.1”来通过 SNMP 获取品牌和型号。它似乎可以工作,但我不确定它是否可以在使用相同 OID 的任何打印机上工作,如果在目标打印机上停用 SNMP,它可能会崩溃。

所以最终选择了使用JNA和Winspool.drv来获取驱动名称。 它的一部分已经在 J​​NA 中实现,但我必须添加一些结构和函数。

这是现有 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 的一些其他功能,Here您可以找到此 API 的引用资料。

注意:仍然存在一个问题,因为我希望此应用程序是多平台的,而此解决方案仅适用于 Windows。 所以将来我必须找到一个解决方案来在 Linux 操作系统和 Mac OS X 上获取打印机驱动程序名称。 如果我发现了什么,我会及时通知你。

最佳答案

(从问题中挑选一些可以回答的部分。)

It seems like it's a know "bug" and I don't really understand the evaluation.

事实上,这是增强请求 (RFE) 而不是错误。

评估只是表明审阅者认为他/她已经找到了一种方法他们可以在 Windows 上实现它......如果他们有时间的话。这不是适合您的解决方法。


这个相关问题讨论了使用 SNMP 获取打印机的型号

您应该能够使用 Java SNMP 库将其映射到解决方案。这种方法假定打印机已联网并且支持 SNMP……但我想您已经知道了。

关于java - 我如何在 Java 中获取打印机的品牌和型号?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15476914/

相关文章:

java - 如何获取客户端 MAC 地址? (在jsp、java中)

javascript - 打印doc文件的JS函数?

java - 跨多个 <Host> 元素为公共(public)库共享单个类加载器是否安全?

java - XML 打印文件中的不同属性顺序

c# - 如何从.NET调用Windows 7自带的 "Print Pictures"应用程序

c - 如何为字符数组分配8kb内存并获取其起始地址和结束地址?

linux - 用于调试 Linux 设备驱动程序的 GDB

java - Google Cloud Datastore v1 API 中 DatastoreHelper Java 类的替代方案

java - 检测套接字断开连接