如何从Java获取Windows进程描述?

时间:2014-01-08 12:43:47

标签: java jna

以下是获取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);
        }
    } 
}

但是我无法在输出中获得进程/服务的描述。提供解决方案来获取每个正在运行的进程的进程描述。提前谢谢。

3 个答案:

答案 0 :(得分:2)

您可以在Windows中使用以下代码片段而不是加载和调用Kernel32,它使用Runtime来执行本机进程:

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();
}

然后执行调用Windows Management Information Command-line

的命令
List<String> output = execCommand("wmic.exe PROCESS where name='"+processName+"'");

processName应该包含正在运行的应用程序的名称,或者尝试从中获取信息。

返回的列表将包含正在运行的应用程序的状态信息的行输出。第一个条目将包含相应字段的标题信息,而以下条目将包含有关所有匹配过程名称的信息。

WMIC的更多信息:

HTH

答案 1 :(得分:1)

我今天偶然发现this post here,它展示了如何从可执行文件中提取版本信息,你的帖子又回到了我的脑海,所以我开始了一些调查。

This further post表示流程描述只能从可执行文件本身中提取,因此我们需要将手放在JNA上,而不是解析WMICTASKLIST的某些输出。这篇文章进一步链接了MSDN page for VerQueryValue函数,它提供了一种提取过程描述的C方法。特别是第二个参数应该是有意义的,因为它定义了返回的内容。

使用第一篇文章中提到的代码,现在有点将C struct typedef转换为Java等价物。我将在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 - 一个帮助器类,它将提取的十六进制值映射到转换表中包含的语言和代码页信息的人类可读输出。因此,这些值来自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());
    }
}

最后但并非最不重要的是提取Windows资源管理器的文件版本和文件描述的代码。代码包含大量文档,因为我自己用它来学习这些东西;)

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)+"\"");
    }
}

最后,我在德国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:更新代码以使用结构的类表示来简化值的提取(处理字节确实需要它们按接收字节的顺序切换 - 大端和小端字符串问题)

在一些尝试之后发现一个应用程序在其文件中使用多种语言和代码页,我可以测试多个翻译的输出。


@ Edit2:重构代码并将其放在github上。正如评论中所提到的,从Logitech WingMan事件监视器的github仓库运行代码的输出返回多个语言和代码页段:

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.

答案 2 :(得分:0)

(OP在回答 - 回复中回答。转换为社区维基回答。请参阅Question with no answers, but issue solved in the comments (or extended in chat)

  

实际上我发现了另一种方式,即。 Windows PowerShell命令:
  get-process notepad | select-object description

     

因此,我使用命令行来获取当前正在运行的进程的描述。同样对于服务:
  get-service | where {$_.status -eq 'running'}