我是JNA的新手,在尝试我的第一个程序列出Windows上的所有进程时,我遇到了一些麻烦。出于某种原因,我得到以下输出:
[pid = 0, name = ???????? ]
[pid = 4, name = ???????? ]
[pid = 364, name = ???????? ]
[pid = 516, name = ????e??? ]
[pid = 648, name = ?????e?? ]
[pid = 668, name = ????ee?? ]
[pid = 708, name = ???????? ]
[pid = 732, name = ????e??? ]
[pid = 740, name = ???ee??? ]
[pid = 796, name = ???????? ]
[pid = 880, name = ?????e?? ]
...
进程标识符有效,并且在快照期间当前正在我的系统上运行,但由于某种原因,字符串已损坏。 StackOverflow上的其他几个类似的例子给了我相同的结果。我是否需要在最新版本的JNA中指定新的东西以使这样的程序起作用?
public class Processes
{
private static final Kernel32 kernel = ( Kernel32 )Native.loadLibrary( Kernel32.class );
public static ArrayList<Process> getSnapshot( ) throws LastErrorException
{
ArrayList<Process> processes = new ArrayList<Process>( );
HANDLE snapshot = null;
try
{
snapshot = kernel.CreateToolhelp32Snapshot( Tlhelp32.TH32CS_SNAPPROCESS, new DWORD( 0 ) );
PROCESSENTRY32 entry = new PROCESSENTRY32( );
kernel.Process32First( snapshot, entry );
do
{
processes.add( new Process( Native.toString( entry.szExeFile ), entry.th32ProcessID.intValue() ) );
}
while( kernel.Process32Next( snapshot, entry ) );
}
finally
{
kernel.CloseHandle( snapshot );
}
return processes;
}
}
我的代码主要基于MSDN示例here。
答案 0 :(得分:1)
JNA使用Process32First\Next which is the ANSI version but you need to use the Unicode or UTF-16LE version which is Process32FirstW\NextW.这可能是JNA中的一个错误,因为它使用PROCESSENTRY32
的Unicode版本,期望TCHAR
szExeFile
为UTF-16LE >
你可以这样扩展Kernel32:
Kernel32.java:
import com.sun.jna.Native;
import com.sun.jna.platform.win32.Tlhelp32;
public interface Kernel32 extends com.sun.jna.platform.win32.Kernel32 {
Kernel32 INSTANCE = (Kernel32)Native.loadLibrary("kernel32", Kernel32.class, com.sun.jna.win32.W32APIOptions.DEFAULT_OPTIONS);
boolean Process32FirstW(HANDLE hSnapshot, Tlhelp32.PROCESSENTRY32 lppe);
boolean Process32NextW(HANDLE hSnapshot, Tlhelp32.PROCESSENTRY32 lppe);
}
改变Processes.java:
try
{
snapshot = kernel.CreateToolhelp32Snapshot( Tlhelp32.TH32CS_SNAPPROCESS, new DWORD( 0 ) );
PROCESSENTRY32 entry = new PROCESSENTRY32( );
kernel.Process32FirstW( snapshot, entry );
do
{
processes.add( new Process( Native.toString(entry.szExeFile ), entry.th32ProcessID.intValue() ) );
}
while( kernel.Process32NextW( snapshot, entry ) );
}
finally
{
kernel.CloseHandle( snapshot );
}
原始答案与可悲的遗弃和过时的ANSI:
尝试
import java.util.ArrayList;
import com.sun.jna.LastErrorException;
import com.sun.jna.Native;
import com.sun.jna.platform.win32.Kernel32;
import com.sun.jna.platform.win32.Tlhelp32;
import com.sun.jna.platform.win32.Tlhelp32.PROCESSENTRY32;
import com.sun.jna.platform.win32.WinDef.DWORD;
import com.sun.jna.platform.win32.WinNT.HANDLE;
public class Processes
{
private static final Kernel32 kernel = ( Kernel32 )Native.loadLibrary( Kernel32.class );
static class Process{
public String pName;
public int pID;
Process(String pName,int pID){
this.pName = pName;
this.pID = pID;
}
}
public static ArrayList<Process> getSnapshot( ) throws LastErrorException
{
ArrayList<Process> processes = new ArrayList<Process>( );
HANDLE snapshot = null;
try
{
snapshot = kernel.CreateToolhelp32Snapshot( Tlhelp32.TH32CS_SNAPPROCESS, new DWORD( 0 ) );
PROCESSENTRY32 entry = new PROCESSENTRY32( );
kernel.Process32First( snapshot, entry );
do
{
byte[] bytes = new byte[entry.szExeFile.length*2];
for(int i=0;i<entry.szExeFile.length;i++) {
bytes[i*2+1] = (byte) (entry.szExeFile[i] >> 8);
bytes[i*2] = (byte) entry.szExeFile[i];
}
processes.add( new Process( Native.toString( bytes, "ANSI" ), entry.th32ProcessID.intValue() ) );
}
while( kernel.Process32Next( snapshot, entry ) );
}
finally
{
kernel.CloseHandle( snapshot );
}
return processes;
}
}
真正唯一的变化是将char []转换为byte [],因此可以指定“ANSI”。
byte[] bytes = new byte[entry.szExeFile.length*2];
for(int i=0;i<entry.szExeFile.length;i++) {
bytes[i*2+1] = (byte) (entry.szExeFile[i] >> 8);
bytes[i*2] = (byte) entry.szExeFile[i];
}
processes.add( new Process( Native.toString( bytes, "ANSI" ), entry.th32ProcessID.intValue() ) );
使用Main中的上述课程:
public static void main(String[] args) {
ArrayList<Processes.Process> curProcesses = Processes.getSnapshot();
for(Processes.Process curP : curProcesses){
System.out.println(curP.pName + ":" + curP.pID);
}
}
我明白了:
[系统流程]:0
系统:4
SMSS.EXE:248
CSRSS.EXE:444
CSRSS.EXE:532
Wininit.exe将:540
Services.exe的:588
LSASS.EXE:596
...等
答案 1 :(得分:1)
您遗漏了Native.loadLibrary
的选项,告诉JNA自动映射到Process32FirstW
(W32APIOptions.DEFAULT_OPTIONS
会为您执行此操作)。了解JNA如何加载kernel32
库。
由于{{1}的定义,JNA Process32First
中包含的platform.jar
的定义实际上仅与unicode(-W
)版本一起使用结构,它使用Java PROCESSENTRY32
作为文件名。您遇到垃圾的原因是“ANSI”版本的编码字节数组已被读入Java char
数组。 char
试图从该数组中读取数据,而不知道数据最初是编码的字节。