Finding if printer is online and ready to print - java

The following 4 questions didn't help, therefore this isn't a duplicate:
ONE, TWO, THREE, FOUR
I need to find a way to discover if the Printer that my system reports is available to print or not.
Printer page:
In the picture, the printer "THERMAL" is available to print, but "HPRT PPTII-A(USB)" isn't available to print. The System shows me that, by making the non-available printer shaded
Using the following code, I'm able to find all the printers in the system
public static List<String> getAvailablePrinters() {
DocFlavor flavor = DocFlavor.SERVICE_FORMATTED.PRINTABLE;
PrintRequestAttributeSet aset = new HashPrintRequestAttributeSet();
PrintService[] services = PrintServiceLookup.lookupPrintServices(flavor, aset);
ArrayList<String> names = new ArrayList<String>();
for (PrintService p : services) {
Attribute at = p.getAttribute(PrinterIsAcceptingJobs.class);
if (at == PrinterIsAcceptingJobs.ACCEPTING_JOBS) {
names.add(p.getName());
}
}
return names;
}
output:
[HPRT PPTII-A(USB), THERMAL]
The problem is: This code shows all the printers that the system have ever installed.
What I need: This list should contain only the really available printers to print. In this example, it should only show "THERMAL", and not show "HPRT PPTII-A(USB)"
How can this be achieved?

If it is okay that the solution is Windows-specific, try WMI4Java. Here is my situation:
As you can see, my default printer "Kyocera Mita FS-1010" is inactive (greyed out) because I simply switched it off.
Now add this to your Maven POM:
<dependency>
<groupId>com.profesorfalken</groupId>
<artifactId>WMI4Java</artifactId>
<version>1.4.2</version>
</dependency>
Then it is as easy as this to list all printers with their respective status:
package de.scrum_master.app;
import com.profesorfalken.wmi4java.WMI4Java;
import com.profesorfalken.wmi4java.WMIClass;
import java.util.Arrays;
public class Printer {
public static void main(String[] args) {
System.out.println(
WMI4Java
.get()
.properties(Arrays.asList("Name", "WorkOffline"))
.getRawWMIObjectOutput(WMIClass.WIN32_PRINTER)
);
}
}
The console log looks as follows:
Name : WEB.DE Club SmartFax
WorkOffline : False
Name : Send To OneNote 2016
WorkOffline : False
Name : Microsoft XPS Document Writer
WorkOffline : False
Name : Microsoft Print to PDF
WorkOffline : False
Name : Kyocera Mita FS-1010 KX
WorkOffline : True
Name : FreePDF
WorkOffline : False
Name : FinePrint
WorkOffline : False
Name : Fax
WorkOffline : False
Please note that WorkOffline is True for the Kyocera printer. Probably this is what you wanted to find out.
And now a little modification in order to filter the printers list so as to only show active printers:
WMI4Java
.get()
.properties(Arrays.asList("Name", "WorkOffline"))
.filters(Arrays.asList("$_.WorkOffline -eq 0"))
.getRawWMIObjectOutput(WMIClass.WIN32_PRINTER)
Update: I was asked how to get a list of active printer names. Well, this is not so easy due to a shortcoming in WMI4Java for which I have just filed a pull request. It causes us to parse and filter the raw WMI output, but the code is still pretty straightforward:
package de.scrum_master.app;
import com.profesorfalken.wmi4java.WMI4Java;
import com.profesorfalken.wmi4java.WMIClass;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class Printer {
public static void main(String[] args) {
String rawOutput = WMI4Java
.get()
.properties(Arrays.asList("Name", "WorkOffline"))
.filters(Arrays.asList("$_.WorkOffline -eq 0"))
.getRawWMIObjectOutput(WMIClass.WIN32_PRINTER);
List<String> printers = Arrays.stream(rawOutput.split("(\r?\n)"))
.filter(line -> line.startsWith("Name"))
.map(line -> line.replaceFirst(".* : ", ""))
.sorted()
.collect(Collectors.toList());
System.out.println(printers);
}
}
The console output looks like this:
[Fax, FinePrint, FreePDF, Microsoft Print to PDF, Microsoft XPS Document Writer, Send To OneNote 2016, WEB.DE Club SmartFax]

