Yuvraj Kakkar
Yuvraj Kakkar

Reputation: 1163

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.

Upvotes: 0

Views: 3072

Answers (3)

Roman Vottner
Roman Vottner

Reputation: 12839

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.

Upvotes: 1

Roman Vottner
Roman Vottner

Reputation: 12839

(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'}.

Upvotes: 0

Roman Vottner
Roman Vottner

Reputation: 12839

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:

HTH

Upvotes: 3

Related Questions