2013-03-18 3 views
10

Я на самом деле работаю над 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

Похоже, что это знать «ошибка», и я не очень понимаю оценку.

Я думаю, что обходным решением было бы получить make и модель, отправив запрос SNMP на принтеры, но я ничего не знаю о SNMP, и я не уверен, что есть одна команда SNMP для получения маркой и моделью любого принтера.

Если у кого-то есть идея о том, как достичь этого, либо используя метод Java, либо отправляя команды SNMP или что-то еще, что можно сделать на любой ОС, ваша помощь будет оценена.

EDIT:

Вот ссылка на тему, где же был задан вопрос:

EDIT 2:

Так lution:

Как я уже сказал в комментарии, я попытался получить марку и модель через 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.

И вот код с моим личным обновлением этих двух классов.

Winspool:

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. Я буду держать вас в курсе, если найду что-нибудь.

+2

* «.. было задано три или четыре раза, но никто, кажется, не нашел ответа». * Это может быть так, если нет ответа. * Где эти повторяющиеся вопросы? Предоставьте ссылки. –

+0

Я добавил ссылку на аналогичный вопрос в stackoverflow, я знаю, что пару раз пробовал этот же вопрос на других сайтах через свои исследования, но больше не могу найти ссылки. – Padrus

+0

Моя организация называет свои принтеры следующим образом - HP2200-RM623. Когда я выбираю принтер, тип и местоположение отображаются в диалоговом окне «Печать». Возможно, вам придется использовать другой язык помимо Java, чтобы получить информацию о принтере, которую вы затем можете передать на Java через JNI. –

ответ

1

Для тех, кто интересуется этой темой, я продолжал искать решение, которое использовало бы базовые библиотеки Java, но когда я начал искать исходный код этих библиотек, я узнал, что большинство методов, которые предполагаются для возврата атрибутов принтера никогда не выполнялись, они всегда возвращают значение Null. Итак, на данный момент в Java нет возможности выполнить это.

Есть два пути, которые я отправил на втором редактировании моего первоначального вопроса:

  • Получить информацию с помощью SNMP-вызовов.
  • Используйте диспетчер очереди печати Windows DLL и получите эту информацию от водителя.
+0

Работа с Java и печать только на Windows - это все, что я пытался сделать. Большое спасибо за то, что поделились своей работой! – Joe

3

(Cherry-собирание некоторые части вопроса, которые подотчетны.)

Похоже, что это знать «ошибка», и я не очень понимаю оценку.

Фактически, это запрос на улучшение (RFE), а не ошибка.

Оценка просто указывает, что рецензент считает, что он нашел способ , который они могут реализовать это на Windows ... если и когда они обойдутся. Это не обходное решение для вас.


Этот связанный с этим вопрос говорит о получении модели печатника с помощью SNMP

Вы должны быть в состоянии отобразить это решение с использованием библиотеки Java SNMP. Этот подход предполагает, что принтер подключен к сети и поддерживает SNMP ... но я думаю, вы уже поняли это.

+0

Спасибо за это объяснение, это не отвечает на мой вопрос, но, по крайней мере, я кое-что узнал. – Padrus

+0

Я на самом деле пытаюсь это сделать, но я никогда не имел дело с SNMP, так что это могло бы занять у меня много времени. – Padrus

+0

Я попытался получить его через SNMP. Отправка команды «1.3.6.1.2.1.25.3.2.1.3.1» на принтер, похоже, работала, но я не уверен, что она работает на всех принтерах с этим OID, поэтому я, наконец, решил получить имя драйвера с помощью JNA и Winspool .drv. Я отредактирую свой вопрос и добавлю к нему свой код. – Padrus

0

Использование ЮНА, правильная версия для ОП раствора (без дублированного кода) заключается в следующем:

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 поддержки.