UPDATE:
Instead of querying WMI "win32_printer" object I would recommend using Powershell directly like this, its much cleaner API :
Get-Printer | where PrinterStatus -like 'Normal' | fl
To see all the printers and statuses:
Get-Printer | fl Name, PrinterStatus
To see all the attributes:
Get-Printer | fl
You can still use ProcessBuilder in Java as described below.
Before update:
Windows solution, query WMI "win32_printer" object:
public static void main(String[] args) {
// select printer that have state = 0 and status = 3, which indicates that printer can print
ProcessBuilder builder = new ProcessBuilder("powershell.exe", "get-wmiobject -class win32_printer | Select-Object Name, PrinterState, PrinterStatus | where {$_.PrinterState -eq 0 -And $_.PrinterStatus -eq 3}");
String fullStatus = null;
Process reg;
builder.redirectErrorStream(true);
try {
reg = builder.start();
fullStatus = getStringFromInputStream(reg.getInputStream());
reg.destroy();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
System.out.print(fullStatus);
}
For converting InputStream to String look here: comprehensive StackOverflow answer, or you can simply use:
public static String getStringFromInputStream(InputStream is) {
ByteArrayOutputStream result = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int length;
try {
while ((length = is.read(buffer)) != -1) {
result.write(buffer, 0, length);
}
} catch (IOException e1) {
e1.printStackTrace();
}
// StandardCharsets.UTF_8.name() > JDK 7
String finalResult = "";
try {
finalResult = result.toString("UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return finalResult;
}
Output:
Name PrinterState PrinterStatus
---- ------------ -------------
Foxit Reader PDF Printer 0 3
Send to OneNote 2010 0 3
Microsoft XPS Document Writer 0 3
Microsoft Print to PDF 0 3
Fax 0 3
\\192.168.50.192\POS_PRINTER 0 3
As you can see, you now have all the printers that are in working state in the string.
You can use your existing method (getAvailablePrinters()) and e.g. add something like this:
ArrayList<String> workingPrinter = new ArrayList<String>();
System.out.println("Working printers:");
for(String printer : getAvailablePrinters()){
if(fullStatus.contains("\n" + printer + " ")){ // add a newline character before the printer name and space after so that it catches exact name
workingPrinter.add(printer);
System.out.println(printer);
}
}
And now you will have a nice list of working printers.
Console output:
Working printers:
Send to OneNote 2010
Foxit Reader PDF Printer
Microsoft XPS Document Writer
Microsoft Print to PDF
Fax
\\192.168.50.192\POS_PRINTER
Of course you have to be careful with the names with this approach - e.g. if "POS_PRINTER" is in all printers but not in working printers list, it could still get added to the workingPrinters list, if there is a working printer named "POS_PRINTER 1" as that name contains "\nPOS_PRINTER " string...

Related

How to invoke a method of a class from another project by Rest Api in Java

I need to call a method from another project in eclipse, I tried to add the project to classpath of the current project (Right click on project -> properties -> java build path -> projects) but I got an error and exception (java.lang.NoClassDefFoundError) and ( java.lang.ClassNotFoundException) and I couldn't fix that. I know there is another way to do this job by using Rest Api. please help me!! Thanks.
I want to call (getSample2) to my current project:
public List<String> getSample2 (String fileName, int minFrequency, int maxFrequency) {
List<SampleMultyFreq> fd = getSamples(fileName, minFrequency, maxFrequency);
List<String> ls = new ArrayList<>();
for(SampleMultyFreq ss: fd) {
ls.add(ss.getFrequencies().toString());
}
return ls;
}
I created this method in the same project with (getsample2) for calling (getSample2) method easy. I don't know it is a right way or not.
#GET
#Path("GET_SAMPLE_API")
public Response getSampleApi (String fileName) {
List<String> ss = new DataReader2NewPods().getSample2(fileName, 1, 9);
return Response.status(Response.Status.OK).entity(ss).build();
}
and Finally I wrote this method in my current project for sending request to get (getSampleApi) like this but I don't know the methods that I used is correct or not I copied another method that was for download a file from AWS cloud by using rest api:
public String getSampleMethdByRest (String fileName) {
if (StringUtils.isNoneBlank(fileName)) {
System.out.println(" print to test 1:");
String url = "http://localhost:8080/project-dev/ss/GET_SAMPLE_API/";
final Response resp = client.target(url).request(MediaType.APPLICATION_OCTET_STREAM).get(Response.class);
if (resp.getStatus() == Response.Status.OK.getStatusCode()) {
System.out.println(" print to test 2:");
InputStream inputStream = (InputStream)resp.getEntity();
}
}
System.out.println(" print to test 3:");
return Constants.root + File.separator +
Config.getInstance().getProperties().getProperty("temp_folder") + File.separator + fileName;
}
and this is the output:
print to test 1:
print to test 3:
C:\home\project\temp_folder\data_98F4ABFB7806_16480262_1595325764285_len_2528.txt
Would you please help me. many thanks in advance.

Jsoup behaves different from my test PC and the server

I'm testing a web crawler with JSoup. The issue comes when I test the crawler on a regular PC, and works as expected, then I export this web crawler as a jar to work in a server in a cron job. This where the things go wrong.
The code is the same, no changes. The data I'm trying to extract is different comments from the users of how they rate a service, the problem is that the web crawler behaves differently when it's executed in the server, for example: the comments are duplicated, something that doesn't happened when I'm testing the program locally.
Also the web crawler differentiates what language the comments are written (I take that info from the URL, .de for German, .es for Spanish, etc). This info get mixed for example, a comment in Spanish is classified as Portuguese one.
Again I repeat the logic behind the crawler is correct, I tested many times with different input.
What could be the problem behind these issues?
Additional notes:
No exceptions/crashes.
I'm using jsoup 1.9.2.
This is how I get the data from the website:
Document doc = Jsoup.connect(link).userAgent(FakeAgentBooking.getAgent()).timeout(60 * 4000).get();
I already tried to use a proxy just in case the server was banned.
System.getProperties().put("https.proxyHost", "PROXY");
System.getProperties().put("https.proxyPort", "PORT");
System.getProperties().put("https.proxyUser", "USER");
System.getProperties().put("https.proxyPassword", "PASSWORD");
This is the code of the cron job:
#Crawler(name = "Booking comments", nameType = "BOOKING_COMMENTS", sentimetal = true, cron = "${cron.booking.comments}")
public class BookingCommentsJob extends MotherCrawler {
private static final org.slf4j.Logger logger = LoggerFactory.getLogger(BookingCommentsJob.class);
#Value("${full.booking.comments}")
private String full;
#Autowired
private ComentariosCDMXRepository comentariosCDMXRepository;
#Override
#PostConstruct
public void init() {
setInfo(this.getClass().getAnnotation(Crawler.class));
}
#Override
public void exec(int num) {
// <DEBUG>
String startTime = time.format(new Date());
// </DEBUG>
Set<CrawQuery> li = queryManager.getMeQueries(type, num, threadnum);
Gson gson = new GsonBuilder().create();
for (CrawQuery s : li) {
String query = s.getQuery().get("query");
try {
//the crawling begins here-->
String result = BookingComentarios.crawlBookingComentarios(query, Boolean.parseBoolean(full));
//get the result from json to a standarized class
ComentarioCDMX[] myComments = gson.fromJson(result, ComentarioCDMX[].class);
for (ComentarioCDMX myComment : myComments) {
//evaluates if the comment is positive, neutral or negative.
Integer sentiment = sentimentAnalysis.classifyVector(myComment.getComment());
myComment.setSentiment(sentiment);
myComment.setQuery(query);
/* <Analisis de sentimiento /> */
comentariosCDMXRepository.save(myComment);
}
s.setStatus(true);
} catch (Exception e) {
logger.error(query, e);
s.setStatus(false);
mailSend.add(e);
} finally {
s.setLastUse(new Date());
//Saves data to Solr
crawQueryDao.save(s);
}
}
update();
// <DEBUG>
String endTime = time.format(new Date());
logger.info(name + " " + num + " > Inicio: " + startTime + ", Fin: " + endTime);
// </DEBUG>
}
#Scheduled(cron = "${cron.booking.comments}")
public void curro0() throws InterruptedException {
exec(0);
}
}
and this is when the code should be executed:
cron.booking.comments=00 30 02 * * *
Additional notes:
The test PC OS is Windows 7 and the server OS is linux Debian 3.16.7. and tghe java version in the test PC is 1.7 oracle JDK and on the server is 1.8.0 JRE.

How to get Windows process Description from Java?

Here is the code to get list of currently running process in windows.
import com.sun.jna.platform.win32.Kernel32;
import com.sun.jna.platform.win32.Tlhelp32;
import com.sun.jna.platform.win32.WinDef;
import com.sun.jna.platform.win32.WinNT;
import com.sun.jna.win32.W32APIOptions;
import com.sun.jna.Native;
public class ListProcesses {
public static void main(String[] args) {
Kernel32 kernel32 = (Kernel32) Native.loadLibrary(Kernel32.class, W32APIOptions.UNICODE_OPTIONS);
Tlhelp32.PROCESSENTRY32.ByReference processEntry = new Tlhelp32.PROCESSENTRY32.ByReference();
WinNT.HANDLE snapshot = kernel32.CreateToolhelp32Snapshot(Tlhelp32.TH32CS_SNAPPROCESS, new WinDef.DWORD(0));
try {
while (kernel32.Process32Next(snapshot, processEntry)) {
System.out.println(processEntry.th32ProcessID + "\t" + Native.toString(processEntry.szExeFile)+"\t"+processEntry.readField(""));
}
}
finally {
kernel32.CloseHandle(snapshot);
}
}
}
But I am unable to get description of the process/service in output.Kindly provide solution to get process description of each running proceess. Thanks in advance.
Instead of loading and invoking Kernel32 you could simply use the following code snippet in windows which uses the Runtime to execute a native process:
public List<String> execCommand(String ... command)
{
try
{
// execute the desired command
Process proc = null;
if (command.length > 1)
proc = Runtime.getRuntime().exec(command);
else
proc = Runtime.getRuntime().exec(command[0]);
// process the response
String line = "";
List<String> output = new ArrayList<>();
try (BufferedReader input = new BufferedReader(new InputStreamReader(proc.getInputStream())))
{
while ((line = input.readLine()) != null)
{
output.add(line);
}
}
return output;
}
catch (IOException e)
{
e.printStackTrace();
}
return Collections.<String>emptyList();
}
and then execute the command which invokes the Windows Management Information Command-line:
List<String> output = execCommand("wmic.exe PROCESS where name='"+processName+"'");
processName should contain the name of the running application or exe you try to get information from.
The returned list will then contain the line output of the status information of the running application. The first entry will contain header-information for the respective fields while the following entries will contain information on all matching process names.
Further infos on WMIC:
MSDN
Product documentation
Generating HTML output for WMI
HTH
As I stumbled today across this post here which showcases how to extract the version info from an executable file, your post came back to my mind and so I started a bit of investigation.
This further post states that the process description can only be extracted from the executable file itself so we need to lay our hands on JNA instead of parsing some output from WMIC or TASKLIST. This post further links the MSDN page for VerQueryValue function which provides a C way of extracting the process description. Here especially the 2nd parameter should be of interest as it defines what to return.
With the code mentioned in the first post it is now a bit of converting the C struct typedefs into Java equivalents. I will post the complete code here which at least works for me on Windows 7 64bit:
Maven pom.xml:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>at.rovo.test</groupId>
<artifactId>JNI_Test</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>JNI_Test</name>
<url>http://maven.apache.org</url>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
</plugins>
</build>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<!-- JNA 3.4
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna</artifactId>
<version>3.4.0</version>
</dependency>
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>platform</artifactId>
<version>3.4.0</version>
</dependency>
-->
<!-- JNA 4.0.0 -->
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna-platform</artifactId>
<version>4.0.0</version>
</dependency>
<!-- -->
</dependencies>
</project>
LangAndCodePage.java - a helper class which maps the extracted hex-values to human readable output of the language and code page information contained within the translation table. The values therefore are taken from this page here:
package at.rovo.test.jni_test;
import java.util.HashMap;
import java.util.Map;
public final class LangAndCodePage
{
private final static Map<String, String> languages = new HashMap<>();
private final static Map<String, String> codePage = new HashMap<>();
static
{
languages.put("0000", "Language Neutral");
languages.put("0401", "Arabic");
languages.put("0402", "Bulgarian");
languages.put("0403", "Catalan");
languages.put("0404", "Traditional Chinese");
languages.put("0405", "Czech");
languages.put("0406", "Danish");
languages.put("0407", "German");
languages.put("0408", "Greek");
languages.put("0409", "U.S. English");
languages.put("040A", "Castilian Spanish");
languages.put("040B", "Finnish");
languages.put("040C", "French");
languages.put("040D", "Hebrew");
languages.put("040E", "Hungarian");
languages.put("040F", "Icelandic");
languages.put("0410", "Italian");
languages.put("0411", "Japanese");
languages.put("0412", "Korean");
languages.put("0413", "Dutch");
languages.put("0414", "Norwegian ? Bokmal");
languages.put("0810", "Swiss Italian");
languages.put("0813", "Belgian Dutch");
languages.put("0814", "Norwegian ? Nynorsk");
languages.put("0415", "Polish");
languages.put("0416", "Portuguese (Brazil)");
languages.put("0417", "Rhaeto-Romanic");
languages.put("0418", "Romanian");
languages.put("0419", "Russian");
languages.put("041A", "Croato-Serbian (Latin)");
languages.put("041B", "Slovak");
languages.put("041C", "Albanian");
languages.put("041D", "Swedish");
languages.put("041E", "Thai");
languages.put("041F", "Turkish");
languages.put("0420", "Urdu");
languages.put("0421", "Bahasa");
languages.put("0804", "Simplified Chinese");
languages.put("0807", "Swiss German");
languages.put("0809", "U.K. English");
languages.put("080A", "Spanish (Mexico)");
languages.put("080C", "Belgian French");
languages.put("0C0C", "Canadian French");
languages.put("100C", "Swiss French");
languages.put("0816", "Portuguese (Portugal)");
languages.put("081A", "Serbo-Croatian (Cyrillic)");
codePage.put("0000", "7-bit ASCII");
codePage.put("03A4", "Japan (Shift ? JIS X-0208)");
codePage.put("03B5", "Korea (Shift ? KSC 5601)");
codePage.put("03B6", "Taiwan (Big5)");
codePage.put("04B0", "Unicode");
codePage.put("04E2", "Latin-2 (Eastern European)");
codePage.put("04E3", "Cyrillic");
codePage.put("04E4", "Multilingual");
codePage.put("04E5", "Greek");
codePage.put("04E6", "Turkish");
codePage.put("04E7", "Hebrew");
codePage.put("04E8", "Arabic");
}
// prohibit instantiation
private LangAndCodePage()
{
}
public static void printTranslationInfo(String lang, String cp)
{
StringBuilder builder = new StringBuilder();
builder.append("Language: ");
builder.append(languages.get(lang));
builder.append(" (");
builder.append(lang);
builder.append("); ");
builder.append("CodePage: ");
builder.append(codePage.get(cp));
builder.append(" (");
builder.append(cp);
builder.append(");");
System.out.println(builder.toString());
}
}
Last but not least the code which extracts the file version and the file description of the Windows explorer. The code contains plenty of documentation as I used it to learn the stuff myself ;)
package at.rovo.test.jni_test;
import java.io.IOException;
import com.sun.jna.Memory;
import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.VerRsrc.VS_FIXEDFILEINFO;
import com.sun.jna.platform.win32.Version;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.ptr.PointerByReference;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
public class FileVersion
{
// The structure as implemented by the MSDN article
public static class LANGANDCODEPAGE extends Structure
{
/** The language contained in the translation table **/
public short wLanguage;
/** The code page contained in the translation table **/
public short wCodePage;
public LANGANDCODEPAGE(Pointer p)
{
useMemory(p);
}
public LANGANDCODEPAGE(Pointer p, int offset)
{
useMemory(p, offset);
}
public static int sizeOf()
{
return 4;
}
// newer versions of JNA require a field order to be set
#Override
protected List getFieldOrder()
{
List fieldOrder = new ArrayList();
fieldOrder.add("wLanguage");
fieldOrder.add("wCodePage");
return fieldOrder;
}
}
public static void main(String[] args) throws IOException
{
// http://msdn.microsoft.com/en-us/library/ms647464%28v=vs.85%29.aspx
//
// VerQueryValue will take two input and two output parameters
// 1. parameter: is a pointer to the version-information returned
// by GetFileVersionInfo
// 2. parameter: will take a string and return an output depending on
// the string:
// "\\"
// Is the root block and retrieves a VS_FIXEDFILEINFO struct
// "\\VarFileInfo\Translation"
// will return an array of Var variable information structure
// holding the language and code page identifier
// "\\StringFileInfo\\{lang-codepage}\\string-name"
// will return a string value of the language and code page
// requested. {lang-codepage} is a concatenation of a language
// and the codepage identifier pair found within the translation
// array in a hexadecimal string! string-name must be one of the
// following values:
// Comments, InternalName, ProductName, CompanyName,
// LegalCopyright, ProductVersion, FileDescription,
// LegalTrademarks, PrivateBuild, FileVersion,
// OriginalFilename, SpecialBuild
// 3. parameter: contains the address of a pointer to the requested
// version information in the buffer of the 1st parameter.
// 4. parameter: contains a pointer to the size of the requested data
// pointed to by the 3rd parameter. The length depends on
// the input of the 2nd parameter:
// *) For root block, the size in bytes of the structure
// *) For translation array values, the size in bytes of
// the array stored at lplpBuffer;
// *) For version information values, the length in
// character of the string stored at lplpBuffer;
String filePath = "C:\\Windows\\explorer.exe";
IntByReference dwDummy = new IntByReference();
dwDummy.setValue(0);
int versionlength =
Version.INSTANCE.GetFileVersionInfoSize(filePath, dwDummy);
if (versionlength > 0)
{
// will hold the bytes of the FileVersionInfo struct
byte[] bufferarray = new byte[versionlength];
// allocates space on the heap (== malloc in C/C++)
Pointer lpData = new Memory(bufferarray.length);
// will contain the address of a pointer to the requested version
// information
PointerByReference lplpBuffer = new PointerByReference();
// will contain a pointer to the size of the requested data pointed
// to by lplpBuffer.
IntByReference puLen = new IntByReference();
// reads versionLength bytes from the executable file into the FileVersionInfo struct buffer
boolean fileInfoResult =
Version.INSTANCE.GetFileVersionInfo(
filePath, 0, versionlength, lpData);
// retrieve file description for language and code page "i"
boolean verQueryVal =
Version.INSTANCE.VerQueryValue(
lpData, "\\", lplpBuffer, puLen);
// contains version information for a file. This information is
// language and code page independent
VS_FIXEDFILEINFO lplpBufStructure =
new VS_FIXEDFILEINFO(lplpBuffer.getValue());
lplpBufStructure.read();
int v1 = (lplpBufStructure.dwFileVersionMS).intValue() >> 16;
int v2 = (lplpBufStructure.dwFileVersionMS).intValue() & 0xffff;
int v3 = (lplpBufStructure.dwFileVersionLS).intValue() >> 16;
int v4 = (lplpBufStructure.dwFileVersionLS).intValue() & 0xffff;
System.out.println(
String.valueOf(v1) + "." +
String.valueOf(v2) + "." +
String.valueOf(v3) + "." +
String.valueOf(v4));
// creates a (reference) pointer
PointerByReference lpTranslate = new PointerByReference();
IntByReference cbTranslate = new IntByReference();
// Read the list of languages and code pages
verQueryVal = Version.INSTANCE.VerQueryValue(
lpData, "\\VarFileInfo\\Translation", lpTranslate, cbTranslate);
if (cbTranslate.getValue() > 0)
{
System.out.println("Found "+(cbTranslate.getValue()/4)
+ " translation(s) (length of cbTranslate: "
+ cbTranslate.getValue()+" bytes)");
}
else
{
System.err.println("No translation found!");
return;
}
// Read the file description
// msdn has this example here:
// for( i=0; i < (cbTranslate/sizeof(struct LANGANDCODEPAGE)); i++ )
// where LANGANDCODEPAGE is a struct holding two WORDS. A word is
// 16 bits (2x 8 bit = 2 bytes) long and as the struct contains two
// words the length of the struct should be 4 bytes long
for (int i=0; i < (cbTranslate.getValue()/LANGANDCODEPAGE.sizeOf()); i++))
{
// writes formatted data to the specified string
// out: pszDest - destination buffer which receives the formatted, null-terminated string created from pszFormat
// in: ccDest - the size of the destination buffer, in characters. This value must be sufficiently large to accomodate the final formatted string plus 1 to account for the terminating null character.
// in: pszFormat - the format string. This string must be null-terminated
// in: ... The arguments to be inserted into the pszFormat string
// hr = StringCchPrintf(SubBlock, 50,
// TEXT("\\StringFileInfo\\%04x%04x\\FileDescription"),
// lpTranslate[i].wLanguage,
// lpTranslate[i].wCodePage);
// fill the structure with the appropriate values
LANGANDCODEPAGE langCodePage =
new LANGANDCODEPAGE(lpTranslate.getValue(), i*LANGANDCODEPAGE.sizeOf());
langCodePage.read();
// convert short values to hex-string:
// https://stackoverflow.com/questions/923863/converting-a-string-to-hexadecimal-in-java
String lang = String.format("%04x", langCodePage.wLanguage);
String codePage = String.format("%04x",langCodePage.wCodePage);
// see http://msdn.microsoft.com/en-us/library/windows/desktop/aa381058.aspx
// for proper values for lang and codePage
LangAndCodePage.printTranslationInfo(lang.toUpperCase(), codePage.toUpperCase());
// build the string for querying the file description stored in
// the executable file
StringBuilder subBlock = new StringBuilder();
subBlock.append("\\StringFileInfo\\");
subBlock.append(lang);
subBlock.append(codePage);
subBlock.append("\\FileDescription");
printDescription(lpData, subBlock.toString());
}
}
else
System.out.println("No version info available");
}
private static void printDescription(Pointer lpData, String subBlock)
{
PointerByReference lpBuffer = new PointerByReference();
IntByReference dwBytes = new IntByReference();
// Retrieve file description for language and code page "i"
boolean verQueryVal = Version.INSTANCE.VerQueryValue(
lpData, subBlock, lpBuffer, dwBytes);
// a single character is represented by 2 bytes!
// the last character is the terminating "\n"
byte[] description =
lpBuffer.getValue().getByteArray(0, (dwBytes.getValue()-1)*2);
System.out.println("File-Description: \""
+ new String(description, StandardCharsets.UTF_16LE)+"\"");
}
}
Finally, the output I'm receiving on my German Windows 7 64bit:
[exec:exec]
Version: 6.1.7601.17567
Found 1 translation(s) (length of cbTranslate: 4 bytes)
Language: German (0407); CodePage: Unicode (04B0);
File-Description: "Windows-Explorer"
HTH
#Edit: updated the code to use a class representation of the struct to simplify the extraction of the values (dealing with bytes does require them to swith the order of the bytes received - big and little endian issue)
Found after some tries an application that uses multiple languages and code pages within their file where I could test the output of multiple translations.
#Edit2: refactored the code and put it up on github. As mentioned in the comment, the output running the code from the github repo for the Logitech WingMan Event Monitor returns multiple language and codepage segments:
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXX Information contained in: C:\Program Files\Logitech\Gaming Software\LWEMon.exe
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
File: C:\Program Files\Logitech\Gaming Software\LWEMon.exe
Version: 5.10.127.0
Language: U.S. English
CodePage: Multilingual
Original-Filename: LWEMon.exe
Company-Name: Logitech Inc.
File-Description: Logitech WingMan Event Monitor
File-Version: 5.10.127
Product-Version: 5.10.127
Product-Name: Logitech Gaming Software
Internal-Name: LWEMon
Private-Build:
Special-Build:
Legal-Copyright: © 1999-2010 Logitech. All rights reserved.
Legal-Trademark: Logitech, the Logitech logo, and other Logitech marks are owned by Logitech and may be registered. All other trademarks are the property of their respective owners.
Comment: Created by the WingMan Team.
File: C:\Program Files\Logitech\Gaming Software\LWEMon.exe
Version: 5.10.127.0
Language: Japanese
CodePage: Multilingual
Original-Filename: LWEMon.exe
Company-Name: Logicool Co. Ltd.
File-Description: Logicool WingMan Event Monitor
File-Version: 5.10.127
Product-Version: 5.10.127
Product-Name: Logicool Gaming Software
Internal-Name: LWEMon
Private-Build:
Special-Build:
Legal-Copyright: © 1999-2010 Logicool Co. Ltd. All rights reserved.
Legal-Trademark: Logicool, the Logicool logo, and other Logicool marks are owned by Logicool and may be registered. All other trademarks are the property of their respective owners.
Comment: Created by the WingMan Team.
(Answered by the OP in an answer-response. Converted to a community wiki answer. See Question with no answers, but issue solved in the comments (or extended in chat) )
Actually I find out another way ie. Windows PowerShell commands:
get-process notepad | select-object description.
Therefore, I am using command line to get descriptions of currently running process. Similarly for Services:
get-service | where {$_.status -eq 'running'}.

Printing with Attributes(Tray Control, Duplex, etc...) using javax.print library

I've been trying for some time to determine a way to use the standard Java Print library to print files - specifically, PDF documents - with certain attributes - specifically, to certain trays or using duplex.
There exists plenty of documentation on how this should be done, and indeed, I've researched and tried these methods. The typical way is something like this:
public static void main (String [] args) {
try {
PrintService[] pservices = PrintServiceLookup.lookupPrintServices(null, null);
//Acquire Printer
PrintService printer = null;
for (PrintService serv: pservices) {
System.out.println(serv.toString());
if (serv.getName().equals("PRINTER_NAME_BLAH")) {
printer = serv;
}
}
if (printer != null) {
System.out.println("Found!");
//Open File
FileInputStream fis = new FileInputStream("FILENAME_BLAH_BLAH.pdf");
//Create Doc out of file, autosense filetype
Doc pdfDoc = new SimpleDoc(fis, DocFlavor.INPUT_STREAM.AUTOSENSE, null);
//Create job for printer
DocPrintJob printJob = printer.createPrintJob();
//Create AttributeSet
PrintRequestAttributeSet pset = new HashPrintRequestAttributeSet();
//Add MediaTray to AttributeSet
pset.add(MediaTray.TOP);
//Add Duplex Option to AttributeSet
pset.add(Sides.DUPLEX);
//Print using Doc and Attributes
printJob.print(pdfDoc, pset);
//Close File
fis.close();
}
}
catch (Throwable t) {
t.printStackTrace();
}
}
In short, you do the following
Find the Printer
Create a PrinterJob
Create an AttributeSet
Add Attributes to the AttributeSet, such as Tray and Duplex
Call print on the printer job using the AttributeSet
The problem here is that, despite being the documented way of doing this, as well as what I've found from several tutorials, this method... doesn't work. Now keep in mind, I know that doesn't sound very descript, but hear me out. I don't say that lightly...
The official documentation for PrinterJob actually mentions that the AttributeSet is ignored in the default implementation. Source code seen here shows this to be true - the attributes are passed in and ignored entirely.
So apparently, you need some sort of extended version of the class, which is possibly based on the specific printers and their capabilities? I attempted to write some test code that would tell me such capabilities - we have a large variety of printers set up at the office, large or small, simple or full of bells and whistles - not to mention several drivers on my computer just for pseudo-printer drivers that just create documents and simulate printers without going to any sort of hardware. The test code is as follows:
public static void main (String [] args) {
PrintService[] pservices = PrintServiceLookup.lookupPrintServices(null, null);
for (PrintService serv: pservices) {
System.out.println(serv.toString());
printFunctionality(serv, "Trays", MediaTray.class);
printFunctionality(serv, "Copies", Copies.class);
printFunctionality(serv, "Print Quality", PrintQuality.class);
printFunctionality(serv, "Color", ColorSupported.class);
printFunctionality(serv, "Media Size", MediaSize.class);
printFunctionality(serv, "Accepting Jobs", PrinterIsAcceptingJobs.class);
}
}
private static void printFunctionality(PrintService serv, String attrName, Class<? extends Attribute> attr) {
boolean isSupported = serv.isAttributeCategorySupported(attr);
System.out.println(" " + attrName + ": " + (isSupported ? "Y" : "N"));
}
The results I found were that every printer, without exception, returned that "copies" were supported, and all other attributes were not. Furthermore, every printer's capabilities were identical, regardless of how implausible that would seem.
The inevitable question is multi-layered: How does one send in attributes in a way that they are registered? Additionally, how does one properly detect the capabilities of a printer? Indeed, is the PrinterJob class actually extended in a usable way at all, or are the Attributes always ignored?
Examples I've found throughout The Internet seem to suggest to me that the answer to the latter question is "No, they are always ignored", which seems ridiculous to me (but increasingly more believable as I sift through hundreds of pages). Is this code that Sun simply set up but never got working to a completed state? If so, are there any alternatives?
The problem is that the the Java print API is a bridge between worlds. Printer manufacturers don't release drivers for the JVM. They release drivers for Windows, Macintosh, and maybe someone has a a driver for a given printer that works on one or more *nix platforms.
Along you come with some Java code running inside a JVM on some host system. When you start querying the printer features, you aren't talking to the printers -- you are talking to a bridge class in java.awt.print that hook into the JVM, which hooks to the host operating system, which hooks into whatever particular driver was installed for a given printer. So there are several places where this can fall apart... The particular JVM you are on may or may not fully implement the API for querying printer features, let alone passing those parameters along for a given job.
A few suggestions:
look into the javax.print classes as an alternative to
java.awt.print -- I've had more luck printing from there.
try using alternative print drivers for your printers -- you can define
multiple named connections to a given printer, each with a different
driver. If you've got a manufacturer provided driver, try a more generic driver, if you've got a generic driver, try to install a more specific one.
run your code under alternate JVM implementations for your platform
So, we inevitably found a way to print to different trays and with different settings, but not directly. We found it impossible to send attributes via the printJob.print method, and that much hasn't changed. However, we were able to set the name of the print job, then intercept the print job with a low-level Perl script, parse the name, and set the tray and duplex settings there. It's an extreme hack, but it works. It still remains true that Java Printer Attributes do not work, and you will need to find another way if you want to set them.
We had similar requirement to print PDF's and wanted to send some pages to Specific tray and also wanted the document to be stapled.
We used Java code + ghost script combination
First convert PDF to ghost script and then add PJL (Print job language) commands to ghost script file to select trays and staple the documents.
Then send that edited ghost script file to printer.
Here is complete example written in Java
http://reddymails.blogspot.com/2014/07/how-to-print-documents-using-java-how.html
-Ram
Here's what it looks like in javafx Tray's may vary and it will also print out all trays that are available just change the tray name
private void printImage(Node node) {
PrinterJob job = PrinterJob.createPrinterJob();
if (job != null) {
JobSettings js = job.getJobSettings();
PaperSource papersource = js.getPaperSource();
System.out.println("PaperSource=" + papersource);
PrinterAttributes pa = printer.getPrinterAttributes();
Set<PaperSource> s = pa.getSupportedPaperSources();
System.out.println("# of papersources=" + s.size());
if (s != null) {
for (PaperSource newPaperSource : s) {
System.out.println("newpapersource= " + newPaperSource);
//Here is where you would put the tray name that is appropriate
//in the contains section
if(newPaperSource.toString().contains("Tray 2"))
js.setPaperSource(newPaperSource);
}
}
job.getJobSettings().setJobName("Whatever");
ObjectProperty<PaperSource> sources = job.getJobSettings().paperSourceProperty();
System.out.println(sources.toString());
boolean success = job.printPage(node);
if (success) {
System.out.println("PRINTING FINISHED");
job.endJob();
//Stage mainStage = (Stage) root.getScene().getWindow();
//mainStage.close();
}
}
}
Here's My output:
PaperSource=Paper source : Automatic
# of papersources=6
newpapersource= Paper source :
newpapersource= Paper source : Manual Feed in Tray 1
newpapersource= Paper source : Printer auto select
newpapersource= Paper source : Tray 1
newpapersource= Paper source : Tray 2
newpapersource= Paper source : Form-Source
ObjectProperty [bean: Collation = UNCOLLATED
Copies = 1
Sides = ONE_SIDED
JobName = Whatever
Page ranges = null
Print color = COLOR
Print quality = NORMAL
Print resolution = Feed res=600dpi. Cross Feed res=600dpi.
Paper source = Paper source : Tray 2
Page layout = Paper=Paper: Letter size=8.5x11.0 INCH Orient=PORTRAIT leftMargin=54.0 rightMargin=54.0 topMargin=54.0 bottomMargin=54.0, name: paperSource, value: Paper source : Tray 2]
PRINTING FINISHED
I've found the trick for the printer trays is to iterate over the Media.class using getSupportedAttributeValues(...), match the human-readable name, and select that particular value. Tested on Windows, MacOS with several tray configurations.
String tray = "1";
// Handle human-readable names, see PRINTER_TRAY_ALIASES usage below for context. Adjust as needed.
List<String> PRINTER_TRAY_ALIASES = Arrays.asList("", "Tray ", "Paper Cassette ");
// Get default printer
PrintService printService = PrintServiceLookup.lookupDefaultPrintService();
// Attributes to be provided at print time
PrintRequestAttributeSet pset = new HashPrintRequestAttributeSet();
Media[] supported = printService.getSupportedAttributeValues(Media.class, null, null);
for(Media m : supported) {
for(String pta : PRINTER_TRAY_ALIASES) {
// Matches "1", "Tray 1", or "Paper Cassette 1"
if (m.toString().trim().equalsIgnoreCase(pta + tray)) {
attributes.add(m);
break;
}
}
}
// Print, etc
// printJob.print(pdfDoc, pset);

cannot open device using jpcap

I'm having trouble opening found network devices with the jpcap library. I have installed winpcap and have jpcap.dll in system32 and syswow64. The following tutorial code crashes when trying to open device. The crash log:
PacketCapture: loading native library jpcap.. ok
net.sourceforge.jpcap.capture.CaptureDeviceOpenException: Error opening adapter: The system cannot find the device specified. (20)
at net.sourceforge.jpcap.capture.PacketCapture.open(Native Method)
at net.sourceforge.jpcap.capture.PacketCapture.open(PacketCapture.java:57)
at networksnifferdesktop.NetworkSnifferDesktop.<init>(NetworkSnifferDesktop.java:26)
at networksnifferdesktop.NetworkSnifferDesktop.main(NetworkSnifferDesktop.java:40)
Java Result: 1
In debug I can see that m_device is set to:
"\Device\NPF_{EC5226CF-3F55-4148-B40E-1FC3F8BB3398} Realtek PCIe GBE Family Controller"
in the following code:
package networksnifferdesktop;
import net.sourceforge.jpcap.capture.*;
import net.sourceforge.jpcap.net.*;
public class NetworkSnifferDesktop
{
private static final int INFINITE = -1;
private static final int PACKET_COUNT = 10;
// BPF filter for capturing any packet
private static final String FILTER = "";
private PacketCapture m_pcap;
private String m_device;
public NetworkSnifferDesktop() throws Exception
{
// Step 1: Instantiate Capturing Engine
m_pcap = new PacketCapture();
// Step 2: Check for devices
m_device = m_pcap.findDevice();
// Step 3: Open Device for Capturing (requires root)
m_pcap.open(m_device, true);
// Step 4: Add a BPF Filter (see tcpdump documentation)
m_pcap.setFilter(FILTER, true);
// Step 5: Register a Listener for Raw Packets
m_pcap.addRawPacketListener(new RawPacketHandler());
// Step 6: Capture Data (max. PACKET_COUNT packets)
m_pcap.capture(PACKET_COUNT);
}
public static void main(String[] args)
{
try
{
NetworkSnifferDesktop example = new NetworkSnifferDesktop();
}
catch (Exception e)
{
e.printStackTrace();
System.exit(1);
}
}
}
class RawPacketHandler implements RawPacketListener
{
private static int m_counter = 0;
public void rawPacketArrived(RawPacket data)
{
m_counter++;
System.out.println("Received packet (" + m_counter + ")");
}
}
"\Device\NPF_{EC5226CF-3F55-4148-B40E-1FC3F8BB3398} Realtek PCIe GBE Family Controller", if you literally mean a String the first character of which is the "D" in "\Device" and the last character of which is the "r" in "Controller", is not a valid WinPcap device name string.
"\Device\NPF_{EC5226CF-3F55-4148-B40E-1FC3F8BB3398}" would be a valid device name string.
From looking at the Jpcap source, it appears that the findDevice method does NOT return valid device name strings. It's documented as returning "a string describing the network device"; what it returns is a string containing the device name string, a newline, two blanks, and the device's vendor description string. This has been reported as a Jpcap bug.
I would suggest that you scan the string looking for the first white-space character ("white-space" includes blanks and newlines), and use, as the device name to pass to the open routine, everything up to but not including that white-space character. (If you don't find a white-space character, use the entire string.)

Categories